Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

21292 lines
591 KiB

/*++ 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 (&params, 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[] = "<inval msg value>";
static char *aszMsgs[] =
{
"LINE_ADDRESSSTATE",
"LINE_CALLINFO",
"LINE_CALLSTATE",
"LINE_CLOSE",
"LINE_DEVSPECIFIC",
"LINE_DEVSPECIFICFEATURE",
"LINE_GATHERDIGITS",
"LINE_GENERATE",
"LINE_LINEDEVSTATE",
"LINE_MONITORDIGITS",
"LINE_MONITORMEDIA",
"LINE_MONITORTONE",
szInvalMsgVal, // LINE_REPLY
szInvalMsgVal, // LINE_REQUEST
szInvalMsgVal, // PHONE_BUTTON
szInvalMsgVal, // PHONE_CLOSE
szInvalMsgVal, // PHONE_DEVSPECIFIC
szInvalMsgVal, // PHONE_REPLY
szInvalMsgVal, // PHONE_STATE
"LINE_CREATE",
szInvalMsgVal, // PHONE_CREATE
"LINE_AGENTSPECIFIC",
"LINE_AGENTSTATUS",
szInvalMsgVal, // LINE_APPNEWCALL
"LINE_PROXYREQUEST",
"LINE_REMOVE",
szInvalMsgVal, // PHONE_REMOVE
"LINE_NEWCALL",
"LINE_CALLDEVSPECIFIC",
"LINE_CALLDEVSPECIFICFEATURE",
"LINE_CREATEDIALOGINSTANCE",
"LINE_SENDDIALOGINSTANCEDATA"
};
if (dwMsg <= PHONE_REMOVE)
{
pszMsg = aszMsgs[dwMsg];
}
else if (dwMsg >= LINE_NEWCALL && dwMsg <= LINE_SENDDIALOGINSTANCEDATA)
{
pszMsg = aszMsgs[27 + dwMsg - TSPI_MESSAGE_BASE];
}
else
{
pszMsg = szInvalMsgVal;
}
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[] = "<inval callstate value>";
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"<empty>")
));
//
// Add app to priority list
//
if (pParams->dwPriority)
{
if (pszCurrentPriorityList &&
(pszLocationInPriorityList = wcsstr(
pszCurrentPriorityList,
szModuleName
)))
{
//
// App already in list. If app not currently at front of
// list then move it to front.
//
if (pszLocationInPriorityList != pszCurrentPriorityList)
{
MoveMemory(
pszCurrentPriorityList + dwAppNameLength,
pszCurrentPriorityList,
(pszLocationInPriorityList - pszCurrentPriorityList) * sizeof(WCHAR)
);
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;
}