summaryrefslogtreecommitdiffstats
path: root/private/tapi/dev/server/line.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/tapi/dev/server/line.c')
-rw-r--r--private/tapi/dev/server/line.c21292
1 files changed, 21292 insertions, 0 deletions
diff --git a/private/tapi/dev/server/line.c b/private/tapi/dev/server/line.c
new file mode 100644
index 000000000..8b6e76080
--- /dev/null
+++ b/private/tapi/dev/server/line.c
@@ -0,0 +1,21292 @@
+/*++ 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;
+}