/*++ 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 #include "private.h" #include #include // PERF #include "tapiperf.h" #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) // PERF extern PERFBLOCK PerfBlock; LONG RtlOpenCurrentUser( IN ULONG DesiredAccess, OUT PHANDLE CurrentUserKey ); //NTSYSAPI //NTSTATUS //NTAPI LONG NtClose( IN HANDLE Handle ); LPLINECOUNTRYLIST gpCountryList = NULL; LPDWORD gpCountryGroups = NULL; extern TAPIGLOBALS TapiGlobals; extern CRITICAL_SECTION gSafeMutexCritSec, gPriorityListCritSec; extern HANDLE ghHandleTable; extern TCHAR gszProviderID[]; extern TCHAR gszNumProviders[]; extern TCHAR gszNextProviderID[]; extern TCHAR gszProviderFilename[]; extern TCHAR gszRegKeyTelephony[]; const TCHAR gszLocation[] = TEXT("Location"); const TCHAR gszLocations[] = TEXT("Locations"); const TCHAR gszAreaCodeRules[] = TEXT("AreaCodeRules"); extern TCHAR gszRegKeyProviders[]; extern PTPROVIDER pRemoteSP; extern DWORD gdwNumSPEventHandlerThreads; extern HINSTANCE ghInstance; extern BOOL gbQueueSPEvents; const TCHAR gszID[] = TEXT("ID"); const TCHAR gszCountry[] = TEXT("Country"); const TCHAR gszFlags[] = TEXT("Flags"); const TCHAR gszNoPrefixAreaCodes[] = TEXT("NoPrefAC"); const TCHAR gszNumEntries[] = TEXT("NumEntries"); const TCHAR gszCurrentID[] = TEXT("CurrentID"); const TCHAR gszNextID[] = TEXT("NextID"); const TCHAR gszLocationListVersion[]= TEXT("LocationListVersion"); const TCHAR gszCallingCard[] = TEXT("CallingCard"); const TCHAR gszSameAreaRuleW[] = TEXT("SameAreaRule"); const TCHAR gszLongDistanceRuleW[] = TEXT("LongDistanceRule"); const TCHAR gszInternationalRuleW[] = TEXT("InternationalRule"); const TCHAR gszCountryGroupW[] = TEXT("CountryGroup"); const TCHAR gszNameW[] = TEXT("Name"); const TCHAR gszNameResW[] = TEXT("NameResourceId"); const TCHAR gszAreaCodeW[] = TEXT("AreaCode"); const TCHAR gszLongDistanceCarrierCodeW[] = TEXT("LongDistanceCarrierCode"); const TCHAR gszInternationalCarrierCodeW[] = TEXT("InternationalCarrierCode"); const TCHAR gszOutsideAccessW[] = TEXT("OutsideAccess"); const TCHAR gszLongDistanceAccessW[] = TEXT("LongDistanceAccess"); const TCHAR gszDisableCallWaitingW[] = TEXT("DisableCallWaiting"); const TCHAR gszTollListW[] = TEXT("TollList"); const TCHAR gszCountryListVersionW[] = TEXT("CountryListVersion"); const TCHAR gszAreaCodeToCallW[] = TEXT("AreaCodeToCall"); const TCHAR gszNumberToDialW[] = TEXT("NumberToDial"); const TCHAR gszPrefixesW[] = TEXT("Prefixes"); // // IMPORTANT NOTE: this value should be incremented any time there is a // change to country.rc // #define TAPI_CURRENT_COUNTRY_LIST_VERSION 0x00000119 #define IS_LRESULT_NOTERROR( foo ) \ ( ! ( 0x80000000 & foo ) && \ ( (foo <= LINEERR_LASTERRORVALUE) || \ (foo > 0x90000000 && foo <= PHONEERR_LASTERRORVALUE) ) ) extern UINT guiAlignmentFaultEnabled; extern BOOL gbWinNT; extern BOOL gbNTServer; extern BOOL gbServerInited; extern HANDLE ghTapisrvHeap; // // The following are used for the call hub implementation. // // One call hub hash table is used for each service provider. // When a outgoing call or is successfully made or an incoming // call shows up, TAPI will retrieve the call ID for that // call and stick it in the hash table using the algorithim : // // hashEntryIndex = callID % numHashTableEntries // // In the case of collision (hashEntry already in use by a // different callID) then the DoCallHubHashing() function will // try to create a dynamic entry to hang off the "static" entry. // // We will allow a total number (per table) of dynamic entries // specified by the GetMaxDynamicHashTableEntries() macro below. // // We will allow a total number (per table entry) of dynamic // entries specified by the symbolic MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT // constant below. // // TapiPrimes is an array of increasing prime numbers used // for hash table sizes. We will not grow a hash table to more // the 261983 (static) entries, this being a seemingly // reasonable limitation at this point. If we try to hash // a call and are unable to (out of memory, max table size, etc) // then we will reset our internal copy of the call ID for // the call to 0, meaning it's not hashed at all. // const DWORD TapiPrimes[] = { 31, 61, 127, 257, 521, 1031, 2053, 4099, 8191, 16381, 32749, 65537, 131071, 261983, 0 }; #define GetMaxDynamicHashTableEntries(TotalNumEntries) \ (TotalNumEntries/10) #define MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT 3 #if DBG extern DWORD gdwDebugLevel; extern BOOL gfBreakOnSeriousProblems; char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult ); #endif void PASCAL DestroytCall( PTCALL ptCall ); void PASCAL DestroytCallClient( PTCALLCLIENT ptCallClient ); void PASCAL DestroytLineClient( HLINE hLine ); void LDevSpecific_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ); void LMakeCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ); void CALLBACK CompletionProcSP( DWORD dwRequestID, LONG lResult ); LONG PASCAL GetPhoneAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ); LONG InitializeClient( PTCLIENT ptClient ); BOOL GetLinePermanentIdFromDeviceID( PTCLIENT ptClient, DWORD dwDeviceID, LPTAPIPERMANENTID pID ); void CALLBACK LineEventProcSP( HTAPILINE htLine, HTAPICALL htCall, DWORD dwMsg, ULONG_PTR dwParam1, ULONG_PTR dwParam2, ULONG_PTR dwParam3 ); PTPHONELOOKUPENTRY GetPhoneLookupEntry( DWORD dwDeviceID ); LONG GetPermLineIDAndInsertInTable( PTPROVIDER ptProvider, DWORD dwDeviceID, DWORD dwSPIVersion ); LONG AppendNewDeviceInfo ( BOOL bLine, DWORD dwDeviceID ); LONG RemoveDeviceInfoEntry ( BOOL bLine, DWORD dwDeviceID ); BOOL IsAPIVersionInRange( DWORD dwAPIVersion, DWORD dwSPIVersion ) { if (dwAPIVersion <= dwSPIVersion) { switch (dwAPIVersion) { case TAPI_VERSION_CURRENT: case TAPI_VERSION3_0: case TAPI_VERSION2_2: case TAPI_VERSION2_1: case TAPI_VERSION2_0: case TAPI_VERSION1_4: case TAPI_VERSION1_0: return TRUE; default: break; } } return FALSE; } LONG GetLineVersions( PTLINECLIENT ptLineClient, LPDWORD lpdwAPIVersion, LPDWORD lpdwSPIVersion ) { *lpdwAPIVersion = ptLineClient->dwAPIVersion; *lpdwSPIVersion = ptLineClient->ptLine->dwSPIVersion; if (ptLineClient->dwKey != TLINECLIENT_KEY) { return LINEERR_INVALLINEHANDLE; } return 0; } BOOL InitTapiStruct( LPVOID pTapiStruct, DWORD dwTotalSize, DWORD dwFixedSize, BOOL bZeroInit ) { // // Verify there's space enough for fixed data // if (dwTotalSize < dwFixedSize) { return FALSE; } // // Init the dwTotalSize as specified, then init the dwUsedSize and // dwNeededSize fields as the fixed size of the structure (saves the // SP some work if it's not planning on adding any of it's own // varible-length data to the structure) // *((LPDWORD) pTapiStruct) = dwTotalSize; *(((LPDWORD) pTapiStruct) + 1) = *(((LPDWORD) pTapiStruct) + 2) = dwFixedSize; // // Now zero out the rest of the buffer if the caller wants us to // if (bZeroInit) { ZeroMemory( ((LPDWORD) pTapiStruct) + 3, dwTotalSize - 3 * sizeof (DWORD) ); } return TRUE; } #if DBG BOOL IsBadSizeOffset( DWORD dwTotalSize, DWORD dwFixedSize, DWORD dwXxxSize, DWORD dwXxxOffset, DWORD dwAlignMask, char *pszCallingFunc, char *pszFieldName ) #else BOOL IsBadSizeOffset( DWORD dwTotalSize, DWORD dwFixedSize, DWORD dwXxxSize, DWORD dwXxxOffset, DWORD dwAlignMask ) #endif { if (dwXxxSize != 0) { DWORD dwSum = dwXxxSize + dwXxxOffset; if ((dwAlignMask == 2) || (dwAlignMask == 4) || (dwAlignMask == 8)) { dwAlignMask--; if (dwAlignMask & dwXxxOffset) { return TRUE; } } if (dwXxxOffset < dwFixedSize) { #if DBG LOG((TL_INFO, "%s: dw%sOffset (=x%x) points at fixed portion (=x%x)" \ " of structure", pszCallingFunc, pszFieldName, dwXxxSize, dwFixedSize )); #else LOG((TL_INFO, "Offset (=x%x) points at fixed portion (=x%x)" \ " of structure", dwXxxSize, dwFixedSize )); #endif return TRUE; } else if ((dwSum > dwTotalSize) || (dwSum < dwXxxSize)) { #if DBG LOG((TL_INFO, "%s: sum of dw%sSize/Offset (=x%x/x%x) > dwTotalSize (=x%x)", pszCallingFunc, pszFieldName, dwXxxSize, dwXxxOffset, dwFixedSize, dwTotalSize )); #endif return TRUE; } } return FALSE; } BOOL IsBadStringParam( DWORD dwParamsBufferSize, LPBYTE pDataBuf, DWORD dwStringOffset ) { WCHAR *p; DWORD dwCharsLeft; // // Check if offset is not WCHAR-aligned or if offset lies outside buffer // if ((dwStringOffset & 1) || (dwStringOffset >= dwParamsBufferSize)) { return TRUE; } // // Ensure we have read access // if (IsBadReadPtr(pDataBuf + dwStringOffset, dwParamsBufferSize - dwStringOffset)) { return TRUE; } // // Walk the string & make sure it's NULL-terminated within the buffer // dwCharsLeft = (dwParamsBufferSize - dwStringOffset) / sizeof (WCHAR); for( p = (WCHAR *) (pDataBuf + dwStringOffset); dwCharsLeft && *p; dwCharsLeft--, p++ ); return (dwCharsLeft ? FALSE : TRUE); } BOOL IsBadStructParam( DWORD dwParamsBufferSize, LPBYTE pDataBuf, DWORD dwXxxOffset ) { DWORD dwTotalSize; if ((dwXxxOffset & 0x3) || (dwParamsBufferSize < sizeof (DWORD)) || (dwXxxOffset >= (dwParamsBufferSize - sizeof (DWORD)))) { return TRUE; } // // Ensure we have read access // if (IsBadReadPtr(pDataBuf + dwXxxOffset, dwParamsBufferSize - dwXxxOffset)) { return TRUE; } dwTotalSize = *((LPDWORD) (pDataBuf + dwXxxOffset)); if (dwTotalSize > (dwParamsBufferSize - dwXxxOffset)) { return TRUE; } return FALSE; } LONG PASCAL ValidateCallParams( LPLINECALLPARAMS pCallParamsApp, LPLINECALLPARAMS *ppCallParamsSP, DWORD dwAPIVersion, DWORD dwSPIVersion, DWORD dwAsciiCallParamsCodePage ) { // // This routine checks the fields in a LINECALLPARAMS struct, // looking for invalid bit flags and making sure that the // various size/offset pairs only reference data within the // variable-data portion of the structure. Also, if the // specified SPI version is greater than the API version and // the fixed structure size differs between the two versions, // a larger buffer is allocated, the var data is relocated, // and the sizeof/offset pairs are patched. // char szFunc[] = "ValidateCallParams"; DWORD dwTotalSize = pCallParamsApp->dwTotalSize, dwFixedSizeApp, dwFixedSizeSP, dwAllBearerModes, dwAllMediaModes, dwAllCallParamFlags; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwFixedSizeApp = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) dwAllMediaModes = AllMediaModes1_0; // // HotFax v1.0 may be hot, but it's not real smart. It's // negotating an API ver == 0x10003, and subsequently tries // to sneak in a v1.4 bearer mode (PASSTHROUGH). We'll // allow for it this time... // //dwAllBearerModes = AllBearerModes1_0; dwAllBearerModes = AllBearerModes1_4; // HACK - see above dwAllCallParamFlags = AllCallParamFlags1_0; break; case TAPI_VERSION1_4: dwFixedSizeApp = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) dwAllMediaModes = AllMediaModes1_4; dwAllBearerModes = AllBearerModes1_4; dwAllCallParamFlags = AllCallParamFlags1_0; break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeApp = 176; // 40 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) dwAllMediaModes = AllMediaModes2_1; dwAllBearerModes = AllBearerModes2_0; dwAllCallParamFlags = AllCallParamFlags2_0; break; case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT: dwFixedSizeApp = sizeof (LINECALLPARAMS); dwAllMediaModes = AllMediaModes2_1; dwAllBearerModes = AllBearerModes2_0; dwAllCallParamFlags = AllCallParamFlags2_0; break; default: return LINEERR_OPERATIONFAILED; } switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 112; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeSP = 176; // 40 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) break; case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLPARAMS); break; default: return LINEERR_OPERATIONFAILED; } if (dwTotalSize < dwFixedSizeApp) { LOG((TL_ERROR, "%sbad dwTotalSize, x%x (minimum valid size=x%x)", szFunc, dwTotalSize, dwFixedSizeApp )); return LINEERR_STRUCTURETOOSMALL; } if (pCallParamsApp->dwBearerMode) { // // Allow 1.x apps to pass >=1 valid bearer modes to 1.x service // providers for backwards compatiblity, but enforce a single // valid bearer mode for newer apps and/or service providers // if ((dwAPIVersion >= TAPI_VERSION2_0) || (dwSPIVersion >= TAPI_VERSION2_0)) { if (!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwBearerMode) || (pCallParamsApp->dwBearerMode & ~dwAllBearerModes)) { bad_bearer_mode: LOG((TL_ERROR, "%sbad dwBearerMode, x%x", szFunc, pCallParamsApp->dwBearerMode )); return LINEERR_INVALBEARERMODE; } } else { if (pCallParamsApp->dwBearerMode & ~dwAllBearerModes) { goto bad_bearer_mode; } else if (!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwBearerMode)) { LOG((TL_ERROR, "%sbad dwBearerMode, x%x, allowed for 1.x apps/SPs", szFunc, pCallParamsApp->dwBearerMode )); } } } else { // // For clarity's sake reset 0 bearer mode to VOICE // pCallParamsApp->dwBearerMode = LINEBEARERMODE_VOICE; } { DWORD dwMediaModeApp = pCallParamsApp->dwMediaMode; if ((dwMediaModeApp & (0x00ffffff ^ dwAllMediaModes)) || // single media mode is version is less <= 2.1 ( (dwAPIVersion <= TAPI_VERSION2_1) && !IsOnlyOneBitSetInDWORD (dwMediaModeApp) && !(dwMediaModeApp & LINEMEDIAMODE_UNKNOWN) ) ) { // // For clarity's sake reset 0 media mode to INTERACTIVEVOICE // if (dwMediaModeApp == 0) { pCallParamsApp->dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE; } else { LOG((TL_ERROR, "%sbad dwMediaMode, x%x", szFunc, dwMediaModeApp)); return LINEERR_INVALMEDIAMODE; } } } if (pCallParamsApp->dwCallParamFlags & ~dwAllCallParamFlags) { LOG((TL_ERROR, "%sbad dwCallParamFlags, x%x", szFunc, pCallParamsApp->dwCallParamFlags )); return LINEERR_INVALCALLPARAMS; } // // Note: an address mode of 0 means "default to any address, // don't select a specific address" (says TNixon) // if (pCallParamsApp->dwAddressMode == LINEADDRESSMODE_ADDRESSID || pCallParamsApp->dwAddressMode == LINEADDRESSMODE_DIALABLEADDR) { // do nothing (it's a valid addr mode) } else if (pCallParamsApp->dwAddressMode == 0) { // // For clarity's sake reset 0 addr mode to ADDRESSID // pCallParamsApp->dwAddressMode = LINEADDRESSMODE_ADDRESSID; } else { LOG((TL_ERROR, "%sbad dwAddressMode, x%x", szFunc, pCallParamsApp->dwAddressMode )); return LINEERR_INVALADDRESSMODE; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwOrigAddressSize, pCallParamsApp->dwOrigAddressOffset, (!guiAlignmentFaultEnabled) ? 0 : ((pCallParamsApp->dwAddressMode & LINEADDRESSMODE_DIALABLEADDR) ? sizeof(TCHAR) : sizeof(DWORD)), szFunc, "OrigAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwUserUserInfoSize, pCallParamsApp->dwUserUserInfoOffset, guiAlignmentFaultEnabled? sizeof(TCHAR) : 0, szFunc, "UserUserInfo" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwHighLevelCompSize, pCallParamsApp->dwHighLevelCompOffset, 0, szFunc, "HighLevelComp" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwLowLevelCompSize, pCallParamsApp->dwLowLevelCompOffset, 0, szFunc, "LowLevelComp" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDevSpecificSize, pCallParamsApp->dwDevSpecificOffset, 0, szFunc, "DevSpecificSize" )) { return LINEERR_INVALCALLPARAMS; } // // The following is an attempt to compensate for 1.x tapi apps // that borrowed dialer.exe's source code and package their // call params incorrectly. The fix is to zero the offending // dwXxxSize/Offset pair of the various information-only fields, // so at worst some logging info will be lost, but the app will // still be able to make calls. (Failure to correctly package // any of the above var-length fields is considered "fatal" in // any case.) // if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDisplayableAddressSize, pCallParamsApp->dwDisplayableAddressOffset, guiAlignmentFaultEnabled? sizeof(TCHAR) : 0, szFunc, "DisplayableAddress" )) { if (dwAPIVersion < TAPI_VERSION2_0) { pCallParamsApp->dwDisplayableAddressSize = pCallParamsApp->dwDisplayableAddressOffset = 0; } else { return LINEERR_INVALCALLPARAMS; } } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCalledPartySize, pCallParamsApp->dwCalledPartyOffset, guiAlignmentFaultEnabled? sizeof(TCHAR) : 0, szFunc, "CalledParty" )) { if (dwAPIVersion < TAPI_VERSION2_0) { pCallParamsApp->dwCalledPartySize = pCallParamsApp->dwCalledPartyOffset = 0; } else { return LINEERR_INVALCALLPARAMS; } } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCommentSize, pCallParamsApp->dwCommentOffset, guiAlignmentFaultEnabled? sizeof(TCHAR) : 0, szFunc, "Comment" )) { if (dwAPIVersion < TAPI_VERSION2_0) { pCallParamsApp->dwCommentSize = pCallParamsApp->dwCommentOffset = 0; } else { return LINEERR_INVALCALLPARAMS; } } if (dwAPIVersion <= TAPI_VERSION1_4) { goto ValidateCallParams_checkFixedSizes; } #define AllCallStates \ (LINECALLSTATE_IDLE | \ LINECALLSTATE_OFFERING | \ LINECALLSTATE_ACCEPTED | \ LINECALLSTATE_DIALTONE | \ LINECALLSTATE_DIALING | \ LINECALLSTATE_RINGBACK | \ LINECALLSTATE_BUSY | \ LINECALLSTATE_SPECIALINFO | \ LINECALLSTATE_CONNECTED | \ LINECALLSTATE_PROCEEDING | \ LINECALLSTATE_ONHOLD | \ LINECALLSTATE_CONFERENCED | \ LINECALLSTATE_ONHOLDPENDCONF | \ LINECALLSTATE_ONHOLDPENDTRANSFER | \ LINECALLSTATE_DISCONNECTED | \ LINECALLSTATE_UNKNOWN) if (pCallParamsApp->dwPredictiveAutoTransferStates & ~AllCallStates) { LOG((TL_ERROR, "%sbad dwPredictiveAutoTransferStates, x%x", szFunc, pCallParamsApp->dwPredictiveAutoTransferStates )); return LINEERR_INVALCALLPARAMS; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwTargetAddressSize, pCallParamsApp->dwTargetAddressOffset, guiAlignmentFaultEnabled? sizeof(TCHAR) : 0, szFunc, "TargetAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwSendingFlowspecSize, pCallParamsApp->dwSendingFlowspecOffset, guiAlignmentFaultEnabled? sizeof(DWORD) : 0, szFunc, "SendingFlowspec" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwReceivingFlowspecSize, pCallParamsApp->dwReceivingFlowspecOffset, guiAlignmentFaultEnabled? sizeof(DWORD) : 0, szFunc, "ReceivingFlowspec" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDeviceClassSize, pCallParamsApp->dwDeviceClassOffset, 0, szFunc, "DeviceClass" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDeviceConfigSize, pCallParamsApp->dwDeviceConfigOffset, 0, szFunc, "DeviceConfig" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCallDataSize, pCallParamsApp->dwCallDataOffset, 0, szFunc, "CallData" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCallingPartyIDSize, pCallParamsApp->dwCallingPartyIDOffset, 0, szFunc, "CallingPartyID" )) { return LINEERR_INVALCALLPARAMS; } if (dwAPIVersion < TAPI_VERSION3_0) { goto ValidateCallParams_checkFixedSizes; } if (pCallParamsApp->dwAddressType == 0) { // pCallParamsApp->dwAddressType = LINEADDRESSTYPE_PHONENUMBER; } else if ((pCallParamsApp->dwAddressType & ~AllAddressTypes) || !IsOnlyOneBitSetInDWORD (pCallParamsApp->dwAddressType)) { LOG((TL_ERROR, "%sbad dwAddressType, x%x", szFunc, pCallParamsApp->dwAddressType )); return LINEERR_INVALCALLPARAMS; } ValidateCallParams_checkFixedSizes: if (dwAsciiCallParamsCodePage == TAPI_NO_DATA) { // // If here we're getting unicode call params from the app // // Check to see if the fixed size of the app's call params // are smaller than the fixed size of the call params // required by the service provider (due to it's negotiated // SPI version), and if so alloc a larger buffer to account // for this different fixed size & set it up correctly // if (dwFixedSizeApp < dwFixedSizeSP) { DWORD dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp; LPLINECALLPARAMS pCallParamsSP; if (!(pCallParamsSP = ServerAlloc (dwTotalSize + dwFixedSizeDiff))) { return LINEERR_NOMEM; } CopyMemory (pCallParamsSP, pCallParamsApp, dwFixedSizeApp); pCallParamsSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff; CopyMemory( ((LPBYTE) pCallParamsSP) + dwFixedSizeSP, ((LPBYTE) pCallParamsApp) + dwFixedSizeApp, dwTotalSize - dwFixedSizeApp ); if (pCallParamsSP->dwOrigAddressOffset) { pCallParamsSP->dwOrigAddressOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwDisplayableAddressOffset) { pCallParamsSP->dwDisplayableAddressOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwCalledPartyOffset) { pCallParamsSP->dwCalledPartyOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwCommentOffset) { pCallParamsSP->dwCommentOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwUserUserInfoOffset) { pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwHighLevelCompOffset) { pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwLowLevelCompOffset) { pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwDevSpecificOffset) { pCallParamsSP->dwDevSpecificOffset += dwFixedSizeDiff; } if (dwAPIVersion >= TAPI_VERSION2_0) { if (pCallParamsSP->dwTargetAddressOffset) { pCallParamsSP->dwTargetAddressOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwSendingFlowspecOffset) { pCallParamsSP->dwSendingFlowspecOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwReceivingFlowspecOffset) { pCallParamsSP->dwReceivingFlowspecOffset +=dwFixedSizeDiff; } if (pCallParamsSP->dwDeviceClassOffset) { pCallParamsSP->dwDeviceClassOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwDeviceConfigOffset) { pCallParamsSP->dwDeviceConfigOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwCallDataOffset) { pCallParamsSP->dwCallDataOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwCallingPartyIDOffset) { pCallParamsSP->dwCallingPartyIDOffset += dwFixedSizeDiff; } } *ppCallParamsSP = pCallParamsSP; } else { *ppCallParamsSP = pCallParamsApp; } } else // see if there's ascii var data fields to translate { // // If here we're getting ascii call params form the app // // We may need to due ascii -> unicode conversions on some // of the var fields, as well as account for differences // in the fixed sizes of the call params structs as described // above // DWORD dwAsciiVarDataSize, dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp; dwAsciiVarDataSize = pCallParamsApp->dwOrigAddressSize + pCallParamsApp->dwDisplayableAddressSize + pCallParamsApp->dwCalledPartySize + pCallParamsApp->dwCommentSize; if (dwAPIVersion > TAPI_VERSION1_4) { dwAsciiVarDataSize += pCallParamsApp->dwTargetAddressSize + pCallParamsApp->dwDeviceClassSize + pCallParamsApp->dwCallingPartyIDSize; } if (dwFixedSizeDiff != 0 || dwAsciiVarDataSize != 0) { LPLINECALLPARAMS pCallParamsSP; // alloc 3 extra for alignment if (!(pCallParamsSP = ServerAlloc( dwTotalSize + dwFixedSizeDiff + 2 * dwAsciiVarDataSize + 3 ))) { return LINEERR_NOMEM; } if (dwFixedSizeDiff) { CopyMemory (pCallParamsSP, pCallParamsApp, dwFixedSizeApp); CopyMemory( ((LPBYTE) pCallParamsSP) + dwFixedSizeSP, ((LPBYTE) pCallParamsApp) + dwFixedSizeApp, dwTotalSize - dwFixedSizeApp ); if (pCallParamsSP->dwUserUserInfoOffset) { pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwHighLevelCompOffset) { pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwLowLevelCompOffset) { pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwDevSpecificOffset) { pCallParamsSP->dwDevSpecificOffset += dwFixedSizeDiff; } if (dwAPIVersion >= TAPI_VERSION2_0) { if (pCallParamsSP->dwSendingFlowspecOffset) { pCallParamsSP->dwSendingFlowspecOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwReceivingFlowspecOffset) { pCallParamsSP->dwReceivingFlowspecOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwDeviceConfigOffset) { pCallParamsSP->dwDeviceConfigOffset += dwFixedSizeDiff; } if (pCallParamsSP->dwCallDataOffset) { pCallParamsSP->dwCallDataOffset += dwFixedSizeDiff; } } } else { CopyMemory (pCallParamsSP, pCallParamsApp, dwTotalSize); } pCallParamsSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff + 2*dwAsciiVarDataSize + 3; if (dwAsciiVarDataSize) { LPDWORD alpdwXxxSize[] = { &pCallParamsSP->dwOrigAddressSize, &pCallParamsSP->dwDisplayableAddressSize, &pCallParamsSP->dwCalledPartySize, &pCallParamsSP->dwCommentSize, (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwTargetAddressSize : NULL), (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwDeviceClassSize : NULL), (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwCallingPartyIDSize : NULL), NULL }; // align dwXxxOffset DWORD i, dwXxxOffset = (dwTotalSize + dwFixedSizeDiff + 3) & 0xFFFFFFFC; for (i = 0; alpdwXxxSize[i]; i++) { if (*alpdwXxxSize[i] != 0) { MultiByteToWideChar( (UINT) dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pCallParamsApp) + *(alpdwXxxSize[i] + 1)), // dwXxxOffset *alpdwXxxSize[i], (LPWSTR) (((LPBYTE) pCallParamsSP) + dwXxxOffset), *alpdwXxxSize[i] ); *(alpdwXxxSize[i] + 1) = dwXxxOffset; *alpdwXxxSize[i] *= 2; dwXxxOffset += *alpdwXxxSize[i]; } } } *ppCallParamsSP = pCallParamsSP; } else { *ppCallParamsSP = pCallParamsApp; } } return 0; // success } void PASCAL InsertVarData( LPVOID lpXxx, LPDWORD pdwXxxSize, LPVOID *pData, DWORD dwDataSize ) { DWORD dwAlignedSize, dwUsedSize; LPVARSTRING lpVarString = (LPVARSTRING) lpXxx; if (dwDataSize != 0) { // // Align var data on 64-bit boundaries // if ((dwAlignedSize = dwDataSize) & 7) { dwAlignedSize += 8; dwAlignedSize &= 0xfffffff8; } // // The following if statement should only be TRUE the first time // we're inserting data into a given structure that does not have // an even number of DWORD fields // if ((dwUsedSize = lpVarString->dwUsedSize) & 7) { dwUsedSize += 8; dwUsedSize &= 0xfffffff8; lpVarString->dwNeededSize += dwUsedSize - lpVarString->dwUsedSize; } lpVarString->dwNeededSize += dwAlignedSize; if ((dwUsedSize + dwAlignedSize) <= lpVarString->dwTotalSize) { CopyMemory( ((LPBYTE) lpVarString) + dwUsedSize, pData, dwDataSize ); *pdwXxxSize = dwDataSize; pdwXxxSize++; // pdwXxxSize = pdwXxxOffset *pdwXxxSize = dwUsedSize; lpVarString->dwUsedSize = dwUsedSize + dwAlignedSize; } } } PTLINELOOKUPENTRY GetLineLookupEntry( DWORD dwDeviceID ) { DWORD dwDeviceIDBase = 0; PTLINELOOKUPTABLE pLookupTable = TapiGlobals.pLineLookup; if (dwDeviceID >= TapiGlobals.dwNumLines) { return ((PTLINELOOKUPENTRY) NULL); } while (pLookupTable) { if (dwDeviceID < pLookupTable->dwNumTotalEntries) { return (pLookupTable->aEntries + dwDeviceID); } dwDeviceID -= pLookupTable->dwNumTotalEntries; pLookupTable = pLookupTable->pNext; } return ((PTLINELOOKUPENTRY) NULL); } BOOL PASCAL IsValidLineExtVersion( DWORD dwDeviceID, DWORD dwExtVersion ) { BOOL bResult; PTLINE ptLine; PTPROVIDER ptProvider; PTLINELOOKUPENTRY pLookupEntry; if (dwExtVersion == 0) { return TRUE; } if (!(pLookupEntry = GetLineLookupEntry (dwDeviceID))) { return FALSE; } ptLine = pLookupEntry->ptLine; if (ptLine) { try { if (ptLine->dwExtVersionCount) { bResult = (dwExtVersion == ptLine->dwExtVersion ? TRUE : FALSE); if (ptLine->dwKey == TLINE_KEY) { goto IsValidLineExtVersion_return; } } } myexcept { // // if here the line was closed, just drop thru to the code below // } } ptProvider = pLookupEntry->ptProvider; if (ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION]) { LONG lResult; DWORD dwNegotiatedExtVersion; lResult = CallSP5( ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION], "lineNegotiateExtVersion", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pLookupEntry->dwSPIVersion, (DWORD) dwExtVersion, (DWORD) dwExtVersion, (ULONG_PTR) &dwNegotiatedExtVersion ); bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE); } else { bResult = FALSE; } IsValidLineExtVersion_return: return bResult; } PTCALLCLIENT PASCAL ReferenceCall( HCALL hCall, PTCLIENT ptClient ) { PTCALLCLIENT ptCallClient; if ((ptCallClient = ReferenceObject( ghHandleTable, hCall, TCALLCLIENT_KEY ))) { if (ptCallClient->ptClient != ptClient) { DereferenceObject (ghHandleTable, hCall, 1); ptCallClient = NULL; } } return ptCallClient; } PTCALLHUBCLIENT PASCAL IsValidCallHub( HCALLHUB hCallHub, PTCLIENT ptClient ) { PTCALLHUBCLIENT ptCallHubClient = NULL; if (hCallHub == 0) { goto ExitHere; } try { ptCallHubClient = ReferenceObject ( ghHandleTable, hCallHub, TCALLHUBCLIENT_KEY); if (ptCallHubClient) { if ((ptCallHubClient->ptClient != ptClient) || (ptCallHubClient->hCallHub != hCallHub)) { ptCallHubClient = NULL; } DereferenceObject(ghHandleTable, hCallHub, 1); } } myexcept { } ExitHere: return ptCallHubClient; } PTLINEAPP PASCAL IsValidLineApp( HLINEAPP hLineApp, PTCLIENT ptClient ) { PTLINEAPP ptLineApp; if ((ptLineApp = ReferenceObject (ghHandleTable, hLineApp, TLINEAPP_KEY))) { if (ptLineApp->ptClient != ptClient) { ptLineApp = NULL; } DereferenceObject (ghHandleTable, hLineApp, 1); } return ptLineApp; } BOOL PASCAL WaitForExclusivetCallAccess( PTCALL ptCall, DWORD dwKey ) { // // Retrieve the call instance & check the key to make sure it's // really a tCall object, then wait for exclusive access, then // reverify the key and the call instance (it's possible the tCall // object might have been freed & reallocated while we were waiting, // in which case it will have come back to life with a different // dwCallInstance value) // BOOL bUnlock = FALSE; try { HCALL hCall = ptCall->hCall; if (ptCall->dwKey == dwKey) { LOCKTCALL (ptCall); bUnlock = TRUE; if (ptCall->dwKey == dwKey && ptCall->hCall == hCall) { return TRUE; } } } myexcept { // just fall thru } if (bUnlock) { UNLOCKTCALL (ptCall); } return FALSE; } BOOL PASCAL WaitForExclusivetLineAccess( PTLINE ptLine, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { BOOL bResult = FALSE; try { if (ptLine->dwKey == TLINE_KEY && WaitForMutex( ptLine->hMutex, phMutex, pbDupedMutex, (LPVOID) ptLine, TLINE_KEY, dwTimeout )) { if (ptLine->dwKey == TLINE_KEY) { bResult = TRUE; } else { MyReleaseMutex (*phMutex, *pbDupedMutex); } } } myexcept { // do nothing } return bResult; } BOOL PASCAL WaitForExclusiveLineClientAccess( PTLINECLIENT ptLineClient ) { // // Assumes ptXxxClient->hXxx has already been referenced, // so we can safely access ptXxxClient // LOCKTLINECLIENT (ptLineClient); if (ptLineClient->dwKey == TLINECLIENT_KEY) { return TRUE; } UNLOCKTLINECLIENT (ptLineClient); return FALSE; } PTLINEAPP PASCAL WaitForExclusiveLineAppAccess( HLINEAPP hLineApp, PTCLIENT ptClient ) { PTLINEAPP ptLineApp; if (!(ptLineApp = ReferenceObject( ghHandleTable, hLineApp, TLINEAPP_KEY ))) { return NULL; } LOCKTLINEAPP (ptLineApp); if ((ptLineApp->dwKey != TLINEAPP_KEY) || (ptLineApp->ptClient != ptClient)) { UNLOCKTLINEAPP (ptLineApp); ptLineApp = NULL; } DereferenceObject (ghHandleTable, hLineApp, 1); return ptLineApp; } PTCLIENT PASCAL WaitForExclusiveClientAccess( PTCLIENT ptClient ) { LOCKTCLIENT (ptClient); try { if (ptClient->dwKey == TCLIENT_KEY) { return (ptClient); } } myexcept { } UNLOCKTCLIENT (ptClient); return NULL; } LONG PASCAL FindProxy( PTLINECLIENT ptLineClient, DWORD dwAddressID, DWORD dwRequestType, PTLINECLIENT *ppProxy, LPDWORD lpdwDeviceID, DWORD dwMinAPIVersion ) { LONG lResult; PTLINE ptLine; try { if (ptLineClient->ptLineApp->dwAPIVersion >= dwMinAPIVersion) { ptLine = ptLineClient->ptLine; *ppProxy = ptLine->apProxys[dwRequestType]; *lpdwDeviceID = ptLine->dwDeviceID; if (dwAddressID >= ptLine->dwNumAddresses) { lResult = LINEERR_INVALADDRESSID; } else if (ptLine->dwKey != TLINE_KEY) { lResult = LINEERR_INVALLINEHANDLE; } else { lResult = 0; } } else { lResult = LINEERR_INCOMPATIBLEAPIVERSION; } } myexcept { lResult = LINEERR_OPERATIONUNAVAIL; } return lResult; } LONG PASCAL CreateProxyRequest( PTLINECLIENT pProxy, DWORD dwRequestType, DWORD dwExtraBytes, PASYNCREQUESTINFO pAsyncReqInfo, PPROXYREQUESTWRAPPER *ppWrapper ) { HLINE hLine; DWORD dwSize, dwComputerNameSize, dwUserNameSize; PTCLIENT ptClient = pAsyncReqInfo->ptClient; DWORD initContext, openContext; PPROXYREQUESTWRAPPER pWrapper; LOG((TL_TRACE, "CreateProxyRequest: enter...")); // // Safely get info from the proxy, then make sure it's still valid // if the proxy is refusing LINE_PROXYREQUEST msg, return failure // try { hLine = pProxy->hLine; initContext = pProxy->ptLineApp->InitContext; openContext = pProxy->OpenContext; if (pProxy->dwKey != TLINECLIENT_KEY || (FMsgDisabled( pProxy->ptLineApp->dwAPIVersion, pProxy->adwEventSubMasks, LINE_PROXYREQUEST, 0))) { return LINEERR_OPERATIONUNAVAIL; } } myexcept { return LINEERR_OPERATIONUNAVAIL; } dwComputerNameSize = (ptClient->dwComputerNameSize + TALIGN_COUNT) & TALIGN_MASK; dwUserNameSize = (ptClient->dwUserNameSize + TALIGN_COUNT) & TALIGN_MASK; // // Calculate, alloc, & initalize a PROXYREQUESTWRAPPER struct. At the // head of this struct is the msg info for the LINE_PROXYREQUEST, // followed by the actual request data. // dwSize = (sizeof (ASYNCEVENTMSG) + // LINE_PROXYREQUEST msg info 7 * sizeof (DWORD) + // Non-union fields in LINEPROXYREQUEST dwExtraBytes + // Request-specific size dwUserNameSize + // User name size dwComputerNameSize + // Computer name size TALIGN_COUNT) & TALIGN_MASK;// make sure size is a ULONG_PTR multiple // so our lstrcpyW's below don't fault // and so that when this msg eventually // gets copied to some client's async // event buf we don't start running into // alignment problems (the msgs's // TotalSize field must be ULONG_PTR- // aligned) if (!(pWrapper = ServerAlloc (dwSize))) { return LINEERR_NOMEM; } pWrapper->AsyncEventMsg.TotalSize = dwSize; pWrapper->AsyncEventMsg.InitContext = initContext; //pWrapper->AsyncEventMsg.hfnPostProcessProc = pWrapper->AsyncEventMsg.hDevice = pProxy->hLine; pWrapper->AsyncEventMsg.Msg = LINE_PROXYREQUEST; pWrapper->AsyncEventMsg.OpenContext = openContext; pWrapper->AsyncEventMsg.Param1 = pAsyncReqInfo->dwLocalRequestID; //pWrapper->AsyncEventMsg.Param2 = //pWrapper->AsyncEventMsg.Param3 = //pWrapper->AsyncEventMsg.Param4 = dwSize -= sizeof (ASYNCEVENTMSG); pWrapper->ProxyRequest.dwSize = dwSize; pWrapper->ProxyRequest.dwClientMachineNameSize = ptClient->dwComputerNameSize; pWrapper->ProxyRequest.dwClientMachineNameOffset = dwSize - dwComputerNameSize; if (NULL != ptClient->pszComputerName) { wcscpy( (PWSTR)((LPBYTE) &pWrapper->ProxyRequest + pWrapper->ProxyRequest.dwClientMachineNameOffset), ptClient->pszComputerName ); } pWrapper->ProxyRequest.dwClientUserNameSize = ptClient->dwUserNameSize; pWrapper->ProxyRequest.dwClientUserNameOffset = (dwSize - dwComputerNameSize) - dwUserNameSize; if (NULL != ptClient->pszUserName) { wcscpy( (PWSTR)((LPBYTE) &pWrapper->ProxyRequest + pWrapper->ProxyRequest.dwClientUserNameOffset), ptClient->pszUserName ); } pWrapper->ProxyRequest.dwClientAppAPIVersion = 0; pWrapper->ProxyRequest.dwRequestType = dwRequestType; *ppWrapper = pWrapper; // // Change the AsyncRequestInfo struct's key value to be == // the proxy's hLine, so we can verify when app calls // lineProxyResponse // pAsyncReqInfo->dwKey = hLine; return 0; } LONG PASCAL SendProxyRequest( PTLINECLIENT pProxy, PPROXYREQUESTWRAPPER pWrapper, PASYNCREQUESTINFO pAsyncRequestInfo ) { LONG lResult; BOOL bUnlock = FALSE; // // Add the request to the proxy's list, then send it the request. // Since the proxy (tLineClient) could get closed at any time we // wrap the following in a try/except. // // Note: the AsyncReqInfo.dwParam4 & dwParam5 fields are used as // the prev & next pointers for maintaining the list of proxy // requests pending on tLineClient. // try { if (WaitForExclusiveLineClientAccess (pProxy)) { bUnlock = TRUE; if ((pAsyncRequestInfo->dwParam5 = (ULONG_PTR) pProxy->pPendingProxyRequests)) { ((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5)->dwParam4 = (ULONG_PTR) pAsyncRequestInfo; } pProxy->pPendingProxyRequests = pAsyncRequestInfo; UNLOCKTLINECLIENT (pProxy); bUnlock = FALSE; WriteEventBuffer (pProxy->ptClient, (PASYNCEVENTMSG) pWrapper); lResult = 0; } else { lResult = LINEERR_OPERATIONUNAVAIL; } } myexcept { lResult = LINEERR_OPERATIONUNAVAIL; } if (bUnlock) { UNLOCKTLINECLIENT (pProxy); } ServerFree (pWrapper); return lResult; } BOOL PASCAL NotifyHighestPriorityRequestRecipient( void ) { // // Send a LINE_REQUEST msg to the highest priority request recipient // to inform it that there are requests available for processing // PTLINEAPP ptLineApp; ASYNCEVENTMSG msg; LOG((TL_TRACE, "NotifyHighestPriorityRequestRecipient: enter...")); EnterCriticalSection (&gPriorityListCritSec); ptLineApp = TapiGlobals.pHighestPriorityRequestRecipient->ptLineApp; msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.InitContext = ptLineApp->InitContext; msg.fnPostProcessProcHandle = 0; msg.hDevice = 0; msg.Msg = LINE_REQUEST; msg.OpenContext = (TapiGlobals.pHighestPriorityRequestRecipient->dwRegistrationInstance); msg.Param1 = LINEREQUESTMODE_MAKECALL; msg.Param2 = msg.Param3 = 0; WriteEventBuffer (ptLineApp->ptClient, &msg); LeaveCriticalSection (&gPriorityListCritSec); LOG((TL_TRACE, "NotifyHighestPriorityRequestRecipient: finished.")); return TRUE; } void SetDrvCallFlags( HCALL hCall, DWORD dwDrvCallFlags ) { // // This func is called on return from TSPI_lineMakeCall (and other // TSPI_lineXxx funcs where calls are created) and sets the // dwDrvCallFlags field in the tCall as specified. This keeps // another thread which is currently doing a DestroytCall on this // call from passing an invalid hdCall to the provider when // doing a TSPI_lineCloseCall. // // PTCALL ptCall; if (ptCall = ReferenceObject(ghHandleTable, hCall, 0)) { LOCKTCALL (ptCall); if ((ptCall->dwKey == TINCOMPLETECALL_KEY) || (ptCall->dwKey == TCALL_KEY) || (ptCall->dwKey == TZOMBIECALL_KEY)) { // only set the loword ptCall->dwDrvCallFlags = MAKELONG(LOWORD(dwDrvCallFlags), HIWORD(ptCall->dwDrvCallFlags)); } UNLOCKTCALL (ptCall); DereferenceObject(ghHandleTable, hCall, 1); } } LONG PASCAL SetCallConfList( PTCALL ptCall, PTCONFERENCELIST pConfList, BOOL bAddToConfPostProcess ) { LONG lResult; BOOL bAddToConfList = FALSE; if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { if (pConfList) { if (ptCall->pConfList && !bAddToConfPostProcess) { lResult = LINEERR_INVALCALLHANDLE; } else { ptCall->pConfList = pConfList; lResult = 0; bAddToConfList = TRUE; } } else { if (ptCall->pConfList) { pConfList = ptCall->pConfList; ptCall->pConfList = NULL; lResult = 0; } else { lResult = LINEERR_INVALCALLHANDLE; } } UNLOCKTCALL (ptCall); } else { lResult = LINEERR_INVALCALLHANDLE; } if (pConfList && (pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff) ) && (lResult == 0)) { if (bAddToConfList) { while (pConfList->dwNumUsedEntries >= pConfList->dwNumTotalEntries) { if (pConfList->pNext) { pConfList = pConfList->pNext; } else { DWORD dwSize; PTCONFERENCELIST pNewConfList; dwSize = sizeof (TCONFERENCELIST) + sizeof (PTCALL) * (2 * pConfList->dwNumTotalEntries - 1); if (!(pNewConfList = ServerAlloc (dwSize))) { ptCall->pConfList = NULL; return LINEERR_NOMEM; } pNewConfList->dwNumTotalEntries = 2 * pConfList->dwNumTotalEntries; pConfList->pNext = pNewConfList; pConfList = pNewConfList; } } pConfList->aptCalls[pConfList->dwNumUsedEntries++] = ptCall; } else { while (pConfList) { DWORD i, dwNumUsedEntries = pConfList->dwNumUsedEntries; PTCALL *pptCall = pConfList->aptCalls; for (i = 0; i < dwNumUsedEntries; i++) { if (pConfList->aptCalls[i] == ptCall) { // // Found the call in the list, shuffle all the // following calls in list down by 1 to maintain // continuity // for (; i < (dwNumUsedEntries - 1); i++) { pConfList->aptCalls[i] = pConfList->aptCalls[i+1]; } pConfList->dwNumUsedEntries--; pConfList = NULL; break; } pptCall++; } if (pConfList) { pConfList = pConfList->pNext; } } } } return lResult; } LONG PASCAL RemoveCallFromLineList( PTCALL ptCall ) { PTLINE ptLine = (PTLINE) ptCall->ptLine; WaitForSingleObject (ptLine->hMutex, INFINITE); if (ptCall->pNext) { ptCall->pNext->pPrev = ptCall->pPrev; } if (ptCall->pPrev) { ptCall->pPrev->pNext = ptCall->pNext; } else { ptLine->ptCalls = ptCall->pNext; } ReleaseMutex (ptLine->hMutex); return 0; } LONG PASCAL RemoveCallClientFromLineClientList( PTCALLCLIENT ptCallClient ) { PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; LOCKTLINECLIENT (ptLineClient); if (ptCallClient->pNextSametLineClient) { ptCallClient->pNextSametLineClient->pPrevSametLineClient = ptCallClient->pPrevSametLineClient; } if (ptCallClient->pPrevSametLineClient) { ptCallClient->pPrevSametLineClient->pNextSametLineClient = ptCallClient->pNextSametLineClient; } else { ptLineClient->ptCallClients = ptCallClient->pNextSametLineClient; } UNLOCKTLINECLIENT (ptLineClient); return 0; } LONG PASCAL GetConfCallListFromConf( PTCONFERENCELIST pConfList, PTPOINTERLIST *ppList ) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0, i; PTPOINTERLIST pList = *ppList; while (pConfList) { if ((dwNumUsedEntries + pConfList->dwNumUsedEntries) > dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; do { dwNumTotalEntries <<= 1; } while ((dwNumUsedEntries + pConfList->dwNumUsedEntries) > dwNumTotalEntries); if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } for (i = 0; i < pConfList->dwNumUsedEntries; i++) { pList->aEntries[dwNumUsedEntries++] = pConfList->aptCalls[i]; } pConfList = pConfList->pNext; } pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; return 0; } LONG PASCAL GetList( LIST_ENTRY *pListHead, PTPOINTERLIST *ppList ) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; LIST_ENTRY *pEntry; pEntry = pListHead->Flink; while (pEntry != pListHead) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = pEntry; pEntry = pEntry->Flink; } pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; return 0; } LONG PASCAL GetCallClientListFromCall( PTCALL ptCall, PTPOINTERLIST *ppList ) { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; PTCALLCLIENT ptCallClient = ptCall->ptCallClients; while (ptCallClient) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { UNLOCKTCALL (ptCall); return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = ptCallClient; ptCallClient = ptCallClient->pNextSametCall; } UNLOCKTCALL (ptCall); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { return LINEERR_INVALCALLHANDLE; } return 0; } LONG PASCAL GetCallListFromLine( PTLINE ptLine, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex; if (WaitForExclusivetLineAccess( ptLine, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTCALL ptCall = ptLine->ptCalls; PTPOINTERLIST pList = *ppList; while (ptCall) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { MyReleaseMutex (hMutex, bDupedMutex); return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = ptCall; ptCall = ptCall->pNext; } MyReleaseMutex (hMutex, bDupedMutex); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { LOG((TL_TRACE, "GetCallListFromLine: inval ptLine=x%p", ptLine)); return LINEERR_INVALLINEHANDLE; } return 0; } LONG PASCAL GetLineClientListFromLine( PTLINE ptLine, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex; if (WaitForExclusivetLineAccess( ptLine, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; PTLINECLIENT ptLineClient = ptLine->ptLineClients; while (ptLineClient) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { MyReleaseMutex (hMutex, bDupedMutex); return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = ptLineClient; ptLineClient = ptLineClient->pNextSametLine; } MyReleaseMutex (hMutex, bDupedMutex); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { LOG((TL_ERROR, "GetLineClientListFromLine: inval ptLine=x%p", ptLine)); return LINEERR_INVALLINEHANDLE; } return 0; } LONG PASCAL GetLineAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ) { if (WaitForExclusiveClientAccess (ptClient)) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTLINEAPP ptLineApp = ptClient->ptLineApps; PTPOINTERLIST pList = *ppList; while (ptLineApp) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { UNLOCKTCLIENT (ptClient); return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = ptLineApp; ptLineApp = ptLineApp->pNext; } UNLOCKTCLIENT (ptClient); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { return LINEERR_OPERATIONFAILED; } return 0; } LONG PASCAL GetClientList( BOOL bAdminOnly, PTPOINTERLIST *ppList ) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; PTCLIENT ptClient; TapiEnterCriticalSection (&TapiGlobals.CritSec); ptClient = TapiGlobals.ptClients; while (ptClient) { if (!bAdminOnly || IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { if (dwNumUsedEntries == dwNumTotalEntries) { // // We need a larger list, so alloc a new one, copy the // contents of the current one, and the free the current // one iff we previously alloc'd it // PTPOINTERLIST pNewList; dwNumTotalEntries <<= 1; if (!(pNewList = ServerAlloc( sizeof (TPOINTERLIST) + sizeof (LPVOID) * (dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES) ))) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); return LINEERR_NOMEM; } CopyMemory( pNewList->aEntries, pList->aEntries, dwNumUsedEntries * sizeof (LPVOID) ); if (pList != *ppList) { ServerFree (pList); } pList = pNewList; } pList->aEntries[dwNumUsedEntries++] = ptClient; } ptClient = ptClient->pNext; } TapiLeaveCriticalSection (&TapiGlobals.CritSec); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; return 0; } void PASCAL SendMsgToCallClients( PTCALL ptCall, PTCALLCLIENT ptCallClientToExclude, DWORD Msg, /* ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 */ DWORD Param1, DWORD Param2, DWORD Param3 ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg[2]; if (GetCallClientListFromCall (ptCall, &pClientList) != 0) { return; } msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB); msg->fnPostProcessProcHandle = 0; msg->Msg = Msg; msg->Param1 = Param1; msg->Param2 = Param2; msg->Param3 = Param3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTCALLCLIENT ptCallClient = pClientList->aEntries[i]; PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; if (ptCallClient == ptCallClientToExclude) { continue; } if (Msg == LINE_MONITORDIGITS) { if ((ptCallClient->dwMonitorDigitModes & Param2) == 0) { continue; } } else if (Msg == LINE_MONITORMEDIA) { // ULONG_PTR mediaModes = Param1; DWORD mediaModes = Param1; // // Munge the media modes so we don't pass unexpected flags // to old apps // if (ptLineClient->dwAPIVersion == TAPI_VERSION1_0) { if ((mediaModes & ~AllMediaModes1_0)) { mediaModes = (mediaModes & AllMediaModes1_0) | LINEMEDIAMODE_UNKNOWN; } } if (ptCallClient->dwMonitorMediaModes & mediaModes) { msg->Param1 = mediaModes; } else { continue; } } else if (Msg == LINE_MONITORTONE) { if (!ptCallClient->bMonitoringTones) { continue; } } else if (FMsgDisabled( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { continue; } msg->InitContext = ptLineClient->ptLineApp->InitContext; msg->hDevice = ptCallClient->hCall; msg->OpenContext = ptLineClient->OpenContext; // // Indicate the hRemoteLine in p4 to make life easier for remotesp // msg->Param4 = ptLineClient->hRemoteLine; *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClient->ptCallHubClient)? ptCallClient->ptCallHubClient->hCallHub : (HCALLHUB)0; ptClient = ptLineClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, msg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendBufferMsgToCallClients( PTCALL ptCall, PTCALLCLIENT ptCallClientToExclude, DWORD Msg, DWORD Param1, DWORD Size, LPBYTE pBuffer ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; PASYNCEVENTMSG pmsg; DWORD dwTotalSize = (sizeof (ASYNCEVENTMSG) + (DWORD) Size + TALIGN_COUNT) & TALIGN_MASK; if (!(pmsg = (ASYNCEVENTMSG *) ServerAlloc (dwTotalSize))) { return; } if (GetCallClientListFromCall (ptCall, &pClientList) != 0) { ServerFree( pmsg ); return; } pmsg->TotalSize = dwTotalSize; pmsg->fnPostProcessProcHandle = 0; pmsg->Msg = Msg; pmsg->Param2 = Size; pmsg->Param3 = 0; CopyMemory ((PBYTE)(pmsg+1), pBuffer, Size); for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTCALLCLIENT ptCallClient = pClientList->aEntries[i]; PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; if (ptCallClient == ptCallClientToExclude) { continue; } if (FMsgDisabled ( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { continue; } pmsg->Param1 = (DWORD) ptCallClient->hCall; pmsg->InitContext = ptLineClient->ptLineApp->InitContext; pmsg->hDevice = (DWORD) ptLineClient->hLine; pmsg->OpenContext = ptLineClient->OpenContext; // // Indicate the hRemoteLine in p4 to make life easier for remotesp // pmsg->Param4 = ptLineClient->hRemoteLine; ptClient = ptCallClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, pmsg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } ServerFree( pmsg ); } void PASCAL SendAMsgToAllLineApps( DWORD dwWantVersion, DWORD Msg, DWORD Param1, // ULONG_PTR Param1, DWORD Param2, // ULONG_PTR Param2 DWORD Param3 // ULONG_PTR Param3 ) { DWORD i, j; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG lineMsg; if (GetClientList (FALSE, &pClientList) != 0) { return; } ZeroMemory (&lineMsg, sizeof (ASYNCEVENTMSG)); lineMsg.TotalSize = sizeof (ASYNCEVENTMSG); lineMsg.Msg = Msg; lineMsg.Param2 = Param2; lineMsg.Param3 = Param3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i]; TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList; if (NULL == ptClient) { break; } lineMsg.Param1 = Param1; // // For LINE_REMOVE, need to remap the dwDeviceID(Param1) // if (Msg == LINE_REMOVE) { DWORD dwNumDevices; LPDWORD lpdwDevices; if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && WaitForExclusiveClientAccess (ptClient)) { if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { dwNumDevices = ptClient->dwLineDevices; lpdwDevices = ptClient->pLineDevices; for (j = 0; j < dwNumDevices; ++j, ++lpdwDevices) { if (*lpdwDevices == Param1) { break; } } if (j >= dwNumDevices) { // Not found in the device map, ignore UNLOCKTCLIENT (ptClient); continue; } else { lineMsg.Param1 = j; } } UNLOCKTCLIENT (ptClient); } } else if (Msg == LINE_CREATE) { if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && WaitForExclusiveClientAccess (ptClient)) { BOOL bAdmin = IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR); UNLOCKTCLIENT (ptClient); if (!bAdmin) { continue; } } } if (GetLineAppListFromClient (ptClient, &pXxxAppList) == 0) { for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++) { PTLINEAPP ptLineApp = (PTLINEAPP) pXxxAppList->aEntries[j]; try { lineMsg.InitContext = ptLineApp->InitContext; if ((ptLineApp->dwKey == TLINEAPP_KEY) && ((dwWantVersion == 0) || (ptLineApp->dwAPIVersion == dwWantVersion) || ((dwWantVersion & 0x80000000) && (ptLineApp->dwAPIVersion >= (dwWantVersion & 0x7fffffff))))) { if (!FMsgDisabled ( ptLineApp->dwAPIVersion, ptLineApp->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { WriteEventBuffer (ptClient, &lineMsg); } } } myexcept { // just continue } } if (pXxxAppList != &xxxAppList) { ServerFree (pXxxAppList); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendAMsgToAllPhoneApps( DWORD dwWantVersion, DWORD Msg, DWORD Param1, // ULONG_PTR Param1, DWORD Param2, // ULONG_PTR Param2, DWORD Param3 // ULONG_PTR Param3 ) { DWORD i, j; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG phoneMsg; if (GetClientList (FALSE, &pClientList) != 0) { return; } ZeroMemory (&phoneMsg, sizeof (ASYNCEVENTMSG)); phoneMsg.TotalSize = sizeof (ASYNCEVENTMSG); phoneMsg.Msg = Msg; phoneMsg.Param2 = Param2; phoneMsg.Param3 = Param3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i]; TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList; if (NULL == ptClient) { break; } phoneMsg.Param1 = Param1; // // For PHONE_REMOVE, need to remap the dwDeviceID(Param1) // if (Msg == PHONE_REMOVE) { DWORD dwNumDevices; LPDWORD lpdwDevices; if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && WaitForExclusiveClientAccess (ptClient)) { if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { dwNumDevices = ptClient->dwPhoneDevices; lpdwDevices = ptClient->pPhoneDevices; for (j = 0; j < dwNumDevices; ++j, ++lpdwDevices) { if (*lpdwDevices == Param1) { break; } } if (j >= dwNumDevices) { // Not found in the device map, ignore UNLOCKTCLIENT (ptClient); continue; } else { phoneMsg.Param1 = j; } } UNLOCKTCLIENT (ptClient); } } else if (Msg == PHONE_CREATE) { if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && WaitForExclusiveClientAccess (ptClient)) { BOOL bAdmin = IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR); UNLOCKTCLIENT (ptClient); if (!bAdmin) { continue; } } } if (GetPhoneAppListFromClient (ptClient, &pXxxAppList) == 0) { for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++) { PTPHONEAPP ptPhoneApp = (PTPHONEAPP) pXxxAppList->aEntries[j]; try { phoneMsg.InitContext = ptPhoneApp->InitContext; if ((ptPhoneApp->dwKey == TPHONEAPP_KEY) && ((dwWantVersion == 0) || (ptPhoneApp->dwAPIVersion == dwWantVersion) || ((dwWantVersion & 0x80000000) && (ptPhoneApp->dwAPIVersion >= (dwWantVersion & 0x7fffffff))))) { if (!FMsgDisabled ( ptPhoneApp->dwAPIVersion, ptPhoneApp->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { WriteEventBuffer (ptClient, &phoneMsg); } } } myexcept { LOG((TL_TRACE, "SendAMsgToAllPhoneApps - exception")); // just continue } } if (pXxxAppList != &xxxAppList) { ServerFree (pXxxAppList); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendReinitMsgToAllXxxApps( void ) { TapiGlobals.dwFlags |= TAPIGLOBALS_REINIT; SendAMsgToAllLineApps (0, LINE_LINEDEVSTATE, LINEDEVSTATE_REINIT, 0, 0); SendAMsgToAllPhoneApps (0, PHONE_STATE, PHONESTATE_REINIT, 0, 0); } void PASCAL SendBufferMsgToLineClients( PTLINE ptLine, PTLINECLIENT ptLineClientToExclude, DWORD dwMsg, DWORD dwParam1, // ULONG_PTR dwParam1, DWORD dwSize, // ULONG_PTR dwSize, LPBYTE pBuffer ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG * pmsg; DWORD dwTotalSize = (sizeof (ASYNCEVENTMSG) + (DWORD) dwSize + TALIGN_COUNT) & TALIGN_MASK; if (!(pmsg = (ASYNCEVENTMSG *) ServerAlloc (dwTotalSize))) { LOG((TL_ERROR, "SendBufferMsgToLineClients - Cannot allocate memory for message")); return; } if (GetLineClientListFromLine (ptLine, &pClientList) != 0) { ServerFree (pmsg); return; } pmsg->TotalSize = dwTotalSize; pmsg->fnPostProcessProcHandle = 0; pmsg->Msg = dwMsg; pmsg->Param1 = dwParam1; pmsg->Param2 = dwSize; pmsg->Param3 = 0; pmsg->Param4 = 0; // remotesp chks this on LINE_DEVSPEC(FEATURE) CopyMemory ((PBYTE)(pmsg+1), pBuffer, dwSize); for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTLINECLIENT ptLineClient = pClientList->aEntries[i]; if (ptLineClient == ptLineClientToExclude) { continue; } if (FMsgDisabled ( ptLineClient->ptLineApp->dwAPIVersion, ptLineClient->adwEventSubMasks, dwMsg, (DWORD) dwParam1 )) { continue; } pmsg->InitContext = ptLineClient->ptLineApp->InitContext; pmsg->hDevice = ptLineClient->hRemoteLine; pmsg->OpenContext = ptLineClient->OpenContext; ptClient = ptLineClient->ptClient; if (ptLineClient->dwKey == TLINECLIENT_KEY) { WriteEventBuffer (ptClient, pmsg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } ServerFree (pmsg); } void PASCAL SendMsgToLineClients( PTLINE ptLine, PTLINECLIENT ptLineClientToExclude, DWORD Msg, DWORD Param1, // ULONG_PTR Param1, DWORD Param2, // ULONG_PTR Param2, DWORD Param3 // ULONG_PTR Param3 ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg; LOG((TL_TRACE, "SendMsgToLineClients - enter")); if (Msg == LINE_LINEDEVSTATE && Param1 & LINEDEVSTATE_REINIT) { SendReinitMsgToAllXxxApps(); if (Param1 == LINEDEVSTATE_REINIT) { return; } else { Param1 &= ~LINEDEVSTATE_REINIT; } } if (GetLineClientListFromLine (ptLine, &pClientList) != 0) { return; } msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.Msg = Msg; msg.Param1 = Param1; msg.Param2 = Param2; msg.Param3 = Param3; msg.Param4 = 0; // remotesp chks this on LINE_DEVSPEC(FEATURE) LOG((TL_INFO, "SendMsgToLineClients - number of Clients:%u", pClientList->dwNumUsedEntries)); for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTLINECLIENT ptLineClient = pClientList->aEntries[i]; if (ptLineClient == ptLineClientToExclude) { continue; } LOG((TL_INFO, "SendMsgToLineClients: Msg:%x -- Param1:%x", Msg, Param1)); if (FMsgDisabled ( ptLineClient->ptLineApp->dwAPIVersion, ptLineClient->adwEventSubMasks, (DWORD) Msg, (DWORD) Param1 )) { continue; } if (Msg == LINE_ADDRESSSTATE) { DWORD addressStates = Param2; // ULONG_PTR addressStates = Param2; // // Munge the state flags so we don't pass // unexpected flags to old apps // switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: addressStates &= AllAddressStates1_0; break; //case TAPI_VERSION1_4: //case TAPI_VERSION2_0: //case TAPI_VERSION2_1: //case TAPI_VERSION2_2: //case TAPI_VERSION_CURRENT: default: addressStates &= AllAddressStates1_4; break; } if ((addressStates &= ptLineClient->dwAddressStates)) { msg.Param2 = addressStates; } else { continue; } if ((Param2 & LINEADDRESSSTATE_CAPSCHANGE)) { } } else if (Msg == LINE_LINEDEVSTATE) { DWORD lineStates = Param1; // ULONG_PTR lineStates = Param1; // // Munge the state flags so we don't pass unexpected flags // to old apps // switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: lineStates &= AllLineStates1_0; break; default: // case TAPI_VERSION1_4: // case TAPI_VERSION_CURRENT: lineStates &= AllLineStates1_4; break; } if ((lineStates &= ptLineClient->dwLineStates)) { msg.Param1 = lineStates; } else { continue; } if ((Param1 & (LINEDEVSTATE_CAPSCHANGE | LINEDEVSTATE_TRANSLATECHANGE))) { } } else if (Msg == LINE_PROXYSTATUS) { // // Don't pass this message to older apps // if (ptLineClient->dwAPIVersion < TAPI_VERSION2_2) { continue; } } msg.InitContext = ptLineClient->ptLineApp->InitContext; msg.hDevice = ptLineClient->hRemoteLine; msg.OpenContext = ptLineClient->OpenContext; ptClient = ptLineClient->ptClient; if (ptLineClient->dwKey == TLINECLIENT_KEY) { WriteEventBuffer (ptClient, &msg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } } LONG PASCAL GetCallIDs( PTCALL ptCall ) { // // NOTE: Caller must already have exclusive access to the // tCall when invoking this function. On return they // will still have exclusive access to the tCall. // // Also, it is assumed that only the LINE_CALLSTATE // msg handler & MakeCallPostProcess-style functions // will call this function. Otherwise, the code that // resets the tCall's dwKey down below will need to // be changed. // // // We don't want to hold the lock while we call the provider, // since this request might take a while (possible ring // transitions, etc). But we also don't want another thread // to destroy this tCall in the meantime (because we didn't // allow for that in NT 4.0, and because it makes life more // difficult for the calling function). So, we'll reset the // tCall's dwKey value to ZOMBIE, thereby causing any other // thread(s) that is waiting to destroy this call to effectively // wait/spin, and we'll then restore the dwKey value down below // after we reacquire the lock. (Since this func is only called // by MakeCallPostProcess-style functions & the LINE_CALLSTATE // handler [on the first callstate msg received on an incoming // call], the only way another thread would be destroying this // call is if the line is being closed, either by an app or as // the result of a LINE_CLOSE, and DestroytLine spins until // it has destroyed all tCall's in the tLine's list.) DWORD dwNumAddresses = ptCall->ptLine->dwNumAddresses, dwSavedKey; PTPROVIDER ptProvider = ptCall->ptProvider; if (ptProvider->apfn[SP_LINEGETCALLINFO] == NULL) { return LINEERR_OPERATIONUNAVAIL; } dwSavedKey = ptCall->dwKey; ptCall->dwKey = TZOMBIECALL_KEY; UNLOCKTCALL (ptCall); if (ptProvider->apfn[SP_LINEGETCALLIDS]) { CallSP4( ptProvider->apfn[SP_LINEGETCALLIDS], "lineGetCalIDs", SP_FUNC_SYNC, (ULONG_PTR) ptCall->hdCall, (ULONG_PTR) &ptCall->dwAddressID, (ULONG_PTR) &ptCall->dwCallID, (ULONG_PTR) &ptCall->dwRelatedCallID ); } else { DWORD dwSPIVersion, dwFixedSizeSP; LINECALLINFO callInfo; // // Determine the fixed size of the structure expected by the SP // dwSPIVersion = ((PTLINE) ptCall->ptLine)->dwSPIVersion; switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 296; // 69 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeSP = 324; // 76 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLINFO); break; } InitTapiStruct (&callInfo, dwFixedSizeSP, dwFixedSizeSP, TRUE); CallSP2( ptProvider->apfn[SP_LINEGETCALLINFO], "lineGetCallInfo", SP_FUNC_SYNC, (ULONG_PTR) ptCall->hdCall, (ULONG_PTR) &callInfo ); ptCall->dwAddressID = callInfo.dwAddressID; ptCall->dwCallID = callInfo.dwCallID; ptCall->dwRelatedCallID = callInfo.dwRelatedCallID; } // // Reacquire the call lock, restore the dwKey value, & fill // in the address id // LOCKTCALL (ptCall); ptCall->dwKey = dwSavedKey; return 0; } VOID PASCAL AcquireHashTableReaderLock( PTPROVIDER ptProvider ) { EnterCriticalSection (&ptProvider->HashTableCritSec); InterlockedIncrement (&ptProvider->lHashTableReaderCount); LeaveCriticalSection (&ptProvider->HashTableCritSec); } VOID PASCAL AcquireHashTableWriterLock( PTPROVIDER ptProvider ) { EnterCriticalSection (&ptProvider->HashTableCritSec); if (InterlockedDecrement (&ptProvider->lHashTableReaderCount) >= 0) { WaitForSingleObject (ptProvider->hHashTableReaderEvent, INFINITE); } } VOID PASCAL ReleaseHashTableReaderLock( PTPROVIDER ptProvider ) { if (InterlockedDecrement (&ptProvider->lHashTableReaderCount) < 0) { SetEvent (ptProvider->hHashTableReaderEvent); } } VOID PASCAL ReleaseHashTableWriterLock( PTPROVIDER ptProvider ) { InterlockedIncrement (&ptProvider->lHashTableReaderCount); LeaveCriticalSection (&ptProvider->HashTableCritSec); } PTHASHTABLEENTRY PASCAL AcquireHashTableEntryLock( PTPROVIDER ptProvider, DWORD dwCallHubID ) { LONG lPreviousCookie; PTHASHTABLEENTRY pEntry; AcquireHashTableReaderLock (ptProvider); pEntry = ptProvider->pHashTable + (dwCallHubID % ptProvider->dwNumHashTableEntries); do { lPreviousCookie = InterlockedExchange (&pEntry->lCookie, 1); } while (lPreviousCookie != 0); return pEntry; } VOID PASCAL ReleaseHashTableEntryLock( PTPROVIDER ptProvider, PTHASHTABLEENTRY pEntry ) { InterlockedExchange (&pEntry->lCookie, 0); ReleaseHashTableReaderLock (ptProvider); } VOID PASCAL FreeHashTable( PTHASHTABLEENTRY pHashTable, DWORD dwNumHashTableEntries, DWORD dwNumDynamicHashTableEntries ) { // // Walk thru hash table to find any dynamic entries that need to // be freed. We compare against both dwNumDynamicHashTableEntries // and dwNumHashTableEntries in case something went wrong somewhere. // // Then free the table itself & return // DWORD i; PTHASHTABLEENTRY pEntry, pEntry2; for( i = 0, pEntry = pHashTable; dwNumDynamicHashTableEntries && i < dwNumHashTableEntries; i++, pEntry++ ) { while (pEntry->pNext) { dwNumDynamicHashTableEntries--; pEntry2 = pEntry->pNext->pNext; ServerFree (pEntry->pNext); pEntry->pNext = pEntry2; } } ServerFree (pHashTable); } PTHASHTABLEENTRY PASCAL FindDynamicHashTableEntry( PTHASHTABLEENTRY pEntry, DWORD dwCallHubID ) { // // Note that the pEntry passed to us is static, so no need to check that // while (pEntry->pNext) { if (pEntry->pNext->dwCallHubID == dwCallHubID) { break; } pEntry = pEntry->pNext; } return pEntry->pNext; } VOID PASCAL RemoveDynamicHashTableEntry( PTPROVIDER ptProvider, PTHASHTABLEENTRY pStaticEntry, PTHASHTABLEENTRY pDynamicEntry ) { while (pStaticEntry->pNext != pDynamicEntry) { pStaticEntry = pStaticEntry->pNext; } pStaticEntry->pNext = pDynamicEntry->pNext; ServerFree (pDynamicEntry); InterlockedDecrement ((LPLONG) &ptProvider->dwNumDynamicHashTableEntries); } DWORD PASCAL GetNumDynamicHashTableEntries( PTHASHTABLEENTRY pEntry ) { // // Note that the pEntry passed to us is static, so no need to count that // DWORD i; for (i = 0; (pEntry = pEntry->pNext); i++); return i; } // // SendNewCallHubEvent // // Utility function used by DoCallHubHashing & UpdateCallHubHashing // to send LINE_NEWCALLHUB event if not sent yet // LONG PASCAL SendNewCallHubEvent ( PTCALL ptCall, PTHASHTABLEENTRY pTargetEntry ) { // // For each tCallClient see if tLineClient has tracking // enabled, and if so then see if there is already an // associated (via common tLineApp) tCallHubClient - if // not then create one & notify the app // DWORD i; BOOL bExistingCallHubClients = (pTargetEntry->ptCallHubClients != NULL); TPOINTERLIST fastCallClientList, *ptCallClientList; if (ptCall->ptLine->dwNumCallHubTrackers != 0) { ptCallClientList = &fastCallClientList; if (GetCallClientListFromCall (ptCall, &ptCallClientList) != 0) { ptCallClientList = NULL; } } else { ptCallClientList = NULL; } if (ptCallClientList == NULL || pTargetEntry == NULL) { return 0; } for (i = 0; i < ptCallClientList->dwNumUsedEntries; i++) { PTLINEAPP ptLineApp; PTCALLCLIENT ptCallClient = ptCallClientList->aEntries[i]; ASYNCEVENTMSG msg; PTCALLHUBCLIENT ptCallHubClient; if (ptCallClient->ptLineClient->dwCurrentTracking || bExistingCallHubClients) { ptLineApp = ptCallClient->ptLineClient->ptLineApp; ptCallHubClient = pTargetEntry->ptCallHubClients; while (ptCallHubClient) { if (ptCallHubClient->ptLineApp == ptLineApp) { break; } ptCallHubClient = ptCallHubClient->pNext; } if (ptCallClient->ptLineClient->dwCurrentTracking && !ptCallHubClient && (!FMsgDisabled ( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, LINE_APPNEWCALLHUB, 0))) { DWORD hptClientHandle = 0; ptCallHubClient = ServerAlloc (sizeof(TCALLHUBCLIENT)); if (!ptCallHubClient) { i = ptCallClientList->dwNumUsedEntries; continue; } ptCallHubClient->hCallHub = (DWORD) NewObject( ghHandleTable, ptCallHubClient, NULL ); if (!ptCallHubClient->hCallHub) { ServerFree(ptCallHubClient); i = ptCallClientList->dwNumUsedEntries; continue; } ptCallHubClient->dwKey = TCALLHUBCLIENT_KEY; ptCallHubClient->ptClient = ptCallClient->ptClient; ptCallHubClient->ptProvider = ptCall->ptProvider; ptCallHubClient->dwCallHubID = ptCall->dwCallID; ptCallHubClient->ptLineApp = ptLineApp; ptCallHubClient->pNext = pTargetEntry->ptCallHubClients; pTargetEntry->ptCallHubClients = ptCallHubClient; // // Queue a msg to alert the app of the new call // hub. We do this rather than sending a msg // directly from here to make sure the app gets // the LINE_REPLY and/or APPNEWCALL msgs first // (i.e. before calling lineGetHubRelatedCalls // in response to LINE_APPNEWCALLHUB) // LineEventProcSP( (HTAPILINE) 0, (HTAPICALL) 0, LINE_APPNEWCALLHUB, ptCallHubClient->hCallHub, ptLineApp->InitContext, (ULONG_PTR)ptLineApp->ptClient ); } ptCallClient->ptCallHubClient = ptCallHubClient; } } return 0; } // // Per Bug 7591 // There might be a owner ship transferring of a call after // it has been created. The new owner will not get the new call // hub event since such event is only generated while the call // is created. UpdateCallHubHashing goes through the call client // if any of the client did not receive the LINE_NEWCALLHUB event // it will send it one. // LONG PASCAL UpdateCallHubHashing ( PTCALL ptCall ) { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { PTHASHTABLEENTRY pStaticEntry, pTargetEntry; pStaticEntry = AcquireHashTableEntryLock( ptCall->ptProvider, ptCall->dwCallID ); if (pStaticEntry->dwCallHubID == ptCall->dwCallID) { pTargetEntry = pStaticEntry; } else { pTargetEntry = FindDynamicHashTableEntry( pStaticEntry, ptCall->dwCallID ); } if (pTargetEntry) { SendNewCallHubEvent (ptCall, pTargetEntry); } ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry); UNLOCKTCALL (ptCall); } return 0; } LONG PASCAL DoCallHubHashing( PTCALL ptCall, DWORD dwPreviousCallID ) { // // Assumes caller has exclusive access to the tCall // DWORD i; PTPROVIDER ptProvider = ptCall->ptProvider; PTHASHTABLEENTRY pStaticEntry, pDynamicEntry; if (ptCall->dwCallID == dwPreviousCallID) { return 0; } if (dwPreviousCallID != 0) { // // Remove tCall from call hub hash table (based on // previous call id). If this is the last tCall in // that hash table entry then destroy any associated // tCallHubClients and alert apps. // // Note that (when freeing tCallHubClients) we call // LineEventProcSP() to queue the CALLHUBCLOSE msgs // rather than sending them directly via // WriteEventBuffer() because we already own the // tCall lock and we don't want to entertain the // possibility of deadlock by grabbing other locks. // PTCALLHUBCLIENT ptCallHubClient = NULL, pNext; pStaticEntry = AcquireHashTableEntryLock( ptProvider, dwPreviousCallID ); if (pStaticEntry->dwCallHubID == dwPreviousCallID) { RemoveEntryList (&ptCall->CallHubList); ptCall->CallHubList.Flink = NULL; ptCall->CallHubList.Blink = NULL; if (IsListEmpty (&pStaticEntry->CallHubList)) { ptCallHubClient = pStaticEntry->ptCallHubClients; pStaticEntry->ptCallHubClients = NULL; pStaticEntry->dwCallHubID = 0; } } else if ((pDynamicEntry = FindDynamicHashTableEntry( pStaticEntry, dwPreviousCallID ))) { RemoveEntryList (&ptCall->CallHubList); ptCall->CallHubList.Flink = NULL; ptCall->CallHubList.Blink = NULL; if (IsListEmpty (&pDynamicEntry->CallHubList)) { ptCallHubClient = pDynamicEntry->ptCallHubClients; RemoveDynamicHashTableEntry( ptProvider, pStaticEntry, pDynamicEntry ); } } else { // TODO assert } ReleaseHashTableEntryLock (ptProvider, pStaticEntry); if (ptCallHubClient) { while (ptCallHubClient) { BOOL bSendMsg = FALSE; DWORD param2 = 0; DWORD param3 = 0; // ULONG_PTR param2, param3; PTLINEAPP ptLineApp; try { ptLineApp = ptCallHubClient->ptLineApp; param2 = ptLineApp->InitContext; if (ptLineApp->dwKey == TLINEAPP_KEY && (!FMsgDisabled( ptLineApp->dwAPIVersion, ptLineApp->adwEventSubMasks, LINE_CALLHUBCLOSE, 0 ))) { bSendMsg = TRUE; } } except (EXCEPTION_EXECUTE_HANDLER) { // tLineApp is gone, just fall through } if (bSendMsg) { LineEventProcSP( (HTAPILINE) UIntToPtr(ptCallHubClient->hCallHub), // "random" seed for MP (HTAPICALL) 0, LINE_CALLHUBCLOSE, ptCallHubClient->hCallHub, param2, (ULONG_PTR)ptLineApp->ptClient ); } pNext = ptCallHubClient->pNext; ptCallHubClient->dwKey = INVAL_KEY; DereferenceObject( ghHandleTable, ptCallHubClient->hCallHub, 1 ); ptCallHubClient = pNext; } } } if (ptCall->dwCallID != 0 && ptCall->CallHubList.Flink == NULL && ptCall->CallHubList.Blink == NULL) { // // If at least one tLineClient has call hub tracking enabled // then retrieve the list of tCallClients before we acquire // exclusive access to the hash table // DWORD dwOldNumHashTableEntries, dwOldNumDynamicHashTableEntries; PTHASHTABLEENTRY pOldHashTable = NULL, pTargetEntry; // // Insert tCall in call hub hash table (based on current call ID). // // In the event of collision, first check to see if there's an // existing dynamic entry with corresponding to the call ID. // If so, party on the dynamic entry. Otherwise, try to create // a dynamic entry if we're still within the dynamic entry // threshholds. // // Finally, failing all the above, attempt to grow the hash table. // acquireTableEntryLock: pStaticEntry = AcquireHashTableEntryLock( ptProvider, ptCall->dwCallID ); if (pStaticEntry->dwCallHubID == ptCall->dwCallID) { // // Add tCall to list (static entry) // InsertTailList (&pStaticEntry->CallHubList, &ptCall->CallHubList); pTargetEntry = pStaticEntry; } else if(pStaticEntry->dwCallHubID == 0) { // // Check to see if there is already a dynamic entry for this dwCallID, // if so, use it // pTargetEntry = pStaticEntry->pNext; while (pTargetEntry && pTargetEntry->dwCallHubID != ptCall->dwCallID) { pTargetEntry = pTargetEntry->pNext; } if (pTargetEntry == NULL) { pTargetEntry = pStaticEntry; pTargetEntry->dwCallHubID = ptCall->dwCallID; } InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList); } else if ((pTargetEntry = FindDynamicHashTableEntry( pStaticEntry, ptCall->dwCallID ))) { // // Add tCall to list (existing dynamic entry) // InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList); } else if (InterlockedIncrement( (LPLONG) &ptProvider->dwNumDynamicHashTableEntries ) < (LONG) GetMaxDynamicHashTableEntries( ptProvider->dwNumHashTableEntries ) && GetNumDynamicHashTableEntries (pStaticEntry) < MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT) { // // Add tCall to list (new dynamic entry) // if (!(pTargetEntry = ServerAlloc (sizeof (*pTargetEntry)))) { // // Failed to allocate memory, so we'll reset the call // hub id for this call to zero so as not to confuse // things later // InterlockedDecrement( (LPLONG) &ptProvider->dwNumDynamicHashTableEntries ); ReleaseHashTableEntryLock (ptProvider, pStaticEntry); ptCall->dwCallID = 0; return 0; } pTargetEntry->dwCallHubID = ptCall->dwCallID; InitializeListHead (&pTargetEntry->CallHubList); InsertTailList (&pTargetEntry->CallHubList, &ptCall->CallHubList); pTargetEntry->pNext = pStaticEntry->pNext; pStaticEntry->pNext = pTargetEntry; } else { // // Grow table // DWORD dwNewNumHashTableEntries, dwMaxDynamicEntries, dwNewNumDynamicHashTableEntries; PTHASHTABLEENTRY pNewHashTable, pNewEntry, pEntry2, pEndOfTable; // // Decrement to compensate for the failed check above // InterlockedDecrement( &ptProvider->dwNumDynamicHashTableEntries ); // // Grab the current number of hash table entries before // we release the entry lock, so we can compare with // that after the table writer lock is acquired. (Another // thread might have grown table in time it took to acquire // table writer lock, in which case we want to jump up // top again.) // // The chances of another thread having released the // entry we collided with (or freed up a related dynamic // entry, etc) are fairly slim, so we won't bother checking // for that // { DWORD dwNumHashTableEntries = ptProvider->dwNumHashTableEntries; ReleaseHashTableEntryLock (ptProvider, pStaticEntry); AcquireHashTableWriterLock (ptProvider); if (dwNumHashTableEntries < ptProvider->dwNumHashTableEntries) { ReleaseHashTableWriterLock (ptProvider); goto acquireTableEntryLock; } // // Because we released the lock & reaquired a lock, if // another call with the same dwCallID got hashed in, we // would got two hash table entries with the same dwCallHubID // that eventually leads to memory corruption when grow // the table again. So check for it // pTargetEntry = ptProvider->pHashTable + (ptCall->dwCallID % ptProvider->dwNumHashTableEntries); while (pTargetEntry && pTargetEntry->dwCallHubID != ptCall->dwCallID) { pTargetEntry = pTargetEntry->pNext; } if (pTargetEntry) { // // Found such entry, go back & retry // ReleaseHashTableWriterLock (ptProvider); goto acquireTableEntryLock; } } // // Ok, we really do need to grow the table. Find the next // larger number of entries. // for( i = 0; ptProvider->dwNumHashTableEntries >= TapiPrimes[i] && TapiPrimes[i]; i++ ); alloc_new_hash_table: if (!(dwNewNumHashTableEntries = TapiPrimes[i])) { // // We won't attempt to grow the hash table any further, // so we'll reset the call hub id for this call to zero // so as not to confuse things later // ptCall->dwCallID = 0; ReleaseHashTableWriterLock (ptProvider); return 0; } pNewHashTable = ServerAlloc( dwNewNumHashTableEntries * sizeof (THASHTABLEENTRY) ); if (!pNewHashTable) { // // Failed to allocate a new hash table, so we'll reset the // call hub id for this call to zero so as not to confuse // things later // ptCall->dwCallID = 0; ReleaseHashTableWriterLock (ptProvider); return 0; } // // Move all existing hash table entries to new table // pEndOfTable = ptProvider->pHashTable + ptProvider->dwNumHashTableEntries; dwNewNumDynamicHashTableEntries = 0; dwMaxDynamicEntries = GetMaxDynamicHashTableEntries( dwNewNumHashTableEntries ); for( pStaticEntry = ptProvider->pHashTable; pStaticEntry != pEndOfTable; pStaticEntry++ ) { // // If this entry is in use somehow, check to see // if we need to start walking at the static entry // or the dynamic entry. Else, simply continue. // if (pStaticEntry->dwCallHubID == 0) { if (!pStaticEntry->pNext) { continue; } pEntry2 = pStaticEntry->pNext; } else { pEntry2 = pStaticEntry; } while (pEntry2) { pNewEntry = pNewHashTable + (pEntry2->dwCallHubID % dwNewNumHashTableEntries); if (pNewEntry->dwCallHubID != 0) { // // Collision, try to add a dynamic entry // if (dwNewNumDynamicHashTableEntries < dwMaxDynamicEntries && GetNumDynamicHashTableEntries (pNewEntry) < MAX_DYNAMIC_HASH_ENTRIES_PER_SLOT) { if (!(pDynamicEntry = ServerAlloc( sizeof (*pDynamicEntry) ))) { // // Failed to allocate a new dynamic entry, // so we'll reset the call hub id for this // call to zero so as not to confuse things // later // ptCall->dwCallID = 0; ReleaseHashTableWriterLock (ptProvider); FreeHashTable( pNewHashTable, dwNewNumHashTableEntries, dwNewNumDynamicHashTableEntries ); return 0; } pDynamicEntry->pNext = pNewEntry->pNext; pNewEntry->pNext = pDynamicEntry; pNewEntry = pDynamicEntry; dwNewNumDynamicHashTableEntries++; } else { // // Free new table and try for a larger one // FreeHashTable( pNewHashTable, dwNewNumHashTableEntries, dwNewNumDynamicHashTableEntries ); i++; goto alloc_new_hash_table; } } pNewEntry->dwCallHubID = pEntry2->dwCallHubID; pNewEntry->CallHubList.Flink = pEntry2->CallHubList.Flink; pNewEntry->CallHubList.Blink = pEntry2->CallHubList.Blink; pNewEntry->ptCallHubClients = pEntry2->ptCallHubClients; pEntry2 = pEntry2->pNext; } } // // Now init the new entry // pNewEntry = pNewHashTable + (ptCall->dwCallID % dwNewNumHashTableEntries); if (pNewEntry->dwCallHubID != 0) { // // Collision, try to add a dynamic entry. // // We intentionally ignore the dyna entry threshhold // checks, as they'd be overkill here. // if ((pDynamicEntry = ServerAlloc (sizeof(*pDynamicEntry)))) { pDynamicEntry->pNext = pNewEntry->pNext; pNewEntry->pNext = pDynamicEntry; pNewEntry = pDynamicEntry; dwNewNumDynamicHashTableEntries++; } else { FreeHashTable( pNewHashTable, dwNewNumHashTableEntries, dwNewNumDynamicHashTableEntries ); i++; goto alloc_new_hash_table; } } pNewEntry->dwCallHubID = ptCall->dwCallID; pNewEntry->CallHubList.Flink = pNewEntry->CallHubList.Blink = &ptCall->CallHubList; // // Save the old table info (so we can free it & dyna // entries later when the lock is released), then save // the new table info // pOldHashTable = ptProvider->pHashTable; dwOldNumHashTableEntries = ptProvider->dwNumHashTableEntries; dwOldNumDynamicHashTableEntries = ptProvider->dwNumDynamicHashTableEntries; ptProvider->pHashTable = pNewHashTable; ptProvider->dwNumHashTableEntries = dwNewNumHashTableEntries; ptProvider->dwNumDynamicHashTableEntries = dwNewNumDynamicHashTableEntries; // // Init the unused table entries and the head & tail // list items in the used entries // pEndOfTable = ptProvider->pHashTable + ptProvider->dwNumHashTableEntries; for( pStaticEntry = ptProvider->pHashTable; pStaticEntry != pEndOfTable; pStaticEntry++ ) { if (pStaticEntry->dwCallHubID == 0) { InitializeListHead (&pStaticEntry->CallHubList); } else { pEntry2 = pStaticEntry; while (pEntry2) { pEntry2->CallHubList.Flink->Blink = pEntry2->CallHubList.Blink->Flink = &pEntry2->CallHubList; pEntry2 = pEntry2->pNext; } } } // // Set pTargetEntry to point to the "new" entry (as expected below) // pTargetEntry = pNewEntry; } // // Check to see if we need to create any tCallHubClient objects // SendNewCallHubEvent (ptCall, pTargetEntry); // // Release the appropriate hash table lock, then if we grew // the table free the old table & dynamic table entries // if (!pOldHashTable) { ReleaseHashTableEntryLock (ptProvider, pStaticEntry); } else { ReleaseHashTableWriterLock (ptProvider); FreeHashTable( pOldHashTable, dwOldNumHashTableEntries, dwOldNumDynamicHashTableEntries ); } } return 0; } LONG PASCAL CreatetCall( PTLINE ptLine, BOOL bIncoming, HDRVCALL hdCall, PTCALL *pptCall, LPLINECALLPARAMS pCallParams, HCALL *phCall, PTCALL ptCallAssociate ) { BOOL bDupedMutex; DWORD dwExtraBytes; HANDLE hMutex; PTCALL ptCall; LOG((TL_TRACE, "CreatetCall: enter, ptLine=%p", ptLine)); // // If there's call params specified check to see if we need to alloc // any extra space for the CalledParty, DisplayableAddr, or Comment // fields. Also, if any of these fields are non-NULL make sure to // get extra space to keep these fields 64-bit aligned. // dwExtraBytes = (pCallParams == NULL ? 0 : pCallParams->dwCalledPartySize + pCallParams->dwDisplayableAddressSize + pCallParams->dwCommentSize); if (dwExtraBytes != 0) { dwExtraBytes += (sizeof (TCALL) & 4) + 16; } // // Alloc necessary resources // if (!(ptCall = ServerAlloc (sizeof (TCALL) + dwExtraBytes))) { return LINEERR_NOMEM; } // // Init tCall & add to tLine's tCall list // if (bIncoming) { // // This is an incoming call (we're being called by the // LINE_NEWCALL handler) // ptCall->dwKey = INVAL_KEY; ptCall->dwDrvCallFlags = DCF_SPIRETURNED | DCF_DRVCALLVALID; ptCall->bAlertApps = TRUE; ptCall->dwCallState = LINECALLSTATE_UNKNOWN; ptCall->hdCall = hdCall; } else { // // This is an outgoing call (we're not being called by // the LINE_NEWCALL handler) // ptCall->dwKey = TINCOMPLETECALL_KEY; } if (pCallParams) { DWORD dwOffset = sizeof (TCALL) + (sizeof (TCALL) & 4); if (pCallParams->dwDisplayableAddressSize != 0) { CopyMemory( (ptCall->pszDisplayableAddress = (WCHAR *) (((LPBYTE) ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwDisplayableAddressOffset, (ptCall->dwDisplayableAddressSize = pCallParams->dwDisplayableAddressSize) ); dwOffset += ((ptCall->dwDisplayableAddressSize + 8) & 0xfffffff8); } if (pCallParams->dwCalledPartySize) { CopyMemory( (ptCall->pszCalledParty = (WCHAR *) (((LPBYTE)ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwCalledPartyOffset, (ptCall->dwCalledPartySize = pCallParams->dwCalledPartySize) ); dwOffset += ((ptCall->dwCalledPartySize + 8) & 0xfffffff8); } if (pCallParams->dwCommentSize) { CopyMemory( (ptCall->pszComment = (WCHAR *) (((LPBYTE) ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwCommentOffset, (ptCall->dwCommentSize = pCallParams->dwCommentSize) ); } } LOG((TL_INFO, "CreatetCall: calling NewObject ptCall %p", ptCall)); ptCall->hCall = (HCALL) NewObject( ghHandleTable, ptCall, NULL ); LOG((TL_TRACE, "CreatetCall: NewObject returned 0x%lx", ptCall->hCall)); *phCall = ptCall->hCall; if (!ptCall->hCall) { ServerFree (ptCall); return LINEERR_NOMEM; } // // Add the new tCall to the tLine's list // if (WaitForExclusivetLineAccess( ptLine, &hMutex, &bDupedMutex, INFINITE )) { ptCall->ptLine = ptLine; ptCall->ptProvider = ptLine->ptProvider; if ((ptCall->pNext = ptLine->ptCalls)) { ptCall->pNext->pPrev = ptCall; } ptLine->ptCalls = ptCall; MyReleaseMutex (hMutex, bDupedMutex); } else { // // tLine was destroyed, so clean up. Note that we return // a generic OPFAILED error, since some calling routines // might no be spec'd to return INVALLINEHANDLE, etc. // DereferenceObject (ghHandleTable, ptCall->hCall, 1); return LINEERR_OPERATIONFAILED; } // // Fill in caller's pointer & return success // *pptCall = ptCall; PerfBlock.dwTotalOutgoingCalls++; PerfBlock.dwCurrentOutgoingCalls++; // // For incoming call, the call is ready to be used // if (bIncoming) { ptCall->dwKey = TCALL_KEY; } LOG((TL_TRACE, "CreatetCall: exit, new ptCall=%p", *pptCall)); return 0; } LONG PASCAL CreatetCallClient( PTCALL ptCall, PTLINECLIENT ptLineClient, DWORD dwPrivilege, BOOL bValidate, BOOL bSendCallInfoMsg, PTCALLCLIENT *pptCallClient, BOOL bIndicatePrivilege ) { BOOL bFastCallClient, bValidLineClient; PTCALLCLIENT ptCallClient; PTLINECLIENT ptLineClient2 = NULL; LOG((TL_TRACE, "CreatetCallClient: enter, ptCall=%p,", ptCall)); if (WaitForExclusivetCallAccess( ptCall, (bValidate ? TCALL_KEY : TINCOMPLETECALL_KEY) )) { if (ptCall->lUsedFastCallClients < DEF_NUM_FAST_CALLCLIENTS) { ptCallClient = ptCall->aFastCallClients + ptCall->lUsedFastCallClients++; ptCall->lActiveFastCallClients++; bFastCallClient = TRUE; } else if ((ptCallClient = ServerAlloc (sizeof(TCALLCLIENT)))) { bFastCallClient = FALSE; } else { UNLOCKTCALL(ptCall); return LINEERR_NOMEM; } LOG((TL_INFO, "CreatetCallClient: calling NewObject, ptCallClient = [%p]", ptCallClient)); if (!(ptCallClient->hCall = (HCALL) NewObject( ghHandleTable, ptCallClient, (LPVOID) UIntToPtr(bFastCallClient) ))) { if (bFastCallClient) { ptCall->lActiveFastCallClients--; ptCall->lUsedFastCallClients--; } else { ServerFree (ptCallClient); } UNLOCKTCALL(ptCall); return LINEERR_NOMEM; } if (dwPrivilege == LINECALLPRIVILEGE_OWNER) { ptCall->dwNumOwners++; } else { ptCall->dwNumMonitors++; } if ((ptCallClient->pNextSametCall = ptCall->ptCallClients)) { ptCallClient->pNextSametCall->pPrevSametCall = ptCallClient; } ptCall->ptCallClients = ptCallClient; UNLOCKTCALL (ptCall); ptCallClient->ptLineClient = ptLineClient; ptCallClient->ptCall = ptCall; ptCallClient->dwPrivilege = dwPrivilege; ptCallClient->bIndicatePrivilege = (bIndicatePrivilege ? 1 : 0); } else { // // tCall was destroyed, so return error. Note that we return // a generic OPFAILED error, since some calling routines // might not be spec'd to return INVALCALLHANDLE, etc. // return LINEERR_OPERATIONFAILED; } // // Add to tLineClient's tCallClient list // LOCKTLINECLIENT (ptLineClient); try { bValidLineClient = (ptLineClient->dwKey == TLINECLIENT_KEY ? TRUE : FALSE); if (bValidLineClient) { ptLineClient2 = (PTLINECLIENT) ReferenceObject ( ghHandleTable, ptLineClient->hLine, TLINECLIENT_KEY ); if (ptLineClient2 == NULL || ptLineClient != ptLineClient2) { bValidLineClient = FALSE; } } } myexcept { bValidLineClient = FALSE; } if (bValidLineClient) { ptCallClient->ptClient = ptLineClient->ptClient; if ((ptCallClient->pNextSametLineClient = ptLineClient->ptCallClients)) { ptCallClient->pNextSametLineClient->pPrevSametLineClient = ptCallClient; } ptLineClient->ptCallClients = ptCallClient; if (ptLineClient2) { DereferenceObject ( ghHandleTable, ptLineClient2->hLine, 1 ); } if (ptLineClient->ptLineApp->dwAPIVersion <= TAPI_VERSION3_0) { FillMemory ( ptCallClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS, (BYTE) 0xff ); } else { CopyMemory ( ptCallClient->adwEventSubMasks, ptLineClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS ); } UNLOCKTLINECLIENT (ptLineClient); } else { if (ptLineClient2) { DereferenceObject ( ghHandleTable, ptLineClient2->hLine, 1 ); } UNLOCKTLINECLIENT (ptLineClient); // // Couldn't add tCallClient to tLineClient's list, so safely // remove it from tCall's list, dec the owner or monitor count, // free the tCallClient, and return an appropriate error // // Note that no validation of tCall is necessary - it has to be // valid since we previously added a tCallClient to it's list, // and that tCallClient's key was not yet validated (so any // threads attempting to destroy the tCall would be spinning) // LOCKTCALL (ptCall); if (dwPrivilege == LINECALLPRIVILEGE_OWNER) { ptCall->dwNumOwners--; } else { ptCall->dwNumMonitors--; } if (ptCallClient->pNextSametCall) { ptCallClient->pNextSametCall->pPrevSametCall = ptCallClient->pPrevSametCall; } if (ptCallClient->pPrevSametCall) { ptCallClient->pPrevSametCall->pNextSametCall = ptCallClient->pNextSametCall; } else { ptCall->ptCallClients = ptCallClient->pNextSametCall; } if (bFastCallClient) { ptCall->lActiveFastCallClients--; } UNLOCKTCALL (ptCall); DereferenceObject (ghHandleTable, ptCallClient->hCall, 1); return LINEERR_INVALLINEHANDLE; } // // If here success, so mark tCallClient as valid (if another thread // was tearing down the corresponding tCall or tLineClient it will // have been spinning waiting for us to validate this tCallClient) // ptCallClient->dwKey = (bValidate ? TCALLCLIENT_KEY : TINCOMPLETECALLCLIENT_KEY); // // Send a call info msg other call clients if appropriate // if (bSendCallInfoMsg) { SendMsgToCallClients( ptCall, ptCallClient, LINE_CALLINFO, (dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERINCR : LINECALLINFOSTATE_NUMMONITORS), 0, 0 ); } // // Fill in caller's pointer & return success // *pptCallClient = ptCallClient; LOG((TL_TRACE, "CreatetCallClient: exit, new ptCallClient=%p", *pptCallClient )); return 0; } LONG PASCAL CreatetCallAndClient( PTLINECLIENT ptLineClient, PTCALL *pptCall, PTCALLCLIENT *pptCallClient, LPLINECALLPARAMS pCallParams, HCALL *phCall, PTCALL ptCallAssociate ) { LONG lResult = 0; DWORD dwAppNameSize; WCHAR *pszAppName = NULL; PTCALL ptCall = NULL; PTLINE ptLine; LOG((TL_TRACE, "CreatetCallAndClient: enter, ptLineClient=%p", ptLineClient)); try { ptLine = ptLineClient->ptLine; dwAppNameSize = ptLineClient->ptLineApp->dwFriendlyNameSize; if (ptLineClient->dwKey != TLINECLIENT_KEY) { lResult = LINEERR_INVALLINEHANDLE; } else if ((pszAppName = ServerAlloc (dwAppNameSize))) { CopyMemory( pszAppName, ptLineClient->ptLineApp->pszFriendlyName, dwAppNameSize ); } else { lResult = LINEERR_NOMEM; } } myexcept { ServerFree (pszAppName); lResult = LINEERR_INVALLINEHANDLE; } if (lResult != 0) { return lResult; } if ((lResult = CreatetCall( ptLine, FALSE, (HDRVCALL) 0, &ptCall, pCallParams, phCall, ptCallAssociate )) != 0) { ServerFree (pszAppName); return lResult; } if ((lResult = CreatetCallClient( ptCall, ptLineClient, LINECALLPRIVILEGE_OWNER, FALSE, FALSE, pptCallClient, FALSE )) != 0) { ServerFree (pszAppName); ptCall->dwDrvCallFlags = DCF_SPIRETURNED; DestroytCall (ptCall); *pptCall = (PTCALL) NULL; *phCall = 0; return lResult; } ptCall->dwAppNameSize = dwAppNameSize; ptCall->pszAppName = pszAppName; *pptCall = ptCall; return lResult; } LONG PASCAL CreateCallMonitors( PTCALL ptCall, BOOL bIncoming ) { // // This func is called by post processing routines when // a call was successfully created, or on receiving the // first call state message for an incoming call, at // which times we want to create call handles for any // monitoring apps. // // Assumes tCall only has has either no clients at all // or a single (owner) client // // Returns the # of monitor call clients created (>=0) or // an error value (<0) // LONG lResult; BOOL bInitializedMsgs, bRemote, bConfParent = FALSE; DWORD i, dwAddressID, dwCallID, dwRelatedCallID; TPOINTERLIST lineClients, *pLineClients = &lineClients; PTLINE ptLine; PTLINECLIENT ptLineClientOwner; ASYNCEVENTMSG newCallMsg[2], callStateUnkMsg[2]; // // Determine if this call is conf parent and get a list of line clients // try { PTCONFERENCELIST pConfList; if ((pConfList = ptCall->pConfList) && (pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) && (pConfList->aptCalls[0] == ptCall)) { bConfParent = TRUE; } dwAddressID = ptCall->dwAddressID; dwCallID = ptCall->dwCallID; dwRelatedCallID = ptCall->dwRelatedCallID; ptLine = (PTLINE) ptCall->ptLine; ptLineClientOwner = (ptCall->ptCallClients ? ptCall->ptCallClients->ptLineClient : NULL); } myexcept { return LINEERR_OPERATIONFAILED; } if ((lResult = GetLineClientListFromLine (ptLine, &pLineClients))) { return lResult; } // // Look at each line client in the list, and if it has // monitor privileges and is not the one associated with // the existing owner call client then create a monitor // call client // // bInitializedMsgs = FALSE; for (i = 0; i < pLineClients->dwNumUsedEntries; i++) { PTCALLCLIENT ptCallClientMonitor; PTLINECLIENT ptLineClient = pLineClients->aEntries[i]; BOOL fContinue; try { if (!(ptLineClient->dwPrivileges & LINECALLPRIVILEGE_MONITOR) || (ptLineClient == ptLineClientOwner)) { fContinue = TRUE; } else { fContinue = FALSE; bRemote = IS_REMOTE_CLIENT (ptLineClient->ptClient); } } myexcept { // // If here the tLineClient or tCallClient was destroyed, // just continue // fContinue = TRUE; } if (fContinue) { continue; } // // NOTE: If client is remote(sp) then create the call client // with OWNER privileges so client can still do everything. // The remote tapisrv will deal with all the remote // privilege issues. We'll still send the appropriate // MONITOR privilege flag so the remote tapisrv will know // not to look for an owner app. // // This scheme might end up confusing other apps since // a LINE_CALLINFO\NUMOWNERINCR (not NUMMONITORS) msgs // get sent, but it certainly beats what we had in tapi 2.1 - // that is, if a remote client did not initially have owner // privilege then it could *never* get owner privilege. // if (CreatetCallClient( ptCall, ptLineClient, (bRemote ? LINECALLPRIVILEGE_OWNER :LINECALLPRIVILEGE_MONITOR), TRUE, FALSE, &ptCallClientMonitor, bIncoming ) == 0) { // // If this is an incoming call simply increment the number of // monitor call clients created and continue. // // Else this is an outgoing call, so send the monitor app // LINE_APPNEWCALL & LINE_CALLSTATE\UNKNOWN messages to alert // it of new outgoing call // if (bIncoming) { lResult++; continue; } if (!bInitializedMsgs) { newCallMsg->TotalSize = sizeof (ASYNCEVENTMSG) + 3 * sizeof (DWORD); newCallMsg->fnPostProcessProcHandle = 0; newCallMsg->Msg = LINE_APPNEWCALL; newCallMsg->Param1 = dwAddressID; newCallMsg->Param3 = LINECALLPRIVILEGE_MONITOR; *(&newCallMsg->Param4 + 1) = dwCallID; *(&newCallMsg->Param4 + 2) = dwRelatedCallID; *(&newCallMsg->Param4 + 3) = (DWORD)bConfParent; callStateUnkMsg->TotalSize = sizeof(ASYNCEVENTMSG) + sizeof (HCALLHUB); callStateUnkMsg->fnPostProcessProcHandle = 0; callStateUnkMsg->Msg = LINE_CALLSTATE; callStateUnkMsg->Param1 = LINECALLSTATE_UNKNOWN; *((LPHCALLHUB)(callStateUnkMsg + 1)) = (HCALLHUB)0; bInitializedMsgs = TRUE; } try { // // We're presenting the app with a new call handle; for // 2.0 & newer apps we indicate this with an APPNEWCALL // msg, while older apps just get the privilege field // set in the call state msg. // if (ptLineClient->ptLineApp->dwAPIVersion >= TAPI_VERSION2_0) { if (!FMsgDisabled( ptLineClient->ptLineApp->dwAPIVersion, ptLineClient->adwEventSubMasks, LINE_APPNEWCALL, 0 )) { newCallMsg->InitContext = ptLineClient->ptLineApp->InitContext; newCallMsg->hDevice = ptLineClient->hRemoteLine; newCallMsg->OpenContext = ptLineClient->OpenContext; newCallMsg->Param2 = ptCallClientMonitor->hCall; WriteEventBuffer (ptLineClient->ptClient, newCallMsg); } callStateUnkMsg->Param3 = 0; } else { callStateUnkMsg->Param3 = LINECALLPRIVILEGE_MONITOR; } if (FMsgDisabled ( ptLineClient->ptLineApp->dwAPIVersion, ptLineClient->adwEventSubMasks, LINE_CALLSTATE, LINECALLSTATE_UNKNOWN )) { continue; } callStateUnkMsg->InitContext = ptLineClient->ptLineApp->InitContext; callStateUnkMsg->hDevice = ptCallClientMonitor->hCall; callStateUnkMsg->OpenContext = ptLineClient->OpenContext; // // Indicate hRemoteLine in p4 to make life easier for remotesp // callStateUnkMsg->Param4 = ptLineClient->hRemoteLine; // // REMOTESP HACK: See note in LINE_CALLSTATE msg handler // if (IS_REMOTE_CLIENT (ptLineClient->ptClient)) { callStateUnkMsg->Param2 = LINECALLPRIVILEGE_MONITOR; callStateUnkMsg->Param3 = LINEMEDIAMODE_UNKNOWN; } else { callStateUnkMsg->Param2 = 0; } WriteEventBuffer (ptLineClient->ptClient, callStateUnkMsg); lResult++; } myexcept { // just continue } } } if (pLineClients != &lineClients) { ServerFree (pLineClients); } // // Now safely set the flag that says it's ok for other routines like // lineGetNewCalls to create new call handles for apps for this call // { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { // // Only do call hub hashing if there's >0 call clients, // since the (incoming) call will get destroyed otherwise // // $$ Per bug 87355 // It is necessary to do DoCallHubHashing even if we do // not have a client now. So we removed the check for // ptCall->ptCallClients. For incoming call who has got // an owner, we behave the same; for incoming call without // an owner, we would hash the call for now and remove the // call from hash table when destroying the call, so we // are safe either way. // DoCallHubHashing (ptCall, 0); ptCall->bCreatedInitialMonitors = TRUE; UNLOCKTCALL (ptCall); } else { lResult = LINEERR_OPERATIONFAILED; } } return lResult; } PTREQUESTRECIPIENT PASCAL GetHighestPriorityRequestRecipient( void ) { BOOL bFoundRecipientInPriorityList = FALSE; WCHAR *pszAppInPriorityList, *pszAppInPriorityListPrev = (WCHAR *) LongToPtr(0xffffffff); PTREQUESTRECIPIENT pRequestRecipient, pHighestPriorityRequestRecipient = NULL; EnterCriticalSection (&gPriorityListCritSec); pRequestRecipient = TapiGlobals.pRequestRecipients; while (pRequestRecipient) { if (TapiGlobals.pszReqMakeCallPriList && (pszAppInPriorityList = wcsstr( TapiGlobals.pszReqMakeCallPriList, pRequestRecipient->ptLineApp->pszModuleName ))) { if (pszAppInPriorityList <= pszAppInPriorityListPrev) { pHighestPriorityRequestRecipient = pRequestRecipient; pszAppInPriorityListPrev = pszAppInPriorityList; bFoundRecipientInPriorityList = TRUE; } } else if (!bFoundRecipientInPriorityList) { pHighestPriorityRequestRecipient = pRequestRecipient; } pRequestRecipient = pRequestRecipient->pNext; } LeaveCriticalSection (&gPriorityListCritSec); return pHighestPriorityRequestRecipient; } void PASCAL FreetCall( PTCALL ptCall ) { if (ptCall->pszAppName) { ServerFree (ptCall->pszAppName); } if (ptCall->dwDrvCallFlags & DCF_INCOMINGCALL) { PerfBlock.dwCurrentIncomingCalls--; } else { PerfBlock.dwCurrentOutgoingCalls--; } DereferenceObject (ghHandleTable, ptCall->hCall, 1); } void PASCAL DestroytCall( PTCALL ptCall ) { DWORD dwKey; LOG((TL_TRACE, "DestroytCall: enter, ptCall=x%p", ptCall)); // // Safely get the call's current key, then grab the call's lock. // The two waits allow us to deal with the case where the tCall's // key is either TINCOMPLETECALL_KEY or TCALL_KEY, or changing // from the former to the latter (the completion proc was called) // try { dwKey = (ptCall->dwKey == TCALL_KEY ? TCALL_KEY : TINCOMPLETECALL_KEY); } myexcept { LOG((TL_ERROR, "DestroytCall: excepted looking at key")); return; } if (WaitForExclusivetCallAccess (ptCall, dwKey) || WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { PTPROVIDER ptProvider; PTCALL ptCall2; ptCall2 = ReferenceObject ( ghHandleTable, ptCall->hCall, dwKey ); if (ptCall2) { DereferenceObject ( ghHandleTable, ptCall2->hCall, 1 ); } if (ptCall2 == NULL || ptCall != ptCall2) { UNLOCKTCALL (ptCall); return; } // // Invalidate the tCall // ptCall->dwKey = TZOMBIECALL_KEY; UNLOCKTCALL (ptCall); // // If the provider has not returned from it's call-creation // routine yet (i.e. TSPI_lineMakeCall) wait for it to do so // while (!(ptCall->dwDrvCallFlags & DCF_SPIRETURNED)) { Sleep (0); } ptProvider = ptCall->ptProvider; // // Remove tCall from call hub list if appropriate // // Note that there's a window of time between which the call IDs // are retrieved and the call is inserted in a hash time, and so // we need to check for that case as well (CallHubList.Flink == 0) // if (ptCall->dwCallID != 0) { PTHASHTABLEENTRY pStaticEntry, pEntry; pStaticEntry = AcquireHashTableEntryLock( ptCall->ptProvider, ptCall->dwCallID ); if (ptCall->CallHubList.Flink == 0 || ptCall->CallHubList.Blink == 0) { ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry); goto finished_callhubID; } RemoveEntryList (&ptCall->CallHubList); ptCall->CallHubList.Flink = NULL; ptCall->CallHubList.Blink = NULL; pEntry = (pStaticEntry->dwCallHubID == ptCall->dwCallID ? pStaticEntry : FindDynamicHashTableEntry (pStaticEntry, ptCall->dwCallID) ); if (IsListEmpty (&pEntry->CallHubList)) { PTCALLHUBCLIENT ptCallHubClient, pNext; ptCallHubClient = pEntry->ptCallHubClients; if (pEntry == pStaticEntry) { pStaticEntry->dwCallHubID = 0; pStaticEntry->ptCallHubClients = NULL; } else { RemoveDynamicHashTableEntry( ptProvider, pStaticEntry, pEntry ); } ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry); if (ptCallHubClient) { ASYNCEVENTMSG msg; msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.Msg = LINE_CALLHUBCLOSE; msg.fnPostProcessProcHandle = 0; msg.hDevice = 0; msg.OpenContext = 0; msg.Param2 = 0; msg.Param3 = 0; while (ptCallHubClient) { msg.Param1 = ptCallHubClient->hCallHub; try { msg.InitContext = ptCallHubClient->ptLineApp->InitContext; if (ptCallHubClient->ptLineApp->dwKey == TLINEAPP_KEY && (!FMsgDisabled( ptCallHubClient->ptLineApp->dwAPIVersion, ptCallHubClient->ptLineApp->adwEventSubMasks, LINE_CALLHUBCLOSE, 0 ))) { WriteEventBuffer( ptCallHubClient->ptClient, &msg ); } } except (EXCEPTION_EXECUTE_HANDLER) { // tLineApp is gone, just fall through } pNext = ptCallHubClient->pNext; ptCallHubClient->dwKey = INVAL_KEY; DereferenceObject( ghHandleTable, ptCallHubClient->hCallHub, 1 ); ptCallHubClient = pNext; } } } else { ReleaseHashTableEntryLock (ptCall->ptProvider, pStaticEntry); } } finished_callhubID: // // Destroy all the tCallClient's // if (ptCall->ptCallClients) { while (ptCall->ptCallClients) { DestroytCallClient (ptCall->ptCallClients); } } // // Tell the provider to close the call, but only if the hdCall // is valid (we might be destroying a call that // LMakeCall_PostProcess would normally destroy in the event // of a failed make-call request, and we wouldn't want to pass // an invalid hdCall to the driver) // if (ptCall->dwDrvCallFlags & DCF_DRVCALLVALID) { if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { WaitForSingleObject (ptProvider->hMutex, INFINITE); } if (ptProvider->apfn[SP_LINECLOSECALL]) { CallSP1( ptProvider->apfn[SP_LINECLOSECALL], "lineCloseCall", SP_FUNC_SYNC, (ULONG_PTR) ptCall->hdCall ); } if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { ReleaseMutex (ptProvider->hMutex); } } // // Remove tCall from the tLine's tCall list // RemoveCallFromLineList (ptCall); // // Free the resources // { PTCONFERENCELIST pConfList; if ((pConfList = ptCall->pConfList) && (pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff))) { DWORD i; if (pConfList->aptCalls[0] == ptCall) { // // We're destroying a conf parent so we want to zero // out the pConfList field of all the conf children, // essentially removing them from the conference. // TPOINTERLIST confCallList, *pConfCallList = &confCallList; if (GetConfCallListFromConf( pConfList, &pConfCallList ) == 0) { for( i = 1; i < pConfCallList->dwNumUsedEntries; i++ ) { SetCallConfList( pConfCallList->aEntries[i], NULL, FALSE ); } if (pConfCallList != &confCallList) { ServerFree (pConfCallList); } } while (pConfList) { PTCONFERENCELIST pNextConfList = pConfList->pNext; ServerFree (pConfList); pConfList = pNextConfList; } } else { } } } while (ptCall->lActiveFastCallClients != 0) { Sleep (5); } FreetCall (ptCall); } else { LOG((TL_ERROR, "DestroytCall: two waits failed!")); } } void PASCAL DestroytCallClient( PTCALLCLIENT ptCallClient ) { BOOL bUnlock = FALSE, bExit = TRUE, bDestroytCall, bSendCallInfoMsgs, bFastCallClient; HCALL hCall; PTCALL ptCall; PTCALLCLIENT ptCallClient2; LOG((TL_TRACE, "DestroytCallClient: enter, ptCallCli=x%p", ptCallClient)); // // Check that this is a valid tCallClient, & if so lock the // corresponding tCall (and recheck) // try { if (ptCallClient->dwKey == TINCOMPLETECALLCLIENT_KEY || ptCallClient->dwKey == TCALLCLIENT_KEY) { ptCall = ptCallClient->ptCall; LOCKTCALL (ptCall); bUnlock = TRUE; // // Check to be sure we are working on a valid memory // ptCallClient2 = ReferenceObject ( ghHandleTable, ptCallClient->hCall, ptCallClient->dwKey ); if (ptCallClient2 != NULL) { DereferenceObject ( ghHandleTable, ptCallClient2->hCall, 1 ); } if ((ptCallClient->dwKey == TINCOMPLETECALLCLIENT_KEY || ptCallClient->dwKey == TCALLCLIENT_KEY) && ptCall == ptCallClient->ptCall && ptCallClient2 == ptCallClient) { // // We can continue detroying this tCallClient // bExit = FALSE; } } } myexcept { LOG((TL_ERROR, "DestroytCallClient: %lx faulted looking at key", ptCallClient )); } if (bExit) { if (bUnlock) { UNLOCKTCALL (ptCall); } return; } // // Mark tCallClient as bad // ptCallClient->dwKey = INVAL_KEY; // // Munge tCall's num owners/monitors fields // if (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER) { ptCall->dwNumOwners--; // // NOTE: per bug #20545 we're no longer auto-dropping // non-IDLE calls; figured this would be the // wrong thing to do in a distributed system // // dankn 02/15/96 // } else { ptCall->dwNumMonitors--; // // NOTE: per bug #20545 we're no longer auto-dropping // non-IDLE calls; figured this would be the // wrong thing to do in a distributed system // // dankn 02/15/96 // } // // Remove it from the tCall's tCallClient list // bDestroytCall = FALSE; bSendCallInfoMsgs = (ptCall->dwKey == TCALL_KEY ? TRUE : FALSE); if (ptCallClient->pNextSametCall) { ptCallClient->pNextSametCall->pPrevSametCall = ptCallClient->pPrevSametCall; } if (ptCallClient->pPrevSametCall) { ptCallClient->pPrevSametCall->pNextSametCall = ptCallClient->pNextSametCall; } else if (ptCallClient->pNextSametCall) { ptCall->ptCallClients = ptCallClient->pNextSametCall; } else // last call client so destroy the tCall too { ptCall->ptCallClients = NULL; bDestroytCall = TRUE; } UNLOCKTCALL (ptCall); // // Remove tCallClient from the tLineClient's tCallClient list // RemoveCallClientFromLineClientList (ptCallClient); // // Save the hCall in a local because it won't be safe to access // ptCallClient->hCall once we've decremented // ptCall->lActiveFastCallClients below // hCall = ptCallClient->hCall; // // If this is a fast call client decrement the number of active // fast call clients prior to calling DestroytCall // bFastCallClient = (ptCallClient >= ptCall->aFastCallClients && ptCallClient < (ptCall->aFastCallClients + DEF_NUM_FAST_CALLCLIENTS)); if (bFastCallClient) { InterlockedDecrement (&ptCall->lActiveFastCallClients); } if (bDestroytCall) { DestroytCall (ptCall); bSendCallInfoMsgs = FALSE; } // // Send call info msgs as appropriate // if (bSendCallInfoMsgs) { SendMsgToCallClients( ptCall, NULL, LINE_CALLINFO, (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERDECR : LINECALLINFOSTATE_NUMMONITORS), 0, 0 ); } // // Decrement reference count remove the initial (creation) reference // DereferenceObject (ghHandleTable, hCall, 1); } void PASCAL DestroytLine( PTLINE ptLine, BOOL bUnconditional ) { BOOL bCloseMutex; HANDLE hMutex; LOG((TL_TRACE, "DestroytLine: enter, ptLine=x%p, bUnconditional=%d", ptLine, bUnconditional )); if (WaitForExclusivetLineAccess( ptLine, &hMutex, &bCloseMutex, INFINITE )) { // // If the key is bad another thread is in the process of // destroying this widget, so just release the mutex & // return. Otherwise, if this is a conditional destroy // & there are existing clients (which can happen when // one app is closing the last client just as another app // is creating one) just release the mutex & return. // Otherwise, mark the widget as bad and proceed with // the destroy; also, send CLOSE msgs to all the clients // (note that we have to do this manually rather than via // SendMsgToLineClients since 1) we don't want to hold the // mutex when sending msgs [deadlock], and 2) we mark the // dwKey as invalid) // { BOOL bExit; TPOINTERLIST fastClientList, *pClientList = &fastClientList; if (ptLine->dwKey == TLINE_KEY && (bUnconditional == TRUE || ptLine->ptLineClients == NULL)) { if (GetLineClientListFromLine (ptLine, &pClientList) != 0) { // // If here we know there's at least a few entries // in the fastClientList (DEF_NUM_PTR_LIST_ENTRIES // to be exact), so we'll just work with that list // and at least get msgs out to a few clients // pClientList = &fastClientList; fastClientList.dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES; } ptLine->dwKey = INVAL_KEY; bExit = FALSE; } else { bExit = TRUE; } MyReleaseMutex (hMutex, bCloseMutex); if (bExit) { LOG((TL_TRACE, "DestroytLine: exit, didn't destroy tLine=x%p", ptLine )); return; } if (pClientList->dwNumUsedEntries) { DWORD i; PTCLIENT ptClient; PTLINECLIENT ptLineClient; ASYNCEVENTMSG msg; ZeroMemory (&msg, sizeof (msg)); msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.Msg = LINE_CLOSE; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { ptLineClient = (PTLINECLIENT) pClientList->aEntries[i]; try { msg.InitContext = ptLineClient->ptLineApp->InitContext; msg.hDevice = ptLineClient->hRemoteLine; msg.OpenContext = ptLineClient->OpenContext; ptClient = ptLineClient->ptClient; if (ptLineClient->dwKey == TLINECLIENT_KEY && (!FMsgDisabled( ptLineClient->ptLineApp->dwAPIVersion, ptLineClient->adwEventSubMasks, LINE_CLOSE, 0 ))) { WriteEventBuffer (ptClient, &msg); } } myexcept { // do nothing } } } if (pClientList != &fastClientList) { ServerFree (pClientList); } } // // Destroy all the widget's clients. Note that we want to // grab the mutex (and we don't have to dup it, since this // thread will be the one to close it) each time we reference // the list of clients, since another thread might be // destroying a client too. // { HLINE hLine; hMutex = ptLine->hMutex; destroy_tLineClients: WaitForSingleObject (hMutex, INFINITE); hLine = (ptLine->ptLineClients ? ptLine->ptLineClients->hLine : (HLINE) 0); ReleaseMutex (hMutex); if (hLine) { DestroytLineClient (hLine); goto destroy_tLineClients; } } // // There may yet be some tCall's hanging around, i.e. incoming // calls that we have not processed the 1st call state msg for // and hence have no associated owner/monitor that would have // been destroyed in the loop above, so destroy any of these // before proceeding // // { PTCALL ptCall; destroy_UnownedtCalls: WaitForSingleObject (hMutex, INFINITE); ptCall = ptLine->ptCalls; ReleaseMutex (hMutex); if (ptCall) { DestroytCall (ptCall); goto destroy_UnownedtCalls; } } // // Tell the provider to close the widget // { PTPROVIDER ptProvider = ptLine->ptProvider; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { WaitForSingleObject (ptProvider->hMutex, INFINITE); } if ( ptProvider->apfn[SP_LINECLOSE] ) { CallSP1( ptProvider->apfn[SP_LINECLOSE], "lineClose", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine ); } if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { ReleaseMutex (ptProvider->hMutex); } } // // NULLify the ptLine field in the lookup entry, so LOpen will // know it has to open the SP's line on the next open request // { PTLINELOOKUPENTRY pEntry; pEntry = GetLineLookupEntry (ptLine->dwDeviceID); if (NULL != pEntry) { pEntry->ptLine = NULL; } } DereferenceObject (ghHandleTable, ptLine->hLine, 1); } else { LOG((TL_ERROR, "DestroytLine: WaitForExclusivetLineAccess failed" )); } // PERF if (PerfBlock.dwLinesInUse) { PerfBlock.dwLinesInUse--; } else { LOG((TL_INFO, "PERF: dwNumLinesInUse below 0")); } LOG((TL_TRACE, "DestroytLine: exit, destroyed line=x%p", ptLine)); } void PASCAL DestroytLineClient( HLINE hLine ) { BOOL bDupedMutex; HANDLE hMutex; PTLINECLIENT ptLineClient; LOG((TL_TRACE, "DestroytLineClient: enter, hLine=x%x", hLine)); if (!(ptLineClient = ReferenceObject (ghHandleTable, hLine, 0))) { return; } // // If we can get exclusive access to this tLineClient then mark // it (the dwKey) as bad & continue with teardown. Else, another // thread is already in the process of destrying this tLineClient // // if (WaitForExclusiveLineClientAccess (ptLineClient)) { BOOL bSendDevStateCloseMsg = FALSE; DWORD dwProxyCloseMsgs = 0; PTLINE ptLine; PTPROVIDER ptProvider = ptLineClient->ptLine->ptProvider; HANDLE hProviderMutex = NULL; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { hProviderMutex = ptProvider->hMutex; } ptLineClient->dwKey = INVAL_KEY; // // Remove the proxy server publishing if any // if (ptLineClient->szProxyClsid) { OnProxyLineClose (ptLineClient->szProxyClsid); ServerFree (ptLineClient->szProxyClsid); } // // Destroy all the tCallClients. Note that we want to grab the // lock each time we reference the list of tCallClient's, since // another thread might be destroying a tCallClient too. // { PTCALLCLIENT ptCallClient; destroy_tCallClients: ptCallClient = ptLineClient->ptCallClients; UNLOCKTLINECLIENT (ptLineClient); if (ptCallClient) { DestroytCallClient (ptCallClient); LOCKTLINECLIENT (ptLineClient); goto destroy_tCallClients; } } // // Remove tLineClient from tLineApp's list. Note that we don't // have to worry validating the tLineApp here, since we know // it's valid (another thread trying to destroy the tLineApp // will be spinning until the tLineClient we're destroying here // is removed from the tLineApp's list) // { PTLINEAPP ptLineApp = (PTLINEAPP) ptLineClient->ptLineApp; LOCKTLINEAPP (ptLineApp); if (ptLineClient->pNextSametLineApp) { ptLineClient->pNextSametLineApp->pPrevSametLineApp = ptLineClient->pPrevSametLineApp; } if (ptLineClient->pPrevSametLineApp) { ptLineClient->pPrevSametLineApp->pNextSametLineApp = ptLineClient->pNextSametLineApp; } else { ptLineApp->ptLineClients = ptLineClient->pNextSametLineApp; } UNLOCKTLINEAPP (ptLineApp); } // // Grab the tLine's mutex & start munging. Note that we don't // have to worry about dup-ing the mutex here because we know // it's valid & won't get closed before we release it. // ptLine = ptLineClient->ptLine; hMutex = ptLine->hMutex; WaitForSingleObject (hMutex, INFINITE); // // If client had call hub tracking enabled then adjust tLine // if (ptLineClient->dwCurrentTracking) { --ptLine->dwNumCallHubTrackers; if ((ptLineClient->dwCurrentTracking & LINECALLHUBTRACKING_PROVIDERLEVEL) && (--ptLine->dwNumCallHubTrackersSPLevel == 0)) { const LINECALLHUBTRACKINGINFO trackingInfo = { sizeof (LINECALLHUBTRACKINGINFO), sizeof (LINECALLHUBTRACKINGINFO), sizeof (LINECALLHUBTRACKINGINFO), 0, LINECALLHUBTRACKING_NONE }; if (hProviderMutex) { WaitForSingleObject (hProviderMutex, INFINITE); } if (ptLine->ptProvider->apfn[SP_LINESETCALLHUBTRACKING]) { CallSP2( ptLine->ptProvider->apfn[SP_LINESETCALLHUBTRACKING], "lineSetCallHubTracking", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (ULONG_PTR) &trackingInfo ); } if (hProviderMutex) { ReleaseMutex (hProviderMutex); } } } // // If client registered as a proxy then unregister it // if (ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY) { DWORD i; for( i = LINEPROXYREQUEST_SETAGENTGROUP; i <= LINEPROXYREQUEST_LASTVALUE; i++ ) { if (ptLine->apProxys[i] == ptLineClient) { // // Alert other clients that a proxy close has occured // LOG((TL_INFO, "tell clients proxy %02X closed", i)); dwProxyCloseMsgs |= (1 << (i - 1)); ptLine->apProxys[i] = NULL; } } } // // // if (ptLineClient->dwExtVersion) { if ((--ptLine->dwExtVersionCount) == 0) { if (hProviderMutex) { WaitForSingleObject (hProviderMutex, INFINITE); } if (ptLine->ptProvider->apfn[SP_LINESELECTEXTVERSION]) { CallSP2( ptLine->ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) 0 ); } if (hProviderMutex) { ReleaseMutex (hProviderMutex); } ptLine->dwExtVersion = 0; } } // // Remove the tLineClient from the tLine's list & decrement // the number of opens // if (ptLineClient->pNextSametLine) { ptLineClient->pNextSametLine->pPrevSametLine = ptLineClient->pPrevSametLine; } if (ptLineClient->pPrevSametLine) { ptLineClient->pPrevSametLine->pNextSametLine = ptLineClient->pNextSametLine; } else { ptLine->ptLineClients = ptLineClient->pNextSametLine; } ptLine->dwNumOpens--; // // See if we need to reset the monitored media modes or close // the tLine (still hanging on the the mutex) // if (ptLine->dwKey == TLINE_KEY) { LOG((TL_INFO, "It's a line_key")); if (ptLine->ptLineClients) { LOG((TL_INFO, "...and there are still clients")); if (ptLine->dwOpenMediaModes && ptLineClient->dwMediaModes) { DWORD dwUnionMediaModes = 0; PTLINECLIENT ptLineClientTmp = ptLine->ptLineClients; while (ptLineClientTmp) { if (ptLineClientTmp->dwPrivileges & LINECALLPRIVILEGE_OWNER) { dwUnionMediaModes |= ptLineClientTmp->dwMediaModes; } ptLineClientTmp = ptLineClientTmp->pNextSametLine; } if (dwUnionMediaModes != ptLine->dwOpenMediaModes) { LONG lResult; if (hProviderMutex) { WaitForSingleObject (hProviderMutex, INFINITE); } if (ptLine->ptProvider->apfn [SP_LINESETDEFAULTMEDIADETECTION]) { lResult = CallSP2( ptLine->ptProvider->apfn [SP_LINESETDEFAULTMEDIADETECTION], "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) dwUnionMediaModes ); } else { lResult = LINEERR_OPERATIONUNAVAIL; } if (hProviderMutex) { ReleaseMutex (hProviderMutex); } ptLine->dwOpenMediaModes = dwUnionMediaModes; } } bSendDevStateCloseMsg = TRUE; // // See if we need to reset the status msgs (if so, make // sure to check/set the busy flag & not to hold the // mutex while calling down to provider - see comments // in LSetStatusMessages) // if ((ptLineClient->dwLineStates & ~LINEDEVSTATE_REINIT) || ptLineClient->dwAddressStates) { DWORD dwUnionLineStates = 0, dwUnionAddressStates = 0; PTLINECLIENT ptLC; while (ptLine->dwBusy) { BOOL bClosed = TRUE; ReleaseMutex (hMutex); Sleep (50); WaitForSingleObject (hMutex, INFINITE); try { if (ptLine->dwKey == TLINE_KEY) { bClosed = FALSE; } } myexcept { // do nothing } if (bClosed) { goto releasMutex; } } for( ptLC = ptLine->ptLineClients; ptLC; ptLC = ptLC->pNextSametLine ) { dwUnionLineStates |= ptLC->dwLineStates; dwUnionAddressStates |= ptLC->dwAddressStates; } if ((dwUnionLineStates != ptLine->dwUnionLineStates) || (dwUnionAddressStates != ptLine->dwUnionAddressStates)) { if (ptLine->ptProvider->apfn[SP_LINESETSTATUSMESSAGES]) { LONG lResult; TSPIPROC pfn; HDRVLINE hdLine = ptLine->hdLine; pfn = ptLine->ptProvider-> apfn[SP_LINESETSTATUSMESSAGES]; ptLine->dwBusy = 1; ReleaseMutex (hMutex); if (hProviderMutex) { WaitForSingleObject (hProviderMutex, INFINITE); } lResult = CallSP3( pfn, "lineSetStatusMessages", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) dwUnionLineStates, (DWORD) dwUnionAddressStates ); if (hProviderMutex) { ReleaseMutex (hProviderMutex); } WaitForSingleObject (hMutex, INFINITE); try { if (ptLine->dwKey == TLINE_KEY) { ptLine->dwBusy = 0; if (lResult == 0) { ptLine->dwUnionLineStates = dwUnionLineStates; ptLine->dwUnionAddressStates = dwUnionAddressStates; } } } myexcept { // do nothing } } } } } else { // // This was the last client so destroy the tLine too // LOG((TL_INFO, "...and it's the last one out")); ReleaseMutex (hMutex); hMutex = NULL; DestroytLine (ptLine, FALSE); // conditional destroy } } releasMutex: if (hMutex) { ReleaseMutex (hMutex); } // // Now that the mutex is released send any necessary msgs // if (bSendDevStateCloseMsg) { DWORD dwOrdinal, dwBitFlag; SendMsgToLineClients( ptLine, NULL, LINE_LINEDEVSTATE, LINEDEVSTATE_CLOSE, 0, 0 ); for( dwOrdinal = LINEPROXYREQUEST_SETAGENTGROUP, dwBitFlag = 1; dwProxyCloseMsgs != 0; dwOrdinal++, dwBitFlag <<= 1) { if (dwProxyCloseMsgs & dwBitFlag) { SendMsgToLineClients( ptLine, NULL, LINE_PROXYSTATUS, LINEPROXYSTATUS_CLOSE, dwOrdinal, // LINEPROXYREQUEST_xx 0 ); dwProxyCloseMsgs ^= dwBitFlag; } } } // // Complete any remaining // proxy requests // if (ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY) { PASYNCREQUESTINFO pAsyncRequestInfo = ptLineClient->pPendingProxyRequests, pNextAsyncRequestInfo; while (pAsyncRequestInfo) { pNextAsyncRequestInfo = (PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5; pAsyncRequestInfo->dwKey = TASYNC_KEY; CompletionProc (pAsyncRequestInfo, LINEERR_OPERATIONUNAVAIL); DereferenceObject( ghHandleTable, pAsyncRequestInfo->dwLocalRequestID, 1 ); pAsyncRequestInfo = pNextAsyncRequestInfo; } } // // Free resources // if (ptLineClient->aNumRings) { ServerFree (ptLineClient->aNumRings); } // // Decrement reference count by two to remove the initial // reference & the reference above // DereferenceObject (ghHandleTable, hLine, 2); } else { DereferenceObject (ghHandleTable, hLine, 1); LOG((TL_ERROR, "DestroytLineClient: WaitForExclLineClientAccess failed!")); } } LONG PASCAL DestroytLineApp( HLINEAPP hLineApp ) { PTCLIENT ptClient; PTLINEAPP ptLineApp; LOG((TL_TRACE, "DestroytLineApp: enter, hLineApp=x%x", hLineApp)); if (!(ptLineApp = ReferenceObject (ghHandleTable, hLineApp, TLINEAPP_KEY))) { return (TapiGlobals.dwNumLineInits ? LINEERR_INVALAPPHANDLE : LINEERR_UNINITIALIZED); } // // See if this this is a valid tLineApp, & if so grab the lock // and mark it as bad, then continue teardown. Else, another // thread is in the processing of tearing down this tLineApp, // so return. // LOCKTLINEAPP (ptLineApp); if (ptLineApp->dwKey != TLINEAPP_KEY) { UNLOCKTLINEAPP (ptLineApp); DereferenceObject (ghHandleTable, hLineApp, 1); return (TapiGlobals.dwNumPhoneInits ? LINEERR_INVALAPPHANDLE : LINEERR_UNINITIALIZED); } ptLineApp->dwKey = INVAL_KEY; ptClient = (PTCLIENT) ptLineApp->ptClient; // // Destroy all the tLineClients. Note that we want to grab the // lock each time we reference the list of tLineClient's, since // another thread might be destroying a tLineClient too. // { HLINE hLine; destroy_tLineClients: hLine = (ptLineApp->ptLineClients ? ptLineApp->ptLineClients->hLine : (HLINE) 0); UNLOCKTLINEAPP (ptLineApp); if (hLine) { DestroytLineClient (hLine); LOCKTLINEAPP (ptLineApp); goto destroy_tLineClients; } } // // Remove tLineApp from tClient's list. Note that we don't // have to worry about dup-ing the mutex here because we know // it's valid & won't get closed before we release it. // LOCKTCLIENT (ptClient); if (ptLineApp->pNext) { ptLineApp->pNext->pPrev = ptLineApp->pPrev; } if (ptLineApp->pPrev) { ptLineApp->pPrev->pNext = ptLineApp->pNext; } else { ptClient->ptLineApps = ptLineApp->pNext; } // // Clean up any existing generic dialog instances if this is the // last tLineApp on this tClient // if (ptClient->pGenericDlgInsts && ptClient->ptLineApps == NULL) { PTAPIDIALOGINSTANCE pGenericDlgInst = ptClient->pGenericDlgInsts, pNextGenericDlgInst; TAPI32_MSG params; while (pGenericDlgInst) { pNextGenericDlgInst = pGenericDlgInst->pNext; params.u.Req_Func = 0; params.Params[0] = pGenericDlgInst->htDlgInst; params.Params[1] = LINEERR_OPERATIONFAILED; FreeDialogInstance( ptClient, (PFREEDIALOGINSTANCE_PARAMS) ¶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->hLine; } } myexcept { LOG((TL_ERROR, "LineProlog: exception")); lResult = LINEERR_INVALCALLHANDLE; } if (lResult || ptCallClient->dwKey != TCALLCLIENT_KEY) { lResult = LINEERR_INVALCALLHANDLE; } else if (phMutex && (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = LINEERR_OPERATIONFAILED; } } } } else { lResult = LINEERR_INVALCALLHANDLE; } break; } case ANY_RT_HLINE: { PTLINECLIENT ptLineClient; LOG((TL_INFO, "LineProlog: ANY_RT_HLINE")); if ((ptLineClient = ReferenceObject( ghHandleTable, dwArg, TLINECLIENT_KEY ))) { LOG((TL_INFO, "LineProlog: ReferenceObject returned ptLineClient %p", ptLineClient)); if (ptLineClient->ptClient != ptClient) { lResult = LINEERR_INVALLINEHANDLE; } else { *pObjectToDereference = dwArg; *pContext = ptLineClient; try { ptProvider = ptLineClient->ptLine->ptProvider; *((HDRVLINE *) phdXxx) = ptLineClient->ptLine->hdLine; if (ppAsyncRequestInfo) { initContext = ptLineClient->ptLineApp->InitContext; openContext = ptLineClient->OpenContext; htXxx = (ULONG_PTR)ptLineClient->ptLine->hLine; } } myexcept { LOG((TL_ERROR, "LineProlog: exception")); lResult = LINEERR_INVALLINEHANDLE; } if (lResult || ptLineClient->dwKey != TLINECLIENT_KEY) { lResult = LINEERR_INVALLINEHANDLE; } else if (phMutex && (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { LOG((TL_ERROR, "LineProlog: waitformutex failed")); lResult = LINEERR_OPERATIONFAILED; } } } } else { LOG((TL_ERROR, "LineProlog: ReferenceObject returned NULL")); lResult = LINEERR_INVALLINEHANDLE; } break; } case DEVICE_ID: { PTLINEAPP ptLineApp = NULL; PTLINELOOKUPENTRY pLineLookupEntry; #if TELE_SERVER // // If it's a server, map the device id // if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { try { if ((dwPrivilege >= ptClient->dwLineDevices) || (ptClient->pLineDevices[dwPrivilege] == 0xffffffff)) { lResult = LINEERR_BADDEVICEID; goto LineProlog_exit; } *((LPDWORD) phdXxx) = ptClient->pLineDevices[dwPrivilege]; } myexcept { lResult = LINEERR_INVALLINEHANDLE; goto LineProlog_exit; } } else #endif { *((LPDWORD)phdXxx) = dwPrivilege; } if (dwArg && !(ptLineApp = IsValidLineApp ((HLINEAPP) dwArg, ptClient))) { lResult = LINEERR_INVALAPPHANDLE; } if (ppAsyncRequestInfo) { try { initContext = ptLineApp->InitContext; openContext = 0; if (ptLineApp->dwKey != TLINEAPP_KEY) { lResult = LINEERR_INVALAPPHANDLE; } } myexcept { lResult = LINEERR_INVALAPPHANDLE; } } if (lResult != 0) { // do nothing } else if (!(pLineLookupEntry = GetLineLookupEntry (*(LPDWORD)phdXxx))) { lResult = LINEERR_BADDEVICEID; } else if (pLineLookupEntry->bRemoved) { lResult = LINEERR_NODEVICE; } else if (!(ptProvider = pLineLookupEntry->ptProvider)) { lResult = LINEERR_NODRIVER; } else { *pContext = pLineLookupEntry; if (phMutex && (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = LINEERR_OPERATIONFAILED; } } } break; } } // switch if (lResult) { goto LineProlog_exit; } // // Make sure that if caller wants a pointer to a TSPI proc that the // func is exported by the provider // if (ppfnTSPI_lineXxx && !(*ppfnTSPI_lineXxx = ptProvider->apfn[dwTSPIFuncIndex])) { lResult = LINEERR_OPERATIONUNAVAIL; goto LineProlog_exit; } // // See if we need to alloc & init an ASYNCREQUESTINFO struct // if (ppAsyncRequestInfo) { PASYNCREQUESTINFO pAsyncRequestInfo; if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO)))) { lResult = LINEERR_NOMEM; goto LineProlog_exit; } pAsyncRequestInfo->dwLocalRequestID = (DWORD) NewObject( ghHandleTable, pAsyncRequestInfo, NULL ); if (pAsyncRequestInfo->dwLocalRequestID == 0) { ServerFree (pAsyncRequestInfo); lResult = LINEERR_NOMEM; goto LineProlog_exit; } pAsyncRequestInfo->dwKey = TASYNC_KEY; pAsyncRequestInfo->ptClient = ptClient; pAsyncRequestInfo->InitContext = initContext; pAsyncRequestInfo->OpenContext = openContext; pAsyncRequestInfo->htXxx = (dwArgType != DEVICE_ID ? htXxx : pAsyncRequestInfo->dwLocalRequestID); // a +/- random # LOG((TL_INFO, "LineProlog: OpenContext %p", openContext)); pAsyncRequestInfo->dwLineFlags = 1; if (dwRemoteRequestID) { lResult = pAsyncRequestInfo->dwRemoteRequestID = dwRemoteRequestID; } else { lResult = pAsyncRequestInfo->dwRemoteRequestID = pAsyncRequestInfo->dwLocalRequestID; } *ppAsyncRequestInfo = pAsyncRequestInfo; } LineProlog_exit: #if DBG { char szResult[32]; LOG((TL_TRACE, "LineProlog: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (lResult, szResult) )); } #else LOG((TL_TRACE, "LienProlog: exit, result = x%lx", lResult )); #endif return lResult; } void PASCAL LineEpilogSync( LONG *plResult, HANDLE hMutex, BOOL bCloseMutex, DWORD ObjectToDereference #if DBG ,char *pszFuncName #endif ) { DereferenceObject (ghHandleTable, ObjectToDereference, 1); if (hMutex) { MyReleaseMutex (hMutex, bCloseMutex); } #if DBG { char szResult[32]; LOG((TL_TRACE, "LineEpilogSync: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (*plResult, szResult) )); } #else LOG((TL_TRACE, "LineEpilogSync: exit, result=x%x", *plResult )); #endif } void PASCAL LineEpilogAsync( LONG *plResult, LONG lRequestID, HANDLE hMutex, BOOL bCloseMutex, PASYNCREQUESTINFO pAsyncRequestInfo, DWORD ObjectToDereference #if DBG ,char *pszFuncName #endif ) { DereferenceObject (ghHandleTable, ObjectToDereference, 1); MyReleaseMutex (hMutex, bCloseMutex); if (lRequestID > 0) { if (*plResult <= 0) { if (*plResult == 0) { LOG((TL_ERROR, "Error: SP returned 0, not request ID")); } // // If here the service provider returned an error (or 0, // which it never should for async requests), so call // CompletionProcSP like the service provider normally // would, & the worker thread will take care of sending // the client a REPLY msg with the request result (we'll // return an async request id) // CompletionProcSP( pAsyncRequestInfo->dwLocalRequestID, *plResult ); } } else if (pAsyncRequestInfo != NULL) { // // If here an error occured before we even called the service // provider, so just free the async request (the error will // be returned to the client synchronously) // DereferenceObject( ghHandleTable, pAsyncRequestInfo->dwLocalRequestID, 1 ); } *plResult = lRequestID; #if DBG { char szResult[32]; LOG((TL_TRACE, "LineEpilogAsync: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (lRequestID, szResult) )); } #else LOG((TL_TRACE, "LineEpilogAsyc: exit, result=x%lx", lRequestID )); #endif } void PASCAL LineEventProc( HTAPILINE htLine, HTAPICALL htCall, DWORD dwMsg, ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 ) { LOG((TL_TRACE, "LineEventProc")); switch (dwMsg) { case LINE_ADDRESSSTATE: case LINE_LINEDEVSTATE: case LINE_DEVSPECIFIC: case LINE_DEVSPECIFICFEATURE: case LINE_PROXYSTATUS: case LINE_AGENTSTATUS: { PTLINE ptLine; if (!(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY))) { return; } if (dwMsg == LINE_LINEDEVSTATE && htLine == 0 && Param1 & LINEDEVSTATE_REINIT) { SendReinitMsgToAllXxxApps(); } else { SendMsgToLineClients( ptLine, NULL, dwMsg, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), DWORD_CAST(Param3,__FILE__,__LINE__) ); } DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); break; } case LINE_AGENTSPECIFIC: if (htCall) { PTCALL ptCall; if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)) { SendMsgToCallClients( ptCall, NULL, LINE_AGENTSPECIFIC, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), DWORD_CAST(Param3,__FILE__,__LINE__) ); DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); } } else { PTLINE ptLine; if(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY)) { SendMsgToLineClients( ptLine, NULL, LINE_AGENTSPECIFIC, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), DWORD_CAST(Param3,__FILE__,__LINE__) ); DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); } } break; case LINE_CLOSE: { PTLINE ptLine; if (!(ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY))) { break; } if (ptLine->dwKey == TINCOMPLETELINE_KEY) { // // The device is in the process of getting opened but // the key has not been set & the Open() func still owns // the mutex and has stuff to do, so repost the msg // and try again later. (Set Param3 to special value // to indicate this repost, so EventProcSP doesn't recurse) // LineEventProcSP (htLine, 0, LINE_CLOSE, 0, 0, 0xdeadbeef); } else if (ptLine->dwKey == TLINE_KEY) { DestroytLine (ptLine, TRUE); // unconditional destroy } DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); break; } case LINE_CALLDEVSPECIFIC: case LINE_CALLDEVSPECIFICFEATURE: case LINE_CALLINFO: { PTCALL ptCall; if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)) { switch (dwMsg) { case LINE_CALLDEVSPECIFIC: dwMsg = LINE_DEVSPECIFIC; break; case LINE_CALLDEVSPECIFICFEATURE: dwMsg = LINE_DEVSPECIFICFEATURE; break; case LINE_CALLINFO: { Param2 = Param3 = 0; if ((Param1 == LINECALLINFOSTATE_CALLID) || (Param1 == LINECALLINFOSTATE_RELATEDCALLID)) { if ((WaitForExclusivetCallAccess (ptCall, TCALL_KEY))) { DWORD dwPreviousCallID = ptCall->dwCallID; GetCallIDs (ptCall); DoCallHubHashing (ptCall, dwPreviousCallID); UNLOCKTCALL(ptCall); } } break; } } SendMsgToCallClients( ptCall, NULL, dwMsg, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), DWORD_CAST(Param3,__FILE__,__LINE__) ); DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); } break; } case LINE_MONITORDIGITS: case LINE_MONITORMEDIA: { PTCALL ptCall; if (NULL == htCall) { return; } if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)) { SendMsgToCallClients( ptCall, NULL, dwMsg, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount()) ); DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); } break; } case LINE_CALLSTATE: { BOOL fastPrivilegeList[DEF_NUM_PTR_LIST_ENTRIES], *pPrivilegeList = fastPrivilegeList; DWORD i, j, dwNumUsedEntries = 0, dwNumTotalEntries= DEF_NUM_PTR_LIST_ENTRIES; PTCALL ptCall; TPOINTERLIST fastCallClientList, *pCallClientList = &fastCallClientList; TPOINTERLIST fastConfCallClientList, *pConfCallClientList = NULL; LOG((TL_EVENT, "LineEventProc: LINE_CALLSTATE event x%lx", Param1)); if(!(ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY))) { break; } if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { PTCALLCLIENT ptCallClient = ptCall->ptCallClients; ASYNCEVENTMSG msg[2]; if (Param1 == LINECALLSTATE_OFFERING) { ptCall->dwDrvCallFlags |= DCF_INCOMINGCALL; PerfBlock.dwCurrentIncomingCalls++; PerfBlock.dwTotalIncomingCalls++; PerfBlock.dwCurrentOutgoingCalls--; PerfBlock.dwTotalOutgoingCalls--; } if (ptCall->bAlertApps) { // // This is the first state msg we've received for an incoming // call. We need to determine who owns & who monitors it, // and create the appropriate tCallClients // BOOL bFindOwner; DWORD dwMediaModes = (DWORD) Param3, dwSPIVersion = ptCall->ptLine->dwSPIVersion, dwAddressID; PTLINECLIENT ptLineClientOwner; ptCall->bAlertApps = FALSE; // // If this is a remotesp call then Param2 points at a // DWORD array, the 1st entry of which is the "real" // Param2 for this message (i.e. the call state mode), // the 2nd entry of which is the original privilege for // this call, and the 3rd entry of which is htCall // (which we use for call verification purposes) // if (ptCall->ptProvider != pRemoteSP) { bFindOwner = TRUE; } else { BOOL bBreak = FALSE; PULONG_PTR pdwRealParam2 = (PULONG_PTR) Param2, pdwPrivilege = (((PULONG_PTR) Param2) + 1); LPHTAPICALL phtCall = (LPHTAPICALL) (((LPDWORD) Param2) + 2); try { Param2 = *pdwRealParam2; bFindOwner = (*pdwPrivilege & LINECALLPRIVILEGE_OWNER ? TRUE : FALSE); bBreak = (*phtCall != htCall ? TRUE : FALSE); } myexcept { bBreak = TRUE; } if (bBreak) { UNLOCKTCALL(ptCall); goto LINE_CALLSTATE_break; } } // // Retrieve call's address id, etc // GetCallIDs (ptCall); dwAddressID = ptCall->dwAddressID; UNLOCKTCALL(ptCall); // // Add the UNKNOWN bit if >1 bit set // if version is <= 2.1 if ( ( (dwSPIVersion <= TAPI_VERSION2_1) && !IsOnlyOneBitSetInDWORD (dwMediaModes) ) || dwMediaModes == 0) { dwMediaModes |= LINEMEDIAMODE_UNKNOWN; } // // Try to find an owner. If no owner found then destroy // the tCall. // if (bFindOwner) { PTLINE ptLine; ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY); if (!ptLine) { // // Line closed // DestroytCall (ptCall); goto LINE_CALLSTATE_break; } LINE_CALLSTATE_findOwner: if ((ptLineClientOwner = GetHighestPriorityLineClient( ptLine, dwMediaModes, dwAddressID ))) { LONG lResult; PTCALLCLIENT ptCallClientOwner; if ((lResult = CreatetCallClient( ptCall, ptLineClientOwner, LINECALLPRIVILEGE_OWNER, TRUE, FALSE, &ptCallClientOwner, TRUE )) != 0) { if (lResult == LINEERR_INVALLINEHANDLE) { // // The tLineClient was just closed, so jump // up top & try to find another owner // goto LINE_CALLSTATE_findOwner; } else { // // No mem, line closed, etc // DestroytCall (ptCall); DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); goto LINE_CALLSTATE_break; } } } DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); } else if (Param1 == LINECALLSTATE_UNKNOWN && Param2 == 0xa5a5a5a5) { // // If here we're being called directly from // remotesp!TSPI_lineGetID, who's being called // by LGetNewCalls. We're not going to look // for an owner of this call, but if we don't // find any monitors we still don't want to // tear the call down, because we want to give // a handle to the app doing the lineGetNewCalls // (which may not have MONITOR privileges). // // So we do the following to prevent the call // from getting destroyed. // ptLineClientOwner = (PTLINECLIENT) 1; Param2 = 0; } else { // // Set ptLineClientOwner == NULL, becaue if there // aren't any monitors we'll want to destroy this // calls. // ptLineClientOwner = (PTLINECLIENT) NULL; } if (CreateCallMonitors (ptCall, TRUE) <= 0 && !ptLineClientOwner) { DestroytCall (ptCall); goto LINE_CALLSTATE_break; } if (!WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { goto LINE_CALLSTATE_break; } } // // NOTE: per bug #20545 we're no longer auto-dropping // non-IDLE calls; figured this would be the wrong // thing to do in a distributed system // // dankn 02/15/96 // // // SP-initiated conference // if (Param1 == LINECALLSTATE_CONFERENCED) { PTCALL ptConfCall; if (!ptCall->pConfList) { PTCONFERENCELIST pConfList; ptCall->pConfList = (LPVOID) LongToPtr(0xffffffff); UNLOCKTCALL(ptCall); if ((ptConfCall = (PTCALL) ReferenceObject( ghHandleTable, (HCALL)(ULONG_PTR)Param2, TCALL_KEY ))) { if (WaitForExclusivetCallAccess( ptConfCall, TCALL_KEY )) { if (!ptConfCall->pConfList) { if ((pConfList = ServerAlloc( sizeof (TCONFERENCELIST) + sizeof(PTCALL) * (DEF_NUM_CONF_LIST_ENTRIES - 1) ))) { pConfList->dwKey = TCONFLIST_KEY; pConfList->dwNumTotalEntries = DEF_NUM_CONF_LIST_ENTRIES; pConfList->dwNumUsedEntries = 1; pConfList->aptCalls[0] = ptConfCall; ptConfCall->pConfList = pConfList; } } pConfList = ptConfCall->pConfList; pConfCallClientList = &fastConfCallClientList; if (GetCallClientListFromCall( ptConfCall, &pConfCallClientList ) != 0) { pConfCallClientList = NULL; } UNLOCKTCALL(ptConfCall); } else { pConfList = NULL; } DereferenceObject (ghHandleTable, (HCALL)(ULONG_PTR)Param2, 1); } else { pConfList = NULL; } SetCallConfList (ptCall, pConfList, TRUE); } else { // Just get the existing call client list UNLOCKTCALL(ptCall); if ((ptConfCall = (PTCALL) ReferenceObject( ghHandleTable, (HCALL)(ULONG_PTR)Param2, TCALL_KEY ))) { if (WaitForExclusivetCallAccess( ptConfCall, TCALL_KEY )) { pConfCallClientList = &fastConfCallClientList; if (GetCallClientListFromCall( ptConfCall, &pConfCallClientList ) != 0) { pConfCallClientList = NULL; } UNLOCKTCALL(ptConfCall); } DereferenceObject (ghHandleTable, (HCALL)(ULONG_PTR)Param2, 1); } } if (!WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { if (pConfCallClientList && pConfCallClientList != &fastConfCallClientList) { ServerFree (pConfCallClientList); } goto LINE_CALLSTATE_break; } } // // If call is a conference child and the call state has // changed then remove it from the conference // else if (ptCall->pConfList && ptCall->pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) { try { if ( ptCall->pConfList->aptCalls[0] != ptCall) { SetCallConfList (ptCall, NULL, FALSE); } } myexcept { } } // // Record the call state & mode // ptCall->dwCallState = DWORD_CAST(Param1,__FILE__,__LINE__); ptCall->dwCallStateMode = (LINECALLSTATE_CONFERENCED==Param1?0:DWORD_CAST(Param2,__FILE__,__LINE__)); // // Build a list of call clients & their bIndicatePrivilege // settings // if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0) { // // If here we know there's at least a few entries // in the fastCallClientList (DEF_NUM_PTR_LIST_ENTRIES // to be exact), so we'll just work with that list // and at least get msgs out to a few clients // pCallClientList = &fastCallClientList; fastCallClientList.dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES; } dwNumUsedEntries = pCallClientList->dwNumUsedEntries; pPrivilegeList = (dwNumUsedEntries <= DEF_NUM_PTR_LIST_ENTRIES ? fastPrivilegeList : ServerAlloc (pCallClientList->dwNumUsedEntries * sizeof (BOOL)) ); if (!pPrivilegeList) { // // Same as above - make due with the stack bufs // pPrivilegeList = fastPrivilegeList; dwNumUsedEntries = DEF_NUM_PTR_LIST_ENTRIES; } for (i = 0; i < dwNumUsedEntries; i++) { ptCallClient = (PTCALLCLIENT) pCallClientList->aEntries[i]; if ((pPrivilegeList[i] = (BOOL) ptCallClient->bIndicatePrivilege)) { ptCallClient->bIndicatePrivilege = 0; } } // // It's now ok to unlock the tCall // UNLOCKTCALL(ptCall); // // Send the CALLSTATE msg to all the clients // msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof(HCALLHUB); msg->Msg = dwMsg; msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); for (i = 0; i < dwNumUsedEntries; i++) { ptCallClient = (PTCALLCLIENT) pCallClientList->aEntries[i]; LOG((TL_INFO, "LineEventProc: i = [%d] corresponding ptCallClient [%p]", i, ptCallClient)); try { PTLINECLIENT ptLineClient; PTLINEAPP ptLineApp; LOG((TL_INFO, "LineEventProc: ptCallClient->ptLineClient[%p]", ptCallClient->ptLineClient)); ptLineClient = ptCallClient->ptLineClient; LOG((TL_INFO, "LineEventProc: ptLineClient->ptLineApp[%p]", ptLineClient->ptLineApp)); ptLineApp = ptLineClient->ptLineApp; LOG((TL_INFO, "LineEventProc: setting msg->InitContext to ptLineApp[%p]->InitContext of [%p]", ptLineApp, ptLineApp->InitContext)); msg->InitContext = ptLineApp->InitContext; msg->hDevice = ptCallClient->hCall; LOG((TL_INFO, "LineEventProc: setting msg->OpenContext to [%p]", ptLineClient->OpenContext)); msg->OpenContext = ptLineClient->OpenContext; // // REMOTESP HACK: indicate the hRemoteLine in p4 // msg->Param4 = ptLineClient->hRemoteLine; *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClient->ptCallHubClient)? ptCallClient->ptCallHubClient->hCallHub : (HCALLHUB)0; if (pPrivilegeList[i]) { // // We're presenting the app with a new call handle; // for 2.0 & newer apps we indicate this with an // APPNEWCALL msg, while older apps just get the // privilege field set in the call state msg. // if (ptLineApp->dwAPIVersion >= TAPI_VERSION2_0) { ASYNCEVENTMSG newCallMsg[2], *pNewCallMsg = newCallMsg; PTCONFERENCELIST pConfList; BOOL bConfParent = FALSE; if (!FMsgDisabled( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, LINE_APPNEWCALL, 0 )) { pNewCallMsg->TotalSize = sizeof (ASYNCEVENTMSG) + 3 * sizeof (DWORD); pNewCallMsg->InitContext = msg->InitContext; pNewCallMsg->hDevice = ptLineClient->hRemoteLine; pNewCallMsg->OpenContext = msg->OpenContext; pNewCallMsg->fnPostProcessProcHandle = 0; pNewCallMsg->Msg = LINE_APPNEWCALL; pNewCallMsg->Param1 = ptCall->dwAddressID; pNewCallMsg->Param2 = ptCallClient->hCall; pNewCallMsg->Param3 = ptCallClient->dwPrivilege; *(&pNewCallMsg->Param4 + 1) = ptCall->dwCallID; *(&pNewCallMsg->Param4 + 2) = ptCall->dwRelatedCallID; if ((pConfList = ptCall->pConfList) && (pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) && (pConfList->aptCalls[0] == ptCall)) { bConfParent = TRUE; } *(&pNewCallMsg->Param4 + 3) = (DWORD) bConfParent; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { LOG((TL_INFO, "LineEventProc: sending LINE_APPNEWCALL, ptClient[%p]", ptCallClient->ptClient)); WriteEventBuffer( ptCallClient->ptClient, pNewCallMsg ); } } msg->Param3 = 0; } else { msg->Param3 = ptCallClient->dwPrivilege; } } else { msg->Param3 = 0; } if (FMsgDisabled ( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, (DWORD) msg->Msg, (DWORD) msg->Param1 )) { continue; } // // Another special case for LINECALLSTATE_CONFERENCED - // try to find the corresponding hConfCall (on same // tLineClient) so we can set Param2 per spec // if (Param1 == LINECALLSTATE_CONFERENCED) { BOOL bDone = (pConfCallClientList ? FALSE : TRUE); Param2 = 0; while (!bDone) { try { for( j = 0; j < pConfCallClientList->dwNumUsedEntries; j++ ) { PTCALLCLIENT pConfCallClient; pConfCallClient = (PTCALLCLIENT) pConfCallClientList->aEntries[j]; if (pConfCallClient && pConfCallClient->ptLineClient == ptLineClient) { pConfCallClientList->aEntries[j] = NULL; Param2 = pConfCallClient->hCall; break; } } bDone = TRUE; } myexcept { // // If here we presumbly blew up because // an entry in the confCallClientList was // bad. So we'll zero this entry & try // again. // pConfCallClientList->aEntries[j] = NULL; } } } // // REMOTESP HACK: If the client is remote(sp), then pass // on the media mode the SP passed us in p3 // We also need the privilege - in p2 // // Should have originally put the privilege // in msg.pfnPostProcess (since it's not // used for this msg in rmeotesp), because // in tapi 2.1 we ended up losing Param2 // (the call state mode). So now we stick // the original Param2 (the call state // mode) in msg.pfnPostProcess to maintain // compatibility. // if (IS_REMOTE_CLIENT (ptLineApp->ptClient)) { msg->Param2 = ptCallClient->dwPrivilege; msg->Param3 = DWORD_CAST(Param3,__FILE__,__LINE__); msg->fnPostProcessProcHandle = DWORD_CAST(Param2,__FILE__,__LINE__); } else { msg->Param2 = DWORD_CAST(Param2,__FILE__,__LINE__); msg->fnPostProcessProcHandle = 0; } if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptCallClient->ptClient, msg); } } myexcept { // do nothing, just fall thru } } if (pCallClientList != &fastCallClientList) { ServerFree (pCallClientList); } if (pPrivilegeList != fastPrivilegeList) { ServerFree (pPrivilegeList); } if (pConfCallClientList && pConfCallClientList != &fastConfCallClientList) { ServerFree (pConfCallClientList); } } // if ((ptCall = WaitForExclusivetCallAccess( else { LOG((TL_ERROR, "LINECALLSTATE: Failed call access for call= x%p", ptCall )); LOG((TL_INFO, " Line=x%lx p1=x%lx p2=x%lx p3=x%lx", htLine, Param1, Param2, Param3 )); } LINE_CALLSTATE_break: DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); break; } case LINE_GATHERDIGITS: { PASYNCREQUESTINFO pAsyncRequestInfo; if (Param2 == 0) // dwEndToEndID { // // The SP is notifying us of the completion of a cancel // request (not a _canceled_ request), so we can just blow // this off and not bother passing it on to the client // break; } if ((pAsyncRequestInfo = ReferenceObject( ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), TASYNC_KEY ))) { LPWSTR lpsDigitsSrv = (LPWSTR) (((LPBYTE) pAsyncRequestInfo) + pAsyncRequestInfo->dwParam1); DWORD hpsDigitsCli = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); DWORD dwNumDigits = DWORD_CAST(pAsyncRequestInfo->dwParam3,__FILE__,__LINE__), dwNumDigitsTmp; HCALL hCall = (HCALL) pAsyncRequestInfo->dwParam4; DWORD dwEndToEndIDRemote = DWORD_CAST( pAsyncRequestInfo->dwParam5,__FILE__,__LINE__); PTCALLCLIENT ptCallClient; ASYNCEVENTMSG *pMsg; if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject( ghHandleTable, hCall, TCALLCLIENT_KEY ))) { goto LINE_GATHERDIGITS_dereferenceAsyncReqInfo; break; } // // 2 * sizeof ULONG_PTR is adding space to include the // dwEndToEndID and hRemoteLine, both for remotesp // if (!(pMsg = ServerAlloc( sizeof (ASYNCEVENTMSG) + (2 * sizeof(DWORD)) + (dwNumDigits + 1) * sizeof (WCHAR) + TALIGN_COUNT ))) { goto LINE_GATHERDIGITS_dereferenceCall; break; } // // Note: We either have < dwNumDigits digits in the buffer, // and they are null-terminated, or we have dwNumDigits // digits in the buffer and they are NOT null-terminated // (such is the implementation given the spec) // { DWORD *pDW = (DWORD *) (pMsg + 1); WCHAR *pBuf = (WCHAR *) (pDW + 2); pDW[0] = dwEndToEndIDRemote; try { pDW[1] = ptCallClient->ptLineClient->hRemoteLine; } myexcept { } wcsncpy (pBuf, lpsDigitsSrv, dwNumDigits); if ((dwNumDigitsTmp = lstrlenW (pBuf)) < dwNumDigits) { dwNumDigits = dwNumDigitsTmp + 1; } } // // Make sure total size is DWORD-aligned so client side doesn't // incur an alignment fault // // sizeof(ULONG_PTR) is added to put the dwEndToEndID in the buf // pMsg->TotalSize = (sizeof (ASYNCEVENTMSG) + 2 * sizeof(DWORD) + dwNumDigits * sizeof (WCHAR) + TALIGN_COUNT) & TALIGN_MASK; pMsg->InitContext = pAsyncRequestInfo->InitContext; pMsg->fnPostProcessProcHandle = pAsyncRequestInfo->hfnClientPostProcessProc; pMsg->hDevice = hCall; pMsg->Msg = LINE_GATHERDIGITS; pMsg->OpenContext = pAsyncRequestInfo->OpenContext; pMsg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); pMsg->Param2 = hpsDigitsCli; pMsg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount()); pMsg->Param4 = dwNumDigits; WriteEventBuffer (pAsyncRequestInfo->ptClient, pMsg); ServerFree (pMsg); LINE_GATHERDIGITS_dereferenceCall: DereferenceObject (ghHandleTable, hCall, 1); LINE_GATHERDIGITS_dereferenceAsyncReqInfo: DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 2); // by 2 to free } else { LOG((TL_ERROR, "Bad Param2=x%lx in LINE_GATHERDIGITS msg!", Param2 )); } break; } case LINE_MONITORTONE: { // // Note: Param2 (the dwToneListID) is really a ptCallClient // // Hack Alert!! : In the case of remotesp we'll get a special // bogus Param2, in which case we really don't // know who the appropriate call client is. So // we'll call SendMsgtoCallClients() and let it // figure out which apps have done tone monitoring // on this call, and we'll forward to all of them. // It's cheesey, but the alternative is keeping a // bunch of context around in the client/server // case, and i really don't want to deal with that. // (Plus, i doubt there will be many, if any, cases // of >1 app doing remote monitor on the same call.) // // DanKn, 06/06/98 // PTCALLCLIENT ptCallClient; if (Param2 == 0) // special remotesp hack { PTCALL ptCall; if(ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)) { SendMsgToCallClients( ptCall, NULL, dwMsg, DWORD_CAST(Param1,__FILE__,__LINE__), 0, DWORD_CAST(Param3,__FILE__,__LINE__) ); DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); } break; } if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject( ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), // dwToneListID == hCall TCALLCLIENT_KEY ))) { break; } try { ASYNCEVENTMSG msg[2]; PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; ptLineClient = ptCallClient->ptLineClient; msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB); msg->InitContext = ptLineClient->ptLineApp->InitContext; msg->fnPostProcessProcHandle = 0; msg->hDevice = ptCallClient->hCall; msg->Msg = dwMsg; msg->OpenContext = ptLineClient->OpenContext; msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); msg->Param2 = 0; msg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount()); msg->Param4 = ptLineClient->hRemoteLine; // for RemoteSP *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClient->ptCallHubClient)? ptCallClient->ptCallHubClient->hCallHub : (HCALLHUB)0; // // Now a final check to make sure all the // params are valid before sending the msg // { PTCLIENT ptClient = ptCallClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, msg); } } } myexcept { // do nothing } DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 1); break; } case LINE_GENERATE: { // // Note: Param2 id really a pointer to instance data containing // ([0]) the hCall & ([1]) the dwEndToEndID or dwToneListID, // the latter of which is only useful to remotesp // HCALL hCall; DWORD dwEndToEndID; LPDWORD pInstData; PTCALLCLIENT ptCallClient; if (!(pInstData = (LPDWORD) ReferenceObject( ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), TASYNC_KEY ))) { break; } hCall = pInstData[1]; dwEndToEndID = pInstData[2]; DereferenceObject (ghHandleTable, DWORD_CAST(Param2,__FILE__,__LINE__), 2); // by 2 to free it if (!(ptCallClient = (PTCALLCLIENT) ReferenceObject( ghHandleTable, hCall, TCALLCLIENT_KEY ))) { break; } try { ASYNCEVENTMSG msg[2]; PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB); msg->InitContext = ptLineClient->ptLineApp->InitContext; msg->fnPostProcessProcHandle = 0; msg->hDevice = hCall; msg->Msg = dwMsg; msg->OpenContext = ptLineClient->OpenContext; msg->Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); LOG((TL_INFO, "LineEventProc: LINE_GENERATE OpenContext %p InitContext %p", msg->OpenContext, msg->InitContext )); // // Indicate the endToEndID/toneListID for remotesp, and the // hRemoteLine in p4 to make life easier for remotesp // msg->Param2 = dwEndToEndID; msg->Param3 = (Param3 ? DWORD_CAST(Param3,__FILE__,__LINE__) : GetTickCount()); msg->Param4 = ptLineClient->hRemoteLine; *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClient->ptCallHubClient)? ptCallClient->ptCallHubClient->hCallHub : (HCALLHUB)0; // // Now a final check to make sure all the // params are valid before sending the msg // { PTCLIENT ptClient = ptCallClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, msg); } } } myexcept { // do nothing } DereferenceObject (ghHandleTable, hCall, 1); break; } case LINE_NEWCALL: { // // Create a tCall & set the bAlertApps field so we create the // appropriate tCallClients on the first call state msg // PTCALL ptCall; PTLINE ptLine; HCALL hCall; ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY); if (NULL != ptLine) { if (CreatetCall( ptLine, TRUE, (HDRVCALL) Param1, &ptCall, NULL, &hCall, NULL ) != 0) { hCall = 0; } DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); } else { hCall = 0; } *((LPHTAPICALL) Param2) = (HTAPICALL)(ULONG_PTR)hCall; break; } case LINE_CREATE: { LONG lResult; DWORD dwDeviceID; TSPIPROC pfnTSPI_providerCreateLineDevice; PTPROVIDER ptProvider = (PTPROVIDER) Param1; PTLINELOOKUPTABLE pTable, pPrevTable; PTLINELOOKUPENTRY pEntry; PTPROVIDER ptProvider2; TapiEnterCriticalSection (&TapiGlobals.CritSec); // // Check to see if ptProvider(Param1) is still valid, LINE_CREATE // might got processed after the TSP has been removed // if (NULL == ptProvider) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); return; } ptProvider2 = TapiGlobals.ptProviders; while (ptProvider2 && ptProvider2 != ptProvider) { ptProvider2 = ptProvider2->pNext; } if (ptProvider2 != ptProvider) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); return; } pfnTSPI_providerCreateLineDevice = ptProvider->apfn[SP_PROVIDERCREATELINEDEVICE]; assert (pfnTSPI_providerCreateLineDevice != NULL); // // Search for a table entry (create a new table if we can't find // a free entry in an existing table) // if (!gbQueueSPEvents) { // // We're shutting down, so bail out // TapiLeaveCriticalSection (&TapiGlobals.CritSec); return; } pTable = TapiGlobals.pLineLookup; while (pTable && !(pTable->dwNumUsedEntries < pTable->dwNumTotalEntries)) { pPrevTable = pTable; pTable = pTable->pNext; } if (!pTable) { if (!(pTable = ServerAlloc( sizeof (TLINELOOKUPTABLE) + (2 * pPrevTable->dwNumTotalEntries - 1) * sizeof (TLINELOOKUPENTRY) ))) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); break; } pPrevTable->pNext = pTable; pTable->dwNumTotalEntries = 2 * pPrevTable->dwNumTotalEntries; } // // Initialize the table entry // pEntry = pTable->aEntries + pTable->dwNumUsedEntries; dwDeviceID = TapiGlobals.dwNumLines; if ((pEntry->hMutex = MyCreateMutex())) { pEntry->ptProvider = (PTPROVIDER) Param1; // // Now call the creation & negotiation entrypoints, and if all // goes well increment the counts & send msgs to the clients // if ((lResult = CallSP2( pfnTSPI_providerCreateLineDevice, "providerCreateLineDevice", SP_FUNC_SYNC, (ULONG_PTR) Param2, (DWORD) dwDeviceID )) == 0) { TSPIPROC pfnTSPI_lineNegotiateTSPIVersion = ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION]; TPOINTERLIST clientList, *pClientList = &clientList; if ((lResult = CallSP4( pfnTSPI_lineNegotiateTSPIVersion, "", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) TAPI_VERSION1_0, (DWORD) TAPI_VERSION_CURRENT, (ULONG_PTR) &pEntry->dwSPIVersion )) == 0) { PTCLIENT ptClient; ASYNCEVENTMSG msg; GetPermLineIDAndInsertInTable( ptProvider, dwDeviceID, pEntry->dwSPIVersion ); pTable->dwNumUsedEntries++; TapiGlobals.dwNumLines++; TapiLeaveCriticalSection (&TapiGlobals.CritSec); AppendNewDeviceInfo (TRUE, dwDeviceID); TapiEnterCriticalSection (&TapiGlobals.CritSec); // PERF ** Number of lines PerfBlock.dwLines = TapiGlobals.dwNumLines; msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.hDevice = 0; msg.OpenContext = 0; msg.Param2 = 0; msg.Param3 = 0; // // Only send the message if the client is an // admin or we're not a telephony server // we don't want to send the message to non-admin // clients, because their lines have not changed. // if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) { lResult = GetClientList (TRUE, &pClientList); } else { lResult = GetClientList (FALSE, &pClientList); } if (lResult == S_OK) { DWORD i; PTLINEAPP ptLineApp; for (i = 0; i < pClientList->dwNumUsedEntries; ++i) { ptClient = (PTCLIENT) pClientList->aEntries[i]; if (!WaitForExclusiveClientAccess (ptClient)) { continue; } ptLineApp = ptClient->ptLineApps; while (ptLineApp) { if (ptLineApp->dwAPIVersion == TAPI_VERSION1_0) { msg.Msg = LINE_LINEDEVSTATE; msg.Param1 = LINEDEVSTATE_REINIT; } else { msg.Msg = LINE_CREATE; msg.Param1 = dwDeviceID; } msg.InitContext = ptLineApp->InitContext; if (!FMsgDisabled ( ptLineApp->dwAPIVersion, ptLineApp->adwEventSubMasks, (DWORD) msg.Msg, (DWORD) msg.Param1 )) { WriteEventBuffer (ptClient, &msg); } ptLineApp = ptLineApp->pNext; } UNLOCKTCLIENT (ptClient); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } if (lResult) { MyCloseMutex (pEntry->hMutex); } } TapiLeaveCriticalSection (&TapiGlobals.CritSec); break; } case LINE_CREATEDIALOGINSTANCE: { DWORD dwDataSize, dwAlignedDataSize, dwAlignedUIDllNameSize, dwTotalSize; PTCLIENT ptClient; PASYNCEVENTMSG pMsg; PASYNCREQUESTINFO pAsyncReqInfo; PTAPIDIALOGINSTANCE ptDlgInst; LPTUISPICREATEDIALOGINSTANCEPARAMS pParams; pParams = (LPTUISPICREATEDIALOGINSTANCEPARAMS) Param1; // // Verify the async request info struct // if (!(pAsyncReqInfo = (PASYNCREQUESTINFO) ReferenceObject( ghHandleTable, pParams->dwRequestID, TASYNC_KEY ))) { pParams->htDlgInst = 0; return; } ptClient = pAsyncReqInfo->ptClient; DereferenceObject (ghHandleTable, pParams->dwRequestID, 1); // // Alloc bufs for the msg & dlg instance, careful to keep offsets // & total msg size on 64-bit boundaries // dwDataSize = pParams->dwSize; dwAlignedDataSize = (dwDataSize + 7) & 0xfffffff8; dwAlignedUIDllNameSize = 0xfffffff8 & (7 + ((lstrlenW ((PWSTR) pParams->lpszUIDLLName) + 1)*sizeof (WCHAR))); dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize + dwAlignedUIDllNameSize; if (!(pMsg = ServerAlloc (dwTotalSize))) { pParams->htDlgInst = 0; return; } if (!(ptDlgInst = ServerAlloc (sizeof (TAPIDIALOGINSTANCE)))) { ServerFree (pMsg); pParams->htDlgInst = 0; return; } ptDlgInst->htDlgInst = NewObject(ghHandleTable, ptDlgInst, NULL); if (0 == ptDlgInst->htDlgInst) { ServerFree (pMsg); ServerFree (ptDlgInst); pParams->htDlgInst = 0; return; } // // Add the dlg inst to the tClient's list // LOCKTCLIENT (ptClient); if ((ptDlgInst->pNext = ptClient->pGenericDlgInsts)) { ptDlgInst->pNext->pPrev = ptDlgInst; } ptClient->pGenericDlgInsts = ptDlgInst; UNLOCKTCLIENT (ptClient); // // Init dlg inst struct & send msg to client // ptDlgInst->dwKey = TDLGINST_KEY; ptDlgInst->hdDlgInst = pParams->hdDlgInst; ptDlgInst->ptClient = ptClient; ptDlgInst->ptProvider = (PTPROVIDER) htLine; pMsg->TotalSize = dwTotalSize; pMsg->hDevice = ptDlgInst->htDlgInst; try { if (ptClient->ptLineApps) { pMsg->InitContext = ptClient->ptLineApps->InitContext; } } myexcept { pMsg->InitContext = 0; } pMsg->Msg = LINE_CREATEDIALOGINSTANCE; pMsg->Param1 = sizeof (ASYNCEVENTMSG); // data offset pMsg->Param2 = dwDataSize; // data size pMsg->Param3 = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize; // name offset CopyMemory ((LPBYTE)(pMsg + 1), pParams->lpParams, dwDataSize); wcscpy( (PWSTR) ((LPBYTE)(pMsg + 1) + dwAlignedDataSize), (PWSTR) pParams->lpszUIDLLName ); pParams->htDlgInst = ptDlgInst->htDlgInst; WriteEventBuffer (ptClient, pMsg); ServerFree (pMsg); break; } case LINE_SENDDIALOGINSTANCEDATA: { DWORD dwDataSize, dwAlignedDataSize, dwTotalSize; PTCLIENT ptClient; PASYNCEVENTMSG pMsg; PTAPIDIALOGINSTANCE ptDlgInst = ReferenceObject (ghHandleTable, DWORD_CAST((ULONG_PTR)htLine,__FILE__,__LINE__), TDLGINST_KEY); // // Verify the dlg inst // try { ptClient = ptDlgInst->ptClient; if (ptDlgInst->dwKey != TDLGINST_KEY) { return; } } myexcept { return; } DereferenceObject (ghHandleTable, DWORD_CAST((ULONG_PTR)htLine,__FILE__,__LINE__), 1); // // Careful to keep offsets & total msg size on 64-bit boundaries // dwDataSize = (DWORD) Param2; dwAlignedDataSize = (dwDataSize + 7) & 0xfffffff8; dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize; if (!(pMsg = ServerAlloc (dwTotalSize))) { return; } // // Send the msg to the client // pMsg->TotalSize = dwTotalSize; pMsg->hDevice = ptDlgInst->htDlgInst; try { if (ptClient->ptLineApps) { pMsg->InitContext = ptClient->ptLineApps->InitContext; } } myexcept { pMsg->InitContext = 0; } pMsg->Msg = LINE_SENDDIALOGINSTANCEDATA; pMsg->Param1 = sizeof (ASYNCEVENTMSG); // data offset pMsg->Param2 = dwDataSize; // data size CopyMemory ((LPBYTE)(pMsg + 1), (LPBYTE) Param1, dwDataSize); WriteEventBuffer (ptClient, pMsg); ServerFree (pMsg); break; } case LINE_REMOVE: { PTLINELOOKUPENTRY pLookupEntry; HANDLE hLookupEntryMutex = NULL; BOOL bOK = FALSE; TapiEnterCriticalSection (&TapiGlobals.CritSec); if (!(pLookupEntry = GetLineLookupEntry ((DWORD) Param1)) || pLookupEntry->bRemoved) { TapiLeaveCriticalSection(&TapiGlobals.CritSec); return; } if ( pLookupEntry->hMutex ) { bOK = DuplicateHandle( TapiGlobals.hProcess, pLookupEntry->hMutex, TapiGlobals.hProcess, &hLookupEntryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS ); } TapiLeaveCriticalSection(&TapiGlobals.CritSec); if ( !bOK ) { return; } // // Wait for the LookupEntry's mutex on the duplicate handle // if (WaitForSingleObject (hLookupEntryMutex, INFINITE) != WAIT_OBJECT_0) { return; } // // Mark the lookup table entry as removed // pLookupEntry->bRemoved = 1; // // Release the mutex and close the duplicate handle // ReleaseMutex (hLookupEntryMutex); CloseHandle (hLookupEntryMutex); hLookupEntryMutex = NULL; if (pLookupEntry->ptLine) { DestroytLine (pLookupEntry->ptLine, TRUE); // unconditional destroy } TapiEnterCriticalSection (&TapiGlobals.CritSec); // // Close the mutex to reduce overall handle count // MyCloseMutex (pLookupEntry->hMutex); pLookupEntry->hMutex = NULL; RemoveDeviceInfoEntry (TRUE, (DWORD)Param1); TapiLeaveCriticalSection(&TapiGlobals.CritSec); SendAMsgToAllLineApps( TAPI_VERSION2_0 | 0x80000000, LINE_REMOVE, DWORD_CAST(Param1,__FILE__,__LINE__), 0, 0 ); break; } case LINE_APPNEWCALLHUB: case LINE_CALLHUBCLOSE: { // // This msg gets queued/sent by our own internal // DoCallHubHashing func. See comments there for // more info. // ASYNCEVENTMSG msg; PTCLIENT ptClient = NULL; msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.InitContext = DWORD_CAST(Param2,__FILE__,__LINE__); msg.fnPostProcessProcHandle = 0; msg.hDevice = 0; msg.Msg = dwMsg; msg.OpenContext = 0; msg.Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); msg.Param2 = msg.Param3 = 0; // // try to recover the pointer to tClient from the 32-bit handle value // ptClient = (PTCLIENT) Param3; if (NULL != ptClient) { WriteEventBuffer (ptClient, &msg); } else { LOG((TL_ERROR, "LineEventProc: LINE_APPNEWCALLHUB/LINE_CALLHUBCLOSE failed to recover ptClient")); } break; } case LINE_SENDMSPDATA: { PASYNCEVENTMSG pmsg; PTLINECLIENT ptLineClient = NULL; PTCALLCLIENT ptCallClient = NULL; DWORD dwSize = (sizeof (ASYNCEVENTMSG) + DWORD_CAST(Param3,__FILE__,__LINE__) + TALIGN_COUNT) & TALIGN_MASK; DWORD initContext; PTCLIENT ptClient = NULL; DWORD dwCount; BOOL bFound = FALSE; TPOINTERLIST clientList, *pClientList = &clientList; PTCALL ptCall; DWORD hLine = 0, hCall = 0; if ( (0 == Param1) && (0 == htCall) ) { return; } if ( 0 != Param1 ) { if (!(ptLineClient = (PTLINECLIENT) ReferenceObject( ghHandleTable, DWORD_CAST(Param1,__FILE__,__LINE__), TLINECLIENT_KEY ))) { return; } ptClient = ptLineClient->ptClient; initContext = ptLineClient->ptLineApp->InitContext; } // // If ptCall isn't NULL, try to find the call client // corresponding to this line client // if (0 != htCall) { if (ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY)) { if ( NULL == ptLineClient ) { SendBufferMsgToCallClients( ptCall, NULL, LINE_SENDMSPDATA, 0, DWORD_CAST(Param3,__FILE__,__LINE__), (LPBYTE)Param2 ); DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); return; } if (GetCallClientListFromCall (ptCall, &pClientList) == 0) { for( dwCount = 0; dwCount < pClientList->dwNumUsedEntries; dwCount++ ) { ptCallClient = pClientList->aEntries[dwCount]; try { if ( ptCallClient->ptLineClient == ptLineClient ) { bFound = TRUE; break; } } myexcept { // do nothing } } if ( pClientList != &clientList ) { ServerFree( pClientList ); } } DereferenceObject( ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); } if ( !bFound ) { // // Didn't find it for some reason // DereferenceObject( ghHandleTable, DWORD_CAST(Param1,__FILE__,__LINE__), 1 ); return; } } if ( NULL != ptLineClient ) { hLine = ptLineClient->hLine; DereferenceObject( ghHandleTable, DWORD_CAST(Param1,__FILE__,__LINE__), 1 ); } if ( NULL != ptCallClient ) { hCall = ptCallClient->hCall; } pmsg = ( PASYNCEVENTMSG )ServerAlloc( dwSize ); if (NULL == pmsg) { LOG((TL_ERROR, "Alloc failed in LINE_SENDMSPDATA")); return; } CopyMemory ((LPBYTE) (pmsg+1), (LPBYTE) Param2, Param3); pmsg->TotalSize = dwSize; pmsg->InitContext = initContext; pmsg->fnPostProcessProcHandle = 0; pmsg->hDevice = hLine; pmsg->Msg = LINE_SENDMSPDATA; pmsg->OpenContext = 0; pmsg->Param1 = hCall; pmsg->Param2 = DWORD_CAST(Param3,__FILE__,__LINE__); pmsg->Param3 = 0; WriteEventBuffer ( ptClient, pmsg ); ServerFree( pmsg ); break; } case LINE_QOSINFO: { ASYNCEVENTMSG msg; PTCALL ptCall; TPOINTERLIST clientList, *pclientList = &clientList; int i; ptCall = ReferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, TCALL_KEY); if (0 == ptCall) { break; } clientList.dwNumUsedEntries = 0; if (GetCallClientListFromCall (ptCall, &pclientList) == 0) { PTCALLCLIENT ptCallClient; msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.Msg = dwMsg; msg.OpenContext = 0; msg.Param1 = DWORD_CAST(Param1,__FILE__,__LINE__); msg.Param2 = DWORD_CAST(Param2,__FILE__,__LINE__); msg.Param3 = 0; for (i = 0; i < (int)pclientList->dwNumUsedEntries; ++ i) { ptCallClient = (PTCALLCLIENT) pclientList->aEntries[i]; if (WaitForExclusivetCallAccess (ptCallClient->ptCall, TCALL_KEY)) { BOOL b = FMsgDisabled( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, LINE_QOSINFO, 0 ); UNLOCKTCALL (ptCallClient->ptCall); if (b) { continue; } } msg.InitContext = ptCallClient->ptLineClient->ptLineApp->InitContext; msg.hDevice = ptCallClient->hCall; WriteEventBuffer (ptCallClient->ptClient, &msg); } if (pclientList && (pclientList != &clientList)) { ServerFree (pclientList); } } DereferenceObject(ghHandleTable, (HCALL)(ULONG_PTR)htCall, 1); break; } case LINE_DEVSPECIFICEX: { PTLINE ptLine; ptLine = ReferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, TLINE_KEY); if(ptLine) { SendBufferMsgToLineClients( ptLine, NULL, LINE_DEVSPECIFICEX, DWORD_CAST(Param1,__FILE__,__LINE__), DWORD_CAST(Param2,__FILE__,__LINE__), (LPBYTE) Param3 ); DereferenceObject(ghHandleTable, (HLINE)(ULONG_PTR)htLine, 1); } break; } default: // if DBG assert (unrecognized dwMsg) break; } } void CALLBACK LineEventProcSP( HTAPILINE htLine, HTAPICALL htCall, DWORD dwMsg, ULONG_PTR Param1, ULONG_PTR Param2, ULONG_PTR Param3 ) { PSPEVENT pSPEvent; #if DBG if (gdwDebugLevel >= 3) { char *pszMsg; static char szInvalMsgVal[] = ""; 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[] = ""; static char *aszCallStates[] = { "IDLE", "OFFERING", "ACCEPTED", "DIALTONE", "DIALING", "RINGBACK", "BUSY", "SPECIALINFO", "CONNECTED", "PROCEEDING", "ONHOLD", "CONFERENCED", "ONHOLDPENDCONF", "ONHOLDPENDTRANSFER", "DISCONNECTED", "UNKNOWN" }; if (!IsOnlyOneBitSetInDWORD(Param1) || Param1 > LINECALLSTATE_UNKNOWN) { pszCallState = szInvalCallStateVal; } else { DWORD i, dwBitMask; for( i = 0, dwBitMask = 1; Param1 != dwBitMask; i++, dwBitMask <<= 1 ); pszCallState = aszCallStates[i]; } LOG((TL_INFO, " P1=%s (x%x), P2=x%x, P3=x%x", pszCallState, Param1, Param2, Param3 )); } else { LOG((TL_INFO, " P1=x%x, P2=x%x, P3=x%x", Param1, Param2, Param3 )); } } #endif LOG((TL_INFO, "LineEventProcSP: HTapiLine=%p, HTapiCall=%p, msg=%lx, P1=x%x, P2=x%x, P3=x%x", htLine, htCall, dwMsg, Param1, Param2, Param3 )); switch (dwMsg) { case LINE_NEWCALL: case LINE_CREATEDIALOGINSTANCE: case LINE_SENDDIALOGINSTANCEDATA: case LINE_DEVSPECIFICEX: // // These msgs need immediate attention, since they contain // pointers that we need to play with which may not be // available during async processing later // LineEventProc (htLine, htCall, dwMsg, Param1, Param2, Param3); break; case LINE_SENDMSPDATA: if ((pSPEvent = (PSPEVENT) ServerAlloc ( sizeof (SPEVENT) + (DWORD)Param3))) { CopyMemory( (LPBYTE)(pSPEvent+1), (LPBYTE)Param2, Param3 ); pSPEvent->dwType = SP_LINE_EVENT; pSPEvent->htLine = htLine; pSPEvent->htCall = htCall; pSPEvent->dwMsg = dwMsg; pSPEvent->dwParam1 = Param1; pSPEvent->dwParam2 = (ULONG_PTR)(LPBYTE)(pSPEvent+1); pSPEvent->dwParam3 = Param3; if (!QueueSPEvent (pSPEvent)) { ServerFree (pSPEvent); } break; } default: if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT)))) { pSPEvent->dwType = SP_LINE_EVENT; pSPEvent->htLine = htLine; pSPEvent->htCall = htCall; pSPEvent->dwMsg = dwMsg; pSPEvent->dwParam1 = Param1; pSPEvent->dwParam2 = Param2; pSPEvent->dwParam3 = Param3; if (!QueueSPEvent (pSPEvent)) { ServerFree (pSPEvent); } } else if (dwMsg != LINE_CLOSE || Param3 != 0xdeadbeef) { // // Alloc failed, so call the event proc within the SP's context // (but not if it's CLOSE msg and Param3 == 0xdeadbeef, // which means the real EventProc() is calling us directly & // we don't want to recurse) // LOG((TL_ERROR, "LineEventProcSP: alloc failed, calling EventProc inline" )); LineEventProc (htLine, htCall, dwMsg, Param1, Param2, Param3); } break; } } void WINAPI LAccept( PTCLIENT ptClient, PLINEACCEPT_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineAccept; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwUserUserInfoOffset, sizeof(DWORD), "LAccept", "pParams->UserUserInfo" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEACCEPT, // provider func index &pfnTSPI_lineAccept, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Accept" // func name )) > 0) { DWORD dwAppNameSize; LPVOID pszAppName = NULL; PTCALL ptCall; // // Safely check to see if the app name associated with this call is // NULL (meaning this is the first client to accept/answer the call), // and if so save the app name // try { ptCall = (PTCALL) ptCallClient->ptCall; if (ptCall->pszAppName == NULL) { PTLINEAPP ptLineApp; ptLineApp = ptCallClient->ptLineClient->ptLineApp; dwAppNameSize = ptLineApp->dwFriendlyNameSize; if (ptLineApp->dwKey != TLINEAPP_KEY) { lRequestID = LINEERR_INVALCALLHANDLE; goto LAccept_epilog; } if ((pszAppName = ServerAlloc (dwAppNameSize))) { CopyMemory( pszAppName, ptLineApp->pszFriendlyName, dwAppNameSize ); } } } myexcept { ServerFree (pszAppName); lRequestID = LINEERR_INVALCALLHANDLE; goto LAccept_epilog; } if (pszAppName) { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { if (!ptCall->pszAppName) { ptCall->pszAppName = pszAppName; ptCall->dwAppNameSize = dwAppNameSize; pszAppName = NULL; } UNLOCKTCALL (ptCall); ServerFree (pszAppName); } else { ServerFree (pszAppName); lRequestID = LINEERR_INVALCALLHANDLE; goto LAccept_epilog; } } pParams->lResult = CallSP4( pfnTSPI_lineAccept, "lineAccept", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwUserUserInfoOffset), (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 : pParams->dwSize) ); } LAccept_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Accept" ); } void LAddToConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PTCALL ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam1; if (pAsyncEventMsg->Param2 == 0) { PTCONFERENCELIST pConfList = (PTCONFERENCELIST) pAsyncRequestInfo->dwParam2; SetCallConfList (ptConsultCall, pConfList, TRUE); } else { SetCallConfList (ptConsultCall, NULL, TRUE); } } void WINAPI LAddToConference( PTCLIENT ptClient, PLINEADDTOCONFERENCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdConfCall; DWORD objectToDereference; PTCALLCLIENT ptConsultCallClient, ptConfCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineAddToConference; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hConfCall, // client widget handle (LPVOID) &hdConfCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEADDTOCONFERENCE, // provider func index &pfnTSPI_lineAddToConference, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptConfCallClient, // context "AddToConference" // func name )) > 0) { PTCALL ptConfCall, ptConsultCall; HDRVCALL hdConsultCall; PTCONFERENCELIST pConfList; // // Safely make sure that the conf call is really a conf parent // try { ptConfCall = ptConfCallClient->ptCall; if (!(pConfList = ptConfCall->pConfList) || (pConfList->aptCalls[0] != ptConfCall)) { lRequestID = LINEERR_INVALCONFCALLHANDLE; goto LAddToConference_return; } } myexcept { lRequestID = LINEERR_INVALCONFCALLHANDLE; goto LAddToConference_return; } // // Verify hConsultCall // if (!(ptConsultCallClient = ReferenceCall( pParams->hConsultCall, ptClient ))) { lRequestID = LINEERR_INVALCALLHANDLE; goto LAddToConference_return; } // // Safely make sure calls are on same tLineClient, that client has // owner privilege for consult call, and that the consult call // is neither a conf parent or child (call SetCallConfList // with an inval list to temporarily mark the call as conf'd) // try { ptConsultCall = ptConsultCallClient->ptCall; if (ptConsultCallClient->ptLineClient != ptConfCallClient->ptLineClient) { lRequestID = LINEERR_INVALCALLHANDLE; goto LAddToConference_dereference; } if (!(ptConsultCallClient->dwPrivilege & LINECALLPRIVILEGE_OWNER)) { lRequestID = LINEERR_NOTOWNER; goto LAddToConference_dereference; } if (SetCallConfList( ptConsultCall, (PTCONFERENCELIST) LongToPtr(0xffffffff), FALSE )) { lRequestID = (pConfList->aptCalls[0] == ptConsultCall ? LINEERR_INVALCALLHANDLE : LINEERR_INVALCALLSTATE); goto LAddToConference_dereference; } hdConsultCall = ptConsultCall->hdCall; } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LAddToConference_dereference; } // // Set up the async request struct & call the SP // pAsyncRequestInfo->pfnPostProcess = LAddToConference_PostProcess; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->dwParam2 = (ULONG_PTR) pConfList; pParams->lResult = CallSP3( pfnTSPI_lineAddToConference, "lineAddToConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdConfCall, (ULONG_PTR) hdConsultCall ); LAddToConference_dereference: DereferenceObject (ghHandleTable, pParams->hConsultCall, 1); } LAddToConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "AddToConference" ); } void WINAPI LAgentSpecific( PTCLIENT ptClient, PLINEAGENTSPECIFIC_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwParamsSize, pParams->dwParamsOffset, sizeof(DWORD), "LAgentSpecific", "pParams->Params" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "AgentSpecific" // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwParamsSize = pParams->dwParamsSize; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, pParams->dwAddressID, LINEPROXYREQUEST_AGENTSPECIFIC, &pProxy, &dwDeviceID, 0 // API ver wasn't checked in 2.0 ))) { lRequestID = lResult; goto LAgentSpecific_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpParams; pAsyncRequestInfo->dwParam2 = dwParamsSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_AGENTSPECIFIC, 3 * sizeof (DWORD) + dwParamsSize, pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LAgentSpecific_epilog; } pProxyRequestWrapper->ProxyRequest.AgentSpecific.dwAddressID = pParams->dwAddressID; pProxyRequestWrapper->ProxyRequest.AgentSpecific. dwAgentExtensionIDIndex = pParams->dwAgentExtensionIDIndex; pProxyRequestWrapper->ProxyRequest.AgentSpecific.dwSize = dwParamsSize; CopyMemory( pProxyRequestWrapper->ProxyRequest.AgentSpecific.Params, pDataBuf + pParams->dwParamsOffset, dwParamsSize ); if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LAgentSpecific_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwParamsSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LAgentSpecific_epilog; } pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, dwParamsSize ); pParams->lResult = CallSP6( pRemoteSP->apfn[SP_LINEAGENTSPECIFIC], "lineAgentSpecific", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (DWORD) pParams->dwAgentExtensionIDIndex, (ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG)), (DWORD) dwParamsSize ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LAgentSpecific_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "AgentSpecific" ); } void WINAPI LAnswer( PTCLIENT ptClient, PLINEANSWER_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineAnswer; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwUserUserInfoSize, pParams->dwUserUserInfoOffset, sizeof(DWORD), "LAnswerReal", "pParams->UserUserInfo" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEANSWER, // provider func index &pfnTSPI_lineAnswer, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Answer" // func name )) > 0) { DWORD dwAppNameSize; LPVOID pszAppName = NULL; PTCALL ptCall; // // Safely check to see if the app name associated with this call is // NULL (meaning this is the first client to accept/answer the call), // and if so save the app name // try { ptCall = (PTCALL) ptCallClient->ptCall; if (ptCall->pszAppName == NULL) { PTLINEAPP ptLineApp; ptLineApp = ptCallClient->ptLineClient->ptLineApp; dwAppNameSize = ptLineApp->dwFriendlyNameSize; if (ptLineApp->dwKey != TLINEAPP_KEY) { lRequestID = LINEERR_INVALCALLHANDLE; goto LAnswer_epilog; } if ((pszAppName = ServerAlloc (dwAppNameSize))) { CopyMemory( pszAppName, ptLineApp->pszFriendlyName, dwAppNameSize ); } } } myexcept { ServerFree (pszAppName); lRequestID = LINEERR_INVALCALLHANDLE; goto LAnswer_epilog; } if (pszAppName) { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { if (!ptCall->pszAppName) { ptCall->pszAppName = pszAppName; ptCall->dwAppNameSize = dwAppNameSize; pszAppName = NULL; } UNLOCKTCALL (ptCall); ServerFree (pszAppName); } else { ServerFree (pszAppName); lRequestID = LINEERR_INVALCALLHANDLE; goto LAnswer_epilog; } } pParams->lResult = CallSP4( pfnTSPI_lineAnswer, "lineAnswer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwUserUserInfoOffset), (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 : pParams->dwUserUserInfoSize) ); } LAnswer_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Answer" ); } void WINAPI LBlindTransfer( PTCLIENT ptClient, PLINEBLINDTRANSFER_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineBlindTransfer; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEBLINDTRANSFER, // provider func index &pfnTSPI_lineBlindTransfer, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "BlindTransfer" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineBlindTransfer, "lineBlindTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset), (DWORD) pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "BlindTransfer" ); } void WINAPI LClose( PTCLIENT ptClient, PLINECLOSE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) NULL, // mutex handle NULL, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "Close" // func name )) == 0) { if (NULL != ptLineClient) { pParams->dwCallbackInstance = ptLineClient->OpenContext; } DestroytLineClient ((HLINE) pParams->hLine); } LINEEPILOGSYNC( &pParams->lResult, NULL, FALSE, objectToDereference, "Close" ); LOG((TL_TRACE, "Leaving lineClose")); } void WINAPI LCloseMSPInstance( PTCLIENT ptClient, PLINECLOSEMSPINSTANCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineCloseMSPInstance; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINECLOSEMSPINSTANCE, // provider func index &pfnTSPI_lineCloseMSPInstance, // provider func pointer NULL, // async request info 0, // client async request ID, &objectToDereference, &ptLineClient, "CloseMSPInstance" // func name )) == 0) { pParams->lResult = CallSP1( pfnTSPI_lineCloseMSPInstance, "lineCloseMSPInstance", SP_FUNC_SYNC, (ULONG_PTR) (ptLineClient->hdMSPLine) ); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "CloseMSPInstance" ); } void LCompleteCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { pAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); pAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); } void WINAPI LCompleteCall( PTCLIENT ptClient, PLINECOMPLETECALL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineCompleteCall; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINECOMPLETECALL, // provider func index &pfnTSPI_lineCompleteCall, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "CompleteCall" // func name )) > 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwCompletionMode) || (pParams->dwCompletionMode & ~AllCallComplModes) ) { lRequestID = LINEERR_INVALCALLCOMPLMODE; goto LCompleteCall_epilog; } pAsyncRequestInfo->pfnPostProcess = LCompleteCall_PostProcess; pAsyncRequestInfo->dwParam2 = pParams->hpdwCompletionID; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineCompleteCall, "lineCompleteCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) &pAsyncRequestInfo->dwParam1, (DWORD) pParams->dwCompletionMode, (DWORD) pParams->dwMessageID ); } LCompleteCall_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "CompleteCall" ); } void LCompleteTransfer_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1; DWORD hpConfCallHandle = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); PTCALLCLIENT ptConfCallClient; if (WaitForExclusivetCallAccess (ptConfCall, TINCOMPLETECALL_KEY)) { PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam3, ptCallThen, ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam4; HCALL hCallThen = (HCALL)pAsyncRequestInfo->dwParam5; // // Check to make sure this is the call we think it is (that the // pointer wasn't freed by a previous call to lineClose/Shutdown // and realloc'd for use as a ptCall again) // if (ptConfCall->hCall != hCallThen) { UNLOCKTCALL(ptConfCall); goto LCompleteTransfer_PostProcess_bad_ptConfCall; } ptConfCallClient = ptConfCall->ptCallClients; if (pAsyncEventMsg->Param2 == 0) // success { // // Check to see if the app closed the line & left us with // 0 call clients (in which case it'll also be taking care of // cleaning up this tCall too) // if (ptConfCall->ptCallClients == NULL) { UNLOCKTCALL(ptConfCall); ptConfCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE; } goto LCompleteTransfer_PostProcess_initMsgParams; } // // Retrieve the various call IDs, then check if call // client was destroyed by another thread (due to // lineClose/Shutdown) while we were getting the call ID. // If so, we'll need to clean up the tCall, since we know // the other thread didn't do it because GetCallIDs marks // the call as a zombie. // GetCallIDs (ptConfCall); if (ptConfCall->ptCallClients == NULL) { goto LCompleteTransfer_PostProcess_cleanupCalls; } // // Stuff the various call IDs in the var data section // of the ASYNCEVENTMSG. // // Make sure to increment the dwTotalSize of the ASYNCEVENTMSG // as appropriate. We rely on the fact that CompletionProc() // calls us with a AsyncEventMsg buffer which is big enough to // handle a few extra DWORDs. // pAsyncEventMsg->Param3 = ptConfCallClient->hCall; pAsyncEventMsg->TotalSize += 3 * sizeof (pAsyncEventMsg->Param4); *(&pAsyncEventMsg->Param4 + 1) = ptConfCall->dwAddressID; *(&pAsyncEventMsg->Param4 + 2) = ptConfCall->dwCallID; *(&pAsyncEventMsg->Param4 + 3) = ptConfCall->dwRelatedCallID; // // Mark the calls & conf list as valid, the release the mutex. // ptConfCall->dwKey = TCALL_KEY; ptConfCallClient->dwKey = TCALLCLIENT_KEY; ptConfCall->pConfList->dwKey = TCONFLIST_KEY; UNLOCKTCALL(ptConfCall); // // Create monitor tCallClients // if(ptCallThen = ReferenceObject(ghHandleTable, hCallThen, TCALL_KEY)) { if (ptCallThen == ptConfCall) { CreateCallMonitors (ptConfCall, FALSE); } DereferenceObject(ghHandleTable, hCallThen, 1); } } else // error { LCompleteTransfer_PostProcess_cleanupCalls: // // Invalidate the tCall, & if there's still a tCallClient // (might have already been destroyed by a lineClose/Shutdown // in another thread) invalidate it too. Then unlock the // tCall & remove the object(s) from the list(s). // ptConfCall->dwKey = ptConfCall->pConfList->dwKey = INVAL_KEY; if (ptConfCall->ptCallClients) { ptConfCallClient->dwKey = INVAL_KEY; ptConfCall->lActiveFastCallClients--; } else { ptConfCallClient = NULL; } UNLOCKTCALL(ptConfCall); RemoveCallFromLineList (ptConfCall); if (ptConfCallClient) { DereferenceObject (ghHandleTable, ptConfCallClient->hCall, 1); RemoveCallClientFromLineClientList (ptConfCallClient); } SetCallConfList (ptCall, NULL, FALSE); SetCallConfList (ptConsultCall, NULL, FALSE); // // Make sure all fast call clients cleaned up before free tCall // while (ptConfCall->lActiveFastCallClients != 0) { Sleep (5); } ServerFree (ptConfCall->pConfList); FreetCall (ptConfCall); } } else { // // If here we can assume that the call was already destroyed // and just fail the request // LCompleteTransfer_PostProcess_bad_ptConfCall: ptConfCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED; } } // // Fill in the params to pass to client (important to remotesp in both // the success & fail cases so it can either init or clean up drvCall) // LCompleteTransfer_PostProcess_initMsgParams: pAsyncEventMsg->Param4 = hpConfCallHandle; } void WINAPI LCompleteTransfer( PTCLIENT ptClient, PLINECOMPLETETRANSFER_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bDereferenceConsultCall = FALSE; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineCompleteTransfer; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINECOMPLETETRANSFER, // provider func index &pfnTSPI_lineCompleteTransfer, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "CompleteTransfer" // func name )) > 0) { PTCALL ptConfCall = (PTCALL) NULL, ptCall, ptConsultCall; HCALL hConfCall = 0; PTCALLCLIENT ptConfCallClient, ptConsultCallClient; // // Validate the hConsultCall // if (!(ptConsultCallClient = ReferenceObject( ghHandleTable, pParams->hConsultCall, TCALLCLIENT_KEY ))) { lRequestID = LINEERR_INVALCONSULTCALLHANDLE; goto LCompleteTransfer_return; } bDereferenceConsultCall = TRUE; if (ptConsultCallClient->ptClient != ptClient) { lRequestID = LINEERR_INVALCONSULTCALLHANDLE; goto LCompleteTransfer_return; } // // Verify that app has owner privilege for hConsultCall // if (ptConsultCallClient->dwPrivilege != LINECALLPRIVILEGE_OWNER) { lRequestID = LINEERR_NOTOWNER; goto LCompleteTransfer_return; } // // Safely verify hCall & hConsultCall are not the same call, // and that they are on the same tLine // try { ptCall = ptCallClient->ptCall; ptConsultCall = ptConsultCallClient->ptCall; if ((ptCall == ptConsultCall) || (ptCallClient->ptLineClient->ptLine != ptConsultCallClient->ptLineClient->ptLine)) { lRequestID = LINEERR_INVALCALLHANDLE; goto LCompleteTransfer_return; } } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LCompleteTransfer_return; } if (pParams->dwTransferMode == LINETRANSFERMODE_CONFERENCE) { LONG lResult; PTCONFERENCELIST pConfList; // // Create & init a conf list // if (!(pConfList = ServerAlloc( sizeof (TCONFERENCELIST) + DEF_NUM_CONF_LIST_ENTRIES * sizeof (PTCALL) ))) { lRequestID = LINEERR_NOMEM; goto LCompleteTransfer_return; } pConfList->dwNumTotalEntries = DEF_NUM_CONF_LIST_ENTRIES + 1; pConfList->dwNumUsedEntries = 1; // // Set the tCall & tConsultCall conf list, then create // the tConfCall & tConfCallClient // if ((lResult = SetCallConfList (ptCall, pConfList, FALSE)) == 0) { if ((lResult = SetCallConfList( ptConsultCall, pConfList, FALSE )) == 0) { if ((lResult = CreatetCallAndClient( ptCallClient->ptLineClient, &ptConfCall, &ptConfCallClient, NULL, &hConfCall, NULL )) == 0) { pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConfCall; ptConfCall->pConfList = pConfList; pConfList->aptCalls[0] = ptConfCall; pAsyncRequestInfo->htXxx = (ULONG_PTR) ptConfCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConfCall; pAsyncRequestInfo->dwParam2 = (ULONG_PTR) pParams->hpConfCallHandle; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) ptCall; pAsyncRequestInfo->dwParam4 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->pfnPostProcess = LCompleteTransfer_PostProcess; goto LCompleteTransfer_callSP; } SetCallConfList (ptConsultCall, NULL, FALSE); } SetCallConfList (ptCall, NULL, FALSE); } // // If here an error occured // ServerFree (pConfList); lRequestID = lResult; goto LCompleteTransfer_return; } else if (pParams->dwTransferMode != LINETRANSFERMODE_TRANSFER) { lRequestID = LINEERR_INVALTRANSFERMODE; goto LCompleteTransfer_return; } LCompleteTransfer_callSP: pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineCompleteTransfer, "lineCompleteTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) ptConsultCallClient->ptCall->hdCall, (ULONG_PTR) hConfCall, (ULONG_PTR) (ptConfCall ? &ptConfCall->hdCall : 0), (DWORD) pParams->dwTransferMode ); if (ptConfCall) { SetDrvCallFlags( hConfCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); } } LCompleteTransfer_return: if (bDereferenceConsultCall) { DereferenceObject (ghHandleTable, pParams->hConsultCall, 1); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "CompleteTransfer" ); } void WINAPI LConditionalMediaDetection( PTCLIENT ptClient, PLINECONDITIONALMEDIADETECTION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineConditionalMediaDetection; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINECONDITIONALMEDIADETECTION, // provider func index &pfnTSPI_lineConditionalMediaDetection, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "ConditionalMediaDetection" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion; LPLINECALLPARAMS pCallParams; // // This func only gets called by RemoteSP. Since RemoteSP // might be down-level, we need to compare API/SPI vers // to see if we need to munge call params (and it's good // to validate them anyway). // pCallParams = (LPLINECALLPARAMS) (pDataBuf + pParams->dwCallParamsOffset); try { dwAPIVersion = ptLineClient->dwAPIVersion; dwSPIVersion = ptLineClient->ptLine-> dwSPIVersion; if (ptLineClient->dwKey != TLINECLIENT_KEY) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LConditionalMediaDetection_epilog; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LConditionalMediaDetection_epilog; } if ((pParams->lResult = ValidateCallParams( pCallParams, &pCallParams, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) == 0) { pParams->lResult = CallSP3( pfnTSPI_lineConditionalMediaDetection, "lineConditionalMediaDetection", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) pParams->dwMediaModes, (ULONG_PTR) pCallParams ); if (pCallParams != (LPLINECALLPARAMS) (pDataBuf + pParams->dwCallParamsOffset)) { ServerFree (pCallParams); } } } LConditionalMediaDetection_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "ConditionalMediaDetection" ); } void LCreateAgent_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3; CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = pNewAsyncEventMsg; if (pAsyncEventMsg->Param2 == 0) // success { pNewAsyncEventMsg->TotalSize += ((sizeof(HAGENT) + 7) & 0xFFFFFFF8); // // param1 must not exceed 32 bits. use DWORD_CAST to enforce this at // least in runtime. // pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); pNewAsyncEventMsg->Param4 = sizeof(HAGENT); } } void WINAPI LCreateAgent( PTCLIENT ptClient, PLINECREATEAGENT_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwAgentIDOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwAgentIDOffset )) || ((pParams->dwAgentPINOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwAgentPINOffset ))) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "CreateAgent" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_CREATEAGENT, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LCreateAgent_epilog; } // // Save client's buffer pointer and post processing proc // pAsyncRequestInfo->dwParam1 = pParams->hpAgent; pAsyncRequestInfo->dwParam2 = sizeof(HAGENT); pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; DWORD dwAgentIDSize = 0; DWORD dwAgentPINSize = 0; DWORD dwTotalSize = 0; DWORD dwOffset = 0; // // Figure out the total size of info we are passing to the proxy // if (TAPI_NO_DATA != pParams->dwAgentIDOffset) { dwAgentIDSize = (lstrlenW ((PWSTR)(pDataBuf + pParams->dwAgentIDOffset)) + 1) * sizeof(WCHAR); dwTotalSize += dwAgentIDSize; } if (TAPI_NO_DATA != pParams->dwAgentPINOffset) { dwAgentPINSize = (lstrlenW ((PWSTR)(pDataBuf + pParams->dwAgentPINOffset)) + 1) * sizeof(WCHAR); dwTotalSize += dwAgentPINSize; } // // Fixed part of union part of structure // dwTotalSize += 4 * sizeof(DWORD) + sizeof(HAGENT); if (lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_CREATEAGENT, dwTotalSize, pAsyncRequestInfo, &pProxyRequestWrapper )) { lRequestID = lResult; goto LCreateAgent_epilog; } // // Save the info in the proxy request // // // The offset is after the fixed size of the CreateAgent // struct which has 4 dwords and an hAgent. // // This will require no extra alloc on the client side // as the thing to be returned is the hAgent // dwOffset = 4 * sizeof(DWORD) + sizeof(HAGENT); // // Copy the id if exists // if (0 != dwAgentIDSize) { pProxyRequestWrapper->ProxyRequest.CreateAgent. dwAgentIDSize = dwAgentIDSize; pProxyRequestWrapper->ProxyRequest.CreateAgent. dwAgentIDOffset = dwOffset; wcscpy( (PWSTR)((LPBYTE)(&(pProxyRequestWrapper-> ProxyRequest.CreateAgent)) + dwOffset), (PWSTR)(pDataBuf + pParams->dwAgentIDOffset) ); dwOffset += dwAgentIDSize; } // // Copy the pin if exists // if (0 != dwAgentPINSize) { pProxyRequestWrapper->ProxyRequest.CreateAgent. dwAgentPINSize = dwAgentPINSize; pProxyRequestWrapper->ProxyRequest.CreateAgent. dwAgentPINOffset = dwOffset; wcscpy( (PWSTR)((LPBYTE)(&(pProxyRequestWrapper-> ProxyRequest.CreateAgent)) + dwOffset), (PWSTR)(pDataBuf + pParams->dwAgentPINOffset) ); } if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LCreateAgent_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; pBuf = ServerAlloc (sizeof (ASYNCEVENTMSG) + sizeof (HAGENT)); if (!pBuf) { lRequestID = LINEERR_NOMEM; goto LCreateAgent_epilog; } pAsyncRequestInfo->pfnPostProcess = LCreateAgent_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINECREATEAGENT], "CreateAgent", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (ULONG_PTR) ((pParams->dwAgentIDOffset) == TAPI_NO_DATA ? NULL : (pDataBuf + pParams->dwAgentIDOffset)), (ULONG_PTR) ((pParams->dwAgentPINOffset) == TAPI_NO_DATA ? NULL : (pDataBuf + pParams->dwAgentPINOffset)), (ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG)) ); } // // No proxy and not remote // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LCreateAgent_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "CreateAgent" ); } void WINAPI LCreateAgentSession( PTCLIENT ptClient, PLINECREATEAGENTSESSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwAgentPINOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwAgentPINOffset )) || ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwGroupIDSize, pParams->dwGroupIDOffset, sizeof(DWORD), "LCreateAgentSession", "pParams->GroupID" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "CreateAgentSession" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, pParams->dwWorkingAddressID, LINEPROXYREQUEST_CREATEAGENTSESSION, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LCreateAgentSession_epilog; } // // save client's buffer pointer and // post processing proc // pAsyncRequestInfo->dwParam1 = pParams->hpAgentSessionHandle; pAsyncRequestInfo->dwParam2 = sizeof(HAGENTSESSION); pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; DWORD dwAgentPINSize = 0; DWORD dwTotalSize = 0; DWORD dwOffset = 0; // // figure out the total size of information // we are passing to the proxy // if (TAPI_NO_DATA != pParams->dwAgentPINOffset) { dwAgentPINSize = (lstrlenW( (PWSTR)(pDataBuf + pParams->dwAgentPINOffset)) + 1 ) * sizeof(WCHAR); } // // Add the union part of the CreateAgentSession request // which looks like: // // struct // { // HAGENTSESSION hAgentSession; // DWORD dwAgentPINSize; // DWORD dwAgentPINOffset; // HAGENT hAgent; // GUID GroupID; // DWORD dwWorkingAddressID; // // } CreateAgentSession; // dwOffset = ( 3 * sizeof(DWORD) ) + sizeof(GUID) + sizeof(HAGENTSESSION) + sizeof(HAGENT); dwTotalSize = dwOffset + dwAgentPINSize; if (lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_CREATEAGENTSESSION, dwTotalSize, pAsyncRequestInfo, &pProxyRequestWrapper )) { lRequestID = lResult; goto LCreateAgentSession_epilog; } // // Save the info in the proxy request - copy the pin if exists // if ( 0 != dwAgentPINSize ) { pProxyRequestWrapper->ProxyRequest.CreateAgentSession. dwAgentPINSize = dwAgentPINSize; pProxyRequestWrapper->ProxyRequest.CreateAgentSession. dwAgentPINOffset = dwOffset; wcscpy( (PWSTR)((LPBYTE)(&(pProxyRequestWrapper-> ProxyRequest.CreateAgentSession)) + dwOffset), (PWSTR)(pDataBuf + pParams->dwAgentPINOffset) ); } CopyMemory( &(pProxyRequestWrapper-> ProxyRequest.CreateAgentSession.GroupID), pDataBuf + pParams->dwGroupIDOffset, sizeof( GUID ) ); pProxyRequestWrapper->ProxyRequest.CreateAgentSession. dwWorkingAddressID = pParams->dwWorkingAddressID; pProxyRequestWrapper->ProxyRequest.CreateAgentSession. hAgent = pParams->hAgent; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LCreateAgentSession_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; pBuf = ServerAlloc(sizeof(ASYNCEVENTMSG) + sizeof (HAGENTSESSION)); if ( NULL == pBuf ) { lRequestID = LINEERR_NOMEM; goto LCreateAgentSession_epilog; } pAsyncRequestInfo->pfnPostProcess = LCreateAgent_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pParams->lResult = CallSP7( pRemoteSP->apfn[SP_LINECREATEAGENTSESSION], "CreateAgentSession", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->hAgent, (ULONG_PTR) ((pParams->dwAgentPINOffset) == TAPI_NO_DATA ? NULL : (pDataBuf + pParams->dwAgentPINOffset)), (DWORD) pParams->dwWorkingAddressID, (ULONG_PTR) (pDataBuf + pParams->dwGroupIDOffset), (ULONG_PTR) (pBuf + sizeof (ASYNCEVENTMSG)) ); } // // no proxy and not remote // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LCreateAgentSession_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "CreateAgentSession" ); } void WINAPI LCreateMSPInstance( PTCLIENT ptClient, PLINECREATEMSPINSTANCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineCreateMSPInstance; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINECREATEMSPINSTANCE, // provider func index &pfnTSPI_lineCreateMSPInstance, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, &ptLineClient, "CreateMSPInstance" // func name )) == 0) { pParams->lResult = CallSP4( pfnTSPI_lineCreateMSPInstance, "lineCreateMSPInstance", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (DWORD) ptLineClient->hLine, (ULONG_PTR) &ptLineClient->hdMSPLine ); if ( 0 == pParams->lResult ) { *pdwNumBytesReturned = sizeof( LINECREATEMSPINSTANCE_PARAMS ); } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "CreateMSPInstance" ); } void WINAPI LDeallocateCall( PTCLIENT ptClient, PLINEDEALLOCATECALL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; DWORD objectToDereference; PTCALLCLIENT ptCallClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "DeallocateCall" // func name )) == 0) { // // Per nt bug #20546 we're now allowing the last owner to dealloc // a non-IDLE call. Decided to do this based on distributed call // ownership issues. dankn 02/13/96 // DestroytCallClient (ptCallClient); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "DeallocateCall" ); } void LDevSpecific_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3; CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = pNewAsyncEventMsg; if (pAsyncEventMsg->Param2 == 0) // success { // // Make sure to keep the total size 64-bit aligned // pNewAsyncEventMsg->TotalSize += (DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__) + 7) & 0xfffffff8; // // need to be at most 32-bit. use dword_cast to ensure this in // runtime // pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); // lpParams pNewAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // dwSize } } void WINAPI LDevSpecific( PTCLIENT ptClient, PLINEDEVSPECIFIC_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bDereferenceLineClient = FALSE; LONG lRequestID; DWORD dwWidgetType, hWidget; DWORD dwPrivilege = LINECALLPRIVILEGE_MONITOR; HANDLE hMutex; TSPIPROC pfnTSPI_lineDevSpecific; DWORD objectToDereference; ULONG_PTR hdWidget; PTCALLCLIENT ptXxxClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwParamsSize, pParams->dwParamsOffset, sizeof(DWORD), "LDevSpecific", "pParams->Params" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (pParams->hCall) { dwWidgetType = ANY_RT_HCALL; hWidget = (DWORD) pParams->hCall; } else { dwWidgetType = ANY_RT_HLINE; hWidget = (DWORD) pParams->hLine; } if ((lRequestID = LINEPROLOG( ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle (LPVOID) &hdWidget, // provider widget handle (pParams->hCall ? (dwPrivilege) : 0), // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEDEVSPECIFIC, // provider func index &pfnTSPI_lineDevSpecific, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptXxxClient, // context "DevSpecific" // func name )) > 0) { LPBYTE pBuf; HDRVCALL hdCall; HDRVLINE hdLine; // // If an hCall was specified verify the hLine & // make sure the call is on the specified hLine // if (dwWidgetType == ANY_RT_HCALL) { LONG lResult; PTLINECLIENT ptLineClient; if (!(ptLineClient = ReferenceObject( ghHandleTable, pParams->hLine, TLINECLIENT_KEY ))) { lRequestID = LINEERR_INVALLINEHANDLE; goto LDevSpecific_epilog; } bDereferenceLineClient = TRUE; if (ptLineClient->ptClient != ptClient) { lRequestID = LINEERR_INVALLINEHANDLE; goto LDevSpecific_epilog; } try { lResult = LINEERR_INVALLINEHANDLE; hdLine = ptLineClient->ptLine->hdLine; lResult = LINEERR_INVALCALLHANDLE; if (ptLineClient != ptXxxClient->ptLineClient) { LOG((TL_ERROR, "LDevSpecific: error, hCall=x%x not related " \ "to hLine=x%x", pParams->hCall, pParams->hLine )); lRequestID = LINEERR_INVALCALLHANDLE; goto LDevSpecific_epilog; } } myexcept { lRequestID = lResult; goto LDevSpecific_epilog; } hdCall = (HDRVCALL) hdWidget; } else { hdLine = (HDRVLINE) hdWidget; hdCall = 0; } // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( ((pParams->dwParamsSize + 7) & 0xfffffff8) + sizeof (ASYNCEVENTMSG) ))) { lRequestID = LINEERR_NOMEM; goto LDevSpecific_epilog; } CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, pParams->dwParamsSize ); pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam1 = pParams->hpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineDevSpecific, "lineDevSpecific", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); } LDevSpecific_epilog: if (bDereferenceLineClient) { DereferenceObject (ghHandleTable, pParams->hLine, 1); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "DevSpecific" ); } void WINAPI LDevSpecificEx( PTCLIENT ptClient, PLINEDEVSPECIFICEX_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwWidgetType, hWidget; DWORD dwPrivilege = LINECALLPRIVILEGE_MONITOR; DWORD dwCallHubID = 0; HANDLE hMutex; LPVOID context; TSPIPROC pfnTSPI_lineDevSpecificEx; DWORD objectToDereference; ULONG_PTR hdWidget; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwParamsSize, pParams->dwParamsOffset, sizeof(DWORD), "LDevSpecificEx", "pParams->Params" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } switch (pParams->dwSelect) { case LINECALLSELECT_DEVICEID: case LINECALLSELECT_ADDRESS: dwWidgetType = DEVICE_ID; hWidget = pParams->dwDeviceID; break; case LINECALLSELECT_CALLID: { PTCALLHUBCLIENT ptCallHubClient; if (ptCallHubClient = IsValidCallHub( pParams->hCallHub, ptClient )) { try { dwCallHubID = ptCallHubClient->dwCallHubID; if (ptCallHubClient->dwKey != TCALLHUBCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; return; } } myexcept { pParams->lResult = LINEERR_INVALCALLSELECT; return; } } } // fall through case LINECALLSELECT_CALL: dwWidgetType = ANY_RT_HCALL; hWidget = (DWORD) pParams->hCall; break; case LINECALLSELECT_LINE: default: pParams->lResult = LINEERR_INVALCALLSELECT; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle (LPVOID) &hdWidget, // provider widget handle (pParams->hCall ? (dwPrivilege) : 0), // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEDEVSPECIFICEX, // provider func index &pfnTSPI_lineDevSpecificEx, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &context, // context "DevSpecificEx" // func name )) > 0) { DWORD dwDeviceID = 0; LPBYTE pBuf; HDRVCALL hdCall = 0; switch (pParams->dwSelect) { case LINECALLSELECT_DEVICEID: case LINECALLSELECT_ADDRESS: dwDeviceID = (DWORD) hdWidget; break; case LINECALLSELECT_CALLID: case LINECALLSELECT_CALL: hdCall = (HDRVCALL) hdWidget; break; default: lRequestID = LINEERR_INVALCALLSELECT; goto LDevSpecificEx_epilog; } // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( ((pParams->dwParamsSize + 7) & 0xfffffff8) + sizeof (ASYNCEVENTMSG) ))) { lRequestID = LINEERR_NOMEM; goto LDevSpecificEx_epilog; } CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, pParams->dwParamsSize ); pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam1 = pParams->hpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP8( pfnTSPI_lineDevSpecificEx, "lineDevSpecificEx", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (DWORD) dwDeviceID, (DWORD) pParams->dwAddressID, (ULONG_PTR) hdCall, (DWORD) dwCallHubID, (DWORD) pParams->dwSelect, (ULONG_PTR) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); } LDevSpecificEx_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "DevSpecific" ); } void WINAPI LDevSpecificFeature( PTCLIENT ptClient, PLINEDEVSPECIFICFEATURE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineDevSpecificFeature; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwParamsSize, pParams->dwParamsOffset, sizeof(DWORD), "LDevSpecificFeature", "pParams->Params" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEDEVSPECIFICFEATURE, // provider func index &pfnTSPI_lineDevSpecificFeature,// provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "DevSpecificFeature" // func name )) > 0) { LPBYTE pBuf; if (pParams->dwFeature > PHONEBUTTONFUNCTION_NONE && (pParams->dwFeature & 0x80000000) == 0) { lRequestID = LINEERR_INVALFEATURE; goto LDevSpecificFeature_epilog; } // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( ((pParams->dwParamsSize + 7) & 0xfffffff8) + sizeof (ASYNCEVENTMSG) ))) { lRequestID = LINEERR_NOMEM; goto LDevSpecificFeature_epilog; } CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, pParams->dwParamsSize ); pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam1 = pParams->hpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineDevSpecificFeature, "lineDevSpecificFeature", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwFeature, (ULONG_PTR) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); } LDevSpecificFeature_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "DevSpecificFeature" ); } void WINAPI LDial( PTCLIENT ptClient, PLINEDIAL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineDial; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEDIAL, // provider func index &pfnTSPI_lineDial, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Dial" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineDial, "lineDial", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset), (DWORD) pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Dial" ); } void WINAPI LDrop( PTCLIENT ptClient, PLINEDROP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineDrop; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwUserUserInfoOffset, sizeof(DWORD), "LDrop", "pParams->UserUserInfo" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEDROP, // provider func index &pfnTSPI_lineDrop, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Drop" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineDrop, "lineDrop", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwUserUserInfoOffset), (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 : pParams->dwSize) ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Drop" ); } LPBYTE NewToOldLineforwardlist( LPLINEFORWARDLIST pFwdList3_1 ); LPLINEFORWARDLIST OldToNewLineforwardlist( LPLINEFORWARDLIST pFwdList3_0 ); void WINAPI LForward( PTCLIENT ptClient, PLINEFORWARD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineForward; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; DWORD dwSizeofLFwdList = sizeof (LINEFORWARDLIST); DWORD dwSizeofLFwd = sizeof (LINEFORWARD); if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEFORWARD, // provider func index &pfnTSPI_lineForward, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "Forward" // func name )) > 0) { LONG lResult; DWORD dwAPIVersion, dwSPIVersion; PTCALL ptConsultCall; HCALL hConsultCall = 0; PTCALLCLIENT ptConsultCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; LPLINEFORWARDLIST pFwdList = (LPLINEFORWARDLIST) (pParams->dwForwardListOffset == TAPI_NO_DATA ? NULL :pDataBuf + pParams->dwForwardListOffset), pTmpFwdList = NULL, pTmpFwdList1 = NULL; // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwForwardListOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwForwardListOffset )) || ((pParams->dwCallParamsOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset ))) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LForward_epilog; } // // Validate the params // if (GetLineVersions (ptLineClient, &dwAPIVersion, &dwSPIVersion) != 0) { lRequestID = LINEERR_INVALLINEHANDLE; goto LForward_epilog; } // // Check if the client app. is < 3.1 ===> uses old LINEFORWARD structure // if ( ptLineClient->ptLineApp->dwAPIVersion < TAPI_VERSION3_1 ) { dwSizeofLFwdList -= 2 * sizeof (DWORD); dwSizeofLFwd -= 2 * sizeof (DWORD); } if (pFwdList) { DWORD dwTotalSize = pFwdList->dwTotalSize, dwFixedSize, dwNumEntries, i, dwInvalidForwardModes; LPLINEFORWARD pFwdEntry = pFwdList->ForwardList; if (dwTotalSize < dwSizeofLFwdList) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LForward_epilog; } // // Note: dwNumEntries == 0 is the same as pFwdList == NULL // dwNumEntries = pFwdList->dwNumEntries; if (dwNumEntries & 0xffff0000) { lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } dwFixedSize = dwSizeofLFwdList + dwSizeofLFwd * (dwNumEntries == 0 ? 0 : dwNumEntries - 1); if (dwFixedSize > dwTotalSize) { lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } dwInvalidForwardModes = (dwAPIVersion < TAPI_VERSION1_4 ? ~AllForwardModes1_0 : ~AllForwardModes1_4); for (i = 0; i < dwNumEntries; i++) { if (!IsOnlyOneBitSetInDWORD (pFwdEntry->dwForwardMode) || pFwdEntry->dwForwardMode & dwInvalidForwardModes) { LOG((TL_ERROR, "LFoward: bad dwForwardMode, x%x", pFwdEntry->dwForwardMode )); lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSize, pFwdEntry->dwCallerAddressSize, pFwdEntry->dwCallerAddressOffset, 0, "LFoward", "CallerAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSize, pFwdEntry->dwDestAddressSize, pFwdEntry->dwDestAddressOffset, 0, "LFoward", "CallerAddress" )) { lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } // don't bother validating country code right now pFwdEntry = (LPLINEFORWARD) ((LPBYTE)pFwdEntry + dwSizeofLFwd); } // // See if we need to convert an ascii fwd list to unicode // if (pParams->dwAsciiCallParamsCodePage != 0xffffffff && dwNumEntries != 0) { DWORD dwXxxOffset; // // Alloc a temporary buffer for storing the converted // data (sizeof(WCHAR) * dwTotalSize to insure buffer // is large enough for all ascii->unicode conversions) // if (!(pTmpFwdList = ServerAlloc (sizeof(WCHAR) * dwTotalSize))) { lRequestID = LINEERR_NOMEM; goto LForward_epilog; } dwXxxOffset = dwSizeofLFwdList + (dwNumEntries - 1) * dwSizeofLFwd; pFwdEntry = pTmpFwdList->ForwardList; CopyMemory (pTmpFwdList, pFwdList, dwXxxOffset); pTmpFwdList->dwTotalSize *= sizeof (WCHAR); for (i = 0; i < dwNumEntries; i++) { if (pFwdEntry->dwCallerAddressSize) { MultiByteToWideChar( pParams->dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pFwdList) + pFwdEntry->dwCallerAddressOffset), pFwdEntry->dwCallerAddressSize, (LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset), pFwdEntry->dwCallerAddressSize ); pFwdEntry->dwCallerAddressOffset = dwXxxOffset; dwXxxOffset += (pFwdEntry->dwCallerAddressSize *= sizeof (WCHAR)); } if (pFwdEntry->dwDestAddressSize) { MultiByteToWideChar( pParams->dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pFwdList) + pFwdEntry->dwDestAddressOffset), pFwdEntry->dwDestAddressSize, (LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset), pFwdEntry->dwDestAddressSize ); pFwdEntry->dwDestAddressOffset = dwXxxOffset; dwXxxOffset += (pFwdEntry->dwDestAddressSize *= sizeof (WCHAR)); } pFwdEntry = (LPLINEFORWARD) ((LPBYTE)pFwdEntry + dwSizeofLFwd); } pFwdList = pTmpFwdList; } } // // Check if we need LINEFORWARDLIST conversion new to old // if the TSP is < 3.1 ===> expects old LINEFORWARDLIST structure // and the App is >= 3.1 ===> sent over new LINEFORWARDLIST structure // if ( pFwdList && dwSPIVersion < TAPI_VERSION3_1 && ptLineClient->ptLineApp->dwAPIVersion >= TAPI_VERSION3_1 ) { if (!(pTmpFwdList1 = ( LPLINEFORWARDLIST ) NewToOldLineforwardlist (pFwdList))) { lRequestID = LINEERR_NOMEM; goto LForward_freeFwdList; } pFwdList = pTmpFwdList1; } // // Check if we need LINEFORWARDLIST conversion old to new // if the TSP is >= 3.1 ===> expects new LINEFORWARDLIST structure // and the App is < 3.1 ===> sent over old LINEFORWARDLIST structure // if ( pFwdList && dwSPIVersion >= TAPI_VERSION3_1 && ptLineClient->ptLineApp->dwAPIVersion < TAPI_VERSION3_1 ) { if (!(pTmpFwdList1 = OldToNewLineforwardlist (pFwdList))) { lRequestID = LINEERR_NOMEM; goto LForward_freeFwdList; } pFwdList = pTmpFwdList1; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwCallParamsOffset); if (pCallParamsApp) { if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LForward_freeFwdList1; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( ptLineClient, &ptConsultCall, &ptConsultCallClient, pCallParamsSP, &hConsultCall, NULL ) != 0) { lRequestID = LINEERR_NOMEM; goto LForward_freeCallParams; } //htConsultCall = ptConsultCall->htCall; pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall; pAsyncRequestInfo->dwParam3 = 1; // special case for post-process proc pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP9( pfnTSPI_lineForward, "lineForward", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->bAllAddresses, (DWORD) pParams->dwAddressID, (ULONG_PTR) pFwdList, (DWORD) pParams->dwNumRingsNoAnswer, (ULONG_PTR) hConsultCall, (ULONG_PTR) &ptConsultCall->hdCall, (ULONG_PTR) pCallParamsSP ); SetDrvCallFlags( hConsultCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); LForward_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } LForward_freeFwdList1: if (pTmpFwdList1) { ServerFree (pTmpFwdList1); } LForward_freeFwdList: if (pTmpFwdList) { ServerFree (pTmpFwdList); } } LForward_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Forward" ); } void WINAPI LGatherDigits( PTCLIENT ptClient, PLINEGATHERDIGITS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGatherDigits; DWORD objectToDereference; PTCALLCLIENT ptCallClient; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwTerminationDigitsOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwTerminationDigitsOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGATHERDIGITS, // provider func index &pfnTSPI_lineGatherDigits, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "GatherDigits" // func name )) == 0) { DWORD dwDigitModes = pParams->dwDigitModes; LPWSTR lpsDigits; PASYNCREQUESTINFO pAsyncRequestInfo; #define AllGatherDigitsModes (LINEDIGITMODE_PULSE | LINEDIGITMODE_DTMF) if (!(dwDigitModes & AllGatherDigitsModes) || (dwDigitModes & ~AllGatherDigitsModes)) { pParams->lResult = LINEERR_INVALDIGITMODE; goto LGatherDigits_epilog; } if (pParams->hpsDigits) { // // The client passed us a non-null digits buffer so we'll // alloc an async request info buf with extra space at the // end for the temporary digits buf for use by the sp // (faster than two two allocs & two frees for separate // async request & digits bufs). Use the pointer as the // dwEndToEndID we pass to the sp. // PTLINECLIENT ptLineClient; if (pParams->dwNumDigits == 0) { pParams->lResult = LINEERR_INVALPARAM; goto LGatherDigits_epilog; } if (!(pAsyncRequestInfo = ServerAlloc( sizeof (ASYNCREQUESTINFO) + (pParams->dwNumDigits * sizeof (WCHAR)) ))) { pParams->lResult = LINEERR_NOMEM; goto LGatherDigits_epilog; } lpsDigits = (LPWSTR) (pAsyncRequestInfo + 1); ptLineClient = ptCallClient->ptLineClient; pAsyncRequestInfo->dwKey = TASYNC_KEY; pAsyncRequestInfo->ptClient = ptClient; try { pAsyncRequestInfo->InitContext = ptLineClient->ptLineApp->InitContext; pAsyncRequestInfo->OpenContext = ptLineClient->OpenContext; } myexcept { ServerFree (pAsyncRequestInfo); pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGatherDigits_epilog; } pAsyncRequestInfo->dwParam1 = sizeof (ASYNCREQUESTINFO); pAsyncRequestInfo->dwParam2 = DWORD_CAST(pParams->hpsDigits,__FILE__,__LINE__); pAsyncRequestInfo->dwParam3 = pParams->dwNumDigits; pAsyncRequestInfo->dwParam4 = pParams->hCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)pParams->dwEndToEndID; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pAsyncRequestInfo->dwLocalRequestID = (DWORD) NewObject( ghHandleTable, pAsyncRequestInfo, NULL ); } else { // // Client wants to cancel gathering, so just set these two to null // lpsDigits = NULL; pAsyncRequestInfo = NULL; } if ((pParams->lResult = CallSP8( pfnTSPI_lineGatherDigits, "lineGatherDigits", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) (pAsyncRequestInfo ? pAsyncRequestInfo->dwLocalRequestID : 0), (DWORD) dwDigitModes, (ULONG_PTR) lpsDigits, (DWORD) pParams->dwNumDigits, (ULONG_PTR) (pParams->dwTerminationDigitsOffset ==TAPI_NO_DATA? 0 : (pDataBuf + pParams->dwTerminationDigitsOffset)), (DWORD) pParams->dwFirstDigitTimeout, (DWORD) pParams->dwInterDigitTimeout )) != 0) { if (pAsyncRequestInfo) { DereferenceObject( ghHandleTable, pAsyncRequestInfo->dwLocalRequestID, 1 ); } } } LGatherDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GatherDigits" ); } void WINAPI LGenerateDigits( PTCLIENT ptClient, PLINEGENERATEDIGITS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGenerateDigits; DWORD objectToDereference; PTCALLCLIENT ptCallClient; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwDigitsOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDigitsOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGENERATEDIGITS, // provider func index &pfnTSPI_lineGenerateDigits,// provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "GenerateDigits" // func name )) == 0) { DWORD dwDigitMode = pParams->dwDigitMode, *pInstData, dwEndToEndID = 0; if (dwDigitMode != LINEDIGITMODE_PULSE && dwDigitMode != LINEDIGITMODE_DTMF) { pParams->lResult = LINEERR_INVALDIGITMODE; goto LGenerateDigits_epilog; } if (pParams->dwDigitsOffset != TAPI_NO_DATA) { if (!(pInstData = ServerAlloc (3 * sizeof (DWORD)))) { pParams->lResult = LINEERR_NOMEM; goto LGenerateDigits_epilog; } pInstData[0] = TASYNC_KEY; pInstData[1] = (DWORD) pParams->hCall; pInstData[2] = pParams->dwEndToEndID; dwEndToEndID = (DWORD) NewObject (ghHandleTable, pInstData, 0); } pParams->lResult = CallSP5( pfnTSPI_lineGenerateDigits, "lineGenerateDigits", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) dwEndToEndID, (DWORD) dwDigitMode, (ULONG_PTR) (pParams->dwDigitsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDigitsOffset), (DWORD) pParams->dwDuration ); if (pParams->lResult != 0 && dwEndToEndID != 0) { DereferenceObject (ghHandleTable, dwEndToEndID, 1); } } LGenerateDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GenerateDigits" ); } void WINAPI LGenerateTone( PTCLIENT ptClient, PLINEGENERATETONE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGenerateTone; DWORD objectToDereference; PTCALLCLIENT ptCallClient; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwToneMode == LINETONEMODE_CUSTOM) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwNumTones * sizeof (LINEGENERATETONE), pParams->dwTonesOffset, sizeof(DWORD), "LGenerateTone", "pParams->Tones" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGENERATETONE, // provider func index &pfnTSPI_lineGenerateTone, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "GenerateTone" // func name )) == 0) { DWORD dwToneMode = pParams->dwToneMode, *pInstData, dwEndToEndID; if (dwToneMode != 0) { if (!(dwToneMode & AllToneModes) || !IsOnlyOneBitSetInDWORD (dwToneMode)) { pParams->lResult = LINEERR_INVALTONEMODE; goto LGenerateTone_epilog; } else if (!(pInstData = ServerAlloc (3 * sizeof (DWORD)))) { pParams->lResult = LINEERR_NOMEM; goto LGenerateTone_epilog; } pInstData[0] = TASYNC_KEY; pInstData[1] = (DWORD) pParams->hCall; pInstData[2] = pParams->dwEndToEndID; dwEndToEndID = (DWORD) NewObject (ghHandleTable, pInstData, 0); } else { dwEndToEndID = 0; } pParams->lResult = CallSP6( pfnTSPI_lineGenerateTone, "lineGenerateTone", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) dwEndToEndID, (DWORD) pParams->dwToneMode, (DWORD) pParams->dwDuration, (DWORD) pParams->dwNumTones, (ULONG_PTR) (pDataBuf + pParams->dwTonesOffset) ); if (pParams->lResult != 0 && dwEndToEndID != 0) { DereferenceObject (ghHandleTable, dwEndToEndID, 1); } } LGenerateTone_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GenerateTone" ); } void WINAPI LGetAddressCaps( PTCLIENT ptClient, PLINEGETADDRESSCAPS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetAddressCaps; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwAddressCapsTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETADDRESSCAPS, // provider func index &pfnTSPI_lineGetAddressCaps,// provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetAddressCaps" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPLINEADDRESSCAPS pAddrCaps = (LPLINEADDRESSCAPS) pDataBuf, pAddrCaps2 = (LPLINEADDRESSCAPS) NULL; // // Verify API & SPI version compatibility // dwAPIVersion = pParams->dwAPIVersion; dwSPIVersion = pLookupEntry->dwSPIVersion; if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion)) { pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetAddressCaps_epilog; } // // Verify Ext version compatibility // if (!IsValidLineExtVersion (dwDeviceID, pParams->dwExtVersion)) { pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION; goto LGetAddressCaps_epilog; } // // Determine the fixed siize of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwAddressCapsTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwFixedSizeClient = 176; // 44 * sizeof (DWORD); break; case TAPI_VERSION1_4: dwFixedSizeClient = 180; // 45 * sizeof (DWORD); break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEADDRESSCAPS); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetAddressCaps_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: dwFixedSizeSP = 176; // 44 * sizeof (DWORD); break; case TAPI_VERSION1_4: dwFixedSizeSP = 180; // 45 * sizeof (DWORD); break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINEADDRESSCAPS); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pAddrCaps2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetAddressCaps_epilog; } pAddrCaps = pAddrCaps2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pAddrCaps, dwTotalSize, dwFixedSizeSP, (pAddrCaps2 == NULL ? TRUE : FALSE) ); if ((pParams->lResult = CallSP5( pfnTSPI_lineGetAddressCaps, "lineGetAddressCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pParams->dwAddressID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtVersion, (ULONG_PTR) pAddrCaps )) == 0) { #if DBG // // Verify the info returned by the provider // #endif // // Add the fields we're responsible for // pAddrCaps->dwCallInfoStates |= LINECALLINFOSTATE_NUMOWNERINCR | LINECALLINFOSTATE_NUMOWNERDECR | LINECALLINFOSTATE_NUMMONITORS; pAddrCaps->dwCallStates |= LINECALLSTATE_UNKNOWN; pAddrCaps->dwLineDeviceID = pParams->dwDeviceID; // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // if ((dwAPIVersion == TAPI_VERSION1_0) && (pAddrCaps->dwForwardModes & (LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL))) { pAddrCaps->dwForwardModes &= ~(LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL); pAddrCaps->dwForwardModes |= LINEFORWARDMODE_UNCOND; } if ((dwAPIVersion == TAPI_VERSION2_0) && (pAddrCaps->dwAvailableMediaModes & LINEMEDIAMODE_VIDEO)) { pAddrCaps->dwAvailableMediaModes = LINEMEDIAMODE_UNKNOWN | (pAddrCaps->dwAvailableMediaModes & ~LINEMEDIAMODE_VIDEO); } // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // if (pAddrCaps == pAddrCaps2) { pAddrCaps = (LPLINEADDRESSCAPS) pDataBuf; CopyMemory (pAddrCaps, pAddrCaps2, dwFixedSizeClient); ServerFree (pAddrCaps2); pAddrCaps->dwTotalSize = pParams->dwAddressCapsTotalSize; pAddrCaps->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->dwAddressCapsOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAddrCaps->dwUsedSize; } } LGetAddressCaps_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetAddressCaps" ); } void WINAPI LGetAddressID( PTCLIENT ptClient, PLINEGETADDRESSID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetAddressID; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwAddressOffset, sizeof(DWORD), "LGetAddressID", "pParams->Address" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETADDRESSID, // provider func index &pfnTSPI_lineGetAddressID, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetAddressID" // func name )) == 0) { if (pParams->dwAddressMode == LINEADDRESSMODE_DIALABLEADDR) { pParams->lResult = CallSP5( pfnTSPI_lineGetAddressID, "lineGetAddressID", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (ULONG_PTR) &pParams->dwAddressID, (DWORD) pParams->dwAddressMode, (ULONG_PTR) (pDataBuf + pParams->dwAddressOffset), (DWORD) pParams->dwSize ); *pdwNumBytesReturned = sizeof (LINEGETADDRESSID_PARAMS); } else { pParams->lResult = LINEERR_INVALADDRESSMODE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetAddressID" ); } void WINAPI LGetAddressStatus( PTCLIENT ptClient, PLINEGETADDRESSSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetAddressStatus; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwAddressStatusTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETADDRESSSTATUS, // provider func index &pfnTSPI_lineGetAddressStatus, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetAddressStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPLINEADDRESSSTATUS pAddrStatus = (LPLINEADDRESSSTATUS) pDataBuf, pAddrStatus2 = (LPLINEADDRESSSTATUS) NULL; // // Safely retrieve the API & SPI versions // if (GetLineVersions (ptLineClient, &dwAPIVersion, &dwSPIVersion) != 0) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetAddressStatus_epilog; } // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwAddressStatusTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeClient = 64; // 16 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEADDRESSSTATUS); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetAddressStatus_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 64; // 16 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINEADDRESSSTATUS); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pAddrStatus2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetAddressStatus_epilog; } pAddrStatus = pAddrStatus2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pAddrStatus, dwTotalSize, dwFixedSizeSP, (pAddrStatus2 == NULL ? TRUE : FALSE) ); if ((pParams->lResult = CallSP3( pfnTSPI_lineGetAddressStatus, "lineGetAddressStatus", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) pAddrStatus )) == 0) { DWORD dwForwardNumEntries; #if DBG // // Verify the info returned by the provider // #endif // // Add the fields we're responsible for // // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // if ((dwAPIVersion == TAPI_VERSION1_0) && (dwForwardNumEntries = pAddrStatus->dwForwardNumEntries)) { DWORD i; LPLINEFORWARD pLineForward; pLineForward = (LPLINEFORWARD) (((LPBYTE) pAddrStatus) + pAddrStatus->dwForwardOffset); for (i = 0; i < dwForwardNumEntries; i++, pLineForward++) { if (pLineForward->dwForwardMode & (LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL)) { pLineForward->dwForwardMode &= ~(LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL); pLineForward->dwForwardMode |= LINEFORWARDMODE_UNCOND; } } } // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // if (pAddrStatus == pAddrStatus2) { pAddrStatus = (LPLINEADDRESSSTATUS) pDataBuf; CopyMemory (pAddrStatus, pAddrStatus2, dwFixedSizeClient); ServerFree (pAddrStatus2); pAddrStatus->dwTotalSize = pParams->dwAddressStatusTotalSize; pAddrStatus->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->dwAddressStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAddrStatus->dwUsedSize; } } LGetAddressStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetAddressStatus" ); } void LGetAgentXxx_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3; CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = pNewAsyncEventMsg; if (pAsyncEventMsg->Param2 == 0) // success { LPLINEAGENTACTIVITYLIST pActivityList = (LPLINEAGENTACTIVITYLIST) (pNewAsyncEventMsg + 1); pNewAsyncEventMsg->TotalSize += ((pActivityList->dwUsedSize + 7) & 0xFFFFFFF8); // // param 1 must not exceed 32-bits. use DWORD_CAST to insure this in // runtime // pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); pNewAsyncEventMsg->Param4 = DWORD_CAST(pActivityList->dwUsedSize,__FILE__,__LINE__); } } #if DBG void PASCAL LGetAgentXxx( PTCLIENT ptClient, PLINEGETAGENTACTIVITYLIST_PARAMS pParams, DWORD dwParamsBufferSize, DWORD dwRequestType, DWORD dwSPIOrdinal, DWORD dwFixedStructSize, char *pszFuncName ) #else void PASCAL LGetAgentXxx( PTCLIENT ptClient, PLINEGETAGENTACTIVITYLIST_PARAMS pParams, DWORD dwParamsBufferSize, DWORD dwRequestType, DWORD dwSPIOrdinal, DWORD dwFixedStructSize ) #endif { // // Since LGetAgentActivityList, LGetAgentGroupList, and LGetAgentStatus // all do the same thing (& the params are more or less identical) we // can safely condense all the functionality into this one procedure // BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwActivityListTotalSize > 0x40000) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context pszFuncName // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwTotalSize = pParams->dwActivityListTotalSize; PTLINECLIENT pProxy; if (dwTotalSize < dwFixedStructSize) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetAgentXxx_epilog; } if ((lResult = FindProxy( ptLineClient, pParams->dwAddressID, dwRequestType, &pProxy, &dwDeviceID, 0 // API ver wasn't checked in 2.0 ))) { lRequestID = lResult; goto LGetAgentXxx_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpAgentActivityList; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, dwRequestType, 2 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetAgentXxx_epilog; } pProxyRequestWrapper->ProxyRequest.GetAgentActivityList. dwAddressID = pParams->dwAddressID; pProxyRequestWrapper->ProxyRequest.GetAgentActivityList. ActivityList.dwTotalSize = dwTotalSize; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetAgentXxx_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; LPLINEAGENTACTIVITYLIST pActivityList; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LGetAgentXxx_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pActivityList = (LPLINEAGENTACTIVITYLIST) (pBuf + sizeof (ASYNCEVENTMSG)); pActivityList->dwTotalSize = dwTotalSize; pParams->lResult = CallSP4( pRemoteSP->apfn[dwSPIOrdinal], pszFuncName, SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) pActivityList ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetAgentXxx_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, pszFuncName ); } #if DBG void PASCAL LGetAgentWithoutAddressIDXxx( PTCLIENT ptClient, PLINEGETAGENTINFO_PARAMS pParams, DWORD dwParamsBufferSize, DWORD dwRequestType, DWORD dwSPIOrdinal, DWORD dwFixedStructSize, char *pszFuncName ) #else void PASCAL LGetAgentWithoutAddressIDXxx( PTCLIENT ptClient, PLINEGETAGENTINFO_PARAMS pParams, DWORD dwParamsBufferSize, DWORD dwRequestType, DWORD dwSPIOrdinal, DWORD dwFixedStructSize ) #endif { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwAgentInfoTotalSize > 0x40000) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context pszFuncName // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwTotalSize = pParams->dwAgentInfoTotalSize; PTLINECLIENT pProxy; if (dwTotalSize < dwFixedStructSize) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetAgentWithoutAddressIDXxx_epilog; } if ((lResult = FindProxy( ptLineClient, 0, dwRequestType, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LGetAgentWithoutAddressIDXxx_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpAgentInfo; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, dwRequestType, 2 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetAgentWithoutAddressIDXxx_epilog; } pProxyRequestWrapper->ProxyRequest.GetAgentInfo. hAgent = pParams->hAgent; pProxyRequestWrapper->ProxyRequest.GetAgentInfo. AgentInfo.dwTotalSize = dwTotalSize; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetAgentWithoutAddressIDXxx_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; LPLINEAGENTINFO pAgentInfo; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LGetAgentWithoutAddressIDXxx_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pAgentInfo = (LPLINEAGENTINFO) (pBuf + sizeof (ASYNCEVENTMSG)); pAgentInfo->dwTotalSize = dwTotalSize; pParams->lResult = CallSP4( pRemoteSP->apfn[dwSPIOrdinal], pszFuncName, SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->hAgent, (ULONG_PTR) pAgentInfo ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetAgentWithoutAddressIDXxx_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, pszFuncName ); } void WINAPI LGetAgentActivityList( PTCLIENT ptClient, PLINEGETAGENTACTIVITYLIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( ptClient, pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTACTIVITYLIST, SP_LINEGETAGENTACTIVITYLIST, sizeof (LINEAGENTACTIVITYLIST) #if DBG , "GetAgentActivityList" #endif ); } void WINAPI LGetAgentCaps( PTCLIENT ptClient, PLINEGETAGENTCAPS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bProxy = FALSE; LONG lRequestID; DWORD dwDeviceID; HANDLE hMutex; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwAgentCapsTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetAgentCaps" // func name )) > 0) { DWORD dwTotalSize = pParams->dwAgentCapsTotalSize; PTLINE ptLine; PTLINECLIENT pProxy = NULL; DWORD dwFixedSize = 0; switch (pParams->dwAppAPIVersion) { case TAPI_VERSION2_0: case TAPI_VERSION2_1: dwFixedSize = 14 * sizeof(DWORD); break; case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION3_1: dwFixedSize = sizeof(LINEAGENTCAPS); break; default: // // Any other version is too low or invalid // lRequestID = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetAgentCaps_epilog; } if (dwTotalSize < dwFixedSize) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetAgentCaps_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpAgentCaps; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; try { if (!(ptLine = pLookupEntry->ptLine)) { // If ptLine is NULL, the line has not been // open by any app on the local machine; this means // that there's no proxy on the local machine; however, // if the line is a remote one (i.e., exposed by remotesp), // there could be a proxy on another machine. So get out // of this try block and continue to check for remote line // (pProxy is already initialized to NULL). leave; } pProxy = ptLine->apProxys[LINEPROXYREQUEST_GETAGENTCAPS]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LGetAgentCaps_epilog; } if (ptLine->dwKey != TLINE_KEY) { lRequestID = LINEERR_INVALLINEHANDLE; goto LGetAgentCaps_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; goto LGetAgentCaps_epilog; } if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; bProxy = TRUE; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_GETAGENTCAPS, 2 * sizeof(DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetAgentCaps_epilog; } pProxyRequestWrapper->ProxyRequest.GetAgentCaps.dwAddressID = pParams->dwAddressID; pProxyRequestWrapper->ProxyRequest.GetAgentCaps. AgentCaps.dwTotalSize = dwTotalSize; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetAgentCaps_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } else if (pLookupEntry->bRemote) { LPBYTE pBuf; LPLINEAGENTCAPS pCaps; bProxy = TRUE; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LGetAgentCaps_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pCaps = (LPLINEAGENTCAPS) (pBuf + sizeof (ASYNCEVENTMSG)); pCaps->dwTotalSize = dwTotalSize; // Note: RemoteSP comes up with it's own hLineApp pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINEGETAGENTCAPS], "lineGetAgentCaps", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (DWORD) dwDeviceID, (DWORD) pParams->dwAddressID, (DWORD) pParams->dwAppAPIVersion, (ULONG_PTR) pCaps ); } // // There's no registered proxy & line is not remote, so fail // if (!bProxy) { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetAgentCaps_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "GetAgentCaps" ); } void WINAPI LGetAgentGroupList( PTCLIENT ptClient, PLINEGETAGENTGROUPLIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( ptClient, (PLINEGETAGENTACTIVITYLIST_PARAMS) pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTGROUPLIST, SP_LINEGETAGENTGROUPLIST, sizeof (LINEAGENTGROUPLIST) #if DBG , "GetAgentGroupList" #endif ); } void WINAPI LGetAgentInfo( PTCLIENT ptClient, PLINEGETAGENTINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentWithoutAddressIDXxx( ptClient, pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTINFO, SP_LINEGETAGENTINFO, sizeof (LINEAGENTINFO) #if DBG , "GetAgentInfo" #endif ); } void WINAPI LGetAgentSessionInfo( PTCLIENT ptClient, PLINEGETAGENTSESSIONINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentWithoutAddressIDXxx( ptClient, (PLINEGETAGENTINFO_PARAMS) pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTSESSIONINFO, SP_LINEGETAGENTSESSIONINFO, sizeof (LINEAGENTSESSIONINFO) #if DBG , "GetAgentSessionInfo" #endif ); } void WINAPI LGetAgentSessionList( PTCLIENT ptClient, PLINEGETAGENTSESSIONLIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentWithoutAddressIDXxx( ptClient, (PLINEGETAGENTINFO_PARAMS) pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTSESSIONLIST, SP_LINEGETAGENTSESSIONLIST, sizeof (LINEAGENTSESSIONLIST) #if DBG , "GetAgentSessionList" #endif ); } void WINAPI LGetAgentStatus( PTCLIENT ptClient, PLINEGETAGENTSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( ptClient, (PLINEGETAGENTACTIVITYLIST_PARAMS) pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETAGENTSTATUS, SP_LINEGETAGENTSTATUS, sizeof (LINEAGENTSTATUS) #if DBG , "GetAgentStatus" #endif ); } void WINAPI LGetAppPriority( PTCLIENT ptClient, PLINEGETAPPPRIORITY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwMediaMode = pParams->dwMediaMode, dwRequestMode = pParams->dwRequestMode; DWORD dwCount; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwAppNameOffset ) || ((pParams->dwExtensionIDOffset != TAPI_NO_DATA) && ((pParams->dwExtensionIDOffset + sizeof (LINEEXTENSIONID)) > dwParamsBufferSize)) || ((pParams->dwExtensionNameTotalSize != TAPI_NO_DATA) && (pParams->dwExtensionNameTotalSize > dwParamsBufferSize))) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (dwMediaMode == 0) { if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) && (dwRequestMode != LINEREQUESTMODE_MEDIACALL)) { pParams->lResult = LINEERR_INVALREQUESTMODE; goto LGetAppPriority_return; } } else if ( 0xFF000000 & dwMediaMode ) { // ignore } else if ( dwMediaMode & ~AllMediaModes2_1 ) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LGetAppPriority_return; } if ((dwMediaMode & 0x00ffffff) || (dwMediaMode == 0)) { WCHAR szModuleName[MAX_PATH]; WCHAR *pszCurrentPriorityList = NULL; WCHAR *pszLocationInPriorityList; szModuleName[0] = '"'; wcsncpy(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset), MAX_PATH - 2); szModuleName[MAX_PATH - 1] = '\0'; _wcsupr( szModuleName + 1 ); // // Enter the pri list critical section before we start looking // EnterCriticalSection (&gPriorityListCritSec); // // Determine which of the priority lists we want to look at // if (dwMediaMode) { for( dwCount = 0; dwCount < TapiGlobals.dwUsedPriorityLists; dwCount++ ) { if (dwMediaMode == TapiGlobals.pPriLists[dwCount].dwMediaModes) { pszCurrentPriorityList = TapiGlobals.pPriLists[dwCount].pszPriList; break; } } } else { pszCurrentPriorityList = (dwRequestMode == LINEREQUESTMODE_MAKECALL ? TapiGlobals.pszReqMakeCallPriList : TapiGlobals.pszReqMediaCallPriList); } if (pszCurrentPriorityList && (pszLocationInPriorityList = wcsstr( pszCurrentPriorityList, szModuleName ))) { // // App is in pri list, determine it's position // WCHAR *p = pszCurrentPriorityList + 1; // skip first '"' DWORD i; for (i = 1; pszLocationInPriorityList > p; i++) { p = wcschr(p, '"'); p++; } pParams->dwPriority = i; } else { // // App not listed in formal priority list, so just return 0 // // Note: TAPI 1.4 said that if app was in soft pri list // (i.e. had line open with OWNER priv for specified // media mode) then we'd return -1 instead of 0. // But that's a pain to figure out, & we figured no // one was going to use that info anyway, so we settled // for always returning 0. // pParams->dwPriority = 0; } // // Leave list critical section now that we're done // LeaveCriticalSection (&gPriorityListCritSec); *pdwNumBytesReturned = sizeof (LINEGETAPPPRIORITY_PARAMS); } LGetAppPriority_return: LOG((TL_TRACE, "LineEpilogSync (lineGetAppPriority) exit, returning x%x", pParams->lResult )); } void WINAPI LGetCallAddressID( PTCLIENT ptClient, PLINEGETCALLADDRESSID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTCALLCLIENT ptCallClient; if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LGetCallAddressID_exit; } if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient))) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallAddressID_exit; } try { pParams->dwAddressID = ptCallClient->ptCall->dwAddressID; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; } } except (EXCEPTION_EXECUTE_HANDLER) { pParams->lResult = LINEERR_INVALCALLHANDLE; } DereferenceObject (ghHandleTable, pParams->hCall, 1); if (pParams->lResult == 0) { *pdwNumBytesReturned = sizeof (LINEGETCALLADDRESSID_PARAMS); } LGetCallAddressID_exit: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetCallAddressID: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetCallAddressID: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetCallHubTracking( PTCLIENT ptClient, PLINEGETCALLHUBTRACKING_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetCallHubTracking; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwTrackingInfoTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETCALLHUBTRACKING, // provider func index &pfnTSPI_lineGetCallHubTracking,// provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetCallHubTracking" // func name )) == 0 || (pParams->lResult == LINEERR_OPERATIONUNAVAIL)) { LPLINECALLHUBTRACKINGINFO pTrackingInfo = (LPLINECALLHUBTRACKINGINFO) pDataBuf; if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { pParams->lResult = 0; pfnTSPI_lineGetCallHubTracking = (TSPIPROC) NULL; } if (pParams->dwTrackingInfoTotalSize < sizeof (LINECALLHUBTRACKINGINFO)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetCallHubTracking_epilog; } InitTapiStruct( pTrackingInfo, pParams->dwTrackingInfoTotalSize, sizeof (LINECALLHUBTRACKINGINFO), TRUE ); if (!pfnTSPI_lineGetCallHubTracking || (pParams->lResult = CallSP2( pfnTSPI_lineGetCallHubTracking, "lineGetCallHubTracking", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (ULONG_PTR) pTrackingInfo )) == 0) { try { pTrackingInfo->dwCurrentTracking = ptLineClient->dwCurrentTracking; } except (EXCEPTION_EXECUTE_HANDLER) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetCallHubTracking_epilog; } pTrackingInfo->dwAvailableTracking |= LINECALLHUBTRACKING_ALLCALLS; pParams->dwTrackingInfoOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pTrackingInfo->dwUsedSize; } } LGetCallHubTracking_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetCallHubTracking" ); } void WINAPI LGetCallIDs( PTCLIENT ptClient, PLINEGETCALLIDS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTCALLCLIENT ptCallClient; if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LGetCallIDs_exit; } if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient))) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallIDs_exit; } try { pParams->dwAddressID = ptCallClient->ptCall->dwAddressID; pParams->dwCallID = ptCallClient->ptCall->dwCallID; pParams->dwRelatedCallID = ptCallClient->ptCall->dwRelatedCallID; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; } } except (EXCEPTION_EXECUTE_HANDLER) { pParams->lResult = LINEERR_INVALCALLHANDLE; } DereferenceObject (ghHandleTable, pParams->hCall, 1); if (pParams->lResult == 0) { *pdwNumBytesReturned = sizeof (LINEGETCALLIDS_PARAMS); } LGetCallIDs_exit: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetCallIDs: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetCallIDs: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetCallInfo( PTCLIENT ptClient, PLINEGETCALLINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGetCallInfo; DWORD objectToDereference; PTCALLCLIENT ptCallClient; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCallInfoTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETCALLINFO, // provider func index &pfnTSPI_lineGetCallInfo, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "GetCallInfo" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; PTCALL ptCall; LPLINECALLINFO pCallInfo = (LPLINECALLINFO) pDataBuf, pCallInfo2 = (LPLINECALLINFO) NULL; // // Safely retrieve the API & SPI versions, etc // try { ptCall = ptCallClient->ptCall; dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion; dwSPIVersion = ((PTLINE) ptCallClient->ptLineClient->ptLine) ->dwSPIVersion; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallInfo_epilog; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallInfo_epilog; } // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwCallInfoTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeClient = 296; // 69 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeClient = 324; // 76 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINECALLINFO); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetCallInfo_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 296; // 69 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeSP = 324; // 76 * sizeof(DWORD) + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLINFO); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pCallInfo2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetCallInfo_epilog; } pCallInfo = pCallInfo2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pCallInfo, dwTotalSize, dwFixedSizeSP, (pCallInfo2 == NULL ? TRUE : FALSE) ); if ((pParams->lResult = CallSP2( pfnTSPI_lineGetCallInfo, "lineGetCallInfo", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (ULONG_PTR) pCallInfo )) == 0) { // // Safely add the fields we're responsible for // try { pCallInfo->hLine = (HLINE) ptCallClient->ptLineClient->hLine; pCallInfo->dwMonitorDigitModes = ptCallClient->dwMonitorDigitModes; pCallInfo->dwMonitorMediaModes = ptCallClient->dwMonitorMediaModes; pCallInfo->dwNumOwners = ptCall->dwNumOwners; pCallInfo->dwNumMonitors = ptCall->dwNumMonitors; InsertVarData( pCallInfo, &pCallInfo->dwAppNameSize, ptCall->pszAppName, ptCall->dwAppNameSize ); InsertVarData( pCallInfo, &pCallInfo->dwDisplayableAddressSize, ptCall->pszDisplayableAddress, ptCall->dwDisplayableAddressSize ); InsertVarData( pCallInfo, &pCallInfo->dwCalledPartySize, ptCall->pszCalledParty, ptCall->dwCalledPartySize ); InsertVarData( pCallInfo, &pCallInfo->dwCommentSize, ptCall->pszComment, ptCall->dwCommentSize ); if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; } pCallInfo->dwCallStates |= LINECALLSTATE_UNKNOWN; #if TELE_SERVER // if it's a server, map the device id if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { DWORD dwCount; // if we fall out of this for loop, the id just // doesn't get updated for( dwCount = 0; dwCount < ptClient->dwLineDevices; dwCount++ ) { if (ptClient->pLineDevices[dwCount] == pCallInfo->dwLineDeviceID) { pCallInfo->dwLineDeviceID = dwCount; break; } } } #endif // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // if (dwAPIVersion == TAPI_VERSION1_0) { if (pCallInfo->dwOrigin & LINECALLORIGIN_INBOUND) { pCallInfo->dwOrigin = LINECALLORIGIN_UNAVAIL; } if ((pCallInfo->dwReason & (LINECALLREASON_INTRUDE | LINECALLREASON_PARKED))) { pCallInfo->dwReason = LINECALLREASON_UNAVAIL; } } // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // if (pCallInfo == pCallInfo2) { pCallInfo = (LPLINECALLINFO) pDataBuf; CopyMemory (pCallInfo, pCallInfo2, dwFixedSizeClient); ServerFree (pCallInfo2); pCallInfo->dwTotalSize = pParams->dwCallInfoTotalSize; pCallInfo->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // if (pParams->lResult == 0) { pParams->dwCallInfoOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallInfo->dwUsedSize; } } } LGetCallInfo_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetCallInfo" ); } void WINAPI LGetCallStatus( PTCLIENT ptClient, PLINEGETCALLSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGetCallStatus; DWORD objectToDereference; PTCALLCLIENT ptCallClient; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCallStatusTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETCALLSTATUS, // provider func index &pfnTSPI_lineGetCallStatus, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "GetCallStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP, dwPrivilege; LPLINECALLSTATUS pCallStatus = (LPLINECALLSTATUS) pDataBuf, pCallStatus2 = (LPLINECALLSTATUS) NULL; // // Safely retrieve the API & SPI versions // try { dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion; dwSPIVersion = ((PTLINE) ptCallClient->ptLineClient->ptLine) ->dwSPIVersion; dwPrivilege = ptCallClient->dwPrivilege; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallStatus_epilog; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetCallStatus_epilog; } // // Determine the fixed siize of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwCallStatusTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeClient = 36; // 9 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINECALLSTATUS); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetCallStatus_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 36; // 9 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLSTATUS); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pCallStatus2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetCallStatus_epilog; } pCallStatus = pCallStatus2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pCallStatus, dwTotalSize, dwFixedSizeSP, (pCallStatus2 == NULL ? TRUE : FALSE) ); if ((pParams->lResult = CallSP2( pfnTSPI_lineGetCallStatus, "lineGetCallStatus", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (ULONG_PTR) pCallStatus )) == 0) { #if DBG // // Verify the info returned by the provider // #endif // // Add the fields we're responsible for // pCallStatus->dwCallPrivilege = dwPrivilege; if (dwSPIVersion < TAPI_VERSION2_0 && dwAPIVersion >= TAPI_VERSION2_0) { GetSystemTime (&pCallStatus->tStateEntryTime); } // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // if (pCallStatus == pCallStatus2) { pCallStatus = (LPLINECALLSTATUS) pDataBuf; CopyMemory (pCallStatus, pCallStatus2, dwFixedSizeClient); ServerFree (pCallStatus2); pCallStatus->dwTotalSize = pParams->dwCallStatusTotalSize; pCallStatus->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->dwCallStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallStatus->dwUsedSize; } } LGetCallStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetCallStatus" ); } void WINAPI LGetConfRelatedCalls( PTCLIENT ptClient, PLINEGETCONFRELATEDCALLS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwTotalSize = pParams->dwCallListTotalSize; PTCALLCLIENT ptCallClient; PTLINECLIENT ptLineClient; LPLINECALLLIST pCallList = (LPLINECALLLIST) pDataBuf; TPOINTERLIST confCallList, *pConfCallList = &confCallList; PTCONFERENCELIST pConfList; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCallListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; return; } if (dwTotalSize < sizeof (LINECALLLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; return; } if (!(ptCallClient = ReferenceCall (pParams->hCall, ptClient))) { pParams->lResult = LINEERR_INVALCALLHANDLE; return; } try { ptLineClient = ptCallClient->ptLineClient; if (!(pConfList = ptCallClient->ptCall->pConfList) || (pConfList == (PTCONFERENCELIST) LongToPtr(0xffffffff))) { pParams->lResult = LINEERR_NOCONFERENCE; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; } DereferenceObject (ghHandleTable, pParams->hCall, 1); if (pParams->lResult != 0) { return; } if ((pParams->lResult = GetConfCallListFromConf( pConfList, &pConfCallList )) != 0) { return; } { DWORD dwNeededSize = sizeof (LINECALLLIST) + pConfCallList->dwNumUsedEntries * sizeof (HCALL); if (dwTotalSize < dwNeededSize) { pCallList->dwNeededSize = dwNeededSize; pCallList->dwUsedSize = sizeof (LINECALLLIST); FillMemory (&pCallList->dwCallsNumEntries, 3 * sizeof (DWORD), 0); goto LGetConfRelatedCalls_fillInList; } } // // For each call in the conf list see if the app has a // call client (if not create one w/ monitor privileges) // and add it to the list // { DWORD dwNumCallsInList = 0, i; LPHCALL lphCallsInList = (LPHCALL) (pCallList + 1); for (i = 0; i < pConfCallList->dwNumUsedEntries; i++) { PTCALL ptCall = pConfCallList->aEntries[i]; if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { ptCallClient = ptCall->ptCallClients; while (ptCallClient && (ptCallClient->ptLineClient != ptLineClient)) { ptCallClient = ptCallClient->pNextSametCall; } if (!ptCallClient) { LONG lResult; if ((lResult = CreatetCallClient( ptCall, ptLineClient, LINECALLPRIVILEGE_MONITOR, TRUE, TRUE, &ptCallClient, FALSE ))) { // Skip... UNLOCKTCALL(ptCall); continue; } } *(lphCallsInList++) = ptCallClient->hCall; dwNumCallsInList++; UNLOCKTCALL(ptCall); } } pCallList->dwUsedSize = pCallList->dwNeededSize = sizeof (LINECALLLIST) + dwNumCallsInList * sizeof (HCALL); pCallList->dwCallsNumEntries = dwNumCallsInList; pCallList->dwCallsSize = dwNumCallsInList * sizeof (HCALL); pCallList->dwCallsOffset = sizeof (LINECALLLIST); } LGetConfRelatedCalls_fillInList: if (pConfCallList != &confCallList) { ServerFree (pConfCallList); } pCallList->dwTotalSize = dwTotalSize; pParams->dwCallListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallList->dwUsedSize; #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetConfRelatedCalls: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetConfRelatedCalls: exit, result=x%x", pParams->lResult )); #endif } void WINAPI LGetCountry( PTCLIENT ptClient, PLINEGETCOUNTRY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LPLINECOUNTRYLIST pCountryList = (LPLINECOUNTRYLIST) pDataBuf; LPLINECOUNTRYLIST pCountries = NULL; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCountryListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (pParams->dwCountryListTotalSize < sizeof (LINECOUNTRYLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; } else { BuildCountryListCache(); if (pParams->dwCountryID == 0) { // // Client wants entire country list // if (RPC_S_OK != RpcImpersonateClient(0)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } pCountries = BuildCountryList(); RpcRevertToSelf(); if (NULL == pCountries) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (pParams->dwCountryListTotalSize >= pCountries->dwNeededSize) { CopyMemory( pCountryList, pCountries, pCountries->dwUsedSize ); } else { pCountryList->dwNeededSize = pCountries->dwNeededSize; pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST); pCountryList->dwNumCountries = 0; pCountryList->dwCountryListSize = 0; pCountryList->dwCountryListOffset = 0; } *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCountryList->dwUsedSize; pCountryList->dwTotalSize = pParams->dwCountryListTotalSize; ServerFree(pCountries); } else { // // Caller wants single country // LPLINECOUNTRYLIST pBuildCountryList; if ( NULL == ( pBuildCountryList = ServerAlloc( sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY) + ((MAXLEN_NAME + MAXLEN_RULE + MAXLEN_RULE + MAXLEN_RULE + 100) * sizeof(WCHAR)) ) ) ) { LOG((TL_ERROR, "Alloc failed for countrylist")); pParams->lResult = LINEERR_NOMEM; } else { LPLINECOUNTRYENTRY pCountryEntrySource; LPLINECOUNTRYENTRY pCountryEntryDest; pCountryEntryDest = (LPLINECOUNTRYENTRY)((PBYTE)pBuildCountryList + sizeof(LINECOUNTRYLIST)); // // search through the gpCountryList looking for the entry // pCountryEntrySource = (LPLINECOUNTRYENTRY)((PBYTE)gpCountryList + sizeof(LINECOUNTRYLIST)); while ( (pCountryEntrySource->dwCountryID != pParams->dwCountryID ) && (pCountryEntrySource->dwNextCountryID) ) { pCountryEntrySource++; } if ( pCountryEntrySource->dwCountryID != pParams->dwCountryID ) { LOG((TL_ERROR, "Invalid Countrycode (%ld) in lineGetCountry", pParams->dwCountryID)); pParams->lResult = LINEERR_INVALCOUNTRYCODE; } else { PBYTE pCountryListToUse; PBYTE pVarOffset; PBYTE pOverrideList = NULL; DWORD dwNeededSize; DWORD dwResourceId; DWORD dwNameSize; WCHAR sz[MAXLEN_NAME]; // // Is the caller calling a specific country that there might be // an override for? // if ( pParams->dwDestCountryID != 0 ) { HKEY hKey; HKEY hKey2; TCHAR p[256]; wsprintf( p, TEXT("Country List\\%ld\\Exceptions\\%ld"), pParams->dwCountryID, pParams->dwDestCountryID ); // // Is there an exception? // if (0 == RegOpenKeyEx (HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey2) && 0 == RegOpenKeyEx (hKey2, p, 0, KEY_READ, &hKey)) { PBYTE pVarOffset; pOverrideList = ServerAlloc( sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY) + ((MAXLEN_NAME + MAXLEN_RULE + MAXLEN_RULE + MAXLEN_RULE + 100) * sizeof(WCHAR)) ); if (!pOverrideList) { ServerFree (pBuildCountryList); RegCloseKey (hKey2); RegCloseKey (hKey); pParams->lResult = LINEERR_NOMEM; return; } pCountryListToUse = pOverrideList; pCountryEntrySource = (LPLINECOUNTRYENTRY) (pOverrideList + sizeof(LINECOUNTRYLIST)); pVarOffset = pOverrideList + sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY); FillupACountryEntry( hKey, pCountryListToUse, pCountryEntrySource, &pVarOffset ); RegCloseKey( hKey ); } else { // // No, we tried, but there was no exception. // pCountryListToUse = (PBYTE)gpCountryList; } RegCloseKey( hKey2); } else { pCountryListToUse = (PBYTE)gpCountryList; } // // Fill in the buffer // dwNeededSize = sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY); pVarOffset = (LPBYTE)pCountryEntryDest + sizeof(LINECOUNTRYENTRY); // // The name field has the resource string ID // Need to load the actual string based on current user's language // CopyMemory( &dwResourceId, pCountryListToUse + pCountryEntrySource->dwCountryNameOffset, sizeof(DWORD) ); if (RPC_S_OK != RpcImpersonateClient(0)) { ServerFree (pBuildCountryList); pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (0 == LoadStringW( ghInstance, dwResourceId, sz, ARRAYSIZE(sz) ) ) { RpcRevertToSelf(); ServerFree (pBuildCountryList); pParams->lResult = LINEERR_OPERATIONFAILED; return; } RpcRevertToSelf(); dwNameSize = (wcslen(sz) + 1) * sizeof(WCHAR); CopyMemory( pVarOffset, (LPBYTE)sz, dwNameSize ); pCountryEntryDest->dwCountryNameSize = dwNameSize; pCountryEntryDest->dwCountryNameOffset = (DWORD) (pVarOffset - (LPBYTE) pBuildCountryList); pVarOffset += dwNameSize; dwNeededSize += dwNameSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwSameAreaRuleOffset, pCountryEntrySource->dwSameAreaRuleSize ); pCountryEntryDest->dwSameAreaRuleSize = pCountryEntrySource->dwSameAreaRuleSize; pCountryEntryDest->dwSameAreaRuleOffset = (DWORD) (pVarOffset - (LPBYTE) pBuildCountryList); pVarOffset += pCountryEntrySource->dwSameAreaRuleSize; dwNeededSize += pCountryEntrySource->dwSameAreaRuleSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwLongDistanceRuleOffset, pCountryEntrySource->dwLongDistanceRuleSize ); pCountryEntryDest->dwLongDistanceRuleSize = pCountryEntrySource->dwLongDistanceRuleSize; pCountryEntryDest->dwLongDistanceRuleOffset = (DWORD) (pVarOffset - (LPBYTE) pBuildCountryList); pVarOffset += pCountryEntrySource->dwLongDistanceRuleSize; dwNeededSize += pCountryEntrySource->dwLongDistanceRuleSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwInternationalRuleOffset, pCountryEntrySource->dwInternationalRuleSize ); pCountryEntryDest->dwInternationalRuleSize = pCountryEntrySource->dwInternationalRuleSize; pCountryEntryDest->dwInternationalRuleOffset = (DWORD) (pVarOffset - (LPBYTE) pBuildCountryList); pVarOffset += pCountryEntrySource->dwInternationalRuleSize; dwNeededSize += pCountryEntrySource->dwInternationalRuleSize; // // Is there room to put this country's info? // if (pParams->dwCountryListTotalSize >= dwNeededSize) { pCountryList->dwUsedSize = dwNeededSize; pCountryList->dwNumCountries = 1; pCountryList->dwCountryListSize = sizeof(LINECOUNTRYENTRY); pCountryList->dwCountryListOffset = sizeof(LINECOUNTRYLIST); pCountryEntryDest->dwCountryID = pParams->dwCountryID; pCountryEntryDest->dwCountryCode = pCountryEntrySource->dwCountryCode; pCountryEntryDest->dwNextCountryID = pCountryEntrySource->dwNextCountryID; CopyMemory( (LPBYTE)pCountryList + sizeof(LINECOUNTRYLIST), (LPBYTE)pBuildCountryList + sizeof(LINECOUNTRYLIST), pCountryList->dwUsedSize - sizeof(LINECOUNTRYLIST) ); } else { // // Buffer not large enough // pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST); pCountryList->dwNumCountries = 0; pCountryList->dwCountryListSize = 0; pCountryList->dwCountryListOffset = 0; } pCountryList->dwNeededSize = dwNeededSize; pCountryList->dwTotalSize = pParams->dwCountryListTotalSize; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCountryList->dwUsedSize; // // Did we have a "special" case? // if ( pOverrideList ) { ServerFree( pOverrideList ); } } ServerFree( pBuildCountryList ); } } } pParams->dwCountryListOffset = 0; #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetCountry: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetCountry: exit, result=x%x", pParams->lResult )); #endif } void WINAPI LGetCountryGroups( PTCLIENT ptClient, PLINEGETCOUNTRYGROUP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwCount, dwIdx, dwIdx1; BOOL bFoundAll = TRUE; DWORD * pCountryGroups = NULL; DWORD * pCountryID; LPLINECOUNTRYENTRY pCountryEntry; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCountryIdSize > dwParamsBufferSize || 0 == pParams->dwCountryIdSize || pParams->dwCountryIdSize > pParams->dwCountryGroupSize ) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } dwCount = pParams->dwCountryIdSize / sizeof(DWORD); BuildCountryListCache(); if (NULL == gpCountryGroups) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } ASSERT( NULL != gpCountryList ); pCountryGroups = ServerAlloc (pParams->dwCountryIdSize); if (NULL == pCountryGroups) { pParams->lResult = LINEERR_NOMEM; return; } pCountryID = (DWORD*)(pDataBuf + pParams->dwCountryIdOffset); for( dwIdx = 0; dwIdx < dwCount; dwIdx++, pCountryID++ ) { // find the country pCountryEntry = (LPLINECOUNTRYENTRY) ((LPBYTE) gpCountryList + gpCountryList->dwCountryListOffset); for( dwIdx1 = 0; dwIdx1 < gpCountryList->dwNumCountries; dwIdx1++, pCountryEntry++ ) { if (pCountryEntry->dwCountryID == *pCountryID) { pCountryGroups[ dwIdx ] = gpCountryGroups[ dwIdx1 ]; break; } } if (dwIdx1 == gpCountryList->dwNumCountries) { LOG((TL_ERROR, "Invalid CountryID (%ld) in lineGetCountryGroup", pCountryEntry->dwCountryID)); bFoundAll = FALSE; break; } } if (bFoundAll) { pParams->dwCountryGroupOffset = pParams->dwCountryIdOffset; pParams->dwCountryGroupSize = pParams->dwCountryIdSize; memset( pDataBuf + pParams->dwCountryGroupOffset, 0, pParams->dwCountryGroupSize ); CopyMemory( pDataBuf + pParams->dwCountryGroupOffset, pCountryGroups, pParams->dwCountryIdSize ); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwCountryGroupOffset + pParams->dwCountryGroupSize; } else { pParams->lResult = LINEERR_OPERATIONFAILED; } ServerFree (pCountryGroups); #if DBG { char szResult[32]; LOG((TL_TRACE, "LGetCountryGroups: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "LGetCountryGroups: exit, result=x%x", pParams->lResult )); #endif } void WINAPI LGetDevCaps( PTCLIENT ptClient, PLINEGETDEVCAPS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetDevCaps; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwDevCapsTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETDEVCAPS, // provider func index &pfnTSPI_lineGetDevCaps, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetDevCaps" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; LPLINEDEVCAPS pDevCaps = (LPLINEDEVCAPS) pDataBuf, pDevCaps2 = (LPLINEDEVCAPS) NULL; // // Verify API & SPI version compatibility // dwAPIVersion = pParams->dwAPIVersion; dwSPIVersion = pLookupEntry->dwSPIVersion; if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion)) { pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetDevCaps_epilog; } // // Verify Ext version compatibility // if (!IsValidLineExtVersion (dwDeviceID, pParams->dwExtVersion)) { pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION; goto LGetDevCaps_epilog; } // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwDevCapsTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwFixedSizeClient = 236; // 47 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION1_4: dwFixedSizeClient = 240; // 48 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: dwFixedSizeClient = 252; // 51 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_2: dwFixedSizeClient = 268; // 51 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) + // sizeof (GUID) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEDEVCAPS); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetDevCaps_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: dwFixedSizeSP = 236; // 47 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION1_4: dwFixedSizeSP = 240; // 48 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: dwFixedSizeSP = 252; // 51 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_2: dwFixedSizeSP = 268; // 51 * sizeof (DWORD) + // 3 * sizeof (LINEDIALPARAMS) + // sizeof (GUID) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINEDEVCAPS); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pDevCaps2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetDevCaps_epilog; } pDevCaps = pDevCaps2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pDevCaps, dwTotalSize, dwFixedSizeSP, (pDevCaps2 == NULL ? TRUE : FALSE) ); if (pLookupEntry->bRemoved) { ServerFree (pDevCaps2); pParams->lResult = LINEERR_NODEVICE; } else if ((pParams->lResult = CallSP4( pfnTSPI_lineGetDevCaps, "lineGetDevCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtVersion, (ULONG_PTR) pDevCaps )) == 0) { #if DBG // // Verify the info returned by the provider // #endif // // Add the fields we're responsible for // pDevCaps->dwLineStates |= LINEDEVSTATE_OPEN | LINEDEVSTATE_CLOSE | LINEDEVSTATE_REINIT | LINEDEVSTATE_TRANSLATECHANGE; if (dwAPIVersion >= TAPI_VERSION3_0) { pDevCaps->dwAvailableTracking |= LINECALLHUBTRACKING_ALLCALLS; } // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // if ((dwAPIVersion == TAPI_VERSION1_0) && (pDevCaps->dwMediaModes & LINEMEDIAMODE_VOICEVIEW)) { pDevCaps->dwMediaModes = LINEMEDIAMODE_UNKNOWN | (pDevCaps->dwMediaModes & ~LINEMEDIAMODE_VOICEVIEW); } if ((dwAPIVersion < TAPI_VERSION2_1) && (pDevCaps->dwMediaModes & LINEMEDIAMODE_VIDEO)) { pDevCaps->dwMediaModes = LINEMEDIAMODE_UNKNOWN | (pDevCaps->dwMediaModes & ~LINEMEDIAMODE_VIDEO); } // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // if (pDevCaps == pDevCaps2) { pDevCaps = (LPLINEDEVCAPS) pDataBuf; CopyMemory (pDevCaps, pDevCaps2, dwFixedSizeClient); ServerFree (pDevCaps2); pDevCaps->dwTotalSize = pParams->dwDevCapsTotalSize; pDevCaps->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->dwDevCapsOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDevCaps->dwUsedSize; } else { ServerFree (pDevCaps2); } } LGetDevCaps_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetDevCaps" ); } void WINAPI LGetDevConfig( PTCLIENT ptClient, PLINEGETDEVCONFIG_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetDevConfig; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwDeviceConfigTotalSize > dwParamsBufferSize) || IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETDEVCONFIG, // provider func index &pfnTSPI_lineGetDevConfig, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetDevConfig" // func name )) == 0) { WCHAR *pszDeviceClass; LPVARSTRING pConfig = (LPVARSTRING) pDataBuf; // // Alloc a temporary buf for the dev class, since we'll be using // the existing buffer for output // if (!(pszDeviceClass = (WCHAR *) ServerAlloc( sizeof(WCHAR) * ( 1 + lstrlenW((PWSTR)(pDataBuf + pParams->dwDeviceClassOffset))) ))) { pParams->lResult = LINEERR_NOMEM; goto LGetDevConfig_epilog; } wcscpy( pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset) ); if (!InitTapiStruct( pConfig, pParams->dwDeviceConfigTotalSize, sizeof (VARSTRING), TRUE )) { ServerFree (pszDeviceClass); pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetDevConfig_epilog; } if (pLookupEntry->bRemoved) { ServerFree (pszDeviceClass); pParams->lResult = LINEERR_NODEVICE; goto LGetDevConfig_epilog; } if ((pParams->lResult = CallSP3( pfnTSPI_lineGetDevConfig, "lineGetDevConfig", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) pConfig, (ULONG_PTR) pszDeviceClass )) == 0) { // // Indicate how many bytes of data we're passing back // pParams->dwDeviceConfigOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pConfig->dwUsedSize; } ServerFree (pszDeviceClass); } LGetDevConfig_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetDevConfig" ); } void WINAPI LGetGroupList( PTCLIENT ptClient, PLINEGETGROUPLIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { // // note: can't use lgetagentxxx because // pparams don't match // BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetGroupList" // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwTotalSize =pParams->dwGroupListTotalSize; PTLINECLIENT pProxy; if (dwTotalSize < sizeof(LINEAGENTGROUPLIST)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetGroupList_epilog; } if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_GETGROUPLIST, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LGetGroupList_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpGroupList; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_GETGROUPLIST, dwTotalSize, pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetGroupList_epilog; } pProxyRequestWrapper->ProxyRequest.GetGroupList. GroupList.dwTotalSize = dwTotalSize; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetGroupList_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; LPLINEAGENTGROUPLIST pGroupList; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LGetGroupList_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pGroupList = (LPLINEAGENTGROUPLIST) (pBuf + sizeof (ASYNCEVENTMSG)); pGroupList->dwTotalSize = dwTotalSize; pParams->lResult = CallSP3( pRemoteSP->apfn[SP_LINEGETGROUPLIST], "GetGroupList", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (ULONG_PTR) pGroupList ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetGroupList_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "GetGroupList" ); } void WINAPI LGetHubRelatedCalls( PTCLIENT ptClient, PLINEGETHUBRELATEDCALLS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwTotalSize = pParams->dwCallListTotalSize, dwNeededSize, dwUsedSize, dwCallHubID, i, j; PTCALL ptCall; PTLINEAPP ptLineApp; PTPROVIDER ptProvider; TPOINTERLIST fastCallList = {0}, *pCallList = &fastCallList; PTCALLCLIENT ptCallClient; PTCALLHUBCLIENT ptCallHubClient; PTHASHTABLEENTRY pEntry; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCallListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } // // State/param validation // if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LGetHubRelatedCalls_exit; } if (dwTotalSize < sizeof (LINECALLLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetHubRelatedCalls_exit; } // // Determine the associated tProvider, call hub id, & tLineApp // (assume failure, resetting lResult to 0 only when we're sure // we're ok) // pParams->lResult = LINEERR_INVALCALLHANDLE; if (pParams->hCallHub) { if (!pParams->hCall && (ptCallHubClient = IsValidCallHub( pParams->hCallHub, ptClient ))) { try { ptProvider = ptCallHubClient->ptProvider; dwCallHubID = ptCallHubClient->dwCallHubID; ptLineApp = ptCallHubClient->ptLineApp; if (ptCallHubClient->dwKey == TCALLHUBCLIENT_KEY) { pParams->lResult = 0; } } except (EXCEPTION_EXECUTE_HANDLER) { // do nothing, error handled below } } } else { if ((ptCallClient = ReferenceCall( pParams->hCall, ptClient ))) { try { if ((dwCallHubID = ptCallClient->ptCall->dwCallID)) { ptProvider = ptCallClient->ptCall->ptProvider; ptLineApp = ptCallClient->ptLineClient->ptLineApp; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { pParams->lResult = 0; ptCallHubClient = NULL; } } } except (EXCEPTION_EXECUTE_HANDLER) { // do nothing, error handled below } DereferenceObject (ghHandleTable, pParams->hCall, 1); } } if (pParams->lResult != 0) { goto LGetHubRelatedCalls_exit; } // // Get the list of tCall's for this tProvider/CallHubID. Also, if // the tCallHubClient is not already known then try to find it. // pEntry = AcquireHashTableEntryLock (ptProvider, dwCallHubID); if (!pEntry) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetHubRelatedCalls_exit; } if (pEntry->dwCallHubID != dwCallHubID) { ReleaseHashTableEntryLock (ptProvider, pEntry); pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetHubRelatedCalls_exit; } if (!ptCallHubClient) { ptCallHubClient = pEntry->ptCallHubClients; while (ptCallHubClient && ptCallHubClient->ptLineApp != ptLineApp) { ptCallHubClient = ptCallHubClient->pNext; } // // If there's no tCallHubClient then there's no call hub as far // as this app is concerned // if (!ptCallHubClient) { ReleaseHashTableEntryLock (ptProvider, pEntry); pParams->lResult = LINEERR_INVALCALLHANDLE; goto LGetHubRelatedCalls_exit; } } GetList (&pEntry->CallHubList, &pCallList); ReleaseHashTableEntryLock (ptProvider, pEntry); // // Insert the hCallHub at the front of the call list // dwNeededSize = sizeof (LINECALLLIST) + sizeof (HCALLHUB); if (dwNeededSize <= dwTotalSize) { *((LPHCALLHUB)(pDataBuf + sizeof (LINECALLLIST))) = ptCallHubClient->hCallHub; dwUsedSize = dwNeededSize; } else { dwUsedSize = sizeof (LINECALLLIST); } // // For each of the tCall in the list get the list of tCallClients, // then for each tCallClient see if it's on the same tLineApp // as the specified call/hub, & if so add it to the list // for (i = 0; i < pCallList->dwNumUsedEntries; i++) { TPOINTERLIST fastCallClientList, *pCallClientList = &fastCallClientList; ptCall = CONTAINING_RECORD( pCallList->aEntries[i], TCALL, CallHubList ); if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0) { continue; } for (j = 0; j < pCallClientList->dwNumUsedEntries; j++) { PTCALLCLIENT ptCallClient = pCallClientList->aEntries[j]; try { if ((ptCallClient->ptLineClient->ptLineApp == ptLineApp) && (ptCallClient->dwKey == TCALLCLIENT_KEY)) { if (!ptCallClient->ptCallHubClient) { ptCallClient->ptCallHubClient = ptCallHubClient; } if ((dwUsedSize + sizeof(HCALL)) <= dwTotalSize) { *((LPHCALL)(pDataBuf + dwUsedSize)) = ptCallClient->hCall; dwUsedSize += sizeof(HCALL); } dwNeededSize += sizeof(HCALL); } } except (EXCEPTION_EXECUTE_HANDLER) { // do nothing, this call not included in list } } if (pCallClientList != &fastCallClientList) { ServerFree (pCallClientList); } } if (pCallList != &fastCallList) { ServerFree (pCallList); } ((LPLINECALLLIST) pDataBuf)->dwTotalSize = dwTotalSize; ((LPLINECALLLIST) pDataBuf)->dwNeededSize = dwNeededSize; ((LPLINECALLLIST) pDataBuf)->dwUsedSize = dwUsedSize; ((LPLINECALLLIST) pDataBuf)->dwCallsSize = dwUsedSize - sizeof (LINECALLLIST); ((LPLINECALLLIST) pDataBuf)->dwCallsNumEntries = ((LPLINECALLLIST) pDataBuf)->dwCallsSize / sizeof (HCALL); ((LPLINECALLLIST) pDataBuf)->dwCallsOffset = sizeof (LINECALLLIST); pParams->dwCallListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + ((LPLINECALLLIST) pDataBuf)->dwUsedSize; LGetHubRelatedCalls_exit: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetHubRelatedCalls: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetHubRelatedCalls: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetIcon( PTCLIENT ptClient, PLINEGETICON_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { // // Note: Icons are Windows NT User Objects, so. HICONs are public to // all processes, and do not need to be dup'd. // BOOL bCloseMutex; WCHAR *pszDeviceClass; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetIcon; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwDeviceClassOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDeviceClassOffset); if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETICON, // provider func index &pfnTSPI_lineGetIcon, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetIcon" // func name )) == 0) { if ((pParams->lResult = CallSP3( pfnTSPI_lineGetIcon, "lineGetIcon", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) pszDeviceClass, (ULONG_PTR) &pParams->hIcon )) == 0) { *pdwNumBytesReturned = sizeof (LINEGETICON_PARAMS); } } else if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { if ((pszDeviceClass == NULL) || (_wcsicmp(pszDeviceClass, L"tapi/line") == 0)) { pParams->hIcon = TapiGlobals.hLineIcon; pParams->lResult = 0; *pdwNumBytesReturned = sizeof (LINEGETICON_PARAMS); } else { pParams->lResult = LINEERR_INVALDEVICECLASS; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetIcon" ); } void WINAPI LGetIDEx( PTCLIENT ptClient, PLINEGETID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LPBYTE pDeviceClass = pDataBuf + pParams->dwDeviceClassOffset; LPWSTR pDeviceClassCopy = NULL; LPWSTR szStringId1 = NULL; LPWSTR szStringId2 = NULL; LPVARSTRING pID = (LPVARSTRING) pDataBuf; DWORD dwAvailSize; // // Make a copy of the device class // pDeviceClassCopy = (LPWSTR) ServerAlloc( (1 + wcslen( (LPWSTR)pDeviceClass )) * sizeof(WCHAR)); if (!pDeviceClassCopy) { LOG((TL_ERROR, "LGetIDEx: failed to allocate DeviceClassCopy")); pParams->lResult = LINEERR_NOMEM; } wcscpy(pDeviceClassCopy, (LPWSTR)pDeviceClass); // // First call LGetID // LGetID( ptClient, pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned); // // if LGetID was successful and the request was for a wave device, // translate the device ID into a string ID // if ( (pParams->lResult == 0) && !(pID->dwNeededSize > pID->dwTotalSize) ) { if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/out") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/in") || !_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/out") ) { szStringId1 = WaveDeviceIdToStringId ( *(DWORD*)((LPBYTE)pID + pID->dwStringOffset), (LPWSTR)pDeviceClassCopy); if ( szStringId1 ) { dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + sizeof(DWORD); if ( dwAvailSize >= (wcslen(szStringId1) + 1) * sizeof(WCHAR) ) { wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 ); pID->dwStringSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR); pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - sizeof(DWORD); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } else { pID->dwNeededSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR); } ServerFree(szStringId1); } else { LOG((TL_ERROR, "LGetIDEx: WaveDeviceIdToStringId failed")); pParams->lResult = LINEERR_OPERATIONFAILED; } } else if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in/out")) { szStringId1 = WaveDeviceIdToStringId ( *(DWORD*)((LPBYTE)pID + pID->dwStringOffset), L"wave/in"); szStringId2 = WaveDeviceIdToStringId ( *( (DWORD*)((LPBYTE)pID + pID->dwStringOffset) + 1 ), L"wave/out"); if ( szStringId1 && szStringId2 ) { dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + 2 * sizeof(DWORD); if ( dwAvailSize >= (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR) ) { wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 ); wcscpy( (LPWSTR) ((LPBYTE)pID + pID->dwStringOffset + (wcslen(szStringId1) + 1) * sizeof(WCHAR)), szStringId2 ); pID->dwStringSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR); pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - 2 * sizeof(DWORD); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } else { pID->dwNeededSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR); } } else { LOG((TL_ERROR, "LGetIDEx: WaveDeviceIdToStringId failed")); pParams->lResult = LINEERR_OPERATIONFAILED; } ServerFree(szStringId1); ServerFree(szStringId2); } } ServerFree(pDeviceClassCopy); } void WINAPI LGetID( PTCLIENT ptClient, PLINEGETID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bSPITooLow = FALSE; DWORD dwWidgetType, hWidget, dwPrivilege; HANDLE hMutex; ULONG_PTR hdWidget; LPVOID context; TSPIPROC pfnTSPI_lineGetID; DWORD objectToDereference; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwDeviceIDTotalSize > dwParamsBufferSize) || IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } switch ( pParams->dwSelect ) { case LINECALLSELECT_CALL: { dwWidgetType = ANY_RT_HCALL; hWidget = pParams->hCall; dwPrivilege = LINECALLPRIVILEGE_MONITOR; break; } case LINECALLSELECT_DEVICEID: { PTLINEAPP ptLineApp; BOOL bVersion = FALSE; PTLINELOOKUPENTRY ptLineLookup; LOG((TL_INFO, "lineGetID: LINECALLSELECT_DEVICEID. ptClient %p", ptClient)); if (WaitForExclusiveClientAccess (ptClient)) { ptLineApp = ptClient->ptLineApps; // see if any line app is > version 2.0 while (ptLineApp) { LOG((TL_INFO, "lineGetID: ptLineApp->dwAPIVersion %lx, TAPI_VERSION2_0 %lx", ptLineApp->dwAPIVersion, TAPI_VERSION2_0)); if (ptLineApp->dwAPIVersion > TAPI_VERSION2_0) { bVersion = TRUE; break; } ptLineApp = ptLineApp->pNext; } UNLOCKTCLIENT (ptClient); } else { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (!bVersion) { LOG((TL_ERROR, "lineGetID failed with invalid call select")); pParams->lResult = LINEERR_INVALCALLSELECT; return; } // check the spi version ptLineLookup = GetLineLookupEntry (pParams->dwAddressID); if (!ptLineLookup) { LOG((TL_ERROR, "lineGetID failed with invalid device id")); pParams->lResult = LINEERR_BADDEVICEID; return; } if (ptLineLookup->ptProvider->dwSPIVersion <= TAPI_VERSION2_0) { bSPITooLow = TRUE; } dwWidgetType = DEVICE_ID; hWidget = 0; dwPrivilege = pParams->dwAddressID; break; } case LINECALLSELECT_ADDRESS: case LINECALLSELECT_LINE: { dwWidgetType = ANY_RT_HLINE; hWidget = pParams->hLine; dwPrivilege = 0; break; } default: LOG((TL_ERROR, "lineGetID failed with invalid call select")); pParams->lResult = LINEERR_INVALCALLSELECT; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle &hdWidget, // provider widget handle dwPrivilege, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETID, // provider func index &pfnTSPI_lineGetID, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &context, // context "GetID" // func name )) == 0 || pParams->lResult == LINEERR_OPERATIONUNAVAIL) { WCHAR *pszDeviceClass; LPVARSTRING pID = (LPVARSTRING) pDataBuf; // // We'll handle the "tapi/line" class right here rather than // burden every single driver with having to support it // if (_wcsicmp( (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset), L"tapi/line" ) == 0) { if (!InitTapiStruct( pID, pParams->dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetID_epilog; } pID->dwNeededSize += sizeof (DWORD); if (pID->dwTotalSize >= pID->dwNeededSize) { try { switch (pParams->dwSelect) { case LINECALLSELECT_ADDRESS: { if (pParams->dwAddressID >= ((PTLINECLIENT) context)->ptLine->dwNumAddresses) { pParams->lResult = LINEERR_INVALADDRESSID; goto LGetID_epilog; } *((LPDWORD)(pID + 1)) = ((PTLINECLIENT) context)->ptLine->dwDeviceID; break; } case LINECALLSELECT_CALL: { *((LPDWORD)(pID + 1)) = ((PTCALLCLIENT) context)->ptCall->ptLine->dwDeviceID; break; } case LINECALLSELECT_LINE: { *((LPDWORD)(pID + 1)) = ((PTLINECLIENT) context)->ptLine->dwDeviceID; break; } case LINECALLSELECT_DEVICEID: { *((LPDWORD)(pID + 1)) = pParams->dwAddressID; break; } } // switch } myexcept { switch (pParams->dwSelect) { case LINECALLSELECT_CALL: pParams->lResult = LINEERR_INVALCALLHANDLE; break; case LINECALLSELECT_LINE: case LINECALLSELECT_ADDRESS: pParams->lResult = LINEERR_INVALLINEHANDLE; break; case LINECALLSELECT_DEVICEID: pParams->lResult = LINEERR_BADDEVICEID; break; } goto LGetID_epilog; } pID->dwUsedSize += sizeof (DWORD); pID->dwStringFormat = STRINGFORMAT_BINARY; pID->dwStringSize = sizeof (DWORD); pID->dwStringOffset = sizeof (VARSTRING); } // // Indicate offset & how many bytes of data we're passing back // pParams->lResult = 0; pParams->dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; goto LGetID_epilog; } // see if they want the provider id if (_wcsicmp( (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset), L"tapi/providerid" ) == 0) { if (!InitTapiStruct( pID, pParams->dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetID_epilog; } pID->dwNeededSize += sizeof (DWORD); if (pID->dwTotalSize >= pID->dwNeededSize) { try { switch (pParams->dwSelect) { case LINECALLSELECT_ADDRESS: { if (pParams->dwAddressID >= ((PTLINECLIENT) context)->ptLine->dwNumAddresses) { pParams->lResult = LINEERR_INVALADDRESSID; goto LGetID_epilog; } *((LPDWORD)(pID + 1)) = ((PTLINECLIENT) context)->ptLine->ptProvider-> dwPermanentProviderID; break; } case LINECALLSELECT_DEVICEID: { *((LPDWORD)(pID + 1)) = ((PTLINELOOKUPENTRY) context)->ptProvider->dwPermanentProviderID; break; } case LINECALLSELECT_CALL: { PTCALLCLIENT ptCallClient = (PTCALLCLIENT) context; *((LPDWORD)(pID + 1)) = ptCallClient->ptLineClient-> ptLine->ptProvider->dwPermanentProviderID; break; } case LINECALLSELECT_LINE: { *((LPDWORD)(pID + 1)) = ((PTLINECLIENT) context)->ptLine->ptProvider-> dwPermanentProviderID; break; } default: // we've already verified the call select flags above. break; } } myexcept { switch (pParams->dwSelect) { case LINECALLSELECT_CALL: pParams->lResult = LINEERR_INVALCALLHANDLE; break; case LINECALLSELECT_LINE: case LINECALLSELECT_ADDRESS: pParams->lResult = LINEERR_INVALLINEHANDLE; break; case LINECALLSELECT_DEVICEID: pParams->lResult = LINEERR_BADDEVICEID; break; } goto LGetID_epilog; } pID->dwUsedSize += sizeof (DWORD); pID->dwStringFormat = STRINGFORMAT_BINARY; pID->dwStringSize = sizeof (DWORD); pID->dwStringOffset = sizeof (VARSTRING); } // // Indicate offset & how many bytes of data we're passing back // pParams->lResult = 0; pParams->dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; goto LGetID_epilog; } if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { goto LGetID_epilog; } if (bSPITooLow) { pParams->lResult = LINEERR_INVALCALLSELECT; goto LGetID_epilog; } // // Alloc a temporary buf for the dev class, since we'll be using // the existing buffer for output // { UINT nStringSize; nStringSize = sizeof(WCHAR) * (1 + wcslen((PWSTR)(pDataBuf + pParams->dwDeviceClassOffset))); if (0 == nStringSize) { LOG((TL_ERROR, "Bad string size (0) in lineGetID!")); pParams->lResult = LINEERR_INVALPARAM; goto LGetID_epilog; } if (!(pszDeviceClass = (WCHAR *) ServerAlloc (nStringSize))) { LOG((TL_ERROR, "Mem failed in lineGetID!")); pParams->lResult = LINEERR_NOMEM; goto LGetID_epilog; } } wcscpy( pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset) ); if (!InitTapiStruct( pID, pParams->dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { ServerFree (pszDeviceClass); pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetID_epilog; } { ULONG_PTR dwCallWidgetHold = 0, dwLineWidgetHold = 0; DWORD dwDeviceIDHold = 0; switch (pParams->dwSelect) { case LINECALLSELECT_ADDRESS: dwDeviceIDHold = pParams->dwAddressID; //fall through case LINECALLSELECT_LINE: dwLineWidgetHold = hdWidget; break; case LINECALLSELECT_DEVICEID: // this is the mapped id. dwDeviceIDHold = DWORD_CAST(hdWidget,__FILE__,__LINE__); break; case LINECALLSELECT_CALL: dwCallWidgetHold = hdWidget; break; default: break; } if ((pParams->lResult = CallSP7( pfnTSPI_lineGetID, "lineGetID", SP_FUNC_SYNC, (ULONG_PTR) dwLineWidgetHold, (DWORD) dwDeviceIDHold, (ULONG_PTR) dwCallWidgetHold, (DWORD) pParams->dwSelect, (ULONG_PTR) pID, (ULONG_PTR) pszDeviceClass, (ULONG_PTR) (IS_REMOTE_CLIENT (ptClient) ? (HANDLE) -1 : ptClient->hProcess) )) == 0) { #if TELE_SERVER // // If // this is a server & // client doesn't have admin privileges & // the specified device class == "tapi/phone" & // the dwUsedSize indicates that a phone id was // (likely) copied to the buffer // then // try to map the retrieved phone device id back // to one that makes sense to the client (and // fail the request if there's no mapping) // if (IS_REMOTE_CLIENT(ptClient) && (_wcsicmp (pszDeviceClass, L"tapi/phone") == 0) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) && (pID->dwUsedSize >= (sizeof (*pID) + sizeof (DWORD)))) { DWORD i; LPDWORD pdwPhoneID = (LPDWORD) (((LPBYTE) pID) + pID->dwStringOffset); for (i = 0; i < ptClient->dwPhoneDevices; i++) { if (*pdwPhoneID == ptClient->pPhoneDevices[i]) { *pdwPhoneID = i; break; } } if (i >= ptClient->dwPhoneDevices) { pParams->lResult = LINEERR_OPERATIONFAILED; } } #endif // // Indicate offset & how many bytes of data we're passing back // pParams->dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } } ServerFree (pszDeviceClass); } LGetID_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetID" ); } void WINAPI LGetLineDevStatus( PTCLIENT ptClient, PLINEGETLINEDEVSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetLineDevStatus; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwLineDevStatusTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETLINEDEVSTATUS, // provider func index &pfnTSPI_lineGetLineDevStatus, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetLineDevStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP, dwNumOpens, dwOpenMediaModes; PTLINE ptLine; LPLINEDEVSTATUS pDevStatus = (LPLINEDEVSTATUS) pDataBuf, pDevStatus2 = (LPLINEDEVSTATUS) NULL; // // Safely retrieve the API & SPI versions, also some other info // try { dwAPIVersion = ptLineClient->dwAPIVersion; ptLine = ptLineClient->ptLine; dwSPIVersion = ptLine->dwSPIVersion; dwNumOpens = ptLine->dwNumOpens; dwOpenMediaModes = ptLine->dwOpenMediaModes; if (ptLineClient->dwKey != TLINECLIENT_KEY) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetLineDevStatus_epilog; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetLineDevStatus_epilog; } // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwTotalSize = pParams->dwLineDevStatusTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeClient = 76; // 19 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEDEVSTATUS); break; } if (dwTotalSize < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetLineDevStatus_epilog; } // // Determine the fixed size of the structure expected by the SP // switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 76; // 19 * sizeof (DWORD) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINEDEVSTATUS); break; } // // If the client's buffer is < the fixed size of that expected by // the SP (client is lower version than SP) then allocate an // intermediate buffer // if (dwTotalSize < dwFixedSizeSP) { if (!(pDevStatus2 = ServerAlloc (dwFixedSizeSP))) { pParams->lResult = LINEERR_NOMEM; goto LGetLineDevStatus_epilog; } pDevStatus = pDevStatus2; dwTotalSize = dwFixedSizeSP; } InitTapiStruct( pDevStatus, dwTotalSize, dwFixedSizeSP, (pDevStatus2 == NULL ? TRUE : FALSE) ); if ((pParams->lResult = CallSP2( pfnTSPI_lineGetLineDevStatus, "lineGetLineDevStatus", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (ULONG_PTR) pDevStatus )) == 0) { // // Add the fields we're responsible for // pDevStatus->dwNumOpens = dwNumOpens; pDevStatus->dwOpenMediaModes = dwOpenMediaModes; if (dwAPIVersion >= TAPI_VERSION2_0) { DWORD dwAppInfoTotalSize, dwNumOpens, dwXxxOffset, i; TPOINTERLIST clientList, *pClientList = &clientList; LPLINEAPPINFO pAppInfo; // // Reset the num opens to 0 in case we return prior to // filling in the app info list (so tapi32.dll doesn't // blow up trying to do unicode->ascii conversion on // bad data) // pDevStatus->dwNumOpens = 0; // // Retrieve the list of line clients & determine how big // of a buffer we need to hold all the related app info // data. Do it safely in case one of the widgets is // destroyed while we're reading it's data. // if (GetLineClientListFromLine (ptLine, &pClientList) != 0) { goto LGetLineDevStatus_copyTmpBuffer; } dwAppInfoTotalSize = pClientList->dwNumUsedEntries * sizeof (LINEAPPINFO); for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTLINECLIENT ptLineClient = (PTLINECLIENT) pClientList->aEntries[i]; try { DWORD d; d = ptLineClient->ptClient->dwComputerNameSize; d += ptLineClient->ptClient->dwUserNameSize; // don't include preceding '"' d += ptLineClient->ptLineApp->dwModuleNameSize - sizeof (WCHAR); d += ptLineClient->ptLineApp->dwFriendlyNameSize; if (ptLineClient->dwKey == TLINECLIENT_KEY) { dwAppInfoTotalSize += d; } else { pClientList->aEntries[i] = 0; } } myexcept { pClientList->aEntries[i] = 0; } } dwAppInfoTotalSize += 3; // add 3 to guarantee DWORD alignment pDevStatus->dwNeededSize += dwAppInfoTotalSize; // // Check to see if there's enough room in the app buffer // for all the app info data // if ((pDevStatus->dwTotalSize - pDevStatus->dwUsedSize) < dwAppInfoTotalSize) { goto LGetLineDevStatus_freeClientList; } // // Now figure out where the app info goes & safely fill // it in // pDevStatus->dwAppInfoSize = pClientList->dwNumUsedEntries * sizeof (LINEAPPINFO); pDevStatus->dwAppInfoOffset = (pDevStatus->dwUsedSize + 3) & 0xfffffffc; pDevStatus->dwUsedSize += dwAppInfoTotalSize; pAppInfo = (LPLINEAPPINFO) (((LPBYTE) pDevStatus) + pDevStatus->dwAppInfoOffset); dwXxxOffset = pDevStatus->dwAppInfoSize + pDevStatus->dwAppInfoOffset; dwNumOpens = 0; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTLINECLIENT ptLineClient = (PTLINECLIENT) pClientList->aEntries[i]; if (ptLineClient == NULL) { continue; } try { DWORD d = dwXxxOffset; PTCLIENT ptClient = ptLineClient->ptClient; PTLINEAPP ptLineApp = ptLineClient->ptLineApp; pAppInfo->dwMachineNameSize = ptClient->dwComputerNameSize; pAppInfo->dwUserNameSize = ptClient->dwUserNameSize; if (ptClient->dwKey != TCLIENT_KEY) { continue; } pAppInfo->dwModuleFilenameSize = ptLineApp->dwModuleNameSize - sizeof (WCHAR); pAppInfo->dwFriendlyNameSize = ptLineApp->dwFriendlyNameSize; if (ptLineApp->dwKey != TLINEAPP_KEY) { continue; } pAppInfo->dwMachineNameOffset = d; if (pAppInfo->dwMachineNameSize) { wcsncpy( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptClient->pszComputerName, pAppInfo->dwMachineNameSize / sizeof (WCHAR) ); d += pAppInfo->dwMachineNameSize; } pAppInfo->dwUserNameOffset = d; if (pAppInfo->dwUserNameSize) { wcsncpy( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptClient->pszUserName, pAppInfo->dwUserNameSize / sizeof (WCHAR) ); d += pAppInfo->dwUserNameSize; } pAppInfo->dwModuleFilenameOffset = d; if (pAppInfo->dwModuleFilenameSize) { // don't include preceding '"' wcsncpy( (LPWSTR) (((LPBYTE) pDevStatus) + d), &ptLineApp->pszModuleName[1], pAppInfo->dwModuleFilenameSize / sizeof (WCHAR) ); d += pAppInfo->dwModuleFilenameSize; } pAppInfo->dwFriendlyNameOffset = d; if (pAppInfo->dwFriendlyNameSize) { wcsncpy( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptLineApp->pszFriendlyName, pAppInfo->dwFriendlyNameSize / sizeof (WCHAR) ); d += pAppInfo->dwFriendlyNameSize; } pAppInfo->dwMediaModes = ptLineClient->dwMediaModes; pAppInfo->dwAddressID = ptLineClient->dwAddressID; // // Finally, make sure the tLineClient is still good // so we know all the info above is kosher, & // if so inc the appropriate vars // if (ptLineClient->dwKey == TLINECLIENT_KEY) { pAppInfo++; dwNumOpens++; dwXxxOffset = d; } } myexcept { // do nothing, just continue to loop } } pDevStatus->dwNumOpens = dwNumOpens; pDevStatus->dwAppInfoSize = dwNumOpens * sizeof (LINEAPPINFO); LGetLineDevStatus_freeClientList: if (pClientList != &clientList) { ServerFree (pClientList); } } // // Munge fields where appropriate for old apps (don't want to // pass back flags that they won't understand) // // // If an intermediate buffer was used then copy the bits back // to the the original buffer, & free the intermediate buffer. // Also reset the dwUsedSize field to the fixed size of the // structure for the specifed version, since any data in the // variable portion is garbage as far as the client is concerned. // LGetLineDevStatus_copyTmpBuffer: if (pDevStatus == pDevStatus2) { pDevStatus = (LPLINEDEVSTATUS) pDataBuf; CopyMemory (pDevStatus, pDevStatus2, dwFixedSizeClient); ServerFree (pDevStatus2); pDevStatus->dwTotalSize = pParams->dwLineDevStatusTotalSize; pDevStatus->dwUsedSize = dwFixedSizeClient; } // // Indicate the API version of the hLine so tapi32.dll knows // which strings to munge from ascii to unicode // pParams->dwAPIVersion = dwAPIVersion; // // Indicate the offset & how many bytes of data we're passing back // pParams->dwLineDevStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDevStatus->dwUsedSize; } } LGetLineDevStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetLineDevStatus" ); } void WINAPI LGetNewCalls( PTCLIENT ptClient, PLINEGETNEWCALLS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LONG lResult = 0; DWORD dwTotalSize = pParams->dwCallListTotalSize, dwAddressID, dwNumNewCalls, i, j, dwSelect = pParams->dwSelect; PTLINE ptLine; HDRVLINE hdLine; PTLINECLIENT ptLineClient; TPOINTERLIST callList, *pCallList = &callList; LPLINECALLLIST pAppCallList = (LPLINECALLLIST) pDataBuf; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwCallListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } // // Verify params // if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LGetNewCalls_return; } if (dwSelect == LINECALLSELECT_ADDRESS) { dwAddressID = pParams->dwAddressID; } else if (dwSelect != LINECALLSELECT_LINE) { pParams->lResult = LINEERR_INVALCALLSELECT; goto LGetNewCalls_return; } if (dwTotalSize < sizeof (LINECALLLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetNewCalls_return; } if (!(ptLineClient = ReferenceObject( ghHandleTable, pParams->hLine, TLINECLIENT_KEY ))) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_return; } if (ptLineClient->ptClient != ptClient) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_dereference; } ptLine = ptLineClient->ptLine; // // HACK ALERT! // // GetNewCalls did not work on remote lines in tapi 2.1, // win98 gold, or nt4sp4. // // The way we get it to work here for remote lines is to do a // TSPI_lineGetID down to remotesp, specifying the device class // of "GetNewCalls", and passing it the pointer to our real // LineEventProc, not the LineEventProcSP which queues msgs, // so it can process LINE_CALLSTATE msgs inline (this allows // the initial/requisite monitor handles to be created, etc, // before we might do so below). // try { hdLine = (ptLine->ptProvider == pRemoteSP ? ptLine->hdLine : 0); if (ptLine->dwKey != TLINE_KEY) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_dereference; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_dereference; } if (hdLine && pRemoteSP->apfn[SP_LINEGETID]) { CallSP7( pRemoteSP->apfn[SP_LINEGETID], "lineGetID(GetNewCalls)", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) dwAddressID, (ULONG_PTR) 0, // hdCall (DWORD) dwSelect, (ULONG_PTR) 0, // lpDeviceID (ULONG_PTR) L"GetNewCalls", // lpszDeviceClass (ULONG_PTR) LineEventProc // hTargetProcess ); } // // Get list of tCalls on the tLine // if ((lResult = GetCallListFromLine (ptLine, &pCallList)) != 0) { pParams->lResult = lResult; goto LGetNewCalls_dereference; } // // Assume worst case scenario- that we have to create a new call // client for each tCall on the tLine- and make sure the app's call // list is large enough to hold them all // pAppCallList->dwTotalSize = dwTotalSize; if (dwTotalSize < (sizeof (LINECALLLIST) + pCallList->dwNumUsedEntries * sizeof(HCALL))) { pAppCallList->dwNeededSize = sizeof (LINECALLLIST) + pCallList->dwNumUsedEntries * sizeof(HCALL); pAppCallList->dwUsedSize = sizeof (LINECALLLIST); FillMemory (&pAppCallList->dwCallsNumEntries, 3 * sizeof (DWORD), 0); goto LGetNewCalls_cleanup; } // // Check to see if there's a call client for the specified // line client for each of the calls on the line/address, // create one with monitor privilege if not // dwNumNewCalls = 0; for (i = 0; i < pCallList->dwNumUsedEntries; i++) { BOOL bContinue = FALSE; PTCALL ptCall = (PTCALL) pCallList->aEntries[i]; TPOINTERLIST callClientList, *pCallClientList = &callClientList; // // Check to see if the post-processing routine (for outgoing calls) // or the CALLSTATE msg handler in the LineEventProc (for incoming // calls) has already created the list of monitors for this tCall. // try { if (ptCall->bCreatedInitialMonitors == FALSE) { bContinue = TRUE; } } myexcept { bContinue = TRUE; } if (dwSelect == LINECALLSELECT_ADDRESS) { try { if (dwAddressID != ptCall->dwAddressID) { bContinue = TRUE; } } myexcept { bContinue = TRUE; } } if (bContinue) { continue; } if (GetCallClientListFromCall (ptCall, &pCallClientList) != 0) { continue; } for (j = 0; j < pCallClientList->dwNumUsedEntries; j++) { try { if (((PTCALLCLIENT)(pCallClientList->aEntries[j])) ->ptLineClient == ptLineClient) { break; } } myexcept { // just continue } } if (j == pCallClientList->dwNumUsedEntries) { PTCALLCLIENT pNewCallClient; // // (Similar remotesp hack in CreateCallMonitors) // // NOTE: If client is remote(sp) then create the call client // with OWNER privileges so client can still do everything. // The remote tapisrv will deal with all the remote // privilege issues. // // This scheme might end up confusing other apps since // a LINE_CALLINFO\NUMOWNERINCR (not NUMMONITORS) msgs // get sent, but it certainly beats what we had in tapi 2.1 - // that is, if a remote client did not initially have owner // privilege then it could *never* get owner privilege. // if ((lResult = CreatetCallClient( ptCall, ptLineClient, (IS_REMOTE_CLIENT (ptClient) ? LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_MONITOR), TRUE, TRUE, &pNewCallClient, FALSE )) == 0) { try { *(((LPHCALL)(pAppCallList + 1)) + dwNumNewCalls) = pNewCallClient->hCall; } myexcept { // // If here the call got torn down, meaning the line // is going down too // pParams->lResult = LINEERR_INVALLINEHANDLE; i = 0xfffffffe; break; } dwNumNewCalls++; } else { // specfied tCall might have been closed, not a fatal error } } if (pCallClientList != &callClientList) { ServerFree (pCallClientList); } } { DWORD dwCallsSize = dwNumNewCalls * sizeof (HCALL); pAppCallList->dwUsedSize = pAppCallList->dwNeededSize = sizeof (LINECALLLIST) + dwCallsSize; pAppCallList->dwCallsNumEntries = dwNumNewCalls; pAppCallList->dwCallsSize = dwCallsSize; pAppCallList->dwCallsOffset = sizeof (LINECALLLIST); } LGetNewCalls_cleanup: if (pCallList != &callList) { ServerFree (pCallList); } pParams->dwCallListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAppCallList->dwUsedSize; LGetNewCalls_dereference: DereferenceObject (ghHandleTable, pParams->hLine, 1); LGetNewCalls_return: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetNewCalls: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetNewCalls: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetNumAddressIDs( PTCLIENT ptClient, PLINEGETNUMADDRESSIDS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetNumAddressIDs" // func name )) == 0) { try { pParams->dwNumAddresses = ptLineClient->ptLine->dwNumAddresses; *pdwNumBytesReturned = sizeof (LINEGETNUMADDRESSIDS_PARAMS); } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetNumAddressIDs" ); } void WINAPI LGetNumRings( PTCLIENT ptClient, PLINEGETNUMRINGS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_NONE, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetNumRings" // func name )) == 0) { DWORD i, dwNumRings = 0xffffffff, dwAddressID = pParams->dwAddressID; PTLINE ptLine; TPOINTERLIST lineClientList, *pLineClientList = &lineClientList; try { ptLine = ptLineClient->ptLine; if (dwAddressID >= ptLine->dwNumAddresses) { pParams->lResult = LINEERR_INVALADDRESSID; goto LGetNumRings_epilog; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNumRings_epilog; } { LONG lResult; if ((lResult = GetLineClientListFromLine( ptLine, &pLineClientList )) != 0) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNumRings_epilog; } } for (i = 0; i < pLineClientList->dwNumUsedEntries; i++) { ptLineClient = (PTLINECLIENT) pLineClientList->aEntries[i]; try { if (ptLineClient->aNumRings == NULL) { continue; } else if (ptLineClient->aNumRings[dwAddressID] < dwNumRings) { DWORD dwNumRingsTmp = ptLineClient->aNumRings[dwAddressID]; if (ptLineClient->dwKey == TLINECLIENT_KEY) { dwNumRings = dwNumRingsTmp; } } } myexcept { // just continue } } if (pLineClientList != &lineClientList) { ServerFree (pLineClientList); } pParams->dwNumRings = dwNumRings; *pdwNumBytesReturned = sizeof (LINEGETNUMRINGS_PARAMS); } LGetNumRings_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetNumRings" ); } void WINAPI LGetProviderList( PTCLIENT ptClient, PLINEGETPROVIDERLIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD iNumProviders = 0, i; WCHAR *bufw; DWORD dwFixedSizeClient, dwTotalSize, dwNeededSize; LPBYTE pVarData; LPLINEPROVIDERLIST pProviderList; LPLINEPROVIDERENTRY pProviderEntry; HKEY hKey; DWORD dwDataSize; DWORD dwDataType; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwProviderListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } switch (pParams->dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEPROVIDERLIST); break; default: pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetProviderList_epilog; } if ((dwTotalSize = pParams->dwProviderListTotalSize) < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetProviderList_epilog; } if (ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyProviders, 0, KEY_ALL_ACCESS, &hKey )) { dwDataSize = sizeof(iNumProviders); iNumProviders = 0; RegQueryValueEx( hKey, gszNumProviders, 0, &dwDataType, (LPBYTE)&iNumProviders, &dwDataSize ); } dwNeededSize = dwFixedSizeClient + (iNumProviders * sizeof (LINEPROVIDERENTRY)); pProviderList = (LPLINEPROVIDERLIST) pDataBuf; pProviderEntry = (LPLINEPROVIDERENTRY) (pDataBuf + dwFixedSizeClient); pVarData = pDataBuf + dwNeededSize; bufw = ServerAlloc (MAX_PATH*sizeof(WCHAR)); // enough for complete path if ( !bufw ) { pParams->lResult = LINEERR_NOMEM; goto LGetProviderList_epilog; } for (i = 0; i < iNumProviders; i++) { TCHAR szProviderXxxN[32]; DWORD dwNameLen; DWORD dwNewSize; wsprintf (szProviderXxxN, TEXT("%s%d"), gszProviderFilename, i); dwNameLen = MAX_PATH*sizeof(WCHAR); if (TAPIRegQueryValueExW( hKey, szProviderXxxN, 0, &dwDataType, (LPBYTE)bufw, &dwNameLen ) != ERROR_SUCCESS) { bufw[0] = 0; } dwNewSize = (lstrlenW(bufw)+1) * sizeof(WCHAR); dwNeededSize += dwNewSize; if (dwTotalSize >= dwNeededSize) { wsprintf(szProviderXxxN, TEXT("%s%d"), gszProviderID, i); dwDataSize = sizeof(pProviderEntry->dwPermanentProviderID); pProviderEntry->dwPermanentProviderID = 0; RegQueryValueEx( hKey, szProviderXxxN, 0, &dwDataType, (LPBYTE)&(pProviderEntry->dwPermanentProviderID), &dwDataSize ); pProviderEntry->dwProviderFilenameSize = dwNewSize; pProviderEntry->dwProviderFilenameOffset = (DWORD) (pVarData - ((LPBYTE) pProviderList)); CopyMemory (pVarData, bufw, dwNewSize); pVarData += dwNewSize; pProviderEntry++; } } ServerFree (bufw); pProviderList->dwTotalSize = dwTotalSize; pProviderList->dwNeededSize = dwNeededSize; if (dwTotalSize >= dwNeededSize) { pProviderList->dwUsedSize = dwNeededSize; pProviderList->dwNumProviders = (DWORD) iNumProviders; pProviderList->dwProviderListSize = (DWORD) (iNumProviders * sizeof (LINEPROVIDERENTRY)); pProviderList->dwProviderListOffset = dwFixedSizeClient; } else { pProviderList->dwUsedSize = dwFixedSizeClient; pProviderList->dwNumProviders = pProviderList->dwProviderListSize = pProviderList->dwProviderListOffset = 0; } pParams->dwProviderListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pProviderList->dwUsedSize; RegCloseKey (hKey); LGetProviderList_epilog: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetProviderList: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetProviderList: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetProxyStatus( PTCLIENT ptClient, PLINEGETPROXYSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (pParams->dwProxyStatusTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } switch (pParams->dwAppAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT: break; default: pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle (LPVOID) &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "GetProxyStatus" // func name )) == 0) { DWORD dwAPIVersion = 0; DWORD dwTotalSize = 0; DWORD dwFixedSizeClient = 0; // // Determine the fixed size of the structure for the // specified API version // dwAPIVersion = pParams->dwAppAPIVersion; dwFixedSizeClient = sizeof (LINEPROXYREQUESTLIST); // // Will it fit ? // dwTotalSize = pParams->dwProxyStatusTotalSize; if (dwTotalSize >= dwFixedSizeClient) { // // OK, buffer's large enough for fixed part. // // Is this line remote ? // if (pLookupEntry->bRemote) { LPLINEPROXYREQUESTLIST pProxyReqList = (LPLINEPROXYREQUESTLIST) pDataBuf; InitTapiStruct( pProxyReqList, dwTotalSize, dwFixedSizeClient, TRUE ); pParams->lResult = CallSP3( pRemoteSP->apfn[SP_LINEGETPROXYSTATUS], "LineGetProxyStatus", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwAPIVersion, (ULONG_PTR) pProxyReqList ); // // Set the return values // pParams->dwAPIVersion = dwAPIVersion; pParams->dwProxyStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pProxyReqList->dwUsedSize; } else // it's a local line { DWORD i; DWORD dwNeededSize; LPDWORD pListEntry; PTLINE ptLine = pLookupEntry->ptLine; LPLINEPROXYREQUESTLIST pProxyReqList = (LPLINEPROXYREQUESTLIST) pDataBuf; if (ptLine != NULL) { // // how much space is needed for the list ? // dwNeededSize = sizeof (LINEPROXYREQUESTLIST); pProxyReqList->dwNumEntries = 0; for( i = LINEPROXYREQUEST_SETAGENTGROUP; i <= LINEPROXYREQUEST_LASTVALUE; i++ ) { try // Just in case the line gets closed { if (ptLine->apProxys[i] != NULL) { // // So there's a proxy associated with // this proxy request type, add on space // requirement for it's list entry // dwNeededSize += sizeof(DWORD); } } myexcept { pParams->lResult = LINEERR_OPERATIONUNAVAIL; goto LGetProxyStatus_epilog; } } // // Will it fit ? // if (dwTotalSize >= dwNeededSize) { // // enough room , so fill in list // pProxyReqList->dwListSize = 0; pProxyReqList->dwNumEntries = 0; pProxyReqList->dwListOffset = sizeof(LINEPROXYREQUESTLIST); pListEntry = (LPDWORD) ((BYTE *) pProxyReqList + sizeof (LINEPROXYREQUESTLIST)); for( i = LINEPROXYREQUEST_SETAGENTGROUP; i <= LINEPROXYREQUEST_LASTVALUE; i++ ) { try // Just in case the line gets closed { if (ptLine->apProxys[i] != NULL) { // // So there's a proxy associated with // this proxy request type, add on space // requirement for entry to list size // pProxyReqList->dwListSize += sizeof(DWORD); // // Incr number of entries in the list // pProxyReqList->dwNumEntries++; // // Proxy reqest type is .. // *pListEntry++ = i; } } myexcept { pParams->lResult = LINEERR_OPERATIONUNAVAIL; goto LGetProxyStatus_epilog; } } // // set the total, used & need sizes // pProxyReqList->dwTotalSize = dwTotalSize; pProxyReqList->dwUsedSize = dwNeededSize; pProxyReqList->dwNeededSize = dwNeededSize; // // Set the return values // pParams->dwAPIVersion = dwAPIVersion; pParams->dwProxyStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pProxyReqList->dwUsedSize; } else // Buffer too small for the list, so return an error { pParams->lResult = LINEERR_STRUCTURETOOSMALL; } } else // (ptLine == NULL) - No line open, so no proxies ! { pParams->lResult = LINEERR_OPERATIONFAILED; LOG((TL_ERROR, "lineGetProxyStatus - no line open")); } } // endif bRemote } else // Buffer too small { pParams->lResult = LINEERR_STRUCTURETOOSMALL; } } // endif LINEPROLOG LGetProxyStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "GetLineProxyStatus" ); } void WINAPI LGetQueueInfo( PTCLIENT ptClient, PLINEGETQUEUEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentWithoutAddressIDXxx( ptClient, (PLINEGETAGENTINFO_PARAMS) pParams, dwParamsBufferSize, LINEPROXYREQUEST_GETQUEUEINFO, SP_LINEGETQUEUEINFO, sizeof (LINEQUEUEINFO) #if DBG , "GetQueueInfo" #endif ); } void WINAPI LGetQueueList( PTCLIENT ptClient, PLINEGETQUEUELIST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwGroupIDSize, pParams->dwGroupIDOffset, sizeof(DWORD), "LGetQueueList", "pParams->GroupID" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "GetQueueList" // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwTotalSize = pParams->dwQueueListTotalSize; PTLINECLIENT pProxy; if (dwTotalSize < sizeof( LINEQUEUELIST ) ) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetQueueList_epilog; } if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_GETQUEUELIST, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LGetQueueList_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->hpQueueList; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_GETQUEUELIST, sizeof(GUID) + sizeof(DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetQueueList_epilog; } CopyMemory( &(pProxyRequestWrapper->ProxyRequest.GetQueueList.GroupID), pDataBuf + pParams->dwGroupIDOffset, sizeof(GUID) ); pProxyRequestWrapper->ProxyRequest.GetQueueList. QueueList.dwTotalSize = dwTotalSize; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetQueueList_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { LPBYTE pBuf; LPLINEAGENTINFO pAgentInfo; // // Alloc a shadow buf that the SP can use until it completes this // request. Make sure there's enough extra space in the buf for // an ASYNCEVENTMSG header so we don't have to alloc yet another // buf in the post processing proc when preparing the completion // msg to send to the client, and that the msg is 64-bit aligned. // if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwTotalSize + 7) & 0xfffffff8) ))) { lRequestID = LINEERR_NOMEM; goto LGetQueueList_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; pAgentInfo = (LPLINEAGENTINFO) (pBuf + sizeof (ASYNCEVENTMSG)); pAgentInfo->dwTotalSize = dwTotalSize; pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINEGETQUEUELIST], "LineGetQueueList", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (ULONG_PTR) (pDataBuf + pParams->dwGroupIDOffset), (ULONG_PTR) pAgentInfo ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetQueueList_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "GetQueueList" ); } void WINAPI LGetRequest( PTCLIENT ptClient, PLINEGETREQUEST_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTLINEAPP ptLineApp; PTREQUESTMAKECALL pRequestMakeCall; // // Verify size/offset/string params given our input buffer/size // if (dwParamsBufferSize < sizeof (LINEREQMAKECALLW)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, ptClient ))) { if (pParams->dwRequestMode == LINEREQUESTMODE_MAKECALL) { if (!ptLineApp->pRequestRecipient) { pParams->lResult = LINEERR_NOTREGISTERED; goto LGetRequest_releaseMutex; } EnterCriticalSection (&gPriorityListCritSec); // note: if here guaranteed to be >=1 reqRecip obj in global list if (_wcsicmp( ptLineApp->pszModuleName, TapiGlobals.pHighestPriorityRequestRecipient-> ptLineApp->pszModuleName ) == 0) { if ((pRequestMakeCall = TapiGlobals.pRequestMakeCallList)) { CopyMemory( pDataBuf, &pRequestMakeCall->LineReqMakeCall, sizeof (LINEREQMAKECALLW) ); LOG((TL_INFO, "Getting request: 0x%p", pRequestMakeCall)); LOG((TL_INFO, " DestAddress: [%ls]", pRequestMakeCall->LineReqMakeCall.szDestAddress)); LOG((TL_INFO, " AppName: [%ls]", pRequestMakeCall->LineReqMakeCall.szAppName)); LOG((TL_INFO, " CalledParty: [%ls]", pRequestMakeCall->LineReqMakeCall.szCalledParty)); LOG((TL_INFO, " Comment: [%ls]", pRequestMakeCall->LineReqMakeCall.szComment)); pParams->dwRequestBufferOffset = 0; pParams->dwSize = sizeof (LINEREQMAKECALLW); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + sizeof (LINEREQMAKECALLW); if (!(TapiGlobals.pRequestMakeCallList = pRequestMakeCall->pNext)) { TapiGlobals.pRequestMakeCallListEnd = NULL; } ServerFree (pRequestMakeCall); } else { pParams->lResult = LINEERR_NOREQUEST; } } else { pParams->lResult = LINEERR_NOREQUEST; } LeaveCriticalSection (&gPriorityListCritSec); } else if (pParams->dwRequestMode == LINEREQUESTMODE_MEDIACALL) { pParams->lResult = (ptLineApp->bReqMediaCallRecipient ? LINEERR_NOREQUEST : LINEERR_NOTREGISTERED); } else { pParams->lResult = LINEERR_INVALREQUESTMODE; } LGetRequest_releaseMutex: UNLOCKTLINEAPP(ptLineApp); } else { pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ? LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE); } #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetRequest: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetRequest: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LGetStatusMessages( PTCLIENT ptClient, PLINEGETSTATUSMESSAGES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTLINECLIENT ptLineClient; if ((ptLineClient = ReferenceObject( ghHandleTable, pParams->hLine, TLINECLIENT_KEY ))) { if (ptLineClient->ptClient == ptClient) { pParams->dwLineStates = ptLineClient->dwLineStates; pParams->dwAddressStates = ptLineClient->dwAddressStates; *pdwNumBytesReturned = sizeof (LINEGETSTATUSMESSAGES_PARAMS); } else { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALLINEHANDLE : LINEERR_UNINITIALIZED); } DereferenceObject (ghHandleTable, pParams->hLine, 1); } else { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALLINEHANDLE : LINEERR_UNINITIALIZED); } #if DBG { char szResult[32]; LOG((TL_TRACE, "lineGetStatusMessages: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineGetStatusMessages: exit, result=x%x", pParams->lResult )); #endif } void WINAPI LHandoff( PTCLIENT ptClient, PLINEHANDOFF_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; DWORD objectToDereference; PTCALLCLIENT ptCallClientApp; TPOINTERLIST xxxClientList, *pXxxClientList = &xxxClientList; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwFileNameOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwFileNameOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClientApp, // context "Handoff" // func name )) == 0) { LONG lResult; DWORD dwAPIVersion, dwValidMediaModes, i, dwMediaMode = pParams->dwMediaMode; WCHAR *pszFileName = (pParams->dwFileNameOffset==TAPI_NO_DATA ? NULL : (PWSTR)(pDataBuf + pParams->dwFileNameOffset)); PTLINE ptLine; PTCALL ptCall; PTLINECLIENT ptLineClientApp, ptLineClientTarget, ptLineClientTmp; HCALL hCall; HLINE hLine; // // Safely retrieve all the object pointers needed below, then get // a list of line clients // try { ptCall = ptCallClientApp->ptCall; ptLineClientApp = ptCallClientApp->ptLineClient; ptLine = ptLineClientApp->ptLine; dwAPIVersion = ptLineClientApp->dwAPIVersion; hCall = ptCall->hCall; hLine = ptLine->hLine; } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LHandoff_epilog; } if ((lResult = GetLineClientListFromLine (ptLine, &pXxxClientList))) { pParams->lResult = lResult; goto LHandoff_epilog; } if (pszFileName) { // // "Directed" handoff // // Walk thru the list of clients on this line & find the oldest // one (that's an owner) with an app name that matches the // specified app name // // Note: It's possible that a target app who opened the line // with OWNER privilege for only DATAMODEM calls will be a // target of a directed handoff for calls of a different media // mode, i.e. G3FAX. TNixon decided that it was desirable // to maintain this behavior for existing apps which may rely // on it. (10/24/95) // _wcsupr(pszFileName); ptLineClientTarget = NULL; for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++) { ptLineClientTmp = (PTLINECLIENT) pXxxClientList->aEntries[i]; try { // // Recall that all app names start with '"' // LOG((TL_INFO, "LHandoff: Looking for [%ls] list entry [%ls]", pszFileName, ptLineClientTmp->ptLineApp->pszModuleName )); if ((_wcsicmp( pszFileName, ptLineClientTmp->ptLineApp->pszModuleName + 1 ) == 0) && (ptLineClientTmp->dwPrivileges & LINECALLPRIVILEGE_OWNER)) { ptLineClientTarget = ptLineClientTmp; } } myexcept { // just continue } } if (ptLineClientTarget == NULL) { pParams->lResult = LINEERR_TARGETNOTFOUND; goto LHandoff_freeXxxClientList; } else if (ptLineClientTarget == ptLineClientApp) { pParams->lResult = LINEERR_TARGETSELF; goto LHandoff_freeXxxClientList; } } else { // // "Non-directed" handoff // // Validate the media mode, then walk thru the list of line // clients and find the highest pri one with owner privileges // that wants calls of the specified media mode // switch (dwAPIVersion) { case TAPI_VERSION1_0: dwValidMediaModes = AllMediaModes1_0; break; case TAPI_VERSION1_4: case TAPI_VERSION2_0: dwValidMediaModes = AllMediaModes1_4; break; //case TAPI_VERSION2_1: //case TAPI_VERSION2_2: default: //case TAPI_VERSION_CURRENT: dwValidMediaModes = AllMediaModes2_1; break; } if ((dwMediaMode == 0) || (dwAPIVersion <= TAPI_VERSION2_1 ) && !IsOnlyOneBitSetInDWORD(dwMediaMode) || (dwMediaMode & (dwValidMediaModes ^ 0x00ffffff))) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LHandoff_freeXxxClientList; } if ((ptLineClientTarget = GetHighestPriorityLineClient( ptLine, dwMediaMode, 0xffffffff )) == NULL) { pParams->lResult = LINEERR_TARGETNOTFOUND; goto LHandoff_freeXxxClientList; } else if (ptLineClientTarget == ptLineClientApp) { pParams->lResult = LINEERR_TARGETSELF; goto LHandoff_freeXxxClientList; } } // // We've found a target tLineClient. See if it already has a // tCallClient for this call, and if not create one. Then set // the privilege on the target's tCallClient to OWNER & send // the appropriate msgs. // if (pXxxClientList != &xxxClientList) { ServerFree (pXxxClientList); } if ((lResult = GetCallClientListFromCall( ptCall, &pXxxClientList ))) { pParams->lResult = lResult; goto LHandoff_epilog; } { BOOL bCreatedtCallClient, bTargetAlreadyOwner = FALSE; HANDLE hMutex; PTCALLCLIENT ptCallClientTarget = NULL, ptCallClientTmp; for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++) { ptCallClientTmp = (PTCALLCLIENT) pXxxClientList->aEntries[i]; try { if (ptCallClientTmp->ptLineClient == ptLineClientTarget) { ptCallClientTarget = ptCallClientTmp; break; } } myexcept { // just continue } } if (!ptCallClientTarget) { if ((lResult = CreatetCallClient( ptCall, ptLineClientTarget, LINECALLPRIVILEGE_OWNER, TRUE, TRUE, &ptCallClientTarget, FALSE )) != 0) { pParams->lResult = lResult; goto LHandoff_freeXxxClientList; } bCreatedtCallClient = TRUE; } else { bCreatedtCallClient = FALSE; } if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { DWORD dwCallInfoState, dwCallState, dwCallStateMode; if (bCreatedtCallClient) { // // CreatetCallClient will have already sent out the // appropriate CALLINFO msgs & updated NumOwners field // dwCallInfoState = 0; } else if (ptCallClientTarget->dwPrivilege == LINECALLPRIVILEGE_MONITOR) { ptCallClientTarget->dwPrivilege = LINECALLPRIVILEGE_OWNER; ptCall->dwNumOwners++; ptCall->dwNumMonitors--; dwCallInfoState = LINECALLINFOSTATE_NUMOWNERINCR | LINECALLINFOSTATE_NUMMONITORS; } else { // // Ideally we should just be able to exit at this point. // However, TAPI 1.x will send a CALLSTATE msg with // dwParam3 == OWNER to the target app even though it // already is an OWNER. Some Intel app relies on this // behavior, so we'll preserve it for now... // bTargetAlreadyOwner = TRUE; dwCallInfoState = 0; } dwCallState = ptCall->dwCallState; dwCallStateMode = ptCall->dwCallStateMode; UNLOCKTCALL(ptCall); if (dwCallInfoState || bCreatedtCallClient || bTargetAlreadyOwner) { BOOL bIndicatePrivilege = TRUE; PTCLIENT ptClientTarget; ASYNCEVENTMSG msg[2]; if (bCreatedtCallClient) { try { if (ptLineClientTarget->dwAPIVersion >= TAPI_VERSION2_0 && !FMsgDisabled( ptLineClientTarget->ptLineApp->dwAPIVersion, ptLineClientTarget->adwEventSubMasks, LINE_APPNEWCALL, 0 )) { ASYNCEVENTMSG newCallMsg[2], *pNewCallMsg = newCallMsg; PTCONFERENCELIST pConfList; BOOL bConfParent = FALSE; pNewCallMsg->TotalSize = sizeof (ASYNCEVENTMSG) + 3*sizeof (DWORD); pNewCallMsg->fnPostProcessProcHandle = 0; pNewCallMsg->hDevice = ptLineClientTarget->hRemoteLine; pNewCallMsg->Msg = LINE_APPNEWCALL; pNewCallMsg->Param1 = ptCall->dwAddressID; pNewCallMsg->Param2 = ptCallClientTarget->hCall; pNewCallMsg->Param3 = LINECALLPRIVILEGE_OWNER; *(&pNewCallMsg->Param4 + 1) = ptCall->dwCallID; *(&pNewCallMsg->Param4 + 2) = ptCall->dwRelatedCallID; if ((pConfList = ptCall->pConfList) && (pConfList != (PTCONFERENCELIST) LongToPtr(0xffffffff)) && (pConfList->aptCalls[0] == ptCall)) { bConfParent = TRUE; } *(&pNewCallMsg->Param4 + 3) = (DWORD) bConfParent; pNewCallMsg->InitContext = ptLineClientTarget->ptLineApp-> InitContext; pNewCallMsg->OpenContext = ptLineClientTarget->OpenContext; ptClientTarget = ptCallClientTarget->ptClient; if (ptCallClientTarget->dwKey == TCALLCLIENT_KEY) { bIndicatePrivilege = FALSE; WriteEventBuffer( ptClientTarget, pNewCallMsg ); } } } myexcept { } } msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB); msg->fnPostProcessProcHandle = 0; msg->Msg = LINE_CALLSTATE; msg->Param1 = dwCallState; msg->Param2 = dwCallStateMode; msg->Param3 = (bIndicatePrivilege ? LINECALLPRIVILEGE_OWNER : 0); try { msg->hDevice = ptCallClientTarget->hCall; msg->InitContext = ptLineClientTarget->ptLineApp->InitContext; msg->OpenContext = ptLineClientTarget->OpenContext; *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClientTarget->ptCallHubClient)? ptCallClientTarget->ptCallHubClient->hCallHub : (HCALLHUB)(ULONG_PTR)NULL; ptClientTarget = ptCallClientTarget->ptClient; if (ptCallClientTarget->dwKey == TCALLCLIENT_KEY && !FMsgDisabled ( ptCallClientTarget->ptLineClient->ptLineApp->dwAPIVersion, ptCallClientTarget->adwEventSubMasks, LINE_CALLSTATE, dwCallState )) { WriteEventBuffer (ptClientTarget, msg); } } myexcept { } if (dwCallInfoState != 0) { LineEventProc( (HTAPILINE)(ULONG_PTR)hLine, (HTAPICALL)(ULONG_PTR)hCall, LINE_CALLINFO, dwCallInfoState, 0, 0 ); } if (bCreatedtCallClient) { UpdateCallHubHashing(ptCall); } } } } LHandoff_freeXxxClientList: if (pXxxClientList != &xxxClientList) { ServerFree (pXxxClientList); } } LHandoff_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "Handoff" ); } void WINAPI LHold( PTCLIENT ptClient, PLINEHOLD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineHold; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEHOLD, // provider func index &pfnTSPI_lineHold, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Hold" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineHold, "lineHold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Hold" ); } void WINAPI LInitialize( PTCLIENT ptClient, PLINEINITIALIZE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bInitClient = FALSE; DWORD dwFriendlyNameSize, dwModuleNameSize; PTLINEAPP ptLineApp; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwFriendlyNameOffset ) || IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwModuleNameOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } // // Alloc & init a new tLineApp // dwFriendlyNameSize = sizeof(WCHAR) * (1 + lstrlenW( (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)) ); dwModuleNameSize = sizeof(WCHAR) * (2 + lstrlenW( (PWSTR)(pDataBuf + pParams->dwModuleNameOffset)) ); if (!(ptLineApp = ServerAlloc( sizeof(TLINEAPP) + dwFriendlyNameSize + dwModuleNameSize ))) { pParams->lResult = LINEERR_NOMEM; goto LInitialize_return; } LOG((TL_INFO, "LInitialize: calling NewObject ptLineApp %p, pParams->InitContext %lx", ptLineApp, pParams->InitContext)); if (!(ptLineApp->hLineApp = (HLINEAPP) NewObject( ghHandleTable, ptLineApp, NULL ))) { pParams->lResult = LINEERR_NOMEM; ServerFree (ptLineApp); goto LInitialize_return; } LOG((TL_INFO, "LInitialize: NewObject returned hLineApp %lx", ptLineApp->hLineApp)); ptLineApp->dwKey = TLINEAPP_KEY; ptLineApp->ptClient = ptClient; LOG((TL_INFO, "LInitialize: initializing ptLineApp->InitContext with %lx", pParams->InitContext)); ptLineApp->InitContext = pParams->InitContext; ptLineApp->dwAPIVersion = pParams->dwAPIVersion; LOG((TL_INFO, "LInitialize: initialized ptLineApp->dwAPIVersion with %lx", pParams->dwAPIVersion)); ptLineApp->dwFriendlyNameSize = dwFriendlyNameSize; ptLineApp->pszFriendlyName = (WCHAR *) (ptLineApp + 1); wcscpy( ptLineApp->pszFriendlyName, (PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset) ); // // Note: we prepend the '"' char to the saved module name to aid in // priority determination for incoming calls // ptLineApp->dwModuleNameSize = dwModuleNameSize; ptLineApp->pszModuleName = (WCHAR *)((LPBYTE)(ptLineApp + 1) + dwFriendlyNameSize); ptLineApp->pszModuleName[0] = '"'; wcscpy( &ptLineApp->pszModuleName[1], (WCHAR *)(pDataBuf + pParams->dwModuleNameOffset) ); _wcsupr (&ptLineApp->pszModuleName[1]); // // Safely insert new tLineApp at front of tClient's tLineApp list // if (ptClient->ptLineApps == NULL) { bInitClient = TRUE; } if (WaitForExclusiveClientAccess (ptClient)) { if (ptLineApp->dwAPIVersion <= TAPI_VERSION3_0) { FillMemory ( ptLineApp->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS, (BYTE) 0xff ); } else { CopyMemory ( ptLineApp->adwEventSubMasks, ptClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS ); } if ((ptLineApp->pNext = ptClient->ptLineApps)) { ptLineApp->pNext->pPrev = ptLineApp; } ptClient->ptLineApps = ptLineApp; UNLOCKTCLIENT (ptClient); } else { pParams->lResult = LINEERR_OPERATIONFAILED; goto LInitialize_error1; } // // Check if global reinit flag set // if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT) { pParams->lResult = LINEERR_REINIT; goto LInitialize_error2; } // // See if we need to go thru init // TapiEnterCriticalSection (&TapiGlobals.CritSec); if ((TapiGlobals.dwNumLineInits == 0) && (TapiGlobals.dwNumPhoneInits == 0) && !gbServerInited) { if ((pParams->lResult = ServerInit(FALSE)) != 0) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto LInitialize_error2; } gbServerInited = TRUE; } #if TELE_SERVER if (bInitClient) { if (pParams->lResult = InitializeClient(ptClient)) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto LInitialize_error2; } } #else pParams->lResult = 0; // That's what happens if it's not a tele_server... #endif // // Fill in the return values // pParams->hLineApp = ptLineApp->hLineApp; LOG((TL_INFO, "LInitialize: returning pParams->hLineApp %p", pParams->hLineApp)); pParams->dwNumDevs = TapiGlobals.dwNumLines; LOG((TL_INFO, "LInitialize: returning pParams->dwNumDevs %p", pParams->dwNumDevs)); #if TELE_SERVER if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { pParams->dwNumDevs = ptClient->dwLineDevices; LOG((TL_TRACE, "LInitialize: returning pParams->dwNumDevs %p (again)", pParams->dwNumDevs)); } #endif // // Increment total num line inits // TapiGlobals.dwNumLineInits++; *pdwNumBytesReturned = sizeof (LINEINITIALIZE_PARAMS); TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto LInitialize_return; LInitialize_error2: if (WaitForExclusiveClientAccess (ptClient)) { if (ptLineApp->pNext) { ptLineApp->pNext->pPrev = ptLineApp->pPrev; } if (ptLineApp->pPrev) { ptLineApp->pPrev->pNext = ptLineApp->pNext; } else { ptClient->ptLineApps = ptLineApp->pNext; } UNLOCKTCLIENT (ptClient); } LInitialize_error1: DereferenceObject (ghHandleTable, ptLineApp->hLineApp, 1); LInitialize_return: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineInitialize: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineInitialize: exit, result=x%x", pParams->lResult )); #endif return; } void LMakeCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1; DWORD hpCallHandle = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); PTCALLCLIENT ptCallClient; if (WaitForExclusivetCallAccess (ptCall, TINCOMPLETECALL_KEY)) { PTCALL ptCallThen; HCALL hCallThen = (HCALL)pAsyncRequestInfo->dwParam5; // // Check to make sure this is the call we think it is (that the // pointer wasn't freed by a previous call to lineClose/Shutdown // and realloc'd for use as a ptCall again) // if (ptCall->hCall != hCallThen) { UNLOCKTCALL(ptCall); goto LMakeCall_PostProcess_bad_ptCall; } ptCallClient = ptCall->ptCallClients; if (pAsyncEventMsg->Param2 == 0) // success { // // In general it's ok with us if service providers want to // specify NULL as their hdCall (could be an index in an // array). But in the TSPI_lineForward case, the spec says // that a NULL hdCall value following successful completion // indicates that no call was created, so in that case we // want to nuke the tCall & tCallClient we created, and // indicate a NULL call handle to the client. A non-zero // pAsyncRequestInfo->dwParam3 tells us that we are // post-processing a lineForward request, otherwise it's a // make call or similar (non-Forward) request. // if (pAsyncRequestInfo->dwParam3 && !ptCall->hdCall) { goto LMakeCall_PostProcess_cleanupCalls; } // // Check to see if the app closed the line & left us with // 0 call clients (in which case it'll also be taking care of // cleaning up this tCall too) // if (ptCall->ptCallClients == NULL) { UNLOCKTCALL(ptCall); ptCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE; } goto LMakeCall_PostProcess_initMsgParams; } // // Retrieve the various call IDs, then check if call // client was destroyed by another thread (due to // lineClose/Shutdown) while we were getting the call ID. // If so, we'll need to clean up the tCall, since we know // the other thread didn't do it because GetCallIDs marks // the call as a zombie. // GetCallIDs (ptCall); if (ptCall->ptCallClients == NULL) { goto LMakeCall_PostProcess_cleanupCalls; } // // Stuff the various call IDs in the var data section // of the ASYNCEVENTMSG. // // Make sure to increment the dwTotalSize of the ASYNCEVENTMSG // as appropriate. We rely on the fact that CompletionProc() // calls us with a AsyncEventMsg buffer which is big enough to // handle a few extra DWORDs. // pAsyncEventMsg->Param3 = ptCallClient->hCall; pAsyncEventMsg->TotalSize += 3 * sizeof (pAsyncEventMsg->Param1); *(&pAsyncEventMsg->Param4 + 1) = ptCall->dwAddressID; *(&pAsyncEventMsg->Param4 + 2) = ptCall->dwCallID; *(&pAsyncEventMsg->Param4 + 3) = ptCall->dwRelatedCallID; // // Mark the calls as valid, the release the mutex. // ptCall->dwKey = TCALL_KEY; ptCallClient->dwKey = TCALLCLIENT_KEY; UNLOCKTCALL(ptCall); // // Create monitor tCallClients // if (ptCallThen = ReferenceObject(ghHandleTable, hCallThen, TCALL_KEY)) { if (ptCallThen == ptCall) { CreateCallMonitors (ptCall, FALSE); } DereferenceObject(ghHandleTable, hCallThen, 1); } } else // error { LMakeCall_PostProcess_cleanupCalls: // // Invalidate the tCall, & if there's still a tCallClient // (might have already been destroyed by a lineClose/Shutdown // in another thread) invalidate it too. Then unlock the // tCall & remove the object(s) from the list(s). // ptCall->dwKey = INVAL_KEY; if (ptCall->ptCallClients) { ptCallClient->dwKey = INVAL_KEY; ptCall->lActiveFastCallClients--; } else { ptCallClient = NULL; } UNLOCKTCALL(ptCall); RemoveCallFromLineList (ptCall); if (ptCallClient) { DereferenceObject (ghHandleTable, ptCallClient->hCall, 1); RemoveCallClientFromLineClientList (ptCallClient); } // // Make sure all fast call clients cleaned up before free tCall // while (ptCall->lActiveFastCallClients != 0) { Sleep (5); } FreetCall (ptCall); ptCallClient = NULL; } } else { // // If here we can assume that the call was already destroyed // and just fail the request // LMakeCall_PostProcess_bad_ptCall: ptCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED; } } LMakeCall_PostProcess_initMsgParams: // // Fill in the params to pass to client (important to remotesp in both // the success & fail cases so it can either init or clean up drvCall) // pAsyncEventMsg->Param4 = hpCallHandle; } void WINAPI LMakeCall( PTCLIENT ptClient, PLINEMAKECALL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineMakeCall; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEMAKECALL, // provider func index &pfnTSPI_lineMakeCall, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "MakeCall" // func name )) > 0) { LONG lResult; PTCALL ptCall; LPWSTR lpszDestAddress; HCALL hCall; PTCALLCLIENT ptCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; LOG((TL_INFO, "LMakeCall: LINEPROLOG succeeded .")); // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwDestAddressOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) || ((pParams->dwCallParamsOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset ))) { LOG((TL_INFO, "LMakeCall: LINEERR_STRUCTURETOOSMALL.")); // // Note: Passing back ERR_STRUCTURETOOSMALL handles the case // where app has passed in a bad size in the callparams, // and does so in a spec-friendly manner. The only // other reason we'd end up here would be an rpc attack, // and in that case it's just important that we fail. // lRequestID = LINEERR_STRUCTURETOOSMALL; goto LMakeCall_return; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); LOG((TL_INFO, "LMakeCall: pCallParamsApp %p.", pCallParamsApp)); if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; if (GetLineVersions( ptLineClient, &dwAPIVersion, &dwSPIVersion ) != 0) { LOG((TL_ERROR, "LMakeCall: GetLineVersions failed. LINEERR_INVALLINEHANDLE")); lRequestID = LINEERR_INVALLINEHANDLE; goto LMakeCall_return; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { LOG((TL_ERROR, "LMakeCall: ValidateCallParams failed. %lx", lResult)); lRequestID = lResult; goto LMakeCall_return; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( ptLineClient, &ptCall, &ptCallClient, pCallParamsSP, &hCall, NULL ) != 0) { LOG((TL_ERROR, "LMakeCall: CreatetCallAndClient failed. LINEERR_NOMEM")); lRequestID = LINEERR_NOMEM; goto LMakeCall_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall; pAsyncRequestInfo->dwParam2 = pParams->hpCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; if (pParams->dwDestAddressOffset == TAPI_NO_DATA) { LOG((TL_ERROR, "LMakeCall: pParams->dwDestAddressOffset == TAPI_NO_DATA")); lpszDestAddress = NULL; } else { lpszDestAddress = (LPWSTR)(pDataBuf +pParams->dwDestAddressOffset); } LOG((TL_TRACE, "LMakeCall: calling CallSP7")); pParams->lResult = CallSP7( pfnTSPI_lineMakeCall, "lineMakeCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (ULONG_PTR) hCall, (ULONG_PTR) &ptCall->hdCall, (ULONG_PTR) lpszDestAddress, (DWORD) pParams->dwCountryCode, (ULONG_PTR) pCallParamsSP ); LOG((TL_INFO, "LMakeCall: CallSP7 returnded %lx", pParams->lResult)); SetDrvCallFlags( hCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); LMakeCall_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LMakeCall_return: LOG((TL_TRACE, "LMakeCall: calling LINEEPILOGASYNC")); LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "MakeCall" ); LOG((TL_TRACE, "LMakeCall: LINEEPILOGASYNC returned")); } void WINAPI LMonitorDigits( PTCLIENT ptClient, PLINEMONITORDIGITS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorDigits; DWORD objectToDereference; PTCALLCLIENT ptCallClient, ptCallClient2; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEMONITORDIGITS, // provider func index &pfnTSPI_lineMonitorDigits, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "MonitorDigits" // func name )) == 0) { DWORD dwUnionDigitModes; PTCALL ptCall; if ((pParams->dwDigitModes & (~AllDigitModes))) { pParams->lResult = LINEERR_INVALDIGITMODE; goto LMonitorDigits_epilog; } // // Determine the new union of modes // dwUnionDigitModes = pParams->dwDigitModes; try { ptCall = ptCallClient->ptCall; } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorDigits_epilog; } if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { ptCallClient2 = ptCall->ptCallClients; while (ptCallClient2) { if (ptCallClient2 != ptCallClient) { dwUnionDigitModes |= ptCallClient2->dwMonitorDigitModes; } ptCallClient2 = ptCallClient2->pNextSametCall; } UNLOCKTCALL (ptCall); } else { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorDigits_epilog; } if ((pParams->lResult = CallSP2( pfnTSPI_lineMonitorDigits, "lineMonitorDigits", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) dwUnionDigitModes )) == 0) { ptCallClient->dwMonitorDigitModes = pParams->dwDigitModes; } } LMonitorDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "MonitorDigits" ); } void WINAPI LMonitorMedia( PTCLIENT ptClient, PLINEMONITORMEDIA_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorMedia; DWORD objectToDereference; PTCALLCLIENT ptCallClient, ptCallClient2; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEMONITORMEDIA, // provider func index &pfnTSPI_lineMonitorMedia, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "MonitorMedia" // func name )) == 0) { DWORD dwAPIVersion, dwValidMediaModes, dwUnionMediaModes; PTCALL ptCall; // // Validate the specified modes // try { ptCall = ptCallClient->ptCall; dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorMedia_epilog; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorMedia_epilog; } switch (dwAPIVersion) { case TAPI_VERSION1_0: dwValidMediaModes = AllMediaModes1_0; break; case TAPI_VERSION1_4: case TAPI_VERSION2_0: dwValidMediaModes = AllMediaModes1_4; break; //case TAPI_VERSION2_1: //case TAPI_VERSION2_2: //case TAPI_VERSION_CURRENT: default: dwValidMediaModes = AllMediaModes2_1; break; } if (pParams->dwMediaModes & (~dwValidMediaModes & 0x00FFFFFF)) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LMonitorMedia_epilog; } // // Determine the new union of modes // dwUnionMediaModes = pParams->dwMediaModes; if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { ptCallClient2 = ptCall->ptCallClients; while (ptCallClient2) { if (ptCallClient2 != ptCallClient) { dwUnionMediaModes |= ptCallClient2->dwMonitorMediaModes; } ptCallClient2 = ptCallClient2->pNextSametCall; } UNLOCKTCALL (ptCall); } else { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorMedia_epilog; } if ((pParams->lResult = CallSP2( pfnTSPI_lineMonitorMedia, "lineMonitorMedia", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) dwUnionMediaModes )) == 0) { ptCallClient->dwMonitorMediaModes = pParams->dwMediaModes; } } LMonitorMedia_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "MonitorMedia" ); } void WINAPI LMonitorTones( PTCLIENT ptClient, PLINEMONITORTONES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorTones; DWORD objectToDereference; PTCALLCLIENT ptCallClient, ptCallClient2; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwTonesOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwNumEntries, // really dwNumEntries * // sizeof(LINEMONITORTONE) pParams->dwTonesOffset, sizeof(DWORD), "LMonitorTones", "pParams->MSPBuffer" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_MONITOR, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEMONITORTONES, // provider func index &pfnTSPI_lineMonitorTones, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "MonitorTones" // func name )) == 0) { // // If this is a remotesp call then we want to mark the // tCallClient as being interested in LINE_MONITORTONES // messages (due to our kludgy handling of this msg, see // comments in the msg handler in LineEventProc()). // PTCALL ptCall; try { ptCall = ptCallClient->ptCall; if (ptCall->ptProvider != pRemoteSP) { ptCall = NULL; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorTones_epilog; } if (ptCall) { if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { for( ptCallClient2 = ptCall->ptCallClients; (ptCallClient2 && (ptCallClient2 != ptCallClient)); ptCallClient2 = ptCallClient2->pNextSametCall ); if (ptCallClient2 == ptCallClient) { ptCallClient->bMonitoringTones = (pParams->dwTonesOffset == TAPI_NO_DATA ? 0 : 1); } UNLOCKTCALL (ptCall); if (!ptCallClient2) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorTones_epilog; } } else { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LMonitorTones_epilog; } } pParams->lResult = CallSP4( pfnTSPI_lineMonitorTones, "lineMonitorTones", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) pParams->hCall, (ULONG_PTR) (pParams->dwTonesOffset == TAPI_NO_DATA ? 0 : pDataBuf + pParams->dwTonesOffset), (DWORD) pParams->dwNumEntries / sizeof (LINEMONITORTONE) ); } LMonitorTones_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "MonitorTones" ); } void WINAPI LNegotiateAPIVersion( PTCLIENT ptClient, PLINENEGOTIATEAPIVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { // // Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion // DWORD dwDeviceID = pParams->dwDeviceID; LOG((TL_TRACE, "LNegotiateAPIVersion: started. dwDeviceID %lx, dwAPILowVersion %lx dwAPIHighVersion %lx", pParams->dwDeviceID, pParams->dwAPILowVersion, pParams->dwAPIHighVersion)); // // Verify size/offset/string params given our input buffer/size // if (dwParamsBufferSize < sizeof (LINEEXTENSIONID)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LNegotiateAPIVersion_exit; } #if TELE_SERVER if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) && !IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { try { if (dwDeviceID >= ptClient->dwLineDevices) { pParams->lResult = LINEERR_BADDEVICEID; goto LNegotiateAPIVersion_exit; } dwDeviceID = ptClient->pLineDevices[dwDeviceID]; } myexcept { LOG((TL_ERROR, "ptClient excepted in LineNegotiateAPIVersion")); pParams->lResult = LINEERR_INVALLINEHANDLE; goto LNegotiateAPIVersion_exit; } } #endif if (dwDeviceID < TapiGlobals.dwNumLines) { DWORD dwAPIHighVersion = pParams->dwAPIHighVersion, dwAPILowVersion = pParams->dwAPILowVersion, dwHighestValidAPIVersion; PTLINEAPP ptLineApp; // // Do a minimax test on the specified lo/hi values // if ((dwAPILowVersion > dwAPIHighVersion) || (dwAPILowVersion > TAPI_VERSION_CURRENT) || (dwAPIHighVersion < TAPI_VERSION1_0)) { LOG((TL_ERROR, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION1")); pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LNegotiateAPIVersion_exit; } // // HACKALERT! Some dumb apps like SmarTerm negotiate specifying // a dwHighVersion of 0x7fffffff or higher, which can really // cause them problems (like when they try to pass down structures // of a size that was fine in the TAPI version under which the app // was built, but which were enlarged in subsequent versions of // TAPI, and the result is lots of LINEERR_STRUCTURETOOSMALL // errors). // // Since we're nice, accomodating people we'll try to munge the // dwHighVersion in these cases to be a value that makes sense, so // we don't end up negotiating a version that the app can't handle. // if (dwAPIHighVersion & 0xc0000000) { dwAPIHighVersion = (dwAPILowVersion > TAPI_VERSION1_0 ? dwAPILowVersion : TAPI_VERSION1_0); } // // Find the highest valid API version given the lo/hi values. // Since valid vers aren't consecutive we need to check for // errors that our minimax test missed. // if (dwAPIHighVersion < TAPI_VERSION_CURRENT) { if ((dwAPIHighVersion >= TAPI_VERSION3_0) && (dwAPILowVersion <= TAPI_VERSION3_0)) { dwHighestValidAPIVersion = TAPI_VERSION3_0; } else if ((dwAPIHighVersion >= TAPI_VERSION2_2) && (dwAPILowVersion <= TAPI_VERSION2_2)) { dwHighestValidAPIVersion = TAPI_VERSION2_2; } else if ((dwAPIHighVersion >= TAPI_VERSION2_1) && (dwAPILowVersion <= TAPI_VERSION2_1)) { dwHighestValidAPIVersion = TAPI_VERSION2_1; } else if ((dwAPIHighVersion >= TAPI_VERSION2_0) && (dwAPILowVersion <= TAPI_VERSION2_0)) { dwHighestValidAPIVersion = TAPI_VERSION2_0; } else if ((dwAPIHighVersion >= TAPI_VERSION1_4) && (dwAPILowVersion <= TAPI_VERSION1_4)) { dwHighestValidAPIVersion = TAPI_VERSION1_4; } else if ((dwAPIHighVersion >= TAPI_VERSION1_0) && (dwAPILowVersion <= TAPI_VERSION1_0)) { dwHighestValidAPIVersion = TAPI_VERSION1_0; } else { LOG((TL_ERROR, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION2")); pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LNegotiateAPIVersion_exit; } } else { dwHighestValidAPIVersion = TAPI_VERSION_CURRENT; } // // WARNING!!! WARNING!!! WARNING!!! WARNING!!! // This code overwrites ptLineApp and later invalidates it. // Do NOT use ptLineApp after the MyReleaseMutex call. // if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, ptClient ))) { LOG((TL_INFO, "LNegotiateAPIVersion WaitForExclusiveLineAppAccess succeeded returned ptLineApp %p for hLineApp %p", ptLineApp, pParams->hLineApp)); // // Is this app trying to negotiate something valid? // // If an app has called lineInitalize (as opposed to // lineInitializeEx), we'll clamp the max APIVersion they can // negotiate to 1.4. // if ( ptLineApp->dwAPIVersion < TAPI_VERSION2_0 ) { dwHighestValidAPIVersion = (dwHighestValidAPIVersion >= TAPI_VERSION1_4) ? TAPI_VERSION1_4 : TAPI_VERSION1_0; } // // Save the highest valid API version the client says it supports // (we need this for determining which msgs to send to it) // if (dwHighestValidAPIVersion > ptLineApp->dwAPIVersion) { ptLineApp->dwAPIVersion = dwHighestValidAPIVersion; } UNLOCKTLINEAPP(ptLineApp); } else { LOG((TL_ERROR, "LNegotiateAPIVersion WaitForExclusiveLineAppAccess returned NULL")); pParams->lResult = LINEERR_INVALAPPHANDLE; goto LNegotiateAPIVersion_exit; } // // See if there's a valid match with the SPI ver // { DWORD dwSPIVersion; PTLINELOOKUPENTRY pLookupEntry; pLookupEntry = GetLineLookupEntry (dwDeviceID); if (NULL == pLookupEntry) { pParams->lResult = LINEERR_INVALAPPHANDLE; goto LNegotiateAPIVersion_exit; } dwSPIVersion = pLookupEntry->dwSPIVersion; if (pLookupEntry->bRemoved) { pParams->lResult = LINEERR_NODEVICE; goto LNegotiateAPIVersion_exit; } if (pLookupEntry->ptProvider == NULL) { pParams->lResult = LINEERR_NODRIVER; goto LNegotiateAPIVersion_exit; } if (dwAPILowVersion <= dwSPIVersion) { pParams->dwAPIVersion = (dwHighestValidAPIVersion > dwSPIVersion ? dwSPIVersion : dwHighestValidAPIVersion); // // Retrieve ext id (indicate no exts if GetExtID not exported) // if ((pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID])) { pParams->lResult = CallSP3( pLookupEntry->ptProvider-> apfn[SP_LINEGETEXTENSIONID], "lineGetExtensionID", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (ULONG_PTR) pDataBuf ); // the sp returned operationunavail. we don't want // to return that, so we just indicate that // there are no extensions if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { pParams->lResult = 0; FillMemory (pDataBuf, sizeof (LINEEXTENSIONID), 0); } } else { // doesn't export it, so fill in with zeros pParams->lResult = 0; FillMemory (pDataBuf, sizeof (LINEEXTENSIONID), 0); } } else { LOG((TL_ERROR, "LNegotiateAPIVersion: LINEERR_INCOMPATIBLEAPIVERSION3")); pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LNegotiateAPIVersion_exit; } } pParams->dwExtensionIDOffset = 0; pParams->dwSize = sizeof (LINEEXTENSIONID); *pdwNumBytesReturned = sizeof (LINEEXTENSIONID) + sizeof (TAPI32_MSG); } else { pParams->lResult = LINEERR_BADDEVICEID; } LNegotiateAPIVersion_exit: #if DBG { char szResult[32]; LOG((TL_TRACE, "lineNegotiateAPIVersion: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineNegotiateAPIVersion: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI NegotiateAPIVersionForAllDevices( PTCLIENT ptClient, PNEGOTIATEAPIVERSIONFORALLDEVICES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { #if TELE_SERVER // // Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion // DWORD i, dwNumLineDevices = pParams->dwNumLineDevices, dwNumPhoneDevices = pParams->dwNumPhoneDevices, dwAPIHighVersion = pParams->dwAPIHighVersion, dwAPILowVersion = TAPI_VERSION1_0, dwHighestValidAPIVersion, *pdwAPIVersion; LPLINEEXTENSIONID pExtID; // // Verify size/offset/string params given our input buffer/size // i = pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize + pParams->dwPhoneAPIVersionListSize + pParams->dwPhoneExtensionIDListSize; if ((pParams->dwLineAPIVersionListSize & 0xc0000000) || (pParams->dwLineExtensionIDListSize & 0xc0000000) || (pParams->dwPhoneAPIVersionListSize & 0xc0000000) || (pParams->dwPhoneExtensionIDListSize & 0xc0000000) || (i > dwParamsBufferSize)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } // // Verify the specified dwNumLine/PhonesDevices // if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { if ((pParams->dwNumLineDevices > TapiGlobals.dwNumLines) || (pParams->dwNumPhoneDevices > TapiGlobals.dwNumPhones)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } } else { if ((pParams->dwNumLineDevices > ptClient->dwLineDevices) || (pParams->dwNumPhoneDevices > ptClient->dwPhoneDevices)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } } // // // if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto NegotiateAPIVersionForAllDevices_exit; } // // Do a minimax test on the specified lo/hi values // if ((dwAPILowVersion > dwAPIHighVersion) || (dwAPILowVersion > TAPI_VERSION_CURRENT) || (dwAPIHighVersion < TAPI_VERSION1_0)) { pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto NegotiateAPIVersionForAllDevices_exit; } // // Find the highest valid API version given the lo/hi values. // Since valid vers aren't consecutive we need to check for // errors that our minimax test missed. // if (dwAPIHighVersion < TAPI_VERSION_CURRENT) { if ((dwAPIHighVersion >= TAPI_VERSION3_0) && (dwAPILowVersion <= TAPI_VERSION3_0)) { dwHighestValidAPIVersion = TAPI_VERSION3_0; } else if ((dwAPIHighVersion >= TAPI_VERSION2_2) && (dwAPILowVersion <= TAPI_VERSION2_2)) { dwHighestValidAPIVersion = TAPI_VERSION2_2; } else if ((dwAPIHighVersion >= TAPI_VERSION2_1) && (dwAPILowVersion <= TAPI_VERSION2_1)) { dwHighestValidAPIVersion = TAPI_VERSION2_1; } else if ((dwAPIHighVersion >= TAPI_VERSION2_0) && (dwAPILowVersion <= TAPI_VERSION2_0)) { dwHighestValidAPIVersion = TAPI_VERSION2_0; } else if ((dwAPIHighVersion >= TAPI_VERSION1_4) && (dwAPILowVersion <= TAPI_VERSION1_4)) { dwHighestValidAPIVersion = TAPI_VERSION1_4; } else if ((dwAPIHighVersion >= TAPI_VERSION1_0) && (dwAPILowVersion <= TAPI_VERSION1_0)) { dwHighestValidAPIVersion = TAPI_VERSION1_0; } else { pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto NegotiateAPIVersionForAllDevices_exit; } } else { dwHighestValidAPIVersion = TAPI_VERSION_CURRENT; } // // Now for each line device do negotiation // pdwAPIVersion = (LPDWORD) pDataBuf; pExtID = (LPLINEEXTENSIONID) (pDataBuf + pParams->dwLineAPIVersionListSize); for (i = 0; i < dwNumLineDevices; i++, pdwAPIVersion++, pExtID++) { DWORD dwDeviceID, dwSPIVersion; PTLINELOOKUPENTRY pLookupEntry; if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { dwDeviceID = ptClient->pLineDevices[i]; } else { dwDeviceID = i; } pLookupEntry = GetLineLookupEntry (dwDeviceID); if (NULL == pLookupEntry) { // Something is wrong with this device ID; // skip it. continue; } dwSPIVersion = pLookupEntry->dwSPIVersion; if ((dwAPILowVersion <= dwSPIVersion) && !pLookupEntry->bRemoved && (pLookupEntry->ptProvider != NULL)) { *pdwAPIVersion = (dwHighestValidAPIVersion > dwSPIVersion ? dwSPIVersion : dwHighestValidAPIVersion); // // Retrieve ext id (indicate no exts if GetExtID not exported) // if (!(pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID]) || CallSP3( pLookupEntry->ptProvider->apfn[SP_LINEGETEXTENSIONID], "lineGetExtensionID", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (ULONG_PTR) pExtID ) != 0) { ZeroMemory (pExtID, sizeof (LINEEXTENSIONID)); } } else { *pdwAPIVersion = 0; } } // // Now for each phone device do negotiation // pdwAPIVersion = (LPDWORD) (pDataBuf + pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize); pExtID = (LPLINEEXTENSIONID) (pDataBuf + pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize + pParams->dwPhoneAPIVersionListSize); for (i = 0; i < dwNumPhoneDevices; i++, pdwAPIVersion++, pExtID++) { DWORD dwDeviceID, dwSPIVersion; PTPHONELOOKUPENTRY pLookupEntry; if (!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR)) { dwDeviceID = ptClient->pPhoneDevices[i]; } else { dwDeviceID = i; } pLookupEntry = GetPhoneLookupEntry (dwDeviceID); if (NULL == pLookupEntry) { // Something wrong with this device; // skip it. continue; } dwSPIVersion = pLookupEntry->dwSPIVersion; if ((dwAPILowVersion <= dwSPIVersion) && !pLookupEntry->bRemoved && (pLookupEntry->ptProvider != NULL)) { *pdwAPIVersion = (dwHighestValidAPIVersion > dwSPIVersion ? dwSPIVersion : dwHighestValidAPIVersion); // // Retrieve ext id (indicate no exts if GetExtID not exported) // if (!(pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID]) || CallSP3( pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID], "phoneGetExtensionID", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (ULONG_PTR) pExtID ) != 0) { ZeroMemory (pExtID, sizeof (LINEEXTENSIONID)); } } else { *pdwAPIVersion = 0; } } pParams->dwLineAPIVersionListOffset = 0; pParams->dwLineExtensionIDListOffset = pParams->dwLineAPIVersionListSize; pParams->dwPhoneAPIVersionListOffset = pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize; pParams->dwPhoneExtensionIDListOffset = pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize + pParams->dwPhoneAPIVersionListSize; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwLineAPIVersionListSize + pParams->dwLineExtensionIDListSize + pParams->dwPhoneAPIVersionListSize + pParams->dwPhoneExtensionIDListSize; NegotiateAPIVersionForAllDevices_exit: #endif #if DBG { char szResult[32]; LOG((TL_TRACE, "NegotiateAPIVersionForAllDevices: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "NegotiateAPIVersionForAllDevices: exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LNegotiateExtVersion( PTCLIENT ptClient, PLINENEGOTIATEEXTVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineNegotiateExtVersion; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINENEGOTIATEEXTVERSION, // provider func index &pfnTSPI_lineNegotiateExtVersion, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "NegotiateExtVersion" // func name )) == 0) { DWORD dwSPIVersion = pLookupEntry->dwSPIVersion; if (!IsAPIVersionInRange( pParams->dwAPIVersion, dwSPIVersion )) { pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LNegotiateExtVersion_epilog; } if ((pParams->lResult = CallSP5( pfnTSPI_lineNegotiateExtVersion, "lineNegotiateExtVersion", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtLowVersion, (DWORD) pParams->dwExtHighVersion, (ULONG_PTR) &pParams->dwExtVersion )) == 0) { if (pParams->dwExtVersion == 0) { pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION; } else { *pdwNumBytesReturned = sizeof (LINENEGOTIATEEXTVERSION_PARAMS); } } } LNegotiateExtVersion_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "NegotiateExtVersion" ); } VOID PASCAL xxxLOpen( PTCLIENT ptClient, PLINEOPEN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned, BOOL bLineMapper ) { BOOL bCloseMutex, bOpenedtLine = FALSE, bDecrExtVerCountOnError = FALSE, bReleasetLineMutex = FALSE, bFreeCallParams = FALSE; LONG lResult; HLINE hLine; DWORD dwDeviceID; HANDLE hMutex; PTLINE ptLine = NULL; DWORD objectToDereference; PTPROVIDER ptProvider = NULL; PTLINECLIENT ptLineClient = NULL; PTLINELOOKUPENTRY pLookupEntry; LPLINECALLPARAMS pCallParams = NULL; TCHAR szClsid[40]; HANDLE hLookupEntryMutex = NULL; szClsid[0] = 0; if ((lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context (bLineMapper ? "Open(LINEMAPPER)" : "Open") // func name )) == 0) { DWORD dwPrivileges = pParams->dwPrivileges, dwAPIVersion = pParams->dwAPIVersion, dwExtVersion = pParams->dwExtVersion, dwMediaModes, dwNumProxyRequestTypes, dwRegisteredProxys, *pdwProxyRequestTypes, i; PTLINEAPP ptLineApp; BOOL bDuplicateOK = FALSE; // // Check if the global reinit flag is set // if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT) { lResult = LINEERR_REINIT; goto xxxLOpen_cleanup; } // // Validate params // if (!IsAPIVersionInRange( dwAPIVersion, pLookupEntry->dwSPIVersion )) { lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto xxxLOpen_cleanup; } ptProvider = pLookupEntry->ptProvider; #define VALID_LOPEN_BITS (LINECALLPRIVILEGE_NONE | \ LINECALLPRIVILEGE_MONITOR | \ LINECALLPRIVILEGE_OWNER | \ LINEOPENOPTION_SINGLEADDRESS | \ LINEOPENOPTION_PROXY) #define VALID_PRIV_BITS (LINECALLPRIVILEGE_NONE | \ LINECALLPRIVILEGE_MONITOR | \ LINECALLPRIVILEGE_OWNER) if (!(dwPrivileges & VALID_PRIV_BITS) || (dwPrivileges & ~VALID_LOPEN_BITS) || ((dwPrivileges & LINECALLPRIVILEGE_NONE) && (dwPrivileges & (LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER)))) { lResult = LINEERR_INVALPRIVSELECT; goto xxxLOpen_cleanup; } if (dwPrivileges & (LINEOPENOPTION_SINGLEADDRESS | LINEOPENOPTION_PROXY) || bLineMapper) { pCallParams = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwCallParamsOffset); if (!pCallParams) { lResult = LINEERR_INVALPOINTER; goto xxxLOpen_cleanup; } // // Verify size/offset/string params given our input buffer/size // if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; goto xxxLOpen_cleanup; } if ((lResult = ValidateCallParams( pCallParams, &pCallParams, dwAPIVersion, pLookupEntry->dwSPIVersion, pParams->dwAsciiCallParamsCodePage ))) { lResult = LINEERR_INVALPOINTER; goto xxxLOpen_cleanup; } if (pCallParams != (LPLINECALLPARAMS) (pDataBuf + pParams->dwCallParamsOffset)) { bFreeCallParams = TRUE; } if ((dwPrivileges & LINEOPENOPTION_SINGLEADDRESS) && (pCallParams->dwAddressMode != LINEADDRESSMODE_ADDRESSID)) { LOG((TL_ERROR, "lineOpen(SINGLEADDRESS): callParams.dwAddressMode" \ "!= ADDRESSID" )); lResult = LINEERR_INVALCALLPARAMS; goto xxxLOpen_cleanup; } if (dwPrivileges & LINEOPENOPTION_PROXY) { // // Verify the array of DWORDs (request types) in the // DevSpecific var field // dwNumProxyRequestTypes = (pCallParams->dwDevSpecificSize & 0xfffc) / sizeof (DWORD); if (dwNumProxyRequestTypes == 0 || dwNumProxyRequestTypes > LINEPROXYREQUEST_LASTVALUE) { LOG((TL_ERROR, "lineOpen(PROXY): inval proxy request type array "\ "size (callParams.dwDevSpecificSize=x%x)", pCallParams->dwDevSpecificSize )); lResult = LINEERR_INVALCALLPARAMS; goto xxxLOpen_cleanup; } // // Per the TAPI (Proxy) server publishing: // // If the HIWORD of dwDevSpecificSize is non-zero // immediately after the dwDevSpecificSize/Offset // field, there is a zero terminated CLSID field // of the proxy server // if (HIWORD(pCallParams->dwDevSpecificSize)) { LPTSTR lpsz; lpsz = (LPTSTR) (((LPBYTE) pCallParams) + pCallParams->dwDevSpecificOffset + LOWORD(pCallParams->dwDevSpecificSize)); pCallParams->dwDevSpecificSize = LOWORD(pCallParams->dwDevSpecificSize); if (_tcslen (lpsz) > sizeof(szClsid) / sizeof(TCHAR)) { lResult = LINEERR_INVALCALLPARAMS; goto xxxLOpen_cleanup; } _tcscpy (szClsid, lpsz); } pdwProxyRequestTypes = (LPDWORD) (((LPBYTE) pCallParams) + pCallParams->dwDevSpecificOffset); for (i = 0; i < dwNumProxyRequestTypes; i++) { if (*(pdwProxyRequestTypes + i) == 0 || *(pdwProxyRequestTypes + i) > LINEPROXYREQUEST_LASTVALUE) { LOG((TL_ERROR, "lineOpen(PROXY): inval proxy request type "\ "(x%x)", *(pdwProxyRequestTypes + i) )); lResult = LINEERR_INVALCALLPARAMS; goto xxxLOpen_cleanup; } } } } if ((dwPrivileges & LINECALLPRIVILEGE_OWNER)) { DWORD dwAllMediaModes; dwMediaModes = pParams->dwMediaModes; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwAllMediaModes = AllMediaModes1_0; break; case TAPI_VERSION1_4: case TAPI_VERSION2_0: dwAllMediaModes = AllMediaModes1_4; break; //case TAPI_VERSION2_1: //case TAPI_VERSION2_2: default: //case TAPI_VERSION_CURRENT: dwAllMediaModes = AllMediaModes2_1; break; } if ((dwMediaModes == 0) || (dwMediaModes & (0x00ffffff & ~dwAllMediaModes))) { lResult = LINEERR_INVALMEDIAMODE; goto xxxLOpen_cleanup; } } else { dwMediaModes = 0; } // // Create & init a tLineClient & associated resources // if (!(ptLineClient = ServerAlloc (sizeof(TLINECLIENT)))) { lResult = LINEERR_NOMEM; goto xxxLOpen_cleanup; } LOG((TL_TRACE, "lineOpen: calling NewObject. ptLineClient %p", ptLineClient)); if (!(ptLineClient->hLine = (HLINE) NewObject( ghHandleTable, ptLineClient, 0 ))) { ptLineClient = NULL; ServerFree (ptLineClient); lResult = LINEERR_NOMEM; goto xxxLOpen_cleanup; } LOG((TL_TRACE, "lineOpen: NewObject returned %p", ptLineClient->hLine)); ptLineClient->ptClient = ptClient; ptLineClient->hRemoteLine = (pParams->hRemoteLine ? (DWORD) pParams->hRemoteLine : ptLineClient->hLine); ptLineClient->dwAPIVersion = dwAPIVersion; ptLineClient->dwPrivileges = dwPrivileges; ptLineClient->dwMediaModes = dwMediaModes; ptLineClient->OpenContext = pParams->OpenContext; ptLineClient->dwAddressID = (dwPrivileges & LINEOPENOPTION_SINGLEADDRESS ? pCallParams->dwAddressID : 0xffffffff); LOG((TL_INFO, "lineOpen: OpenContext %p", pParams->OpenContext)); // // Duplicate the handle to tLine's mutex // Grab the mutex using the duplicate handle then start doing the open // TapiEnterCriticalSection (&TapiGlobals.CritSec); if ( pLookupEntry->hMutex ) { bDuplicateOK = DuplicateHandle( TapiGlobals.hProcess, pLookupEntry->hMutex, TapiGlobals.hProcess, &hLookupEntryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS ); } TapiLeaveCriticalSection(&TapiGlobals.CritSec); if ( !bDuplicateOK ) { bReleasetLineMutex = FALSE; lResult = LINEERR_OPERATIONFAILED; goto xxxLOpen_cleanup; } xxxLOpen_waitForMutex: if (WaitForSingleObject (hLookupEntryMutex, INFINITE) != WAIT_OBJECT_0) { bReleasetLineMutex = FALSE; lResult = LINEERR_OPERATIONFAILED; goto xxxLOpen_cleanup; } bReleasetLineMutex = TRUE; // // If the tLine is in the process of being destroyed then spin // until it's been completely destroyed (DestroytLine() will // NULLify pLookupEntry->ptLine when it's finished). Make sure // to release the mutex while sleeping so we don't block // DestroytLine. // try { while (pLookupEntry->ptLine && pLookupEntry->ptLine->dwKey != TLINE_KEY) { ReleaseMutex (hLookupEntryMutex); Sleep (0); goto xxxLOpen_waitForMutex; } } myexcept { // If here pLookupEntry->ptLine was NULLified, safe to continue } // // Check if the line has been removed // if (pLookupEntry->bRemoved) { lResult = LINEERR_BADDEVICEID; goto xxxLOpen_cleanup; } // // Validate ext ver as appropriate // if (dwExtVersion != 0 && (!IsValidLineExtVersion (dwDeviceID, dwExtVersion) || ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL)) { if ( ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL) { LOG((TL_ERROR, "The provider does not support TSPI_lineSelectExtVersion" \ " - that's a problem" )); } else { LOG((TL_ERROR, "Bad ExtVersion was passed in - that's a problem" )); } lResult = LINEERR_INCOMPATIBLEEXTVERSION; goto xxxLOpen_cleanup; } // // If line isn't open already then try to open it // if (!(ptLine = pLookupEntry->ptLine)) { if (!(ptLine = ServerAlloc (sizeof(TLINE)))) { lResult = LINEERR_NOMEM; goto xxxLOpen_cleanup; } LOG((TL_TRACE, "xxxLOpen: calling NewObject ptLine %p", ptLine)); if (!(ptLine->hLine = (HLINE) NewObject( ghHandleTable, (LPVOID) ptLine, NULL ))) { ServerFree (ptLine); lResult = LINEERR_NOMEM; goto xxxLOpen_cleanup; } ptLine->dwKey = TINCOMPLETELINE_KEY; ptLine->hMutex = pLookupEntry->hMutex; ptLine->ptProvider = ptProvider; ptLine->dwDeviceID = dwDeviceID; ptLine->dwSPIVersion = pLookupEntry->dwSPIVersion; { // // Hack Alert! // // We need to pass the privileges,etc through to // remote sp, so we make this a special case // ULONG_PTR aParams[5]; ULONG_PTR param; if (ptProvider == pRemoteSP) { aParams[0] = (ULONG_PTR) ptLine->hLine; aParams[1] = pParams->dwPrivileges; aParams[2] = pParams->dwMediaModes; aParams[3] = (ULONG_PTR) pCallParams; aParams[4] = dwExtVersion; param = (ULONG_PTR) aParams; } else { param = (ULONG_PTR) ptLine->hLine; } if (ptProvider->apfn[SP_LINEOPEN] == NULL) { lResult = LINEERR_OPERATIONUNAVAIL; } if (lResult != S_OK || (lResult = CallSP5( ptProvider->apfn[SP_LINEOPEN], "lineOpen", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) param, (ULONG_PTR) &ptLine->hdLine, (DWORD) pLookupEntry->dwSPIVersion, (ULONG_PTR) LineEventProcSP )) != 0) { DereferenceObject( ghHandleTable, ptLine->hLine, 1 ); lResult = (bLineMapper ? LINEERR_OPERATIONFAILED : lResult); goto xxxLOpen_cleanup; } bOpenedtLine = TRUE; } if (ptProvider->apfn[SP_LINEGETNUMADDRESSIDS] == NULL) { lResult = LINEERR_OPERATIONUNAVAIL; goto xxxLOpen_cleanup; } CallSP2( ptProvider->apfn[SP_LINEGETNUMADDRESSIDS], "lineGetNumAddressIDs", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (ULONG_PTR) &ptLine->dwNumAddresses ); // PERF PerfBlock.dwLinesInUse++; } // // If line is already opened & client is trying to register // as a proxy then see if there's any conflicts with existing // proxys // else if (dwPrivileges & LINEOPENOPTION_PROXY) { for (i = 0; i < dwNumProxyRequestTypes; i++) { DWORD dwProxyRequestType = *(pdwProxyRequestTypes + i); if (ptLine->apProxys[dwProxyRequestType] != NULL) { lResult = LINEERR_NOTREGISTERED; goto xxxLOpen_cleanup; } } } ptLineClient->ptLine = ptLine; // // Verify the specified addr if appropriate // if ((dwPrivileges & LINEOPENOPTION_SINGLEADDRESS) && (ptLineClient->dwAddressID >= ptLine->dwNumAddresses)) { lResult = LINEERR_INVALADDRESSID; goto xxxLOpen_cleanup; } // // If the client has specified a non-zero ext version then // ask the driver to enable it and/or increment the ext // version count. If this fails, and we're processing a // LINEMAPPER request, then return a generic error so the // caller will try the next device. // if (dwExtVersion) { if (ptLine->dwExtVersionCount == 0) { if (ptProvider != pRemoteSP && ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL) { lResult = LINEERR_OPERATIONUNAVAIL; goto xxxLOpen_cleanup; } if (ptProvider != pRemoteSP && (lResult = CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) dwExtVersion )) != 0) { lResult = (bLineMapper ? LINEERR_OPERATIONFAILED : lResult); goto xxxLOpen_cleanup; } ptLine->dwExtVersion = dwExtVersion; } ptLineClient->dwExtVersion = dwExtVersion; ptLine->dwExtVersionCount++; bDecrExtVerCountOnError = TRUE; } // // If we're processing a LINEMAPPER request, check to see if the // device supports capabilities requested by client. If not, // return a generic error so the caller will try the next device. // if (bLineMapper) { if (ptProvider->apfn[SP_LINECONDITIONALMEDIADETECTION] == NULL || CallSP3( ptProvider->apfn[SP_LINECONDITIONALMEDIADETECTION], "lineConditionalMediaDetection", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) dwMediaModes | ptLine->dwOpenMediaModes, (ULONG_PTR) pCallParams ) != 0) { PerfBlock.dwLinesInUse--; lResult = LINEERR_OPERATIONFAILED; goto xxxLOpen_cleanup; } } // // If the client is requesting OWNER privileges (it's interested // in incoming calls of the specified media mode(s)), then check // to see if it wants incoming calls of a media mode(s) other // than that the device has already agreed to indicate, and ask // the driver if it can support looking for all of them at the // same time. If this fails, and we're processing a LINEMAPPER // request, then return a generic error so the caller will try // the next device. // if (pParams->dwPrivileges & LINECALLPRIVILEGE_OWNER) { if ((dwMediaModes & ptLine->dwOpenMediaModes) != dwMediaModes) { DWORD dwUnionMediaModes = dwMediaModes | ptLine->dwOpenMediaModes; if (ptProvider->apfn[SP_LINESETDEFAULTMEDIADETECTION]) { if ((lResult = CallSP2( ptProvider->apfn[SP_LINESETDEFAULTMEDIADETECTION], "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) dwUnionMediaModes )) != 0) { lResult = (bLineMapper ? LINEERR_OPERATIONFAILED : lResult); PerfBlock.dwLinesInUse--; goto xxxLOpen_cleanup; } } else { lResult = LINEERR_OPERATIONUNAVAIL; PerfBlock.dwLinesInUse--; goto xxxLOpen_cleanup; } ptLine->dwOpenMediaModes = dwUnionMediaModes; } } // // Set the proxy ptrs if appropriate // if (dwPrivileges & LINEOPENOPTION_PROXY) { for (i = 0; i < dwNumProxyRequestTypes; i++) { ptLine->apProxys[*(pdwProxyRequestTypes + i)] = ptLineClient; } } // // What proxys have opened now ? // for( i = LINEPROXYREQUEST_SETAGENTGROUP, dwRegisteredProxys = 0; i <= LINEPROXYREQUEST_LASTVALUE; i++ ) { if (ptLine->apProxys[i] != NULL) { // // Munge them all into a DWORD (if we ever // get more that 32 we'll have to do an // additional test) // dwRegisteredProxys |= ( 1<pNextSametLine = ptLine->ptLineClients)) { ptLineClient->pNextSametLine->pPrevSametLine = ptLineClient; } ptLine->ptLineClients = ptLineClient; ptLine->dwNumOpens++; if (bOpenedtLine) { pLookupEntry->ptLine = ptLine; ptLine->dwKey = TLINE_KEY; } ReleaseMutex (hLookupEntryMutex); bReleasetLineMutex = FALSE; // // Safely add the new tLineClient to the tLineApp's list. // { LOG((TL_TRACE, "xxxLOpen: adding ptLineClient [%p] to tLineApp's [%p] list", ptLineClient, pParams->hLineApp)); if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, ptClient ))) { if (ptLineApp->dwAPIVersion <= TAPI_VERSION3_0) { FillMemory ( ptLineClient->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS, (BYTE) 0xff ); } else { CopyMemory ( ptLineClient->adwEventSubMasks, ptLineApp->adwEventSubMasks, sizeof(DWORD) * EM_NUM_MASKS ); } if ((ptLineClient->pNextSametLineApp = ptLineApp->ptLineClients)) { ptLineClient->pNextSametLineApp->pPrevSametLineApp = ptLineClient; } ptLineApp->ptLineClients = ptLineClient; // // Note: it's important to mark the newtLineClient as // valid way down here because another thread could be // simultaneously trying to do an unconditional // DestroytLine (due to receiving a LINE_CLOSE, etc.) // and we want to make sure the tLineClient is in both // tLine's & tLineApp's lists before DestroytLine calls // DestroytLineClient which'll try to yank the tLineClient // out of these lists. // hLine = ptLineClient->hLine; ptLineClient->ptLineApp = ptLineApp; ptLineClient->dwKey = TLINECLIENT_KEY; UNLOCKTLINEAPP(ptLineApp); // // Alert other clients that another open has occured // SendMsgToLineClients( ptLine, ptLineClient, LINE_LINEDEVSTATE, LINEDEVSTATE_OPEN, 0, 0 ); // // Alert other clients that a proxy open has occured // if (dwPrivileges & LINEOPENOPTION_PROXY) { // One message per LINEPROXYREQUEST_ type for (i = 0; i < dwNumProxyRequestTypes; i++) { LOG((TL_INFO, "tell clients proxy %02X opened", *(pdwProxyRequestTypes + i) )); SendMsgToLineClients( ptLine, ptLineClient, LINE_PROXYSTATUS, LINEPROXYSTATUS_OPEN, *(pdwProxyRequestTypes + i),// LINEPROXYREQUEST_xx 0 ); } // // Now see if we have all the ones required by // TAPI3.0 for an ACD proxy // if ((dwRegisteredProxys & AllRequiredACDProxyRequests3_0) == AllRequiredACDProxyRequests3_0) { LOG((TL_INFO, "tell clients that all proxys needed " \ "for TAPI3.0 ACD are open" )); SendMsgToLineClients( ptLine, ptLineClient, LINE_PROXYSTATUS, LINEPROXYSTATUS_ALLOPENFORACD, 0, 0 ); } // // If we are given a proxy server CLSID, register // the proxy server in DS, error not considered // critical here // if (*szClsid != 0) { ptLineClient->szProxyClsid = ServerAlloc ( (_tcslen (szClsid) + 1) * sizeof(TCHAR) ); if (ptLineClient->szProxyClsid) { _tcscpy (ptLineClient->szProxyClsid, szClsid); OnProxyLineOpen (szClsid); } } } // // Fill in the return values // LOG((TL_TRACE, "xxxLOpen returning hLine of %p", hLine)); pParams->hLine = hLine; *pdwNumBytesReturned = sizeof (LINEOPEN_PARAMS); // // (Now we need to return the call params if this // is a remote client) // // This was for some 2.1 kludge which didn't make // any sense, so i've chg'd to indicate NO_DATA // so nothing gets copied back on the client side. // // DanKn, Aug 6 '98 // if (IS_REMOTE_CLIENT (ptClient)) { pParams->dwCallParamsReturnOffset = TAPI_NO_DATA; } } else { // // If here the app handle is bad, & we've some special // case cleanup to do. Since the tLineClient is not // in the tLineApp's list, we can't simply call // DestroytLine(Client) to clean things up, since the // pointer-resetting code will blow up. So we'll // grab the tLine's mutex and explicitly remove the // new tLineClient from it's list, then do a conditional // shutdown on the tLine (in case any other clients // have come along & opened it). Also deselect the // ext version and/or decrement the ext version count // as appropriate. // // Note: keep in mind that a LINE_CLOSE might be being // processed by another thread (if so, it will be // spinning on trying to destroy the tLineClient // which isn't valid at this point) // lResult = LINEERR_INVALAPPHANDLE; WaitForSingleObject (hLookupEntryMutex, INFINITE); if (ptLineClient->pNextSametLine) { ptLineClient->pNextSametLine->pPrevSametLine = ptLineClient->pPrevSametLine; } if (ptLineClient->pPrevSametLine) { ptLineClient->pPrevSametLine->pNextSametLine = ptLineClient->pNextSametLine; } else { ptLine->ptLineClients = ptLineClient->pNextSametLine; } ptLine->dwNumOpens--; if (bDecrExtVerCountOnError == TRUE) { ptLine->dwExtVersionCount--; if (ptLine->dwExtVersionCount == 0) { ptLine->dwExtVersion = 0; if (ptProvider->apfn[SP_LINESELECTEXTVERSION]) { CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) 0 ); } } } ReleaseMutex (hLookupEntryMutex); DestroytLine (ptLine, FALSE); // conditional destroy bOpenedtLine = FALSE; // so we don't do err handling below } } CloseHandle (hLookupEntryMutex); } xxxLOpen_cleanup: if (bReleasetLineMutex) { if (lResult != 0) { if (bDecrExtVerCountOnError == TRUE) { ptLine->dwExtVersionCount--; if (ptLine->dwExtVersionCount == 0) { ptLine->dwExtVersion = 0; if (ptProvider->apfn[SP_LINESELECTEXTVERSION]) { CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine, (DWORD) 0 ); } } } if (bOpenedtLine == TRUE && ptProvider->apfn[SP_LINECLOSE]) { CallSP1( ptProvider->apfn[SP_LINECLOSE], "lineClose", SP_FUNC_SYNC, (ULONG_PTR) ptLine->hdLine ); } } ReleaseMutex (hLookupEntryMutex); CloseHandle (hLookupEntryMutex); } if ((pParams->lResult = lResult) != 0) { if (ptLineClient) { DereferenceObject (ghHandleTable, ptLineClient->hLine, 1); } if (bOpenedtLine) { DereferenceObject (ghHandleTable, ptLine->hLine, 1); } } if (bFreeCallParams) { ServerFree (pCallParams); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, (bLineMapper ? "Open(LINEMAPPER)" : "Open") ); } void WINAPI LOpen( PTCLIENT ptClient, PLINEOPEN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { if (pParams->dwDeviceID != LINEMAPPER) { xxxLOpen( ptClient, pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, FALSE ); } else { // // Try to open each line device, starting with device 0, until // either we find a device that'll handle the capabilities // requested by the client or we run out of devices. If we // encounter a certain subset of parameter errors the first time // we call xxxLOpen we want to return these back to the app // immediately to aid debugging (rather than always returning // LINEMAPPERFAILED). // for( pParams->dwDeviceID = 0; pParams->dwDeviceID < TapiGlobals.dwNumLines; pParams->dwDeviceID++ ) { xxxLOpen( ptClient, pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, TRUE ); if (pParams->dwDeviceID == 0) { switch (pParams->lResult) { case LINEERR_BADDEVICEID: // 0 line devices case LINEERR_INVALAPPHANDLE: case LINEERR_INVALCALLPARAMS: case LINEERR_INVALMEDIAMODE: case LINEERR_INVALPOINTER: // no call params, etc case LINEERR_INVALPRIVSELECT: case LINEERR_REINIT: case LINEERR_UNINITIALIZED: return; default: break; } } if (pParams->lResult == 0) { break; } } if (pParams->dwDeviceID >= TapiGlobals.dwNumLines) { pParams->lResult = LINEERR_LINEMAPPERFAILED; } } } void LPark_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { // // Note: pAsyncEventMsg->dwParam1 & dwParam2 are reserved for // the request ID and result, respectively // PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam1; LPVARSTRING pNonDirAddress = (LPVARSTRING) (pNewAsyncEventMsg + 1); CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = (LPVOID) pNewAsyncEventMsg; if (pAsyncEventMsg->Param2 == 0) // success { // // Add the used size of the non-dir addr, & keep the total // length of the msg DWORD-aligned // pNewAsyncEventMsg->TotalSize += ((pNonDirAddress->dwUsedSize + TALIGN_COUNT) & TALIGN_MASK); pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // hpNonDirAddr pNewAsyncEventMsg->Param4 = pNonDirAddress->dwUsedSize; } } void WINAPI LPark( PTCLIENT ptClient, PLINEPARK_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_linePark; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwParkMode == LINEPARKMODE_DIRECTED) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDirAddressOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEPARK, // provider func index &pfnTSPI_linePark, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Park" // func name )) > 0) { LPBYTE pBuf; LPVARSTRING pNonDirAddress; if (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED) { if (pParams->dwNonDirAddressTotalSize < sizeof (VARSTRING)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LPark_return; } if (!(pBuf = ServerAlloc( (pParams->dwNonDirAddressTotalSize + sizeof (ASYNCEVENTMSG) + TALIGN_COUNT) & TALIGN_MASK ))) { lRequestID = LINEERR_NOMEM; goto LPark_return; } pNonDirAddress = (LPVARSTRING) (pBuf + sizeof (ASYNCEVENTMSG)); pNonDirAddress->dwTotalSize = pParams->dwNonDirAddressTotalSize; pNonDirAddress->dwNeededSize = pNonDirAddress->dwUsedSize = sizeof (VARSTRING); pAsyncRequestInfo->pfnPostProcess = LPark_PostProcess; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) pBuf; pAsyncRequestInfo->dwParam2 = pParams->hpNonDirAddress; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; } else if (pParams->dwParkMode == LINEPARKMODE_DIRECTED) { pNonDirAddress = (LPVARSTRING) NULL; } else { lRequestID = LINEERR_INVALPARKMODE; goto LPark_return; } pParams->lResult = CallSP5( pfnTSPI_linePark, "linePark", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (DWORD) pParams->dwParkMode, (ULONG_PTR) (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED ? NULL : pDataBuf + pParams->dwDirAddressOffset), (ULONG_PTR) pNonDirAddress ); } LPark_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Park" ); } void WINAPI LPickup( PTCLIENT ptClient, PLINEPICKUP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_linePickup; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwDestAddressOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) || ((pParams->dwGroupIDOffset != TAPI_NO_DATA) && IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwGroupIDOffset ))) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEPICKUP, // provider func index &pfnTSPI_linePickup, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "Pickup" // func name )) > 0) { PTCALL ptCall; HCALL hCall = 0; PTCALLCLIENT ptCallClient; if (CreatetCallAndClient( ptLineClient, &ptCall, &ptCallClient, NULL, &hCall, NULL ) != 0) { lRequestID = LINEERR_NOMEM; goto LPickup_return; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall; pAsyncRequestInfo->dwParam2 = pParams->hpCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP7( pfnTSPI_linePickup, "linePickup", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) hCall, (ULONG_PTR) &ptCall->hdCall, (ULONG_PTR) (pParams->dwDestAddressOffset == TAPI_NO_DATA ? 0 : pDataBuf + pParams->dwDestAddressOffset), (ULONG_PTR) (pParams->dwGroupIDOffset == TAPI_NO_DATA ? 0 : pDataBuf + pParams->dwGroupIDOffset) ); SetDrvCallFlags( hCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); } LPickup_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Pickup" ); } void WINAPI LPrepareAddToConference( PTCLIENT ptClient, PLINEPREPAREADDTOCONFERENCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdConfCall; TSPIPROC pfnTSPI_linePrepareAddToConference; DWORD objectToDereference; PTCALLCLIENT ptConfCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hConfCall, // client widget handle (LPVOID) &hdConfCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEPREPAREADDTOCONFERENCE, // provider func index &pfnTSPI_linePrepareAddToConference,// provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptConfCallClient, // context "PrepareAddToConference" // func name )) > 0) { LONG lResult; PTCALL ptConsultCall; HCALL hConsultCall; PTCALLCLIENT ptConsultCallClient; PTLINECLIENT ptLineClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset )) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LPrepareAddToConference_return; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : pDataBuf + pParams->dwCallParamsOffset); try { // // Safely get the ptLineClient // ptLineClient = ptConfCallClient->ptLineClient; // // Make sure the hConfCall is really a conf parent // { PTCALL ptCall; ptCall = (PTCALL) ptConfCallClient->ptCall; if ((ptCall->pConfList)->aptCalls[0] != ptCall) { lRequestID = LINEERR_INVALCONFCALLHANDLE; goto LPrepareAddToConference_return; } } } myexcept { // // If here the conf call was destroyed // lRequestID = LINEERR_INVALCONFCALLHANDLE; goto LPrepareAddToConference_return; } if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; if (GetLineVersions( ptLineClient, &dwAPIVersion, &dwSPIVersion ) != 0) { lRequestID = LINEERR_INVALCONFCALLHANDLE; goto LPrepareAddToConference_return; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LPrepareAddToConference_return; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( ptLineClient, &ptConsultCall, &ptConsultCallClient, pCallParamsSP, &hConsultCall, NULL ) != 0) { lRequestID = LINEERR_NOMEM; goto LPrepareAddToConference_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_linePrepareAddToConference, "linePrepareAddToConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdConfCall, (ULONG_PTR) hConsultCall, (ULONG_PTR) &ptConsultCall->hdCall, (ULONG_PTR) pCallParamsSP ); SetDrvCallFlags( hConsultCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); LPrepareAddToConference_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LPrepareAddToConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "PrepareAddToConference" ); } void WINAPI LProxyMessage( PTCLIENT ptClient, PLINEPROXYMESSAGE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_NONE, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "ProxyMessage" // func name )) == 0) { DWORD dwMsg = pParams->dwMsg, i; PTCALL ptCall; PTLINE ptLine; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg[2]; // // Verify params // try { ptLine = ptLineClient->ptLine; if (!(ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY)) { pParams->lResult = LINEERR_NOTREGISTERED; goto LProxyMessage_epilog; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LProxyMessage_epilog; } switch (dwMsg) { case LINE_AGENTSTATUS: // ignore the hCall param if (pParams->dwParam1 >= ptLine->dwNumAddresses) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSTATUS): dwParam1 " \ "bad addr ID (=x%x, num addrs=x%x)", pParams->dwParam1, ptLine->dwNumAddresses )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam2 == 0 || pParams->dwParam2 & ~AllAgentStatus) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSTATUS): dwParam2 " \ "(=x%x) bad LINEAGENTSTATUS_ flags", pParams->dwParam2 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam2 & LINEAGENTSTATUS_STATE) { if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) || pParams->dwParam3 & ~AllAgentStates) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSTATUS): " \ "dwParam3 (=x%x) bad LINEAGENTSTATE_ flags", pParams->dwParam3 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } } else if (pParams->dwParam3 != 0) { // don't bother complaining about a non-zero dwParam3 pParams->dwParam3 = 0; } break; case LINE_AGENTSPECIFIC: // ignore dwParam1, dwParam2, & dwParam3 (app-specific) if (pParams->hCall) { PTCALLCLIENT ptCallClient; if (!(ptCallClient = ReferenceCall( pParams->hCall, ptClient ))) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LProxyMessage_epilog; } ptCall = ptCallClient->ptCall; DereferenceObject (ghHandleTable, pParams->hCall, 1); goto LProxyMessage_fwdMsgToCallClients; } break; case LINE_AGENTSESSIONSTATUS: // ignore the hCall param // ignore the dwParam1 , it's the agent handle if (pParams->dwParam2 == 0 || pParams->dwParam2 & ~AllAgentSessionStatus) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSESSIONSTATUS): dwParam2 " \ "(=x%x) bad LINEAGENTSESSIONSTATUS_ flags", pParams->dwParam2 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam2 & LINEAGENTSESSIONSTATUS_STATE) { if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) || pParams->dwParam3 & ~AllAgentSessionStates) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSESSIONSTATUS): " \ "dwParam3 (=x%x) bad LINEAGENTSESSIONSTATE_ flags", pParams->dwParam3 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } } else if (pParams->dwParam3 != 0) { // don't bother complaining about a non-zero dwParam3 pParams->dwParam3 = 0; } break; case LINE_AGENTSTATUSEX: // ignore the hCall param // ignore the dwParam1 , it's the agent handle if (pParams->dwParam2 == 0 || pParams->dwParam2 & ~AllAgentStatusEx) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSTATUSEX): dwParam2 " \ "(=x%x) bad LINEAGENTSTATUSEX_ flags", pParams->dwParam2 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam2 & LINEAGENTSESSIONSTATUS_STATE) { if (!IsOnlyOneBitSetInDWORD (pParams->dwParam3) || pParams->dwParam3 & ~AllAgentStatesEx) { LOG((TL_ERROR, "ERROR: lineProxyMessage (AGENTSTATUSEX): " \ "dwParam3 (=x%x) bad LINEAGENTSTATEEX_ flags", pParams->dwParam3 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } } else if (pParams->dwParam3 != 0) { // don't bother complaining about a non-zero dwParam3 pParams->dwParam3 = 0; } break; case LINE_QUEUESTATUS: // ignore the hCall param // ignore the dwParam1 , it's the queue handle if (pParams->dwParam2 == 0 || pParams->dwParam2 & ~AllQueueStatus) { LOG((TL_ERROR, "ERROR: lineProxyMessage (QUEUESTATUS): dwParam2 " \ "(=x%x) bad LINEQUEUESTATUS_ flags", pParams->dwParam2 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam3 != 0) { // don't bother complaining about a non-zero dwParam3 pParams->dwParam3 = 0; } break; case LINE_GROUPSTATUS: // ignore the hCall param if (pParams->dwParam1 == 0 || pParams->dwParam1 & ~AllGroupStatus) { LOG((TL_ERROR, "ERROR: lineProxyMessage (GROUPSTATUS): dwParam1 " \ "(=x%x) bad LINEQUEUESTATUS_ flags", pParams->dwParam1 )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } else if (pParams->dwParam2 != 0) { // don't bother complaining about a non-zero dwParam2 pParams->dwParam2 = 0; } else if (pParams->dwParam3 != 0) { // don't bother complaining about a non-zero dwParam3 pParams->dwParam3 = 0; } break; default: LOG((TL_ERROR, "ERROR : lineProxyMessage: inval dwMsg (=x%x)", pParams->dwMsg )); pParams->lResult = LINEERR_INVALPARAM; goto LProxyMessage_epilog; } // switch (dwMsg) // // Fwd this msg on to all line's clients who say they support // >= TAPI_VERSION2_0 (not including the proxy's line client) // if ((pParams->lResult = GetLineClientListFromLine( ptLine, &pClientList )) != 0) { goto LProxyMessage_epilog; } msg->TotalSize = sizeof (ASYNCEVENTMSG); msg->fnPostProcessProcHandle = 0; msg->Msg = dwMsg; msg->Param1 = pParams->dwParam1; msg->Param2 = pParams->dwParam2; msg->Param3 = pParams->dwParam3; msg->Param4 = 0; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTLINECLIENT ptLineClient2 = (PTLINECLIENT) pClientList->aEntries[i]; if (ptLineClient2 != ptLineClient) { try { if (ptLineClient2->ptLineApp->dwAPIVersion >= TAPI_VERSION2_0) { if (FMsgDisabled ( ptLineClient2->ptLineApp->dwAPIVersion, ptLineClient2->adwEventSubMasks, dwMsg, pParams->dwParam1 )) { continue; } msg->InitContext = ptLineClient2->ptLineApp->InitContext; msg->hDevice = ptLineClient2->hRemoteLine; msg->OpenContext = ptLineClient2->OpenContext; // // Now a final check to make sure all the // params are valid before sending the msg // { PTCLIENT ptClient = ptLineClient2->ptClient; if (ptLineClient2->dwKey == TLINECLIENT_KEY) { WriteEventBuffer (ptClient, msg); } } } } myexcept { // just continue } } } goto LProxyMessage_freeClientList; // // Fwd this msg on to all call's clients who say they support // >= TAPI_VERSION2_0 (not including the proxy's line client) // LProxyMessage_fwdMsgToCallClients: if ((pParams->lResult = GetCallClientListFromCall( ptCall, &pClientList )) != 0) { goto LProxyMessage_epilog; } msg->TotalSize = sizeof (ASYNCEVENTMSG) + sizeof (HCALLHUB); msg->fnPostProcessProcHandle = 0; msg->Msg = dwMsg; msg->Param1 = pParams->dwParam1; msg->Param2 = pParams->dwParam2; msg->Param3 = pParams->dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pClientList->aEntries[i]; try { if (ptCallClient->hCall != pParams->hCall) { PTLINEAPP ptLineApp; ptLineApp = ptCallClient->ptLineClient->ptLineApp; if (ptLineApp->dwAPIVersion >= TAPI_VERSION2_0) { if (FMsgDisabled ( ptCallClient->ptLineClient->ptLineApp->dwAPIVersion, ptCallClient->adwEventSubMasks, dwMsg, pParams->dwParam1 )) { continue; } msg->InitContext = ptLineApp->InitContext; msg->hDevice = ptCallClient->hCall; msg->OpenContext = ptCallClient->ptLineClient->OpenContext; msg->Param4 = ptCallClient->ptLineClient->hRemoteLine; *((LPHCALLHUB)(&msg->Param4 + 1)) = (ptCallClient->ptCallHubClient)? ptCallClient->ptCallHubClient->hCallHub : (HCALLHUB)(ULONG_PTR)NULL; // // Now a final check to make sure all the // params are valid before sending the msg // { PTCLIENT ptClient = ptCallClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, msg); } } } } } myexcept { // just continue } } LProxyMessage_freeClientList: if (pClientList != &clientList) { ServerFree (pClientList); } } LProxyMessage_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "ProxyMessage" ); } void WINAPI LProxyResponse( PTCLIENT ptClient, PLINEPROXYRESPONSE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT pProxy; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_NONE, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pProxy, // context "ProxyResponse" // func name )) == 0) { PASYNCREQUESTINFO pAsyncRequestInfo; // // The dwInstance param is the dwLocalRequestID for the // AsyncRequestInfo struct. Note that the dwKey value of // this struct was reset to == pProxy->hLine in // CreateProxyRequest(). // if (!(pAsyncRequestInfo = ReferenceObject( ghHandleTable, pParams->dwInstance, pParams->hLine ))) { pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_Epilog; } // // Safely remove the proxy request from the list of pending requests // if (WaitForExclusiveLineClientAccess (pProxy)) { if (pAsyncRequestInfo->dwKey == pParams->hLine) { pAsyncRequestInfo->dwKey = TASYNC_KEY; if (pAsyncRequestInfo->dwParam5) { ((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5)->dwParam4 = pAsyncRequestInfo->dwParam4; } if (pAsyncRequestInfo->dwParam4) { ((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam4)->dwParam5 = pAsyncRequestInfo->dwParam5; } else { pProxy->pPendingProxyRequests = (PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5; } UNLOCKTLINECLIENT(pProxy); } else { // // Another thread must have simultaneously been // completing this request, so fail gracefully // UNLOCKTLINECLIENT(pProxy); DereferenceObject (ghHandleTable, pParams->dwInstance, 1); pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_Epilog; } } else { DereferenceObject (ghHandleTable, pParams->dwInstance, 1); pParams->dwResult = LINEERR_INVALLINEHANDLE; goto LProxyResponse_Epilog; } // // If this is a proxy request where there's data to be returned // to the client (aside from the result) then we want to alloc // a buffer & fill it with the data. We'll make it look like a // DevSpecific request that just completed, and have the DevSpecfic // post process routine deal with it. // // Make sure buffers are 64-bit aligned // if (pParams->dwProxyResponseOffset != TAPI_NO_DATA && pParams->dwResult == 0) { DWORD dwSize; LPBYTE pBuf; LPLINEPROXYREQUEST pProxyRequest = (LPLINEPROXYREQUEST) ( pDataBuf + pParams->dwProxyResponseOffset ); switch (pProxyRequest->dwRequestType) { case LINEPROXYREQUEST_AGENTSPECIFIC: { dwSize = pProxyRequest->AgentSpecific.dwSize; if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8) ))) { pParams->dwResult = LINEERR_NOMEM; goto LProxyResponse_completeRequest; } CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pProxyRequest->AgentSpecific.Params, dwSize ); break; } case LINEPROXYREQUEST_CREATEAGENT: case LINEPROXYREQUEST_CREATEAGENTSESSION: { // // Proces both of these together. the handle is // the first member of both structures // dwSize = sizeof (HAGENT); pBuf = ServerAlloc( sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8) ); if ( NULL == pBuf ) { pParams->dwResult = LINEERR_NOMEM; goto LProxyResponse_completeRequest; } CopyMemory( pBuf + sizeof(ASYNCEVENTMSG), &(pProxyRequest->CreateAgent.hAgent), dwSize ); break; } case LINEPROXYREQUEST_GETQUEUELIST: { dwSize = pProxyRequest->GetQueueList.QueueList.dwUsedSize; pBuf = ServerAlloc( sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8) ); if ( NULL == pBuf ) { pParams->dwResult = LINEERR_NOMEM; goto LProxyResponse_completeRequest; } CopyMemory( pBuf + sizeof(ASYNCEVENTMSG), &(pProxyRequest->GetQueueList.QueueList), dwSize ); break; } case LINEPROXYREQUEST_GETGROUPLIST: { dwSize = pProxyRequest->GetGroupList.GroupList.dwUsedSize; pBuf = ServerAlloc( sizeof(ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8) ); if ( NULL == pBuf ) { pParams->dwResult = LINEERR_NOMEM; goto LProxyResponse_completeRequest; } CopyMemory( pBuf + sizeof(ASYNCEVENTMSG), &(pProxyRequest->GetGroupList.GroupList), dwSize ); break; } case LINEPROXYREQUEST_GETAGENTCAPS: case LINEPROXYREQUEST_GETAGENTSTATUS: case LINEPROXYREQUEST_GETAGENTACTIVITYLIST: case LINEPROXYREQUEST_GETAGENTGROUPLIST: case LINEPROXYREQUEST_GETAGENTINFO: case LINEPROXYREQUEST_GETAGENTSESSIONLIST: case LINEPROXYREQUEST_SETAGENTSESSIONSTATE: case LINEPROXYREQUEST_GETAGENTSESSIONINFO: case LINEPROXYREQUEST_GETQUEUEINFO: { dwSize = pProxyRequest->GetAgentCaps.AgentCaps.dwUsedSize; if (!(pBuf = ServerAlloc( sizeof (ASYNCEVENTMSG) + ((dwSize + 7) & 0xfffffff8) ))) { pParams->dwResult = LINEERR_NOMEM; goto LProxyResponse_completeRequest; } CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), &pProxyRequest->GetAgentCaps.AgentCaps, dwSize ); break; } default: LOG((TL_ERROR, "LProxyResponse: unrecognized proxy request type (x%x)", pProxyRequest->dwRequestType )); pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_completeRequest; } // // Check to see if the size of the data we're copying back is // larger than the size of client's buffer // if (dwSize > pAsyncRequestInfo->dwParam2) { LOG((TL_ERROR, "LProxyResponse: data size too large (exp<=x%x,act=x%x)", pAsyncRequestInfo->dwParam2, dwSize )); ServerFree (pBuf); pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_completeRequest; } pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam2 = dwSize; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf; } // // Now call the deferred completion proc with the "request id" // & result, just like a provider would // LProxyResponse_completeRequest: CompletionProcSP( pAsyncRequestInfo->dwLocalRequestID, pParams->dwResult ); DereferenceObject (ghHandleTable, pParams->dwInstance, 1); } LProxyResponse_Epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "ProxyResponse" ); } void WINAPI LRedirect( PTCLIENT ptClient, PLINEREDIRECT_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineRedirect; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEREDIRECT, // provider func index &pfnTSPI_lineRedirect, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Redirect" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineRedirect, "lineRedirect", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset), (DWORD) pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Redirect" ); } void WINAPI LRegisterRequestRecipient( PTCLIENT ptClient, PLINEREGISTERREQUESTRECIPIENT_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTLINEAPP ptLineApp; if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, ptClient ))) { DWORD dwRequestMode = pParams->dwRequestMode; if (!(dwRequestMode & (LINEREQUESTMODE_MAKECALL | LINEREQUESTMODE_MEDIACALL)) || (dwRequestMode & (~(LINEREQUESTMODE_MAKECALL | LINEREQUESTMODE_MEDIACALL)))) { pParams->lResult = LINEERR_INVALREQUESTMODE; goto LRegisterRequestRecipient_myReleaseMutex; } if (pParams->bEnable) { // // If app wants MEDIACALL requests see if already registered // if ((dwRequestMode & LINEREQUESTMODE_MEDIACALL) && ptLineApp->bReqMediaCallRecipient) { LOG((TL_ERROR, "App is already registered for mediacall")); pParams->lResult = LINEERR_OPERATIONFAILED; goto LRegisterRequestRecipient_myReleaseMutex; } // // If app wants MAKECALL requests see if already registered, // then prepare a request recipient object & add it to the // global list // if (dwRequestMode & LINEREQUESTMODE_MAKECALL) { if (!ptLineApp->pRequestRecipient) { // // Add to request recipient list // PTREQUESTRECIPIENT pRequestRecipient; if (!(pRequestRecipient= (PTREQUESTRECIPIENT) ServerAlloc( sizeof (TREQUESTRECIPIENT) ))) { LOG((TL_ERROR, "Failed alloc for requestrecip struct")); pParams->lResult = LINEERR_NOMEM; goto LRegisterRequestRecipient_myReleaseMutex; } pRequestRecipient->ptLineApp = ptLineApp; pRequestRecipient->dwRegistrationInstance = pParams->dwRegistrationInstance; EnterCriticalSection (&gPriorityListCritSec); if ((pRequestRecipient->pNext = TapiGlobals.pRequestRecipients)) { pRequestRecipient->pNext->pPrev = pRequestRecipient; } TapiGlobals.pRequestRecipients = pRequestRecipient; LeaveCriticalSection (&gPriorityListCritSec); ptLineApp->pRequestRecipient = pRequestRecipient; TapiGlobals.pHighestPriorityRequestRecipient = GetHighestPriorityRequestRecipient(); if (TapiGlobals.pRequestMakeCallList) { NotifyHighestPriorityRequestRecipient(); } } else // already registered { LOG((TL_ERROR, "App is already registered for makecall")); pParams->lResult = LINEERR_OPERATIONFAILED; goto LRegisterRequestRecipient_myReleaseMutex; } } // // Now register app for MEDIACALL reqs as appropriate // ptLineApp->bReqMediaCallRecipient = (dwRequestMode & LINEREQUESTMODE_MEDIACALL ? 1 : ptLineApp->bReqMediaCallRecipient); } else { // // If apps doesn't want MEDIACALL requests see if not registered // if ((dwRequestMode & LINEREQUESTMODE_MEDIACALL) && !ptLineApp->bReqMediaCallRecipient) { LOG((TL_ERROR, "App is not registered for mediacall")); pParams->lResult = LINEERR_OPERATIONFAILED; goto LRegisterRequestRecipient_myReleaseMutex; } // // If app doesn't want MAKECALL requests see if already // registered, then remove it's request recipient object // from the global list // if (dwRequestMode & LINEREQUESTMODE_MAKECALL) { if (ptLineApp->pRequestRecipient) { // // Remove from request recipient list // PTREQUESTRECIPIENT pRequestRecipient = ptLineApp->pRequestRecipient; EnterCriticalSection (&gPriorityListCritSec); if (pRequestRecipient->pNext) { pRequestRecipient->pNext->pPrev = pRequestRecipient->pPrev; } if (pRequestRecipient->pPrev) { pRequestRecipient->pPrev->pNext = pRequestRecipient->pNext; } else { TapiGlobals.pRequestRecipients = pRequestRecipient->pNext; } LeaveCriticalSection (&gPriorityListCritSec); ServerFree (pRequestRecipient); ptLineApp->pRequestRecipient = NULL; // // Reset the highest priority request recipient, then check // to see if there's any pending request make calls // TapiGlobals.pHighestPriorityRequestRecipient = GetHighestPriorityRequestRecipient(); if (TapiGlobals.pRequestMakeCallList) { if (TapiGlobals.pHighestPriorityRequestRecipient) { NotifyHighestPriorityRequestRecipient(); } else { // // We couldn't start a request recipient so // nuke all pending request make calls // PTREQUESTMAKECALL pRequestMakeCall, pNextRequestMakeCall; pRequestMakeCall = TapiGlobals.pRequestMakeCallList; TapiGlobals.pRequestMakeCallList = TapiGlobals.pRequestMakeCallListEnd = NULL; while (pRequestMakeCall) { pNextRequestMakeCall = pRequestMakeCall->pNext; ServerFree (pRequestMakeCall); pRequestMakeCall = pNextRequestMakeCall; } LOG((TL_INFO, "LRegisterRequestRecipient: deleting " \ "pending MakeCall requests" )); } } } else // not registered { LOG((TL_ERROR, "App is not registered for makecall")); pParams->lResult = LINEERR_OPERATIONFAILED; } } // // Now deregister app for MEDIACALL reqs as appropriate // ptLineApp->bReqMediaCallRecipient = (dwRequestMode & LINEREQUESTMODE_MEDIACALL ? 0 : ptLineApp->bReqMediaCallRecipient); } LRegisterRequestRecipient_myReleaseMutex: UNLOCKTLINEAPP(ptLineApp); } else { pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ? LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE); } #if DBG { char szResult[32]; LOG((TL_TRACE, "lineRegisterRequestRecipient: exit, returning %s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineRegisterRequestRecipient: exit, returning x%x", pParams->lResult )); #endif return; } void WINAPI LReleaseUserUserInfo( PTCLIENT ptClient, PLINEDIAL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineReleaseUserUserInfo; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINERELEASEUSERUSERINFO, // provider func index &pfnTSPI_lineReleaseUserUserInfo, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "ReleaseUserUserInfo" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineReleaseUserUserInfo, "lineReleaseUserUserInfo", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "ReleaseUserUserInfo" ); } void LRemoveFromConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { if (pAsyncEventMsg->Param2 == 0) { PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1; SetCallConfList (ptCall, (PTCONFERENCELIST) NULL, FALSE); } } void WINAPI LRemoveFromConference( PTCLIENT ptClient, PLINEREMOVEFROMCONFERENCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineRemoveFromConference; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEREMOVEFROMCONFERENCE,// provider func index &pfnTSPI_lineRemoveFromConference, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "RemoveFromConference" // func name )) > 0) { PTCALL ptCall; // // Safely make sure the call is currently conferenced & // that it's not a conf parent // try { PTCONFERENCELIST pConfList; ptCall = ptCallClient->ptCall; pConfList = ptCall->pConfList; if (!pConfList || (pConfList == (LPVOID) LongToPtr(0xffffffff)) || (pConfList->aptCalls[0] == ptCall)) { lRequestID = LINEERR_INVALCALLSTATE; goto LRemoveFromConference_return; } } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LRemoveFromConference_return; } // // Set up the async request struct & call the SP // pAsyncRequestInfo->pfnPostProcess = LRemoveFromConference_PostProcess; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall; pParams->lResult = CallSP2( pfnTSPI_lineRemoveFromConference, "lineRemoveFromConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall ); } LRemoveFromConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "RemoveFromConference" ); } void WINAPI LSecureCall( PTCLIENT ptClient, PLINESECURECALL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; DWORD objectToDereference; TSPIPROC pfnTSPI_lineSecureCall; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESECURECALL, // provider func index &pfnTSPI_lineSecureCall, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SecureCall" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineSecureCall, "lineSecureCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SecureCall" ); } void WINAPI LSelectExtVersion( PTCLIENT ptClient, PLINESELECTEXTVERSION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bCloseMutex2; HANDLE hMutex, hMutex2; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSelectExtVersion; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESELECTEXTVERSION, // provider func index &pfnTSPI_lineSelectExtVersion, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SelectExtVersion" // func name )) == 0) { if (WaitForExclusivetLineAccess( ptLineClient->ptLine, &hMutex2, &bCloseMutex2, INFINITE )) { if (IsValidLineExtVersion( ptLineClient->ptLine->dwDeviceID, pParams->dwExtVersion )) { if (pParams->dwExtVersion) { if (ptLineClient->ptLine->dwExtVersionCount || (pParams->lResult = CallSP2( pfnTSPI_lineSelectExtVersion, "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) pParams->dwExtVersion )) == 0) { ptLineClient->dwExtVersion = ptLineClient->ptLine->dwExtVersion = pParams->dwExtVersion; ptLineClient->ptLine->dwExtVersionCount++; } } else if (ptLineClient->ptLine->dwExtVersionCount) { if (--ptLineClient->ptLine->dwExtVersionCount == 0) { CallSP2( pfnTSPI_lineSelectExtVersion, "lineSelectExtVersion", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) 0 ); ptLineClient->ptLine->dwExtVersion = 0; } ptLineClient->dwExtVersion = 0; } } else { pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION; } MyReleaseMutex (hMutex2, bCloseMutex2); } else { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetDefaultMediaDetection" ); } void WINAPI LSendUserUserInfo( PTCLIENT ptClient, PLINESENDUSERUSERINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSendUserUserInfo; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwUserUserInfoOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwUserUserInfoOffset, sizeof(DWORD), "LSendUserUserInfo", "pParams->UserUserInfo" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESENDUSERUSERINFO, // provider func index &pfnTSPI_lineSendUserUserInfo, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SendUserUserInfo" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineSendUserUserInfo, "lineSendUserUserInfo", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwUserUserInfoOffset), (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 : pParams->dwSize) ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SendUserUserInfo" ); } void WINAPI LSetAppPriority( PTCLIENT ptClient, PLINESETAPPPRIORITY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwMediaMode = pParams->dwMediaMode, dwRequestMode = pParams->dwRequestMode, dwPriority = pParams->dwPriority; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwAppNameOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (dwMediaMode == 0) { if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) && (dwRequestMode != LINEREQUESTMODE_MEDIACALL)) { pParams->lResult = LINEERR_INVALREQUESTMODE; goto LSetAppPriority_return; } } else if ( dwMediaMode & ~AllMediaModes2_1 ) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetAppPriority_return; } if ((dwPriority & 0xfffffffe)) { pParams->lResult = LINEERR_INVALPARAM; goto LSetAppPriority_return; } if ((dwMediaMode & 0x00ffffff) || (dwMediaMode == 0)) { WCHAR szModuleName[MAX_PATH]; WCHAR *pszCurrentPriorityList, **ppszCurrentPriorityList; WCHAR *pszLocationInPriorityList; DWORD dwAppNameLength; DWORD dwCount; szModuleName[0] = '"'; wcsncpy(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset), MAX_PATH - 2); szModuleName[MAX_PATH - 1] = '\0'; _wcsupr(szModuleName + 1); dwAppNameLength = (DWORD) lstrlenW(szModuleName); // // Enter the pri list critical section before we start munging // EnterCriticalSection (&gPriorityListCritSec); // // Determine which of the priority lists we want to look at // if (dwMediaMode & 0x00ffffff) { pszCurrentPriorityList = NULL; ppszCurrentPriorityList = NULL; for( dwCount = 0; dwCount < TapiGlobals.dwUsedPriorityLists; dwCount++ ) { // did we find it? if (dwMediaMode == TapiGlobals.pPriLists[dwCount].dwMediaModes) { ppszCurrentPriorityList = &(TapiGlobals.pPriLists[dwCount].pszPriList); pszCurrentPriorityList = *ppszCurrentPriorityList; break; } } // did we find it? if (NULL == ppszCurrentPriorityList) { // are we setting if (pParams->dwPriority != 0) { // do we need to alloc more space? if (TapiGlobals.dwUsedPriorityLists == TapiGlobals.dwTotalPriorityLists) { PRILISTSTRUCT * pNewList; pNewList = (PRILISTSTRUCT *)ServerAlloc( sizeof (PRILISTSTRUCT) * TapiGlobals.dwTotalPriorityLists * 2 ); if (NULL == pNewList) { LOG((TL_ERROR, "Alloc failed in LineSetAppPriority")); pParams->lResult = LINEERR_NOMEM; goto LSetAppPriority_return; } CopyMemory( pNewList, TapiGlobals.pPriLists, sizeof( PRILISTSTRUCT ) * TapiGlobals.dwUsedPriorityLists ); ServerFree(TapiGlobals.pPriLists); TapiGlobals.pPriLists = pNewList; TapiGlobals.dwTotalPriorityLists *= 2; } TapiGlobals.pPriLists[TapiGlobals.dwUsedPriorityLists]. dwMediaModes = dwMediaMode; ppszCurrentPriorityList = &(TapiGlobals.pPriLists [TapiGlobals.dwUsedPriorityLists].pszPriList); pszCurrentPriorityList = *ppszCurrentPriorityList; TapiGlobals.dwUsedPriorityLists++; } } } else { ppszCurrentPriorityList = (dwRequestMode==LINEREQUESTMODE_MAKECALL ? &TapiGlobals.pszReqMakeCallPriList : &TapiGlobals.pszReqMediaCallPriList); pszCurrentPriorityList = *ppszCurrentPriorityList; } LOG((TL_INFO, "LSetAppPri: priList=%ls", (pszCurrentPriorityList ? pszCurrentPriorityList : L"") )); // // Add app to priority list // if (pParams->dwPriority) { if (pszCurrentPriorityList && (pszLocationInPriorityList = wcsstr( pszCurrentPriorityList, szModuleName ))) { // // App already in list. If app not currently at front of // list then move it to front. // if (pszLocationInPriorityList != pszCurrentPriorityList) { MoveMemory( pszCurrentPriorityList + dwAppNameLength, pszCurrentPriorityList, (pszLocationInPriorityList - pszCurrentPriorityList) * sizeof(WCHAR) ); wcscpy(pszCurrentPriorityList, szModuleName); pszCurrentPriorityList[dwAppNameLength] = '"'; } } else { // // App not in list, so create a new list // WCHAR *pszNewPriorityList; if (!(pszNewPriorityList = ServerAlloc( sizeof(WCHAR) * (dwAppNameLength + (pszCurrentPriorityList ? lstrlenW(pszCurrentPriorityList) : 0) + 1) // for terminating NULL ))) { pParams->lResult = LINEERR_NOMEM; } else { wcscpy(pszNewPriorityList, szModuleName); if (pszCurrentPriorityList) { wcscat(pszNewPriorityList, pszCurrentPriorityList); ServerFree (pszCurrentPriorityList); } *ppszCurrentPriorityList = pszNewPriorityList; } } } // // Remove app from priority list for specified media mode // // Note: We currently do not alloc a smaller buffer to store // the new list in, we just use the existing one. // else { if (pszCurrentPriorityList && (pszLocationInPriorityList = wcsstr( pszCurrentPriorityList, szModuleName ))) { if (*(pszLocationInPriorityList + dwAppNameLength) != 0) { // // This is not the last app in the list, so move // following apps up one notch in the list // wcscpy( pszLocationInPriorityList, pszLocationInPriorityList + dwAppNameLength ); } else if (pszLocationInPriorityList == pszCurrentPriorityList) { // // This is the only app in the list, so free the buffer // & set the global pointer to NULL // ServerFree (pszCurrentPriorityList); *ppszCurrentPriorityList = NULL; } else { // // This is the last app in the list, so just mark this as // the end of the list // *pszLocationInPriorityList = 0; } } } // // We're done munging, so leave the pri list crit sec // LeaveCriticalSection (&gPriorityListCritSec); } LSetAppPriority_return: LOG((TL_TRACE, "LineEpilogSync (lineSetAppPriority) exit, returning x%x", pParams->lResult )); } void WINAPI LSetAgentActivity( PTCLIENT ptClient, PLINESETAGENTACTIVITY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentActivity" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, pParams->dwAddressID, LINEPROXYREQUEST_SETAGENTACTIVITY, &pProxy, &dwDeviceID, 0 // API ver wasn't checked in 2.0 ))) { lRequestID = lResult; goto LSetAgentActivity_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTACTIVITY, 2 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentActivity_epilog; } pProxyRequestWrapper->ProxyRequest.SetAgentActivity.dwAddressID = pParams->dwAddressID; pProxyRequestWrapper->ProxyRequest.SetAgentActivity.dwActivityID = pParams->dwActivityID; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentActivity_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETAGENTACTIVITY], "lineSetAgentActivity", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (DWORD) pParams->dwActivityID ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentActivity_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentActivity" ); } void WINAPI LSetAgentGroup( PTCLIENT ptClient, PLINESETAGENTGROUP_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentGroup" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; LPLINEAGENTGROUPLIST pGroupList = (LPLINEAGENTGROUPLIST) (pDataBuf + pParams->dwAgentGroupListOffset); // // Verify size/offset/string params given our input buffer/size // if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwAgentGroupListOffset )) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LSetAgentGroup_epilog; } // // Param verification... // { DWORD dwTotalSize = pGroupList->dwTotalSize; if (dwTotalSize < sizeof (LINEAGENTGROUPLIST)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LSetAgentGroup_epilog; } if (ISBADSIZEOFFSET( dwTotalSize, sizeof (LINEAGENTGROUPLIST), pGroupList->dwListSize, pGroupList->dwListOffset, guiAlignmentFaultEnabled? sizeof(DWORD) : 0, "lineSetAgentGroup", "List" )) { lRequestID = LINEERR_INVALAGENTGROUP; goto LSetAgentGroup_epilog; } if (pGroupList->dwNumEntries > ((dwTotalSize - sizeof (LINEAGENTGROUPLIST)) / sizeof (LINEAGENTGROUPENTRY))) { lRequestID = LINEERR_INVALAGENTGROUP; goto LSetAgentGroup_epilog; } } if ((lResult = FindProxy( ptLineClient, pParams->dwAddressID, LINEPROXYREQUEST_SETAGENTGROUP, &pProxy, &dwDeviceID, 0 // API ver wasn't checked in 2.0 ))) { lRequestID = lResult; goto LSetAgentGroup_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTGROUP, sizeof (DWORD) + pGroupList->dwTotalSize, pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentGroup_epilog; } pProxyRequestWrapper->ProxyRequest.SetAgentGroup.dwAddressID = pParams->dwAddressID; CopyMemory( &pProxyRequestWrapper->ProxyRequest.SetAgentGroup.GroupList, pGroupList, pGroupList->dwTotalSize ); if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentGroup_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETAGENTGROUP], "lineSetAgentGroup", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) pGroupList ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentGroup_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentGroup" ); } void WINAPI LSetAgentMeasurementPeriod( PTCLIENT ptClient, PLINESETAGENTMEASUREMENTPERIOD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentMeasurementPeriod" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LSetAgentMeasurementPeriod_epilog; } // Measurement period must be > 0 if (pParams->dwMeasurementPeriod == 0) { lRequestID = LINEERR_INVALPARAM; goto LSetAgentMeasurementPeriod_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD, sizeof (DWORD) + sizeof (HAGENT), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentMeasurementPeriod_epilog; } pProxyRequestWrapper->ProxyRequest. SetAgentMeasurementPeriod.hAgent = pParams->hAgent; pProxyRequestWrapper->ProxyRequest. SetAgentMeasurementPeriod.dwMeasurementPeriod = pParams->dwMeasurementPeriod; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentMeasurementPeriod_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETAGENTMEASUREMENTPERIOD], "lineSetAgentMeasurementPeriod", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->hAgent, (DWORD) pParams->dwMeasurementPeriod ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentMeasurementPeriod_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentMeasurementPeriod" ); } void WINAPI LSetAgentSessionState( PTCLIENT ptClient, PLINESETAGENTSESSIONSTATE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentSessionState" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; DWORD dwAgentState = pParams->dwAgentState; DWORD dwNextAgentState = pParams->dwNextAgentState; PTLINECLIENT pProxy; // // Param verification... // if (dwAgentState == 0 && dwNextAgentState == 0) { lRequestID = LINEERR_INVALAGENTSESSIONSTATE; goto LSetAgentSessionState_epilog; } if (dwAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwAgentState) || dwAgentState & ~AllAgentSessionStates)) { lRequestID = LINEERR_INVALAGENTSESSIONSTATE; goto LSetAgentSessionState_epilog; } if (dwNextAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwNextAgentState) || dwNextAgentState & ~AllAgentSessionStates)) { lRequestID = LINEERR_INVALAGENTSESSIONSTATE; goto LSetAgentSessionState_epilog; } if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_SETAGENTSESSIONSTATE, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LSetAgentSessionState_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTSESSIONSTATE, 2 * sizeof (DWORD) + sizeof (HAGENT), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentSessionState_epilog; } pProxyRequestWrapper->ProxyRequest. SetAgentSessionState.hAgentSession = pParams->hAgentSession; pProxyRequestWrapper->ProxyRequest. SetAgentSessionState.dwAgentSessionState = dwAgentState; pProxyRequestWrapper->ProxyRequest. SetAgentSessionState.dwNextAgentSessionState = dwNextAgentState; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentSessionState_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINESETAGENTSESSIONSTATE], "lineSetAgentSessionState", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->hAgentSession, (DWORD) pParams->dwAgentState, (DWORD) pParams->dwNextAgentState ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentSessionState_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentSessionState" ); } void WINAPI LSetAgentState( PTCLIENT ptClient, PLINESETAGENTSTATE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentState" // func name )) > 0) { LONG lResult; DWORD dwDeviceID, dwAddressID = pParams->dwAddressID, dwAgentState = pParams->dwAgentState, dwNextAgentState = pParams->dwNextAgentState; PTLINECLIENT pProxy; // // Param verification... // if (dwAgentState == 0 && dwNextAgentState == 0) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentState_epilog; } if (dwAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwAgentState) || dwAgentState & ~AllAgentStates)) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentState_epilog; } if (dwNextAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwNextAgentState) || dwNextAgentState & ~AllAgentStates)) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentState_epilog; } if ((lResult = FindProxy( ptLineClient, dwAddressID, LINEPROXYREQUEST_SETAGENTSTATE, &pProxy, &dwDeviceID, 0 // API ver wasn't checked in 2.0 ))) { lRequestID = lResult; goto LSetAgentState_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTSTATE, 3 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentState_epilog; } pProxyRequestWrapper->ProxyRequest.SetAgentState.dwAddressID = dwAddressID; pProxyRequestWrapper->ProxyRequest.SetAgentState.dwAgentState = dwAgentState; pProxyRequestWrapper->ProxyRequest.SetAgentState.dwNextAgentState = dwNextAgentState; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentState_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINESETAGENTSTATE], "lineSetAgentState", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) dwAddressID, (DWORD) dwAgentState, (DWORD) dwNextAgentState ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentState_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentState" ); } void WINAPI LSetAgentStateEx( PTCLIENT ptClient, PLINESETAGENTSTATEEX_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetAgentStateEx" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; DWORD dwAgentState = pParams->dwAgentState; DWORD dwNextAgentState = pParams->dwNextAgentState; PTLINECLIENT pProxy; // // Param verification... // if (dwAgentState == 0 && dwNextAgentState == 0) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentStateEx_epilog; } if (dwAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwAgentState) || dwAgentState & ~AllAgentStatesEx)) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentStateEx_epilog; } if (dwNextAgentState != 0 && (!IsOnlyOneBitSetInDWORD (dwNextAgentState) || dwNextAgentState & ~AllAgentStatesEx)) { lRequestID = LINEERR_INVALAGENTSTATE; goto LSetAgentStateEx_epilog; } // // Find Proxy // if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_SETAGENTSTATEEX, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LSetAgentStateEx_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETAGENTSTATEEX, 2 * sizeof (DWORD) + sizeof (HAGENT), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetAgentStateEx_epilog; } pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.hAgent = pParams->hAgent; pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.dwAgentState = dwAgentState; pProxyRequestWrapper->ProxyRequest.SetAgentStateEx.dwNextAgentState = dwNextAgentState; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentStateEx_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINESETAGENTSTATEEX], "lineSetAgentStateEx", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->hAgent, (DWORD) dwAgentState, (DWORD) dwNextAgentState ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetAgentStateEx_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetAgentStateEx" ); } void WINAPI LSetAppSpecific( PTCLIENT ptClient, PLINESETAPPSPECIFIC_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetAppSpecific; DWORD objectToDereference; PTCALLCLIENT ptCallClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETAPPSPECIFIC, // provider func index &pfnTSPI_lineSetAppSpecific,// provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetAppSpecific" // func name )) == 0) { pParams->lResult = CallSP2( pfnTSPI_lineSetAppSpecific, "lineSetAppSpecific", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) pParams->dwAppSpecific ); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetAppSpecific" ); } void WINAPI LSetCallData( PTCLIENT ptClient, PLINESETCALLDATA_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetCallData; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwCallDataSize, pParams->dwCallDataOffset, sizeof(DWORD), "LSetCallData", "pParams->CallData" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETCALLDATA, // provider func index &pfnTSPI_lineSetCallData, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetCallData" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineSetCallData, "lineSetCallData", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pParams->dwCallDataSize ? pDataBuf + pParams->dwCallDataOffset : NULL), (DWORD) pParams->dwCallDataSize ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetCallData" ); } void WINAPI LSetCallHubTracking( PTCLIENT ptClient, PLINESETCALLHUBTRACKING_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetCallHubTracking; DWORD objectToDereference; PTLINECLIENT ptLineClient; // // Verify size/offset/string params given our input buffer/size // if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwTrackingInfoOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult =LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETCALLHUBTRACKING, // provider func index &pfnTSPI_lineSetCallHubTracking,// provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetCallHubTracking" // func name )) == 0 || (pParams->lResult == LINEERR_OPERATIONUNAVAIL)) { BOOL bOwnMutex, bSetSPTracking; DWORD dwNewSPTracking; PTLINE ptLine; PTLINELOOKUPENTRY pLookupEntry; LPLINECALLHUBTRACKINGINFO pTrackingInfo; if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { pParams->lResult = 0; pfnTSPI_lineSetCallHubTracking = (TSPIPROC) NULL; } // // Check validity of tracking info structure // pTrackingInfo = (LPLINECALLHUBTRACKINGINFO) (pDataBuf + pParams->dwTrackingInfoOffset); if (pTrackingInfo->dwTotalSize < sizeof (LINECALLHUBTRACKINGINFO)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LSetCallHubTracking_epilog; } // // Check for invalid options // switch (pTrackingInfo->dwCurrentTracking) { case LINECALLHUBTRACKING_NONE: case LINECALLHUBTRACKING_ALLCALLS: break; case (LINECALLHUBTRACKING_ALLCALLS |LINECALLHUBTRACKING_PROVIDERLEVEL): if (!pfnTSPI_lineSetCallHubTracking) { pParams->lResult = LINEERR_INVALPARAM; goto LSetCallHubTracking_epilog; } break; default: pParams->lResult = LINEERR_INVALPARAM; goto LSetCallHubTracking_epilog; } // // Safely get exclusive access to the tLine, then check if: // // * new tLineClient tracking state equals current tLineClient // tracking state, in which case we can simply return success, or // // * new tLineClient tracking state has no net effect on the // driver's line tracking state due to the existing number // of trackers, in which case we can simply adjust the current // number of trackers and return success, or // // * (otherwise) we need to inform driver of new tracking state // bOwnMutex = FALSE; try { pLookupEntry = GetLineLookupEntry( ptLineClient->ptLine->dwDeviceID ); if (!pLookupEntry) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetCallHubTracking_epilog; } WaitForSingleObject (pLookupEntry->hMutex, INFINITE); bOwnMutex = TRUE; if ((ptLineClient->dwKey != TLINECLIENT_KEY) || !(ptLine = pLookupEntry->ptLine)) { ReleaseMutex (pLookupEntry->hMutex); pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetCallHubTracking_epilog; } } except (EXCEPTION_EXECUTE_HANDLER) { if (bOwnMutex) { ReleaseMutex (pLookupEntry->hMutex); } pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetCallHubTracking_epilog; } if (pTrackingInfo->dwCurrentTracking == ptLineClient->dwCurrentTracking) { goto LSetCallHubTracking_releaseMutex; } bSetSPTracking = FALSE; switch (pTrackingInfo->dwCurrentTracking) { case LINECALLHUBTRACKING_NONE: case LINECALLHUBTRACKING_ALLCALLS: if (ptLineClient->dwCurrentTracking & LINECALLHUBTRACKING_PROVIDERLEVEL) { if (ptLine->dwNumCallHubTrackersSPLevel == 1) { // // We're the only one with SP-level tracking // currently enabled, so call SP to turn OFF // tracking // bSetSPTracking = TRUE; dwNewSPTracking = LINECALLHUBTRACKING_NONE; } } break; default : // CALLHUBTRACKING_ALLCALLS | CALLHUBTRACKING_PROVIDERLEVEL if (ptLine->dwNumCallHubTrackersSPLevel > 0) { // // We're the only one with SP-level tracking // currently enabled, so call SP to turn ON // tracking // bSetSPTracking = TRUE; dwNewSPTracking = LINECALLHUBTRACKING_ALLCALLS | LINECALLHUBTRACKING_PROVIDERLEVEL; } break; } if (bSetSPTracking && pfnTSPI_lineSetCallHubTracking) { LINECALLHUBTRACKINGINFO info; info.dwTotalSize = info.dwNeededSize = info.dwUsedSize = sizeof (info); info.dwAvailableTracking = 0; info.dwCurrentTracking = dwNewSPTracking; pParams->lResult = CallSP2( pfnTSPI_lineSetCallHubTracking, "lineSetCallHubTracking", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (ULONG_PTR) &info ); } if (pParams->lResult == 0) { switch (pTrackingInfo->dwCurrentTracking) { case LINECALLHUBTRACKING_NONE: ptLine->dwNumCallHubTrackers--; if (ptLineClient->dwCurrentTracking & LINECALLHUBTRACKING_PROVIDERLEVEL) { ptLine->dwNumCallHubTrackersSPLevel--; } break; case LINECALLHUBTRACKING_ALLCALLS: if (ptLineClient->dwCurrentTracking == LINECALLHUBTRACKING_NONE) { ptLine->dwNumCallHubTrackers++; } else { ptLine->dwNumCallHubTrackersSPLevel--; } break; default: // CALLHUBTRACKING_ALLCALLS |CALLHUBTRACKING_PROVIDERLEVEL if (ptLineClient->dwCurrentTracking == LINECALLHUBTRACKING_NONE) { ptLine->dwNumCallHubTrackers++; } ptLine->dwNumCallHubTrackersSPLevel++; break; } ptLineClient->dwCurrentTracking = pTrackingInfo->dwCurrentTracking; } LSetCallHubTracking_releaseMutex: ReleaseMutex (ptLine->hMutex); } LSetCallHubTracking_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetCallHubTracking" ); } void WINAPI LSetCallParams( PTCLIENT ptClient, PLINESETCALLPARAMS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetCallParams; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwDialParamsOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, sizeof (LINEDIALPARAMS), pParams->dwDialParamsOffset, sizeof(DWORD), "LSetCallParams", "pParams->DialParams" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETCALLPARAMS, // provider func index &pfnTSPI_lineSetCallParams, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetCallParams" // func name )) > 0) { DWORD dwAPIVersion, dwAllBearerModes, dwBearerMode = pParams->dwBearerMode; // // Safely get the API ver associated with this call & make sure // no invalid bearer modes are specified (high 16 bearer mode // bits are extensions) // try { dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion; } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LSetCallParams_epilog; } switch (dwAPIVersion) { case TAPI_VERSION1_0: dwAllBearerModes = AllBearerModes1_0; break; case TAPI_VERSION1_4: dwAllBearerModes = AllBearerModes1_4; break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: case TAPI_VERSION3_0: case TAPI_VERSION_CURRENT: dwAllBearerModes = AllBearerModes2_0; break; default: lRequestID = LINEERR_INVALBEARERMODE; goto LSetCallParams_epilog; } if (!IsOnlyOneBitSetInDWORD(dwBearerMode) || (dwBearerMode & ~(dwAllBearerModes | 0xffff0000))) { lRequestID = LINEERR_INVALBEARERMODE; goto LSetCallParams_epilog; } pParams->lResult = CallSP6( pfnTSPI_lineSetCallParams, "lineSetCallParams", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (DWORD) pParams->dwBearerMode, (DWORD) pParams->dwMinRate, (DWORD) pParams->dwMaxRate, (ULONG_PTR) (pParams->dwDialParamsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDialParamsOffset) ); } LSetCallParams_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetCallParams" ); } void WINAPI LSetCallPrivilege( PTCLIENT ptClient, PLINESETCALLPRIVILEGE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTCALL ptCall; PTCALLCLIENT ptCallClient; if (!(ptCallClient = ReferenceObject( ghHandleTable, pParams->hCall, TCALLCLIENT_KEY ))) { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED); goto LSetCallPrivilege_epilog; } // // Don't both with LineProlog, since we need a try/except // to get the ptCall anyway // try { ptCall = ptCallClient->ptCall; if (ptCallClient->dwKey != TCALLCLIENT_KEY || ptCallClient->ptClient != ptClient) { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED); goto LSetCallPrivilege_Dereference; } } myexcept { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALCALLHANDLE : LINEERR_UNINITIALIZED); goto LSetCallPrivilege_Dereference; } if ((pParams->dwPrivilege != LINECALLPRIVILEGE_MONITOR) && (pParams->dwPrivilege != LINECALLPRIVILEGE_OWNER)) { pParams->lResult = LINEERR_INVALCALLPRIVILEGE; goto LSetCallPrivilege_Dereference; } if (WaitForExclusivetCallAccess (ptCall, TCALL_KEY)) { // // Make sure the tCallClient is still valid // try { if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LSetCallPrivilege_UnlocktCall; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LSetCallPrivilege_UnlocktCall; } if (pParams->dwPrivilege != ptCallClient->dwPrivilege) { // if (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER && // ptCall->dwNumOwners == 1 && // ptCall->dwCallState != LINECALLSTATE_IDLE) // { // pParams->lResult = LINEERR_INVALCALLSTATE; // goto LSetCallPrivilege_releaseMutex; // } if (pParams->dwPrivilege == LINECALLPRIVILEGE_OWNER) { ptCall->dwNumOwners++; ptCall->dwNumMonitors--; } else { ptCall->dwNumOwners--; ptCall->dwNumMonitors++; } ptCallClient->dwPrivilege = pParams->dwPrivilege; UNLOCKTCALL(ptCall); SendMsgToCallClients( ptCall, ptCallClient, LINE_CALLINFO, LINECALLINFOSTATE_NUMMONITORS | (pParams->dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERINCR : LINECALLINFOSTATE_NUMOWNERDECR), 0, 0 ); } else { LSetCallPrivilege_UnlocktCall: UNLOCKTCALL(ptCall); } } else { pParams->lResult = LINEERR_INVALCALLHANDLE; } LSetCallPrivilege_Dereference: DereferenceObject (ghHandleTable, pParams->hCall, 1); LSetCallPrivilege_epilog: #if DBG { char szResult[32]; LOG((TL_TRACE, "LineEpilogSync: (lineSetCallPrivilege) exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "LineEpilogSync: (lineSetCallPrivilege) exit, result=x%x", pParams->lResult )); #endif return; } void WINAPI LSetCallQualityOfService( PTCLIENT ptClient, PLINESETCALLQUALITYOFSERVICE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetCallQualityOfService; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSendingFlowspecSize, pParams->dwSendingFlowspecOffset, sizeof(DWORD), "LSetCallQualityOfService", "pParams->SendingFlowspec" ) || ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwReceivingFlowspecSize, pParams->dwReceivingFlowspecOffset, sizeof(DWORD), "LSetCallQualityOfService", "pParams->ReceivingFlowspec" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETCALLQUALITYOFSERVICE, // provider func index &pfnTSPI_lineSetCallQualityOfService, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetCallQualityOfService" // func name )) > 0) { pParams->lResult = CallSP6( pfnTSPI_lineSetCallQualityOfService, "lineSetCallQualityOfService", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) (pDataBuf + pParams->dwSendingFlowspecOffset), (DWORD) pParams->dwSendingFlowspecSize, (ULONG_PTR) (pDataBuf + pParams->dwReceivingFlowspecOffset), (DWORD) pParams->dwReceivingFlowspecSize ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetCallQualityOfService" ); } void WINAPI LSetCallTreatment( PTCLIENT ptClient, PLINESETCALLTREATMENT_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetCallTreatment; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETCALLTREATMENT, // provider func index &pfnTSPI_lineSetCallTreatment, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetCallTreatment" // func name )) > 0) { if (pParams->dwTreatment == 0 || (pParams->dwTreatment > LINECALLTREATMENT_MUSIC && pParams->dwTreatment < 0x100)) { lRequestID = LINEERR_INVALPARAM; goto LSetCallTreatment_epilog; } pParams->lResult = CallSP3( pfnTSPI_lineSetCallTreatment, "lineSetCallTreatment", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (DWORD) pParams->dwTreatment ); } LSetCallTreatment_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetCallTreatment" ); } void WINAPI LSetDefaultMediaDetection( PTCLIENT ptClient, PLINESETDEFAULTMEDIADETECTION_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetDefaultMediaDetection; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETDEFAULTMEDIADETECTION, // provider func index &pfnTSPI_lineSetDefaultMediaDetection, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetDefaultMediaDetection" // func name )) == 0) { DWORD dwMediaModes = pParams->dwMediaModes; PTLINE ptLine; ptLine = ptLineClient->ptLine; if ((dwMediaModes & ptLine->dwOpenMediaModes) != dwMediaModes) { DWORD dwUnionMediaModes = dwMediaModes | ptLine->dwOpenMediaModes; if ((pParams->lResult = CallSP2( pfnTSPI_lineSetDefaultMediaDetection, "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) dwUnionMediaModes )) == 0) { ptLine->dwOpenMediaModes = dwUnionMediaModes; } } if (pParams->lResult == 0) { // // For remote clients, give the monitor privilege. It doesn't // matter if we do with (except for increased network traffic), // because tapisrv on the client will filter out anything // the client clients don't want. // if (IS_REMOTE_CLIENT (ptClient)) { ptLineClient->dwPrivileges = (dwMediaModes ? LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_NONE); } else { ptLineClient->dwPrivileges = (dwMediaModes ? LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_NONE); } ptLineClient->dwMediaModes = dwMediaModes; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetDefaultMediaDetection" ); } void WINAPI LSetDevConfig( PTCLIENT ptClient, PLINESETDEVCONFIG_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineSetDevConfig; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwSize, pParams->dwDeviceConfigOffset, sizeof(DWORD), "LSetDevConfig", "pParams->DeviceConfig" ) || IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceClassOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle &dwDeviceID, // provider widget handle pParams->dwDeviceID, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETDEVCONFIG, // provider func index &pfnTSPI_lineSetDevConfig, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "SetDevConfig" // func name )) == 0) { pParams->lResult = CallSP4( pfnTSPI_lineSetDevConfig, "lineSetDevConfig", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) (pParams->dwSize ? pDataBuf + pParams->dwDeviceConfigOffset : NULL), (DWORD) pParams->dwSize, (ULONG_PTR) (pDataBuf + pParams->dwDeviceClassOffset) ); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetDevConfig" ); } void WINAPI LSetLineDevStatus( PTCLIENT ptClient, PLINESETLINEDEVSTATUS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetLineDevStatus; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETLINEDEVSTATUS, // provider func index &pfnTSPI_lineSetLineDevStatus, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetLineDevStatus" // func name )) > 0) { #define AllLineDevStatusFlags \ (LINEDEVSTATUSFLAGS_CONNECTED | \ LINEDEVSTATUSFLAGS_MSGWAIT | \ LINEDEVSTATUSFLAGS_INSERVICE | \ LINEDEVSTATUSFLAGS_LOCKED) if (pParams->dwStatusToChange == 0 || (pParams->dwStatusToChange & ~AllLineDevStatusFlags) != 0) { lRequestID = LINEERR_INVALLINESTATE; } else { pParams->lResult = CallSP4( pfnTSPI_lineSetLineDevStatus, "lineSetLineDevStatus", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwStatusToChange, (DWORD) pParams->fStatus ); } } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetLineDevStatus" ); } void WINAPI LSetMediaControl( PTCLIENT ptClient, PLINESETMEDIACONTROL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwWidgetType, hWidget, dwPrivilege; HANDLE hMutex; LPVOID context; TSPIPROC pfnTSPI_lineSetMediaControl; DWORD objectToDereference; ULONG_PTR hdWidget; // // Verify size/offset/string params given our input buffer/size // if (((pParams->dwDigitListOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwDigitListNumEntries, // actually dwNumEntries * sizeof(LINEMEDIACONTROLDIGIT) pParams->dwDigitListOffset, sizeof(DWORD), "LSetMediaControl", "pParams->DigitList" )) || ((pParams->dwMediaListOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwMediaListNumEntries, // actually dwNumEntries * sizeof(LINEMEDIACONTROLMEDIA) pParams->dwMediaListOffset, sizeof(DWORD), "LSetMediaControl", "pParams->MediaList" )) || ((pParams->dwToneListOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwToneListNumEntries, // actually dwNumEntries * sizeof(LINEMEDIACONTROLTONE) pParams->dwToneListOffset, sizeof(DWORD), "LSetMediaControl", "pParams->ToneList" )) || ((pParams->dwCallStateListOffset != TAPI_NO_DATA) && ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwCallStateListNumEntries, // actually dwNumEntries *sizeof(LINEMEDIACONTROLCALLSTATE) pParams->dwCallStateListOffset, sizeof(DWORD), "LSetMediaControl", "pParams->CallStateList" ))) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (pParams->dwSelect == LINECALLSELECT_CALL) { dwWidgetType = ANY_RT_HCALL; hWidget = (DWORD) pParams->hCall; dwPrivilege = LINECALLPRIVILEGE_OWNER; } else { dwWidgetType = ANY_RT_HLINE; hWidget = (DWORD) pParams->hLine; dwPrivilege = 0; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient dwWidgetType, // widget type (DWORD) hWidget, // client widget handle (LPVOID) &hdWidget, // provider widget handle dwPrivilege, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETMEDIACONTROL, // provider func index &pfnTSPI_lineSetMediaControl, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &context, // context "SetMediaControl" // func name )) == 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwSelect) || (pParams->dwSelect & ~AllCallSelect)) { pParams->lResult = LINEERR_INVALCALLSELECT; goto LSetMediaControl_epilog; } pParams->lResult = CallSP12( pfnTSPI_lineSetMediaControl, "lineSetMediaControl", SP_FUNC_SYNC, (ULONG_PTR) (pParams->dwSelect == LINECALLSELECT_CALL ? 0 : hdWidget), (DWORD) pParams->dwAddressID, (ULONG_PTR) (pParams->dwSelect == LINECALLSELECT_CALL ? hdWidget : 0), (DWORD) pParams->dwSelect, (ULONG_PTR) (pParams->dwDigitListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDigitListOffset), (DWORD) pParams->dwDigitListNumEntries / sizeof(LINEMEDIACONTROLDIGIT), (ULONG_PTR) (pParams->dwMediaListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwMediaListOffset), (DWORD) pParams->dwMediaListNumEntries / sizeof(LINEMEDIACONTROLMEDIA), (ULONG_PTR) (pParams->dwToneListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwToneListOffset), (DWORD) pParams->dwToneListNumEntries / sizeof(LINEMEDIACONTROLTONE), (ULONG_PTR) (pParams->dwCallStateListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwCallStateListOffset), (DWORD) pParams->dwCallStateListNumEntries / sizeof(LINEMEDIACONTROLCALLSTATE) ); } LSetMediaControl_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetMediaControl" ); } void WINAPI LSetMediaMode( PTCLIENT ptClient, PLINESETMEDIAMODE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwAPIVersion, dwSPIVersion, dwAllMediaModes; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetMediaMode; DWORD objectToDereference; PTCALLCLIENT ptCallClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETMEDIAMODE, // provider func index &pfnTSPI_lineSetMediaMode, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetMediaMode" // func name )) == 0) { try { dwAPIVersion = ptCallClient->ptLineClient->dwAPIVersion; dwSPIVersion = ptCallClient->ptLineClient->ptLine->dwSPIVersion; if (ptCallClient->dwKey != TCALLCLIENT_KEY) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LSetMediaMode_epilog; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LSetMediaMode_epilog; } // // Check for 0 media mode, and if > 1 bit set without UNKNOWN bit // if ( (dwAPIVersion <= TAPI_VERSION2_1 ) && !IsOnlyOneBitSetInDWORD (pParams->dwMediaModes) && !(pParams->dwMediaModes & LINEMEDIAMODE_UNKNOWN)) { LOG((TL_ERROR, "LSetMediaMode: error, >1 media mode selected without " \ "UNKNOWN flag (APIVer=x%x)", dwAPIVersion )); pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetMediaMode_epilog; } // // Now the harder checks // switch (dwAPIVersion) { case TAPI_VERSION1_0: dwAllMediaModes = AllMediaModes1_0; break; case TAPI_VERSION1_4: case TAPI_VERSION2_0: dwAllMediaModes = AllMediaModes1_4; break; //case TAPI_VERSION2_1: //case TAPI_VERSION2_2: default: //case TAPI_VERSION_CURRENT: dwAllMediaModes = AllMediaModes2_1; break; } if ((pParams->dwMediaModes & (dwAllMediaModes ^ 0x00ffffff)) || (pParams->dwMediaModes == 0)) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetMediaMode_epilog; } pParams->lResult = CallSP2( pfnTSPI_lineSetMediaMode, "lineSetMediaMode", SP_FUNC_SYNC, (ULONG_PTR) hdCall, (DWORD) pParams->dwMediaModes ); } LSetMediaMode_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetMediaMode" ); } void WINAPI LSetNumRings( PTCLIENT ptClient, PLINESETNUMRINGS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_NONE, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetNumRings" // func name )) == 0) { if (WaitForExclusiveLineClientAccess (ptLineClient)) { DWORD dwNumAddresses = ptLineClient->ptLine->dwNumAddresses; if (pParams->dwAddressID >= dwNumAddresses) { pParams->lResult = LINEERR_INVALADDRESSID; goto LSetNumRings_releaseMutex; } if (ptLineClient->aNumRings == NULL) { if (!(ptLineClient->aNumRings = ServerAlloc( dwNumAddresses * sizeof (DWORD) ))) { pParams->lResult = LINEERR_NOMEM; goto LSetNumRings_releaseMutex; } FillMemory( ptLineClient->aNumRings, dwNumAddresses * sizeof (DWORD), 0xff ); } ptLineClient->aNumRings[pParams->dwAddressID] = pParams->dwNumRings; LSetNumRings_releaseMutex: UNLOCKTLINECLIENT(ptLineClient); } else { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetNumRings" ); } void WINAPI LSetQueueMeasurementPeriod( PTCLIENT ptClient, PLINESETQUEUEMEASUREMENTPERIOD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetQueueMeasurementPeriod" // func name )) > 0) { LONG lResult; DWORD dwDeviceID; PTLINECLIENT pProxy; if ((lResult = FindProxy( ptLineClient, 0, LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD, &pProxy, &dwDeviceID, TAPI_VERSION2_2 ))) { lRequestID = lResult; goto LSetQueueMeasurementPeriod_epilog; } // Measurement period must be > 0 if (pParams->dwMeasurementPeriod == 0) { lRequestID = LINEERR_INVALPARAM; goto LSetQueueMeasurementPeriod_epilog; } // // First check to see if there's a (local) proxy registered // for this type of request on this line. If so, build a // request & send it to the proxy. // if (pProxy) { LONG lResult; PPROXYREQUESTWRAPPER pProxyRequestWrapper; if ((lResult = CreateProxyRequest( pProxy, LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD, 2 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LSetQueueMeasurementPeriod_epilog; } pProxyRequestWrapper->ProxyRequest. SetQueueMeasurementPeriod.dwQueueID = pParams->dwQueueID; pProxyRequestWrapper->ProxyRequest. SetQueueMeasurementPeriod.dwMeasurementPeriod = pParams->dwMeasurementPeriod; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetQueueMeasurementPeriod_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo->dwLocalRequestID; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETQUEUEMEASUREMENTPERIOD], "lineSetQueueMeasurementPeriod", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwQueueID, (DWORD) pParams->dwMeasurementPeriod ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LSetQueueMeasurementPeriod_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetQueueManagementPeriod" ); } void WINAPI LSetStatusMessages( PTCLIENT ptClient, PLINESETSTATUSMESSAGES_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex, bCloseMutex2; HANDLE hMutex, hMutex2; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetStatusMessages; DWORD objectToDereference; PTLINECLIENT ptLineClient, ptLineClient2; if ((pParams->lResult = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETSTATUSMESSAGES, // provider func index &pfnTSPI_lineSetStatusMessages, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "SetStatusMessages" // func name )) == 0) { DWORD dwAPIVersion, dwUnionLineStates, dwUnionAddressStates; PTLINE ptLine; // // Safely get the ptLine & api version // try { ptLine = ptLineClient->ptLine; dwAPIVersion = ptLineClient->dwAPIVersion; if (ptLineClient->dwKey != TLINECLIENT_KEY) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetStatusMessages_epilog; } } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetStatusMessages_epilog; } // // Validate the params // { DWORD dwValidLineStates, dwValidAddressStates; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwValidLineStates = AllLineStates1_0; dwValidAddressStates = AllAddressStates1_0; break; default: dwValidLineStates = AllLineStates1_4; dwValidAddressStates = AllAddressStates1_4; break; } if (pParams->dwLineStates & ~dwValidLineStates) { pParams->lResult = LINEERR_INVALLINESTATE; goto LSetStatusMessages_epilog; } if (pParams->dwAddressStates & ~dwValidAddressStates) { pParams->lResult = LINEERR_INVALADDRESSSTATE; goto LSetStatusMessages_epilog; } } // // Make sure the REINIT bit is always set // pParams->dwLineStates |= LINEDEVSTATE_REINIT; // // Get exclusive access to the device, determine the // new union of all the client's status message settings // and call down to the SP as appropriate // dwUnionLineStates = pParams->dwLineStates; dwUnionAddressStates = pParams->dwAddressStates; waitForExclAccess: if (WaitForExclusivetLineAccess( ptLine, &hMutex2, &bCloseMutex2, INFINITE )) { if (ptLine->dwBusy) { MyReleaseMutex (hMutex2, bCloseMutex2); Sleep (50); goto waitForExclAccess; } for( ptLineClient2 = ptLine->ptLineClients; ptLineClient2; ptLineClient2 = ptLineClient2->pNextSametLine ) { if (ptLineClient2 != ptLineClient) { dwUnionLineStates |= ptLineClient2->dwLineStates; dwUnionAddressStates |= ptLineClient2->dwAddressStates; } } if ((dwUnionLineStates != ptLine->dwUnionLineStates) || (dwUnionAddressStates != ptLine->dwUnionAddressStates)) { ptLine->dwBusy = 1; MyReleaseMutex (hMutex2, bCloseMutex2); pParams->lResult = CallSP3( pfnTSPI_lineSetStatusMessages, "lineSetStatusMessages", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (DWORD) dwUnionLineStates, (DWORD) dwUnionAddressStates ); if (WaitForExclusivetLineAccess( ptLine, &hMutex2, &bCloseMutex2, INFINITE )) { ptLine->dwBusy = 0; if (pParams->lResult == 0) { ptLine->dwUnionLineStates = dwUnionLineStates; ptLine->dwUnionAddressStates = dwUnionAddressStates; } MyReleaseMutex (hMutex2, bCloseMutex2); } else { pParams->lResult = LINEERR_INVALLINEHANDLE; } } else { MyReleaseMutex (hMutex2, bCloseMutex2); } if (pParams->lResult == 0) { if (WaitForExclusiveLineClientAccess (ptLineClient)) { ptLineClient->dwLineStates = pParams->dwLineStates; ptLineClient->dwAddressStates = pParams->dwAddressStates; UNLOCKTLINECLIENT (ptLineClient); } else { // // The client is invalid now, but don't bother // restoring the status msg states (will eventually // get reset correctly & worse case is that SP just // sends some extra msgs that get discarded) // pParams->lResult = LINEERR_INVALLINEHANDLE; } } } else { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LSetStatusMessages_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "SetStatusMessages" ); } void WINAPI LSetTerminal( PTCLIENT ptClient, PLINESETTERMINAL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwWidgetType, hWidget, dwPrivilege, dwSelect = pParams->dwSelect; HANDLE hMutex; LPVOID context; TSPIPROC pfnTSPI_lineSetTerminal; DWORD objectToDereference; ULONG_PTR hdWidget; PASYNCREQUESTINFO pAsyncRequestInfo; if (dwSelect == LINECALLSELECT_CALL) { dwWidgetType = ANY_RT_HCALL; hWidget = (DWORD) pParams->hCall; dwPrivilege = LINECALLPRIVILEGE_MONITOR; } else { dwWidgetType = ANY_RT_HLINE; hWidget = (DWORD) pParams->hLine; dwPrivilege = 0; } if ((lRequestID = LINEPROLOG( ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle &hdWidget, // provider widget handle dwPrivilege, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETTERMINAL, // provider func index &pfnTSPI_lineSetTerminal, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &context, // context "SetTerminal" // func name )) > 0) { DWORD dwTerminalModes = pParams->dwTerminalModes; if (!IsOnlyOneBitSetInDWORD (dwSelect) || (dwSelect & ~AllCallSelects)) { lRequestID = LINEERR_INVALCALLSELECT; goto LSetTerminal_epilog; } if (dwTerminalModes == 0 || (dwTerminalModes & (~AllTerminalModes))) { lRequestID = LINEERR_INVALTERMINALMODE; goto LSetTerminal_epilog; } pParams->lResult = CallSP8( pfnTSPI_lineSetTerminal, "lineSetTerminal", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) (dwWidgetType == ANY_RT_HLINE ? hdWidget : 0), (DWORD) pParams->dwAddressID, (ULONG_PTR) (dwWidgetType == ANY_RT_HCALL ? hdWidget : 0), (DWORD) dwSelect, (DWORD) dwTerminalModes, (DWORD) pParams->dwTerminalID, (DWORD) pParams->bEnable ); } LSetTerminal_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetTerminal" ); } void LSetupConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1, ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam3, ptCall = (PTCALL) pAsyncRequestInfo->dwParam5; HCALL hpConfCall = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); HCALL hpConsultCall = DWORD_CAST(pAsyncRequestInfo->dwParam4,__FILE__,__LINE__); PTCALLCLIENT ptConfCallClient, ptConsultCallClient; // LSetupConference_PostProcess: mutex on confCall too? // // Actually, this may be ok as is- the consult call is // positioned before the conf call in the tline's list, // so if we can safely access the former we ought to be // able to safely access the latter too if (WaitForExclusivetCallAccess (ptConsultCall, TINCOMPLETECALL_KEY)) { HCALL hConsultCallThen = (HCALL)*(&pAsyncRequestInfo->dwParam5 + 2); PTCALL ptConsultCallThen; // // Check to make sure this is the call we think it is (that the // pointer wasn't freed by a previous call to lineClose/Shutdown // and realloc'd for use as a ptCall again) // if (ptConsultCall->hCall != hConsultCallThen) { UNLOCKTCALL(ptConsultCall); goto LSetupConference_PostProcess_bad_ptConsultCall; } ptConfCallClient = ptConfCall->ptCallClients; ptConsultCallClient = ptConsultCall->ptCallClients; if (pAsyncEventMsg->Param2 == 0) // success { PTCONFERENCELIST pConfList = ptConfCall->pConfList; // // Check to see if the app closed the line & left us with // 0 call clients (in which case it'll also be taking care of // cleaning up this tCall too) // if (ptConsultCall->ptCallClients == NULL) { UNLOCKTCALL(ptConsultCall); ptConfCallClient = (PTCALLCLIENT) NULL; ptConsultCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_INVALLINEHANDLE; } goto LSetupConference_PostProcess_initMsgParams; } // // Retrieve the various call IDs, then check if call // client was destroyed by another thread (due to // lineClose/Shutdown) while we were getting the call ID. // If so, we'll need to clean up the tCall, since we know // the other thread didn't do it because GetCallIDs marks // the call as a zombie. // // Note that we can't use GetCallIDs() because we need // to get id's for two calls at once // { PTPROVIDER ptProvider = ptConfCall->ptProvider; ptConfCall->dwKey = ptConsultCall->dwKey = TZOMBIECALL_KEY; UNLOCKTCALL (ptConsultCall); if (ptProvider->apfn[SP_LINEGETCALLIDS]) { CallSP4( ptProvider->apfn[SP_LINEGETCALLIDS], "lineGetCalIDs", SP_FUNC_SYNC, (ULONG_PTR) ptConfCall->hdCall, (ULONG_PTR) &ptConfCall->dwAddressID, (ULONG_PTR) &ptConfCall->dwCallID, (ULONG_PTR) &ptConfCall->dwRelatedCallID ); CallSP4( ptProvider->apfn[SP_LINEGETCALLIDS], "lineGetCalIDs", SP_FUNC_SYNC, (ULONG_PTR) ptConsultCall->hdCall, (ULONG_PTR) &ptConsultCall->dwAddressID, (ULONG_PTR) &ptConsultCall->dwCallID, (ULONG_PTR) &ptConsultCall->dwRelatedCallID ); } else { DWORD dwSPIVersion, dwFixedSizeSP; LINECALLINFO callInfo; // // Determine the fixed size of the structure expected // by the SP // dwSPIVersion = ((PTLINE) ptConfCall->ptLine)->dwSPIVersion; switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 296; // 69 * sizeof(DWORD) // + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; case TAPI_VERSION2_0: case TAPI_VERSION2_1: case TAPI_VERSION2_2: dwFixedSizeSP = 324; // 76 * sizeof(DWORD) // + sizeof (HLINE) // + sizeof (LINEDIALPARAMS) break; default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLINFO); break; } InitTapiStruct( &callInfo, dwFixedSizeSP, dwFixedSizeSP, TRUE ); if (ptProvider->apfn[SP_LINEGETCALLINFO] == NULL) { LOCKTCALL (ptConsultCall); goto LSetupConference_PostProcess_cleanupCalls; } CallSP2( ptProvider->apfn[SP_LINEGETCALLINFO], "lineGetCallInfo", SP_FUNC_SYNC, (ULONG_PTR) ptConfCall->hdCall, (ULONG_PTR) &callInfo ); ptConfCall->dwAddressID = callInfo.dwAddressID; ptConfCall->dwCallID = callInfo.dwCallID; ptConfCall->dwRelatedCallID = callInfo.dwRelatedCallID; InitTapiStruct( &callInfo, dwFixedSizeSP, dwFixedSizeSP, TRUE ); CallSP2( ptProvider->apfn[SP_LINEGETCALLINFO], "lineGetCallInfo", SP_FUNC_SYNC, (ULONG_PTR) ptConsultCall->hdCall, (ULONG_PTR) &callInfo ); ptConsultCall->dwAddressID = callInfo.dwAddressID; ptConsultCall->dwCallID = callInfo.dwCallID; ptConsultCall->dwRelatedCallID = callInfo.dwRelatedCallID; } LOCKTCALL (ptConsultCall); } if (!ptConsultCall->ptCallClients) { goto LSetupConference_PostProcess_cleanupCalls; } // // Indicate the various call IDs in the adwParams[] field of // the ASYNCEVENTMSG. // // Make sure to increment the dwTotalSize of the ASYNCEVENTMSG // as appropriate. We rely on the fact that CompletionProc() // calls us with an AsyncEventMsg buffer that is big enough to // handle a few extra DWORDs. // pAsyncEventMsg->Param3 = ptConfCallClient->hCall; *(&pAsyncEventMsg->Param4 + 1) = ptConsultCallClient->hCall; pAsyncEventMsg->TotalSize += 6 * sizeof (pAsyncEventMsg->Param1); *(&pAsyncEventMsg->Param4 + 3) = ptConfCall->dwAddressID; *(&pAsyncEventMsg->Param4 + 4) = ptConfCall->dwCallID; *(&pAsyncEventMsg->Param4 + 5) = ptConfCall->dwRelatedCallID; *(&pAsyncEventMsg->Param4 + 6) = ptConsultCall->dwAddressID; *(&pAsyncEventMsg->Param4 + 7) = ptConsultCall->dwCallID; *(&pAsyncEventMsg->Param4 + 8) = ptConsultCall->dwRelatedCallID; // // Mark the calls as valid, the release the mutex // ptConfCall->dwKey = ptConsultCall->dwKey = TCALL_KEY; ptConfCallClient->dwKey = ptConsultCallClient->dwKey = TCALLCLIENT_KEY; pConfList->dwKey = TCONFLIST_KEY; UNLOCKTCALL(ptConsultCall); // // Create monitor tCallClients // if (ptConsultCallThen = ReferenceObject(ghHandleTable, hConsultCallThen, TCALL_KEY)) { if (ptConsultCallThen == ptConsultCall) { CreateCallMonitors (ptConfCall, FALSE); CreateCallMonitors (ptConsultCall, FALSE); } DereferenceObject(ghHandleTable, hConsultCallThen, 1); } } else // error { LSetupConference_PostProcess_cleanupCalls: // // Invalidate the tCalls, & if there's still tCallClients // (might have already been destroyed by a lineClose/Shutdown // in another thread) invalidate them too. Then unlock the // tCalls & remove the object(s) from the list(s). // ptConfCall->dwKey = ptConsultCall->dwKey = INVAL_KEY; if (ptConfCall->ptCallClients) { ptConfCallClient->dwKey = INVAL_KEY; ptConfCall->lActiveFastCallClients--; } else { ptConfCallClient = NULL; } if (ptConsultCall->ptCallClients) { ptConsultCallClient->dwKey = INVAL_KEY; ptConsultCall->lActiveFastCallClients--; } else { ptConsultCallClient = NULL; } UNLOCKTCALL(ptConsultCall); RemoveCallFromLineList (ptConfCall); RemoveCallFromLineList (ptConsultCall); if (ptConfCallClient) { DereferenceObject (ghHandleTable, ptConfCallClient->hCall, 1); RemoveCallClientFromLineClientList (ptConfCallClient); } if (ptConsultCallClient) { DereferenceObject (ghHandleTable,ptConsultCallClient->hCall,1); RemoveCallClientFromLineClientList (ptConsultCallClient); } // // Make sure all fast call clients cleaned up before free tCalls // while ((ptConfCall->lActiveFastCallClients != 0) || (ptConsultCall->lActiveFastCallClients != 0)) { Sleep (5); } FreetCall (ptConsultCall); if (ptCall) { SetCallConfList (ptCall, NULL, FALSE); } ServerFree (ptConfCall->pConfList); FreetCall (ptConfCall); } } else { // // If here we can assume that the call was already destroyed // and just fail the request // LSetupConference_PostProcess_bad_ptConsultCall: if (pAsyncEventMsg->Param2 == 0) { pAsyncEventMsg->Param2 = LINEERR_OPERATIONFAILED; } } LSetupConference_PostProcess_initMsgParams: // // Fill in the params to pass to client (important to remotesp in both // the success & fail cases so it can either init or clean up drvCall) // // Make sure to increment the dwTotalSize of the ASYNCEVENTMSG // as appropriate. We rely on the fact that CompletionProc() // calls us with an AsyncEventMsg buffer that is big enough to // handle a few extra DWORDs. // pAsyncEventMsg->Param4 = hpConfCall; pAsyncEventMsg->TotalSize += 2 * sizeof (pAsyncEventMsg->Param1); *(&pAsyncEventMsg->Param4 + 2) = hpConsultCall; } void WINAPI LSetupConference( PTCLIENT ptClient, PLINESETUPCONFERENCE_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwPrivilege = LINECALLPRIVILEGE_OWNER; HCALL hCall = pParams->hCall; HLINE hLine = pParams->hLine; HANDLE hMutex; LPVOID context; TSPIPROC pfnTSPI_lineSetupConference; DWORD objectToDereference; ULONG_PTR hdXxx; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient (hCall ? ANY_RT_HCALL : ANY_RT_HLINE), // widget type (hCall ? (DWORD) hCall : (DWORD) hLine),// client widget handle (LPVOID) &hdXxx, // provider widget handle (hCall ? dwPrivilege : 0), // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when done SP_LINESETUPCONFERENCE, // provider func index &pfnTSPI_lineSetupConference, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &context, // context "SetupConference" // func name )) > 0) { LONG lResult; DWORD dwNumParties; PTCALL ptCall, ptConfCall, ptConsultCall; HCALL hConfCall, hConsultCall; PTCALLCLIENT ptConfCallClient, ptConsultCallClient; PTLINECLIENT ptLineClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; PTCONFERENCELIST pConfList; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset )) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LSetupConference_return; } // // We need two more async request info params than are available, // so we'll realloc a larger buf & work with it // { PASYNCREQUESTINFO pAsyncRequestInfo2; if (!(pAsyncRequestInfo2 = ServerAlloc( sizeof (ASYNCREQUESTINFO) + 2 * sizeof (ULONG_PTR) ))) { lRequestID = LINEERR_NOMEM; goto LSetupConference_return; } CopyMemory( pAsyncRequestInfo2, pAsyncRequestInfo, sizeof (ASYNCREQUESTINFO) ); pAsyncRequestInfo2->dwLocalRequestID = (DWORD)NewObject( ghHandleTable, pAsyncRequestInfo2, NULL ); // The following lines are to be removed for BUG 258501(xzhang). // When called from RemoteSP, dwRemoteRequestID is used by the RemoteSP // to identify the async request, if set to dwLocalRequestID, RemoteSP // will get an invalid request ID and discard the call event notification. /* if (lRequestID != (LONG) pAsyncRequestInfo->dwLocalRequestID) { lRequestID = (LONG) (pAsyncRequestInfo2->dwRemoteRequestID = pAsyncRequestInfo2->dwLocalRequestID); } */ DereferenceObject( ghHandleTable, pAsyncRequestInfo->dwLocalRequestID, 1 ); pAsyncRequestInfo = pAsyncRequestInfo2; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); // // Reference the tLineClient if not already // if (hCall) { try { hLine = ((PTCALLCLIENT) context)->ptLineClient->hLine; } myexcept { lRequestID = LINEERR_OPERATIONFAILED; goto LSetupConference_return; } if (!(ptLineClient = ReferenceObject( ghHandleTable, hLine, TLINECLIENT_KEY ))) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSetupConference_return; } } else { ptLineClient = (PTLINECLIENT) context; } if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; try { dwAPIVersion = ptLineClient->dwAPIVersion; dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_OPERATIONFAILED; goto LSetupConference_Dereference; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LSetupConference_Dereference; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } dwNumParties = (pParams->dwNumParties > DEF_NUM_CONF_LIST_ENTRIES ? pParams->dwNumParties : DEF_NUM_CONF_LIST_ENTRIES); if (!(pConfList = (PTCONFERENCELIST) ServerAlloc( sizeof (TCONFERENCELIST) + dwNumParties * sizeof(PTCALL) ))) { lRequestID = LINEERR_NOMEM; goto LSetupConference_freeCallParams; } pConfList->dwNumTotalEntries = dwNumParties + 1; pConfList->dwNumUsedEntries = 1; if (hCall) { try { ptCall = ((PTCALLCLIENT) context)->ptCall; } myexcept { lResult = LINEERR_INVALCALLHANDLE; goto LSetupConference_freeConfList; } if ((lResult = SetCallConfList (ptCall, pConfList, FALSE)) != 0) { goto LSetupConference_freeConfList; } } else { ptCall = NULL; } if ((lResult = CreatetCallAndClient( ptLineClient, &ptConfCall, &ptConfCallClient, pCallParamsSP, &hConfCall, NULL )) == 0) { pConfList->aptCalls[0] = ptConfCall; if ((lResult = CreatetCallAndClient( ptLineClient, &ptConsultCall, &ptConsultCallClient, NULL, &hConsultCall, ptConfCall ) == 0)) { ptConfCall->pConfList = pConfList; pAsyncRequestInfo->pfnPostProcess = LSetupConference_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConfCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConfCall; pAsyncRequestInfo->dwParam2 = pParams->hpConfCall; pAsyncRequestInfo->dwParam3 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->dwParam4 = pParams->hpConsultCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR) ptCall; *(&pAsyncRequestInfo->dwParam5 + 1) = (ULONG_PTR)hConfCall; *(&pAsyncRequestInfo->dwParam5 + 2) = (ULONG_PTR)hConsultCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; goto LSetupConference_callSP; } SetDrvCallFlags (hConfCall, DCF_SPIRETURNED); DestroytCall (ptConfCall); } LSetupConference_freeConfList: ServerFree (pConfList); lRequestID = lResult; goto LSetupConference_freeCallParams; LSetupConference_callSP: pParams->lResult = CallSP9( pfnTSPI_lineSetupConference, "lineSetupConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) (hCall ? hdXxx : 0), // hdCall (ULONG_PTR) (hCall ? 0 : hdXxx), // hdLine (ULONG_PTR) hConfCall, (ULONG_PTR) &ptConfCall->hdCall, (ULONG_PTR) hConsultCall, (ULONG_PTR) &ptConsultCall->hdCall, (DWORD) pParams->dwNumParties, (ULONG_PTR) pCallParamsSP ); SetDrvCallFlags( hConfCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); SetDrvCallFlags( hConsultCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); LSetupConference_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } LSetupConference_Dereference: if (hCall) { DereferenceObject (ghHandleTable, hLine, 1); } } LSetupConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetupConference" ); } void WINAPI LSetupTransfer( PTCLIENT ptClient, PLINESETUPTRANSFER_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetupTransfer; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESETUPTRANSFER, // provider func index &pfnTSPI_lineSetupTransfer, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "SetupTransfer" // func name )) > 0) { LONG lResult; HLINE hLine; PTCALL ptConsultCall; HCALL hConsultCall; PTCALLCLIENT ptConsultCallClient; PTLINECLIENT ptLineClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; // // Verify size/offset/string params given our input buffer/size // if ((pParams->dwCallParamsOffset != TAPI_NO_DATA) && IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwCallParamsOffset )) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LSetupTransfer_return; } // // Reference the tLineClient // try { hLine = ptCallClient->ptLineClient->hLine; } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LSetupTransfer_return; } if (!(ptLineClient = ReferenceObject( ghHandleTable, hLine, TLINECLIENT_KEY ))) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSetupTransfer_return; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; dwAPIVersion = ptLineClient->dwAPIVersion; try { dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_OPERATIONFAILED; goto LSetupTransfer_Dereference; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LSetupTransfer_Dereference; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( ptLineClient, &ptConsultCall, &ptConsultCallClient, NULL, &hConsultCall, NULL ) != 0) { lRequestID = LINEERR_NOMEM; goto LSetupTransfer_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptConsultCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptConsultCall; pAsyncRequestInfo->dwParam2 = pParams->hpConsultCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hConsultCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineSetupTransfer, "lineSetupTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall, (ULONG_PTR) hConsultCall, (ULONG_PTR) &ptConsultCall->hdCall, (ULONG_PTR) pCallParamsSP ); SetDrvCallFlags( hConsultCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); LSetupTransfer_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } LSetupTransfer_Dereference: DereferenceObject (ghHandleTable, hLine, 1); } LSetupTransfer_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SetupTransfer" ); } void WINAPI LShutdown( PTCLIENT ptClient, PLINESHUTDOWN_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { pParams->lResult = DestroytLineApp ((HLINEAPP) pParams->hLineApp); #if DBG { char szResult[32]; LOG((TL_TRACE, "lineShutdown: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "lineShutdown: exit, result=x%x", pParams->lResult )); #endif } void WINAPI LSwapHold( PTCLIENT ptClient, PLINESWAPHOLD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdActiveCall; TSPIPROC pfnTSPI_lineSwapHold; DWORD objectToDereference; PTCALLCLIENT ptActiveCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type pParams->hActiveCall, // client widget handle (LPVOID) &hdActiveCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINESWAPHOLD, // provider func index &pfnTSPI_lineSwapHold, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptActiveCallClient, // context "SwapHold" // func name )) > 0) { HDRVCALL hdHeldCall; PTCALLCLIENT ptHeldCallClient; // // Verify held call // if (!(ptHeldCallClient = ReferenceObject( ghHandleTable, pParams->hHeldCall, TCALLCLIENT_KEY ))) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_epilog; } if (ptHeldCallClient->ptClient != ptClient) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_Dereference; } // // Safely verify that client has owner privilege to held call, // and that calls are on same tLine // try { if (!(ptHeldCallClient->dwPrivilege & LINECALLPRIVILEGE_OWNER)) { lRequestID = LINEERR_NOTOWNER; goto LSwapHold_Dereference; } if (ptHeldCallClient->ptCall->ptLine != ptActiveCallClient->ptCall->ptLine) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_Dereference; } hdHeldCall = ptHeldCallClient->ptCall->hdCall; } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_Dereference; } // // Are they the same call? // if (hdActiveCall == hdHeldCall) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_Dereference; } pParams->lResult = CallSP3( pfnTSPI_lineSwapHold, "lineSwapHold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdActiveCall, (ULONG_PTR) hdHeldCall ); LSwapHold_Dereference: DereferenceObject (ghHandleTable, pParams->hHeldCall, 1); } LSwapHold_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "SwapHold" ); } void WINAPI LUncompleteCall( PTCLIENT ptClient, PLINEUNCOMPLETECALL_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineUncompleteCall; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEUNCOMPLETECALL, // provider func index &pfnTSPI_lineUncompleteCall,// provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "UncompleteCall" // func name )) > 0) { pParams->lResult = CallSP3( pfnTSPI_lineUncompleteCall, "lineUncompleteCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwCompletionID ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "UncompleteCall" ); } void WINAPI LUnhold( PTCLIENT ptClient, PLINEUNHOLD_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineUnhold; DWORD objectToDereference; PTCALLCLIENT ptCallClient; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) pParams->hCall, // client widget handle (LPVOID) &hdCall, // provider widget handle LINECALLPRIVILEGE_OWNER, // req'd privileges (call only) &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEUNHOLD, // provider func index &pfnTSPI_lineUnhold, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptCallClient, // context "Unhold" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineUnhold, "lineUnhold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Unhold" ); } void WINAPI LUnpark( PTCLIENT ptClient, PLINEUNPARK_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineUnpark; DWORD objectToDereference; PTLINECLIENT ptLineClient; PASYNCREQUESTINFO pAsyncRequestInfo; // // Verify size/offset/string params given our input buffer/size // if (IsBadStringParam( dwParamsBufferSize, pDataBuf, pParams->dwDestAddressOffset )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((lRequestID = LINEPROLOG( ptClient, // tClient ANY_RT_HLINE, // widget type (DWORD) pParams->hLine, // client widget handle (LPVOID) &hdLine, // provider widget handle 0, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEUNPARK, // provider func index &pfnTSPI_lineUnpark, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID &objectToDereference, // object to dereference &ptLineClient, // context "Unpark" // func name )) > 0) { PTCALL ptCall; HCALL hCall; PTCALLCLIENT ptCallClient; if (CreatetCallAndClient( ptLineClient, &ptCall, &ptCallClient, NULL, &hCall, NULL ) != 0) { lRequestID = LINEERR_NOMEM; goto LUnpark_return; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->htXxx = (ULONG_PTR)ptCallClient->ptLineClient->ptLine->hLine; pAsyncRequestInfo->dwParam1 = (ULONG_PTR) ptCall; pAsyncRequestInfo->dwParam2 = pParams->hpCall; pAsyncRequestInfo->dwParam5 = (ULONG_PTR)hCall; pAsyncRequestInfo->hfnClientPostProcessProc = pParams->hfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineUnpark, "lineUnpark", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo->dwLocalRequestID, (ULONG_PTR) hdLine, (DWORD) pParams->dwAddressID, (ULONG_PTR) hCall, (ULONG_PTR) &ptCall->hdCall, (ULONG_PTR) (pDataBuf + pParams->dwDestAddressOffset) ); SetDrvCallFlags( hCall, DCF_SPIRETURNED | (IS_LRESULT_NOTERROR(pParams->lResult) ? DCF_DRVCALLVALID : 0) ); } LUnpark_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, objectToDereference, "Unpark" ); } void WINAPI TAllocNewID( PTCLIENT ptClient, P_ALLOCNEWID_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { HKEY hKey; HKEY hKey2; DWORD dwDataSize; DWORD dwDataType; DWORD dwNewID; DWORD dwDisposition; RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey2, &dwDisposition ); RegCreateKeyEx( hKey2, gszLocations, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisposition ); dwDataSize = sizeof(DWORD); // // Use 1 as the first ID. // pParams->dwNewID = 1; RegQueryValueEx( hKey, gszNextID, 0, &dwDataType, (LPBYTE)&pParams->dwNewID, &dwDataSize ); dwNewID = pParams->dwNewID + 1; RegSetValueEx( hKey, gszNextID, 0, REG_DWORD, (LPBYTE)&dwNewID, sizeof(DWORD) ); RegCloseKey( hKey ); RegCloseKey( hKey2); *pdwNumBytesReturned = sizeof(ALLOCNEWID_PARAMS); return; } #define MAX_KEY_LENGTH 256 DWORD RegDeleteKeyNT(HKEY hStartKey , LPCTSTR pKeyName ) { DWORD dwRtn, dwSubKeyLength; LPTSTR pSubKey = NULL; TCHAR szSubKey[MAX_KEY_LENGTH]; // (256) this should be dynamic. HKEY hKey; // Do not allow NULL or empty key name if ( pKeyName && lstrlen(pKeyName)) { if( (dwRtn=RegOpenKeyEx(hStartKey,pKeyName, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey )) == ERROR_SUCCESS) { while (dwRtn == ERROR_SUCCESS ) { dwSubKeyLength = MAX_KEY_LENGTH; dwRtn=RegEnumKeyEx( hKey, 0, // always index zero szSubKey, &dwSubKeyLength, NULL, NULL, NULL, NULL ); if(dwRtn == ERROR_NO_MORE_ITEMS) { dwRtn = RegDeleteKey(hStartKey, pKeyName); break; } else if(dwRtn == ERROR_SUCCESS) dwRtn=RegDeleteKeyNT(hKey, szSubKey); } RegCloseKey(hKey); // Do not save return code because error // has already occurred } } else dwRtn = ERROR_BADKEY; return dwRtn; } void WINAPI TWriteLocations( PTCLIENT ptClient, PW_LOCATIONS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwLocationID; DWORD dwCount,dwCount2,dwError; DWORD dwDisposition; DWORD dwNumEntries,dwNumRules; DWORD dwVersion; TCHAR szCurrentLocationKey[256]; TCHAR szCurrentRuleKey[256]; HKEY hAllLocationsKey = NULL; HKEY hLocationKey; HKEY hAllAreaCodeRulesKey; HKEY hAreaCodeRuleKey; HKEY hTelephonyKey; HKEY hUTelephonyKey; HKEY hUAllLocationsKey = NULL; HANDLE CurrentUserKey; PLOCATIONLIST pLocationList = NULL; PLOCATION pLocation = NULL; PAREACODERULE pAreaCodeRule = NULL; BOOL bRelMutex = FALSE; HANDLE hProvidersMutex; LOG((TL_TRACE, "TWriteLocations: enter")); hProvidersMutex = CreateMutex ( NULL, FALSE, TEXT("TapisrvProviderListMutex") ); if (NULL == hProvidersMutex) { LOG((TL_ERROR, "WriteLocation: CreateMutex failed, err=%d", GetLastError() )); goto ExitHere; } WaitForSingleObject (hProvidersMutex, INFINITE); bRelMutex = TRUE; dwVersion = TAPI_LOCATION_LIST_VERSION; if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hTelephonyKey, &dwDisposition ) != ERROR_SUCCESS) { goto ExitHere; } if (RegCreateKeyEx( hTelephonyKey, gszLocations, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hAllLocationsKey, &dwDisposition ) != ERROR_SUCCESS) { RegCloseKey(hTelephonyKey); goto ExitHere; } RegSetValueEx( hAllLocationsKey, gszLocationListVersion, 0, REG_DWORD, (BYTE *)&dwVersion, sizeof(dwVersion) ); RegCloseKey( hTelephonyKey ); ///////////////////////////////////////////////////// // Now open clients key // if ((dwError=RpcImpersonateClient (0)) != RPC_S_OK) { LOG((TL_ERROR, "WriteLocation: RpcImpersonateClient failed, err=%d", dwError )); goto ExitHere; } else { if (RtlOpenCurrentUser(KEY_ALL_ACCESS, &CurrentUserKey) != ERROR_SUCCESS) { RpcRevertToSelf(); goto ExitHere; } dwError = RegCreateKeyEx( CurrentUserKey, gszRegKeyTelephony, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hUTelephonyKey, &dwDisposition ); if ( dwError != ERROR_SUCCESS ) { LOG((TL_ERROR, "Registry can't create/open Users telephony key")); NtClose(CurrentUserKey); RpcRevertToSelf(); goto ExitHere; } NtClose(CurrentUserKey); dwError = RegCreateKeyEx( hUTelephonyKey, gszLocations, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hUAllLocationsKey, &dwDisposition ); if ( dwError != ERROR_SUCCESS ) { LOG((TL_ERROR, "Registry can't create/open Users Locations key")); RegCloseKey( hUTelephonyKey ); RpcRevertToSelf(); goto ExitHere; } RegSetValueEx( hUAllLocationsKey, gszLocationListVersion, 0, REG_DWORD, (BYTE *)&dwVersion, sizeof(dwVersion) ); RegCloseKey( hUTelephonyKey ); RpcRevertToSelf(); } pLocationList = (PLOCATIONLIST)(pDataBuf + pParams->dwLocationListOffset); if ( pParams->dwChangedFlags & CHANGEDFLAGS_CURLOCATIONCHANGED ) { RegSetValueEx( hAllLocationsKey, gszCurrentID, 0, REG_DWORD, (LPBYTE)&pLocationList->dwCurrentLocationID, sizeof(DWORD) ); } // Find position of 1st LOCATION structure in the LOCATIONLIST structure pLocation = (PLOCATION) ((BYTE*)(pLocationList) + pLocationList->dwLocationListOffset ); // Number of locations ? dwNumEntries = pLocationList->dwNumLocationsInList; for (dwCount = 0; dwCount < dwNumEntries ; dwCount++) { //Form key name for this location dwLocationID = pLocation->dwPermanentLocationID; wsprintf(szCurrentLocationKey, TEXT("Location%d"), dwLocationID); // Is Entry to be deleted from reg ? if(pLocation->dwLocationNameSize > sizeof(WCHAR) && *(WCHAR *)((BYTE*)(pLocation) + pLocation->dwLocationNameOffset) != 0) // not just NULL { LOG((TL_INFO, "Location - write %s",szCurrentLocationKey)); // Create or open key for this location dwError = RegCreateKeyEx( hAllLocationsKey, szCurrentLocationKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hLocationKey, &dwDisposition ); if (dwError == ERROR_SUCCESS) { // Country ID if(RegSetValueEx( hLocationKey, gszCountry, 0, REG_DWORD, (LPBYTE)&pLocation->dwCountryID, sizeof(DWORD) ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write country")); } // Options (flags) if(RegSetValueEx( hLocationKey, gszFlags, 0, REG_DWORD, (LPBYTE)&pLocation->dwOptions, sizeof(DWORD) ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write Flags")); } // Name if(TAPIRegSetValueExW( hLocationKey, gszNameW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwLocationNameOffset, pLocation->dwLocationNameSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write Name")); } // AreaCode if(TAPIRegSetValueExW( hLocationKey, gszAreaCodeW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwAreaCodeOffset, pLocation->dwAreaCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write area code")); } // CallWaiting if(TAPIRegSetValueExW( hLocationKey, gszDisableCallWaitingW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwCancelCallWaitingOffset, pLocation->dwCancelCallWaitingSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write call waiting")); } // LD Carrier Code if(TAPIRegSetValueExW( hLocationKey, gszLongDistanceCarrierCodeW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwLongDistanceCarrierCodeOffset, pLocation->dwLongDistanceCarrierCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write LD carrier code")); } // International Carrier Code if(TAPIRegSetValueExW( hLocationKey, gszInternationalCarrierCodeW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwInternationalCarrierCodeOffset, pLocation->dwInternationalCarrierCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write International carrier code")); } // LD Access if(TAPIRegSetValueExW( hLocationKey, gszLongDistanceAccessW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwLongDistanceAccessCodeOffset, pLocation->dwLongDistanceAccessCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write LD access code")); } // Local Access if(TAPIRegSetValueExW( hLocationKey, gszOutsideAccessW, 0, REG_SZ, (BYTE*)(pLocation) + pLocation->dwLocalAccessCodeOffset, pLocation->dwLocalAccessCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Location - can't write Local access code")); } // if this is an existing key then delete all the subkeys RegDeleteKeyNT(hLocationKey, gszAreaCodeRules ); // create or open the AreaCodeRules key dwError = RegCreateKeyEx( hLocationKey, gszAreaCodeRules, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hAllAreaCodeRulesKey, &dwDisposition ); if (dwError == ERROR_SUCCESS) { // Find position of 1st AREACODERULE structure in the LOCATION structure pAreaCodeRule = (PAREACODERULE) ((BYTE*)(pLocation) + pLocation->dwAreaCodeRulesListOffset ); dwNumRules = pLocation->dwNumAreaCodeRules; for (dwCount2 = 0; dwCount2 != dwNumRules; dwCount2++) { //Form key name for this aea code rule wsprintf(szCurrentRuleKey, TEXT("Rule%d"),dwCount2); // create or open this Area Code Rule Key dwError = RegCreateKeyEx( hAllAreaCodeRulesKey, szCurrentRuleKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hAreaCodeRuleKey, &dwDisposition ); if (dwError == ERROR_SUCCESS) { // Pull Dataout of AREACODERULE structure // Options (flags) if(RegSetValueEx( hAreaCodeRuleKey, gszFlags, 0, REG_DWORD, (LPBYTE)&pAreaCodeRule->dwOptions, sizeof(DWORD) ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't write Flags")); } // AreaCode to call if(TAPIRegSetValueExW( hAreaCodeRuleKey, gszAreaCodeToCallW, 0, REG_SZ, (BYTE*)(pLocation) + pAreaCodeRule->dwAreaCodeOffset, pAreaCodeRule->dwAreaCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't write Area code to call")); } //Number to Dial if(TAPIRegSetValueExW( hAreaCodeRuleKey, gszNumberToDialW, 0, REG_SZ, (BYTE*)(pLocation) + pAreaCodeRule->dwNumberToDialOffset, pAreaCodeRule->dwNumberToDialSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't write Number to dial")); } //Prefixes List if(TAPIRegSetValueExW( hAreaCodeRuleKey, gszPrefixesW, 0, REG_MULTI_SZ, (BYTE*)(pLocation) + pAreaCodeRule->dwPrefixesListOffset, pAreaCodeRule->dwPrefixesListSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't write Prefixes")); } RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore... } else { LOG((TL_ERROR, "can't create/open hAreaCodeRuleKey")); } pAreaCodeRule++; } RegCloseKey(hAllAreaCodeRulesKey); } else { LOG((TL_ERROR, "can't create/open hAllAreaCodeRulesKey")); } RegCloseKey(hLocationKey); ///////////////////////////////////////////////////// // Now do clients location entry // // Create or open key for this location dwError = RegCreateKeyEx( hUAllLocationsKey, szCurrentLocationKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hLocationKey, &dwDisposition ); if (dwError == ERROR_SUCCESS) { // CallingCard if(RegSetValueEx( hLocationKey, gszCallingCard, 0, REG_DWORD, (LPBYTE)&pLocation->dwPreferredCardID, sizeof(DWORD) ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't user preferred card")); } RegCloseKey( hLocationKey ); // Don't need this key anymore... } } else { LOG((TL_ERROR, "can't create/open hLocationKey")); } } else //Delete this location entry { LOG((TL_ERROR, "Location - delete %s",szCurrentLocationKey)); RegDeleteKeyNT( hAllLocationsKey, szCurrentLocationKey ); ///////////////////////////////////////////////////// // Now do clients location entry // RegDeleteKey(hUAllLocationsKey, szCurrentLocationKey); } // Try next location in list //pEntry++; pLocation = (PLOCATION) ((BYTE*)(pLocation) + pLocation->dwUsedSize); } // // We're inside "if (dwChangedFlags)", so we know _something_ changed... // LOG((TL_TRACE, "Sending LINE_LINEDEVSTATE/LINEDEVSTATE_TRANSLATECHANGE msg")); SendAMsgToAllLineApps( 0x80010004, // (OR with 0x80000000 for >= version) LINE_LINEDEVSTATE, LINEDEVSTATE_TRANSLATECHANGE, 0, 0 ); SendAMsgToAllLineApps( 0x00010003, LINE_LINEDEVSTATE, LINEDEVSTATE_REINIT, LINE_LINEDEVSTATE, LINEDEVSTATE_TRANSLATECHANGE ); LOG((TL_TRACE, "TWriteLocations: exit")); ExitHere: if (hAllLocationsKey != NULL) { RegCloseKey(hAllLocationsKey); } if (hUAllLocationsKey != NULL) { RegCloseKey(hUAllLocationsKey); } if (bRelMutex && hProvidersMutex) { ReleaseMutex (hProvidersMutex); CloseHandle (hProvidersMutex); } return; } void WINAPI TReadLocations( PTCLIENT ptClient, PR_LOCATIONS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PLOCATIONLIST pLocationList = (PLOCATIONLIST)(pDataBuf); UINT n; UINT nNumLocations; UINT nCurrentLocationID; TCHAR szCurrentLocationKey[256]; // Holds "LOCATIONxx" during reads TCHAR szAreaCodeRuleKey[256]; // Holds "Rulexx" during reads DWORD dwDataSize,dwKeySize; DWORD dwNumLocationKeys=0; DWORD dwMaxLocationKeyLength=0; DWORD dwNumAreaCodeKeys=0; DWORD dwMaxAreaCodeKeyLength=0; DWORD dwDataType; DWORD dwNeededSize = 0; DWORD dwCount, dwCount2; DWORD dwError; HKEY hAllLocationsKey; HKEY hLocationKey; HKEY hAllAreaCodeRulesKey; HKEY hAreaCodeRuleKey; HKEY hTelephonyKey; HKEY hUTelephonyKey; HKEY hUserAllLocationsKey; HANDLE CurrentUserKey; BOOL bRelMutex = FALSE; HANDLE hProvidersMutex; LOG((TL_TRACE, "TReadLocations: enter")); // // Verify size/offset/string params given our input buffer/size // if (pParams->dwLocationsTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWHLINEAPP ) { if ( 0 == pParams->dwhLineApp ) { // // NULL is valid for these functions... // } else { if ( !IsValidLineApp((HLINEAPP)pParams->dwhLineApp, ptClient) ) { LOG((TL_ERROR, "0x%lx is not a valid hLineApp", pParams->dwhLineApp)); pParams->lResult = LINEERR_INVALAPPHANDLE; goto CLEANUP_ERROR; } } } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWDEVICEID ) { if ( pParams->dwhLineApp && (pParams->dwDeviceID != 0) && (pParams->dwDeviceID >= TapiGlobals.dwNumLines) ) { LOG((TL_ERROR, "%ld is not a valid dwDeviceID", pParams->dwDeviceID)); pParams->lResult = LINEERR_BADDEVICEID; goto CLEANUP_ERROR; } } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWAPIVERSION ) { switch (pParams->dwAPIVersion) { case TAPI_VERSION_CURRENT: case TAPI_VERSION3_0: case TAPI_VERSION2_2: case TAPI_VERSION2_1: case TAPI_VERSION2_0: case TAPI_VERSION1_4: case TAPI_VERSION1_0: break; default: LOG((TL_ERROR, "TReadLocations: invalid API version x%x", pParams->dwAPIVersion )); pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto CLEANUP_ERROR; } } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_ONLY ) { LOG((TL_INFO, "TReadLocations: Check only, no data transfer")); pParams->lResult = 0; if (pParams->dwLocationsTotalSize >= 3 * sizeof(DWORD)) { pLocationList->dwTotalSize = pParams->dwLocationsTotalSize; pLocationList->dwNeededSize = pLocationList->dwUsedSize = 3 * sizeof(DWORD); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + (3 * sizeof(DWORD)); } else { *pdwNumBytesReturned = sizeof (TAPI32_MSG); } pParams->dwLocationsOffset = 0; goto CLEANUP_ERROR; } hProvidersMutex = CreateMutex ( NULL, FALSE, TEXT("TapisrvProviderListMutex") ); if (NULL == hProvidersMutex) { LOG((TL_ERROR, "TReadLocations: CreateMutex failed, err=%d", GetLastError() )); pParams->lResult = LINEERR_OPERATIONFAILED; goto CLEANUP_ERROR; } WaitForSingleObject (hProvidersMutex, INFINITE); bRelMutex = TRUE; dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hTelephonyKey ); if (dwError == ERROR_SUCCESS) { dwError = RegOpenKeyEx( hTelephonyKey, gszLocations, 0, KEY_READ, &hAllLocationsKey ); RegCloseKey( hTelephonyKey ); // Don't need this key anymore... } if ( dwError != ERROR_SUCCESS ) { LOG((TL_ERROR, "ReadLocation: Registry can't open Locations key")); pParams->lResult = LINEERR_INIFILECORRUPT; goto CLEANUP_ERROR; } // Test the version of the Machine Locations key. Upgrade if necessary. if(IsLocationListInOldFormat(hAllLocationsKey)) { LOG((TL_INFO, "ReadLocation: Upgrade the Machine Locations key")); dwError = ConvertLocations(); if(dwError != ERROR_SUCCESS) { LOG((TL_ERROR, "ReadLocation: Cannot convert the Machine Locations key")); } } ///////////////////////////////////////////////////// // Now open clients key // if ((dwError=RpcImpersonateClient (0)) != RPC_S_OK) { LOG((TL_ERROR, "ReadLocation: RpcImpersonateClient failed, err=%d", dwError )); pParams->lResult = LINEERR_OPERATIONFAILED; goto CLEANUP_ERROR; } else { RtlOpenCurrentUser(KEY_ALL_ACCESS, &CurrentUserKey); dwError = RegOpenKeyEx( CurrentUserKey, gszRegKeyTelephony, 0, KEY_READ, &hUTelephonyKey ); if ( dwError != ERROR_SUCCESS ) { LOG((TL_ERROR, " Registry can't open Users Locations key")); RpcRevertToSelf(); RegCloseKey( hAllLocationsKey ); NtClose(CurrentUserKey); pParams->lResult = LINEERR_OPERATIONFAILED; goto CLEANUP_ERROR; } if (RegOpenKeyEx( hUTelephonyKey, gszLocations, 0, KEY_READ, &hUserAllLocationsKey ) != ERROR_SUCCESS) { hUserAllLocationsKey = NULL; } RegCloseKey( hUTelephonyKey ); // Don't need this key anymore... RpcRevertToSelf(); // Test the version of the User Locations key. Upgrade if necessary. if(hUserAllLocationsKey && IsLocationListInOldFormat(hUserAllLocationsKey)) { dwError = ConvertUserLocations(CurrentUserKey); if(dwError != ERROR_SUCCESS) { LOG((TL_ERROR, " Cannot convert the User Locations key")); } } NtClose(CurrentUserKey); } dwDataSize = sizeof(nCurrentLocationID); nCurrentLocationID = 0; RegQueryValueEx( hAllLocationsKey, gszCurrentID, 0, &dwDataType, (LPBYTE)&nCurrentLocationID, &dwDataSize ); // query some info about the Locations key in order to allocate memory RegQueryInfoKey(hAllLocationsKey, NULL, NULL, NULL, &dwNumLocationKeys, &dwMaxLocationKeyLength, NULL, NULL, NULL, NULL, NULL, NULL ); // // It's _REALLY_ bad if NumLocations is zero for any // reason. Should probably fail the function on the spot... // if ( 0 == dwNumLocationKeys ) { LOG((TL_ERROR, " Registry says there are 0 locations")); pParams->lResult = LINEERR_INIFILECORRUPT; RegCloseKey( hAllLocationsKey ); if (hUserAllLocationsKey) { RegCloseKey(hUserAllLocationsKey); } goto CLEANUP_ERROR; } // Need to work out need size, so start with static part of list dwNeededSize = ALIGN(sizeof(LOCATIONLIST)); // go though locations to work out needed size for (dwCount=0; dwCount < dwNumLocationKeys ; dwCount++) { dwKeySize = sizeof(szCurrentLocationKey)/sizeof(TCHAR); dwError = RegEnumKeyEx( hAllLocationsKey, dwCount, szCurrentLocationKey, &dwKeySize, NULL, NULL, NULL, NULL ); if(dwError == ERROR_NO_MORE_ITEMS) { break; } if (dwError != ERROR_SUCCESS ) { continue; } // Open this Location Key dwError = RegOpenKeyEx( hAllLocationsKey, szCurrentLocationKey, 0, KEY_ALL_ACCESS, &hLocationKey ); if (dwError == ERROR_SUCCESS) { //Static part then strings dwNeededSize += ALIGN(sizeof(LOCATION)); // Name if (TAPIRegQueryValueExW( hLocationKey, gszNameW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); // AreaCode if (TAPIRegQueryValueExW( hLocationKey, gszAreaCodeW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); //CallWaiting if (TAPIRegQueryValueExW( hLocationKey, gszDisableCallWaitingW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); //LD Carrier if (TAPIRegQueryValueExW( hLocationKey, gszLongDistanceCarrierCodeW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); //International Carrier if (TAPIRegQueryValueExW( hLocationKey, gszInternationalCarrierCodeW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); //LD Access if (TAPIRegQueryValueExW( hLocationKey, gszLongDistanceAccessW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); //Local Access if (TAPIRegQueryValueExW( hLocationKey, gszOutsideAccessW, NULL, NULL, NULL, &dwDataSize ) != ERROR_SUCCESS) { dwDataSize = sizeof(WCHAR); } dwNeededSize += ALIGN(dwDataSize); dwError = RegOpenKeyEx( hLocationKey, gszAreaCodeRules, 0, KEY_READ, &hAllAreaCodeRulesKey ); if (dwError == ERROR_SUCCESS) { // query info about the AreaCodeRules key RegQueryInfoKey(hAllAreaCodeRulesKey, NULL, NULL, NULL, &dwNumAreaCodeKeys, &dwMaxAreaCodeKeyLength, NULL, NULL, NULL, NULL, NULL, NULL ); // go though this location's area code rules for (dwCount2=0; dwCount2 < dwNumAreaCodeKeys; dwCount2++) { dwKeySize = sizeof(szAreaCodeRuleKey)/sizeof(TCHAR); dwError = RegEnumKeyEx( hAllAreaCodeRulesKey, dwCount2, szAreaCodeRuleKey, &dwKeySize, NULL, NULL, NULL, NULL ); if(dwError == ERROR_NO_MORE_ITEMS) { break; } if (dwError != ERROR_SUCCESS ) { continue; } // Open this Aeea Code Rule Key dwError = RegOpenKeyEx( hAllAreaCodeRulesKey, szAreaCodeRuleKey, 0, KEY_ALL_ACCESS, &hAreaCodeRuleKey ); if (dwError == ERROR_SUCCESS) { //Static part then strings dwNeededSize += ALIGN(sizeof(AREACODERULE)); // AreaCode to call TAPIRegQueryValueExW( hAreaCodeRuleKey, gszAreaCodeToCallW, NULL, NULL, NULL, &dwDataSize ); dwNeededSize += ALIGN(dwDataSize); //Number to Dial TAPIRegQueryValueExW( hAreaCodeRuleKey, gszNumberToDialW, NULL, NULL, NULL, &dwDataSize ); dwNeededSize += ALIGN(dwDataSize); //Number to Dial TAPIRegQueryValueExW( hAreaCodeRuleKey, gszPrefixesW, NULL, NULL, NULL, &dwDataSize ); dwNeededSize += ALIGN(dwDataSize); RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore... } } RegCloseKey( hAllAreaCodeRulesKey ); // Don't need this key anymore... } } RegCloseKey( hLocationKey ); // Don't need this key anymore... } // // Do we have enough space? // if ( pParams->dwLocationsTotalSize < dwNeededSize ) { LOG((TL_ERROR, "(0x%08lx) is not enough room for sizeof( 0x%08lx )", pParams->dwLocationsTotalSize, dwNeededSize )); // // Buffer not large enough // pLocationList->dwTotalSize = pParams->dwLocationsTotalSize; pLocationList->dwNeededSize = dwNeededSize; pLocationList->dwUsedSize = sizeof(LOCATIONLIST); pLocationList->dwNumLocationsInList = 0; pLocationList->dwLocationListSize = 0; pLocationList->dwLocationListOffset = 0; pParams->lResult = 0; pParams->dwLocationsOffset = 0; } else // Big enough buffer, now fill it { DWORD dwLocationOffset, dwOffset; PLOCATION pLocation; PAREACODERULE pAreaCodeRule; DWORD dwMaxValueLength; // buffer size pLocationList->dwTotalSize = pParams->dwLocationsTotalSize; pLocationList->dwNeededSize = dwNeededSize; pLocationList->dwUsedSize = dwNeededSize; // Results pParams->lResult = 0; pParams->dwLocationsOffset = 0; pLocationList->dwCurrentLocationID = nCurrentLocationID; pLocationList->dwNumLocationsAvailable = dwNumLocationKeys; //list size & offset dwLocationOffset = ALIGN(sizeof(LOCATIONLIST)); pLocationList->dwNumLocationsInList = dwNumLocationKeys; pLocationList->dwLocationListSize = dwNeededSize - sizeof(LOCATIONLIST); pLocationList->dwLocationListOffset = dwLocationOffset; // go through locations for (dwCount=0; dwCount < dwNumLocationKeys ; dwCount++) { dwKeySize = dwMaxLocationKeyLength + 1; dwError = RegEnumKeyEx( hAllLocationsKey, dwCount, szCurrentLocationKey, &dwKeySize, NULL, NULL, NULL, NULL ); if(dwError == ERROR_NO_MORE_ITEMS) { break; } pLocation = (PLOCATION)(((LPBYTE)pLocationList) + dwLocationOffset); // Open this Location Key dwError = RegOpenKeyEx( hAllLocationsKey, szCurrentLocationKey, 0, KEY_ALL_ACCESS, &hLocationKey ); if (dwError == ERROR_SUCCESS) { LOG((TL_INFO, "Location - read %S",szCurrentLocationKey)); // Find out how big is our biggest value dwMaxValueLength = 256; RegQueryInfoKey(hLocationKey,0,0,0,0,0,0,0,0,&dwMaxValueLength,0,0); ///////////////////////////////////////////////////////////////////// // Process fized part of Location info dwOffset = ALIGN(sizeof(LOCATION)); //pLocation->dwPreferredCardID = m_dwPreferredCardID; // Location ID (is included in the key name) pLocation->dwPermanentLocationID = 0; if(dwKeySize >= ARRAYSIZE(gszLocation)) // minimum a Location_ key { pLocation->dwPermanentLocationID = (DWORD)_ttol(szCurrentLocationKey + (ARRAYSIZE(gszLocation))-1); } else { LOG((TL_ERROR, "location - can't determine ID")); } // Country ID dwDataSize = sizeof(DWORD); pLocation->dwCountryID = 1; if(RegQueryValueEx( hLocationKey, gszCountry, 0, &dwDataType, (LPBYTE)&pLocation->dwCountryID, &dwDataSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read CountryID")); } // Options (flags) dwDataSize = sizeof(DWORD); pLocation->dwOptions = 0; if(RegQueryValueEx( hLocationKey, gszFlags, 0, &dwDataType, (LPBYTE)&pLocation->dwOptions, &dwDataSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read Flags")); } // Name pLocation->dwLocationNameSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszNameW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwLocationNameSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read Name")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwLocationNameSize = sizeof(WCHAR); } pLocation->dwLocationNameOffset = dwOffset; dwOffset += ALIGN(pLocation->dwLocationNameSize); // AreaCode pLocation->dwAreaCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszAreaCodeW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwAreaCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read Area code")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwAreaCodeSize = sizeof(WCHAR); } pLocation->dwAreaCodeOffset = dwOffset; dwOffset += ALIGN(pLocation->dwAreaCodeSize); // CallWaiting pLocation->dwCancelCallWaitingSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszDisableCallWaitingW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwCancelCallWaitingSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read Callwaiting")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwCancelCallWaitingSize = sizeof(WCHAR); } pLocation->dwCancelCallWaitingOffset = dwOffset; dwOffset += ALIGN(pLocation->dwCancelCallWaitingSize); // LD Carrier pLocation->dwLongDistanceCarrierCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszLongDistanceCarrierCodeW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwLongDistanceCarrierCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read LD carrier code")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwLongDistanceCarrierCodeSize = sizeof(WCHAR); } pLocation->dwLongDistanceCarrierCodeOffset = dwOffset; dwOffset += ALIGN(pLocation->dwLongDistanceCarrierCodeSize); // International Carrier pLocation->dwInternationalCarrierCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszInternationalCarrierCodeW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwInternationalCarrierCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read International carrier code")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwInternationalCarrierCodeSize = sizeof(WCHAR); } pLocation->dwInternationalCarrierCodeOffset = dwOffset; dwOffset += ALIGN(pLocation->dwInternationalCarrierCodeSize); // LD Access pLocation->dwLongDistanceAccessCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszLongDistanceAccessW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwLongDistanceAccessCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read LD access code")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwLongDistanceAccessCodeSize = sizeof(WCHAR); } pLocation->dwLongDistanceAccessCodeOffset = dwOffset; dwOffset += ALIGN(pLocation->dwLongDistanceAccessCodeSize); // Local Access pLocation->dwLocalAccessCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hLocationKey, gszOutsideAccessW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pLocation->dwLocalAccessCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read local access code")); *(LPWSTR)((LPBYTE)pLocation + dwOffset) = 0; pLocation->dwLocalAccessCodeSize = sizeof(WCHAR); } pLocation->dwLocalAccessCodeOffset = dwOffset; dwOffset += ALIGN(pLocation->dwLocalAccessCodeSize); /////////////////////////////////////////////////////////////////// // Do the Area Code Rules dwError = RegOpenKeyEx( hLocationKey, gszAreaCodeRules, 0, KEY_READ, &hAllAreaCodeRulesKey ); if (dwError == ERROR_SUCCESS) { // Find out how many keys & how long is a key RegQueryInfoKey(hAllAreaCodeRulesKey,0,0,0,&dwNumAreaCodeKeys,&dwMaxAreaCodeKeyLength,0,0,0,0,0,0); pLocation->dwNumAreaCodeRules = dwNumAreaCodeKeys; // pLocation->dwAreaCodeRulesListSize; pLocation->dwAreaCodeRulesListOffset = dwOffset; // point to the 1st rule pAreaCodeRule = (PAREACODERULE)(((LPBYTE)pLocation) + dwOffset); //point strings past rule area dwOffset += ALIGN(( sizeof(AREACODERULE) * dwNumAreaCodeKeys )); // go though this location's area code rules for (dwCount2=0; dwCount2 < dwNumAreaCodeKeys; dwCount2++) { dwKeySize = dwMaxAreaCodeKeyLength + 1; dwError = RegEnumKeyEx( hAllAreaCodeRulesKey, dwCount2, szAreaCodeRuleKey, &dwKeySize, NULL, NULL, NULL, NULL ); if(dwError == ERROR_NO_MORE_ITEMS) { break; } if(dwError != ERROR_SUCCESS) { continue; } // Open this Area Code Rule Key dwError = RegOpenKeyEx( hAllAreaCodeRulesKey, szAreaCodeRuleKey, 0, KEY_ALL_ACCESS, &hAreaCodeRuleKey ); if (dwError == ERROR_SUCCESS) { LOG((TL_ERROR, "ReadLocation - areacode %s",szAreaCodeRuleKey)); // Find out how big is our biggest value RegQueryInfoKey(hAreaCodeRuleKey,0,0,0,0,0,0,0,0,&dwMaxValueLength,0,0); //Static part then strings dwDataSize = sizeof(DWORD); pAreaCodeRule->dwOptions = 0; if(RegQueryValueEx( hAreaCodeRuleKey, gszFlags, 0, &dwDataType, (LPBYTE)&pAreaCodeRule->dwOptions, &dwDataSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't read Flags")); } // AreaCode to call pAreaCodeRule->dwAreaCodeSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hAreaCodeRuleKey, gszAreaCodeToCallW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pAreaCodeRule->dwAreaCodeSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't read Area code to call")); } pAreaCodeRule->dwAreaCodeOffset = dwOffset; dwOffset += ALIGN(pAreaCodeRule->dwAreaCodeSize); //Number to Dial pAreaCodeRule->dwNumberToDialSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hAreaCodeRuleKey, gszNumberToDialW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pAreaCodeRule->dwNumberToDialSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't read number to dial")); } pAreaCodeRule->dwNumberToDialOffset = dwOffset; dwOffset += ALIGN(pAreaCodeRule->dwNumberToDialSize); //Prefixes List pAreaCodeRule->dwPrefixesListSize = dwMaxValueLength; if(TAPIRegQueryValueExW( hAreaCodeRuleKey, gszPrefixesW, NULL, NULL, (LPBYTE)pLocation + dwOffset, &pAreaCodeRule->dwPrefixesListSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "Area code rule - can't read prefixes")); } pAreaCodeRule->dwPrefixesListOffset = dwOffset; dwOffset += ALIGN(pAreaCodeRule->dwPrefixesListSize); RegCloseKey( hAreaCodeRuleKey ); // Don't need this key anymore... pAreaCodeRule++; } } RegCloseKey( hAllAreaCodeRulesKey ); // Don't need this key anymore... } // offset gives how many bytes we used pLocation->dwUsedSize = dwOffset; dwLocationOffset += dwOffset; } RegCloseKey( hLocationKey ); ///////////////////////////////////////////////////// // Now do clients location entry // pLocation->dwPreferredCardID = 0; if (hUserAllLocationsKey) { // Open this Location Key dwError = RegOpenKeyEx( hUserAllLocationsKey, szCurrentLocationKey, 0, KEY_ALL_ACCESS, &hLocationKey ); if (dwError == ERROR_SUCCESS) { // Preferred Card ID dwDataSize = sizeof(DWORD); if(RegQueryValueEx( hLocationKey, gszCallingCard, 0, &dwDataType, (LPBYTE)&pLocation->dwPreferredCardID, &dwDataSize ) != ERROR_SUCCESS) { LOG((TL_ERROR, "location - can't read users PreferredCardID")); } RegCloseKey( hLocationKey ); // Don't need this key anymore... } else { LOG((TL_ERROR, "location - can't read users location key")); } } } } *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pLocationList->dwUsedSize; RegCloseKey(hAllLocationsKey); if (hUserAllLocationsKey) { RegCloseKey(hUserAllLocationsKey); } CLEANUP_ERROR: #if DBG { char szResult[32]; LOG((TL_TRACE, "TReadLocations: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #else LOG((TL_TRACE, "TReadLocations: exit, result=x%x", pParams->lResult )); #endif if (bRelMutex && hProvidersMutex) { ReleaseMutex (hProvidersMutex); CloseHandle (hProvidersMutex); } return; } void WINAPI LReceiveMSPData( PTCLIENT ptClient, PLINERECEIVEMSPDATA_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { TSPIPROC pfnTSPI_lineReceiveMSPData; PTPROVIDER ptProvider; PTLINECLIENT ptLineClient; PTCALLCLIENT ptCallClient = NULL; HDRVMSPLINE hdMSPLine; HDRVCALL hdCall; HDRVLINE hdLine; // // Verify size/offset/string params given our input buffer/size // if (ISBADSIZEOFFSET( dwParamsBufferSize, 0, pParams->dwBufferSize, pParams->dwBufferOffset, sizeof(DWORD), "LReceiveMSPData", "pParams->Buffer" )) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if (!(ptLineClient = ReferenceObject( ghHandleTable, pParams->hLine, TLINECLIENT_KEY ))) { pParams->lResult = LINEERR_INVALLINEHANDLE; return; } if (pParams->hCall) { if (!(ptCallClient = ReferenceObject( ghHandleTable, pParams->hCall, TCALLCLIENT_KEY ))) { DereferenceObject (ghHandleTable, pParams->hLine, 1); pParams->lResult = LINEERR_INVALCALLHANDLE; return; } } hdMSPLine = ptLineClient->hdMSPLine; try { hdLine = ptLineClient->ptLine->hdLine; ptProvider = ptLineClient->ptLine->ptProvider; hdCall = (ptCallClient ? ptCallClient->ptCall->hdCall : 0); if (ptLineClient->dwKey != TLINECLIENT_KEY) { pParams->lResult = LINEERR_INVALLINEHANDLE; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; } DereferenceObject (ghHandleTable, pParams->hLine, 1); if (ptCallClient) { DereferenceObject (ghHandleTable, pParams->hCall, 1); } if (pParams->lResult == 0) { if ((pfnTSPI_lineReceiveMSPData = ptProvider->apfn[SP_LINERECEIVEMSPDATA])) { PBYTE pTemp = pDataBuf + pParams->dwBufferOffset; #ifdef _WIN64 if (!(ALIGNED (pTemp))) { pTemp = ServerAlloc (pParams->dwBufferSize); if (NULL == pTemp) { pParams->lResult = LINEERR_NOMEM; goto LReceiveMSPData_Return; } CopyMemory (pTemp, pDataBuf + pParams->dwBufferOffset, pParams->dwBufferSize); } #endif //_WIN64 pParams->lResult = CallSP5( pfnTSPI_lineReceiveMSPData, "lineReceiveMSPData", SP_FUNC_SYNC, (ULONG_PTR) hdLine, (ULONG_PTR) hdCall, (ULONG_PTR) hdMSPLine, (ULONG_PTR) pTemp, (DWORD) pParams->dwBufferSize ); #ifdef _WIN64 if (pTemp != pDataBuf + pParams->dwBufferOffset) { ServerFree (pTemp); } #endif //_WIN64 } else { pParams->lResult = LINEERR_OPERATIONUNAVAIL; } } #ifdef _WIN64 LReceiveMSPData_Return: #endif //_WIN64 { char szResult[32]; #if DBG LOG((TL_TRACE, "ReceiveMSPData: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); #else LOG((TL_TRACE, "ReceiveMSPData: exit, result=x%x", pParams->lResult )); #endif //DBG } } void WINAPI LMSPIdentify( PTCLIENT ptClient, PLINEMSPIDENTIFY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineMSPIdentify; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (dwParamsBufferSize < sizeof (GUID)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle (LPVOID) &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or deviceID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEMSPIDENTIFY, // provider func index &pfnTSPI_lineMSPIdentify, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "MSPIdentify" // func name )) == 0) { if ((pParams->lResult = CallSP2( pfnTSPI_lineMSPIdentify, "lineMSPIdentify", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) pDataBuf )) == 0) { pParams->dwCLSIDOffset = 0; pParams->dwCLSIDSize = sizeof (GUID); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwCLSIDSize; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "MSPIdentify" ); } void WINAPI PrivateFactoryIdentify( PTCLIENT ptClient, PPRIVATEFACTORYIDENTIFY_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_providerPrivateFactoryIdentify; DWORD objectToDereference; PTLINELOOKUPENTRY pLookupEntry; // // Verify size/offset/string params given our input buffer/size // if (dwParamsBufferSize < sizeof (GUID)) { pParams->lResult = LINEERR_OPERATIONFAILED; return; } if ((pParams->lResult = LINEPROLOG( ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle (LPVOID) &dwDeviceID, // provider widget handle pParams->dwDeviceID, // privileges or deviceID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_PROVIDERPRIVATEFACTORYIDENTIFY, // provider func index &pfnTSPI_providerPrivateFactoryIdentify, // provider func pointer NULL, // async request info 0, // client async request ID &objectToDereference, // object to dereference &pLookupEntry, // context "PrivateFactoryIdentify" // func name )) == 0) { if ((pParams->lResult = CallSP2( pfnTSPI_providerPrivateFactoryIdentify, "providerPrivateFactoryIdentify", SP_FUNC_SYNC, (DWORD) dwDeviceID, (ULONG_PTR) pDataBuf )) == 0) { pParams->dwCLSIDOffset = 0; pParams->dwCLSIDSize = sizeof (GUID); *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwCLSIDSize; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, objectToDereference, "PrivateFactoryIdentify" ); } LPBYTE NewToOldLineforwardlist( LPLINEFORWARDLIST pFwdList3_1 ) { DWORD dwOffset3_0, dwOffset3_1, i; DWORD dwTotalSize; DWORD dwSizeofLFwdList3_0 = sizeof (LINEFORWARDLIST) - 2 * sizeof(DWORD); DWORD dwSizeofLFwd3_0 = sizeof (LINEFORWARD) - 2 * sizeof(DWORD); LPLINEFORWARD pFwdEntry3_1 = NULL; LPBYTE pFwdEntry3_0 = NULL; LPBYTE pFwdList3_0 = NULL; // // Alloc a buffer for storing the converted FORWARDLIST // dwTotalSize = pFwdList3_1->dwTotalSize - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries; pFwdList3_0 = ServerAlloc (dwTotalSize); if (!pFwdList3_0) return NULL; memset (pFwdList3_0, 0, dwTotalSize); ((LPLINEFORWARDLIST)pFwdList3_0)->dwTotalSize = dwTotalSize; ((LPLINEFORWARDLIST)pFwdList3_0)->dwNumEntries = pFwdList3_1->dwNumEntries; dwOffset3_1 = sizeof (LINEFORWARDLIST) + (pFwdList3_1->dwNumEntries - 1) * sizeof (LINEFORWARD); dwOffset3_0 = dwSizeofLFwdList3_0 + (pFwdList3_1->dwNumEntries - 1) * dwSizeofLFwd3_0; CopyMemory (pFwdList3_0 + dwOffset3_0, (LPBYTE)pFwdList3_1 + dwOffset3_1, pFwdList3_1->dwTotalSize - dwOffset3_1); pFwdEntry3_1 = pFwdList3_1->ForwardList; pFwdEntry3_0 = (LPBYTE)((LPLINEFORWARDLIST)pFwdList3_0)->ForwardList; for (i = 0; i < pFwdList3_1->dwNumEntries; i++, pFwdEntry3_1++) { CopyMemory (pFwdEntry3_0, pFwdEntry3_1, dwSizeofLFwd3_0); if (pFwdEntry3_1->dwCallerAddressSize) { ((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressOffset = pFwdEntry3_1->dwCallerAddressOffset - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries; } if (pFwdEntry3_1->dwDestAddressSize) { ((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressOffset = pFwdEntry3_1->dwDestAddressOffset - 2 * sizeof(DWORD) * pFwdList3_1->dwNumEntries; } pFwdEntry3_0 += dwSizeofLFwd3_0; } return pFwdList3_0; } LPLINEFORWARDLIST OldToNewLineforwardlist( LPLINEFORWARDLIST pFwdList3_0 ) { DWORD dwOffset3_0, dwOffset3_1, i; DWORD dwSizeofLFwdList3_0 = sizeof (LINEFORWARDLIST) - 2 * sizeof(DWORD); DWORD dwSizeofLFwd3_0 = sizeof (LINEFORWARD) - 2 * sizeof(DWORD); DWORD dwTotalSize; LPLINEFORWARD pFwdEntry3_1 = NULL; LPBYTE pFwdEntry3_0 = NULL; LPLINEFORWARDLIST pFwdList3_1 = NULL; // // Alloc a buffer for storing the converted FORWARDLIST // dwTotalSize = pFwdList3_0->dwTotalSize + 2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries; pFwdList3_1 = ServerAlloc (dwTotalSize); if (!pFwdList3_1) return NULL; memset (pFwdList3_1, 0, dwTotalSize); pFwdList3_1->dwTotalSize = dwTotalSize; pFwdList3_1->dwNumEntries = pFwdList3_0->dwNumEntries; dwOffset3_1 = sizeof (LINEFORWARDLIST) + (pFwdList3_0->dwNumEntries - 1) * sizeof (LINEFORWARD); dwOffset3_0 = dwSizeofLFwdList3_0 + (pFwdList3_0->dwNumEntries - 1) * dwSizeofLFwd3_0; CopyMemory ((LPBYTE)pFwdList3_1 + dwOffset3_1, (LPBYTE)pFwdList3_0 + dwOffset3_0, pFwdList3_0->dwTotalSize - dwOffset3_0); pFwdEntry3_1 = pFwdList3_1->ForwardList; pFwdEntry3_0 = (LPBYTE)(pFwdList3_0->ForwardList); for (i = 0; i < pFwdList3_0->dwNumEntries; i++, pFwdEntry3_1++) { CopyMemory (pFwdEntry3_1, pFwdEntry3_0, dwSizeofLFwd3_0); if ( ((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressSize ) { pFwdEntry3_1->dwCallerAddressOffset = ((LPLINEFORWARD)pFwdEntry3_0)->dwCallerAddressOffset + 2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries; } if ( ((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressSize ) { pFwdEntry3_1->dwDestAddressOffset = ((LPLINEFORWARD)pFwdEntry3_0)->dwDestAddressOffset + 2 * sizeof(DWORD) * pFwdList3_0->dwNumEntries; } pFwdEntry3_0 += dwSizeofLFwd3_0; } return pFwdList3_1; } LPWSTR WaveDeviceIdToStringId(DWORD dwDeviceId, LPWSTR pwszDeviceType) { LPWSTR pwszStringID = NULL; DWORD dwSize; DWORD_PTR dwParam; if (!pwszDeviceType) return NULL; do { if ( !_wcsicmp(pwszDeviceType, L"wave/in") ) { HWAVEIN hWaveIn; *(DWORD_PTR*)&hWaveIn = dwDeviceId; // get the needed size if (MMSYSERR_NOERROR != waveInMessage( hWaveIn, DRV_QUERYSTRINGIDSIZE, (DWORD_PTR)&dwSize, 0)) break; assert (dwSize != 0); pwszStringID = ServerAlloc (dwSize); if(!pwszStringID) break; dwParam = dwSize; // get the wave string ID if (MMSYSERR_NOERROR != waveInMessage( hWaveIn, DRV_QUERYSTRINGID, (DWORD_PTR)pwszStringID, dwParam)) { ServerFree(pwszStringID); pwszStringID = NULL; } } else if (!_wcsicmp(pwszDeviceType, L"wave/out")) { HWAVEOUT hWaveOut; *(DWORD_PTR*)&hWaveOut = dwDeviceId; // get the needed size if (MMSYSERR_NOERROR != waveOutMessage( hWaveOut, DRV_QUERYSTRINGIDSIZE, (DWORD_PTR)&dwSize, 0)) break; assert (dwSize != 0); pwszStringID = ServerAlloc (dwSize); if(!pwszStringID) break; dwParam = dwSize; // get the wave string ID if (MMSYSERR_NOERROR != waveOutMessage( hWaveOut, DRV_QUERYSTRINGID, (DWORD_PTR)pwszStringID, dwParam)) { ServerFree(pwszStringID); pwszStringID = NULL; } } else if (!_wcsicmp(pwszDeviceType, L"midi/in")) { HMIDIIN hMidiIn; *(DWORD_PTR*)&hMidiIn = dwDeviceId; // get the needed size if (MMSYSERR_NOERROR != midiInMessage( hMidiIn, DRV_QUERYSTRINGIDSIZE, (DWORD_PTR)&dwSize, 0)) break; assert (dwSize != 0); pwszStringID = ServerAlloc (dwSize); if(!pwszStringID) break; dwParam = dwSize; // get the wave string ID if (MMSYSERR_NOERROR != midiInMessage( hMidiIn, DRV_QUERYSTRINGID, (DWORD_PTR)pwszStringID, dwParam)) { ServerFree(pwszStringID); pwszStringID = NULL; } } else if (!_wcsicmp(pwszDeviceType, L"midi/out")) { HMIDIOUT hMidiOut; *(DWORD_PTR*)&hMidiOut = dwDeviceId; // get the needed size if (MMSYSERR_NOERROR != midiOutMessage( hMidiOut, DRV_QUERYSTRINGIDSIZE, (DWORD_PTR)&dwSize, 0)) break; assert (dwSize != 0); pwszStringID = ServerAlloc (dwSize); if(!pwszStringID) break; dwParam = dwSize; // get the wave string ID if (MMSYSERR_NOERROR != midiOutMessage( hMidiOut, DRV_QUERYSTRINGID, (DWORD_PTR)pwszStringID, dwParam)) { ServerFree(pwszStringID); pwszStringID = NULL; } } } while (0); return pwszStringID; }