/*++ BUILD Version: 0000 // Increment this if a change has global effects Copyright (c) 1996 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 "tapi.h" #include "tspi.h" #include "..\client\client.h" #include "..\client\loc_comn.h" #include "server.h" #include "line.h" #include "resource.h" // PERF #include "..\perfdll\tapiperf.h" // PERF extern PERFBLOCK PerfBlock; LPLINECOUNTRYLIST gpCountryList = NULL; DWORD gdwCallInstance = 1; extern TAPIGLOBALS TapiGlobals; extern CRITICAL_SECTION gSafeMutexCritSec, gRequestIDCritSec, gPriorityListCritSec; extern char gszProviders[]; extern WCHAR gszProviderIDW[]; //extern char gszTelephonIni[]; extern char gszNumProviders[]; extern char gszNextProviderID[]; extern char gszProviderFilenameW[]; extern char gszRegKeyTelephony[]; const WCHAR gszLocationW[] = L"Location"; const WCHAR gszLocationsW[] = L"Locations"; extern char gszRegKeyProviders[]; extern PTPROVIDER pRemoteSP; WCHAR gszNameW[] = L"Name"; WCHAR gszIDW[] = L"ID"; WCHAR gszAreaCodeW[] = L"AreaCode"; WCHAR gszCountryW[] = L"Country"; WCHAR gszOutsideAccessW[] = L"OutsideAccess"; WCHAR gszLongDistanceAccessW[] = L"LongDistanceAccess"; WCHAR gszFlagsW[] = L"Flags"; WCHAR gszCallingCardW[] = L"CallingCard"; WCHAR gszDisableCallWaitingW[] = L"DisableCallWaiting"; WCHAR gszTollListW[] = L"TollList"; WCHAR gszNumEntriesW[] = L"NumEntries"; WCHAR gszCurrentIDW[] = L"CurrentID"; WCHAR gszNextIDW[] = L"NextID"; #if DBG extern DWORD gdwDebugLevel; char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult ); #endif void PASCAL DestroytCall( PTCALL ptCall ); void PASCAL DestroytCallClient( PTCALLCLIENT ptCallClient ); void PASCAL DestroytLineClient( PTLINECLIENT ptLineClient ); void LDevSpecific_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ); void LMakeCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ); void WINAPI FreeDialogInstance( PFREEDIALOGINSTANCE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ); void CALLBACK CompletionProcSP( DWORD dwRequestID, LONG lResult ); LONG PASCAL GetPhoneAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ); BOOL IsAPIVersionInRange( DWORD dwAPIVersion, DWORD dwSPIVersion ) { if (dwAPIVersion <= dwSPIVersion) { switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: case TAPI_VERSION_CURRENT: return TRUE; default: break; } } return FALSE; } 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, char *pszCallingFunc, char *pszFieldName ) #else BOOL IsBadSizeOffset( DWORD dwTotalSize, DWORD dwFixedSize, DWORD dwXxxSize, DWORD dwXxxOffset ) #endif { if (dwXxxSize != 0) { DWORD dwSum = dwXxxSize + dwXxxOffset; if (dwXxxOffset < dwFixedSize) { DBGOUT(( 2, "%s: dw%sOffset (=x%x) points at fixed portion (=x%x)" \ " of structure", pszCallingFunc, pszFieldName, dwXxxSize, dwFixedSize )); return TRUE; } else if ((dwSum > dwTotalSize) || (dwSum < dwXxxSize)) { DBGOUT(( 2, "%s: sum of dw%sSize/Offset (=x%x/x%x) > dwTotalSize (=x%x)", pszCallingFunc, pszFieldName, dwXxxSize, dwXxxOffset, dwFixedSize, dwTotalSize )); 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. // #if DBG char szFunc[] = "ValidateCallParams"; #endif DWORD dwTotalSize = pCallParamsApp->dwTotalSize, dwFixedSizeApp, dwFixedSizeSP, dwAllBearerModes, dwAllMediaModes; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwFixedSizeApp = 108; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) dwAllMediaModes = AllMediaModes1_0; dwAllBearerModes = AllBearerModes1_0; break; case TAPI_VERSION1_4: dwFixedSizeApp = 108; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) dwAllMediaModes = AllMediaModes1_4; dwAllBearerModes = AllBearerModes1_4; break; case TAPI_VERSION_CURRENT: dwFixedSizeApp = sizeof (LINECALLPARAMS); dwAllMediaModes = AllMediaModes1_4; dwAllBearerModes = AllBearerModes2_0; break; default: return LINEERR_OPERATIONFAILED; } switch (dwSPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeSP = 108; // 24 * sizeof (DWORD) + sizeof(LINEDIALPARAMS) break; case TAPI_VERSION_CURRENT: dwFixedSizeSP = sizeof (LINECALLPARAMS); break; default: return LINEERR_OPERATIONFAILED; } if (dwTotalSize < dwFixedSizeApp) { DBGOUT(( 3, "%sbad dwTotalSize, x%x (minimum valid size=x%x)", szFunc, dwTotalSize, dwFixedSizeApp )); return LINEERR_STRUCTURETOOSMALL; } if ( (pCallParamsApp->dwBearerMode) && (!IsOnlyOneBitSetInDWORD (pCallParamsApp->dwBearerMode) || (pCallParamsApp->dwBearerMode & ~dwAllBearerModes))) { // // For clarity's sake reset 0 bearer mode to VOICE // if (pCallParamsApp->dwBearerMode == 0) { pCallParamsApp->dwBearerMode = LINEBEARERMODE_VOICE; } else { DBGOUT(( 3, "%sbad dwBearerMode, x%x", szFunc, pCallParamsApp->dwBearerMode )); return LINEERR_INVALBEARERMODE; } } { DWORD dwMediaModeApp = pCallParamsApp->dwMediaMode; if ((dwMediaModeApp & (0x00ffffff ^ dwAllMediaModes)) || (!IsOnlyOneBitSetInDWORD (dwMediaModeApp) && !(dwMediaModeApp & LINEMEDIAMODE_UNKNOWN))) { // // For clarity's sake reset 0 media mode to INTERACTIVEVOICE // if (dwMediaModeApp == 0) { pCallParamsApp->dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE; } else { DBGOUT((3, "%sbad dwMediaMode, x%x", szFunc, dwMediaModeApp)); return LINEERR_INVALMEDIAMODE; } } } if (pCallParamsApp->dwCallParamFlags & ~AllCallParamFlags) { DBGOUT(( 3, "%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 { DBGOUT(( 3, "%sbad dwAddressMode, x%x", szFunc, pCallParamsApp->dwAddressMode )); return LINEERR_INVALADDRESSMODE; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwOrigAddressSize, pCallParamsApp->dwOrigAddressOffset, szFunc, "OrigAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwUserUserInfoSize, pCallParamsApp->dwUserUserInfoOffset, szFunc, "UserUserInfo" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwHighLevelCompSize, pCallParamsApp->dwHighLevelCompOffset, szFunc, "HighLevelComp" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwLowLevelCompSize, pCallParamsApp->dwLowLevelCompOffset, szFunc, "LowLevelComp" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDevSpecificSize, pCallParamsApp->dwDevSpecificOffset, 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, szFunc, "DisplayableAddress" )) { if (dwAPIVersion < TAPI_VERSION2_0) { pCallParamsApp->dwDisplayableAddressSize = pCallParamsApp->dwDisplayableAddressOffset = 0; } else { return LINEERR_INVALCALLPARAMS; } } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCalledPartySize, pCallParamsApp->dwCalledPartyOffset, szFunc, "CalledParty" )) { if (dwAPIVersion < TAPI_VERSION2_0) { pCallParamsApp->dwCalledPartySize = pCallParamsApp->dwCalledPartyOffset = 0; } else { return LINEERR_INVALCALLPARAMS; } } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCommentSize, pCallParamsApp->dwCommentOffset, 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) { DBGOUT(( 3, "%sbad dwPredictiveAutoTransferStates, x%x", szFunc, pCallParamsApp->dwPredictiveAutoTransferStates )); return LINEERR_INVALCALLPARAMS; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwTargetAddressSize, pCallParamsApp->dwTargetAddressOffset, szFunc, "TargetAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwSendingFlowspecSize, pCallParamsApp->dwSendingFlowspecOffset, szFunc, "SendingFlowspec" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwReceivingFlowspecSize, pCallParamsApp->dwReceivingFlowspecOffset, szFunc, "ReceivingFlowspec" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDeviceClassSize, pCallParamsApp->dwDeviceClassOffset, szFunc, "DeviceClass" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwDeviceConfigSize, pCallParamsApp->dwDeviceConfigOffset, szFunc, "DeviceConfig" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCallDataSize, pCallParamsApp->dwCallDataOffset, szFunc, "CallData" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSizeApp, pCallParamsApp->dwCallingPartyIDSize, pCallParamsApp->dwCallingPartyIDOffset, szFunc, "CallingPartyID" )) { return LINEERR_INVALCALLPARAMS; } ValidateCallParams_checkFixedSizes: if (dwAsciiCallParamsCodePage == 0xffffffff) { // // 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 ); pCallParamsSP->dwOrigAddressOffset += dwFixedSizeDiff; pCallParamsSP->dwDisplayableAddressOffset += dwFixedSizeDiff; pCallParamsSP->dwCalledPartyOffset += dwFixedSizeDiff; pCallParamsSP->dwCommentOffset += dwFixedSizeDiff; pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff; pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff; pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff; pCallParamsSP->dwDevSpecificOffset += 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 ); pCallParamsSP->dwUserUserInfoOffset += dwFixedSizeDiff; pCallParamsSP->dwHighLevelCompOffset += dwFixedSizeDiff; pCallParamsSP->dwLowLevelCompOffset += dwFixedSizeDiff; pCallParamsSP->dwDevSpecificOffset += dwFixedSizeDiff; } else { CopyMemory (pCallParamsSP, pCallParamsApp, dwTotalSize); } pCallParamsSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff + 2*dwAsciiVarDataSize; if (dwAsciiVarDataSize) { LPDWORD alpdwXxxSize[] = { &pCallParamsSP->dwOrigAddressSize, &pCallParamsSP->dwDisplayableAddressSize, &pCallParamsSP->dwCalledPartySize, &pCallParamsSP->dwCommentSize, (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwTargetAddressSize : NULL), (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwDeviceClassSize : NULL), (dwAPIVersion > TAPI_VERSION1_4 ? &pCallParamsSP->dwCallingPartyIDSize : NULL), NULL }; // align dwXxxOffset DWORD i, dwXxxOffset = (dwTotalSize + dwFixedSizeDiff + 3) & 0xFFFFFFFC; for (i = 0; alpdwXxxSize[i]; i++) { if (*alpdwXxxSize[i] != 0) { MultiByteToWideChar( (UINT) dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pCallParamsApp) + *(alpdwXxxSize[i] + 1)), // dwXxxOffset *alpdwXxxSize[i], (LPWSTR) (((LPBYTE) pCallParamsSP) + dwXxxOffset), *alpdwXxxSize[i] * 2 ); *(alpdwXxxSize[i] + 1) = dwXxxOffset; *alpdwXxxSize[i] *= 2; dwXxxOffset += *alpdwXxxSize[i]; } } } *ppCallParamsSP = pCallParamsSP; } else { *ppCallParamsSP = pCallParamsApp; } } return 0; // success } void PASCAL InsertVarData( LPVOID lpXxx, LPDWORD pdwXxxSize, LPVOID *pData, DWORD dwDataSize ) { DWORD dwAlignedSize, dwUsedSize; LPVARSTRING lpVarString = (LPVARSTRING) lpXxx; if (dwDataSize != 0) { // // Align var data on 64-bit boundaries // if ((dwAlignedSize = dwDataSize) & 7) { dwAlignedSize += 8; dwAlignedSize &= 0xfffffff8; } // // The following if statement should only be TRUE the first time // we're inserting data into a given structure that does not have // an even number of DWORD fields // if ((dwUsedSize = lpVarString->dwUsedSize) & 7) { dwUsedSize += 8; dwUsedSize &= 0xfffffff8; lpVarString->dwNeededSize += dwUsedSize - lpVarString->dwUsedSize; } lpVarString->dwNeededSize += dwAlignedSize; if ((dwUsedSize + dwAlignedSize) <= lpVarString->dwTotalSize) { CopyMemory( ((LPBYTE) lpVarString) + dwUsedSize, pData, dwDataSize ); *pdwXxxSize = dwDataSize; pdwXxxSize++; // pdwXxxSize = pdwXxxOffset *pdwXxxSize = dwUsedSize; lpVarString->dwUsedSize = dwUsedSize + dwAlignedSize; } } } PTLINELOOKUPENTRY GetLineLookupEntry( DWORD dwDeviceID ) { DWORD dwDeviceIDBase = 0; PTLINELOOKUPTABLE pLookupTable = TapiGlobals.pLineLookup; if (dwDeviceID >= TapiGlobals.dwNumLines) { return ((PTLINELOOKUPENTRY) NULL); } while (pLookupTable) { if (dwDeviceID < pLookupTable->dwNumTotalEntries) { return (pLookupTable->aEntries + dwDeviceID); } dwDeviceID -= pLookupTable->dwNumTotalEntries; pLookupTable = pLookupTable->pNext; } return ((PTLINELOOKUPENTRY) NULL); } BOOL PASCAL IsValidLineExtVersion( DWORD dwDeviceID, DWORD dwExtVersion ) { BOOL bResult; PTLINE ptLine; PTPROVIDER ptProvider; PTLINELOOKUPENTRY pLookupEntry; if (dwExtVersion == 0) { return TRUE; } if (!(pLookupEntry = GetLineLookupEntry (dwDeviceID))) { return FALSE; } ptLine = pLookupEntry->ptLine; if (ptLine) { try { if (ptLine->dwExtVersionCount) { bResult = (dwExtVersion == ptLine->dwExtVersion ? TRUE : FALSE); if (ptLine->dwKey == TLINE_KEY) { goto IsValidLineExtVersion_return; } } } myexcept { // // if here the line was closed, just drop thru to the code below // } } ptProvider = pLookupEntry->ptProvider; if (ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION]) { LONG lResult; DWORD dwNegotiatedExtVersion; lResult = CallSP5( ptProvider->apfn[SP_LINENEGOTIATEEXTVERSION], "lineNegotiateExtVersion", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pLookupEntry->dwSPIVersion, (DWORD) dwExtVersion, (DWORD) dwExtVersion, (DWORD) &dwNegotiatedExtVersion ); bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE); } else { bResult = FALSE; } IsValidLineExtVersion_return: return bResult; } PTCALL PASCAL IsValidtCall( HTAPICALL htCall ) { try { if (IsBadPtrKey (htCall, TCALL_KEY)) { htCall = (HTAPICALL) 0; } } myexcept { htCall = (HTAPICALL) 0; } return ((PTCALL) htCall); } PTCALLCLIENT PASCAL IsValidCall( HCALL hCall, PTCLIENT ptClient ) { try { if (IsBadPtrKey (hCall, TCALLCLIENT_KEY) || (*(((LPDWORD) hCall) + 1) != (DWORD) ptClient)) { hCall = (HCALL) 0; } } myexcept { hCall = (HCALL) 0; } return ((PTCALLCLIENT) hCall); } PTLINECLIENT PASCAL IsValidLine( HLINE hLine, PTCLIENT ptClient ) { try { if (IsBadPtrKey (hLine, TLINECLIENT_KEY) || (*(((LPDWORD) hLine) + 1) != (DWORD) ptClient)) { hLine = (HLINE) 0; } } myexcept { hLine = (HLINE) 0; } return ((PTLINECLIENT) hLine); } PTLINEAPP PASCAL IsValidLineApp( HLINEAPP hLineApp, PTCLIENT ptClient ) { try { if (IsBadPtrKey (hLineApp, TLINEAPP_KEY) || (*( ((LPDWORD) hLineApp) + 1) != (DWORD) ptClient)) { hLineApp = (HLINEAPP) 0; } } myexcept { hLineApp = (HLINEAPP) 0; } return ((PTLINEAPP) hLineApp); } PTCALL PASCAL WaitForExclusivetCallAccess( HTAPICALL htCall, DWORD dwKey, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (!IsBadPtrKey (htCall, dwKey) && WaitForMutex( ((PTCALL) htCall)->hMutex, phMutex, pbDupedMutex, (LPVOID) htCall, dwKey, dwTimeout )) { if (((PTCALL) htCall)->dwKey == dwKey) { return ((PTCALL) htCall); } MyReleaseMutex (*phMutex, *pbDupedMutex); } } myexcept { // do nothing } return NULL; } PTLINE PASCAL WaitForExclusivetLineAccess( HTAPILINE htLine, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (!IsBadPtrKey (htLine, TLINE_KEY) && WaitForMutex( ((PTLINE) htLine)->hMutex, phMutex, pbDupedMutex, (LPVOID) htLine, TLINE_KEY, dwTimeout )) { if (((PTLINE) htLine)->dwKey == TLINE_KEY) { return ((PTLINE) htLine); } MyReleaseMutex (*phMutex, *pbDupedMutex); } } myexcept { // do nothing } return NULL; } PTLINECLIENT PASCAL WaitForExclusiveLineClientAccess( HLINE hLine, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (WaitForMutex( ((PTLINECLIENT) hLine)->hMutex, phMutex, pbDupedMutex, (LPVOID) hLine, TLINECLIENT_KEY, dwTimeout )) { if (((PTLINECLIENT) hLine)->dwKey == TLINECLIENT_KEY) { return ((PTLINECLIENT) hLine); } MyReleaseMutex (*phMutex, *pbDupedMutex); } } myexcept { // do nothing } return NULL; } PTLINEAPP PASCAL WaitForExclusiveLineAppAccess( HLINEAPP hLineApp, PTCLIENT ptClient, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (IsBadPtrKey (hLineApp, TLINEAPP_KEY)) { return NULL; } if (WaitForMutex( ((PTLINEAPP) hLineApp)->hMutex, phMutex, pbDupedMutex, (LPVOID) hLineApp, TLINEAPP_KEY, dwTimeout )) { if (((PTLINEAPP) hLineApp)->dwKey == TLINEAPP_KEY && ((PTLINEAPP) hLineApp)->ptClient == ptClient) { return ((PTLINEAPP) hLineApp); } MyReleaseMutex (*phMutex, *pbDupedMutex); } } myexcept { // do nothing } return NULL; } PTCLIENT PASCAL WaitForExclusiveClientAccess( PTCLIENT ptClient, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout ) { try { if (WaitForMutex( ptClient->hMutex, phMutex, pbDupedMutex, (LPVOID) ptClient, TCLIENT_KEY, dwTimeout )) { if (ptClient->dwKey == TCLIENT_KEY) { return (ptClient); } MyReleaseMutex (*phMutex, *pbDupedMutex); } } myexcept { // do nothing } return NULL; } LONG PASCAL CreateProxyRequest( PTLINECLIENT pProxy, DWORD dwRequestType, DWORD dwExtraBytes, PASYNCREQUESTINFO pAsyncReqInfo, PPROXYREQUESTWRAPPER *ppWrapper ) { DWORD dwSize, dwComputerNameSize, dwUserNameSize; PTCLIENT ptClient = pAsyncReqInfo->ptClient; PPROXYREQUESTWRAPPER pWrapper; dwComputerNameSize = ptClient->dwComputerNameSize; dwUserNameSize = ptClient->dwUserNameSize; // // 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 3) & 0xfffffffc; // make sure size is a DWORD 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 // dwTotalSize field must be DWORD- // aligned) if (!(pWrapper = ServerAlloc (dwSize))) { return LINEERR_NOMEM; } pWrapper->AsyncEventMsg.dwTotalSize = dwSize; pWrapper->AsyncEventMsg.pInitData = (DWORD) ((PTLINEAPP) pProxy->ptLineApp)->lpfnCallback; //pWrapper->AsyncEventMsg.pfnPostProcessProc = pWrapper->AsyncEventMsg.hDevice = (DWORD) pProxy; pWrapper->AsyncEventMsg.dwMsg = LINE_PROXYREQUEST; pWrapper->AsyncEventMsg.dwCallbackInst = pProxy->dwCallbackInstance; pWrapper->AsyncEventMsg.dwParam1 = (DWORD) pAsyncReqInfo; //pWrapper->AsyncEventMsg.dwParam2 = //pWrapper->AsyncEventMsg.dwParam3 = //pWrapper->AsyncEventMsg.dwParam4 = dwSize -= sizeof (ASYNCEVENTMSG); pWrapper->ProxyRequest.dwSize = dwSize; pWrapper->ProxyRequest.dwClientMachineNameSize = dwComputerNameSize; pWrapper->ProxyRequest.dwClientMachineNameOffset = dwSize - dwComputerNameSize; lstrcpyW( (PWSTR)((LPBYTE) &pWrapper->ProxyRequest + pWrapper->ProxyRequest.dwClientMachineNameOffset), ptClient->pszComputerName ); pWrapper->ProxyRequest.dwClientUserNameSize = dwUserNameSize; pWrapper->ProxyRequest.dwClientUserNameOffset = (dwSize - dwComputerNameSize) - dwUserNameSize; lstrcpyW( (PWSTR)((LPBYTE) &pWrapper->ProxyRequest + pWrapper->ProxyRequest.dwClientUserNameOffset), ptClient->pszUserName ); pWrapper->ProxyRequest.dwClientAppAPIVersion = 0; // BUGBUG pWrapper->ProxyRequest.dwRequestType = dwRequestType; *ppWrapper = pWrapper; return 0; } LONG PASCAL SendProxyRequest( PTLINECLIENT pProxy, PPROXYREQUESTWRAPPER pWrapper, PASYNCREQUESTINFO pAsyncRequestInfo ) { LONG lResult; // // 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 { BOOL bDupedMutex; HANDLE hMutex; if (WaitForMutex( pProxy->hMutex, &hMutex, &bDupedMutex, pProxy, TLINECLIENT_KEY, INFINITE )) { if ((pAsyncRequestInfo->dwParam5 = (DWORD) pProxy->pPendingProxyRequests)) { ((PASYNCREQUESTINFO) pAsyncRequestInfo->dwParam5)->dwParam4 = (DWORD) pAsyncRequestInfo; } pProxy->pPendingProxyRequests = pAsyncRequestInfo; MyReleaseMutex (hMutex, bDupedMutex); WriteEventBuffer (pProxy->ptClient, (PASYNCEVENTMSG) pWrapper); lResult = 0; } else { lResult = LINEERR_OPERATIONUNAVAIL; } } myexcept { lResult = LINEERR_OPERATIONUNAVAIL; } 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; // BUGBUG NotifyHighestPriorityRequestRecipient: mutex or try/xcpt ptLineApp = TapiGlobals.pHighestPriorityRequestRecipient->ptLineApp; msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pInitData = (DWORD) ptLineApp->lpfnCallback; msg.pfnPostProcessProc = msg.hDevice = 0; msg.dwMsg = LINE_REQUEST; msg.dwCallbackInst = 0; msg.dwParam1 = LINEREQUESTMODE_MAKECALL; msg.dwParam2 = msg.dwParam3 = 0; WriteEventBuffer (ptLineApp->ptClient, &msg); return TRUE; } void SetDrvCallFlags( PTCALL ptCall, DWORD dwDrvCallFlags ) { // // This func is called on return from TSPI_lineMakeCall (and other // TSPI_lineXxx funcs where calls are created) and sets the // dwDrvCallFlags field in the tCall as specified. This keeps // another thread which is currently doing a DestroytCall on this // call from passing an invalid hdCall to the provider when // doing a TSPI_lineCloseCall. // // try { BOOL bCloseMutex; HANDLE hMutex = ptCall->hMutex; if ((ptCall->dwKey == TINCOMPLETECALL_KEY) || (ptCall->dwKey == TCALL_KEY) || (ptCall->dwKey == TZOMBIECALL_KEY)) { if (WaitForMutex( hMutex, &hMutex, &bCloseMutex, NULL, 0, INFINITE )) { 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)); } MyReleaseMutex (hMutex, bCloseMutex); } } } myexcept { // do nothing } } LONG PASCAL SetCallConfList( PTCALL ptCall, PTCONFERENCELIST pConfList, BOOL bAddToConfPostProcess ) { LONG lResult; BOOL bDupedMutex, bAddToConfList = FALSE; HANDLE hMutex; if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bDupedMutex, // BUGBUG SetCallConfList: use timeout here? INFINITE )) { 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; } } MyReleaseMutex (hMutex, bDupedMutex); } else { lResult = LINEERR_INVALCALLHANDLE; } // BUGBUG SetCallConfList: verify the conf list, and wrap in mutex if (pConfList && (pConfList != (PTCONFERENCELIST) 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 = (PTLINECLIENT) ptCallClient->ptLineClient; WaitForSingleObject (ptLineClient->hMutex, INFINITE); if (ptCallClient->pNextSametLineClient) { ptCallClient->pNextSametLineClient->pPrevSametLineClient = ptCallClient->pPrevSametLineClient; } if (ptCallClient->pPrevSametLineClient) { ptCallClient->pPrevSametLineClient->pNextSametLineClient = ptCallClient->pNextSametLineClient; } else { ptLineClient->ptCallClients = ptCallClient->pNextSametLineClient; } ReleaseMutex (ptLineClient->hMutex); return 0; } LONG PASCAL GetConfCallListFromConf( PTCONFERENCELIST pConfList, PTPOINTERLIST *ppList ) { // BUGBUG GetConfCallListFromConf: needs a mutex 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 GetCallClientListFromCall( PTCALL ptCall, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex; if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { 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) ))) { MyReleaseMutex (hMutex, bDupedMutex); 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; } MyReleaseMutex (hMutex, bDupedMutex); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { return LINEERR_INVALCALLHANDLE; } return 0; } LONG PASCAL GetCallListFromLine( PTLINE ptLine, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex; if (WaitForExclusivetLineAccess( (HTAPILINE) 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 { return LINEERR_INVALLINEHANDLE; } return 0; } LONG PASCAL GetLineClientListFromLine( PTLINE ptLine, PTPOINTERLIST *ppList ) { BOOL bDupedMutex; HANDLE hMutex; if (WaitForExclusivetLineAccess( (HTAPILINE) 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 { return LINEERR_INVALLINEHANDLE; } return 0; } LONG PASCAL GetLineAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ) { BOOL bCloseMutex; HANDLE hMutex; if (WaitForExclusiveClientAccess( ptClient, &hMutex, &bCloseMutex, INFINITE )) { 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) ))) { MyReleaseMutex (hMutex, bCloseMutex); 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; } MyReleaseMutex (hMutex, bCloseMutex); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; } else { return LINEERR_OPERATIONFAILED; } return 0; } LONG PASCAL GetClientList( PTPOINTERLIST *ppList ) { DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES, dwNumUsedEntries = 0; PTPOINTERLIST pList = *ppList; PTCLIENT ptClient; WaitForSingleObject (TapiGlobals.hMutex, INFINITE); ptClient = TapiGlobals.ptClients; while (ptClient) { 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) ))) { ReleaseMutex (TapiGlobals.hMutex); 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; } ReleaseMutex (TapiGlobals.hMutex); pList->dwNumUsedEntries = dwNumUsedEntries; *ppList = pList; ReleaseMutex (TapiGlobals.hMutex); } void PASCAL SendMsgToCallClients( PTCALL ptCall, PTCALLCLIENT ptCallClientToExclude, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg; if (GetCallClientListFromCall (ptCall, &pClientList) != 0) { return; } msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; msg.dwMsg = dwMsg; msg.dwParam1 = dwParam1; msg.dwParam2 = dwParam2; msg.dwParam3 = dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTCALLCLIENT ptCallClient = pClientList->aEntries[i]; PTLINECLIENT ptLineClient = ptCallClient->ptLineClient; if (ptCallClient == ptCallClientToExclude) { continue; } if (dwMsg == LINE_MONITORDIGITS) { if ((ptCallClient->dwMonitorDigitModes & dwParam2) == 0) { continue; } } else if (dwMsg == LINE_MONITORMEDIA) { DWORD dwMediaModes = dwParam1; // // Munge the media modes so we don't pass unexpected flags // to old apps // if (ptLineClient->dwAPIVersion == TAPI_VERSION1_0) { if ((dwMediaModes & ~AllMediaModes1_0)) { dwMediaModes = (dwMediaModes & AllMediaModes1_0) | LINEMEDIAMODE_UNKNOWN; } } if (ptCallClient->dwMonitorMediaModes & dwMediaModes) { msg.dwParam1 = dwMediaModes; } else { continue; } } msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; msg.hDevice = (DWORD) ptCallClient; msg.dwCallbackInst = ptLineClient->dwCallbackInstance; // // Indicate the hRemoteLine in p4 to make life easier for remotesp // msg.dwParam4 = ptLineClient->hRemoteLine; ptClient = ptLineClient->ptClient; if (ptCallClient->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClient, &msg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendAMsgToAllLineApps( DWORD dwWantVersion, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { DWORD i, j; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG lineMsg; if (GetClientList (&pClientList) != 0) { return; } ZeroMemory (&lineMsg, sizeof (ASYNCEVENTMSG)); lineMsg.dwTotalSize = sizeof (ASYNCEVENTMSG); lineMsg.dwMsg = dwMsg; lineMsg.dwParam1 = dwParam1; lineMsg.dwParam2 = dwParam2; lineMsg.dwParam3 = dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i]; TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList; if (GetLineAppListFromClient (ptClient, &pXxxAppList) == 0) { for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++) { PTLINEAPP ptLineApp = (PTLINEAPP) pXxxAppList->aEntries[j]; try { lineMsg.pInitData = (DWORD) ptLineApp->lpfnCallback; if ( (ptLineApp->dwKey == TLINEAPP_KEY) && ( (dwWantVersion == 0) || (ptLineApp->dwAPIVersion == dwWantVersion) || ( (dwWantVersion & 0x80000000) && (ptLineApp->dwAPIVersion > (dwWantVersion & 0x7fffffff) ) ) ) ) { WriteEventBuffer (ptClient, &lineMsg); } } myexcept { // just continue } } if (pXxxAppList != &xxxAppList) { ServerFree (pXxxAppList); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendAMsgToAllPhoneApps( DWORD dwWantVersion, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { DWORD i, j; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG phoneMsg; if (GetClientList (&pClientList) != 0) { return; } ZeroMemory (&phoneMsg, sizeof (ASYNCEVENTMSG)); phoneMsg.dwTotalSize = sizeof (ASYNCEVENTMSG); phoneMsg.dwMsg = dwMsg; phoneMsg.dwParam1 = dwParam1; phoneMsg.dwParam2 = dwParam2; phoneMsg.dwParam3 = dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCLIENT ptClient = (PTCLIENT) pClientList->aEntries[i]; TPOINTERLIST xxxAppList, *pXxxAppList = &xxxAppList; if (GetPhoneAppListFromClient (ptClient, &pXxxAppList) == 0) { for (j = 0; j < pXxxAppList->dwNumUsedEntries; j++) { PTPHONEAPP ptPhoneApp = (PTPHONEAPP) pXxxAppList->aEntries[j]; try { phoneMsg.pInitData = (DWORD) ptPhoneApp->lpfnCallback; if ( (ptPhoneApp->dwKey == TPHONEAPP_KEY) && ( (dwWantVersion == 0) || (ptPhoneApp->dwAPIVersion == dwWantVersion) || ( (dwWantVersion & 0x80000000) && (ptPhoneApp->dwAPIVersion > (dwWantVersion & 0x7fffffff) ) ) ) ) { WriteEventBuffer (ptClient, &phoneMsg); } } myexcept { // just continue } } if (pXxxAppList != &xxxAppList) { ServerFree (pXxxAppList); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } void PASCAL SendReinitMsgToAllXxxApps( void ) { TapiGlobals.bReinit = TRUE; SendAMsgToAllLineApps( 0, LINE_LINEDEVSTATE, LINEDEVSTATE_REINIT, 0, 0 ); SendAMsgToAllPhoneApps( 0, PHONE_STATE, PHONESTATE_REINIT, 0, 0 ); } void PASCAL SendMsgToLineClients( PTLINE ptLine, PTLINECLIENT ptLineClientToExclude, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { DWORD i; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg; if (dwMsg == LINE_LINEDEVSTATE && dwParam1 & LINEDEVSTATE_REINIT) { SendReinitMsgToAllXxxApps(); if (dwParam1 == LINEDEVSTATE_REINIT) { return; } else { dwParam1 &= ~LINEDEVSTATE_REINIT; } } if (GetLineClientListFromLine (ptLine, &pClientList) != 0) { return; } msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; msg.dwMsg = dwMsg; msg.dwParam1 = dwParam1; msg.dwParam2 = dwParam2; msg.dwParam3 = dwParam3; msg.dwParam4 = 0; // remotesp chks this on LINE_DEVSPEC(FEATURE) for (i = 0; i < pClientList->dwNumUsedEntries; i++) { try { PTCLIENT ptClient; PTLINECLIENT ptLineClient = pClientList->aEntries[i]; if (ptLineClient == ptLineClientToExclude) { continue; } if (dwMsg == LINE_ADDRESSSTATE) { DWORD dwAddressStates = dwParam2; // // Munge the state flags so we don't pass // unexpected flags to old apps // switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: dwAddressStates &= AllAddressStates1_0; break; case TAPI_VERSION1_4: dwAddressStates &= AllAddressStates1_4; break; case TAPI_VERSION_CURRENT: dwAddressStates &= AllAddressStates1_4; // dwAddressStates &= AllAddressStates2_0; break; } if ((dwAddressStates &= ptLineClient->dwAddressStates)) { msg.dwParam2 = dwAddressStates; } else { continue; } if ((dwParam2 & LINEADDRESSSTATE_CAPSCHANGE)) { // BUGBUG LINE_ADDRSTATE: send REINIT msg to 1_0 apps (dwParam3 = dwParam1?) } } else if (dwMsg == LINE_LINEDEVSTATE) { DWORD dwLineStates = dwParam1; // // Munge the state flags so we don't pass unexpected flags // to old apps // switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: dwLineStates &= AllLineStates1_0; break; default: // case TAPI_VERSION1_4: // case TAPI_VERSION_CURRENT: dwLineStates &= AllLineStates1_4; break; } if ((dwLineStates &= ptLineClient->dwLineStates)) { msg.dwParam1 = dwLineStates; } else { continue; } if ((dwParam1 & (LINEDEVSTATE_CAPSCHANGE | LINEDEVSTATE_TRANSLATECHANGE))) { // BUGBUG LINE_LINEDEVSTATE: send REINIT to 1_0 apps (dwParam3 = dwParam1) } } msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; msg.hDevice = (DWORD) ptLineClient->hRemoteLine; msg.dwCallbackInst = ptLineClient->dwCallbackInstance; ptClient = ptLineClient->ptClient; if (ptLineClient->dwKey == TLINECLIENT_KEY) { WriteEventBuffer (ptClient, &msg); } } myexcept { // just continue } } if (pClientList != &clientList) { ServerFree (pClientList); } } LONG PASCAL CreatetCall( PTLINE ptLine, BOOL bValidate, PTCALL *pptCall, LPLINECALLPARAMS pCallParams, LPDWORD pdwCallInstance ) { BOOL bDupedMutex; DWORD dwExtraBytes; HANDLE hMutex; PTCALL ptCall; // DBGOUT((3, "CreatetCall: enter, ptLine=x%x", 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)) || !(ptCall->hMutex = MyCreateMutex())) { if (ptCall) { ServerFree (ptCall); } return LINEERR_NOMEM; } // // Init tCall & add to tLine's tCall list // if (bValidate) { ptCall->dwKey = TCALL_KEY; ptCall->dwDrvCallFlags = DCF_SPIRETURNED | DCF_DRVCALLVALID; } else { EnterCriticalSection (&gRequestIDCritSec); *pdwCallInstance = ptCall->dwCallInstance = gdwCallInstance; gdwCallInstance++; LeaveCriticalSection (&gRequestIDCritSec); ptCall->dwKey = TINCOMPLETECALL_KEY; } if (pCallParams) { DWORD dwOffset = sizeof (TCALL) + (sizeof (TCALL) & 4); if (pCallParams->dwDisplayableAddressSize != 0) { CopyMemory( (ptCall->pszDisplayableAddress = (WCHAR *) (((LPBYTE) ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwDisplayableAddressOffset, (ptCall->dwDisplayableAddressSize = pCallParams->dwDisplayableAddressSize) ); dwOffset += ((ptCall->dwDisplayableAddressSize + 8) & 0xfffffff8); } if (pCallParams->dwCalledPartySize) { CopyMemory( (ptCall->pszCalledParty = (WCHAR *) (((LPBYTE)ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwCalledPartyOffset, (ptCall->dwCalledPartySize = pCallParams->dwCalledPartySize) ); dwOffset += ((ptCall->dwCalledPartySize + 8) & 0xfffffff8); } if (pCallParams->dwCommentSize) { CopyMemory( (ptCall->pszComment = (WCHAR *) (((LPBYTE) ptCall) + dwOffset)), ((LPBYTE) pCallParams) + pCallParams->dwCommentOffset, (ptCall->dwCommentSize = pCallParams->dwCommentSize) ); } } if (WaitForExclusivetLineAccess( (HTAPILINE) 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. // CloseHandle (ptCall->hMutex); ServerFree (ptCall); return LINEERR_OPERATIONFAILED; } // // Fill in caller's pointer & return success // *pptCall = ptCall; PerfBlock.dwTotalOutgoingCalls++; PerfBlock.dwCurrentOutgoingCalls++; // DBGOUT((3, "CreatetCall: exit, new ptCall=x%x", *pptCall)); return 0; } LONG PASCAL CreatetCallClient( PTCALL ptCall, PTLINECLIENT ptLineClient, DWORD dwPrivilege, BOOL bValidate, BOOL bSendCallInfoMsg, PTCALLCLIENT *pptCallClient, BOOL bIndicatePrivilege ) { BOOL bDupedMutex; HANDLE hMutex; PTCALLCLIENT ptCallClient; // DBGOUT((3, "CreatetCallClient: enter, ptCall=x%lx", ptCall)); if (!(ptCallClient = ServerAlloc (sizeof(TCALLCLIENT)))) { return LINEERR_NOMEM; } ptCallClient->dwKey = (bValidate ? TCALLCLIENT_KEY : TINCOMPLETECALLCLIENT_KEY); try { ptCallClient->ptClient = ptLineClient->ptClient; } myexcept { ServerFree (ptCallClient); return LINEERR_INVALLINEHANDLE; } ptCallClient->ptLineClient = ptLineClient; ptCallClient->ptCall = ptCall; ptCallClient->dwPrivilege = dwPrivilege; ptCallClient->bIndicatePrivilege = bIndicatePrivilege; // // Send a call info msg to existing call clients if appropriate. // Note that if the following attempt to add the new call client // to the line client's list fails we will have sent an "invalid" // msg. // if (bSendCallInfoMsg) { SendMsgToCallClients( ptCall, NULL, LINE_CALLINFO, (dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERINCR : LINECALLINFOSTATE_NUMMONITORS), 0, 0 ); } // // Safely increment tCall's dwNumOwners or dwNumMonitors field, // and add new call client to list of call clients // if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, (bValidate ? TCALL_KEY : TINCOMPLETECALL_KEY), &hMutex, &bDupedMutex, INFINITE )) { if (dwPrivilege == LINECALLPRIVILEGE_OWNER) { ptCall->dwNumOwners++; } else { ptCall->dwNumMonitors++; } if ((ptCallClient->pNextSametCall = ptCall->ptCallClients)) { ptCallClient->pNextSametCall->pPrevSametCall = ptCallClient; } ptCall->ptCallClients = ptCallClient; MyReleaseMutex (hMutex, bDupedMutex); } else { // // tCall was destroyed, so clean up. Note that we return // a generic OPFAILED error, since some calling routines // might no be spec'd to return INVALCALLHANDLE, etc. // ServerFree (ptCallClient); return LINEERR_OPERATIONFAILED; } // // Add to tLineClient's tCallClient list // if (WaitForExclusiveLineClientAccess( (HLINE) ptLineClient, &hMutex, &bDupedMutex, INFINITE )) { if ((ptCallClient->pNextSametLineClient = ptLineClient->ptCallClients)) { ptCallClient->pNextSametLineClient->pPrevSametLineClient = ptCallClient; } ptLineClient->ptCallClients = ptCallClient; MyReleaseMutex (hMutex, bDupedMutex); } else { // // 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 // if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, (bValidate ? TCALL_KEY : TINCOMPLETECALL_KEY), &hMutex, &bDupedMutex, INFINITE )) { if (ptCallClient->dwKey == (bValidate ? TCALLCLIENT_KEY : TINCOMPLETECALLCLIENT_KEY)) { 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; } ServerFree (ptCallClient); } MyReleaseMutex (hMutex, bDupedMutex); } return LINEERR_INVALLINEHANDLE; } // // Fill in caller's pointer & return success // *pptCallClient = ptCallClient; // DBGOUT(( // 3, // "CreatetCallClient: exit, new ptCallClient=x%lx", // *pptCallClient // )); return 0; } LONG PASCAL CreatetCallAndClient( PTLINECLIENT ptLineClient, PTCALL *pptCall, PTCALLCLIENT *pptCallClient, LPLINECALLPARAMS pCallParams, LPDWORD pdwCallInstance ) { LONG lResult; PTCALL ptCall = NULL; if ((lResult = CreatetCall( ptLineClient->ptLine, FALSE, &ptCall, pCallParams, pdwCallInstance )) != 0 || (lResult = CreatetCallClient( ptCall, ptLineClient, LINECALLPRIVILEGE_OWNER, FALSE, FALSE, pptCallClient, FALSE )) != 0) { if (ptCall) { // BUGBUG CreatetCallAndClient: cleanup *pptCall = (PTCALL) NULL; } return lResult; } try { WCHAR *pszXxx; DWORD dwXxxSize = ((PTLINEAPP) ptLineClient->ptLineApp)->dwFriendlyNameSize; if ((pszXxx = ServerAlloc (dwXxxSize))) { CopyMemory( pszXxx, ((PTLINEAPP) ptLineClient->ptLineApp)->pszFriendlyName, dwXxxSize ); ptCall->dwAppNameSize = dwXxxSize; ptCall->pszAppName = pszXxx; } // don't worry about the error case for now (will just show up in // lineCallInfo as NULL app name) } myexcept { lResult = LINEERR_OPERATIONFAILED; // CreatetCallAndClient: cleanup } *pptCall = ptCall; return lResult; } LONG PASCAL CreateCallMonitors( PTCALL ptCall ) { // // 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 // and error value (<0) // LONG lResult; DWORD i; TPOINTERLIST lineClients, *pLineClients = &lineClients; PTLINE ptLine; PTLINECLIENT ptLineClientOwner; // // Get a list of line clients // try { ptLine = (PTLINE) ptCall->ptLine; ptLineClientOwner = (PTLINECLIENT) (ptCall->ptCallClients ? ((PTCALLCLIENT) 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 // // for (i = 0; i < pLineClients->dwNumUsedEntries; i++) { PTCALLCLIENT ptCallClientMonitor; PTLINECLIENT ptLineClient = pLineClients->aEntries[i]; try { if (!(ptLineClient->dwPrivileges & LINECALLPRIVILEGE_MONITOR) || (ptLineClient == ptLineClientOwner)) { continue; } } myexcept { // // If here the tLineClient or tCallClient was destroyed, // just continue // continue; } if (CreatetCallClient( ptCall, ptLineClient, LINECALLPRIVILEGE_MONITOR, TRUE, FALSE, &ptCallClientMonitor, TRUE ) == 0) { lResult++; } } 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 // { BOOL bCloseMutex; HANDLE hMutex; if ((ptCall = WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bCloseMutex, 0xffffffff ))) { ptCall->bCreatedInitialMonitors = TRUE; MyReleaseMutex (hMutex, bCloseMutex); } else { lResult = LINEERR_OPERATIONFAILED; } } return lResult; } PTREQUESTRECIPIENT PASCAL GetHighestPriorityRequestRecipient( void ) { BOOL bFoundRecipientInPriorityList = FALSE; WCHAR *pszAppInPriorityList, *pszAppInPriorityListPrev = (WCHAR *) 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--; } ServerFree (ptCall); } void PASCAL DestroytCall( PTCALL ptCall ) { BOOL bDupedMutex; DWORD dwKey; HANDLE hMutex; // DBGOUT((3, "DestroytCall: enter, ptCall=x%x", ptCall)); // // Safely get the call's hMutex & current key, then grab the call's // mutex. 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 { hMutex = ptCall->hMutex; dwKey = (ptCall->dwKey == TCALL_KEY ? TCALL_KEY : TINCOMPLETECALL_KEY); } myexcept { return; } if (WaitForMutex( hMutex, &hMutex, &bDupedMutex, ptCall, dwKey, INFINITE ) || WaitForMutex( hMutex, &hMutex, &bDupedMutex, ptCall, TCALL_KEY, INFINITE )) { if (ptCall->dwKey == TCALL_KEY || ptCall->dwKey == TINCOMPLETECALL_KEY) { // // Invalidate the tCall // ptCall->dwKey = TZOMBIECALL_KEY; MyReleaseMutex (hMutex, bDupedMutex); // // 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); } // // 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) { PTPROVIDER ptProvider = ptCall->ptProvider; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { WaitForSingleObject (ptProvider->hMutex, INFINITE); } CallSP1( ptProvider->apfn[SP_LINECLOSECALL], "lineCloseCall", SP_FUNC_SYNC, (DWORD) ptCall->hdCall ); if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { ReleaseMutex (ptProvider->hMutex); } } // // Remove tCall from the tLine's tCall list // RemoveCallFromLineList (ptCall); // // If we have a dup'd mutex handle (bCloseMutex == TRUE) // then we can safely go ahead and close the ptCall->hMutex // since no other thread will be waiting on it (thanks to // the first WaitForSingleObject in WaitForMutex). Also // release & close the dup'd handle. // // Otherwise, we have the actual ptCall->hMutex, and we // wrap the release & close in a critical section to // prevent another thread "T2" from grabbing ptCall->hMutex // right after we release but right before we close. This // could result in deadlock at some point when "T2" goes to // release the mutex, only to find that it's handle is bad, // and thread "T3", which is waiting on the mutex (or a dup'd // handle) waits forever. (See corresponding critical // section in WaitForMutex.) // WaitForMutex( ptCall->hMutex, &hMutex, &bDupedMutex, NULL, 0, INFINITE ); if (bDupedMutex) { CloseHandle (ptCall->hMutex); MyReleaseMutex (hMutex, bDupedMutex); } else { EnterCriticalSection (&gSafeMutexCritSec); ReleaseMutex (hMutex); CloseHandle (hMutex); LeaveCriticalSection (&gSafeMutexCritSec); } // // Free the resources // { PTCONFERENCELIST pConfList; // BUGBUG DestroytCall: confList stuff needs a mutex, do this up above? if ((pConfList = ptCall->pConfList) && (pConfList != (PTCONFERENCELIST) 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 { // // We're destroying a conf child so we want to // remove it from the conference list // SetCallConfList( ptCall, (PTCONFERENCELIST) NULL, FALSE ); } } } FreetCall (ptCall); } else { MyReleaseMutex (hMutex, bDupedMutex); } } } void PASCAL DestroytCallClient( PTCALLCLIENT ptCallClient ) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptCall; // DBGOUT((3, "DestroytCallClient: enter, ptCallCli=x%x", ptCallClient)); try { if (ptCallClient->dwKey != TINCOMPLETECALLCLIENT_KEY && ptCallClient->dwKey != TCALLCLIENT_KEY) { return; } ptCall = ptCallClient->ptCall; hMutex = ptCall->hMutex; } myexcept { return; } if (WaitForMutex (hMutex, &hMutex, &bDupedMutex, NULL, 0, INFINITE)) { if (ptCallClient->dwKey == TINCOMPLETECALLCLIENT_KEY || ptCallClient->dwKey == TCALLCLIENT_KEY) { BOOL bDestroytCall = FALSE, bSendCallInfoMsgs = (ptCall->dwKey == TCALL_KEY ? TRUE : FALSE); // // 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 if (ptCall->dwNumOwners == 0 && ptCall->dwCallState != LINECALLSTATE_IDLE) { MyReleaseMutex (hMutex, bDupedMutex); // BUG//BUG DestroytCallClient: grab provider's mutex if approp if (ptCall->ptProvider->apfn[SP_LINEDROPONCLOSE]) { CallSP1( ptCall->ptProvider->apfn[SP_LINEDROPONCLOSE], "lineDropOnClose", SP_FUNC_SYNC, (DWORD) ptCall->hdCall ); } else { CallSP4( ptCall->ptProvider->apfn[SP_LINEDROP], "lineDrop", SP_FUNC_ASYNC, (DWORD) BOGUS_REQUEST_ID, (DWORD) ptCall->hdCall, (DWORD) NULL, (DWORD) 0 ); } WaitForMutex( ptCall->hMutex, &hMutex, &bDupedMutex, NULL, 0, INFINITE ); } */ } 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 if (ptCall->dwNumMonitors == 0 && ptCall->dwNumOwners == 0 && ptCall->dwCallState != LINECALLSTATE_IDLE) { MyReleaseMutex (hMutex, bDupedMutex); // BUGBUG DestroytCallClient: grab provider's mutex if approp CallSP4( ptCall->ptProvider->apfn[SP_LINEDROP], "lineDrop", SP_FUNC_ASYNC, (DWORD) BOGUS_REQUEST_ID, (DWORD) ptCall->hdCall, (DWORD) NULL, (DWORD) 0 ); WaitForMutex( ptCall->hMutex, &hMutex, &bDupedMutex, NULL, 0, INFINITE ); } */ } // // Remove it from the tCall's tCallClient list // 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; } // // Release the mutex, destroy the call if appropriate, // & send call info msgs // MyReleaseMutex (hMutex, bDupedMutex); if (bDestroytCall) { DestroytCall (ptCall); bSendCallInfoMsgs = FALSE; } if (bSendCallInfoMsgs) { SendMsgToCallClients( ptCall, NULL, LINE_CALLINFO, (ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERDECR : LINECALLINFOSTATE_NUMMONITORS), 0, 0 ); } // // Remove tCallClient from the tLineClient's tCallClient list // RemoveCallClientFromLineClientList (ptCallClient); // // Free the tCallClient // ServerFree (ptCallClient); } else { MyReleaseMutex (hMutex, bDupedMutex); } } } void PASCAL DestroytLine( PTLINE ptLine, BOOL bUnconditional ) { BOOL bCloseMutex; HANDLE hMutex; DBGOUT(( 3, "DestroytLine: enter, ptLine=x%x, bUnconditional=%d", ptLine, bUnconditional )); if (WaitForExclusivetLineAccess( (HTAPILINE) 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. // { BOOL bExit; if (ptLine->dwKey == TLINE_KEY && (bUnconditional == TRUE || ptLine->ptLineClients == NULL)) { SendMsgToLineClients (ptLine, NULL, LINE_CLOSE, 0, 0, 0); ptLine->dwKey = INVAL_KEY; bExit = FALSE; } else { bExit = TRUE; } MyReleaseMutex (hMutex, bCloseMutex); if (bExit) { DBGOUT(( 3, "DestroytLine: exit, didn't destroy tLine=x%x", ptLine )); return; } } // // 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. // { PTLINECLIENT ptLineClient; hMutex = ptLine->hMutex; destroy_tLineClients: WaitForSingleObject (hMutex, INFINITE); ptLineClient = ptLine->ptLineClients; ReleaseMutex (hMutex); if (ptLineClient) { DestroytLineClient (ptLineClient); 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); } CallSP1( ptProvider->apfn[SP_LINECLOSE], "lineClose", SP_FUNC_SYNC, (DWORD) 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); pEntry->ptLine = NULL; } ServerFree (ptLine); } // PERF if (PerfBlock.dwLinesInUse) { PerfBlock.dwLinesInUse--; } else { DBGOUT((10, "PERF: dwNumLinesInUse below 0")); } DBGOUT((3, "DestroytLine: exit, destroyed line=x%x", ptLine)); } void PASCAL DestroytLineClient( PTLINECLIENT ptLineClient ) { BOOL bDupedMutex; HANDLE hMutex; DBGOUT((3, "DestroytLineClient: enter, ptLineClient=x%x", ptLineClient)); if (WaitForMutex( ptLineClient->hMutex, &hMutex, &bDupedMutex, ptLineClient, TLINECLIENT_KEY, INFINITE )) { PTLINE ptLine; // // If the key is bad another thread is in the process of // destroying this tLineClient, so just release the mutex & // return. Otherwise, mark the tLineClient as bad, release // the mutex, and continue on. // { BOOL bExit; if (ptLineClient->dwKey == TLINECLIENT_KEY) { ptLineClient->dwKey = INVAL_KEY; bExit = FALSE; } else { bExit = TRUE; } MyReleaseMutex (hMutex, bDupedMutex); if (bExit) { DBGOUT((3, "DestroytLineClient: bExit")); return; } } // // Destroy all the tCallClients. 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 // tCallClient's, since another thread might be destroying a // tCallClient too. // while (ptLineClient->ptCallClients) { DestroytCallClient (ptLineClient->ptCallClients); } // // Remove tLineClient from tLineApp'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. // { PTLINEAPP ptLineApp = (PTLINEAPP) ptLineClient->ptLineApp; WaitForSingleObject (ptLineApp->hMutex, INFINITE); if (ptLineClient->pNextSametLineApp) { ptLineClient->pNextSametLineApp->pPrevSametLineApp = ptLineClient->pPrevSametLineApp; } if (ptLineClient->pPrevSametLineApp) { ptLineClient->pPrevSametLineApp->pNextSametLineApp = ptLineClient->pNextSametLineApp; } else { ptLineApp->ptLineClients = ptLineClient->pNextSametLineApp; } ReleaseMutex (ptLineApp->hMutex); } // // 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 registered as a proxy then unregister it // if (ptLineClient->dwPrivileges & LINEOPENOPTION_PROXY) { DWORD i; // BUGBUG DestroytLineClient- restore lower pri proxies for( i = LINEPROXYREQUEST_SETAGENTGROUP; i <= LINEPROXYREQUEST_GETAGENTGROUPLIST; i++ ) { if (ptLine->apProxys[i] == ptLineClient) { ptLine->apProxys[i] = NULL; } } } // // // if (ptLineClient->dwExtVersion) { if ((--ptLine->dwExtVersionCount) == 0) { CallSP2( ptLine->ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) 0 ); 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) { DBGOUT((4, "It's a line_key")); if (ptLine->ptLineClients) { DBGOUT((4, "...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; PTPROVIDER ptProvider = ptLine->ptProvider; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { WaitForSingleObject (ptProvider->hMutex, INFINITE); } lResult = CallSP2( ptLine->ptProvider->apfn [SP_LINESETDEFAULTMEDIADETECTION], "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, dwUnionMediaModes ); if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { ReleaseMutex (ptProvider->hMutex); } ptLine->dwOpenMediaModes = dwUnionMediaModes; } } SendMsgToLineClients( ptLine, NULL, LINE_LINEDEVSTATE, LINEDEVSTATE_CLOSE, 0, 0 ); } else { // // This was the last client so destroy the tLine too // DBGOUT((4, "...and it's the last one out")); ReleaseMutex (hMutex); hMutex = NULL; DestroytLine (ptLine, FALSE); // conditional destroy } } if (hMutex) { ReleaseMutex (hMutex); } // // 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); pAsyncRequestInfo = pNextAsyncRequestInfo; } } // // Now clean up the tLineClient. Before we close ptLineClient->hMutex // we want to make sure no one else is waiting on it. // WaitForMutex( ptLineClient->hMutex, &hMutex, &bDupedMutex, NULL, 0, INFINITE ); if (bDupedMutex) { CloseHandle (ptLineClient->hMutex); ReleaseMutex (hMutex); CloseHandle (hMutex); } else { EnterCriticalSection (&gSafeMutexCritSec); ReleaseMutex (hMutex); CloseHandle (hMutex); LeaveCriticalSection (&gSafeMutexCritSec); } if (ptLineClient->aNumRings) { ServerFree (ptLineClient->aNumRings); } ServerFree (ptLineClient); } #if DBG else { DBGOUT((1, "DestroytLineClient: mutex failed!")); } #endif } void PASCAL DestroytLineApp( PTLINEAPP ptLineApp ) { BOOL bCloseMutex; HANDLE hMutex; DBGOUT((3, "DestroytLineApp: enter, ptLineApp=x%x", ptLineApp)); if (WaitForMutex( ptLineApp->hMutex, &hMutex, &bCloseMutex, ptLineApp, TLINEAPP_KEY, INFINITE )) { PTCLIENT ptClient = (PTCLIENT) ptLineApp->ptClient; // // If the key is bad another thread is in the process of // destroying this tLineApp, so just release the mutex & // return. Otherwise, mark the tLineApp as bad, release // the mutex, and continue on. // { BOOL bExit; if (ptLineApp->dwKey == TLINEAPP_KEY) { ptLineApp->dwKey = INVAL_KEY; bExit = FALSE; } else { bExit = TRUE; } MyReleaseMutex (hMutex, bCloseMutex); if (bExit) { DBGOUT((3, "DestroytLineApp: bExit")); return; } } // // Destroy all the tLineClients. 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 // tLineClient's, since another thread might be destroying a // tLineClient too. // { PTLINECLIENT ptLineClient; hMutex = ptLineApp->hMutex; destroy_tLineClients: WaitForSingleObject (hMutex, INFINITE); ptLineClient = ptLineApp->ptLineClients; ReleaseMutex (hMutex); if (ptLineClient) { DestroytLineClient (ptLineClient); 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. // WaitForSingleObject (ptClient->hMutex, INFINITE); 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; FREEDIALOGINSTANCE_PARAMS params = { 0, ptClient, (HTAPIDIALOGINSTANCE) pGenericDlgInst, LINEERR_OPERATIONFAILED }; while (pGenericDlgInst) { pNextGenericDlgInst = pGenericDlgInst->pNext; FreeDialogInstance (¶ms, NULL, NULL); pGenericDlgInst = pNextGenericDlgInst; } } ReleaseMutex (ptClient->hMutex); // // Decrement total num inits & see if we need to go thru shutdown // WaitForSingleObject (TapiGlobals.hMutex, INFINITE); //assert(TapiGlobals.dwNumLineInits != 0); TapiGlobals.dwNumLineInits--; if ((TapiGlobals.dwNumLineInits == 0) && (TapiGlobals.dwNumPhoneInits == 0)) { ServerShutdown(); } ReleaseMutex (TapiGlobals.hMutex); // // 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(); } // BUGBUG DestroytLineApp: else if (!StartRequestRecipient()) 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; } DBGOUT(( 2, "DestroytLineApp: deleting pending " \ "MakeCall requests" )); } } } LeaveCriticalSection (&gPriorityListCritSec); } } // // Free the resources // CloseHandle (ptLineApp->hMutex); ServerFree (ptLineApp); } } DWORD MyWToL(PWSTR lpszBuf) { DWORD dwReturn = 0; while ( (*lpszBuf >= '0') && (*lpszBuf <= '9') ) { dwReturn = dwReturn*10 + (*lpszBuf - '0'); lpszBuf++; } return dwReturn; } BOOL FillupACountryEntry( HKEY hKey, PBYTE pcl, LPLINECOUNTRYENTRY pce, PBYTE *ppVarOffset ) { PBYTE pVarOffset = *ppVarOffset; DWORD dwSize; DWORD dwType; dwSize = sizeof(pce->dwCountryCode); RegQueryValueExW( hKey, L"CountryCode", NULL, &dwType, (LPBYTE)&(pce->dwCountryCode), &dwSize ); dwSize = MAXLEN_NAME * sizeof(WCHAR); RegQueryValueExW( hKey, L"Name", NULL, &dwType, pVarOffset, &dwSize ); pce->dwCountryNameOffset = pVarOffset - pcl; pce->dwCountryNameSize = dwSize; pVarOffset += dwSize; dwSize = MAXLEN_RULE * sizeof(WCHAR); RegQueryValueExW( hKey, L"SameAreaRule", NULL, &dwType, pVarOffset, &dwSize ); pce->dwSameAreaRuleOffset = pVarOffset - pcl; pce->dwSameAreaRuleSize = dwSize; pVarOffset += dwSize; dwSize = MAXLEN_RULE * sizeof(WCHAR); RegQueryValueExW( hKey, L"LongDistanceRule", NULL, &dwType, pVarOffset, &dwSize ); pce->dwLongDistanceRuleOffset = pVarOffset - pcl; pce->dwLongDistanceRuleSize = dwSize; pVarOffset += dwSize; dwSize = MAXLEN_RULE * sizeof(WCHAR); RegQueryValueExW( hKey, L"InternationalRule", NULL, &dwType, pVarOffset, &dwSize ); pce->dwInternationalRuleOffset = pVarOffset - pcl; pce->dwInternationalRuleSize = dwSize; pVarOffset += dwSize; *ppVarOffset = pVarOffset; return TRUE; } BOOL BuildCountryRegistryListFromRC( void ) { HKEY hKey; HKEY hKey2; DWORD dwDisposition; WCHAR sz[512]; UINT uNumEntries; DWORD dwNextCountryID; HINSTANCE hInst; DWORD dw; hInst = GetModuleHandle (NULL); RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey2 ); RegCreateKeyEx( hKey2, "Country List", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition ); RegCloseKey( hKey2 ); dwNextCountryID = 1; while( dwNextCountryID ) { if ( LoadStringW( hInst, RC_COUNTRY_ID_BASE + dwNextCountryID, sz, sizeof(sz) / sizeof(WCHAR) ) > 0 ) { CHAR szCountryKey[20]; PWSTR p; PWSTR p2; wsprintf( szCountryKey, "%ld", dwNextCountryID ); RegCreateKeyEx( hKey, szCountryKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey2, &dwDisposition ); //RC_COUNTRY_ID_BASE + 1 "1,101,""United States of America"",""G"","" 1FG"",""011EFG""" p = sz; // // Get the countryID // dw = MyWToL( p ); RegSetValueEx( hKey2, "CountryCode", 0, REG_DWORD, (LPBYTE)&dw, sizeof(DWORD) ); p = wcschr( p, L',' ) + 1; dwNextCountryID = MyWToL( p ); p = wcschr( p, L'"' ) + 1; p2 = wcschr( p, L'"' ); *p2 = L'\0'; RegSetValueExW( hKey2, L"Name", 0, REG_SZ, (LPBYTE)p, (PBYTE)p2 - (PBYTE)p + sizeof(WCHAR) ); p = wcschr( p2 + 1, L'"' ) + 1; // Point to start of rule p2 = wcschr( p, L'"' ); // Point to end of rule *p2 = L'\0'; RegSetValueExW( hKey2, L"SameAreaRule", 0, REG_SZ, (LPBYTE)p, (PBYTE)p2 - (PBYTE)p + sizeof(WCHAR) ); p = wcschr( p2 + 1, L'"' ) + 1; // Point to start of rule p2 = wcschr( p, L'"' ); // Point to end of rule *p2 = L'\0'; RegSetValueExW( hKey2, L"LongDistanceRule", 0, REG_SZ, (LPBYTE)p, (PBYTE)p2 - (PBYTE)p + sizeof(WCHAR) ); p = wcschr( p2 + 1, L'"' ) + 1; // Point to start of rule p2 = wcschr( p, L'"' ); // Point to end of rule *p2 = L'\0'; RegSetValueExW( hKey2, L"InternationalRule", 0, REG_SZ, (LPBYTE)p, (PBYTE)p2 - (PBYTE)p + sizeof(WCHAR) ); RegCloseKey( hKey2 ); } else { // // BUGBUG? // There should be something else we could do here, but what? // dwNextCountryID = 0; } } /* LoadStringW( ExceptionsBase ) uNumEntries = MyWToL( sz ); for ( i = 0; i < uNumCountries; i++ ) { if ( LoadStringW( ExceptionsBase + i ) > 0 ) { parse and write to registry } } */ // dwNextCountryID = 0; // // while ( LoadStringW( // hInst, // RC_COUNTRY_EXCEPTIONS_BASE + dwNextCountryID, // sz, // sizeof(sz) / sizeof(WCHAR) // ) > 0 // ) // { // PWSTR pstrRuleName; // PWSTR pstrRule; // ////RC_COUNTRY_EXCEPTIONS_BASE + 1 "1\\Exceptions\\95,InternationalRule,011EFG" // // // // // The stuff following the first comma is the RuleName // // // pstrRuleName = wcschr( sz, L',' ) + 1; // // // // // Give the key name a terminating NULL // // // *(pstrRuleName - 1) = L'\0'; // // // // // The stuff following the first comma is the rule itself // // // pstrRule = wcschr( pstrRuleName, L',') + 1; // // // // // Give the rule name a terminating NULL // // // *(pstrRule - 1) = L'\0'; // // // RegCreateKeyExW( // hKey, // sz, // 0, // NULL, // REG_OPTION_NON_VOLATILE, // KEY_ALL_ACCESS, // NULL, // &hKey2, // &dwDisposition // ); // // RegSetValueExW( hKey2, // pstrRuleName, // 0, // REG_SZ, // (LPBYTE)pstrRule, // ( lstrlenW( pstrRule ) + 1 ) * sizeof(WCHAR) // ); // // // RegCloseKey( hKey2 ); // // dwNextCountryID++; // } // // RegCloseKey( hKey ); return TRUE; } BOOL BuildCountryList( 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; // static BOOL fAintNeverDoneThat = TRUE; // static HANDLE hRegistryEvent = NULL; // // // if ( fAintNeverDoneThat ) // { // hRegistryEvent = CreateEvent( // NULL, // TRUE, // FALSE, // NULL // ); // // //BUGBUG Need to kill the event when TAPISRV exits. // // // RegNotifyChangeKeyValue( // hKey, // TRUE, // REG_NOTIFY_CHANGE_LAST_SET | // REG_NOTIFY_CHANGE_NAME, // hRegistryEvent, // TRUE // ); // } if (!gpCountryList) { WCHAR sz[256]; DWORD dwSize; DWORD dwType; DWORD dwListSize; DWORD dwCountryId; 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; DBGOUT((1, "Mem alloc failed for country list!1 (0x%lx", dwListSize)); goto BuildCountryList_return; } // // Make sure the list is more-or-less there first // RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey ); // // 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 ( RegOpenKeyEx( hKey, "Country List\\1", 0, KEY_READ, &hKeyTemp ) ) { // // (re)create it // BuildCountryRegistryListFromRC(); } else { RegCloseKey( hKeyTemp ); } RegCloseKey( hKey ); // // In any case, the list is now good // RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKeyTemp ); RegOpenKeyEx( hKeyTemp, "Country List", 0, KEY_READ, &hKey ); 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 = sizeof(sz) / sizeof(WCHAR); uNumCountries = 0; while ( 0 == RegEnumKeyExW( hKey, uNumCountries, sz, &dwSize, NULL, NULL, NULL, NULL ) ) { 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; DBGOUT((1, "Mem alloc failed for country list!2 (0x%lx", dwListSize)); ServerFree( pTempCountryList ); goto BuildCountryList_return; } CopyMemory( p, pTempCountryList, (LPBYTE)pce - pTempCountryList ); ServerFree( pTempCountryList ); pTempCountryList = p; pce = (LPLINECOUNTRYENTRY)((LPBYTE)p + uOldSize); } dwCountryId = MyWToL( sz ); pce->dwCountryID = dwCountryId; pcePrev->dwNextCountryID = dwCountryId; // Prepare for next trip through the loop pcePrev = pce; pce++; uNumCountries++; dwSize = sizeof(sz) / sizeof(WCHAR); // need to set every time :-( } 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; DBGOUT((1, "Mem alloc failed for country list!3 (0x%lx", dwListSize)); ServerFree( pTempCountryList ); goto BuildCountryList_return; } CopyMemory( p, pTempCountryList, (LPBYTE)pce - pTempCountryList ); pVarOffset = (LPVOID)(p + (UINT)(pTempCountryList - pVarOffset)); ServerFree( pTempCountryList ); pTempCountryList = p; pce = (LPLINECOUNTRYENTRY) (pTempCountryList + sizeof(LINECOUNTRYLIST) + ( sizeof(LINECOUNTRYENTRY) * i )); } wsprintfW( sz, L"%ld", pce->dwCountryID); RegOpenKeyExW( hKey, sz, 0, KEY_READ, &hKey2 ); FillupACountryEntry( hKey2, pTempCountryList, pce, &pVarOffset ); 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; } /* // // Build the country list // DWORD dwNextCountryID = 1, dwNumCountries = 0, dwCountryListSize = 4096, dwVarDataSize = 4096, dwFixedSize, dwVarDataOffset = 0, i; HINSTANCE hInst = (HINSTANCE) GetModuleHandle (NULL); LPLINECOUNTRYENTRY pCountryEntry; LPLINECOUNTRYLIST pCountryList = ServerAlloc (dwCountryListSize); LPBYTE pVarData = ServerAlloc (dwVarDataSize); if (!pCountryList || !pVarData) { bResult = FALSE; goto BuildCountryList_return; } pCountryEntry = (LPLINECOUNTRYENTRY) (((LPBYTE) pCountryList) + sizeof(LINECOUNTRYLIST)); while (dwNextCountryID != 0) { WCHAR szCountryInfo[256], *p = szCountryInfo; LPDWORD pdwXxxSize; // // Get next country info string // if (LoadStringW( hInst, RC_COUNTRY_ID_BASE + dwNextCountryID, szCountryInfo, 256 ) == 0) { DBGOUT(( 3, "BuildCountryList: LoadString failed, err=%ld", GetLastError() )); ServerFree (pCountryList); ServerFree (pVarData); bResult = FALSE; goto BuildCountryList_return; } // // Increment the number of countries & make sure our buffer is // large enough // dwNumCountries++; if ((dwNumCountries * sizeof(LINECOUNTRYENTRY) + sizeof(LINECOUNTRYLIST)) > dwCountryListSize) { LPLINECOUNTRYLIST pTmpCountryList; if (!(pTmpCountryList = ServerAlloc (dwCountryListSize * 2))) { ServerFree (pCountryList); ServerFree (pVarData); bResult = FALSE; goto BuildCountryList_return; } CopyMemory (pTmpCountryList, pCountryList, dwCountryListSize); ServerFree (pCountryList); pCountryList = pTmpCountryList; dwCountryListSize *= 2; pCountryEntry = (LPLINECOUNTRYENTRY) (((LPBYTE) pCountryList) + sizeof(LINECOUNTRYLIST) + (dwNumCountries - 1) * sizeof(LINECOUNTRYENTRY)); } // // Initialize all the country entry DWORD fields // pCountryEntry->dwCountryID = dwNextCountryID; pCountryEntry->dwCountryCode = (DWORD) _wtoi (p); p = wcschr(p, ','); p++; dwNextCountryID = pCountryEntry->dwNextCountryID = (DWORD) _wtoi (p); p = wcschr(p, '\"'); p++; // // Initialize all the country entry string fields // pdwXxxSize = &pCountryEntry->dwCountryNameSize; for (i = 0; i < 4; i++) { WCHAR *p2 = wcschr (p, '\"'); *p2 = 0; *pdwXxxSize = (wcslen (p) + 1) * sizeof(WCHAR); *(pdwXxxSize + 1) = dwVarDataOffset; if ((dwVarDataOffset + *pdwXxxSize) > dwVarDataSize) { LPBYTE pTmpVarData; if (!(pTmpVarData = ServerAlloc (dwVarDataSize * 2))) { ServerFree (pCountryList); ServerFree (pVarData); bResult = FALSE; goto BuildCountryList_return; } CopyMemory (pTmpVarData, pVarData, dwVarDataSize); ServerFree (pVarData); pVarData = pTmpVarData; dwVarDataSize *= 2; } wcscpy ((PWSTR)(pVarData + dwVarDataOffset), p); dwVarDataOffset += *pdwXxxSize; p = p2 + 3; // "," pdwXxxSize++; pdwXxxSize++; } pCountryEntry++; } // // Alloc a global buffer, initialize it, and copy the fixed // & var data into it // dwFixedSize = sizeof(LINECOUNTRYLIST) + dwNumCountries * sizeof(LINECOUNTRYENTRY); if (!(gpCountryList = ServerAlloc (dwFixedSize + dwVarDataOffset))) { ServerFree (pCountryList); ServerFree (pVarData); bResult = FALSE; goto BuildCountryList_return; } CopyMemory( (LPBYTE) gpCountryList, (LPBYTE) pCountryList, dwFixedSize ); CopyMemory( ((LPBYTE) gpCountryList) + dwFixedSize, (LPBYTE) pVarData, dwVarDataOffset ); gpCountryList->dwTotalSize = gpCountryList->dwNeededSize = gpCountryList->dwUsedSize = dwFixedSize + dwVarDataOffset; gpCountryList->dwNumCountries = dwNumCountries; gpCountryList->dwCountryListSize = dwNumCountries * sizeof(LINECOUNTRYENTRY); gpCountryList->dwCountryListOffset = sizeof(LINECOUNTRYLIST); ServerFree (pCountryList); ServerFree (pVarData); // // Add the fixed size offset to the dwXxxOffset fields of all // the country entries // pCountryEntry = (LPLINECOUNTRYENTRY) (((LPBYTE) gpCountryList) + gpCountryList->dwCountryListOffset); for (i = 0; i < dwNumCountries; i++) { pCountryEntry->dwCountryNameOffset += dwFixedSize; pCountryEntry->dwSameAreaRuleOffset += dwFixedSize; pCountryEntry->dwLongDistanceRuleOffset += dwFixedSize; pCountryEntry->dwInternationalRuleOffset += dwFixedSize; pCountryEntry++; } } */ BuildCountryList_return: if (bResult == FALSE) { gpCountryList = &defCountryList; } return bResult; } PTLINECLIENT PASCAL GetHighestPriorityLineClient( PTLINE ptLine, DWORD dwMediaModes, DWORD dwAddressID ) { WCHAR *pszPriorityList, *pszAppInPriorityList, *pszAppInPriorityListPrev = (WCHAR *) 0xffffffff; BOOL bFoundOwnerInPriorityList = FALSE; DWORD dwMaskBit, dwPriorityListIndex, i; TPOINTERLIST lineClientList, *pLineClientList = &lineClientList; PTLINECLIENT ptHiPriLineClient = (PTLINECLIENT) NULL; if (GetLineClientListFromLine( ptLine, &pLineClientList ) != 0) { return NULL; } for( dwMaskBit = LINEMEDIAMODE_UNKNOWN, dwPriorityListIndex = 1; dwMediaModes; dwMaskBit <<= 1, dwPriorityListIndex++ ) { if (dwMaskBit & dwMediaModes) { // // See if there's a non-empty priority list for this media // mode, and if so safely make a local copy of it // EnterCriticalSection (&gPriorityListCritSec); { WCHAR *pszGlobalPriList; if ((pszGlobalPriList = TapiGlobals.apszPriorityList[dwPriorityListIndex])) { if (!(pszPriorityList = ServerAlloc( sizeof(WCHAR) * (1 + lstrlenW(pszGlobalPriList)) ))) { } lstrcpyW(pszPriorityList, pszGlobalPriList); } else { pszPriorityList = NULL; } } LeaveCriticalSection (&gPriorityListCritSec); // // 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. // for (i = 0; i < pLineClientList->dwNumUsedEntries; i++) { PTLINECLIENT ptLineClient = (PTLINECLIENT) pLineClientList->aEntries[i]; try { if ((ptLineClient->dwPrivileges & LINECALLPRIVILEGE_OWNER) && (ptLineClient->dwMediaModes & dwMaskBit) && // 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, ((PTLINEAPP) 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 } } // // If we alloc'd a local pri list above then free it // if (pszPriorityList) { ServerFree (pszPriorityList); } } if (ptHiPriLineClient != NULL) { break; } dwMediaModes &= ~dwMaskBit; } if (pLineClientList != &lineClientList) { ServerFree (pLineClientList); } return ptHiPriLineClient; } LONG PASCAL LineProlog( PTCLIENT ptClient, DWORD dwArgType, DWORD dwArg, LPVOID phdXxx, DWORD dwPrivilege, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTSPIFuncIndex, FARPROC *ppfnTSPI_lineXxx, PASYNCREQUESTINFO *ppAsyncRequestInfo, DWORD dwRemoteRequestID #if DBG ,char *pszFuncName #endif ) { LONG lResult = 0; PTPROVIDER ptProvider; DBGOUT((3, "LineProlog: (line%s) enter", pszFuncName)); *phMutex = NULL; *pbDupedMutex = FALSE; if (ppAsyncRequestInfo) { *ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL; } if (TapiGlobals.dwNumLineInits == 0) { lResult = LINEERR_UNINITIALIZED; goto LineProlog_exit; } switch (dwArgType) { case ANY_RT_HCALL: { try { PTCALLCLIENT ptCallClient = (PTCALLCLIENT) dwArg; if (IsBadPtrKey (ptCallClient, TCALLCLIENT_KEY) || (ptCallClient->ptClient != ptClient)) { lResult = LINEERR_INVALCALLHANDLE; goto LineProlog_exit; } ptProvider = ptCallClient->ptCall->ptProvider; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = LINEERR_OPERATIONFAILED; goto LineProlog_exit; } } *((HDRVCALL *) phdXxx) = ptCallClient->ptCall->hdCall; if (ptCallClient->dwPrivilege < dwPrivilege) { lResult = LINEERR_NOTOWNER; goto LineProlog_exit; } if (ptCallClient->dwKey != TCALLCLIENT_KEY) { lResult = LINEERR_INVALCALLHANDLE; goto LineProlog_exit; } } myexcept { lResult = LINEERR_INVALCALLHANDLE; goto LineProlog_exit; } break; } case ANY_RT_HLINE: { try { PTLINECLIENT ptLineClient = (PTLINECLIENT) dwArg; if (IsBadPtrKey (ptLineClient, TLINECLIENT_KEY) || (ptLineClient->ptClient != ptClient)) { lResult = LINEERR_INVALLINEHANDLE; goto LineProlog_exit; } ptProvider = ptLineClient->ptLine->ptProvider; if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = LINEERR_OPERATIONFAILED; goto LineProlog_exit; } } *((HDRVLINE *) phdXxx) = ptLineClient->ptLine->hdLine; if ((ptLineClient->dwKey != TLINECLIENT_KEY) || (ptLineClient->ptClient != ptClient)) { lResult = LINEERR_INVALLINEHANDLE; goto LineProlog_exit; } } myexcept { lResult = LINEERR_INVALLINEHANDLE; goto LineProlog_exit; } break; } case DEVICE_ID: { PTLINELOOKUPENTRY pLineLookupEntry; if (dwArg && !IsValidLineApp ((HLINEAPP) dwArg, ptClient)) { lResult = LINEERR_INVALAPPHANDLE; goto LineProlog_exit; } if (!(pLineLookupEntry = GetLineLookupEntry (dwPrivilege))) { lResult = LINEERR_BADDEVICEID; goto LineProlog_exit; } if (pLineLookupEntry->bRemoved) { lResult = LINEERR_NODEVICE; goto LineProlog_exit; } if (!(ptProvider = pLineLookupEntry->ptProvider)) { lResult = LINEERR_NODRIVER; goto LineProlog_exit; } // BUGBUG LineProlog: wrap tProvider access in try/except if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT) { if (!WaitForMutex( ptProvider->hMutex, phMutex, pbDupedMutex, ptProvider, TPROVIDER_KEY, INFINITE )) { lResult = LINEERR_OPERATIONFAILED; goto LineProlog_exit; } } break; } } // switch // // 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->dwKey = TASYNC_KEY; pAsyncRequestInfo->ptClient = ptClient; if (dwArgType == ANY_RT_HCALL) { PTLINECLIENT ptLineClient = (PTLINECLIENT) ((PTCALLCLIENT) dwArg)->ptLineClient; pAsyncRequestInfo->pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; pAsyncRequestInfo->dwCallbackInst = ptLineClient->dwCallbackInstance; } else if (dwArgType == ANY_RT_HLINE) { pAsyncRequestInfo->pInitData = (DWORD) ((PTLINEAPP) ((PTLINECLIENT) dwArg)->ptLineApp)->lpfnCallback; pAsyncRequestInfo->dwCallbackInst = ((PTLINECLIENT) dwArg)->dwCallbackInstance; } else { pAsyncRequestInfo->pInitData = (DWORD) ((PTLINEAPP) dwArg)->lpfnCallback; pAsyncRequestInfo->dwCallbackInst = 0; } pAsyncRequestInfo->bLineFunc = TRUE; if (dwRemoteRequestID) { lResult = pAsyncRequestInfo->dwRequestID = dwRemoteRequestID; } else { EnterCriticalSection (&gRequestIDCritSec); lResult = pAsyncRequestInfo->dwRequestID = TapiGlobals.dwAsyncRequestID; if (++TapiGlobals.dwAsyncRequestID & 0x80000000) { TapiGlobals.dwAsyncRequestID = 1; } LeaveCriticalSection (&gRequestIDCritSec); } *ppAsyncRequestInfo = pAsyncRequestInfo; } LineProlog_exit: #if DBG { char szResult[32]; DBGOUT(( 3, "LineProlog: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (lResult, szResult) )); } #endif return lResult; } void PASCAL LineEpilogSync( LONG *plResult, HANDLE hMutex, BOOL bCloseMutex #if DBG ,char *pszFuncName #endif ) { MyReleaseMutex (hMutex, bCloseMutex); #if DBG { char szResult[32]; DBGOUT(( 3, "LineEpilogSync: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (*plResult, szResult) )); } #endif } void PASCAL LineEpilogAsync( LONG *plResult, LONG lRequestID, HANDLE hMutex, BOOL bCloseMutex, PASYNCREQUESTINFO pAsyncRequestInfo #if DBG ,char *pszFuncName #endif ) { MyReleaseMutex (hMutex, bCloseMutex); if (lRequestID > 0) { if (*plResult != (LONG) pAsyncRequestInfo) { // // 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 ((DWORD) pAsyncRequestInfo, *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) // ServerFree (pAsyncRequestInfo); } *plResult = lRequestID; #if DBG { char szResult[32]; DBGOUT(( 3, "LineEpilogAsync: (line%s) exit, result=%s", pszFuncName, MapResultCodeToText (lRequestID, szResult) )); } #endif } void PASCAL LineEventProc( HTAPILINE htLine, HTAPICALL htCall, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { switch (dwMsg) { case LINE_ADDRESSSTATE: case LINE_LINEDEVSTATE: case LINE_DEVSPECIFIC: case LINE_DEVSPECIFICFEATURE: // BUGBUG: if LINE_LINEDEVSTATE\CAPSCHG get num addr id's again SendMsgToLineClients( (PTLINE) htLine, NULL, dwMsg, dwParam1, dwParam2, dwParam3 ); break; case LINE_CLOSE: DestroytLine ((PTLINE) htLine, TRUE); // unconditional destroy break; case LINE_CALLDEVSPECIFIC: case LINE_CALLDEVSPECIFICFEATURE: case LINE_CALLINFO: switch (dwMsg) { case LINE_CALLDEVSPECIFIC: dwMsg = LINE_DEVSPECIFIC; break; case LINE_CALLDEVSPECIFICFEATURE: dwMsg = LINE_DEVSPECIFICFEATURE; break; case LINE_CALLINFO: dwParam2 = dwParam3 = 0; break; } SendMsgToCallClients( (PTCALL) htCall, NULL, dwMsg, dwParam1, dwParam2, dwParam3 ); break; case LINE_MONITORDIGITS: case LINE_MONITORMEDIA: // BUGBUG LINE_MONITORDIGITS\MEDIA: only send these msgs to callCli's that // have the corresponding bits enabled SendMsgToCallClients( (PTCALL) htCall, NULL, dwMsg, dwParam1, dwParam2, (dwParam3 ? dwParam3 : (DWORD) GetTickCount()) ); break; case LINE_CALLSTATE: { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptCall = (PTCALL) htCall; if ((ptCall = WaitForExclusivetCallAccess( htCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE ))) { PTCALLCLIENT ptCallClient = (PTCALLCLIENT)ptCall->ptCallClients; ASYNCEVENTMSG msg; if (dwParam1 == 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 // DWORD dwMediaModes = dwParam3; PTLINECLIENT ptLineClientOwner; ptCall->bAlertApps = FALSE; // // Find out which address the call is on // // BUGBUG mutex if req'b by SP CallSP2( ptCall->ptProvider->apfn[SP_LINEGETCALLADDRESSID], "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) ptCall->hdCall, (DWORD) (&ptCall->dwAddressID) ); MyReleaseMutex (hMutex, bDupedMutex); // // Add the UNKNOWN bit if >1 bit set // if (!IsOnlyOneBitSetInDWORD (dwMediaModes) || dwMediaModes == 0) { dwMediaModes |= LINEMEDIAMODE_UNKNOWN; } // // Try to find an owner. If no owner found then destroy // the tCall. // LINE_CALLSTATE_findOwner: if ((ptLineClientOwner = GetHighestPriorityLineClient( (PTLINE) htLine, dwMediaModes, ptCall->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); return; } } } if (CreateCallMonitors (ptCall) <= 0 && !ptLineClientOwner) { DestroytCall (ptCall); return; } if (!WaitForExclusivetCallAccess( htCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { return; } } /* 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 // // If there isn't an owner for this call & the state is something // other than IDLE or OFFERING then drop the call (otherwise no // app has "responsibility" for it) // if (ptCall->dwNumOwners == 0 && !(dwParam1 & (LINECALLSTATE_IDLE | LINECALLSTATE_OFFERING))) { // BUG//BUG LINE_CALLSTATE: grab provider mutex if needed if (ptCall->ptProvider->apfn[SP_LINEDROPNOOWNER]) { CallSP1( ptCall->ptProvider->apfn[SP_LINEDROPNOOWNER], "lineDropNoOwner", SP_FUNC_SYNC, (DWORD) ptCall->hdCall ); } else { CallSP4( ptCall->ptProvider->apfn[SP_LINEDROP], "lineDrop", SP_FUNC_ASYNC, (DWORD) BOGUS_REQUEST_ID, (DWORD) ptCall->hdCall, (DWORD) NULL, (DWORD) 0 ); } MyReleaseMutex (hMutex, bDupedMutex); return; } */ // // SP-initiated conference // if (dwParam1 == LINECALLSTATE_CONFERENCED) { if (!ptCall->pConfList) { PTCALL ptConfCall = (PTCALL) dwParam2; PTCONFERENCELIST pConfList; ptCall->pConfList = (LPVOID) 0xffffffff; MyReleaseMutex (hMutex, bDupedMutex); if (WaitForExclusivetCallAccess( (HTAPICALL) dwParam2, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { ptConfCall = (PTCALL) dwParam2; 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; MyReleaseMutex (hMutex, bDupedMutex); } else { pConfList = NULL; } SetCallConfList (ptCall, pConfList, TRUE); if (!WaitForExclusivetCallAccess( htCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { return; } } } // // If call is a conference child and the call state has // changed then remove it from the conference // // BUGBUG LINE_CALLSTATE: conf list race conditions else if (ptCall->pConfList && ptCall->pConfList != (PTCONFERENCELIST) 0xffffffff) { try { if (((PTCONFERENCELIST) ptCall->pConfList)->aptCalls[0] != ptCall) { SetCallConfList (ptCall, NULL, FALSE); } } myexcept { } } // // // ptCall->dwCallState = dwParam1; ptCall->dwCallStateMode = dwParam2; // // Send the CALLSTATE msg to all the clients // msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; msg.dwMsg = dwMsg; msg.dwParam1 = dwParam1; msg.dwParam2 = dwParam2; ptCallClient = ptCall->ptCallClients; while (ptCallClient) { PTLINECLIENT ptLineClient; PTLINEAPP ptLineApp; ptLineClient = (PTLINECLIENT) ptCallClient->ptLineClient; ptLineApp = (PTLINEAPP) ptLineClient->ptLineApp; msg.pInitData = (DWORD) ptLineApp->lpfnCallback; msg.hDevice = (DWORD) ptCallClient; msg.dwCallbackInst = ptLineClient->dwCallbackInstance; // // REMOTESP HACK: indicate the hRemoteLine in p4 // msg.dwParam4 = ptLineClient->hRemoteLine; if (ptCallClient->bIndicatePrivilege) { // // 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; newCallMsg.dwTotalSize = sizeof (ASYNCEVENTMSG); newCallMsg.pInitData = (DWORD) msg.pInitData; newCallMsg.hDevice = (DWORD) ptLineClient->hRemoteLine; newCallMsg.dwCallbackInst = msg.dwCallbackInst; newCallMsg.pfnPostProcessProc = 0; newCallMsg.dwMsg = LINE_APPNEWCALL; newCallMsg.dwParam1 = ptCall->dwAddressID; newCallMsg.dwParam2 = (DWORD) ptCallClient; newCallMsg.dwParam3 = ptCallClient->dwPrivilege; WriteEventBuffer (ptCallClient->ptClient, &newCallMsg); msg.dwParam3 = 0; } else { msg.dwParam3 = ptCallClient->dwPrivilege; } ptCallClient->bIndicatePrivilege = FALSE; } else { msg.dwParam3 = 0; } // // REMOTESP HACK: If the client is remote(sp), then pass // on the media mode the SP passed us in p3 // if (((PTCLIENT) ptLineApp->ptClient)->hProcess == (HANDLE) 0xffffffff) { msg.dwParam3 = dwParam3; } WriteEventBuffer (ptCallClient->ptClient, &msg); ptCallClient = ptCallClient->pNextSametCall; } MyReleaseMutex (hMutex, bDupedMutex); } // if ((ptCall = WaitForExclusivetCallAccess( break; } case LINE_GATHERDIGITS: { PASYNCREQUESTINFO pAsyncRequestInfo; if (!(pAsyncRequestInfo = (PASYNCREQUESTINFO) dwParam2)) { // // 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 (!IsBadReadPtr (pAsyncRequestInfo, sizeof (ASYNCREQUESTINFO)) && !IsBadPtrKey (pAsyncRequestInfo, TASYNC_KEY)) { LPWSTR lpsDigitsSrv = (LPWSTR) (((LPBYTE) pAsyncRequestInfo) + pAsyncRequestInfo->dwParam1), lpsDigitsCli = (LPWSTR) pAsyncRequestInfo->dwParam2; DWORD dwNumDigits = pAsyncRequestInfo->dwParam3, dwNumDigitsTmp; HCALL hCall = (HCALL) pAsyncRequestInfo->dwParam4; ASYNCEVENTMSG *pMsg; // BUGBUG LINE_GATHERDIGITS: need to pass pLine->hRemoteLine for remotesp if (!(pMsg = ServerAlloc( sizeof (ASYNCEVENTMSG) + dwNumDigits * sizeof (WCHAR) + 3 ))) { 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) // lstrcpynW ((WCHAR *) (pMsg + 1), lpsDigitsSrv, dwNumDigits + 1); if ((dwNumDigitsTmp = lstrlenW ((WCHAR *) (pMsg + 1))) < dwNumDigits) { dwNumDigits = dwNumDigitsTmp + 1; } // // Make sure total size is DWORD-aligned so client side doesn't // incur an alignment fault // pMsg->dwTotalSize = (sizeof (ASYNCEVENTMSG) + dwNumDigits * sizeof (WCHAR) + 3) & 0xfffffffc; pMsg->pInitData = pAsyncRequestInfo->pInitData; pMsg->pfnPostProcessProc = pAsyncRequestInfo->pfnClientPostProcessProc; pMsg->hDevice = (DWORD) hCall; pMsg->dwMsg = LINE_GATHERDIGITS; pMsg->dwCallbackInst = pAsyncRequestInfo->dwCallbackInst; pMsg->dwParam1 = dwParam1; pMsg->dwParam2 = (DWORD) lpsDigitsCli; pMsg->dwParam4 = dwNumDigits; if (pMsg->dwParam3 == 0) { pMsg->dwParam3 = GetTickCount(); } WriteEventBuffer (pAsyncRequestInfo->ptClient, pMsg); ServerFree (pMsg); ServerFree (pAsyncRequestInfo); } else { // BUGBUG assert (sp error) } break; } case LINE_GENERATE: case LINE_MONITORTONE: { // // Note: dwParam2 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 // try { LPDWORD pInstData = (LPDWORD) dwParam2; ASYNCEVENTMSG msg; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pInstData[0]; PTLINECLIENT ptLineClient = (PTLINECLIENT) ptCallClient->ptLineClient; msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; msg.pfnPostProcessProc = 0; msg.hDevice = (DWORD) ptCallClient; msg.dwMsg = dwMsg; msg.dwCallbackInst = ptLineClient->dwCallbackInstance; msg.dwParam1 = dwParam1; // // Indicate the endToEndID/toneListID for remotesp, and the // hRemoteLine in p4 to make life easier for remotesp // msg.dwParam2 = pInstData[1]; if (msg.dwParam3 == 0) { msg.dwParam3 = GetTickCount(); } msg.dwParam4 = ptLineClient->hRemoteLine; // // 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); } } ServerFree (pInstData); } myexcept { // do nothing } break; } case LINE_NEWCALL: { BOOL bCloseMutex; HANDLE hMutex; PTLINE ptLine; if ((ptLine = WaitForExclusivetLineAccess( htLine, &hMutex, &bCloseMutex, INFINITE ))) { // // Create a tCall & set the bAlertApps field so we create the // appropriate tCallClients on the first call state msg // PTCALL ptCall; if (CreatetCall ((PTLINE) htLine, TRUE, &ptCall, NULL, NULL) == 0) { ptCall->hdCall = (HDRVCALL) dwParam1; ptCall->bAlertApps = TRUE; ptCall->dwCallState = LINECALLSTATE_UNKNOWN; } else { // // Failed to create the tCall, so make sure we set // *lphtCall to NULL below to indicate this failure // to the provider // ptCall = (PTCALL) NULL; } // // Fill in the provider's lphtCall // *((LPHTAPICALL) dwParam2) = (HTAPICALL) ptCall; MyReleaseMutex (hMutex, bCloseMutex); } break; } case LINE_CREATE: { LONG lResult; DWORD dwDeviceID; TSPIPROC pfnTSPI_providerCreateLineDevice; PTPROVIDER ptProvider = (PTPROVIDER) dwParam1; PTLINELOOKUPTABLE pTable, pPrevTable; PTLINELOOKUPENTRY pEntry; 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) // WaitForSingleObject (TapiGlobals.hMutex, INFINITE); 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) ))) { ReleaseMutex (TapiGlobals.hMutex); 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) dwParam1; // // 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, dwParam2, dwDeviceID )) == 0) { TSPIPROC pfnTSPI_lineNegotiateTSPIVersion = ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION]; if ((lResult = CallSP4( pfnTSPI_lineNegotiateTSPIVersion, "", SP_FUNC_SYNC, dwDeviceID, TAPI_VERSION1_0, TAPI_VERSION_CURRENT, (DWORD) &pEntry->dwSPIVersion )) == 0) { PTCLIENT ptClient = TapiGlobals.ptClients; ASYNCEVENTMSG msg; pTable->dwNumUsedEntries++; TapiGlobals.dwNumLines++; // PERF ** Number of lines PerfBlock.dwLines = TapiGlobals.dwNumLines; msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = msg.hDevice = msg.dwCallbackInst = msg.dwParam2 = msg.dwParam3 = 0; while (ptClient) { // BUGBUG LINE_CREATE: WaitForSingleObject (ptClient->hMutex, PTLINEAPP ptLineApp = ptClient->ptLineApps; while (ptLineApp) { if (ptLineApp->dwAPIVersion == TAPI_VERSION1_0) { msg.dwMsg = LINE_LINEDEVSTATE; msg.dwParam1 = LINEDEVSTATE_REINIT; } else { msg.dwMsg = LINE_CREATE; msg.dwParam1 = dwDeviceID; } msg.pInitData = (DWORD) ptLineApp->lpfnCallback; WriteEventBuffer (ptClient, &msg); ptLineApp = ptLineApp->pNext; } ptClient = ptClient->pNext; } // break; } #if DBG else { DBGOUT((1, "SP failed TSPI_lineNegotiateTSPIVersion")); } #endif } #if DBG else { DBGOUT((1, "SP failed providerCreateLineDevice")); } #endif if (lResult) { CloseHandle (pEntry->hMutex); } } ReleaseMutex (TapiGlobals.hMutex); break; } case LINE_CREATEDIALOGINSTANCE: { DWORD dwDataSize, dwAlignedDataSize, dwAlignedUIDllNameSize, dwTotalSize; PTCLIENT ptClient; PASYNCEVENTMSG pMsg; PASYNCREQUESTINFO pAsyncReqInfo; PTAPIDIALOGINSTANCE ptDlgInst; LPTUISPICREATEDIALOGINSTANCEPARAMS pParams; pParams = (LPTUISPICREATEDIALOGINSTANCEPARAMS) dwParam1; // // Verify the async request info struct // pAsyncReqInfo = (PASYNCREQUESTINFO) pParams->dwRequestID; try { ptClient = pAsyncReqInfo->ptClient; if (IsBadPtrKey (pAsyncReqInfo, TASYNC_KEY)) { pParams->htDlgInst = NULL; return; } } myexcept { pParams->htDlgInst = NULL; return; } // // Alloc bufs for the msg & dlg instance, careful to keep offsets // & total msg size on 64-bit boundaries // dwDataSize = pParams->dwSize; dwAlignedDataSize = (dwDataSize + 8) & 0xfffffff7; dwAlignedUIDllNameSize = 0xfffffff7 & (8 + ((lstrlenW ((PWSTR) pParams->lpszUIDLLName) + 1)*sizeof (WCHAR))); dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize + dwAlignedUIDllNameSize; if (!(pMsg = ServerAlloc (dwTotalSize))) { pParams->htDlgInst = NULL; return; } if (!(ptDlgInst = ServerAlloc (sizeof (TAPIDIALOGINSTANCE)))) { ServerFree (pMsg); pParams->htDlgInst = NULL; return; } // // Add the dlg inst to the tClient's list // // BUGBUG mutex if ((ptDlgInst->pNext = ptClient->pGenericDlgInsts)) { ptDlgInst->pNext->pPrev = ptDlgInst; } ptClient->pGenericDlgInsts = ptDlgInst; // // Init dlg inst struct & send msg to client // ptDlgInst->dwKey = TDLGINST_KEY; ptDlgInst->hdDlgInst = pParams->hdDlgInst; ptDlgInst->ptClient = ptClient; ptDlgInst->ptProvider = (PTPROVIDER) htLine; pMsg->dwTotalSize = dwTotalSize; pMsg->hDevice = (DWORD) ptDlgInst; pMsg->dwMsg = LINE_CREATEDIALOGINSTANCE; pMsg->dwParam1 = sizeof (ASYNCEVENTMSG); // data offset pMsg->dwParam2 = dwDataSize; // data size pMsg->dwParam3 = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize; // name offset CopyMemory ((LPBYTE)(pMsg + 1), pParams->lpParams, dwDataSize); lstrcpyW( (PWSTR) ((LPBYTE)(pMsg + 1) + dwAlignedDataSize), (PWSTR) pParams->lpszUIDLLName ); pParams->htDlgInst = (HTAPIDIALOGINSTANCE) ptDlgInst; WriteEventBuffer (ptClient, pMsg); ServerFree (pMsg); break; } case LINE_SENDDIALOGINSTANCEDATA: { DWORD dwDataSize, dwAlignedDataSize, dwTotalSize; PTCLIENT ptClient; PASYNCEVENTMSG pMsg; PTAPIDIALOGINSTANCE ptDlgInst = (PTAPIDIALOGINSTANCE) htLine; // // Verify the dlg inst // try { ptClient = ptDlgInst->ptClient; if (IsBadPtrKey (ptDlgInst, TDLGINST_KEY)) { return; } } myexcept { return; } // // Careful to keep offsets & total msg size on 64-bit boundaries // dwDataSize = dwParam2; dwAlignedDataSize = (dwDataSize + 8) & 0xfffffff7; dwTotalSize = sizeof (ASYNCEVENTMSG) + dwAlignedDataSize; if (!(pMsg = ServerAlloc (dwTotalSize))) { return; } // // Send the msg to the client // pMsg->dwTotalSize = dwTotalSize; pMsg->hDevice = (DWORD) ptDlgInst; pMsg->dwMsg = LINE_SENDDIALOGINSTANCEDATA; pMsg->dwParam1 = sizeof (ASYNCEVENTMSG); // data offset pMsg->dwParam2 = dwDataSize; // data size CopyMemory ((LPBYTE)(pMsg + 1), (LPBYTE) dwParam1, dwDataSize); WriteEventBuffer (ptClient, pMsg); ServerFree (pMsg); break; } case LINE_REMOVE: { PTLINELOOKUPENTRY pLookupEntry; if (!(pLookupEntry = GetLineLookupEntry (dwParam1))) { return; } // // Mark the lookup table entry as removed // pLookupEntry->bRemoved = 1; DestroytLine (pLookupEntry->ptLine, TRUE); // unconditional destroy SendAMsgToAllLineApps (TAPI_VERSION2_0, LINE_REMOVE, dwParam1, 0, 0); break; } default: // if DBG assert (unrecognized dwMsg) break; } } void CALLBACK LineEventProcSP( HTAPILINE htLine, HTAPICALL htCall, DWORD dwMsg, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3 ) { 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; } DBGOUT(( 3, "LineEventProc: 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(dwParam1) || dwParam1 > LINECALLSTATE_UNKNOWN) { pszCallState = szInvalCallStateVal; } else { DWORD i, dwBitMask; for( i = 0, dwBitMask = 1; dwParam1 != dwBitMask; i++, dwBitMask <<= 1 ); pszCallState = aszCallStates[i]; } DBGOUT(( 3, " P1=%s (x%x), P2=x%x, P3=x%x", pszCallState, dwParam1, dwParam2, dwParam3 )); } else { DBGOUT(( 3, " P1=x%x, P2=x%x, P3=x%x", dwParam1, dwParam2, dwParam3 )); } } #endif switch (dwMsg) { case LINE_NEWCALL: case LINE_CREATEDIALOGINSTANCE: case LINE_SENDDIALOGINSTANCEDATA: // // 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, dwParam1, dwParam2, dwParam3); break; default: if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT)))) { pSPEvent->dwType = SP_LINE_EVENT; pSPEvent->htLine = htLine; pSPEvent->htCall = htCall; pSPEvent->dwMsg = dwMsg; pSPEvent->dwParam1 = dwParam1; pSPEvent->dwParam2 = dwParam2; pSPEvent->dwParam3 = dwParam3; QueueSPEvent (pSPEvent); } else { // // Alloc failed, so call the event proc within the SP's context // LineEventProc (htLine, htCall, dwMsg, dwParam1, dwParam2, dwParam3); } break; } } void WINAPI LAccept( PLINEACCEPT_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineAccept; if ((lRequestID = LINEPROLOG( pParams->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_LINEACCEPT, // provider func index &pfnTSPI_lineAccept, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "Accept" // func name )) > 0) { // // 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 = (PTCALL) ((PTCALLCLIENT) pParams->hCall)->ptCall; if (ptCall->pszAppName == NULL) { DWORD dwAppNameSize; PTLINEAPP ptLineApp; ptLineApp = (PTLINEAPP) ((PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient)->ptLineApp; dwAppNameSize = ptLineApp->dwFriendlyNameSize; if ((ptCall->pszAppName = ServerAlloc (dwAppNameSize))) { CopyMemory( ptCall->pszAppName, ptLineApp->pszFriendlyName, dwAppNameSize ); ptCall->dwAppNameSize = dwAppNameSize; } } } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LAccept_epilog; } pParams->lResult = CallSP4( pfnTSPI_lineAccept, "lineAccept", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (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, "Accept" ); } void LAddToConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PTCALL ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam1; if (pAsyncEventMsg->dwParam2 == 0) { PTCONFERENCELIST pConfList = (PTCONFERENCELIST) pAsyncRequestInfo->dwParam2; SetCallConfList (ptConsultCall, pConfList, TRUE); } else { SetCallConfList (ptConsultCall, NULL, TRUE); } } void WINAPI LAddToConference( PLINEADDTOCONFERENCE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdConfCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineAddToConference; if ((lRequestID = LINEPROLOG( pParams->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 "AddToConference" // func name )) > 0) { PTCALL ptConfCall, ptConsultCall; HDRVCALL hdConsultCall; PTCALLCLIENT ptConsultCallClient, ptConfCallClient = (PTCALLCLIENT) pParams->hConfCall; PTCONFERENCELIST pConfList; // // Safely make sure that the conf call is really a conf parent // try { ptConfCall = ((PTCALLCLIENT) pParams->hConfCall)->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 = IsValidCall( pParams->hConsultCall, pParams->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_return; } if (!(ptConsultCallClient->dwPrivilege & LINECALLPRIVILEGE_OWNER)) { lRequestID = LINEERR_NOTOWNER; goto LAddToConference_return; } if (SetCallConfList( ptConsultCall, (PTCONFERENCELIST) 0xffffffff, FALSE )) { lRequestID = (pConfList->aptCalls[0] == ptConsultCall ? LINEERR_INVALCALLHANDLE : LINEERR_INVALCALLSTATE); goto LAddToConference_return; } hdConsultCall = ptConsultCall->hdCall; } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LAddToConference_return; } // // Set up the async request struct & call the SP // pAsyncRequestInfo->pfnPostProcess = LAddToConference_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptConsultCall; pAsyncRequestInfo->dwParam2 = (DWORD) pConfList; pParams->lResult = CallSP3( pfnTSPI_lineAddToConference, "lineAddToConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdConfCall, (DWORD) hdConsultCall ); } LAddToConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "AddToConference" ); } void WINAPI LAgentSpecific( PLINEAGENTSPECIFIC_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "AgentSpecific" // func name )) > 0) { DWORD dwParamsSize = pParams->dwParamsSize; PTLINE ptLine; PTLINECLIENT pProxy; try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; pProxy = ptLine->apProxys[LINEPROXYREQUEST_AGENTSPECIFIC]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LAgentSpecific_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; goto LAgentSpecific_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->lpParams; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; // // 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 ); // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LAgentSpecific_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (ptLine->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->dwParam2 = dwParamsSize; pAsyncRequestInfo->dwParam3 = (DWORD) pBuf; CopyMemory( pBuf + sizeof (ASYNCEVENTMSG), pDataBuf + pParams->dwParamsOffset, dwParamsSize ); pParams->lResult = CallSP6( pRemoteSP->apfn[SP_LINEAGENTSPECIFIC], "lineAgentSpecific", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) pParams->dwAgentExtensionIDIndex, (DWORD) 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, "AgentSpecific" ); } void WINAPI LAnswer( PLINEANSWER_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineAnswer; if ((lRequestID = LINEPROLOG( pParams->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 "Answer" // func name )) > 0) { // // 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 = (PTCALL) ((PTCALLCLIENT) pParams->hCall)->ptCall; if (ptCall->pszAppName == NULL) { DWORD dwAppNameSize; PTLINEAPP ptLineApp; ptLineApp = (PTLINEAPP) ((PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient)->ptLineApp; dwAppNameSize = ptLineApp->dwFriendlyNameSize; if ((ptCall->pszAppName = ServerAlloc (dwAppNameSize))) { CopyMemory( ptCall->pszAppName, ptLineApp->pszFriendlyName, dwAppNameSize ); ptCall->dwAppNameSize = dwAppNameSize; } } } myexcept { lRequestID = LINEERR_INVALCALLHANDLE; goto LAnswer_epilog; } pParams->lResult = CallSP4( pfnTSPI_lineAnswer, "lineAnswer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwUserUserInfoOffset), (DWORD) (pParams->dwUserUserInfoOffset == TAPI_NO_DATA ? 0 : pParams->dwSize) ); } LAnswer_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Answer" ); } void WINAPI LBlindTransfer( PLINEBLINDTRANSFER_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineBlindTransfer; if ((lRequestID = LINEPROLOG( pParams->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 "BlindTransfer" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineBlindTransfer, "lineBlindTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) pDataBuf + pParams->dwDestAddressOffset, pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "BlindTransfer" ); } void WINAPI LClose( PLINECLOSE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; DBGOUT((4, "Entering lineClose")); if ((pParams->lResult = LINEPROLOG( pParams->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 "Close" // func name )) == 0) { DestroytLineClient ((PTLINECLIENT) pParams->hLine); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "Close" ); DBGOUT((4, "Leaving lineClose")); } void LCompleteCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { pAsyncEventMsg->dwParam3 = pAsyncRequestInfo->dwParam1; pAsyncEventMsg->dwParam4 = pAsyncRequestInfo->dwParam2; } void WINAPI LCompleteCall( PLINECOMPLETECALL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineCompleteCall; if ((lRequestID = LINEPROLOG( pParams->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 "CompleteCall" // func name )) > 0) { if (!IsOnlyOneBitSetInDWORD (pParams->dwCompletionMode) || (pParams->dwCompletionMode & ~AllCallComplModes) ) { lRequestID = LINEERR_INVALCALLCOMPLMODE; goto LCompleteCall_epilog; } pAsyncRequestInfo->pfnPostProcess = LCompleteCall_PostProcess; pAsyncRequestInfo->dwParam2 = pParams->lpdwCompletionID; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineCompleteCall, "lineCompleteCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) &pAsyncRequestInfo->dwParam1, (DWORD) pParams->dwCompletionMode, (DWORD) pParams->dwMessageID ); } LCompleteCall_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "CompleteCall" ); } void LCompleteTransfer_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1; LPHCALL lphConfCall = (LPHCALL) pAsyncRequestInfo->dwParam2; PTCALLCLIENT ptConfCallClient; if (WaitForExclusivetCallAccess( (HTAPICALL) ptConfCall, TINCOMPLETECALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwCallInstance = pAsyncRequestInfo->dwParam5; PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam3, ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam4; LPHCALL lphCall = (LPHCALL) pAsyncRequestInfo->dwParam2; // // 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->dwCallInstance != dwCallInstance) { MyReleaseMutex (hMutex, bDupedMutex); goto LCompleteTransfer_PostProcess_bad_ptConfCall; } ptConfCallClient = (PTCALLCLIENT) ptConfCall->ptCallClients; if (pAsyncEventMsg->dwParam2 == 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) { MyReleaseMutex (hMutex, bDupedMutex); ptConfCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = LINEERR_INVALLINEHANDLE; } goto LCompleteTransfer_PostProcess_initMsgParams; } // // Find out which address the call is on // CallSP2( ptCall->ptProvider->apfn[SP_LINEGETCALLADDRESSID], "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) ptCall->hdCall, (DWORD) (&ptCall->dwAddressID) ); // // Mark the calls & conf list as valid, the release the mutex. // ptConfCall->dwKey = TCALL_KEY; ptConfCallClient->dwKey = TCALLCLIENT_KEY; ((PTCONFERENCELIST) ptConfCall->pConfList)->dwKey = TCONFLIST_KEY; MyReleaseMutex (hMutex, bDupedMutex); // // Create monitor tCallClients // CreateCallMonitors (ptConfCall); } else // error { RemoveCallFromLineList (ptConfCall); ptConfCall->dwKey = ((PTCONFERENCELIST) ptConfCall->pConfList)->dwKey = INVAL_KEY; // // Check to see if another thread already destroyed the // tCallClient (due to a lineClose/Shutdown) before trying // to reference a freed object // if (ptConfCall->ptCallClients) { RemoveCallClientFromLineClientList (ptConfCallClient); ptConfCallClient->dwKey = INVAL_KEY; ServerFree (ptConfCallClient); } // // If we have a duped mutex handle (bDupedMutex == TRUE) // then we can safely go ahead and close the ptCall->hMutex // since no other thread will be waiting on it (thanks to // the first WaitForSingleObject in WaitForMutex). Also // release & close the duped handle. // // Otherwise, we have the actual ptCall->hMutex, and we // wrap the release & close in a critical section to // prevent another thread "T2" from grabbing ptCall->hMutex // right after we release but right before we close. This // could result in deadlock at some point when "T2" goes to // release the mutex, only to find that it's handle is bad, // and thread "T3", which is waiting on the mutex (or a dup'd // handle) waits forever. (See corresponding critical // section in WaitForMutex.) // if (bDupedMutex) { CloseHandle (ptConfCall->hMutex); MyReleaseMutex (hMutex, bDupedMutex); } else { EnterCriticalSection (&gSafeMutexCritSec); ReleaseMutex (hMutex); CloseHandle (hMutex); LeaveCriticalSection (&gSafeMutexCritSec); } SetCallConfList (ptCall, NULL, FALSE); SetCallConfList (ptConsultCall, NULL, FALSE); 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->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = 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->dwParam3 = (DWORD) ptConfCallClient; pAsyncEventMsg->dwParam4 = (DWORD) lphConfCall; } void WINAPI LCompleteTransfer( PLINECOMPLETETRANSFER_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineCompleteTransfer; if ((lRequestID = LINEPROLOG( pParams->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 "CompleteTransfer" // func name )) > 0) { PTCALL ptConfCall = (PTCALL) NULL, ptCall, ptConsultCall; PTCALLCLIENT ptConfCallClient, ptCallClient = (PTCALLCLIENT) pParams->hCall, ptConsultCallClient; // // Validate the hConsultCall // if (!(ptConsultCallClient = IsValidCall( pParams->hConsultCall, pParams->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) || (((PTLINECLIENT) ptCallClient->ptLineClient)->ptLine != ((PTLINECLIENT)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, &pAsyncRequestInfo->dwParam5 )) == 0) { ptConfCall->pConfList = pConfList; pConfList->aptCalls[0] = ptConfCall; pAsyncRequestInfo->dwParam1 = (DWORD) ptConfCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphConfCall; pAsyncRequestInfo->dwParam3 = (DWORD) ptCall; pAsyncRequestInfo->dwParam4 = (DWORD) 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->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineCompleteTransfer, "lineCompleteTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) ptConsultCallClient->ptCall->hdCall, (DWORD) ptConfCall, (DWORD) (ptConfCall ? (DWORD) &ptConfCall->hdCall : 0), (DWORD) pParams->dwTransferMode ); if (ptConfCall) { SetDrvCallFlags( ptConfCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); } } LCompleteTransfer_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "CompleteTransfer" ); } void WINAPI LDeallocateCall( PLINEDEALLOCATECALL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; if ((pParams->lResult = LINEPROLOG( pParams->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 "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) pParams->hCall); /* try { PTCALL ptCall; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall; // BUG//BUG LDeallocateCall: race condition, may want to move this to DestroytCC ptCall = ptCallClient->ptCall; if (ptCall->dwNumOwners == 1 && ptCallClient->dwPrivilege == LINECALLPRIVILEGE_OWNER && ptCall->dwCallState != LINECALLSTATE_IDLE) { pParams->lResult = LINEERR_INVALCALLSTATE; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; } if (pParams->lResult == 0) { DestroytCallClient ((PTCALLCLIENT) pParams->hCall); } */ } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "DeallocateCall" ); } void LDevSpecific_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3; CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = pNewAsyncEventMsg; if (pAsyncEventMsg->dwParam2 == 0) // success { // // Make sure to keep the total size 64-bit aligned // pNewAsyncEventMsg->dwTotalSize += (pAsyncRequestInfo->dwParam2 + 7) & 0xfffffff8; pNewAsyncEventMsg->dwParam3 = pAsyncRequestInfo->dwParam1; // lpParams pNewAsyncEventMsg->dwParam4 = pAsyncRequestInfo->dwParam2; // dwSize } } void WINAPI LDevSpecific( PLINEDEVSPECIFIC_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwWidgetType, hWidget; HANDLE hMutex; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineDevSpecific; if (pParams->hCall) { dwWidgetType = ANY_RT_HCALL; hWidget = (DWORD) pParams->hCall; } else { dwWidgetType = ANY_RT_HLINE; hWidget = (DWORD) pParams->hLine; } if ((lRequestID = LINEPROLOG( pParams->ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle (LPVOID) &hWidget, // provider widget handle (pParams->hCall ? LINECALLPRIVILEGE_MONITOR : 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 "DevSpecific" // func name )) > 0) { DWORD hdLine, hdCall; LPBYTE pBuf; // // If an hCall was specified verify the hLine & // make sure the call is on the specified hLine // if (dwWidgetType == ANY_RT_HCALL) { LONG lResult; try { PTLINECLIENT ptLineClient; ptLineClient = (PTLINECLIENT) pParams->hLine; lResult = LINEERR_INVALLINEHANDLE; if (IsBadPtrKey (ptLineClient, TLINECLIENT_KEY) || (ptLineClient->ptClient != pParams->ptClient)) { lRequestID = LINEERR_INVALLINEHANDLE; goto LDevSpecific_epilog; } hdLine = (DWORD) ptLineClient->ptLine; lResult = LINEERR_INVALCALLHANDLE; if (ptLineClient != (PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient) { DBGOUT(( 1, "LDevSpecific: error, hCall=x%x not related " \ "to hLine=x%x", pParams->hCall, ptLineClient )); lRequestID = LINEERR_INVALCALLHANDLE; goto LDevSpecific_epilog; } } myexcept { lRequestID = lResult; goto LDevSpecific_epilog; } hdCall = hWidget; } else { hdLine = hWidget; 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 = (DWORD) pParams->lpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (DWORD) pBuf; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineDevSpecific, "lineDevSpecific", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) hdCall, (DWORD) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); } LDevSpecific_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "DevSpecific" ); } void WINAPI LDevSpecificFeature( PLINEDEVSPECIFICFEATURE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineDevSpecificFeature; if ((lRequestID = LINEPROLOG( pParams->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 "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 = (DWORD) pParams->lpParams; pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize; pAsyncRequestInfo->dwParam3 = (DWORD) pBuf; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineDevSpecificFeature, "lineDevSpecificFeature", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwFeature, (DWORD) (pParams->dwParamsSize ? pBuf + sizeof (ASYNCEVENTMSG) : NULL), (DWORD) pParams->dwParamsSize ); } LDevSpecificFeature_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "DevSpecificFeature" ); } void WINAPI LDial( PLINEDIAL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineDial; if ((lRequestID = LINEPROLOG( pParams->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 "Dial" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineDial, "lineDial", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) pDataBuf + pParams->dwDestAddressOffset, pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Dial" ); } void WINAPI LDrop( PLINEDROP_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineDrop; if ((lRequestID = LINEPROLOG( pParams->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 "Drop" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineDrop, "lineDrop", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (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, "Drop" ); } void WINAPI LForward( PLINEFORWARD_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineForward; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "Forward" // func name )) > 0) { LONG lResult; DWORD dwAPIVersion, dwSPIVersion; PTCALL ptConsultCall; PTCALLCLIENT ptConsultCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; LPLINEFORWARDLIST pFwdList = (LPLINEFORWARDLIST) (pParams->dwForwardListOffset == TAPI_NO_DATA ? NULL :pDataBuf + pParams->dwForwardListOffset), pTmpFwdList = NULL; // // Validate the params // try { dwAPIVersion = ((PTLINECLIENT) pParams->hLine)->dwAPIVersion; dwSPIVersion = ((PTLINECLIENT) pParams->hLine)->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_INVALLINEHANDLE; goto LForward_epilog; } if (pFwdList) { DWORD dwTotalSize = pFwdList->dwTotalSize, dwFixedSize, dwNumEntries, i, dwInvalidForwardModes; LPLINEFORWARD pFwdEntry = pFwdList->ForwardList; if (dwTotalSize < sizeof (LINEFORWARDLIST)) { 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 = sizeof (LINEFORWARDLIST) + sizeof (LINEFORWARD) * (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++, pFwdEntry++) { if (!IsOnlyOneBitSetInDWORD (pFwdEntry->dwForwardMode) || pFwdEntry->dwForwardMode & dwInvalidForwardModes) { DBGOUT(( 3, "LFoward: bad dwForwardMode, x%x", pFwdEntry->dwForwardMode )); lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } if (ISBADSIZEOFFSET( dwTotalSize, dwFixedSize, pFwdEntry->dwCallerAddressSize, pFwdEntry->dwCallerAddressOffset, "LFoward", "CallerAddress" ) || ISBADSIZEOFFSET( dwTotalSize, dwFixedSize, pFwdEntry->dwDestAddressSize, pFwdEntry->dwDestAddressOffset, "LFoward", "CallerAddress" )) { lRequestID = LINEERR_INVALPARAM; goto LForward_epilog; } // don't bother validating country code right now } // // 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 = sizeof (LINEFORWARDLIST) + (dwNumEntries - 1) * sizeof (LINEFORWARD); pFwdEntry = pTmpFwdList->ForwardList; CopyMemory (pTmpFwdList, pFwdList, dwXxxOffset); pTmpFwdList->dwTotalSize *= sizeof (WCHAR); for (i = 0; i < dwNumEntries; i++, pFwdEntry++) { if (pFwdEntry->dwCallerAddressSize) { MultiByteToWideChar( pParams->dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pFwdList) + pFwdEntry->dwCallerAddressOffset), pFwdEntry->dwCallerAddressSize, (LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset), pFwdEntry->dwCallerAddressSize * sizeof (WCHAR) ); pFwdEntry->dwCallerAddressOffset = dwXxxOffset; dwXxxOffset += (pFwdEntry->dwCallerAddressSize *= sizeof (WCHAR)); } if (pFwdEntry->dwDestAddressSize) { MultiByteToWideChar( pParams->dwAsciiCallParamsCodePage, MB_PRECOMPOSED, (LPCSTR) (((LPBYTE) pFwdList) + pFwdEntry->dwDestAddressOffset), pFwdEntry->dwDestAddressSize, (LPWSTR) (((LPBYTE) pTmpFwdList) + dwXxxOffset), pFwdEntry->dwDestAddressSize * sizeof (WCHAR) ); pFwdEntry->dwDestAddressOffset = dwXxxOffset; dwXxxOffset += (pFwdEntry->dwDestAddressSize *= sizeof (WCHAR)); } } pFwdList = pTmpFwdList; } } 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_freeFwdList; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( (PTLINECLIENT) pParams->hLine, &ptConsultCall, &ptConsultCallClient, pCallParamsSP, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LForward_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptConsultCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphConsultCall; pAsyncRequestInfo->dwParam3 = 1; // special case for post-process proc pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP9( pfnTSPI_lineForward, "lineForward", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->bAllAddresses, (DWORD) pParams->dwAddressID, (DWORD) pFwdList, (DWORD) pParams->dwNumRingsNoAnswer, (DWORD) ptConsultCall, (DWORD) &ptConsultCall->hdCall, (DWORD) pCallParamsSP ); SetDrvCallFlags( ptConsultCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); LForward_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } LForward_freeFwdList: if (pTmpFwdList) { ServerFree (pTmpFwdList); } } LForward_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Forward" ); } void WINAPI LGatherDigits( PLINEGATHERDIGITS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGatherDigits; if ((pParams->lResult = LINEPROLOG( pParams->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 "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->lpsDigits) { // // 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 = (PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient; pAsyncRequestInfo->dwKey = TASYNC_KEY; pAsyncRequestInfo->ptClient = pParams->ptClient; pAsyncRequestInfo->pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; pAsyncRequestInfo->dwCallbackInst = ptLineClient->dwCallbackInstance; pAsyncRequestInfo->dwParam1 = sizeof (ASYNCREQUESTINFO); pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lpsDigits; pAsyncRequestInfo->dwParam3 = (DWORD) pParams->dwNumDigits; pAsyncRequestInfo->dwParam4 = (DWORD) pParams->hCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; } 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, (DWORD) hdCall, (DWORD) pAsyncRequestInfo, (DWORD) dwDigitModes, (DWORD) lpsDigits, (DWORD) pParams->dwNumDigits, (pParams->dwTerminationDigitsOffset == TAPI_NO_DATA ? 0 : (DWORD) (pDataBuf + pParams->dwTerminationDigitsOffset)), (DWORD) pParams->dwFirstDigitTimeout, (DWORD) pParams->dwInterDigitTimeout )) != 0) { if (pAsyncRequestInfo) { ServerFree (pAsyncRequestInfo); } } } LGatherDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GatherDigits" ); } void WINAPI LGenerateDigits( PLINEGENERATEDIGITS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGenerateDigits; if ((pParams->lResult = LINEPROLOG( pParams->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 "GenerateDigits" // func name )) == 0) { DWORD dwDigitMode = pParams->dwDigitMode, *pInstData; if (dwDigitMode != LINEDIGITMODE_PULSE && dwDigitMode != LINEDIGITMODE_DTMF) { pParams->lResult = LINEERR_INVALDIGITMODE; goto LGenerateDigits_epilog; } if (pParams->dwDigitsOffset != TAPI_NO_DATA) { if (!(pInstData = ServerAlloc (2 * sizeof (DWORD)))) { pParams->lResult = LINEERR_NOMEM; goto LGenerateDigits_epilog; } pInstData[0] = (DWORD) pParams->hCall; pInstData[1] = pParams->dwEndToEndID; } else { pInstData = NULL; } pParams->lResult = CallSP5( pfnTSPI_lineGenerateDigits, "lineGenerateDigits", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) pInstData, // used as dwEndToEndID (DWORD) dwDigitMode, (DWORD) (pParams->dwDigitsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDigitsOffset), (DWORD) pParams->dwDuration ); if (pParams->lResult != 0 && pInstData != NULL) { ServerFree (pInstData); } } LGenerateDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GenerateDigits" ); } void WINAPI LGenerateTone( PLINEGENERATETONE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGenerateTone; if ((pParams->lResult = LINEPROLOG( pParams->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 "GenerateTone" // func name )) == 0) { DWORD dwToneMode = pParams->dwToneMode, *pInstData; if (dwToneMode != 0) { if (!(dwToneMode & AllToneModes) || !IsOnlyOneBitSetInDWORD (dwToneMode)) { pParams->lResult = LINEERR_INVALTONEMODE; goto LGenerateTone_epilog; } else if (!(pInstData = ServerAlloc (2 * sizeof (DWORD)))) { pParams->lResult = LINEERR_NOMEM; goto LGenerateTone_epilog; } pInstData[0] = (DWORD) pParams->hCall; pInstData[1] = pParams->dwEndToEndID; } else { pInstData = NULL; } pParams->lResult = CallSP6( pfnTSPI_lineGenerateTone, "lineGenerateTone", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) pInstData, // used as dwEndToEndID (DWORD) pParams->dwToneMode, (DWORD) pParams->dwDuration, (DWORD) pParams->dwNumTones, (DWORD) pDataBuf + pParams->dwTonesOffset ); if (pParams->lResult != 0 && pInstData) { ServerFree (pInstData); } } LGenerateTone_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GenerateTone" ); } void WINAPI LGetAddressCaps( PLINEGETADDRESSCAPS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetAddressCaps; if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle NULL, // provider widget handle 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 "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 = (GetLineLookupEntry (dwDeviceID))->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->u.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, (DWORD) 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; // // 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))) { // BUGBUG?? LGetAddrssCaps: compare w/ orig src pAddrCaps->dwForwardModes &= ~(LINEFORWARDMODE_UNKNOWN | LINEFORWARDMODE_UNAVAIL); pAddrCaps->dwForwardModes |= 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 (pAddrCaps == pAddrCaps2) { pAddrCaps = (LPLINEADDRESSCAPS) pDataBuf; CopyMemory (pAddrCaps, pAddrCaps2, dwFixedSizeClient); ServerFree (pAddrCaps2); pAddrCaps->dwTotalSize = pParams->u.dwAddressCapsTotalSize; pAddrCaps->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->u.dwAddressCapsOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAddrCaps->dwUsedSize; } } LGetAddressCaps_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetAddressCaps" ); } void WINAPI LGetAddressID( PLINEGETADDRESSID_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetAddressID; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetAddressID" // func name )) == 0) { if (pParams->dwAddressMode == LINEADDRESSMODE_DIALABLEADDR) { pParams->lResult = CallSP5( pfnTSPI_lineGetAddressID, "lineGetAddressID", SP_FUNC_SYNC, (DWORD) hdLine, (DWORD) &pParams->dwAddressID, (DWORD) pParams->dwAddressMode, (DWORD) pDataBuf + pParams->dwAddressOffset, (DWORD) pParams->dwSize ); *pdwNumBytesReturned = sizeof (LINEGETADDRESSID_PARAMS); } else { pParams->lResult = LINEERR_INVALADDRESSMODE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetAddressID" ); } void WINAPI LGetAddressStatus( PLINEGETADDRESSSTATUS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetAddressStatus; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetAddressStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; LPLINEADDRESSSTATUS pAddrStatus = (LPLINEADDRESSSTATUS) pDataBuf, pAddrStatus2 = (LPLINEADDRESSSTATUS) NULL; // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwAPIVersion = ptLineClient->dwAPIVersion; dwTotalSize = pParams->u.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 // dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; 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, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) 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->u.dwAddressStatusTotalSize; pAddrStatus->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->u.dwAddressStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAddrStatus->dwUsedSize; } } LGetAddressStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetAddressStatus" ); } void LGetAgentXxx_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG) pAsyncRequestInfo->dwParam3; CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); *ppBuf = pNewAsyncEventMsg; if (pAsyncEventMsg->dwParam2 == 0) // success { LPLINEAGENTACTIVITYLIST pActivityList = (LPLINEAGENTACTIVITYLIST) pNewAsyncEventMsg + 1; pNewAsyncEventMsg->dwTotalSize += pActivityList->dwUsedSize; pNewAsyncEventMsg->dwParam3 = pAsyncRequestInfo->dwParam1; } } #if DBG void PASCAL LGetAgentXxx( PLINEGETAGENTACTIVITYLIST_PARAMS pParams, DWORD dwRequestType, DWORD dwSPIOrdinal, DWORD dwFixedStructSize, char *pszFuncName ) #else void PASCAL LGetAgentXxx( PLINEGETAGENTACTIVITYLIST_PARAMS pParams, 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; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 pszFuncName // func name )) > 0) { DWORD dwTotalSize = pParams->dwActivityListTotalSize; PTLINE ptLine; PTLINECLIENT pProxy; if (dwTotalSize < dwFixedStructSize) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetAgentXxx_epilog; } try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; pProxy = ptLine->apProxys[dwRequestType]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LGetAgentXxx_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; goto LGetAgentXxx_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->lpAgentActivityList; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; // // 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; // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetAgentXxx_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (ptLine->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 + 8) & 0xfffffff7) ))) { lRequestID = LINEERR_NOMEM; goto LGetAgentXxx_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->dwParam3 = (DWORD) pBuf; pActivityList = (LPLINEAGENTACTIVITYLIST) (pBuf + sizeof (ASYNCEVENTMSG)); pActivityList->dwTotalSize = dwTotalSize; pParams->lResult = CallSP4( pRemoteSP->apfn[dwSPIOrdinal], pszFuncName, SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) 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, pszFuncName ); } void WINAPI LGetAgentActivityList( PLINEGETAGENTACTIVITYLIST_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( pParams, LINEPROXYREQUEST_GETAGENTACTIVITYLIST, SP_LINEGETAGENTACTIVITYLIST, sizeof (LINEAGENTACTIVITYLIST) #if DBG , "GetAgentActivityList" #endif ); } void WINAPI LGetAgentCaps( PLINEGETAGENTCAPS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle NULL, // provider widget handle dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "GetAgentCaps" // func name )) > 0) { DWORD dwTotalSize = pParams->dwAgentCapsTotalSize; PTLINE ptLine; PTLINECLIENT pProxy; PTLINELOOKUPENTRY pLookupEntry = GetLineLookupEntry (dwDeviceID); if (dwTotalSize < sizeof (LINEAGENTCAPS)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LGetAgentCaps_epilog; } if (pParams->dwAppAPIVersion != TAPI_VERSION2_0) { lRequestID = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetAgentCaps_epilog; } try { if (!(ptLine = pLookupEntry->ptLine)) { lRequestID = LINEERR_OPERATIONUNAVAIL; goto LGetAgentCaps_epilog; } pProxy = ptLine->apProxys[LINEPROXYREQUEST_GETAGENTCAPS]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LGetAgentCaps_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; goto LGetAgentCaps_epilog; } // // Save the client's buf ptr & post processing proc ptr // pAsyncRequestInfo->dwParam1 = pParams->lpAgentCaps; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; // // 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_GETAGENTCAPS, 2 * sizeof (DWORD), pAsyncRequestInfo, &pProxyRequestWrapper ))) { lRequestID = lResult; goto LGetAgentCaps_epilog; } pProxyRequestWrapper->ProxyRequest.GetAgentCaps.dwAddressID = pParams->dwAddressID; pProxyRequestWrapper->ProxyRequest.GetAgentCaps. AgentCaps.dwTotalSize = dwTotalSize; // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LGetAgentCaps_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if (pLookupEntry->bRemote) { LPBYTE pBuf; LPLINEAGENTCAPS pCaps; // // 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 + 8) & 0xfffffff7) ))) { lRequestID = LINEERR_NOMEM; goto LGetAgentCaps_epilog; } pAsyncRequestInfo->pfnPostProcess = LGetAgentXxx_PostProcess; pAsyncRequestInfo->dwParam2 = dwTotalSize; pAsyncRequestInfo->dwParam3 = (DWORD) 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, (DWORD) dwDeviceID, (DWORD) pParams->dwAddressID, (DWORD) pParams->dwAppAPIVersion, (DWORD) pCaps ); } // // There's no registered proxy & line is not remote, so fail // else { lRequestID = LINEERR_OPERATIONUNAVAIL; } } LGetAgentCaps_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "GetAgentCaps" ); } void WINAPI LGetAgentGroupList( PLINEGETAGENTGROUPLIST_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( (PLINEGETAGENTACTIVITYLIST_PARAMS) pParams, LINEPROXYREQUEST_GETAGENTGROUPLIST, SP_LINEGETAGENTGROUPLIST, sizeof (LINEAGENTGROUPLIST) #if DBG , "GetAgentGroupList" #endif ); } void WINAPI LGetAgentStatus( PLINEGETAGENTSTATUS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LGetAgentXxx( (PLINEGETAGENTACTIVITYLIST_PARAMS) pParams, LINEPROXYREQUEST_GETAGENTSTATUS, SP_LINEGETAGENTSTATUS, sizeof (LINEAGENTSTATUS) #if DBG , "GetAgentStatus" #endif ); } void WINAPI LGetAppPriority( PLINEGETAPPPRIORITY_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwMediaMode = pParams->dwMediaMode, dwRequestMode = pParams->dwRequestMode; // BUGBUG LGetAppPriority: ext mm's if (dwMediaMode == 0) { if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) && (dwRequestMode != LINEREQUESTMODE_MEDIACALL)) { pParams->lResult = LINEERR_INVALREQUESTMODE; goto LGetAppPriority_return; } } else if (IsOnlyOneBitSetInDWORD (dwMediaMode)) { if (dwMediaMode & 0xff000000) { } else if (dwMediaMode & ~AllMediaModes1_4) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LGetAppPriority_return; } } else { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LGetAppPriority_return; } if ((dwMediaMode & 0x00ffffff) || (dwMediaMode == 0)) { WCHAR szModuleName[MAX_PATH]; WCHAR *pszCurrentPriorityList; WCHAR *pszLocationInPriorityList; szModuleName[0] = '"'; lstrcpyW(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset)); CharUpperW (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) { DWORD dwMaskBit, dwPriorityListIndex; for( dwPriorityListIndex = 0, dwMaskBit = 1; dwMaskBit != pParams->dwMediaMode; dwPriorityListIndex++, dwMaskBit <<= 1 ); pszCurrentPriorityList = TapiGlobals.apszPriorityList[dwPriorityListIndex]; } 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: DBGOUT(( 3, "LineEpilogSync (lineGetAppPriority) exit, returning x%x", pParams->lResult )); } void WINAPI LGetCallAddressID( PLINEGETCALLADDRESSID_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGetCallAddressID; if ((pParams->lResult = LINEPROLOG( pParams->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_LINEGETCALLADDRESSID, // provider func index &pfnTSPI_lineGetCallAddressID, // provider func pointer NULL, // async request info 0, // client async request ID "GetCallAddressID" // func name )) == 0) { if ((pParams->lResult = CallSP2( pfnTSPI_lineGetCallAddressID, "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) &pParams->dwAddressID )) == 0) { *pdwNumBytesReturned = sizeof (LINEGETCALLADDRESSID_PARAMS); } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetCallAddressID" ); } void WINAPI LGetCallInfo( PLINEGETCALLINFO_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGetCallInfo; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetCallInfo" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall; PTCALL ptCall = ptCallClient->ptCall; LPLINECALLINFO pCallInfo = (LPLINECALLINFO) pDataBuf, pCallInfo2 = (LPLINECALLINFO) NULL; // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwAPIVersion = ((PTLINECLIENT) ptCallClient->ptLineClient)->dwAPIVersion; dwTotalSize = pParams->u.dwCallInfoTotalSize; switch (dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: dwFixedSizeClient = 296; // 69 * 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 // 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; 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, (DWORD) hdCall, (DWORD) pCallInfo )) == 0) { // // Safely add the fields we're responsible for // try { pCallInfo->hLine = (HLINE) ptCallClient->ptLineClient; pCallInfo->dwMonitorDigitModes = ptCallClient->dwMonitorDigitModes; pCallInfo->dwMonitorMediaModes = ptCallClient->dwMonitorMediaModes; // BUGBUG LGetCallInfo: app name 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 ); } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; } pCallInfo->dwCallStates |= LINECALLSTATE_UNKNOWN; // // 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->u.dwCallInfoTotalSize; pCallInfo->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // if (pParams->lResult == 0) { pParams->u.dwCallInfoOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallInfo->dwUsedSize; } } } LGetCallInfo_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetCallInfo" ); } void WINAPI LGetCallStatus( PLINEGETCALLSTATUS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineGetCallStatus; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetCallStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall; LPLINECALLSTATUS pCallStatus = (LPLINECALLSTATUS) pDataBuf, pCallStatus2 = (LPLINECALLSTATUS) NULL; // // Determine the fixed siize of the structure for the specified API // version, verify client's buffer is big enough // dwAPIVersion = ((PTLINECLIENT) ptCallClient->ptLineClient)->dwAPIVersion; dwTotalSize = pParams->u.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 // dwSPIVersion = ((PTLINE) ptCallClient->ptCall->ptLine)->dwSPIVersion; 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, (DWORD) hdCall, (DWORD) pCallStatus )) == 0) { #if DBG // // Verify the info returned by the provider // #endif // // Add the fields we're responsible for // pCallStatus->dwCallPrivilege = ((PTCALLCLIENT) pParams->hCall)->dwPrivilege; // BUGBUG LGetCallStatus: fill in pCallStatus->tStateEntrytTime? // // 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->u.dwCallStatusTotalSize; pCallStatus->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->u.dwCallStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallStatus->dwUsedSize; } } LGetCallStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetCallStatus" ); } void WINAPI LGetConfRelatedCalls( PLINEGETCONFRELATEDCALLS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwTotalSize = pParams->u.dwCallListTotalSize; PTCALLCLIENT ptCallClient; PTLINECLIENT ptLineClient; LPLINECALLLIST pCallList = (LPLINECALLLIST) pDataBuf; TPOINTERLIST confCallList, *pConfCallList = &confCallList; PTCONFERENCELIST pConfList; if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; return; } if (dwTotalSize < sizeof (LINECALLLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; return; } if (!(ptCallClient = IsValidCall (pParams->hCall, pParams->ptClient))) { pParams->lResult = LINEERR_INVALCALLHANDLE; return; } try { ptLineClient = (PTLINECLIENT) ptCallClient->ptLineClient; if (!(pConfList = (PTCONFERENCELIST) ptCallClient->ptCall->pConfList)) { pParams->lResult = LINEERR_NOCONFERENCE; return; } } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; return; } if ((pParams->lResult = GetConfCallListFromConf( pConfList, &pConfCallList )) != 0) { return; } { DWORD dwNeededSize = sizeof (LINECALLLIST) + pConfCallList->dwNumUsedEntries * sizeof(DWORD); 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++) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptCall = pConfCallList->aEntries[i]; if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bDupedMutex, 5 )) { 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 ))) { // BUGBUG LGetConfRelatedCalls: err creating tCallClient } } *(lphCallsInList++) = (HCALL) ptCallClient; dwNumCallsInList++; MyReleaseMutex (hMutex, bDupedMutex); } } 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->u.dwCallListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCallList->dwUsedSize; #if DBG { char szResult[32]; DBGOUT(( 3, "lineGetConfRelatedCalls: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif } void WINAPI LGetCountry( PLINEGETCOUNTRY_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LPLINECOUNTRYLIST pCountryList = (LPLINECOUNTRYLIST) pDataBuf; BuildCountryList(); if (pParams->u.dwCountryListTotalSize < sizeof (LINECOUNTRYLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; } else if (pParams->dwCountryID == 0) { // // Client wants entire country list // if (pParams->u.dwCountryListTotalSize >= gpCountryList->dwNeededSize) { CopyMemory( pCountryList, gpCountryList, gpCountryList->dwUsedSize ); } else { pCountryList->dwNeededSize = gpCountryList->dwNeededSize; pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST); pCountryList->dwNumCountries = 0; pCountryList->dwCountryListSize = 0; pCountryList->dwCountryListOffset = 0; } *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCountryList->dwUsedSize; pCountryList->dwTotalSize = pParams->u.dwCountryListTotalSize; } 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)) ) ) ) { DBGOUT((1, "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 ) { DBGOUT((1, "Invalid Countrycode (%ld) in lineGetCountry", pParams->dwCountryID)); pParams->lResult = LINEERR_INVALCOUNTRYCODE; } else { PBYTE pCountryListToUse; PBYTE pVarOffset; PBYTE pOverrideList = NULL; DWORD dwNeededSize; // // Is the caller calling a specific country that there might be // an override for? // if ( pParams->dwDestCountryID != 0 ) { HKEY hKey; HKEY hKey2; PSTR p; p = ServerAlloc( 256 ); wsprintf( p, "Country List\\%ld\\Exceptions\\%ld", pParams->dwCountryID, pParams->dwDestCountryID ); RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey2 ); // // Is there an exception? // if ( 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)) ); 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); ServerFree( p ); } else { pCountryListToUse = (PBYTE)gpCountryList; } // // Fill in the buffer // dwNeededSize = sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY); pVarOffset = (LPBYTE)pCountryEntryDest + sizeof(LINECOUNTRYENTRY); CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwCountryNameOffset, pCountryEntrySource->dwCountryNameSize ); pCountryEntryDest->dwCountryNameSize = pCountryEntrySource->dwCountryNameSize; pCountryEntryDest->dwCountryNameOffset = pVarOffset - (LPBYTE)pBuildCountryList; pVarOffset += pCountryEntrySource->dwCountryNameSize; dwNeededSize += pCountryEntrySource->dwCountryNameSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwSameAreaRuleOffset, pCountryEntrySource->dwSameAreaRuleSize ); pCountryEntryDest->dwSameAreaRuleSize = pCountryEntrySource->dwSameAreaRuleSize; pCountryEntryDest->dwSameAreaRuleOffset = pVarOffset - (LPBYTE)pBuildCountryList; pVarOffset += pCountryEntrySource->dwSameAreaRuleSize; dwNeededSize += pCountryEntrySource->dwSameAreaRuleSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwLongDistanceRuleOffset, pCountryEntrySource->dwLongDistanceRuleSize ); pCountryEntryDest->dwLongDistanceRuleSize = pCountryEntrySource->dwLongDistanceRuleSize; pCountryEntryDest->dwLongDistanceRuleOffset = pVarOffset - (LPBYTE)pBuildCountryList; pVarOffset += pCountryEntrySource->dwLongDistanceRuleSize; dwNeededSize += pCountryEntrySource->dwLongDistanceRuleSize; CopyMemory( pVarOffset, pCountryListToUse + pCountryEntrySource->dwInternationalRuleOffset, pCountryEntrySource->dwInternationalRuleSize ); pCountryEntryDest->dwInternationalRuleSize = pCountryEntrySource->dwInternationalRuleSize; pCountryEntryDest->dwInternationalRuleOffset = pVarOffset - (LPBYTE)pBuildCountryList; pVarOffset += pCountryEntrySource->dwInternationalRuleSize; dwNeededSize += pCountryEntrySource->dwInternationalRuleSize; // // Is there room to put this country's info? // if (pParams->u.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->u.dwCountryListTotalSize; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCountryList->dwUsedSize; // // Did we have a "special" case? // if ( pOverrideList ) { ServerFree( pOverrideList ); } } ServerFree( pBuildCountryList ); } } /* WCHAR szCountryInfo[256], *p; DWORD dwNeededSize; LPLINECOUNTRYLIST pCountryList; if (LoadStringW( GetModuleHandle (NULL), RC_COUNTRY_ID_BASE + pParams->dwCountryID, szCountryInfo, 256 ) == 0) { DBGOUT(( 3, "LGetCountry: LoadString failed, err=%ld", GetLastError() )); pParams->lResult = LINEERR_INVALCOUNTRYCODE; return; } // // Note: 7 = 3 (commas) + 8 (dblquotes) - 4 (NULL terminators) // dwNeededSize = sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY); p = wcschr(szCountryInfo, '\"'); dwNeededSize += ((wcslen (p) - 7)*sizeof(WCHAR)); pCountryList = (LPLINECOUNTRYLIST) pDataBuf; if (pParams->u.dwCountryListTotalSize >= dwNeededSize) { // // Fill in the buffer // DWORD i, dwVarDataOffset = sizeof(LINECOUNTRYLIST) + sizeof(LINECOUNTRYENTRY); LPDWORD pdwXxxSize; LPLINECOUNTRYENTRY pCountryEntry = (LPLINECOUNTRYENTRY) (((LPBYTE)pCountryList) + sizeof(LINECOUNTRYLIST)); pCountryList->dwUsedSize = dwNeededSize; pCountryList->dwNumCountries = 1; pCountryList->dwCountryListSize = sizeof(LINECOUNTRYENTRY); pCountryList->dwCountryListOffset = sizeof(LINECOUNTRYLIST); pCountryEntry->dwCountryID = pParams->dwCountryID; pCountryEntry->dwCountryCode = (DWORD) _wtoi (szCountryInfo); p = wcschr(szCountryInfo, ','); p++; pCountryEntry->dwNextCountryID = (DWORD) _wtoi (p); p = wcschr(szCountryInfo, '\"'); p++; // // Initialize all the country entry string fields // pdwXxxSize = &pCountryEntry->dwCountryNameSize; for (i = 0; i < 4; i++) { WCHAR *p2 = wcschr(p, '\"'); *p2 = 0; *pdwXxxSize = (wcslen (p) + 1) * sizeof(WCHAR); *(pdwXxxSize + 1) = dwVarDataOffset; wcscpy((PWSTR)(((LPBYTE)pCountryList) + dwVarDataOffset), p); dwVarDataOffset += *pdwXxxSize; p = p2 + 3; // "," pdwXxxSize++; pdwXxxSize++; } } else { // // Buffer not large enough // pCountryList->dwUsedSize = sizeof(LINECOUNTRYLIST); pCountryList->dwNumCountries = pCountryList->dwCountryListSize = pCountryList->dwCountryListOffset = 0; } pCountryList->dwNeededSize = dwNeededSize; pCountryList->dwTotalSize = pParams->u.dwCountryListTotalSize; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCountryList->dwUsedSize; } */ pParams->u.dwCountryListOffset = 0; #if DBG { char szResult[32]; DBGOUT(( 3, "lineGetCountry: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif } void WINAPI LGetDevCaps( PLINEGETDEVCAPS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetDevCaps; if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle NULL, // provider widget handle 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 "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 = (GetLineLookupEntry (dwDeviceID))->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->u.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; 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; 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 ((pParams->lResult = CallSP4( pfnTSPI_lineGetDevCaps, "lineGetDevCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pParams->dwExtVersion, (DWORD) 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; // // 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 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->u.dwDevCapsTotalSize; pDevCaps->dwUsedSize = dwFixedSizeClient; } // // Indicate the offset & how many bytes of data we're passing back // pParams->u.dwDevCapsOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDevCaps->dwUsedSize; } } LGetDevCaps_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetDevCaps" ); } void WINAPI LGetDevConfig( PLINEGETDEVCONFIG_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetDevConfig; if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle NULL, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETDEVCONFIG, // provider func index &pfnTSPI_lineGetDevConfig, // provider func pointer NULL, // async request info 0, // client async request ID "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; } lstrcpyW( pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset) ); if (!InitTapiStruct( pConfig, pParams->u.dwDeviceConfigTotalSize, sizeof (VARSTRING), TRUE )) { ServerFree (pszDeviceClass); pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetDevConfig_epilog; } if ((pParams->lResult = CallSP3( pfnTSPI_lineGetDevConfig, "lineGetDevConfig", SP_FUNC_SYNC, (DWORD) pParams->dwDeviceID, (DWORD) pConfig, (DWORD) pszDeviceClass )) == 0) { // // Indicate how many bytes of data we're passing back // pParams->u.dwDeviceConfigOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pConfig->dwUsedSize; } ServerFree (pszDeviceClass); } LGetDevConfig_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetDevConfig" ); } void WINAPI LGetIcon( PLINEGETICON_PARAMS pParams, 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. // WCHAR *pszDeviceClass; BOOL bCloseMutex; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetIcon; pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDeviceClassOffset); if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle NULL, // provider widget handle pParams->dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished SP_LINEGETICON, // provider func index &pfnTSPI_lineGetIcon, // provider func pointer NULL, // async request info 0, // client async request ID "GetIcon" // func name )) == 0) { if ((pParams->lResult = CallSP3( pfnTSPI_lineGetIcon, "lineGetIcon", SP_FUNC_SYNC, pParams->dwDeviceID, (DWORD) pszDeviceClass, (DWORD) &pParams->hIcon )) == 0) { *pdwNumBytesReturned = sizeof (LINEGETICON_PARAMS); } } else if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { if ((pszDeviceClass == NULL) || (lstrcmpW(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, "GetIcon" ); } void WINAPI LGetID( PLINEGETID_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwWidgetType, hdWidget, dwPrivilege; HANDLE hWidget; HANDLE hMutex; TSPIPROC pfnTSPI_lineGetID; if (pParams->dwSelect == LINECALLSELECT_CALL) { dwWidgetType = ANY_RT_HCALL; hWidget = (HANDLE) pParams->hCall; dwPrivilege = LINECALLPRIVILEGE_MONITOR; } else { dwWidgetType = ANY_RT_HLINE; hWidget = (HANDLE) pParams->hLine; dwPrivilege = 0; } if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient dwWidgetType, // widget type (DWORD) 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 "GetID" // func name )) == 0 || pParams->lResult == LINEERR_OPERATIONUNAVAIL) { WCHAR *pszDeviceClass; LPVARSTRING pID = (LPVARSTRING) pDataBuf; if (!(pParams->dwSelect & AllCallSelect) || !IsOnlyOneBitSetInDWORD (pParams->dwSelect)) { pParams->lResult = LINEERR_INVALCALLSELECT; goto LGetID_epilog; } // // We'll handle the "tapi/line" class right here rather than // burden every single driver with having to support it // if (lstrcmpiW( (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset), L"tapi/line" ) == 0) { if (!InitTapiStruct( pID, pParams->u.dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetID_epilog; } pID->dwNeededSize += sizeof (DWORD); if (pID->dwTotalSize >= pID->dwNeededSize) { try { if (pParams->dwSelect == LINECALLSELECT_ADDRESS) { if (pParams->dwAddressID >= ((PTLINECLIENT) pParams->hLine)->ptLine->dwNumAddresses) { pParams->lResult = LINEERR_INVALADDRESSID; goto LGetID_epilog; } } *((LPDWORD)(pID + 1)) = (pParams->dwSelect == LINECALLSELECT_CALL ? ((PTLINE) ((PTCALLCLIENT) pParams->hCall)->ptCall ->ptLine)->dwDeviceID : ((PTLINECLIENT) pParams->hLine)->ptLine->dwDeviceID); } myexcept { pParams->lResult = (pParams->dwSelect == LINECALLSELECT_CALL ? LINEERR_INVALCALLHANDLE : LINEERR_INVALLINEHANDLE); 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->u.dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; goto LGetID_epilog; } else if (pParams->lResult == LINEERR_OPERATIONUNAVAIL) { goto LGetID_epilog; } // // 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 LGetID_epilog; } lstrcpyW( pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset) ); if (!InitTapiStruct( pID, pParams->u.dwDeviceIDTotalSize, sizeof (VARSTRING), TRUE )) { ServerFree (pszDeviceClass); pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetID_epilog; } if ((pParams->lResult = CallSP7( pfnTSPI_lineGetID, "lineGetID", SP_FUNC_SYNC, (dwWidgetType == ANY_RT_HCALL ? 0 : hdWidget), pParams->dwAddressID, (dwWidgetType == ANY_RT_HCALL ? hdWidget : 0), pParams->dwSelect, (DWORD) pID, (DWORD) pszDeviceClass, (DWORD) pParams->ptClient->hProcess )) == 0) { // // Indicate offset & how many bytes of data we're passing back // pParams->u.dwDeviceIDOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize; } ServerFree (pszDeviceClass); } LGetID_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetID" ); } void WINAPI LGetLineDevStatus( PLINEGETLINEDEVSTATUS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineGetLineDevStatus; if ((pParams->lResult = LINEPROLOG( pParams->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_LINEGETLINEDEVSTATUS, // provider func index &pfnTSPI_lineGetLineDevStatus, // provider func pointer NULL, // async request info 0, // client async request ID "GetLineDevStatus" // func name )) == 0) { DWORD dwAPIVersion, dwSPIVersion, dwTotalSize, dwFixedSizeClient, dwFixedSizeSP; PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; LPLINEDEVSTATUS pDevStatus = (LPLINEDEVSTATUS) pDataBuf, pDevStatus2 = (LPLINEDEVSTATUS) NULL; // // Determine the fixed size of the structure for the specified API // version, verify client's buffer is big enough // dwAPIVersion = ptLineClient->dwAPIVersion; dwTotalSize = pParams->u.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 // dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; 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, (DWORD) hdLine, (DWORD) pDevStatus )) == 0) { PTLINE ptLine; // // Add the fields we're responsible for // try { ptLine = ptLineClient->ptLine; pDevStatus->dwNumOpens = ptLine->dwNumOpens; pDevStatus->dwOpenMediaModes = ptLine->dwOpenMediaModes; } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; } 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 = ((PTCLIENT) ptLineClient->ptClient)-> dwComputerNameSize; d += ((PTCLIENT) ptLineClient->ptClient)-> dwUserNameSize; // don't include preceding '"' d += ((PTLINEAPP) ptLineClient->ptLineApp)-> dwModuleNameSize - sizeof (WCHAR); d += ((PTLINEAPP) 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 = (PTCLIENT) ptLineClient->ptClient; PTLINEAPP ptLineApp = (PTLINEAPP) ptLineClient->ptLineApp; pAppInfo->dwMachineNameOffset = d; if ((pAppInfo->dwMachineNameSize = ptClient->dwComputerNameSize)) { lstrcpyW( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptClient->pszComputerName ); d += pAppInfo->dwMachineNameSize; } pAppInfo->dwUserNameOffset = d; if ((pAppInfo->dwUserNameSize = ptClient->dwUserNameSize)) { lstrcpyW( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptClient->pszUserName ); d += pAppInfo->dwUserNameSize; } pAppInfo->dwModuleFilenameOffset = d; if ((pAppInfo->dwModuleFilenameSize = ptLineApp->dwModuleNameSize - sizeof (WCHAR))) { // don't include preceding '"' lstrcpyW( (LPWSTR) (((LPBYTE) pDevStatus) + d), &ptLineApp->pszModuleName[1] ); d += pAppInfo->dwModuleFilenameSize; } pAppInfo->dwFriendlyNameOffset = d; if ((pAppInfo->dwFriendlyNameSize = ptLineApp->dwFriendlyNameSize)) { lstrcpyW( (LPWSTR) (((LPBYTE) pDevStatus) + d), ptLineApp->pszFriendlyName ); 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->u.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->u.dwLineDevStatusOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDevStatus->dwUsedSize; } } LGetLineDevStatus_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetLineDevStatus" ); } void WINAPI LGetNewCalls( PLINEGETNEWCALLS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LONG lResult = 0; DWORD dwTotalSize = pParams->u.dwCallListTotalSize, dwAddressID, dwNumNewCalls, i, j, dwSelect = pParams->dwSelect; PTLINE ptLine; PTLINECLIENT ptLineClient; TPOINTERLIST callList, *pCallList = &callList; LPLINECALLLIST pAppCallList = (LPLINECALLLIST) pDataBuf; // // 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 = IsValidLine (pParams->hLine, pParams->ptClient))) { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_return; } // // Safely get the ptLine // try { ptLine = ptLineClient->ptLine; } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LGetNewCalls_return; } // // Get list of tCalls on the tLine // if ((lResult = GetCallListFromLine (ptLine, &pCallList)) != 0) { pParams->lResult = lResult; goto LGetNewCalls_return; } // // 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) { if ((lResult = CreatetCallClient( ptCall, ptLineClient, LINECALLPRIVILEGE_MONITOR, TRUE, TRUE, (PTCALLCLIENT *) (pCallList->aEntries + dwNumNewCalls), FALSE )) == 0) { dwNumNewCalls++; } else { } } if (pCallClientList != &callClientList) { ServerFree (pCallClientList); } } { DWORD dwCallsSize = dwNumNewCalls * sizeof (HCALL); CopyMemory (pAppCallList + 1, pCallList->aEntries, dwCallsSize); 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->u.dwCallListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pAppCallList->dwUsedSize; LGetNewCalls_return: #if DBG { char szResult[32]; DBGOUT(( 3, "lineGetNewCalls: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void WINAPI LGetNumAddressIDs( PLINEGETNUMADDRESSIDS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetNumAddressIDs" // func name )) == 0) { try { pParams->dwNumAddresses = ((PTLINECLIENT) pParams->hLine)->ptLine->dwNumAddresses; *pdwNumBytesReturned = sizeof (LINEGETNUMADDRESSIDS_PARAMS); } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetNumAddressIDs" ); } void WINAPI LGetNumRings( PLINEGETNUMRINGS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 "GetNumRings" // func name )) == 0) { DWORD i, dwNumRings = 0xffffffff, dwAddressID = pParams->dwAddressID; PTLINE ptLine; TPOINTERLIST lineClientList, *pLineClientList = &lineClientList; try { ptLine = ((PTLINECLIENT) pParams->hLine)->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 = (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, "GetNumRings" ); } void WINAPI LGetProviderList( PLINEGETPROVIDERLIST_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD iNumProviders, i; WCHAR *buf; DWORD dwFixedSizeClient, dwTotalSize, dwNeededSize; LPBYTE pVarData; LPLINEPROVIDERLIST pProviderList; LPLINEPROVIDERENTRY pProviderEntry; HKEY hKey; DWORD dwDataSize; DWORD dwDataType; switch (pParams->dwAPIVersion) { case TAPI_VERSION1_0: case TAPI_VERSION1_4: case TAPI_VERSION_CURRENT: dwFixedSizeClient = sizeof (LINEPROVIDERLIST); break; default: pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto LGetProviderList_epilog; } if ((dwTotalSize = pParams->u.dwProviderListTotalSize) < dwFixedSizeClient) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto LGetProviderList_epilog; } 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; buf = ServerAlloc (sizeof(WCHAR) * MAX_PATH); // enough for complete provider path for (i = 0; i < iNumProviders; i++) { WCHAR szProviderXxxN[32]; DWORD dwNameLen; wsprintfW(szProviderXxxN, L"%ls%d", gszProviderFilenameW, i); dwNameLen = MAX_PATH; RegQueryValueExW( hKey, szProviderXxxN, 0, &dwDataType, (LPBYTE)buf, &dwNameLen ); // buf[dwNameLen] = '\0'; dwNeededSize += dwNameLen; if (dwTotalSize >= dwNeededSize) { wsprintfW(szProviderXxxN, L"%ls%d", gszProviderIDW, i); dwDataSize = sizeof(pProviderEntry->dwPermanentProviderID); pProviderEntry->dwPermanentProviderID = 0; RegQueryValueExW( hKey, szProviderXxxN, 0, &dwDataType, (LPBYTE)&(pProviderEntry->dwPermanentProviderID), &dwDataSize ); pProviderEntry->dwProviderFilenameSize = dwNameLen; pProviderEntry->dwProviderFilenameOffset = pVarData - ((LPBYTE) pProviderList); CopyMemory (pVarData, buf, dwNameLen); pVarData += dwNameLen; pProviderEntry++; } } ServerFree (buf); 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->u.dwProviderListOffset = 0; *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pProviderList->dwUsedSize; RegCloseKey (hKey); LGetProviderList_epilog: #if DBG { char szResult[32]; DBGOUT(( 3, "lineGetProviderList: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void WINAPI LGetRequest( PLINEGETREQUEST_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; PTLINEAPP ptLineApp; PTREQUESTMAKECALL pRequestMakeCall; if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, pParams->ptClient, &hMutex, &bCloseMutex, INFINITE ))) { 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 (lstrcmpiW( ptLineApp->pszModuleName, TapiGlobals.pHighestPriorityRequestRecipient-> ptLineApp->pszModuleName ) == 0) { if ((pRequestMakeCall = TapiGlobals.pRequestMakeCallList)) { CopyMemory( pDataBuf, &pRequestMakeCall->LineReqMakeCall, sizeof (LINEREQMAKECALLW) ); 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: MyReleaseMutex (hMutex, bCloseMutex); } else { pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ? LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE); } LGetRequest_return: #if DBG { char szResult[32]; DBGOUT(( 3, "lineGetRequest: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void WINAPI LGetStatusMessages( PLINEGETSTATUSMESSAGES_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID "GetStatusMessages" // func name )) == 0) { PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; pParams->dwLineStates = ptLineClient->dwLineStates; pParams->dwAddressStates = ptLineClient->dwAddressStates; *pdwNumBytesReturned = sizeof (LINEGETSTATUSMESSAGES_PARAMS); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "GetStatusMessages" ); } void WINAPI LHandoff( PLINEHANDOFF_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TPOINTERLIST xxxClientList, *pXxxClientList = &xxxClientList; if ((pParams->lResult = LINEPROLOG( pParams->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 "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; PTCALLCLIENT ptCallClientApp; PTLINECLIENT ptLineClientApp, ptLineClientTarget, ptLineClientTmp; // // Safely retrieve all the object pointers needed below, then get // a list of line clients // try { ptCallClientApp = (PTCALLCLIENT) pParams->hCall; ptCall = ptCallClientApp->ptCall; ptLineClientApp = ptCallClientApp->ptLineClient; ptLine = ptLineClientApp->ptLine; dwAPIVersion = ptLineClientApp->dwAPIVersion; } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LHandoff_epilog; } if ((lResult = GetLineClientListFromLine (ptLine, &pXxxClientList))) { pParams->lResult = lResult; goto LHandoff_epilog; } // BUGBUG LHandoff: ext mm's 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) // CharUpperW(pszFileName); ptLineClientTarget = NULL; for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++) { ptLineClientTmp = (PTLINECLIENT) pXxxClientList->aEntries[i]; try { // // Recall that all app names start with '"' // DBGOUT((0, "Looking for [%ls] list entry [%ls]", pszFileName, ((PTLINEAPP) ptLineClientTmp->ptLineApp) ->pszModuleName )); if ((lstrcmpW( pszFileName, ((PTLINEAPP) 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) { // BUGBUG? LHandoff: directed handoff & target == self not an error? 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: default: //case TAPI_VERSION_CURRENT: dwValidMediaModes = AllMediaModes1_4; break; } if (!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 bDupedMutex, bCreatedtCallClient; HANDLE hMutex; PTCALLCLIENT ptCallClientTarget = NULL, ptCallClientTmp; for (i = 0; i < pXxxClientList->dwNumUsedEntries; i++) { ptCallClientTmp = (PTCALLCLIENT) pXxxClientList->aEntries[i]; try { if ((PTLINECLIENT) 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( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { 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 { dwCallInfoState = 0; } dwCallState = ptCall->dwCallState; dwCallStateMode = ptCall->dwCallStateMode; MyReleaseMutex (hMutex, bDupedMutex); if (dwCallInfoState || bCreatedtCallClient) { BOOL bIndicatePrivilege = TRUE; PTCLIENT ptClientTarget; ASYNCEVENTMSG msg; msg.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; if (bCreatedtCallClient) { try { if (ptLineClientTarget->dwAPIVersion >= TAPI_VERSION2_0) { msg.hDevice = (DWORD) ptLineClientTarget; msg.dwMsg = LINE_APPNEWCALL; msg.dwParam1 = ptCall->dwAddressID; msg.dwParam2 = (DWORD) ptCallClientTarget; msg.dwParam3 = LINECALLPRIVILEGE_OWNER; msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClientTarget->ptLineApp)-> lpfnCallback; msg.dwCallbackInst = ptLineClientTarget->dwCallbackInstance; ptClientTarget = (PTCLIENT) ptCallClientTarget->ptClient; if (ptCallClientTarget->dwKey == TCALLCLIENT_KEY) { bIndicatePrivilege = FALSE; WriteEventBuffer (ptClientTarget, &msg); } } } myexcept { } } msg.hDevice = (DWORD) ptCallClientTarget; msg.dwMsg = LINE_CALLSTATE; msg.dwParam1 = dwCallState; msg.dwParam2 = dwCallStateMode; msg.dwParam3 = (bIndicatePrivilege ? LINECALLPRIVILEGE_OWNER : 0); try { msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClientTarget->ptLineApp)->lpfnCallback; msg.dwCallbackInst = ptLineClientTarget->dwCallbackInstance; ptClientTarget = (PTCLIENT) ptCallClientTarget->ptClient; if (ptCallClientTarget->dwKey == TCALLCLIENT_KEY) { WriteEventBuffer (ptClientTarget, &msg); } } myexcept { } if (dwCallInfoState != 0) { LineEventProc( (HTAPILINE) ptLine, (HTAPICALL) ptCall, LINE_CALLINFO, dwCallInfoState, 0, 0 ); } } } } LHandoff_freeXxxClientList: if (pXxxClientList != &xxxClientList) { ServerFree (pXxxClientList); } } LHandoff_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "Handoff" ); } void WINAPI LHold( PLINEHOLD_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineHold; if ((lRequestID = LINEPROLOG( pParams->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_LINEHOLD, // provider func index &pfnTSPI_lineHold, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "Hold" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineHold, "lineHold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Hold" ); } void WINAPI LInitialize( PLINEINITIALIZE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwFriendlyNameSize, dwModuleNameSize; HANDLE hMutex; PTCLIENT ptClient = pParams->ptClient; PTLINEAPP ptLineApp; // PDWORD pdwCounter; // // 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 )) || !(ptLineApp->hMutex = MyCreateMutex())) { pParams->lResult = LINEERR_NOMEM; goto LInitialize_error1; } ptLineApp->dwKey = TLINEAPP_KEY; ptLineApp->ptClient = ptClient; ptLineApp->lpfnCallback = pParams->lpfnCallback; ptLineApp->dwAPIVersion = pParams->dwAPIVersion; ptLineApp->dwFriendlyNameSize = dwFriendlyNameSize; ptLineApp->pszFriendlyName = (WCHAR *) (ptLineApp + 1); lstrcpyW( 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] = '"'; lstrcpyW( &ptLineApp->pszModuleName[1], (WCHAR *)(pDataBuf + pParams->dwModuleNameOffset) ); CharUpperW (&ptLineApp->pszModuleName[1]); // // Safely insert new tLineApp at front of tClient's tLineApp list // if (WaitForExclusiveClientAccess( ptClient, &hMutex, &bCloseMutex, INFINITE )) { if ((ptLineApp->pNext = ptClient->ptLineApps)) { ptLineApp->pNext->pPrev = ptLineApp; } ptClient->ptLineApps = ptLineApp; MyReleaseMutex (hMutex, bCloseMutex); } else { pParams->lResult = LINEERR_OPERATIONFAILED; goto LInitialize_error1; } // // Check if global reinit flag set // if (TapiGlobals.bReinit) { pParams->lResult = LINEERR_REINIT; goto LInitialize_error2; } // // See if we need to go thru init // WaitForSingleObject (TapiGlobals.hMutex, INFINITE); if ((TapiGlobals.dwNumLineInits == 0) && (TapiGlobals.dwNumPhoneInits == 0)) { if ((pParams->lResult = ServerInit()) != 0) { ReleaseMutex (TapiGlobals.hMutex); goto LInitialize_error2; } } // // Fill in the return values // pParams->hLineApp = (HLINEAPP) ptLineApp; pParams->dwNumDevs = TapiGlobals.dwNumLines; // // Increment total num line inits // TapiGlobals.dwNumLineInits++; *pdwNumBytesReturned = sizeof (LINEINITIALIZE_PARAMS); ReleaseMutex (TapiGlobals.hMutex); goto LInitialize_return; LInitialize_error2: if (WaitForExclusiveClientAccess( ptClient, &hMutex, &bCloseMutex, INFINITE )) { if (ptLineApp->pNext) { ptLineApp->pNext->pPrev = ptLineApp->pPrev; } if (ptLineApp->pPrev) { ptLineApp->pPrev->pNext = ptLineApp->pNext; } else { ptClient->ptLineApps = ptLineApp->pNext; } MyReleaseMutex (hMutex, bCloseMutex); } LInitialize_error1: if (ptLineApp) { if (ptLineApp->hMutex) { CloseHandle (ptLineApp->hMutex); } ServerFree (ptLineApp); } LInitialize_return: #if DBG { char szResult[32]; DBGOUT(( 3, "lineInitialize: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void LMakeCall_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1; LPHCALL lphCall = (LPHCALL) pAsyncRequestInfo->dwParam2; PTCALLCLIENT ptCallClient; if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TINCOMPLETECALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwCallInstance = 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->dwCallInstance != dwCallInstance) { MyReleaseMutex (hMutex, bDupedMutex); goto LMakeCall_PostProcess_bad_ptCall; } ptCallClient = (PTCALLCLIENT) ptCall->ptCallClients; if (pAsyncEventMsg->dwParam2 == 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) { MyReleaseMutex (hMutex, bDupedMutex); ptCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = LINEERR_INVALLINEHANDLE; } goto LMakeCall_PostProcess_initMsgParams; } // // Find out which address the call is on // CallSP2( ptCall->ptProvider->apfn[SP_LINEGETCALLADDRESSID], "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) ptCall->hdCall, (DWORD) (&ptCall->dwAddressID) ); // // Mark the calls as valid, the release the mutex. // ptCall->dwKey = TCALL_KEY; ptCallClient->dwKey = TCALLCLIENT_KEY; MyReleaseMutex (hMutex, bDupedMutex); // // Create monitor tCallClients // CreateCallMonitors (ptCall); } else // error { LMakeCall_PostProcess_cleanupCalls: RemoveCallFromLineList (ptCall); ptCall->dwKey = INVAL_KEY; // // Check to see if another thread already destroyed the // tCallClient (due to a lineClose/Shutdown) before trying // to reference a freed object // if (ptCall->ptCallClients) { RemoveCallClientFromLineClientList (ptCallClient); ptCallClient->dwKey = INVAL_KEY; ServerFree (ptCallClient); } // // If we have a duped mutex handle (bDupedMutex == TRUE) // then we can safely go ahead and close the ptCall->hMutex // since no other thread will be waiting on it (thanks to // the first WaitForSingleObject in WaitForMutex). Also // release & close the duped handle. // // Otherwise, we have the actual ptCall->hMutex, and we // wrap the release & close in a critical section to // prevent another thread "T2" from grabbing ptCall->hMutex // right after we release but right before we close. This // could result in deadlock at some point when "T2" goes to // release the mutex, only to find that it's handle is bad, // and thread "T3", which is waiting on the mutex (or a dup'd // handle) waits forever. (See corresponding critical // section in WaitForMutex.) // if (bDupedMutex) { CloseHandle (ptCall->hMutex); MyReleaseMutex (hMutex, bDupedMutex); } else { EnterCriticalSection (&gSafeMutexCritSec); ReleaseMutex (hMutex); CloseHandle (hMutex); LeaveCriticalSection (&gSafeMutexCritSec); } 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->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = 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->dwParam3 = (DWORD) ptCallClient; pAsyncEventMsg->dwParam4 = (DWORD) lphCall; } void WINAPI LMakeCall( PLINEMAKECALL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineMakeCall; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "MakeCall" // func name )) > 0) { LONG lResult; PTCALL ptCall; PTCALLCLIENT ptCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; try { dwAPIVersion = ((PTLINECLIENT) pParams->hLine)->dwAPIVersion; dwSPIVersion = ((PTLINECLIENT) pParams->hLine)->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_INVALLINEHANDLE; goto LMakeCall_return; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LMakeCall_return; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( (PTLINECLIENT) pParams->hLine, &ptCall, &ptCallClient, pCallParamsSP, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LMakeCall_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP7( pfnTSPI_lineMakeCall, "lineMakeCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) ptCall, (DWORD) &ptCall->hdCall, (pParams->dwDestAddressOffset == TAPI_NO_DATA ? 0 : (DWORD) (pDataBuf + pParams->dwDestAddressOffset)), pParams->dwCountryCode, (DWORD) pCallParamsSP ); SetDrvCallFlags( ptCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); LMakeCall_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LMakeCall_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "MakeCall" ); } void WINAPI LMonitorDigits( PLINEMONITORDIGITS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorDigits; if ((pParams->lResult = LINEPROLOG( pParams->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 "MonitorDigits" // func name )) == 0) { DWORD dwUnionDigitModes; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall, ptCallClient2; if ((pParams->dwDigitModes & (~AllDigitModes))) { pParams->lResult = LINEERR_INVALDIGITMODE; goto LMonitorDigits_epilog; } // // Determine the new union of modes // dwUnionDigitModes = pParams->dwDigitModes; ptCallClient2 = (PTCALLCLIENT) ptCallClient->ptCall->ptCallClients; while (ptCallClient2) { if (ptCallClient2 != ptCallClient) { dwUnionDigitModes |= ptCallClient2->dwMonitorDigitModes; } ptCallClient2 = ptCallClient2->pNextSametCall; } if ((pParams->lResult = CallSP2( pfnTSPI_lineMonitorDigits, "lineMonitorDigits", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) dwUnionDigitModes )) == 0) { ptCallClient->dwMonitorDigitModes = pParams->dwDigitModes; } } LMonitorDigits_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "MonitorDigits" ); } void WINAPI LMonitorMedia( PLINEMONITORMEDIA_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorMedia; if ((pParams->lResult = LINEPROLOG( pParams->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 "MonitorMedia" // func name )) == 0) { DWORD dwValidMediaModes, dwUnionMediaModes; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall, ptCallClient2; PTLINECLIENT ptLineClient = (PTLINECLIENT) ptCallClient->ptLineClient; // // Validate the specified modes // switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: dwValidMediaModes = AllMediaModes1_0; break; default: // case TAPI_VERSION1_4: // case TAPI_VERSION_CURRENT: dwValidMediaModes = AllMediaModes1_4; break; } if (pParams->dwMediaModes & ~dwValidMediaModes) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LMonitorMedia_epilog; } // // Determine the new union of modes // dwUnionMediaModes = pParams->dwMediaModes; ptCallClient2 = (PTCALLCLIENT) ptCallClient->ptCall->ptCallClients; while (ptCallClient2) { if (ptCallClient2 != ptCallClient) { dwUnionMediaModes |= ptCallClient2->dwMonitorMediaModes; } ptCallClient2 = ptCallClient2->pNextSametCall; } if ((pParams->lResult = CallSP2( pfnTSPI_lineMonitorMedia, "lineMonitorMedia", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) dwUnionMediaModes )) == 0) { ptCallClient->dwMonitorMediaModes = pParams->dwMediaModes; } } LMonitorMedia_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "MonitorMedia" ); } void WINAPI LMonitorTones( PLINEMONITORTONES_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineMonitorTones; if ((pParams->lResult = LINEPROLOG( pParams->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 "MonitorTones" // func name )) == 0) { LPDWORD pInstData; if ((pInstData = ServerAlloc (2 * sizeof (DWORD)))) { pInstData[0] = (DWORD) pParams->hCall; pInstData[1] = pParams->dwToneListID; pParams->lResult = CallSP4( pfnTSPI_lineMonitorTones, "lineMonitorTones", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) pInstData, // used as ID (pParams->dwTonesOffset == TAPI_NO_DATA ? 0 : (DWORD) pDataBuf + pParams->dwTonesOffset), (DWORD) pParams->dwNumEntries / sizeof (LINEMONITORTONE) ); } else { pParams->lResult = LINEERR_NOMEM; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "MonitorTones" ); } void WINAPI LNegotiateAPIVersion( PLINENEGOTIATEAPIVERSION_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { // // Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion // DWORD dwDeviceID = pParams->dwDeviceID; if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; goto LNegotiateAPIVersion_exit; } if (dwDeviceID < TapiGlobals.dwNumLines) { DWORD dwAPIHighVersion = pParams->dwAPIHighVersion, dwAPILowVersion = pParams->dwAPILowVersion, dwHighestValidAPIVersion; PTLINEAPP ptLineApp = (PTLINEAPP) pParams->hLineApp; if (!IsValidLineApp ((HLINEAPP) ptLineApp, pParams->ptClient)) { pParams->lResult = (TapiGlobals.dwNumLineInits ? LINEERR_INVALAPPHANDLE : LINEERR_UNINITIALIZED); goto LNegotiateAPIVersion_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 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_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 LNegotiateAPIVersion_exit; } } else { dwHighestValidAPIVersion = TAPI_VERSION_CURRENT; } { BOOL bCloseMutex; HANDLE hMutex; // // 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, pParams->ptClient, &hMutex, &bCloseMutex, INFINITE ))) { // // 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; } MyReleaseMutex (hMutex, bCloseMutex); } else { 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); 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]) { if ((pParams->lResult = CallSP3( pLookupEntry->ptProvider-> apfn[SP_LINEGETEXTENSIONID], "lineGetExtensionID", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) dwSPIVersion, (DWORD) pDataBuf )) != 0) { goto LNegotiateAPIVersion_exit; } } else { FillMemory (pDataBuf, sizeof (LINEEXTENSIONID), 0); } } else { 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]; DBGOUT(( 3, "lineNegotiateAPIVersion: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void WINAPI LNegotiateExtVersion( PLINENEGOTIATEEXTVERSION_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; TSPIPROC pfnTSPI_lineNegotiateExtVersion; if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle NULL, // provider widget handle 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 "NegotiateExtVersion" // func name )) == 0) { DWORD dwSPIVersion = (GetLineLookupEntry(dwDeviceID))->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, (DWORD) &pParams->dwExtVersion )) == 0) { if (pParams->dwExtVersion == 0) { pParams->lResult = LINEERR_INCOMPATIBLEEXTVERSION; } else { *pdwNumBytesReturned = sizeof (LINENEGOTIATEEXTVERSION_PARAMS); } } } LNegotiateExtVersion_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "NegotiateExtVersion" ); } VOID PASCAL xxxLOpen( PLINEOPEN_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned, BOOL bLineMapper ) { BOOL bCloseMutex, bOpenedtLine = FALSE, bDecrExtVerCountOnError = FALSE, bReleasetLineMutex = FALSE, bFreeCallParams = FALSE; LONG lResult; DWORD dwDeviceID = pParams->dwDeviceID; HANDLE hMutex; PTLINE ptLine = NULL; PTPROVIDER ptProvider = NULL; PTLINECLIENT ptLineClient = NULL; PTLINELOOKUPENTRY pLookupEntry; LPLINECALLPARAMS pCallParams = NULL; if ((lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type (DWORD) pParams->hLineApp, // client widget handle NULL, // provider widget handle dwDeviceID, // privileges or device ID &hMutex, // mutex handle &bCloseMutex, // close hMutex when finished 0, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID (bLineMapper ? "Open(LINEMAPPER)" : "Open") // func name )) == 0) { DWORD dwPrivileges = pParams->dwPrivileges, dwAPIVersion = pParams->dwAPIVersion, dwExtVersion = pParams->dwExtVersion, dwMediaModes, dwNumProxyRequestTypes, *pdwProxyRequestTypes, i; PTLINEAPP ptLineApp; // // Check if the global reinit flag is set // if (TapiGlobals.bReinit) { lResult = LINEERR_REINIT; goto xxxLOpen_cleanup; } // // Validate params // pLookupEntry = GetLineLookupEntry (dwDeviceID); 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; } if ((lResult = ValidateCallParams( pCallParams, &pCallParams, dwAPIVersion, dwAPIVersion, pParams->dwAsciiCallParamsCodePage ))) { lResult = LINEERR_INVALPOINTER; goto xxxLOpen_cleanup; } if (pCallParams != (LPLINECALLPARAMS) (pDataBuf + pParams->dwCallParamsOffset)) { bFreeCallParams = TRUE; } if ((dwPrivileges & LINEOPENOPTION_SINGLEADDRESS) && (pCallParams->dwAddressMode != LINEADDRESSMODE_ADDRESSID)) { DBGOUT(( 3, "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 & 0xfffffffc) / sizeof (DWORD); if (dwNumProxyRequestTypes == 0 || dwNumProxyRequestTypes > 8) { DBGOUT(( 3, "lineOpen(PROXY): inval proxy request type array "\ "size (callParams.dwDevSpecificSize=x%x)", pCallParams->dwDevSpecificSize )); lResult = LINEERR_INVALCALLPARAMS; goto xxxLOpen_cleanup; } pdwProxyRequestTypes = (LPDWORD) (((LPBYTE) pCallParams) + pCallParams->dwDevSpecificOffset); for (i = 0; i < dwNumProxyRequestTypes; i++) { if (*(pdwProxyRequestTypes + i) == 0 || *(pdwProxyRequestTypes + i) > LINEPROXYREQUEST_GETAGENTGROUPLIST) { DBGOUT(( 3, "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; default: // case TAPI_VERSION_CURRENT: dwAllMediaModes = AllMediaModes1_4; 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; } ptLineClient->hMutex = MyCreateMutex(); ptLineClient->ptClient = pParams->ptClient; ptLineClient->ptLineApp = (PTLINEAPP) pParams->hLineApp; ptLineClient->hRemoteLine = (pParams->hRemoteLine ? (DWORD) pParams->hRemoteLine : (DWORD) ptLineClient); ptLineClient->dwAPIVersion = dwAPIVersion; ptLineClient->dwPrivileges = dwPrivileges; ptLineClient->dwMediaModes = dwMediaModes; ptLineClient->dwCallbackInstance = pParams->dwCallbackInstance; ptLineClient->dwAddressID = (dwPrivileges & LINEOPENOPTION_SINGLEADDRESS ? pCallParams->dwAddressID : 0xffffffff); // // Grab the tLine's mutex, then start doing the open // xxxLOpen_waitForMutex: if (WaitForSingleObject (pLookupEntry->hMutex, 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 (pLookupEntry->hMutex); Sleep (0); goto xxxLOpen_waitForMutex; } } myexcept { // If here pLookupEntry->ptLine was NULLified, safe to continue } // // Validate ext ver as appropriate // if (dwExtVersion != 0 && (!IsValidLineExtVersion (dwDeviceID, dwExtVersion) || ptProvider->apfn[SP_LINESELECTEXTVERSION] == NULL)) { 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; } ptLine->hMutex = pLookupEntry->hMutex; ptLine->ptProvider = ptProvider; ptLine->dwDeviceID = dwDeviceID; ptLine->dwSPIVersion = pLookupEntry->dwSPIVersion; if ((lResult = CallSP5( ptProvider->apfn[SP_LINEOPEN], "lineOpen", SP_FUNC_SYNC, dwDeviceID, (DWORD) ptLine, (DWORD) &ptLine->hdLine, (DWORD) pLookupEntry->dwSPIVersion, (DWORD) LineEventProcSP )) != 0) { ServerFree (ptLine); goto xxxLOpen_cleanup; } bOpenedtLine = TRUE; CallSP2( ptProvider->apfn[SP_LINEGETNUMADDRESSIDS], "lineGetNumAddressIDs", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) &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 ((lResult = CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) dwExtVersion )) != 0) { lResult = (bLineMapper ? LINEERR_OPERATIONFAILED : lResult); goto xxxLOpen_cleanup; } ptLine->dwExtVersion = ptLineClient->dwExtVersion = pParams->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 (CallSP3( ptProvider->apfn[SP_LINECONDITIONALMEDIADETECTION], "lineConditionalMediaDetection", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) dwMediaModes | ptLine->dwOpenMediaModes, (DWORD) pCallParams ) != 0) { 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 ((lResult = CallSP2( ptProvider->apfn[SP_LINESETDEFAULTMEDIADETECTION], "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) dwUnionMediaModes )) != 0) { lResult = (bLineMapper ? LINEERR_OPERATIONFAILED : lResult); 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; } } // // Add the tLineClient to the tLine's list & increment the // number of opens // if ((ptLineClient->pNextSametLine = ptLine->ptLineClients)) { ptLineClient->pNextSametLine->pPrevSametLine = ptLineClient; } ptLine->ptLineClients = ptLineClient; ptLine->dwNumOpens++; if (bOpenedtLine) { pLookupEntry->ptLine = ptLine; ptLine->dwKey = TLINE_KEY; } ReleaseMutex (pLookupEntry->hMutex); bReleasetLineMutex = FALSE; // // Safely add the new tLineClient to the tLineApp's list. // { BOOL bDupedMutex; HANDLE hMutex; if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, pParams->ptClient, &hMutex, &bDupedMutex, INFINITE ))) { 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. // ptLineClient->dwKey = TLINECLIENT_KEY; MyReleaseMutex (hMutex, bDupedMutex); // // Alert other clients that another open has occured // SendMsgToLineClients( ptLine, ptLineClient, LINE_LINEDEVSTATE, LINEDEVSTATE_OPEN, 0, 0 ); // // Fill in the return values // pParams->hLine = (HLINE) ptLineClient; *pdwNumBytesReturned = sizeof (LINEOPEN_PARAMS); } 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 (pLookupEntry->hMutex, 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; CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) 0 ); } } ReleaseMutex (pLookupEntry->hMutex); DestroytLine (ptLine, FALSE); // conditional destroy bOpenedtLine = FALSE; // so ptr won't get freed below } } } xxxLOpen_cleanup: if (bReleasetLineMutex) { if (lResult != 0) { if (bDecrExtVerCountOnError == TRUE) { ptLine->dwExtVersionCount--; if (ptLine->dwExtVersionCount == 0) { ptLine->dwExtVersion = 0; CallSP2( ptProvider->apfn[SP_LINESELECTEXTVERSION], "lineSelectExtVersion", SP_FUNC_SYNC, (DWORD) ptLine->hdLine, (DWORD) 0 ); } } if (bOpenedtLine == TRUE) { CallSP1( ptProvider->apfn[SP_LINECLOSE], "lineClose", SP_FUNC_SYNC, (DWORD) ptLine->hdLine ); } } ReleaseMutex (pLookupEntry->hMutex); } if ((pParams->lResult = lResult) != 0) { if (ptLineClient) { if (ptLineClient->hMutex) { CloseHandle (ptLineClient->hMutex); } ServerFree (ptLineClient); } if (bOpenedtLine) { ServerFree (ptLine); } } if (bFreeCallParams) { ServerFree (pCallParams); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, (bLineMapper ? "Open(LINEMAPPER)" : "Open") ); } void WINAPI LOpen( PLINEOPEN_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { if (pParams->dwDeviceID != LINEMAPPER) { xxxLOpen (pParams, 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 (pParams, 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->dwParam2 == 0) // success { // // Add the used size of the non-dir addr, & keep the total // length of the msg DWORD-aligned // pNewAsyncEventMsg->dwTotalSize += ((pNonDirAddress->dwUsedSize + 3) & 0xfffffffc); pNewAsyncEventMsg->dwParam3 = pAsyncRequestInfo->dwParam2; // lpNonDirAddr pNewAsyncEventMsg->dwParam4 = pNonDirAddress->dwUsedSize; } } void WINAPI LPark( PLINEPARK_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_linePark; if ((lRequestID = LINEPROLOG( pParams->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 "Park" // func name )) > 0) { LPBYTE pBuf; LPVARSTRING pNonDirAddress; if (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED) { if (pParams->u.dwNonDirAddressTotalSize < sizeof (VARSTRING)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LPark_return; } if (!(pBuf = ServerAlloc( (pParams->u.dwNonDirAddressTotalSize + sizeof (ASYNCEVENTMSG) + 3) & 0xfffffffc ))) { lRequestID = LINEERR_NOMEM; goto LPark_return; } pNonDirAddress = (LPVARSTRING) (pBuf + sizeof (ASYNCEVENTMSG)); pNonDirAddress->dwTotalSize = pParams->u.dwNonDirAddressTotalSize; pNonDirAddress->dwNeededSize = pNonDirAddress->dwUsedSize = sizeof (VARSTRING); pAsyncRequestInfo->pfnPostProcess = LPark_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) pBuf; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lpNonDirAddress; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; } 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, (DWORD) hdCall, (DWORD) pParams->dwParkMode, (DWORD) (pParams->dwParkMode == LINEPARKMODE_NONDIRECTED ? NULL : pDataBuf + pParams->dwDirAddressOffset), (DWORD) pNonDirAddress ); } LPark_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Park" ); } void WINAPI LPickup( PLINEPICKUP_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_linePickup; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "Pickup" // func name )) > 0) { PTCALL ptCall; PTCALLCLIENT ptCallClient; if (CreatetCallAndClient( (PTLINECLIENT) pParams->hLine, &ptCall, &ptCallClient, NULL, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LPickup_return; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP7( pfnTSPI_linePickup, "linePickup", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) ptCall, (DWORD) &ptCall->hdCall, (pParams->dwDestAddressOffset == TAPI_NO_DATA ? 0 : (DWORD)(pDataBuf + pParams->dwDestAddressOffset)), (pParams->dwGroupIDOffset == TAPI_NO_DATA ? 0 : (DWORD)(pDataBuf + pParams->dwGroupIDOffset)) ); SetDrvCallFlags( ptCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); } LPickup_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Pickup" ); } void WINAPI LPrepareAddToConference( PLINEPREPAREADDTOCONFERENCE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdConfCall; TSPIPROC pfnTSPI_linePrepareAddToConference; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "PrepareAddToConference" // func name )) > 0) { LONG lResult; PTCALL ptConsultCall; PTCALLCLIENT ptConsultCallClient; PTLINECLIENT ptLineClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : pDataBuf + pParams->dwCallParamsOffset); try { // // Safely get the ptLineClient // ptLineClient = ((PTLINECLIENT) ((PTCALLCLIENT) pParams->hConfCall)->ptLineClient); // // Make sure the hConfCall is really a conf parent // { PTCALL ptCall; ptCall = (PTCALL) ((PTCALLCLIENT) pParams->hConfCall)->ptCall; if (((PTCONFERENCELIST) 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; try { dwAPIVersion = ptLineClient->dwAPIVersion; dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; } myexcept { // // If here either the line client or the line was closed // 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, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LPrepareAddToConference_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptConsultCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphConsultCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_linePrepareAddToConference, "linePrepareAddToConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdConfCall, (DWORD) ptConsultCall, (DWORD) &ptConsultCall->hdCall, (DWORD) pCallParamsSP ); SetDrvCallFlags( ptConsultCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); LPrepareAddToConference_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LPrepareAddToConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "PrepareAddToConference" ); } void WINAPI LProxyMessage( PLINEPROXYMESSAGE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 "ProxyMessage" // func name )) == 0) { DWORD dwMsg = pParams->dwMsg, i; PTCALL ptCall; PTLINE ptLine; TPOINTERLIST clientList, *pClientList = &clientList; ASYNCEVENTMSG msg; // // Verify params // try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; if (!(((PTLINECLIENT) pParams->hLine)->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) { DBGOUT(( 3, "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) { DBGOUT(( 3, "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) { DBGOUT(( 3, "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) { if (!IsValidCall (pParams->hCall, pParams->ptClient)) { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LProxyMessage_epilog; } try { ptCall = ((PTCALLCLIENT) pParams->hCall)->ptCall; } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LProxyMessage_epilog; } goto LProxyMessage_fwdMsgToCallClients; } break; default: DBGOUT(( 3, "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.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; msg.dwMsg = dwMsg; msg.dwParam1 = pParams->dwParam1; msg.dwParam2 = pParams->dwParam2; msg.dwParam3 = pParams->dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTLINECLIENT ptLineClient = (PTLINECLIENT) pClientList->aEntries[i]; if (ptLineClient != (PTLINECLIENT) pParams->hLine) { try { if (((PTLINEAPP) ptLineClient->ptLineApp)->dwAPIVersion >= TAPI_VERSION2_0) { msg.pInitData = (DWORD) ((PTLINEAPP) ptLineClient->ptLineApp)->lpfnCallback; msg.hDevice = (DWORD) ptLineClient->hRemoteLine; msg.dwCallbackInst = ptLineClient->dwCallbackInstance; // // Now a final check to make sure all the // params are valid before sending the msg // { PTCLIENT ptClient = ptLineClient->ptClient; if (ptLineClient->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.dwTotalSize = sizeof (ASYNCEVENTMSG); msg.pfnPostProcessProc = 0; msg.dwMsg = dwMsg; msg.dwParam1 = pParams->dwParam1; msg.dwParam2 = pParams->dwParam2; msg.dwParam3 = pParams->dwParam3; for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pClientList->aEntries[i]; if (ptCallClient != (PTCALLCLIENT) pParams->hCall) { try { PTLINEAPP ptLineApp; ptLineApp = (PTLINEAPP) ((PTLINECLIENT) ptCallClient->ptLineClient)->ptLineApp; if (ptLineApp->dwAPIVersion >= TAPI_VERSION2_0) { msg.pInitData = (DWORD) ptLineApp->lpfnCallback; msg.hDevice = (DWORD) ptCallClient->hRemoteCall; msg.dwCallbackInst = ((PTLINECLIENT) ptCallClient->ptLineClient) ->dwCallbackInstance; // // 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, "ProxyMessage" ); } void WINAPI LProxyResponse( PLINEPROXYRESPONSE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 "ProxyResponse" // func name )) == 0) { BOOL bDupedMutex; HANDLE hMutex; PTLINECLIENT pProxy = (PTLINECLIENT) pParams->hLine; PASYNCREQUESTINFO pAsyncRequestInfo = (PASYNCREQUESTINFO) pParams->dwInstance; // // Safely remove the proxy request from the list of pending requests // (make sure it's a valid request on the specified line) // try { hMutex = pProxy->hMutex; } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LProxyResponse_Epilog; } if (WaitForMutex( hMutex, &hMutex, &bDupedMutex, pProxy, TLINECLIENT_KEY, INFINITE )) { try { if (pAsyncRequestInfo->dwKey != (DWORD) pProxy) { MyReleaseMutex (hMutex, bDupedMutex); pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_Epilog; } } myexcept { MyReleaseMutex (hMutex, bDupedMutex); pParams->dwResult = LINEERR_OPERATIONFAILED; goto LProxyResponse_Epilog; } 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; } MyReleaseMutex (hMutex, bDupedMutex); } else { 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; if (pProxyRequest->dwRequestType == 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 ); } else { 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 ); } pAsyncRequestInfo->pfnPostProcess = LDevSpecific_PostProcess; pAsyncRequestInfo->dwParam2 = dwSize; pAsyncRequestInfo->dwParam3 = (DWORD) pBuf; } // // Now call the deferred completion proc with the "request id" // & result, just like a provider would // LProxyResponse_completeRequest: CompletionProcSP ((DWORD) pAsyncRequestInfo, pParams->dwResult); } LProxyResponse_Epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "ProxyResponse" ); } void WINAPI LRedirect( PLINEREDIRECT_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineRedirect; if ((lRequestID = LINEPROLOG( pParams->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 "Redirect" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineRedirect, "lineRedirect", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) pDataBuf + pParams->dwDestAddressOffset, (DWORD) pParams->dwCountryCode ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Redirect" ); } void WINAPI LRegisterRequestRecipient( PLINEREGISTERREQUESTRECIPIENT_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; PTLINEAPP ptLineApp; if ((ptLineApp = WaitForExclusiveLineAppAccess( pParams->hLineApp, pParams->ptClient, &hMutex, &bCloseMutex, INFINITE ))) { 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) { 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) ))) { pParams->lResult = LINEERR_OPERATIONFAILED; 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 { 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) { 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(); } // BUGBUG LRegisterRequestRecip: else if (!StartRequestRecipient()) 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; } DBGOUT(( 2, "LRegisterRequestRecipient: deleting pending " \ "MakeCall requests" )); } } } else // not registered { pParams->lResult = LINEERR_OPERATIONFAILED; } } // // Now deregister app for MEDIACALL reqs as appropriate // ptLineApp->bReqMediaCallRecipient = (dwRequestMode & LINEREQUESTMODE_MEDIACALL ? 0 : ptLineApp->bReqMediaCallRecipient); } LRegisterRequestRecipient_myReleaseMutex: MyReleaseMutex (hMutex, bCloseMutex); } else { pParams->lResult = (TapiGlobals.dwNumLineInits == 0 ? LINEERR_UNINITIALIZED : LINEERR_INVALAPPHANDLE); } LRegisterRequestRecipient_return: #if DBG { char szResult[32]; DBGOUT(( 3, "lineRegisterRequestRecipient: exit, returning %s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif return; } void WINAPI LReleaseUserUserInfo( PLINEDIAL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineReleaseUserUserInfo; if ((lRequestID = LINEPROLOG( pParams->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 "ReleaseUserUserInfo" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineReleaseUserUserInfo, "lineReleaseUserUserInfo", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "ReleaseUserUserInfo" ); } void LRemoveFromConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { if (pAsyncEventMsg->dwParam2 == 0) { PTCALL ptCall = (PTCALL) pAsyncRequestInfo->dwParam1; SetCallConfList (ptCall, (PTCONFERENCELIST) NULL, FALSE); } } void WINAPI LRemoveFromConference( PLINEREMOVEFROMCONFERENCE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineRemoveFromConference; if ((lRequestID = LINEPROLOG( pParams->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 "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) pParams->hCall)->ptCall; pConfList = ptCall->pConfList; if (!pConfList || (pConfList == (LPVOID) 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 = (DWORD) ptCall; pParams->lResult = CallSP2( pfnTSPI_lineRemoveFromConference, "lineRemoveFromConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall ); } LRemoveFromConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "RemoveFromConference" ); } void WINAPI LSecureCall( PLINESECURECALL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSecureCall; if ((lRequestID = LINEPROLOG( pParams->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 "SecureCall" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineSecureCall, "lineSecureCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SecureCall" ); } void WINAPI LSendUserUserInfo( PLINESENDUSERUSERINFO_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSendUserUserInfo; if ((lRequestID = LINEPROLOG( pParams->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 "SendUserUserInfo" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineSendUserUserInfo, "lineSendUserUserInfo", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (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, "SendUserUserInfo" ); } void WINAPI LSetAppPriority( PLINESETAPPPRIORITY_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwMediaMode = pParams->dwMediaMode, dwRequestMode = pParams->dwRequestMode, dwPriority = pParams->dwPriority; // BUGBUG LSetAppPriority: ext mm's if (dwMediaMode == 0) { if ((dwRequestMode != LINEREQUESTMODE_MAKECALL) && (dwRequestMode != LINEREQUESTMODE_MEDIACALL)) { pParams->lResult = LINEERR_INVALREQUESTMODE; goto LSetAppPriority_return; } } else if (IsOnlyOneBitSetInDWORD (dwMediaMode)) { if ((dwMediaMode & 0xff000000)) { } else if (dwMediaMode & ~AllMediaModes1_4) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetAppPriority_return; } } else { 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; szModuleName[0] = '"'; lstrcpyW(szModuleName + 1, (PWSTR)(pDataBuf + pParams->dwAppNameOffset)); CharUpperW(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) { DWORD dwMaskBit, dwPriorityListIndex; for( dwPriorityListIndex = 0, dwMaskBit = 1; dwMaskBit != dwMediaMode; dwPriorityListIndex++, dwMaskBit <<= 1 ); ppszCurrentPriorityList = TapiGlobals.apszPriorityList + dwPriorityListIndex; pszCurrentPriorityList = *ppszCurrentPriorityList; } else { ppszCurrentPriorityList = (dwRequestMode==LINEREQUESTMODE_MAKECALL ? &TapiGlobals.pszReqMakeCallPriList : &TapiGlobals.pszReqMediaCallPriList); pszCurrentPriorityList = *ppszCurrentPriorityList; } DBGOUT(( 3, "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) ); lstrcpyW(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 { lstrcpyW(pszNewPriorityList, szModuleName); if (pszCurrentPriorityList) { lstrcatW(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 // lstrcpyW( 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: DBGOUT(( 3, "LineEpilogSync (lineSetAppPriority) exit, returning x%x", pParams->lResult )); } void WINAPI LSetAgentActivity( PLINESETAGENTACTIVITY_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "SetAgentActivity" // func name )) > 0) { PTLINE ptLine; PTLINECLIENT pProxy; try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; pProxy = ptLine->apProxys[LINEPROXYREQUEST_SETAGENTACTIVITY]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LSetAgentActivity_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; 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; // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentActivity_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (ptLine->dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETAGENTACTIVITY], "lineSetAgentActivity", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) 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, "SetAgentActivity" ); } void WINAPI LSetAgentGroup( PLINESETAGENTGROUP_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "SetAgentGroup" // func name )) > 0) { PTLINE ptLine; PTLINECLIENT pProxy; LPLINEAGENTGROUPLIST pGroupList = (LPLINEAGENTGROUPLIST) pDataBuf + pParams->dwAgentGroupListOffset; // // Param verification... // { DWORD dwTotalSize = pGroupList->dwTotalSize, i; LPLINEAGENTGROUPENTRY pGroupEntry; if (dwTotalSize < sizeof (LINEAGENTGROUPLIST)) { lRequestID = LINEERR_STRUCTURETOOSMALL; goto LSetAgentGroup_epilog; } if (ISBADSIZEOFFSET( dwTotalSize, sizeof (LINEAGENTGROUPLIST), pGroupList->dwListSize, pGroupList->dwListOffset, "lineSetAgentGroup", "List" )) { lRequestID = LINEERR_INVALAGENTGROUP; goto LSetAgentGroup_epilog; } if (pGroupList->dwNumEntries > ((dwTotalSize - sizeof (LINEAGENTGROUPLIST)) / sizeof (LINEAGENTGROUPENTRY))) { lRequestID = LINEERR_INVALAGENTGROUP; goto LSetAgentGroup_epilog; } // pGroupEntry = (LPLINEAGENTGROUPENTRY) // ((LPBYTE) pGroupList) + pGroupList->dwListOffset; // // for (i = 0; i < pGroupList->dwNumEntries; i++) // { // if (ISBADSIZEOFFSET( // dwTotalSize, // sizeof (LINEAGENTGROUPLIST), // pGroupEntry->dwNameSize, // pGroupEntry->dwNameOffset, // "lineSetAgentGroup", // "Name" // )) // { // lRequestID = LINEERR_INVALAGENTGROUP; // goto LSetAgentGroup_epilog; // } // // pGroupEntry++; // } } try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; pProxy = ptLine->apProxys[LINEPROXYREQUEST_SETAGENTGROUP]; if (pParams->dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LSetAgentGroup_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; 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 ); // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentGroup_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (ptLine->dwDeviceID))->bRemote) { pParams->lResult = CallSP4( pRemoteSP->apfn[SP_LINESETAGENTGROUP], "lineSetAgentGroup", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) 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, "SetAgentGroup" ); } void WINAPI LSetAgentState( PLINESETAGENTSTATE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "SetAgentState" // func name )) > 0) { DWORD dwAddressID = pParams->dwAddressID, dwAgentState = pParams->dwAgentState, dwNextAgentState = pParams->dwNextAgentState; PTLINE ptLine; 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; } try { ptLine = ((PTLINECLIENT) pParams->hLine)->ptLine; pProxy = ptLine->apProxys[LINEPROXYREQUEST_SETAGENTSTATE]; if (dwAddressID >= ptLine->dwNumAddresses) { lRequestID = LINEERR_INVALADDRESSID; goto LSetAgentState_epilog; } } myexcept { lRequestID = LINEERR_OPERATIONUNAVAIL; 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; // // Change the async request info key so we can verify stuff // when lineProxyRequest is called // pAsyncRequestInfo->dwKey = (DWORD) pProxy; if ((lResult = SendProxyRequest( pProxy, pProxyRequestWrapper, pAsyncRequestInfo ))) { lRequestID = lResult; goto LSetAgentState_epilog; } else // success { pParams->lResult = (LONG) pAsyncRequestInfo; } } // // There's no proxy, so check to see if line is remote and // call remotesp if so // else if ((GetLineLookupEntry (ptLine->dwDeviceID))->bRemote) { pParams->lResult = CallSP5( pRemoteSP->apfn[SP_LINESETAGENTSTATE], "lineSetAgentState", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) 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, "SetAgentState" ); } void WINAPI LSetAppSpecific( PLINESETAPPSPECIFIC_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetAppSpecific; if ((pParams->lResult = LINEPROLOG( pParams->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_LINESETAPPSPECIFIC, // provider func index &pfnTSPI_lineSetAppSpecific,// provider func pointer NULL, // async request info 0, // client async request ID "SetAppSpecific" // func name )) == 0) { pParams->lResult = CallSP2( pfnTSPI_lineSetAppSpecific, "lineSetAppSpecific", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) pParams->dwAppSpecific ); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetAppSpecific" ); } void WINAPI LSetCallData( PLINESETCALLDATA_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetCallData; if ((lRequestID = LINEPROLOG( pParams->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_LINESETCALLDATA, // provider func index &pfnTSPI_lineSetCallData, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "SetCallData" // func name )) > 0) { pParams->lResult = CallSP4( pfnTSPI_lineSetCallData, "lineSetCallData", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (pParams->dwCallDataSize ? pDataBuf + pParams->dwCallDataOffset : NULL), (DWORD) pParams->dwCallDataSize ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetCallData" ); } void WINAPI LSetCallParams( PLINESETCALLPARAMS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetCallParams; if ((lRequestID = LINEPROLOG( pParams->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_LINESETCALLPARAMS, // provider func index &pfnTSPI_lineSetCallParams, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "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 = ((PTLINECLIENT)((PTCALLCLIENT) pParams->hCall)-> ptLineClient)->dwAPIVersion; } myexcept { } switch (dwAPIVersion) { case TAPI_VERSION1_0: dwAllBearerModes = AllBearerModes1_0; break; case TAPI_VERSION1_4: dwAllBearerModes = AllBearerModes1_4; break; case TAPI_VERSION_CURRENT: dwAllBearerModes = AllBearerModes2_0; break; } if (!IsOnlyOneBitSetInDWORD(dwBearerMode) || (dwBearerMode & ~(dwAllBearerModes | 0xffff0000))) { lRequestID = LINEERR_INVALBEARERMODE; goto LSetCallParams_epilog; } pParams->lResult = CallSP6( pfnTSPI_lineSetCallParams, "lineSetCallParams", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) pParams->dwBearerMode, (DWORD) pParams->dwMinRate, (DWORD) pParams->dwMaxRate, (DWORD) (pParams->dwDialParamsOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDialParamsOffset) ); } LSetCallParams_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetCallParams" ); } void WINAPI LSetCallPrivilege( PLINESETCALLPRIVILEGE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; if ((pParams->lResult = LINEPROLOG( pParams->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_NONE, // provider func index NULL, // provider func pointer NULL, // async request info 0, // client async request ID "SetCallPrivilege" // func name )) == 0) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptCall; PTCALLCLIENT ptCallClient = (PTCALLCLIENT) pParams->hCall; if ((pParams->dwPrivilege != LINECALLPRIVILEGE_MONITOR) && (pParams->dwPrivilege != LINECALLPRIVILEGE_OWNER)) { pParams->lResult = LINEERR_INVALCALLPRIVILEGE; goto LSetCallPrivilege_epilog; } try { ptCall = ptCallClient->ptCall; hMutex = ptCall->hMutex; } myexcept { pParams->lResult = LINEERR_INVALCALLHANDLE; goto LSetCallPrivilege_epilog; } if (WaitForExclusivetCallAccess( (HTAPICALL) ptCall, TCALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { 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++; } SendMsgToCallClients( ptCall, ptCallClient, LINE_CALLINFO, LINECALLINFOSTATE_NUMMONITORS | (pParams->dwPrivilege == LINECALLPRIVILEGE_OWNER ? LINECALLINFOSTATE_NUMOWNERINCR : LINECALLINFOSTATE_NUMOWNERDECR), 0, 0 ); ptCallClient->dwPrivilege = pParams->dwPrivilege; } LSetCallPrivilege_releaseMutex: MyReleaseMutex (hMutex, bDupedMutex); } else { pParams->lResult = LINEERR_INVALCALLHANDLE; } } LSetCallPrivilege_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetCallPrivilege" ); } void WINAPI LSetCallQualityOfService( PLINESETCALLQUALITYOFSERVICE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetCallQualityOfService; if ((lRequestID = LINEPROLOG( pParams->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_LINESETCALLQUALITYOFSERVICE, // provider func index &pfnTSPI_lineSetCallQualityOfService, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "SetCallQualityOfService" // func name )) > 0) { pParams->lResult = CallSP6( pfnTSPI_lineSetCallQualityOfService, "lineSetCallQualityOfService", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) (pDataBuf + pParams->dwSendingFlowspecOffset), (DWORD) pParams->dwSendingFlowspecSize, (DWORD) (pDataBuf + pParams->dwReceivingFlowspecOffset), (DWORD) pParams->dwReceivingFlowspecSize ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetCallQualityOfService" ); } void WINAPI LSetCallTreatment( PLINESETCALLTREATMENT_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetCallTreatment; if ((lRequestID = LINEPROLOG( pParams->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_LINESETCALLTREATMENT, // provider func index &pfnTSPI_lineSetCallTreatment, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "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, (DWORD) hdCall, (DWORD) pParams->dwTreatment ); } LSetCallTreatment_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetCallTreatment" ); } // This code is in TAPI32.DLL now // // void // WINAPI // LSetCurrentLocation( // PLINESETCURRENTLOCATION_PARAMS pParams, // LPBYTE pDataBuf, // LPDWORD pdwNumBytesReturned // ) // { // pParams->lResult = LINEERR_OPERATIONFAILED; // } void WINAPI LSetDefaultMediaDetection( PLINESETDEFAULTMEDIADETECTION_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetDefaultMediaDetection; if ((pParams->lResult = LINEPROLOG( pParams->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_LINESETDEFAULTMEDIADETECTION, // provider func index &pfnTSPI_lineSetDefaultMediaDetection, // provider func pointer NULL, // async request info 0, // client async request ID "SetDefaultMediaDetection" // func name )) == 0) { DWORD dwMediaModes = pParams->dwMediaModes; PTLINE ptLine; PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; ptLine = ptLineClient->ptLine; // BUGBUG LSetDefaultMediaDetection: mutex if ((dwMediaModes & ptLine->dwOpenMediaModes) != dwMediaModes) { DWORD dwUnionMediaModes = dwMediaModes | ptLine->dwOpenMediaModes; if ((pParams->lResult = CallSP2( pfnTSPI_lineSetDefaultMediaDetection, "lineSetDefaultMediaDetection", SP_FUNC_SYNC, (DWORD) hdLine, dwUnionMediaModes )) == 0) { ptLine->dwOpenMediaModes = dwUnionMediaModes; } } if (pParams->lResult == 0) { ptLineClient->dwPrivileges = (dwMediaModes ? LINECALLPRIVILEGE_OWNER : LINECALLPRIVILEGE_NONE); ptLineClient->dwMediaModes = dwMediaModes; } } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetDefaultMediaDetection" ); } void WINAPI LSetDevConfig( PLINESETDEVCONFIG_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; TSPIPROC pfnTSPI_lineSetDevConfig; if ((pParams->lResult = LINEPROLOG( pParams->ptClient, // tClient DEVICE_ID, // widget type 0, // client widget handle NULL, // provider widget handle (DWORD) 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 "SetDevConfig" // func name )) == 0) { pParams->lResult = CallSP4( pfnTSPI_lineSetDevConfig, "lineSetDevConfig", SP_FUNC_SYNC, (DWORD) pParams->dwDeviceID, (DWORD) (pParams->dwSize ? pDataBuf + pParams->dwDeviceConfigOffset : NULL), (DWORD) pParams->dwSize, (DWORD) pDataBuf + pParams->dwDeviceClassOffset ); } LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetDevConfig" ); } void WINAPI LSetLineDevStatus( PLINESETLINEDEVSTATUS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetLineDevStatus; if ((lRequestID = LINEPROLOG( pParams->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_LINESETLINEDEVSTATUS, // provider func index &pfnTSPI_lineSetLineDevStatus, // provider func pointer &pAsyncRequestInfo, // async request info pParams->dwRemoteRequestID, // client async request ID "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, (DWORD) hdLine, (DWORD) pParams->dwStatusToChange, (DWORD) pParams->fStatus ); } } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetLineDevStatus" ); } void WINAPI LSetMediaControl( PLINESETMEDIACONTROL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; DWORD dwWidgetType, hWidget, dwPrivilege; HANDLE hMutex; TSPIPROC pfnTSPI_lineSetMediaControl; 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( pParams->ptClient, // tClient dwWidgetType, // widget type (DWORD) hWidget, // client widget handle (LPVOID) &hWidget, // 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 "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, (DWORD) (pParams->dwSelect == LINECALLSELECT_CALL ? 0 : hWidget), (DWORD) pParams->dwAddressID, (DWORD) (pParams->dwSelect == LINECALLSELECT_CALL ? hWidget : 0), (DWORD) pParams->dwSelect, (DWORD) (pParams->dwDigitListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwDigitListOffset), (DWORD) pParams->dwDigitListNumEntries / sizeof(LINEMEDIACONTROLDIGIT), (DWORD) (pParams->dwMediaListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwMediaListOffset), (DWORD) pParams->dwMediaListNumEntries / sizeof(LINEMEDIACONTROLMEDIA), (DWORD) (pParams->dwToneListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwToneListOffset), (DWORD) pParams->dwToneListNumEntries / sizeof(LINEMEDIACONTROLTONE), (DWORD) (pParams->dwCallStateListOffset == TAPI_NO_DATA ? NULL : pDataBuf + pParams->dwCallStateListOffset), (DWORD) pParams->dwCallStateListNumEntries / sizeof(LINEMEDIACONTROLCALLSTATE) ); } LSetMediaControl_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetMediaControl" ); } void WINAPI LSetMediaMode( PLINESETMEDIAMODE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetMediaMode; if ((pParams->lResult = LINEPROLOG( pParams->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 "SetMediaMode" // func name )) == 0) { DWORD dwAPIVersion, dwAllMediaModes; // // Check for 0 media mode, and if > 1 bit set without UNKNOWN bit // if (!IsOnlyOneBitSetInDWORD (pParams->dwMediaModes) && !(pParams->dwMediaModes & LINEMEDIAMODE_UNKNOWN)) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetMediaMode_epilog; } // // Now the harder checks // dwAPIVersion = ((PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient)->dwAPIVersion; switch (dwAPIVersion) { case TAPI_VERSION1_0: dwAllMediaModes = AllMediaModes1_0; break; default: // case TAPI_VERSION1_4: // case TAPI_VERSION_CURRENT: dwAllMediaModes = AllMediaModes1_4; break; } if ((pParams->dwMediaModes & (dwAllMediaModes ^ 0x00ffffff))) { pParams->lResult = LINEERR_INVALMEDIAMODE; goto LSetMediaMode_epilog; } pParams->lResult = CallSP2( pfnTSPI_lineSetMediaMode, "lineSetMediaMode", SP_FUNC_SYNC, (DWORD) hdCall, (DWORD) pParams->dwMediaModes ); } LSetMediaMode_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetMediaMode" ); } void WINAPI LSetNumRings( PLINESETNUMRINGS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; if ((pParams->lResult = LINEPROLOG( pParams->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 "SetNumRings" // func name )) == 0) { BOOL bDupedMutex; HANDLE hMutex; PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; try { hMutex = ptLineClient->hMutex; } myexcept { pParams->lResult = LINEERR_INVALLINEHANDLE; goto LSetNumRings_epilog; } if (WaitForMutex( hMutex, &hMutex, &bDupedMutex, ptLineClient, TLINECLIENT_KEY, INFINITE )) { 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: MyReleaseMutex (hMutex, bDupedMutex); } else { pParams->lResult = LINEERR_INVALLINEHANDLE; } } LSetNumRings_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetNumRings" ); } void WINAPI LSetStatusMessages( PLINESETSTATUSMESSAGES_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineSetStatusMessages; if ((pParams->lResult = LINEPROLOG( pParams->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 "SetStatusMessages" // func name )) == 0) { DWORD dwUnionLineStates, dwUnionAddressStates; PTLINECLIENT ptLineClient = (PTLINECLIENT) pParams->hLine; PTLINE ptLine = ptLineClient->ptLine; // // Validate the params // { DWORD dwValidLineStates, dwValidAddressStates; switch (ptLineClient->dwAPIVersion) { case TAPI_VERSION1_0: dwValidLineStates = AllLineStates1_0; dwValidAddressStates = AllAddressStates1_0; break; case TAPI_VERSION1_4: dwValidLineStates = AllLineStates1_4; dwValidAddressStates = AllAddressStates1_4; break; default: // (fix ppc bld wrn) case TAPI_VERSION_CURRENT: dwValidLineStates = AllLineStates1_4; // dwValidAddressStates = AllAddressStates2_0; 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; // // Determine the new state unions of all the line clients // dwUnionLineStates = pParams->dwLineStates; dwUnionAddressStates = pParams->dwAddressStates; { PTLINECLIENT ptLineClientTmp = ptLine->ptLineClients; while (ptLineClientTmp) { if (ptLineClientTmp != ptLineClient) { dwUnionLineStates |= ptLineClientTmp->dwLineStates; dwUnionAddressStates |= ptLineClientTmp->dwAddressStates; } ptLineClientTmp = ptLineClientTmp->pNextSametLine; } } // // If the new state unions are the same as previous state unions // just reset the fields in the tLineClient, else call the provider // if (((dwUnionLineStates == ptLine->dwUnionLineStates) && (dwUnionAddressStates == ptLine->dwUnionAddressStates)) || ((pParams->lResult = CallSP3( pfnTSPI_lineSetStatusMessages, "lineSetStatusMessages", SP_FUNC_SYNC, (DWORD) hdLine, (DWORD) dwUnionLineStates, (DWORD) dwUnionAddressStates )) == 0)) { ptLineClient->dwLineStates = pParams->dwLineStates; ptLineClient->dwAddressStates = pParams->dwAddressStates; ptLine->dwUnionLineStates = dwUnionLineStates; ptLine->dwUnionAddressStates = dwUnionAddressStates; } } LSetStatusMessages_epilog: LINEEPILOGSYNC( &pParams->lResult, hMutex, bCloseMutex, "SetStatusMessages" ); } void WINAPI LSetTerminal( PLINESETTERMINAL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD dwWidgetType, hWidget, dwPrivilege, dwSelect = pParams->dwSelect; HANDLE hMutex; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSetTerminal; 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( pParams->ptClient, // tClient dwWidgetType, // widget type hWidget, // client widget handle (LPVOID) &hWidget, // 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 "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, (DWORD) (dwWidgetType == ANY_RT_HLINE ? hWidget : 0), (DWORD) pParams->dwAddressID, (DWORD) (dwWidgetType == ANY_RT_HCALL ? hWidget : 0), (DWORD) dwSelect, (DWORD) dwTerminalModes, (DWORD) pParams->dwTerminalID, (DWORD) pParams->bEnable ); } LSetTerminal_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetTerminal" ); } // This code is in TAPI32.DLL now // // void // WINAPI // LSetTollList( // PLINESETTOLLLIST_PARAMS pParams, // LPBYTE pDataBuf, // LPDWORD pdwNumBytesReturned // ) // { // pParams->lResult = LINEERR_OPERATIONUNAVAIL; // } void LSetupConference_PostProcess( PASYNCREQUESTINFO pAsyncRequestInfo, PASYNCEVENTMSG pAsyncEventMsg, LPVOID *ppBuf ) { BOOL bDupedMutex; HANDLE hMutex; PTCALL ptConfCall = (PTCALL) pAsyncRequestInfo->dwParam1, ptConsultCall = (PTCALL) pAsyncRequestInfo->dwParam3, ptCall = (PTCALL) pAsyncRequestInfo->dwParam5; LPHCALL lphConfCall = (LPHCALL) pAsyncRequestInfo->dwParam2, lphConsultCall = (LPHCALL) pAsyncRequestInfo->dwParam4; PTCALLCLIENT ptConfCallClient, ptConsultCallClient; // BUGBUG? 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( (HTAPICALL) ptConsultCall, TINCOMPLETECALL_KEY, &hMutex, &bDupedMutex, INFINITE )) { DWORD dwConsultCallInstance = *(&pAsyncRequestInfo->dwParam5 + 2); // // Check to make sure this is the call we think it is (that the // pointer wasn't freed by a previous call to lineClose/Shutdown // and realloc'd for use as a ptCall again) // if (ptConsultCall->dwCallInstance != dwConsultCallInstance) { MyReleaseMutex (hMutex, bDupedMutex); goto LSetupConference_PostProcess_bad_ptConsultCall; } ptConfCallClient = (PTCALLCLIENT) ptConfCall->ptCallClients; ptConsultCallClient = (PTCALLCLIENT) ptConsultCall->ptCallClients; if (pAsyncEventMsg->dwParam2 == 0) // success { PTCONFERENCELIST pConfList = (PTCONFERENCELIST) 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) { MyReleaseMutex (hMutex, bDupedMutex); ptConfCallClient = (PTCALLCLIENT) NULL; ptConsultCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = LINEERR_INVALLINEHANDLE; } goto LSetupConference_PostProcess_initMsgParams; } // // Find out which address the calls are on // CallSP2( ptConfCall->ptProvider->apfn[SP_LINEGETCALLADDRESSID], "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) ptConfCall->hdCall, (DWORD) (&ptConfCall->dwAddressID) ); CallSP2( ptConsultCall->ptProvider->apfn[SP_LINEGETCALLADDRESSID], "lineGetCallAddressID", SP_FUNC_SYNC, (DWORD) ptConsultCall->hdCall, (DWORD) (&ptConsultCall->dwAddressID) ); // // 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; MyReleaseMutex (hMutex, bDupedMutex); // // Create monitor tCallClients // CreateCallMonitors (ptConfCall); CreateCallMonitors (ptConsultCall); } else // error { RemoveCallFromLineList (ptConfCall); RemoveCallFromLineList (ptConsultCall); ptConfCall->dwKey = ptConsultCall->dwKey = INVAL_KEY; // // Check to see if another thread already destroyed the // tCallClients (due to a lineClose/Shutdown) before trying // to reference a freed object // if (ptConfCall->ptCallClients) { RemoveCallClientFromLineClientList (ptConfCallClient); ptConfCallClient->dwKey = INVAL_KEY; ServerFree (ptConfCallClient); } if (ptConsultCall->ptCallClients) { RemoveCallClientFromLineClientList (ptConsultCallClient); ptConsultCallClient->dwKey = INVAL_KEY; ServerFree (ptConsultCallClient); } // // If we have a duped mutex handle (bDupedMutex == TRUE) // then we can safely go ahead and close the ptCall->hMutex // since no other thread will be waiting on it (thanks to // the first WaitForSingleObject in WaitForMutex). Also // release & close the duped handle. // // Otherwise, we have the actual ptCall->hMutex, and we // wrap the release & close in a critical section to // prevent another thread "T2" from grabbing ptCall->hMutex // right after we release but right before we close. This // could result in deadlock at some point when "T2" goes to // release the mutex, only to find that it's handle is bad, // and thread "T3", which is waiting on the mutex (or a dup'd // handle) waits forever. (See corresponding critical // section in WaitForMutex.) // if (bDupedMutex) { CloseHandle (ptConfCall->hMutex); MyReleaseMutex (hMutex, bDupedMutex); } else { EnterCriticalSection (&gSafeMutexCritSec); ReleaseMutex (hMutex); CloseHandle (hMutex); LeaveCriticalSection (&gSafeMutexCritSec); } 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: ptConfCallClient = (PTCALLCLIENT) NULL; ptConsultCallClient = (PTCALLCLIENT) NULL; if (pAsyncEventMsg->dwParam2 == 0) { pAsyncEventMsg->dwParam2 = LINEERR_OPERATIONFAILED; } } // // Fill in the params to pass to client. Note that we have to // create our our msg, since the std msg isn't large enough to // hold all the info we need to send. (The caller will take // care of dealloc'ing this buf.) // // Also, we do this for both the success & fail cases because // remotesp needs the lphXxxCall ptrs back so it can either // fill in or free // LSetupConference_PostProcess_initMsgParams: { DWORD dwMsgSize = sizeof (ASYNCEVENTMSG) + 2 * sizeof (DWORD); PASYNCEVENTMSG pMsg; if (!(pMsg = ServerAlloc (dwMsgSize))) { // BUGBUG it would be better if this struct was alloc'd // in the main routine } CopyMemory (pMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG)); pMsg->dwTotalSize = (DWORD) dwMsgSize; pMsg->dwParam3 = (DWORD) ptConfCallClient; pMsg->dwParam4 = (DWORD) lphConfCall; *(&pMsg->dwParam4 + 1) = (DWORD) ptConsultCallClient; *(&pMsg->dwParam4 + 2) = (DWORD) lphConsultCall; *ppBuf = pMsg; } } void WINAPI LSetupConference( PLINESETUPCONFERENCE_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; DWORD hdXxx; HCALL hCall = pParams->hCall; HLINE hLine = pParams->hLine; HANDLE hMutex; TSPIPROC pfnTSPI_lineSetupConference; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 ? LINECALLPRIVILEGE_OWNER : 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 "SetupConference" // func name )) > 0) { LONG lResult; DWORD dwNumParties; PTCALL ptCall, ptConfCall, ptConsultCall; PTCALLCLIENT ptConfCallClient, ptConsultCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; PTCONFERENCELIST pConfList; // // 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 (DWORD) ))) { lRequestID = LINEERR_NOMEM; goto LSetupConference_return; } CopyMemory( pAsyncRequestInfo2, pAsyncRequestInfo, sizeof (ASYNCREQUESTINFO) ); ServerFree (pAsyncRequestInfo); pAsyncRequestInfo = pAsyncRequestInfo2; } pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; PTLINECLIENT ptLineClient; try { ptLineClient = (hCall ? (PTLINECLIENT) ((PTCALLCLIENT) hCall)->ptLineClient : (PTLINECLIENT) hLine); dwAPIVersion = ptLineClient->dwAPIVersion; dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_OPERATIONFAILED; goto LSetupConference_return; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LSetupConference_return; } } 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) hCall)->ptCall; hLine = ((PTCALLCLIENT) hCall)->ptLineClient; } myexcept { lResult = LINEERR_INVALCALLHANDLE; goto LSetupConference_freeConfList; } if ((lResult = SetCallConfList (ptCall, pConfList, FALSE)) != 0) { goto LSetupConference_freeConfList; } } else { ptCall = NULL; } if ((lResult = CreatetCallAndClient( (PTLINECLIENT) hLine, &ptConfCall, &ptConfCallClient, pCallParamsSP, &pAsyncRequestInfo->dwParam5 + 1 // &dwConfCallInstance )) == 0) { pConfList->aptCalls[0] = ptConfCall; if ((lResult = CreatetCallAndClient( (PTLINECLIENT) hLine, &ptConsultCall, &ptConsultCallClient, NULL, &pAsyncRequestInfo->dwParam5 + 2 // &dwConsultCallInstance ) == 0)) { ptConfCall->pConfList = pConfList; pAsyncRequestInfo->pfnPostProcess = LSetupConference_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptConfCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphConfCall; pAsyncRequestInfo->dwParam3 = (DWORD) ptConsultCall; pAsyncRequestInfo->dwParam4 = (DWORD) pParams->lphConsultCall; pAsyncRequestInfo->dwParam5 = (DWORD) ptCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; goto LSetupConference_callSP; } SetDrvCallFlags (ptConfCall, DCF_SPIRETURNED); DestroytCall (ptConfCall); } LSetupConference_freeConfList: ServerFree (pConfList); lRequestID = lResult; goto LSetupConference_freeCallParams; LSetupConference_callSP: pParams->lResult = CallSP9( pfnTSPI_lineSetupConference, "lineSetupConference", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) (hCall ? hdXxx : 0), // hdCall (DWORD) (hCall ? 0 : hdXxx), // hdLine (DWORD) ptConfCall, (DWORD) &ptConfCall->hdCall, (DWORD) ptConsultCall, (DWORD) &ptConsultCall->hdCall, (DWORD) pParams->dwNumParties, (DWORD) pCallParamsSP ); SetDrvCallFlags( ptConfCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); SetDrvCallFlags( ptConsultCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); LSetupConference_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LSetupConference_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetupConference" ); } void WINAPI LSetupTransfer( PLINESETUPTRANSFER_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; TSPIPROC pfnTSPI_lineSetupTransfer; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "SetupTransfer" // func name )) > 0) { LONG lResult; PTCALL ptConsultCall; PTCALLCLIENT ptConsultCallClient; LPLINECALLPARAMS pCallParamsApp, pCallParamsSP; pCallParamsApp = (LPLINECALLPARAMS) (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (pDataBuf + pParams->dwCallParamsOffset)); if (pCallParamsApp) { DWORD dwAPIVersion, dwSPIVersion; PTLINECLIENT ptLineClient; try { ptLineClient = (PTLINECLIENT) ((PTCALLCLIENT) pParams->hCall)->ptLineClient; dwAPIVersion = ptLineClient->dwAPIVersion; dwSPIVersion = ptLineClient->ptLine->dwSPIVersion; } myexcept { lRequestID = LINEERR_OPERATIONFAILED; goto LSetupTransfer_return; } if ((lResult = ValidateCallParams( pCallParamsApp, &pCallParamsSP, dwAPIVersion, dwSPIVersion, pParams->dwAsciiCallParamsCodePage )) != 0) { lRequestID = lResult; goto LSetupTransfer_return; } } else { pCallParamsSP = (LPLINECALLPARAMS) NULL; } if (CreatetCallAndClient( (PTLINECLIENT) ((PTCALLCLIENT)(pParams->hCall))->ptLineClient, &ptConsultCall, &ptConsultCallClient, NULL, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LSetupTransfer_freeCallParams; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptConsultCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphConsultCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP5( pfnTSPI_lineSetupTransfer, "lineSetupTransfer", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall, (DWORD) ptConsultCall, (DWORD) &ptConsultCall->hdCall, (pParams->dwCallParamsOffset == TAPI_NO_DATA ? 0 : (DWORD)(pDataBuf + pParams->dwCallParamsOffset)) ); SetDrvCallFlags( ptConsultCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); LSetupTransfer_freeCallParams: if (pCallParamsSP != pCallParamsApp) { ServerFree (pCallParamsSP); } } LSetupTransfer_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SetupTransfer" ); } void WINAPI LShutdown( PLINESHUTDOWN_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { PTLINEAPP ptLineApp; WaitForSingleObject (TapiGlobals.hMutex, INFINITE); if (!(ptLineApp = IsValidLineApp (pParams->hLineApp, pParams->ptClient))) { if (TapiGlobals.dwNumLineInits == 0) { pParams->lResult = LINEERR_UNINITIALIZED; } else { pParams->lResult = LINEERR_INVALAPPHANDLE; } } ReleaseMutex (TapiGlobals.hMutex); if (pParams->lResult == 0) { DestroytLineApp ((PTLINEAPP) pParams->hLineApp); } #if DBG { char szResult[32]; DBGOUT(( 3, "lineShutdown: exit, result=%s", MapResultCodeToText (pParams->lResult, szResult) )); } #endif } void WINAPI LSwapHold( PLINESWAPHOLD_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdActiveCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineSwapHold; if ((lRequestID = LINEPROLOG( pParams->ptClient, // tClient ANY_RT_HCALL, // widget type (DWORD) 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 "SwapHold" // func name )) > 0) { HDRVCALL hdHeldCall; PTCALLCLIENT ptHeldCallClient, ptActiveCallClient; // // Verify held call // if (!(ptHeldCallClient = IsValidCall( pParams->hHeldCall, pParams->ptClient ))) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_epilog; } // // 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_epilog; } ptActiveCallClient = (PTCALLCLIENT) pParams->hActiveCall; if (ptHeldCallClient->ptCall->ptLine != ptActiveCallClient->ptCall->ptLine) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_epilog; } hdHeldCall = ptHeldCallClient->ptCall->hdCall; } myexcept { } // // Are they the same call? // if (hdActiveCall == hdHeldCall) { lRequestID = LINEERR_INVALCALLHANDLE; goto LSwapHold_epilog; } pParams->lResult = CallSP3( pfnTSPI_lineSwapHold, "lineSwapHold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdActiveCall, (DWORD) hdHeldCall ); } LSwapHold_epilog: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "SwapHold" ); } void WINAPI LUncompleteCall( PLINEUNCOMPLETECALL_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineUncompleteCall; if ((lRequestID = LINEPROLOG( pParams->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 "UncompleteCall" // func name )) > 0) { pParams->lResult = CallSP3( pfnTSPI_lineUncompleteCall, "lineUncompleteCall", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, pParams->dwCompletionID ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "UncompleteCall" ); } void WINAPI LUnhold( PLINEUNHOLD_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVCALL hdCall; PASYNCREQUESTINFO pAsyncRequestInfo; TSPIPROC pfnTSPI_lineUnhold; if ((lRequestID = LINEPROLOG( pParams->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 "Unhold" // func name )) > 0) { pParams->lResult = CallSP2( pfnTSPI_lineUnhold, "lineUnhold", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdCall ); } LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Unhold" ); } void WINAPI LUnpark( PLINEUNPARK_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bCloseMutex; LONG lRequestID; HANDLE hMutex; HDRVLINE hdLine; TSPIPROC pfnTSPI_lineUnpark; PASYNCREQUESTINFO pAsyncRequestInfo; if ((lRequestID = LINEPROLOG( pParams->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 "Unpark" // func name )) > 0) { PTCALL ptCall; PTCALLCLIENT ptCallClient; if (CreatetCallAndClient( (PTLINECLIENT) pParams->hLine, &ptCall, &ptCallClient, NULL, &pAsyncRequestInfo->dwParam5 ) != 0) { lRequestID = LINEERR_NOMEM; goto LUnpark_return; } pAsyncRequestInfo->pfnPostProcess = LMakeCall_PostProcess; pAsyncRequestInfo->dwParam1 = (DWORD) ptCall; pAsyncRequestInfo->dwParam2 = (DWORD) pParams->lphCall; pAsyncRequestInfo->pfnClientPostProcessProc = pParams->pfnPostProcessProc; pParams->lResult = CallSP6( pfnTSPI_lineUnpark, "lineUnpark", SP_FUNC_ASYNC, (DWORD) pAsyncRequestInfo, (DWORD) hdLine, (DWORD) pParams->dwAddressID, (DWORD) ptCall, (DWORD) &ptCall->hdCall, (DWORD) (pDataBuf + pParams->dwDestAddressOffset) ); SetDrvCallFlags( ptCall, DCF_SPIRETURNED | (pParams->lResult > 0 ? DCF_DRVCALLVALID : 0) ); } LUnpark_return: LINEEPILOGASYNC( &pParams->lResult, lRequestID, hMutex, bCloseMutex, pAsyncRequestInfo, "Unpark" ); } //*************************************************************************** //*************************************************************************** //*************************************************************************** void WINAPI TAllocNewID( P_ALLOCNEWID_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { HKEY hKey; HKEY hKey2; DWORD dwDataSize; DWORD dwDataType; DWORD dwNewID; DWORD dwDisposition; RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey2, &dwDisposition ); RegCreateKeyExW( hKey2, gszLocationsW, 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisposition ); dwDataSize = sizeof(DWORD); // // Use 1 as the first ID. // pParams->u.dwNewID = 1; RegQueryValueExW( hKey, gszNextIDW, 0, &dwDataType, (LPBYTE)&pParams->u.dwNewID, &dwDataSize ); dwNewID = pParams->u.dwNewID + 1; RegSetValueExW( hKey, gszNextIDW, 0, REG_DWORD, (LPBYTE)&dwNewID, sizeof(DWORD) ); RegCloseKey( hKey ); RegCloseKey( hKey2); *pdwNumBytesReturned = sizeof(ALLOCNEWID_PARAMS); return; } //*************************************************************************** //*************************************************************************** //*************************************************************************** void WriteCurrentLocationValue( UINT dwNewLocation ) { HKEY hKey; HKEY hKey2; DBGOUT((90, "Updating curlocation value (%ld)", dwNewLocation)); RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_ALL_ACCESS, &hKey2 ); RegOpenKeyExW( hKey2, gszLocationsW, 0, KEY_ALL_ACCESS, &hKey ); RegSetValueExW( hKey, gszCurrentIDW, 0, REG_DWORD, (LPBYTE)&dwNewLocation, sizeof(dwNewLocation) ); RegCloseKey( hKey ); RegCloseKey( hKey2); } //*************************************************************************** //*************************************************************************** //*************************************************************************** void WINAPI TWriteLocations( PW_LOCATIONS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { UINT n; UINT nCurrentLocation; WCHAR szCurrentLocationKey[256]; HKEY hKey; HKEY hKey2; PLOCATION pLocationList; DWORD dwDisposition; DBGOUT((40, "In writelocations")); // // Has _anything_ changed? // if ( pParams->dwChangedFlags ) { pLocationList = (PLOCATION)( (PDWORD)pDataBuf + 3 ); // // Has anything changed that should cause us to write out all // of the location info? // RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisposition ); RegCreateKeyExW( hKey, gszLocationsW, 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey2, &dwDisposition ); RegCloseKey( hKey ); if ( pParams->dwChangedFlags & CHANGEDFLAGS_REALCHANGE ) { DBGOUT((40, "About to write %d locations", pParams->nNumLocations)); // // This var will be the # of the current location as opposed to the // # in mem - if a user deleted one, we can't write LOCATIONX ... // nCurrentLocation = 0; for (n = 0; n < pParams->nNumLocations; n++) { PLOCATION ThisLocation = &(pLocationList[n]); // // If the user Removed this location, don't write it. // if ( (WCHAR)'\0' == ThisLocation->NameW[0] ) { continue; // skipit } DBGOUT((50, "About to write Location#%d [id:%ld]- %ls", nCurrentLocation, ThisLocation->dwID, ThisLocation->NameW)); wsprintfW(szCurrentLocationKey, L"%ls%d", gszLocationW, nCurrentLocation); { RegCreateKeyExW( hKey2, szCurrentLocationKey, 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &dwDisposition ); RegSetValueExW( hKey, gszNameW, 0, REG_SZ, (LPBYTE)ThisLocation->NameW, (lstrlenW(ThisLocation->NameW)+1)*sizeof(WCHAR) ); RegSetValueExW( hKey, gszAreaCodeW, 0, REG_SZ, (LPBYTE)ThisLocation->AreaCodeW, (lstrlenW(ThisLocation->AreaCodeW)+1)*sizeof(WCHAR) ); RegSetValueExW( hKey, gszCountryW, 0, REG_DWORD, (LPBYTE)&ThisLocation->dwCountry, sizeof(DWORD) ); RegSetValueExW( hKey, gszOutsideAccessW, 0, REG_SZ, (LPBYTE)ThisLocation->OutsideAccessW, (lstrlenW(ThisLocation->OutsideAccessW)+1)*sizeof(WCHAR) ); RegSetValueExW( hKey, gszLongDistanceAccessW, 0, REG_SZ, (LPBYTE)ThisLocation->LongDistanceAccessW, (lstrlenW(ThisLocation->LongDistanceAccessW)+1)*sizeof(WCHAR) ); RegSetValueExW( hKey, gszIDW, 0, REG_DWORD, (LPBYTE)&ThisLocation->dwID, sizeof(DWORD) ); // // If this location has the callwaiting flag on, but nothing // (besides spaces) in the callwaiting string, clear the // flag and the string // if ( ThisLocation->dwFlags & LOCATION_HASCALLWAITING ) { LPWSTR pTemp; pTemp = ThisLocation->DisableCallWaitingW; while ( *pTemp ) { if ( *pTemp != ' ' ) { break; } pTemp++; } // // Did we make it to the end with only spaces? // if ( *pTemp == '\0' ) { // // Yup. Let's tidy up a bit. // ThisLocation->dwFlags &= ~LOCATION_HASCALLWAITING; ThisLocation->DisableCallWaitingW[0] = '\0'; } } RegSetValueExW( hKey, gszDisableCallWaitingW, 0, REG_SZ, (LPBYTE)&ThisLocation->DisableCallWaitingW, (lstrlenW(ThisLocation->DisableCallWaitingW)+1)*sizeof(WCHAR) ); RegSetValueExW( hKey, gszFlagsW, 0, REG_DWORD, (LPBYTE)&ThisLocation->dwFlags, sizeof(DWORD) ); RegCloseKey( hKey ); } nCurrentLocation++; } // // If we "deleted" one or more locations, they're still hanging // around. Delete them now. // for (n = nCurrentLocation; n < pParams->nNumLocations; n++) { wsprintfW( szCurrentLocationKey, L"%ls%d", gszLocationW, n ); RegDeleteKeyW( hKey2, szCurrentLocationKey ); } RegSetValueExW( hKey2, gszNumEntriesW, 0, REG_DWORD, (LPBYTE)&nCurrentLocation, sizeof(DWORD) ); } if ( pParams->dwChangedFlags & CHANGEDFLAGS_TOLLLIST ) { DBGOUT((40, "About to update tolllists for %d locations", pParams->nNumLocations)); // // This var will be the # of the current location as opposed to the // # in mem - if a user deleted one, we can't write LOCATIONX ... // nCurrentLocation = 0; for (n = 0; n < pParams->nNumLocations; n++) { PLOCATION ThisLocation = &(pLocationList[n]); // // If the user Removed this location, don't write it. // if ( (WCHAR)'\0' == ThisLocation->NameW[0] ) { continue; // skipit } DBGOUT((40, "About to write tolllist of %ls", ThisLocation->NameW)); wsprintfW(szCurrentLocationKey, L"%ls%d", gszLocationW, nCurrentLocation); RegOpenKeyExW( hKey2, szCurrentLocationKey, 0, KEY_ALL_ACCESS, &hKey ); RegSetValueExW( hKey, gszTollListW, 0, REG_SZ, (LPBYTE)ThisLocation->TollListW, (lstrlenW(ThisLocation->TollListW)+1)*sizeof(WCHAR) ); RegCloseKey( hKey ); nCurrentLocation++; } } // // Has the current country changed? // if ( pParams->dwChangedFlags & CHANGEDFLAGS_CURLOCATIONCHANGED ) { WriteCurrentLocationValue( pParams->dwCurrentLocationID ); } RegCloseKey( hKey2); // // We're inside "if (dwChangedFlags)", so we know _something_ changed... // DBGOUT((31, "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 ); } return; } void WINAPI TReadLocations( PR_LOCATIONS_PARAMS pParams, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { //dwTotalSize //dwNeededSize //dwUsedSize //pnStuff[0] //pnStuff[1] //pnStuff[2] //LOCATION[n] PUINT pnStuff = (PUINT) (pDataBuf + (sizeof(UINT) * 3)); PLOCATION pLocationList = (PLOCATION)(pDataBuf + (sizeof(UINT) * 6)); UINT n; UINT nNumLocations; UINT nCurrentLocationID; WCHAR szCurrentLocationKey[64]; // Holds "LOCATIONxx" during reads DWORD dwDataSize; DWORD dwDataType; HKEY hKey2; HKEY hKey; if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWHLINEAPP ) { if ( 0 == pParams->dwhLineApp ) { // // NULL is valid for these functions... // } else { if ( !IsValidLineApp((HLINEAPP)pParams->dwhLineApp, pParams->ptClient) ) { DBGOUT((1, "0x%lx is not a valid hLineApp", pParams->dwhLineApp)); pParams->lResult = LINEERR_INVALAPPHANDLE; goto CLEANUP_ERROR; } } } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWDEVICEID ) { if ( pParams->dwDeviceID > TapiGlobals.dwNumLines ) { DBGOUT((1, "%ld is not a valid dwDeviceID", pParams->dwDeviceID)); pParams->lResult = LINEERR_BADDEVICEID; goto CLEANUP_ERROR; } } if ( pParams->dwParmsToCheckFlags & CHECKPARMS_DWAPIVERSION ) { if ( (pParams->dwAPIVersion != TAPI_VERSION2_0) && (pParams->dwAPIVersion != TAPI_VERSION1_4) && (pParams->dwAPIVersion != TAPI_VERSION1_0) ) { DBGOUT((1, "0x%08lx is not a valid version", pParams->dwAPIVersion)); pParams->lResult = LINEERR_INCOMPATIBLEAPIVERSION; goto CLEANUP_ERROR; } } // BUGBUG - performance/extensibility //should do a read of an entire key and get the # of locations from there - //no need to keep a separate # locations field (name of subkeys is name of loc?) RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_READ, &hKey ); RegOpenKeyExW( hKey, gszLocationsW, 0, KEY_READ, &hKey2 ); RegCloseKey( hKey ); // Don't need this key anymore... dwDataSize = sizeof(nCurrentLocationID); nCurrentLocationID = 0; RegQueryValueExW( hKey2, gszCurrentIDW, 0, &dwDataType, (LPBYTE)&nCurrentLocationID, &dwDataSize ); dwDataSize = sizeof(nNumLocations); nNumLocations = 0; RegQueryValueExW( hKey2, gszNumEntriesW, 0, &dwDataType, (LPBYTE)&nNumLocations, &dwDataSize ); // // It's _REALLY_ bad if gnNumLocations is zero for any // reason. Should probably fail the function on the spot... // if ( 0 == nNumLocations ) { DBGOUT((1, " Registry says there are 0 locations")); pParams->lResult = LINEERR_INIFILECORRUPT; RegCloseKey( hKey2 ); goto CLEANUP_ERROR; } // // Do we have enough space? // if ( pParams->u.dwLocationsTotalSize < (nNumLocations * sizeof(LOCATION) + 6 * sizeof(DWORD) ) ) { DBGOUT((4, "(0x%08lx) is not enough room for sizeof( 0x%08lx )", pParams->u.dwLocationsTotalSize, nNumLocations * sizeof(LOCATION) + 6 * sizeof(DWORD) )); // // We did not have enough space. Show the user the error of his ways. // ((PDWORD)pDataBuf)[DWTOTALSIZE] = pParams->u.dwLocationsTotalSize; pParams->lResult = 0; ((PDWORD)pDataBuf)[DWNEEDEDSIZE] = nNumLocations * sizeof(LOCATION) + 6 * sizeof(DWORD); ((PDWORD)pDataBuf)[DWUSEDSIZE] = 3 * sizeof(DWORD); pParams->u.dwLocationsOffset = 0; } else { for (n = 0; n < nNumLocations; n++) { PLOCATION ThisLocation = &pLocationList[n]; wsprintfW(szCurrentLocationKey, L"%ls%d", gszLocationW, n); RegOpenKeyExW( hKey2, szCurrentLocationKey, 0, KEY_ALL_ACCESS, &hKey ); dwDataSize = sizeof(DWORD); ThisLocation->dwID = 0; RegQueryValueExW( hKey, gszIDW, 0, &dwDataType, (LPBYTE)&ThisLocation->dwID, &dwDataSize ); dwDataSize = sizeof(ThisLocation->NameW); ThisLocation->NameW[0] = '\0'; RegQueryValueExW( hKey, gszNameW, 0, &dwDataType, (LPBYTE)ThisLocation->NameW, &dwDataSize ); ThisLocation->NameW[dwDataSize/sizeof(WCHAR)] = '\0'; DBGOUT((31, "getting list entry %d is %d [%ls]", n,ThisLocation->dwID,ThisLocation->NameW)); dwDataSize = sizeof(ThisLocation->AreaCodeW); ThisLocation->AreaCodeW[0] = '\0'; RegQueryValueExW( hKey, gszAreaCodeW, 0, &dwDataType, (LPBYTE)ThisLocation->AreaCodeW, &dwDataSize ); ThisLocation->AreaCodeW[dwDataSize/sizeof(WCHAR)] = '\0'; dwDataSize = sizeof(DWORD); ThisLocation->dwCountry = 1; RegQueryValueExW( hKey, gszCountryW, 0, &dwDataType, (LPBYTE)&ThisLocation->dwCountry, &dwDataSize ); dwDataSize = sizeof(ThisLocation->OutsideAccessW); ThisLocation->OutsideAccessW[0] = '\0'; RegQueryValueExW( hKey, gszOutsideAccessW, 0, &dwDataType, (LPBYTE)ThisLocation->OutsideAccessW, &dwDataSize ); ThisLocation->OutsideAccessW[dwDataSize/sizeof(WCHAR)] = '\0'; dwDataSize = sizeof(ThisLocation->LongDistanceAccessW); ThisLocation->LongDistanceAccessW[0] = '\0'; RegQueryValueExW( hKey, gszLongDistanceAccessW, 0, &dwDataType, (LPBYTE)ThisLocation->LongDistanceAccessW, &dwDataSize ); ThisLocation->LongDistanceAccessW[dwDataSize/sizeof(WCHAR)] = '\0'; dwDataSize = sizeof(DWORD); ThisLocation->dwFlags = 0; RegQueryValueExW( hKey, gszFlagsW, 0, &dwDataType, (LPBYTE)&ThisLocation->dwFlags, &dwDataSize ); dwDataSize = sizeof(ThisLocation->DisableCallWaitingW); ThisLocation->DisableCallWaitingW[0] = '\0'; RegQueryValueExW( hKey, gszDisableCallWaitingW, 0, &dwDataType, (LPBYTE)ThisLocation->DisableCallWaitingW, &dwDataSize ); ThisLocation->DisableCallWaitingW[dwDataSize/sizeof(WCHAR)] = '\0'; dwDataSize = sizeof(ThisLocation->TollListW); ThisLocation->TollListW[0] = '\0'; RegQueryValueExW( hKey, gszTollListW, 0, &dwDataType, (LPBYTE)ThisLocation->TollListW, &dwDataSize ); ThisLocation->TollListW[dwDataSize/sizeof(WCHAR)] = '\0'; RegCloseKey( hKey ); } pnStuff[0] = (UINT)nCurrentLocationID; pnStuff[1] = (UINT)pLocationList; pnStuff[2] = (UINT)nNumLocations; ((PDWORD)pDataBuf)[DWTOTALSIZE] = pParams->u.dwLocationsTotalSize; ((PDWORD)pDataBuf)[DWUSEDSIZE] = nNumLocations * sizeof(LOCATION) + 6 * sizeof(DWORD); ((PDWORD)pDataBuf)[DWNEEDEDSIZE] = nNumLocations * sizeof(LOCATION) + 6 * sizeof(DWORD); pParams->lResult = 0; pParams->u.dwLocationsOffset = 0; } *pdwNumBytesReturned = sizeof (TAPI32_MSG) + ((LPDWORD)pDataBuf)[2]; RegCloseKey( hKey2 ); CLEANUP_ERROR: return; }