diff options
Diffstat (limited to 'private/tapi/dev/sp/atsp32/atsp.c')
-rw-r--r-- | private/tapi/dev/sp/atsp32/atsp.c | 2630 |
1 files changed, 2630 insertions, 0 deletions
diff --git a/private/tapi/dev/sp/atsp32/atsp.c b/private/tapi/dev/sp/atsp32/atsp.c new file mode 100644 index 000000000..0141d18fc --- /dev/null +++ b/private/tapi/dev/sp/atsp32/atsp.c @@ -0,0 +1,2630 @@ +/*++ + +Copyright (c) 1995-1996 Microsoft Corporation + +Module Name: + + atsp.c + +Notes: + +--*/ + + +#include "atsp.h" + + +BOOL +WINAPI +DllMain( + HANDLE hDLL, + DWORD dwReason, + LPVOID lpReserved + ) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + ghInst = hDLL; + +#if DBG + { + HKEY hKey; + DWORD dwDataSize, dwDataType; + char szAtsp32DebugLevel[] = "Atsp32DebugLevel"; + + + RegOpenKeyExA( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + KEY_ALL_ACCESS, + &hKey + ); + + dwDataSize = sizeof (DWORD); + gdwDebugLevel=0; + + RegQueryValueEx( + hKey, + szAtsp32DebugLevel, + 0, + &dwDataType, + (LPBYTE) &gdwDebugLevel, + &dwDataSize + ); + + RegCloseKey (hKey); + } +#endif + + } + + return TRUE; +} + + +void +CommThread( + PDRVLINE pLine + ) +{ + char buf[4]; + DWORD dwThreadID = GetCurrentThreadId(), dwNumBytes; + HANDLE hComm = pLine->hComm, hEvent; + LPOVERLAPPED pOverlapped = &pLine->Overlapped; + + + DBGOUT(( + 3, + "CommThread (id=%d): enter, port=%s", + dwThreadID, + pLine->szComm + )); + + hEvent = pOverlapped->hEvent; + buf[0] = buf[1] = '.'; + + + // + // Loop waiting for i/o to complete (either the Write done in + // TSPI_lineMakeCall or the Reads done to retrieve status info). + // Note that TSPI_lineDrop or TSPI_lineCloseCall may set the + // event to alert us that they're tearing down the call, in + // which case we just exit. + // + + for (;;) + { + if (WaitForSingleObject (hEvent, ATSP_TIMEOUT) == WAIT_OBJECT_0) + { + if (pLine->bDropInProgress == TRUE) + { + DBGOUT((2, "CommThread (id=%d): drop in progress")); + goto CommThread_exit; + } + + GetOverlappedResult (hComm, pOverlapped, &dwNumBytes, FALSE); + ResetEvent (hEvent); + } + else + { + DBGOUT((2, "CommThread (id=%d): wait timeout")); + SetCallState (pLine, LINECALLSTATE_IDLE, 0); + goto CommThread_exit; + } + + buf[1] &= 0x7f; // nuke the parity bit + + DBGOUT(( + 3, + "CommThread (id=%d): read '%c'", + dwThreadID, + (buf[1] == '\r' ? '.' : buf[1]) + )); + + switch ((buf[0] << 8) + buf[1]) + { + case 'CT': // "CONNECT" + case 'OK': // "OK" + + SetCallState (pLine, LINECALLSTATE_CONNECTED, 0); + goto CommThread_exit; + + case 'SY': // "BUSY" + case 'OR': // "ERROR" + case 'NO': // "NO ANSWER", "NO DIALTONE", "NO CARRIER" + + SetCallState (pLine, LINECALLSTATE_IDLE, 0); + goto CommThread_exit; + + default: + + break; + } + + buf[0] = buf[1]; + + ZeroMemory (pOverlapped, sizeof (OVERLAPPED) - sizeof (HANDLE)); + ReadFile (hComm, &buf[1], 1, &dwNumBytes, pOverlapped); + } + +CommThread_exit: + + CloseHandle (hEvent); + DBGOUT((3, "CommThread (id=%d): exit", dwThreadID)); + ExitThread (0); +} + + +// +// We get a slough of C4047 (different levels of indrection) warnings down +// below in the initialization of FUNC_PARAM structs as a result of the +// real func prototypes having params that are types other than DWORDs, +// so since these are known non-interesting warnings just turn them off +// + +#pragma warning (disable:4047) + + +// +// --------------------------- TAPI_lineXxx funcs ----------------------------- +// + +LONG +TSPIAPI +TSPI_lineClose( + HDRVLINE hdLine + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine } + }; + FUNC_INFO info = + { + "TSPI_lineClose", + 1, + params, + }; +#endif + + Prolog (&info); + DrvFree ((PDRVLINE) hdLine); + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineCloseCall( + HDRVCALL hdCall + ) +{ + PDRVLINE pLine = (PDRVLINE) hdCall; +#if DBG + FUNC_PARAM params[] = + { + { gszhdCall, hdCall } + }; + FUNC_INFO info = + { + "TSPI_lineCloseCall", + 1, + params + }; +#endif + + + // + // Note that in TAPI 2.0 TSPI_lineCloseCall can get called + // without TSPI_lineDrop ever being called, so we need to + // be prepared for either case. + // + + Prolog (&info); + DropActiveCall (pLine); + pLine->htCall = NULL; + return (Epilog (&info, 0)); +} + + +LONG +TSPIAPI +TSPI_lineConditionalMediaDetection( + HDRVLINE hdLine, + DWORD dwMediaModes, + LPLINECALLPARAMS const lpCallParams + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "dwMediaModes", dwMediaModes }, + { gszlpCallParams, lpCallParams } + }; + FUNC_INFO info = + { + "TSPI_lineConditionalMediaDetection", + 3, + params + }; +#endif + + + // + // This func is really a no-op for us, since we don't look + // for incoming calls (though we do say we support them to + // make apps happy) + // + + Prolog (&info); + return (Epilog (&info, 0)); +} + + +LONG +TSPIAPI +TSPI_lineDrop( + DRV_REQUESTID dwRequestID, + HDRVCALL hdCall, + LPCSTR lpsUserUserInfo, + DWORD dwSize + ) +{ + PDRVLINE pLine = (PDRVLINE) hdCall; +#if DBG + FUNC_PARAM params[] = + { + { gszdwRequestID, dwRequestID }, + { gszhdCall, hdCall }, + { "lpsUserUserInfo", lpsUserUserInfo }, + { gszdwSize, dwSize } + }; + FUNC_INFO info = + { + "TSPI_lineDrop", + 4, + params + }; +#endif + + + Prolog (&info); + DropActiveCall (pLine); + SetCallState (pLine, LINECALLSTATE_IDLE, 0); + (*gpfnCompletionProc)(dwRequestID, 0); + return (Epilog (&info, dwRequestID)); +} + + +LONG +TSPIAPI +TSPI_lineGetAddressCaps( + DWORD dwDeviceID, + DWORD dwAddressID, + DWORD dwTSPIVersion, + DWORD dwExtVersion, + LPLINEADDRESSCAPS lpAddressCaps + ) +{ + +#if DBG + FUNC_PARAM params[] = + { + { gszdwDeviceID, dwDeviceID }, + { "dwAddressID", dwAddressID }, + { "dwTSPIVersion", dwTSPIVersion }, + { "dwExtVersion", dwExtVersion }, + { "lpAddressCaps", lpAddressCaps } + }; + FUNC_INFO info = + { + "TSPI_lineGetAddressCaps", + 5, + params + }; +#endif + + LONG lResult = 0; + + + Prolog (&info); + + if (dwAddressID != 0) + { + lResult = LINEERR_INVALADDRESSID; + } + + lpAddressCaps->dwNeededSize = + lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS); + + lpAddressCaps->dwLineDeviceID = dwDeviceID; + lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE; + lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_MEDIAMODE | + LINECALLINFOSTATE_APPSPECIFIC; + lpAddressCaps->dwCallerIDFlags = + lpAddressCaps->dwCalledIDFlags = + lpAddressCaps->dwRedirectionIDFlags = + lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL; + lpAddressCaps->dwCallStates = LINECALLSTATE_IDLE | + LINECALLSTATE_OFFERING | + LINECALLSTATE_ACCEPTED | + LINECALLSTATE_DIALTONE | + LINECALLSTATE_DIALING | + LINECALLSTATE_CONNECTED | + LINECALLSTATE_PROCEEDING | + LINECALLSTATE_DISCONNECTED | + LINECALLSTATE_UNKNOWN; + lpAddressCaps->dwDialToneModes = LINEDIALTONEMODE_UNAVAIL; + lpAddressCaps->dwBusyModes = LINEBUSYMODE_UNAVAIL; + lpAddressCaps->dwSpecialInfo = LINESPECIALINFO_UNAVAIL; + lpAddressCaps->dwDisconnectModes = LINEDISCONNECTMODE_NORMAL | + LINEDISCONNECTMODE_BUSY | + LINEDISCONNECTMODE_NOANSWER | + LINEDISCONNECTMODE_UNAVAIL | + LINEDISCONNECTMODE_NODIALTONE; + lpAddressCaps->dwMaxNumActiveCalls = 1; + lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_DIALED; + lpAddressCaps->dwCallFeatures = LINECALLFEATURE_ACCEPT | + LINECALLFEATURE_ANSWER | + LINECALLFEATURE_DROP | + LINECALLFEATURE_SETCALLPARAMS; + lpAddressCaps->dwAddressFeatures = LINEADDRFEATURE_MAKECALL; + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetAddressStatus( + HDRVLINE hdLine, + DWORD dwAddressID, + LPLINEADDRESSSTATUS lpAddressStatus + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "dwAddressID", dwAddressID }, + { "lpAddressStatus", lpAddressStatus } + }; + FUNC_INFO info = + { + "TSPI_lineGetAddressStatus", + 3, + params + }; +#endif + + LONG lResult = 0; + PDRVLINE pLine = (PDRVLINE) hdLine; + + + Prolog (&info); + + lpAddressStatus->dwNeededSize = + lpAddressStatus->dwUsedSize = sizeof(LINEADDRESSSTATUS); + + lpAddressStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0); + lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL; + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetCallAddressID( + HDRVCALL hdCall, + LPDWORD lpdwAddressID + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdCall, hdCall }, + { "lpdwAddressID", lpdwAddressID } + }; + FUNC_INFO info = + { + "TSPI_lineGetCallAddressID", + 2, + params + }; +#endif + + + // + // We only support 1 address (id=0) + // + + Prolog (&info); + *lpdwAddressID = 0; + return (Epilog (&info, 0)); +} + + +LONG +TSPIAPI +TSPI_lineGetCallInfo( + HDRVCALL hdCall, + LPLINECALLINFO lpLineInfo + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdCall, hdCall }, + { "lpLineInfo", lpLineInfo } + }; + FUNC_INFO info = + { + "TSPI_lineGetCallInfo", + 2, + params + }; +#endif + LONG lResult = 0; + PDRVLINE pLine = (PDRVLINE) hdCall; + + + Prolog (&info); + + lpLineInfo->dwNeededSize = + lpLineInfo->dwUsedSize = sizeof(LINECALLINFO); + + lpLineInfo->dwBearerMode = LINEBEARERMODE_VOICE; + lpLineInfo->dwMediaMode = pLine->dwMediaMode; + lpLineInfo->dwCallStates = LINECALLSTATE_IDLE | + LINECALLSTATE_DIALTONE | + LINECALLSTATE_DIALING | + LINECALLSTATE_CONNECTED | + LINECALLSTATE_PROCEEDING | + LINECALLSTATE_DISCONNECTED | + LINECALLSTATE_UNKNOWN; + lpLineInfo->dwOrigin = LINECALLORIGIN_OUTBOUND; + lpLineInfo->dwReason = LINECALLREASON_DIRECT; + lpLineInfo->dwCallerIDFlags = + lpLineInfo->dwCalledIDFlags = + lpLineInfo->dwConnectedIDFlags = + lpLineInfo->dwRedirectionIDFlags = + lpLineInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL; + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetCallStatus( + HDRVCALL hdCall, + LPLINECALLSTATUS lpLineStatus + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdCall, hdCall }, + { "lpLineStatus", lpLineStatus } + }; + FUNC_INFO info = + { + "TSPI_lineGetCallStatus", + 2, + params + }; +#endif + LONG lResult = 0; + PDRVLINE pLine = (PDRVLINE) hdCall; + + + Prolog (&info); + + lpLineStatus->dwNeededSize = + lpLineStatus->dwUsedSize = sizeof(LINECALLSTATUS); + + lpLineStatus->dwCallState = pLine->dwCallState; + + if (pLine->dwCallState != LINECALLSTATE_IDLE) + { + lpLineStatus->dwCallFeatures = LINECALLFEATURE_DROP; + } + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetDevCaps( + DWORD dwDeviceID, + DWORD dwTSPIVersion, + DWORD dwExtVersion, + LPLINEDEVCAPS lpLineDevCaps + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszdwDeviceID, dwDeviceID }, + { "dwTSPIVersion", dwTSPIVersion }, + { "dwExtVersion", dwExtVersion }, + { "lpLineDevCaps", lpLineDevCaps } + }; + FUNC_INFO info = + { + "TSPI_lineGetDevCaps", + 4, + params + }; +#endif + + LONG lResult = 0; + static WCHAR szProviderInfo[] = L"AT-compatible modem service provider"; + + #define PROVIDER_INFO_SIZE (37 * sizeof (WCHAR)) + + Prolog (&info); + + lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS) + PROVIDER_INFO_SIZE + + (MAX_DEV_NAME_LENGTH + 1) * sizeof (WCHAR); + + if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwNeededSize) + { + #define LINECONFIG_SIZE (2 * (MAX_DEV_NAME_LENGTH + 1) + 40) + + char szLineConfig[LINECONFIG_SIZE], szLineN[16], *p; + HKEY hKey; + DWORD dwDataSize, dwDataType; + + + lpLineDevCaps->dwUsedSize = lpLineDevCaps->dwNeededSize; + + lpLineDevCaps->dwProviderInfoSize = PROVIDER_INFO_SIZE; + lpLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS); + + lstrcpyW ((WCHAR *)(lpLineDevCaps + 1), szProviderInfo); + + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + KEY_ALL_ACCESS, + &hKey + ); + + dwDataSize = LINECONFIG_SIZE; + wsprintf (szLineN, "Line%d", dwDeviceID - gdwLineDeviceIDBase); + lstrcpy (szLineConfig, gszDefLineConfigParams); + + RegQueryValueEx( + hKey, + szLineN, + 0, + &dwDataType, + (LPBYTE) szLineConfig, + &dwDataSize + ); + + RegCloseKey (hKey); + + for (p = szLineConfig; *p != ','; p++); + *p = 0; + + lpLineDevCaps->dwLineNameSize = (lstrlen (szLineConfig) + 1) * + sizeof (WCHAR); + lpLineDevCaps->dwLineNameOffset = sizeof(LINEDEVCAPS) + + PROVIDER_INFO_SIZE; + + MultiByteToWideChar( + CP_ACP, + MB_PRECOMPOSED, + szLineConfig, + -1, + (WCHAR *) ((LPBYTE) (lpLineDevCaps + 1) + PROVIDER_INFO_SIZE), + lpLineDevCaps->dwLineNameSize + ); + } + else + { + lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS); + } + + lpLineDevCaps->dwStringFormat = STRINGFORMAT_ASCII; + lpLineDevCaps->dwAddressModes = LINEADDRESSMODE_ADDRESSID; + lpLineDevCaps->dwNumAddresses = 1; + lpLineDevCaps->dwBearerModes = LINEBEARERMODE_VOICE; + lpLineDevCaps->dwMaxRate = 9600; + lpLineDevCaps->dwMediaModes = LINEMEDIAMODE_INTERACTIVEVOICE | + LINEMEDIAMODE_DATAMODEM; + lpLineDevCaps->dwDevCapFlags = LINEDEVCAPFLAGS_CLOSEDROP | + LINEDEVCAPFLAGS_DIALBILLING | + LINEDEVCAPFLAGS_DIALQUIET | + LINEDEVCAPFLAGS_DIALDIALTONE; + lpLineDevCaps->dwMaxNumActiveCalls = 1; + lpLineDevCaps->dwRingModes = 1; + lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL; + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetID( + HDRVLINE hdLine, + DWORD dwAddressID, + HDRVCALL hdCall, + DWORD dwSelect, + LPVARSTRING lpDeviceID, + LPCWSTR lpszDeviceClass, + HANDLE hTargetProcess + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "dwAddressID", dwAddressID }, + { gszhdCall, hdCall }, + { "dwSelect", dwSelect }, + { "lpDeviceID", lpDeviceID }, + { "lpszDeviceClass", lpszDeviceClass }, + { "hTargetProcess", hTargetProcess } + }; + FUNC_INFO info = + { + "TSPI_lineGetID", + 7, + params + }; +#endif + + DWORD dwNeededSize = sizeof(VARSTRING) + sizeof (DWORD); + LONG lResult = 0; + PDRVLINE pLine = (dwSelect == LINECALLSELECT_CALL ? + (PDRVLINE) hdCall : (PDRVLINE) hdLine); + + + Prolog (&info); + + if (lstrcmpiW (lpszDeviceClass, L"tapi/line") == 0) + { + if (lpDeviceID->dwTotalSize < dwNeededSize) + { + lpDeviceID->dwUsedSize = 3*sizeof(DWORD); + } + else + { + lpDeviceID->dwUsedSize = dwNeededSize; + + lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY; + lpDeviceID->dwStringSize = sizeof(DWORD); + lpDeviceID->dwStringOffset = sizeof(VARSTRING); + + *((LPDWORD)(lpDeviceID + 1)) = pLine->dwDeviceID; + } + + lpDeviceID->dwNeededSize = dwNeededSize; + } + else if (lstrcmpiW (lpszDeviceClass, L"comm/datamodem") == 0) + { + dwNeededSize += (strlen (pLine->szComm) + 1) * sizeof (WCHAR); + + if (lpDeviceID->dwTotalSize < dwNeededSize) + { + lpDeviceID->dwUsedSize = 3 * sizeof(DWORD); + } + else + { + HANDLE hCommDup = NULL; + + + if (!pLine->htCall) + { + DBGOUT((1, "TSPI_lineGetID32: error, no active call")); + + lResult = LINEERR_OPERATIONFAILED; + + goto TSPI_lineGetID_epilog; + } + + if (!DuplicateHandle( + GetCurrentProcess(), + pLine->hComm, + hTargetProcess, + &hCommDup, + 0, + TRUE, + DUPLICATE_SAME_ACCESS + )) + { + DBGOUT(( + 1, + "TSPI_lineGetID: DupHandle failed, err=%ld", + GetLastError() + )); + + lResult = LINEERR_OPERATIONFAILED; + + goto TSPI_lineGetID_epilog; + } + + lpDeviceID->dwUsedSize = dwNeededSize; + + lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY; + lpDeviceID->dwStringSize = dwNeededSize - sizeof(VARSTRING); + lpDeviceID->dwStringOffset = sizeof(VARSTRING); + + *((HANDLE *)(lpDeviceID + 1)) = hCommDup; + + lstrcpy( + ((char *)(lpDeviceID + 1)) + sizeof (HANDLE), + pLine->szComm + ); + + MultiByteToWideChar( + CP_ACP, + 0, + pLine->szComm, + -1, + ((WCHAR *)(lpDeviceID + 1)) + sizeof (HANDLE), + 256 + ); + } + + lpDeviceID->dwNeededSize = dwNeededSize; + } + else + { + lResult = LINEERR_NODEVICE; + } + +TSPI_lineGetID_epilog: + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetLineDevStatus( + HDRVLINE hdLine, + LPLINEDEVSTATUS lpLineDevStatus + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "lpLineDevStatus", lpLineDevStatus } + }; + FUNC_INFO info = + { + "TSPI_lineGetLineDevStatus", + 2, + params + }; +#endif + + LONG lResult = 0; + PDRVLINE pLine = (PDRVLINE) hdLine; + + + Prolog (&info); + + lpLineDevStatus->dwUsedSize = + lpLineDevStatus->dwNeededSize = sizeof (LINEDEVSTATUS); + + lpLineDevStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0); + //lpLineDevStatus->dwLineFeatures = + lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED | + LINEDEVSTATUSFLAGS_INSERVICE; + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineGetNumAddressIDs( + HDRVLINE hdLine, + LPDWORD lpdwNumAddressIDs + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "lpdwNumAddressIDs", lpdwNumAddressIDs } + }; + FUNC_INFO info = + { + "TSPI_lineGetNumAddressIDs", + 2, + params + }; +#endif + + LONG lResult = 0; + PDRVLINE pLine = (PDRVLINE) hdLine; + + + // + // We only support 1 address (id=0) + // + + Prolog (&info); + *lpdwNumAddressIDs = 1; + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineMakeCall( + DRV_REQUESTID dwRequestID, + HDRVLINE hdLine, + HTAPICALL htCall, + LPHDRVCALL lphdCall, + LPCWSTR lpszDestAddress, + DWORD dwCountryCode, + LPLINECALLPARAMS const lpCallParams + ) +{ + char szCommands[64], szCommand[64], szDestAddress[128]; + DWORD dwThreadID, dwNumBytes, dwError; + PDRVLINE pLine = (PDRVLINE) hdLine; +#if DBG + FUNC_PARAM params[] = + { + { gszdwRequestID, dwRequestID }, + { gszhdLine, hdLine }, + { "htCall", htCall }, + { "lphdCall", lphdCall }, + { "lpszDestAddress", szDestAddress }, + { "dwCountryCode", dwCountryCode }, + { gszlpCallParams, lpCallParams } + }; + FUNC_INFO info = + { + "TSPI_lineMakeCall", + 7, + params + }; +#endif + + + if (lpszDestAddress) + { + WideCharToMultiByte( + CP_ACP, + 0, + lpszDestAddress, + -1, + (LPSTR) szDestAddress, + 128, + NULL, + NULL + ); + } + + Prolog (&info); + + + // + // Check to see if there's already another call + // + + if (pLine->htCall) + { + (*gpfnCompletionProc)(dwRequestID, LINEERR_CALLUNAVAIL); + goto TSPI_lineMakeCall_return; + } + + + // + // Since we don't support TSPI_lineDial, fail if app tries + // to pass a NULL lpszDestAddress (implying that app just + // wants to go offhook) + // + + if (lpszDestAddress == NULL) + { + (*gpfnCompletionProc)(dwRequestID, LINEERR_INVALADDRESS); + goto TSPI_lineMakeCall_return; + } + + + // + // Get the line's config info + // + + { + HKEY hKey; + DWORD dwDataSize, dwDataType; + char szLineN[8], *pszConfig, *p, *p2; + + + wsprintf( + szLineN, + "Line%d", + ((PDRVLINE) hdLine)->dwDeviceID - gdwLineDeviceIDBase + ); + + dwDataSize = 256; + + pszConfig = DrvAlloc (dwDataSize); + + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + KEY_ALL_ACCESS, + &hKey + ); + + RegQueryValueEx( + hKey, + szLineN, + 0, + &dwDataType, + (LPBYTE) pszConfig, + &dwDataSize + ); + + pszConfig[dwDataSize] = '\0'; // *pszConfig = "MyLine,COM1,L0" + + RegCloseKey (hKey); + + + // + // szComm + // + + for (p = pszConfig; *p != ','; p++); + p++; // *p = "COM1,L0" + for (p2 = p; *p2 != ','; p2++); + *p2 = 0; // *p = "COM1" + + lstrcpy (pLine->szComm, p); + + + // + // szCommands + // + + p2++; // *p2 = "L0" + lstrcpy (szCommands, p2); + + DrvFree (pszConfig); + } + + + // + // Open the port + // + + if ((pLine->hComm = CreateFile( + pLine->szComm, + GENERIC_READ | GENERIC_WRITE, + 0, //FILE_SHARE_READ | FILE_SHARE_WRITE, // BUGBUG + NULL, // no security attrs + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL // no template file + + )) == INVALID_HANDLE_VALUE) + { + DBGOUT(( + 3, + "TSPI_lineMakeCall: CreateFile(%s) failed, err=%ld", + pLine->szComm, + GetLastError() + )); + + (*gpfnCompletionProc)(dwRequestID, LINEERR_RESOURCEUNAVAIL); + goto TSPI_lineMakeCall_return; + } + + + // + // Setup up the modem command string. If there's an initial 'T' + // or 'P' (for Tone or Pulse) in the dest address then disregard + // it. Also if it's a voice call add the semi colon so we return + // to cmd mode. + // + + { + char *p = (char *) szDestAddress; + + + if (*p == 'T' || *p == 'P') + { + p++; + } + + if (lpCallParams && + lpCallParams->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE) + { + wsprintf (szCommand, "AT%sDT%s\r", szCommands, p); + } + else + { + wsprintf (szCommand, "AT%sDT%s;\r", szCommands, p); + } + } + + + // + // Init the data structure & tell tapi our handle to the call + // + + pLine->htCall = htCall; + pLine->bDropInProgress = FALSE; + pLine->dwMediaMode = (lpCallParams ? lpCallParams->dwMediaMode : + LINEMEDIAMODE_INTERACTIVEVOICE); + + *lphdCall = (HDRVCALL) pLine; + + + // + // Do an overlapped write, the comm thread will deal with the results + // + + pLine->Overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + + if (!WriteFile( + pLine->hComm, + szCommand, + lstrlen (szCommand), + &dwNumBytes, + &pLine->Overlapped + ) + + && (dwError = GetLastError()) != ERROR_IO_PENDING) + { + DBGOUT(( + 1, + "TSPI_lineMakeCall: WriteFile(%s) failed, error=%d", + pLine->szComm, + dwError + )); + + pLine->htCall = NULL; + CloseHandle (pLine->hComm); + CloseHandle (pLine->Overlapped.hEvent); + (*gpfnCompletionProc)(dwRequestID, LINEERR_OPERATIONFAILED); + goto TSPI_lineMakeCall_return; + } + + + // + // Complete the requests & set the initial call state + // + + (*gpfnCompletionProc)(dwRequestID, 0); + SetCallState (pLine, LINECALLSTATE_DIALING, 0); + + + // + // Spin the comm thread to handle the results of the Write above + // + + { + HANDLE hCommThread; + + + if (!(hCommThread = CreateThread( + (LPSECURITY_ATTRIBUTES) NULL, + 0, + (LPTHREAD_START_ROUTINE) CommThread, + pLine, + 0, + &dwThreadID + ))) + { + DBGOUT(( + 1, + "TSPI_lineMakeCall: CreateThread failed, err=%ld", + GetLastError() + )); + + GetOverlappedResult( + pLine->hComm, + &pLine->Overlapped, + &dwNumBytes, + TRUE + ); + + SetCallState (pLine, LINECALLSTATE_IDLE, 0); + CloseHandle (pLine->hComm); + CloseHandle (pLine->Overlapped.hEvent); + goto TSPI_lineMakeCall_return; + } + + CloseHandle (hCommThread); + } + + +TSPI_lineMakeCall_return: + + return (Epilog (&info, dwRequestID)); +} + + +LONG +TSPIAPI +TSPI_lineNegotiateTSPIVersion( + DWORD dwDeviceID, + DWORD dwLowVersion, + DWORD dwHighVersion, + LPDWORD lpdwTSPIVersion + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { gszdwDeviceID, dwDeviceID }, + { "dwLowVersion", dwLowVersion }, + { "dwHighVersion", dwHighVersion }, + { "lpdwTSPIVersion", lpdwTSPIVersion } + }; + FUNC_INFO info = + { + "TSPI_lineNegotiateTSPIVersion", + 4, + params + }; +#endif + + Prolog (&info); + *lpdwTSPIVersion = 0x00020000; + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineOpen( + DWORD dwDeviceID, + HTAPILINE htLine, + LPHDRVLINE lphdLine, + DWORD dwTSPIVersion, + LINEEVENT lpfnEventProc + ) +{ + LONG lResult; + PDRVLINE pLine; +#if DBG + FUNC_PARAM params[] = + { + { gszdwDeviceID, dwDeviceID }, + { "htLine", htLine }, + { "lphdLine", lphdLine }, + { "dwTSPIVersion", dwTSPIVersion }, + { "lpfnEventProc", lpfnEventProc } + }; + FUNC_INFO info = + { + "TSPI_lineOpen", + 5, + params + }; +#endif + + + Prolog (&info); + + if ((pLine = DrvAlloc (sizeof (DRVLINE)))) + { + pLine->htLine = htLine; + pLine->pfnEventProc = lpfnEventProc; + pLine->dwDeviceID = dwDeviceID; + + *lphdLine = (HDRVLINE) pLine; + + lResult = 0; + } + else + { + lResult = LINEERR_NOMEM; + } + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_lineSetDefaultMediaDetection( + HDRVLINE hdLine, + DWORD dwMediaModes + ) +{ +#if DBG + FUNC_PARAM params[] = + { + { gszhdLine, hdLine }, + { "dwMediaModes", dwMediaModes } + }; + FUNC_INFO info = + { + "TSPI_lineSetDefaultMediaDetection", + 2, + params + }; +#endif + + + // + // This func is really a no-op for us, since we don't look + // for incoming calls (though we do say we support them to + // make apps happy) + // + + Prolog (&info); + return (Epilog (&info, 0)); +} + + +// +// ------------------------- TSPI_providerXxx funcs --------------------------- +// + +LONG +TSPIAPI +TSPI_providerConfig( + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + // + // Although this func is never called by TAPI v2.0, we export + // it so that the Telephony Control Panel Applet knows that it + // can configure this provider via lineConfigProvider(), + // otherwise Telephon.cpl will not consider it configurable + // + + return 0; +} + + +LONG +TSPIAPI +TSPI_providerGenericDialogData( + DWORD dwObjectID, + DWORD dwObjectType, + LPVOID lpParams, + DWORD dwSize + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "dwObjectID", dwObjectID }, + { "dwObjectType", dwObjectType }, + { "lpParams", lpParams }, + { "dwSize", dwSize } + }; + FUNC_INFO info = + { + "TSPI_providerGenericDialogData", + 4, + params + }; +#endif + + + Prolog (&info); + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_providerInit( + DWORD dwTSPIVersion, + DWORD dwPermanentProviderID, + DWORD dwLineDeviceIDBase, + DWORD dwPhoneDeviceIDBase, + DWORD dwNumLines, + DWORD dwNumPhones, + ASYNC_COMPLETION lpfnCompletionProc, + LPDWORD lpdwTSPIOptions + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "dwTSPIVersion", dwTSPIVersion }, + { gszdwPermanentProviderID, dwPermanentProviderID }, + { "dwLineDeviceIDBase", dwLineDeviceIDBase }, + { "dwPhoneDeviceIDBase", dwPhoneDeviceIDBase }, + { "dwNumLines", dwNumLines }, + { "dwNumPhones", dwNumPhones }, + { "lpfnCompletionProc", lpfnCompletionProc } + }; + FUNC_INFO info = + { + "TSPI_providerInit", + 7, + params + }; +#endif + + Prolog (&info); + gdwLineDeviceIDBase = dwLineDeviceIDBase; + gpfnCompletionProc = lpfnCompletionProc; + *lpdwTSPIOptions = LINETSPIOPTION_NONREENTRANT; + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_providerInstall( + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + // + // Although this func is never called by TAPI v2.0, we export + // it so that the Telephony Control Panel Applet knows that it + // can add this provider via lineAddProvider(), otherwise + // Telephon.cpl will not consider it installable + // + // + + return 0; +} + + +LONG +TSPIAPI +TSPI_providerRemove( + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + // + // Although this func is never called by TAPI v2.0, we export + // it so that the Telephony Control Panel Applet knows that it + // can remove this provider via lineRemoveProvider(), otherwise + // Telephon.cpl will not consider it removable + // + + return 0; +} + + +LONG +TSPIAPI +TSPI_providerShutdown( + DWORD dwTSPIVersion, + DWORD dwPermanentProviderID + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "dwTSPIVersion", dwTSPIVersion }, + { gszdwPermanentProviderID, dwPermanentProviderID } + }; + FUNC_INFO info = + { + "TSPI_providerShutdown", + 2, + params + }; +#endif + + + Prolog (&info); + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TSPI_providerEnumDevices( + DWORD dwPermanentProviderID, + LPDWORD lpdwNumLines, + LPDWORD lpdwNumPhones, + HPROVIDER hProvider, + LINEEVENT lpfnLineCreateProc, + PHONEEVENT lpfnPhoneCreateProc + ) +{ + HKEY hKey; + DWORD dwNumLines, dwDataType, dwDataSize; + + + // + // Retrieve the number of devices we're + // configured for from our registry section + // + + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + KEY_ALL_ACCESS, + &hKey + ); + + dwDataSize = sizeof(dwNumLines); + dwNumLines = 0; + + RegQueryValueEx( + hKey, + gszNumLines, + 0, + &dwDataType, + (LPBYTE) &dwNumLines, + &dwDataSize + ); + + RegCloseKey (hKey); + + *lpdwNumLines = dwNumLines; + *lpdwNumPhones = 0; + return 0; +} + + +LONG +TSPIAPI +TSPI_providerUIIdentify( + LPWSTR lpszUIDLLName + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "lpsUIDLLName", lpszUIDLLName } + }; + FUNC_INFO info = + { + "TSPI_providerUIIdentify", + 1, + params + }; +#endif + + + Prolog (&info); + lstrcpyW(lpszUIDLLName, L"atsp32.tsp"); + return (Epilog (&info, lResult)); +} + + +// +// ---------------------------- TUISPI_xxx funcs ------------------------------ +// + +LONG +TSPIAPI +TUISPI_lineConfigDialog( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + DWORD dwDeviceID, + HWND hwndOwner, + LPCWSTR lpszDeviceClass + ) +{ + char szDeviceClass[128]; + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "lpfnUIDLLCallback", lpfnUIDLLCallback }, + { gszdwDeviceID, dwDeviceID }, + { gszhwndOwner, hwndOwner }, + { "lpszDeviceClass", szDeviceClass } + }; + FUNC_INFO info = + { + "TUISPI_lineConfigDialog", + 4, + params + }; +#endif + + + if (lpszDeviceClass) + { + WideCharToMultiByte( + CP_ACP, + 0, + lpszDeviceClass, + -1, + (LPSTR) szDeviceClass, + 128, + NULL, + NULL + ); + } + + Prolog (&info); + + DialogBoxParam( + ghInst, + MAKEINTRESOURCE(IDD_DIALOG1), + hwndOwner, + (DLGPROC) ConfigDlgProc, + 0 + ); + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TUISPI_providerConfig( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + LONG lResult = 0; +#if DBG + FUNC_PARAM params[] = + { + { "lpfnUIDLLCallback", lpfnUIDLLCallback }, + { gszhwndOwner, hwndOwner }, + { gszdwPermanentProviderID, dwPermanentProviderID } + }; + FUNC_INFO info = + { + "TUISPI_providerConfig", + 3, + params + }; +#endif + + + Prolog (&info); + + DialogBoxParam( + ghInst, + MAKEINTRESOURCE(IDD_DIALOG1), + hwndOwner, + (DLGPROC) ConfigDlgProc, + 0 + ); + + return (Epilog (&info, lResult)); +} + + +LONG +TSPIAPI +TUISPI_providerInstall( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + LONG lResult; + + + if ((lResult = ProviderInstall ("atsp32.tsp", TRUE)) == 0) + { + DialogBoxParam( + ghInst, + MAKEINTRESOURCE(IDD_DIALOG1), + hwndOwner, + (DLGPROC) ConfigDlgProc, + 0 + ); + } + + return lResult; +} + + +LONG +TSPIAPI +TUISPI_providerRemove( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + HKEY hKey; + char szSoftwareMsft[] = "Software\\Microsoft", szATSP[] = "ATSP"; + + + // + // Clean up our registry section + // + + RegOpenKeyExA( + HKEY_LOCAL_MACHINE, + szSoftwareMsft, + 0, + KEY_ALL_ACCESS, + &hKey + ); + + RegDeleteKeyA (hKey, szATSP); + RegCloseKey (hKey); + return 0; +} + + +#pragma warning (default:4047) + + +// +// ---------------------- Misc private support routines ----------------------- +// + +void +PASCAL +EnableChildren( + HWND hwnd, + BOOL bEnable + ) +{ + int i; + static int aiControlIDs[] = + { + IDC_DEVICES, + IDC_NAME, + IDC_PORT, + IDC_COMMANDS, + IDC_REMOVE, + 0 + }; + + + for (i = 0; aiControlIDs[i]; i++) + { + EnableWindow (GetDlgItem (hwnd, aiControlIDs[i]), bEnable); + } +} + + +void +PASCAL +SelectDevice( + HWND hwnd, + int iDevice + ) +{ + SendDlgItemMessage (hwnd, IDC_DEVICES, LB_SETCURSEL, iDevice, 0); + PostMessage(hwnd, WM_COMMAND, IDC_DEVICES | (LBN_SELCHANGE << 16), 0); +} + + +BOOL +CALLBACK +ConfigDlgProc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam + ) +{ + static HKEY hAtspKey; + + DWORD dwDataSize; + DWORD dwDataType; + + + switch (msg) + { + case WM_INITDIALOG: + { + char *pBuf; + DWORD i, iNumLines; + + + // + // Create or open our configuration key in the registry. If the + // create fails it may well be that the current user does not + // have write access to this portion of the registry, so we'll + // just show a "read only" dialog and not allow user to make any + // changes + // + + { + LONG lResult; + DWORD dwDisposition; + + + if ((lResult = RegCreateKeyEx( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + "", + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + (LPSECURITY_ATTRIBUTES) NULL, + &hAtspKey, + &dwDisposition + + )) != ERROR_SUCCESS) + { + DBGOUT(( + 3, + "RegCreateKeyEx(%s,ALL_ACCESS) failed, err=%d", + gszAtspKey, + lResult + )); + + if ((lResult = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + gszAtspKey, + 0, + KEY_QUERY_VALUE, + &hAtspKey + + )) != ERROR_SUCCESS) + { + DBGOUT(( + 3, + "RegOpenKeyEx(%s,ALL_ACCESS) failed, err=%d", + gszAtspKey, + lResult + )); + + EndDialog (hwnd, 0); + return FALSE; + } + + { + int i; + static int aiControlIDs[] = + { + IDC_NAME, + IDC_PORT, + IDC_COMMANDS, + IDC_ADD, + IDC_REMOVE, + IDOK, + 0 + }; + + + for (i = 0; aiControlIDs[i]; i++) + { + EnableWindow( + GetDlgItem (hwnd, aiControlIDs[i]), + FALSE + ); + } + } + } + } + + + // + // Retrieve our configuration info from the registry + // + + dwDataSize = sizeof(iNumLines); + iNumLines = 0; + + RegQueryValueEx( + hAtspKey, + gszNumLines, + 0, + &dwDataType, + (LPBYTE) &iNumLines, + &dwDataSize + ); + + SendDlgItemMessage( + hwnd, + IDC_NAME, + EM_LIMITTEXT, + MAX_DEV_NAME_LENGTH, + 0 + ); + + SendDlgItemMessage( + hwnd, + IDC_COMMANDS, + EM_LIMITTEXT, + MAX_DEV_NAME_LENGTH, + 0 + ); + + pBuf = DrvAlloc (256); + + for (i = 0; i < iNumLines; i++) + { + char *p, *p2, szLineN[8]; + PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG)); + LONG lResult; + + + wsprintf (szLineN, "Line%d", i); + + dwDataSize = 256; + + lResult = RegQueryValueEx( + hAtspKey, + szLineN, + 0, + &dwDataType, + (LPBYTE) pBuf, + &dwDataSize + ); + + + // + // If there was a problem, use the default config + // + + if (0 != lResult) + { + lstrcpy (pBuf, gszDefLineConfigParams); + } + + for (p = pBuf; *p != ','; p++); + *p = 0; + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_ADDSTRING, + 0, + (LPARAM) pBuf + ); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_SETITEMDATA, + i, + (LPARAM) pLineConfig + ); + + p++; + for (p2 = p; *p2 != ','; p2++); + *p2 = 0; + + lstrcpy (pLineConfig->szPort, p); + + p = p2 + 1; + + lstrcpy (pLineConfig->szCommands, p); + } + + DrvFree (pBuf); + + + // + // Fill up the various controls with configuration options + // + + { + static char *aszPorts[] = { "COM1","COM2","COM3",NULL }; + + for (i = 0; aszPorts[i]; i++) + { + SendDlgItemMessage( + hwnd, + IDC_PORT, + LB_ADDSTRING, + 0, + (LPARAM) aszPorts[i] + ); + } + } + + if (iNumLines == 0) + { + EnableChildren (hwnd, FALSE); + } + else + { + SelectDevice (hwnd, 0); + } + + break; + } + case WM_COMMAND: + { + int iSelection; + PDRVLINECONFIG pLineConfig; + + + iSelection = SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETCURSEL, + 0, + 0 + ); + + pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETITEMDATA, + (WPARAM) iSelection, + 0 + ); + + switch (LOWORD((DWORD)wParam)) + { + case IDC_DEVICES: + + if (HIWORD(wParam) == LBN_SELCHANGE) + { + char buf[MAX_DEV_NAME_LENGTH + 1]; + + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETTEXT, + iSelection, + (LPARAM) buf + ); + + SetDlgItemText (hwnd, IDC_NAME, buf); + + SendDlgItemMessage( + hwnd, + IDC_PORT, + LB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) pLineConfig->szPort + ); + + SetDlgItemText (hwnd, IDC_COMMANDS, pLineConfig->szCommands); + } + + break; + + case IDC_NAME: + + if ((HIWORD(wParam) == EN_CHANGE) && (iSelection != LB_ERR)) + { + char buf[MAX_DEV_NAME_LENGTH + 1]; + + + GetDlgItemText (hwnd, IDC_NAME, buf, MAX_DEV_NAME_LENGTH); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_DELETESTRING, + iSelection, + 0 + ); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_INSERTSTRING, + iSelection, + (LPARAM) buf + ); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_SETCURSEL, + iSelection, + 0 + ); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_SETITEMDATA, + iSelection, + (LPARAM) pLineConfig + ); + } + + break; + + case IDC_PORT: + + if (HIWORD(wParam) == LBN_SELCHANGE) + { + iSelection = SendDlgItemMessage( + hwnd, + IDC_PORT, + LB_GETCURSEL, + 0, + 0 + ); + + SendDlgItemMessage( + hwnd, + IDC_PORT, + LB_GETTEXT, + iSelection, + (LPARAM) pLineConfig->szPort + ); + } + + break; + + case IDC_COMMANDS: + + if ((HIWORD(wParam) == EN_CHANGE) && (iSelection != LB_ERR)) + { + GetDlgItemText( + hwnd, + IDC_COMMANDS, + pLineConfig->szCommands, + 63 + ); + } + + break; + + case IDC_ADD: + { + int iNumLines, i = 2; + char szLineName[32]; + PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG)); + + + iNumLines = SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETCOUNT, + 0, + 0 + ); + + lstrcpy (pLineConfig->szPort, "COM1"); + + lstrcpy (szLineName, "my new line"); + +find_unique_line_name: + + if (SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_FINDSTRING, + (WPARAM) -1, + (LPARAM) szLineName + + ) != LB_ERR) + { + wsprintf (szLineName, "my new line%d", i++); + goto find_unique_line_name; + } + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_ADDSTRING, + 0, + (LPARAM) szLineName + ); + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_SETITEMDATA, + iNumLines, + (LPARAM) pLineConfig + ); + + EnableChildren (hwnd, TRUE); + + SelectDevice (hwnd, iNumLines); + + SetFocus (GetDlgItem (hwnd, IDC_NAME)); + + SendDlgItemMessage( + hwnd, + IDC_NAME, + EM_SETSEL, + 0, + (LPARAM) -1 + ); + + break; + } + case IDC_REMOVE: + { + int iNumLines; + + + DrvFree (pLineConfig); + + iNumLines = SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_DELETESTRING, + iSelection, + 0 + ); + + if (iNumLines == 0) + { + SetDlgItemText (hwnd, IDC_NAME, ""); + SetDlgItemText (hwnd, IDC_COMMANDS, ""); + + EnableChildren (hwnd, FALSE); + } + else + { + SelectDevice (hwnd, 0); + } + + break; + } + case IDOK: + { + int i, iNumLines; + char *pBuf; + + + // + // Update the num lines & num phones values + // + + pBuf = DrvAlloc (256); + + iNumLines = SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETCOUNT, + 0, + 0 + ); + + RegSetValueEx( + hAtspKey, + gszNumLines, + 0, + REG_DWORD, + (LPBYTE) &iNumLines, + sizeof(DWORD) + ); + + + // + // For each installed device save it's config info + // + + for (i = 0; i < iNumLines; i++) + { + char szLineN[8]; + PDRVLINECONFIG pLineConfig; + + + SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETTEXT, + i, + (LPARAM) pBuf + ); + + pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage( + hwnd, + IDC_DEVICES, + LB_GETITEMDATA, + i, + 0 + ); + + wsprintf( + pBuf + strlen (pBuf), + ",%s,%s", + pLineConfig->szPort, + pLineConfig->szCommands + ); + + wsprintf (szLineN, "Line%d", i); + + RegSetValueEx( + hAtspKey, + szLineN, + 0, + REG_SZ, + (LPBYTE) pBuf, + lstrlen (pBuf) + 1 + ); + + DrvFree (pLineConfig); + } + + DrvFree (pBuf); + + // fall thru to EndDialog... + } + case IDCANCEL: + + RegCloseKey (hAtspKey); + EndDialog (hwnd, 0); + break; + + } // switch (LOWORD((DWORD)wParam)) + + break; + } + } // switch (msg) + + return FALSE; +} + + +LPVOID +PASCAL +DrvAlloc( + DWORD dwSize + ) +{ + return (LocalAlloc (LPTR, dwSize)); +} + + +VOID +PASCAL +DrvFree( + LPVOID lp + ) +{ + LocalFree (lp); +} + + +void +PASCAL +SetCallState( + PDRVLINE pLine, + DWORD dwCallState, + DWORD dwCallStateMode + ) +{ + if (dwCallState != pLine->dwCallState) + { + pLine->dwCallState = dwCallState; + pLine->dwCallStateMode = dwCallStateMode; + + (*pLine->pfnEventProc)( + pLine->htLine, + pLine->htCall, + LINE_CALLSTATE, + dwCallState, + dwCallStateMode, + pLine->dwMediaMode + ); + } +} + + +#if DBG + +void +PASCAL +Prolog( + PFUNC_INFO pInfo + ) +{ + DWORD i; + + + DBGOUT((3, "%s: enter", pInfo->lpszFuncName)); + + for (i = 0; i < pInfo->dwNumParams; i++) + { + if (pInfo->aParams[i].dwVal && + pInfo->aParams[i].lpszVal[3] == 'z') // lpszVal = "lpsz..." + { + DBGOUT(( + 3, + "%s%s=x%lx, '%s'", + gszTab, + pInfo->aParams[i].lpszVal, + pInfo->aParams[i].dwVal, + pInfo->aParams[i].dwVal + )); + } + else + { + DBGOUT(( + 3, + "%s%s=x%lx", + gszTab, + pInfo->aParams[i].lpszVal, + pInfo->aParams[i].dwVal + )); + } + } +} + + +LONG +PASCAL +Epilog( + PFUNC_INFO pInfo, + LONG lResult + ) +{ + DBGOUT((3, "%s: returning x%x", pInfo->lpszFuncName, lResult)); + + return lResult; +} + + +void +CDECL +DebugOutput( + DWORD dwDbgLevel, + LPCSTR lpszFormat, + ... + ) +{ + if (dwDbgLevel <= gdwDebugLevel) + { + char buf[128] = "ATSP32: "; + va_list ap; + + + va_start(ap, lpszFormat); + + wvsprintf (&buf[8], lpszFormat, ap); + + lstrcat (buf, "\n"); + + OutputDebugString (buf); + + va_end(ap); + } +} + +#endif + + +LONG +PASCAL +ProviderInstall( + char *pszProviderName, + BOOL bNoMultipleInstance + ) +{ + LONG lResult; + + + // + // If only one installation instance of this provider is + // allowed then we want to check the provider list to see + // if the provider is already installed + // + + if (bNoMultipleInstance) + { + LONG (WINAPI *pfnGetProviderList)(); + DWORD dwTotalSize, i; + HINSTANCE hTapi32; + LPLINEPROVIDERLIST pProviderList; + LPLINEPROVIDERENTRY pProviderEntry; + + + // + // Load Tapi32.dll & get a pointer to the lineGetProviderList + // func. We don't want to statically link because this module + // plays the part of both core SP & UI DLL, and we don't want + // to incur the performance hit of automatically loading + // Tapi32.dll when running as a core SP within Tapisrv.exe's + // context. + // + + if (!(hTapi32 = LoadLibrary ("tapi32.dll"))) + { + DBGOUT(( + 1, + "LoadLibrary(tapi32.dll) failed, err=%d", + GetLastError() + )); + + lResult = LINEERR_OPERATIONFAILED; + goto ProviderInstall_return; + } + + if (!((FARPROC) pfnGetProviderList = GetProcAddress( + hTapi32, + (LPCSTR) "lineGetProviderList" + ))) + { + DBGOUT(( + 1, + "GetProcAddr(lineGetProviderList) failed, err=%d", + GetLastError() + )); + + lResult = LINEERR_OPERATIONFAILED; + goto ProviderInstall_unloadTapi32; + } + + + // + // Loop until we get the full provider list + // + + dwTotalSize = sizeof (LINEPROVIDERLIST); + + goto ProviderInstall_allocProviderList; + +ProviderInstall_getProviderList: + + if ((lResult = (*pfnGetProviderList)(0x00020000, pProviderList)) != 0) + { + goto ProviderInstall_freeProviderList; + } + + if (pProviderList->dwNeededSize > pProviderList->dwTotalSize) + { + dwTotalSize = pProviderList->dwNeededSize; + + LocalFree (pProviderList); + +ProviderInstall_allocProviderList: + + if (!(pProviderList = LocalAlloc (LPTR, dwTotalSize))) + { + lResult = LINEERR_NOMEM; + goto ProviderInstall_unloadTapi32; + } + + pProviderList->dwTotalSize = dwTotalSize; + + goto ProviderInstall_getProviderList; + } + + + // + // Inspect the provider list entries to see if this provider + // is already installed + // + + pProviderEntry = (LPLINEPROVIDERENTRY) (((LPBYTE) pProviderList) + + pProviderList->dwProviderListOffset); + + for (i = 0; i < pProviderList->dwNumProviders; i++) + { + char *pszInstalledProviderName = ((char *) pProviderList) + + pProviderEntry->dwProviderFilenameOffset, + *p; + + + // + // Make sure pszInstalledProviderName points at <filename> + // and not <path>\filename by walking backeards thru the + // string searching for last '\\' + // + + p = pszInstalledProviderName + + lstrlen (pszInstalledProviderName) - 1; + + for (; *p != '\\' && p != pszInstalledProviderName; p--); + + pszInstalledProviderName = + (p == pszInstalledProviderName ? p : p + 1); + + if (lstrcmpiA (pszInstalledProviderName, pszProviderName) == 0) + { + lResult = LINEERR_NOMULTIPLEINSTANCE; + goto ProviderInstall_freeProviderList; + } + + pProviderEntry++; + } + + + // + // If here then the provider isn't currently installed, + // so do whatever configuration stuff is necessary and + // indicate SUCCESS + // + + lResult = 0; + + +ProviderInstall_freeProviderList: + + LocalFree (pProviderList); + +ProviderInstall_unloadTapi32: + + FreeLibrary (hTapi32); + } + else + { + // + // Do whatever configuration stuff is necessary and return SUCCESS + // + + lResult = 0; + } + +ProviderInstall_return: + + return lResult; +} + + +void +PASCAL +DropActiveCall( + PDRVLINE pLine + ) +{ + if (pLine->hComm) + { + DWORD dwNumBytes, dwError; + OVERLAPPED overlapped; + + + pLine->bDropInProgress = TRUE; + + SetEvent (pLine->Overlapped.hEvent); + + ZeroMemory (&overlapped, sizeof (OVERLAPPED)); + + overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + + if (pLine->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE) + { + if (!WriteFile( + pLine->hComm, + "+++\r", 4, + &dwNumBytes, + &overlapped + )) + { + if ((dwError = GetLastError()) == ERROR_IO_PENDING) + { + GetOverlappedResult( + pLine->hComm, + &overlapped, + &dwNumBytes, + TRUE + ); + + ResetEvent (overlapped.hEvent); + } + else + { + } + } + } + + if (!WriteFile (pLine->hComm, "ATH\r", 4, &dwNumBytes, &overlapped)) + { + if ((dwError = GetLastError()) == ERROR_IO_PENDING) + { + GetOverlappedResult( + pLine->hComm, + &overlapped, + &dwNumBytes, + TRUE + ); + } + else + { + } + } + + CloseHandle (overlapped.hEvent); + CloseHandle (pLine->hComm); + pLine->hComm = NULL; + } +} |