//****************************************************************************
//
// Module: Unimdm.tsp
// File: unimdm.c
// Content: This file contains the moudle initialization.
//
// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved
//
// History:
// Tue 23-Feb-1993 14:08:25 -by- Viroon Touranachun [viroont]
// Ported from TAPI's atsp
//
//****************************************************************************
#include "unimdm.h"
#include "umdmspi.h"
#include "rcids.h"
//****************************************************************************
// Global Variables
//****************************************************************************
HINSTANCE ghInstance = NULL; // The global module handle
DWORD gdwProviderID;
HPROVIDER ghProvider;
// Asynchronous operation completion callback
//
ASYNC_COMPLETION gfnCompletionCallback = NULL;
LINEEVENT gfnLineCreateProc = NULL;
void SetPendingRequest(
PLINEDEV pLineDev,
DWORD dwRequestID,
DWORD dwRequestOp
);
void ClearPendingRequest(
PLINEDEV pLineDev
);
//****************************************************************************
// Constant Parameters
//****************************************************************************
GETIDINFO aGetID[] = {{TEXT("tapi/line"), STRINGFORMAT_BINARY},
{TEXT("comm"), STRINGFORMAT_ASCII},
{TEXT("comm/datamodem"), STRINGFORMAT_BINARY},
{TEXT("comm/datamodem/portname"), STRINGFORMAT_ASCII},
{TEXT("ndis"), STRINGFORMAT_BINARY}};
TCHAR g_szzClassList[] = {TEXT("tapi/line")TEXT("\0")
TEXT("comm")TEXT("\0")
TEXT("comm/datamodem")TEXT("\0")
TEXT("comm/datamodem/portname")TEXT("\0")
TEXT("ndis")TEXT("\0\0")};
TCHAR g_szDeviceClass[] = TEXT("com");
// Generic string
//
TCHAR szNull[] = TEXT("");
CHAR szSemicolon[] = ";";
CHAR szAttachedTo[] = "AttachedTo";
//****************************************************************************
//*********************** The Device ID Specific Calls************************
//****************************************************************************
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetDevConfig(DWORD dwDeviceID,
// LPVARSTRING lpDeviceConfig,
// LPCSTR lpszDeviceClass)
//
// Functions: Get the modem configuration
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALDEVICECLASS if the device class in invalid
// LINEERR_INVALPOINTER if the output buffer address is invalid
// LINEERR_STRUCTURETOOSMALL if the buffer is too small
// LINEERR_NODEVICE if the line ID is invalid
//****************************************************************************
LONG TSPIAPI TSPI_lineGetDevConfig(DWORD dwDeviceID,
LPVARSTRING lpDeviceConfig,
LPCTSTR lpszDeviceClass)
{
PLINEDEV pLineDev=NULL;
LPBYTE lpCC;
DWORD cbSize;
DWORD dwRet;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineGetDevConfig");
TRACE3(IDEVENT_TSPFN_ENTER, IDFROM_TSPI_lineGetDevConfig, &dwDeviceID);
// Validate the requested device class
//
if (!ValidateDevCfgClass(lpszDeviceClass))
{
lRet = LINEERR_INVALDEVICECLASS;
goto end;
}
// Validate the buffer
//
if (lpDeviceConfig == NULL)
{
lRet = LINEERR_INVALPOINTER;
goto end;
}
if (lpDeviceConfig->dwTotalSize < sizeof(VARSTRING))
{
lRet = LINEERR_STRUCTURETOOSMALL;
goto end;
}
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
lRet = LINEERR_NODEVICE;
goto end;
}
ASSERT(pLineDev->pDevCfg != NULL);
#ifdef DYNA_ADDREMOVE
// Fail if out-of-service
//
if (pLineDev->fdwResources&LINEDEVFLAGS_OUTOFSERVICE)
{
lRet = LINEERR_RESOURCEUNAVAIL;
goto end;
}
#endif // DYNA_ADDREMOVE
// Validate the buffer size
//
cbSize = pLineDev->pDevCfg->dfgHdr.dwSize;
lpDeviceConfig->dwUsedSize = sizeof(VARSTRING);
lpDeviceConfig->dwNeededSize = sizeof(VARSTRING) + cbSize;
if (lpDeviceConfig->dwTotalSize >= lpDeviceConfig->dwNeededSize)
{
// If the line is active, we need to get the current modem setting.
//
if (pLineDev->hDevice != INVALID_DEVICE)
{
DWORD cb = pLineDev->pDevCfg->commconfig.dwSize;
// Set the modem configuration
//
UnimodemGetCommConfig(pLineDev,
&(pLineDev->pDevCfg->commconfig),
&cb);
};
// Fill with the default value
//
lpCC = (LPBYTE)(((LPBYTE)lpDeviceConfig) + sizeof(VARSTRING));
CopyMemory(lpCC, (LPBYTE)pLineDev->pDevCfg, cbSize);
lpDeviceConfig->dwStringFormat = STRINGFORMAT_BINARY;
lpDeviceConfig->dwStringSize = cbSize;
lpDeviceConfig->dwStringOffset = sizeof(VARSTRING);
lpDeviceConfig->dwUsedSize += cbSize;
};
lRet = ERROR_SUCCESS;
end:
if (pLineDev) RELEASE_LINEDEV(pLineDev);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetDevConfig,
&dwDeviceID,
lRet
);
DBG_DDI_EXIT("TSPI_lineGetDevConfig", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetDevConfig(DWORD dwDeviceID,
// LPVOID const lpDeviceConfig,
// DWORD dwSize,
// LPCSTR lpszDeviceClass)
//
// Functions: Set the modem configuration
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALDEVICECLASS if the device class in invalid
// LINEERR_INVALPOINTER if the output buffer address is invalid
// LINEERR_NODEVICE if the line ID is invalid
// LINEERR_INVALPARAM if the buffer is invalid configuration
//****************************************************************************
LONG TSPIAPI TSPI_lineSetDevConfig(DWORD dwDeviceID,
LPVOID const lpDeviceConfig,
DWORD dwSize,
LPCTSTR lpszDeviceClass)
{
PLINEDEV pLineDev;
PDEVCFG pDevCfg;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineSetDevConfig");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetDevConfig,
&dwDeviceID
);
// Validate the requested device class
//
if (!ValidateDevCfgClass(lpszDeviceClass))
{
lRet = LINEERR_INVALDEVICECLASS;
goto end;
}
// Validate the buffer, make sure it's dword aligned
//
if (lpDeviceConfig == NULL || ((DWORD)lpDeviceConfig & 3))
{
ASSERT(FALSE);
lRet = LINEERR_INVALPOINTER;
goto end;
}
if (dwSize < sizeof(DWORD)) {
lRet = LINEERR_INVALPARAM;
goto end;
}
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
lRet = LINEERR_NODEVICE;
goto end;
}
ASSERT(pLineDev->pDevCfg != NULL);
// Check the copied size
//
pDevCfg = pLineDev->pDevCfg;
if ((dwSize < pDevCfg->dfgHdr.dwSize) ||
(pDevCfg->dfgHdr.dwVersion != ((LPDEVCFG)lpDeviceConfig)->dfgHdr.dwVersion))
{
RELEASE_LINEDEV(pLineDev);
lRet = LINEERR_INVALPARAM;
goto end;
}
// Get the new settings
//
SETWAITBONG(pDevCfg, GETWAITBONG(((LPDEVCFG)lpDeviceConfig)));
SETOPTIONS(pDevCfg, GETOPTIONS(((LPDEVCFG)lpDeviceConfig)));
ASSERT(pDevCfg->commconfig.wVersion == ((LPDEVCFG)lpDeviceConfig)->commconfig.wVersion);
ASSERT(pDevCfg->commconfig.dwProviderSubType ==
((LPDEVCFG)lpDeviceConfig)->commconfig.dwProviderSubType);
ASSERT(pDevCfg->commconfig.dwProviderSize ==
((LPDEVCFG)lpDeviceConfig)->commconfig.dwProviderSize);
pDevCfg->commconfig.dcb = ((LPDEVCFG)lpDeviceConfig)->commconfig.dcb;
CopyMemory(((LPBYTE)&pDevCfg->commconfig)+pDevCfg->commconfig.dwProviderOffset,
((LPBYTE)&((LPDEVCFG)lpDeviceConfig)->commconfig)+((LPDEVCFG)lpDeviceConfig)->commconfig.dwProviderOffset,
((LPDEVCFG)lpDeviceConfig)->commconfig.dwProviderSize);
pLineDev->InitStringsAreValid=FALSE;
#if 0 // ifdef'ed off because of bug win95b:21204. Don't pass down comm config when connected.
// If the line is active, we need to propagate the new setting to modem.
//
if (pLineDev->hDevice != INVALID_DEVICE)
{
// Set the modem configuration
//
UnimodemSetCommConfig(pLineDev,
&(pDevCfg->commconfig),
pDevCfg->commconfig.dwSize);
};
#endif // 0
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetDevConfig,
&dwDeviceID,
lRet
);
DBG_DDI_EXIT("TSPI_lineSetDevConfig", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetDevCaps(DWORD dwDeviceID,
// DWORD dwTSPIVersion,
// DWORD dwExtVersion,
// LPLINEDEVCAPS lpLineDevCaps)
//
// Functions: Get the line capibilities
//
// Return: ERROR_SUCCESS if successful
// LINEERR_NODEVICE if the device ID is invalid
//****************************************************************************
LONG TSPIAPI TSPI_lineGetDevCaps(DWORD dwDeviceID,
DWORD dwTSPIVersion,
DWORD dwExtVersion,
LPLINEDEVCAPS lpLineDevCaps)
{
PLINEDEV pLineDev=NULL;
TCHAR lpszProviderInfo[80];
int cbProviderInfoLen,
cbLineNameLen,
cbDevSpecificLen,
cbDevClassLen,
cbAvailMem,
#ifdef UNICODE
cbDeviceKeyLen,
#endif // UNICODE
cbDWORDPad;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineGetDevCaps");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetDevCaps,
&dwDeviceID
);
// Check the version
//
VALIDATE_VERSION(dwTSPIVersion);
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
lRet = LINEERR_NODEVICE;
goto end;
}
#ifdef DYNA_ADDREMOVE
// Fail if out-of-service
//
if (pLineDev->fdwResources&LINEDEVFLAGS_OUTOFSERVICE)
{
lRet = LINEERR_RESOURCEUNAVAIL;
goto end;
}
#endif // DYNA_ADDREMOVE
// Check to see how much memory we'll need.
//
cbProviderInfoLen = sizeof(TCHAR) * (LoadString(ghInstance,
ID_PROVIDER_INFO,
lpszProviderInfo,
sizeof(lpszProviderInfo)/sizeof(TCHAR))
+ 1);
cbLineNameLen = sizeof(TCHAR) * (lstrlen(pLineDev->szDeviceName) + 1);
lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
cbAvailMem = (int) (lpLineDevCaps->dwTotalSize - lpLineDevCaps->dwUsedSize);
// Enter the size we ideally need.
lpLineDevCaps->dwNeededSize = cbProviderInfoLen + cbLineNameLen +
lpLineDevCaps->dwUsedSize;
// Copy in the provider info if it fits
if (cbAvailMem >= cbProviderInfoLen)
{
lstrcpy((LPTSTR)((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize),
lpszProviderInfo);
lpLineDevCaps->dwProviderInfoSize = cbProviderInfoLen;
lpLineDevCaps->dwProviderInfoOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbProviderInfoLen;
cbAvailMem -= cbProviderInfoLen;
}
// Copy the name if it fits
if (cbAvailMem >= cbLineNameLen)
{
lstrcpy((LPTSTR)((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize),
pLineDev->szDeviceName);
lpLineDevCaps->dwLineNameSize = cbLineNameLen;
lpLineDevCaps->dwLineNameOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbLineNameLen;
cbAvailMem -= cbLineNameLen;
}
lpLineDevCaps->dwPermanentLineID = MAKELONG(LOWORD(pLineDev->dwPermanentLineID),
LOWORD(gdwProviderID));
lpLineDevCaps->dwStringFormat = STRINGFORMAT_ASCII;
// Line address information
//
lpLineDevCaps->dwAddressModes = LINEADDRESSMODE_ADDRESSID;
lpLineDevCaps->dwNumAddresses = 1;
// Bearer mode & information
//
lpLineDevCaps->dwMaxRate = pLineDev->dwMaxDCERate;
//
lpLineDevCaps->dwBearerModes = pLineDev->dwBearerModes;
// Media mode
//
lpLineDevCaps->dwMediaModes = pLineDev->dwMediaModes;
// Tones & Digits
//
//lpLineDevCaps->dwGenerateToneModes = 0;
//lpLineDevCaps->dwGenerateToneMaxNumFreq = 0;
//lpLineDevCaps->dwGenerateDigitModes = 0;
//lpLineDevCaps->dwMonitorToneMaxNumFreq = 0;
//lpLineDevCaps->dwMonitorToneMaxNumEntries = 0;
//lpLineDevCaps->dwMonitorDigitModes = 0;
//lpLineDevCaps->dwGatherDigitsMinTimeout = 0;
//lpLineDevCaps->dwGatherDigitsMaxTimeout = 0;
//lpLineDevCaps->dwMedCtlDigitMaxListSize = 0;
//lpLineDevCaps->dwMedCtlMediaMaxListSize = 0;
//lpLineDevCaps->dwMedCtlToneMaxListSize = 0;
//lpLineDevCaps->dwMedCtlCallStateMaxListSize = 0;
// Line capabilities
//
// We can simulate wait-for-bong.
lpLineDevCaps->dwDevCapFlags = pLineDev->dwDevCapFlags |
LINEDEVCAPFLAGS_DIALBILLING |
LINEDEVCAPFLAGS_CLOSEDROP;
//lpLineDevCaps->dwAnswerMode = 0;
lpLineDevCaps->dwRingModes = 1;
//
lpLineDevCaps->dwMaxNumActiveCalls = 1;
// Line device state to be notified
//
lpLineDevCaps->dwLineStates = LINEDEVSTATE_CONNECTED |
LINEDEVSTATE_DISCONNECTED |
LINEDEVSTATE_OPEN |
LINEDEVSTATE_CLOSE |
LINEDEVSTATE_INSERVICE |
LINEDEVSTATE_OUTOFSERVICE |
LINEDEVSTATE_REMOVED |
LINEDEVSTATE_RINGING |
LINEDEVSTATE_REINIT;
// We do not support user-to-user information
//
//lpLineDevCaps->dwUUIAcceptSize = 0;
//lpLineDevCaps->dwUUIAnswerSize = 0;
//lpLineDevCaps->dwUUIMakeCallSize = 0;
//lpLineDevCaps->dwUUIDropSize = 0;
//lpLineDevCaps->dwUUISendUserUserInfoSize = 0;
//lpLineDevCaps->dwUUICallInfoSize = 0;
// We do not support dial parameters setting
//
//lpLineDevCaps->MinDialParams.dwDialPause = 0;
//lpLineDevCaps->MinDialParams.dwDialSpeed = 0;
//lpLineDevCaps->MinDialParams.dwDigitDuration = 0;
//lpLineDevCaps->MinDialParams.dwWaitForDialtone = 0;
//lpLineDevCaps->MaxDialParams.dwDialPause = 0;
//lpLineDevCaps->MaxDialParams.dwDialSpeed = 0;
//lpLineDevCaps->MaxDialParams.dwDigitDuration = 0;
//lpLineDevCaps->MaxDialParams.dwWaitForDialtone = 0;
//lpLineDevCaps->DefaultDialParams.dwDialPause = 0;
//lpLineDevCaps->DefaultDialParams.dwDialSpeed = 0;
//lpLineDevCaps->DefaultDialParams.dwDigitDuration = 0;
//lpLineDevCaps->DefaultDialParams.dwWaitForDialtone = 0;
// We do not support terminal settings
//
//lpLineDevCaps->dwNumTerminals = 0;
//lpLineDevCaps->dwTerminalCapsSize = 0;
//lpLineDevCaps->dwTerminalCapsOffset = 0;
//lpLineDevCaps->dwTerminalTextEntrySize = 0;
//lpLineDevCaps->dwTerminalTextSize = 0;
//lpLineDevCaps->dwTerminalTextOffset = 0;
lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL;
// We will return this in the dev specific section:
// struct {
// DWORD dwContents; Set to 1 (indicates containing key)
// DWORD dwKeyOffset; Offset to key from start of this structure (8)
// BYTE rgby[...]; place containing null-terminated registry key.
// }
// Since we need to store a DWORD, we need to calculate how much padding we need
// to add so that we are DWORD aligned. Only add padding if necessary.
cbDWORDPad = lpLineDevCaps->dwUsedSize % sizeof(DWORD);
if (cbDWORDPad >= 0)
{
cbDWORDPad = sizeof(DWORD) - cbDWORDPad;
}
#ifdef UNICODE
cbDeviceKeyLen = WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDriverKey,
-1,
NULL,
0,
NULL,
NULL);
if (cbDeviceKeyLen == 0)
{
TSPPRINTF1("TSPI_lineGetDevCaps: WideCharToMultiByte() returned %d",
GetLastError());
}
else
{
cbDeviceKeyLen++;
cbDevSpecificLen = sizeof(DWORD) +
sizeof(DWORD) +
cbDeviceKeyLen;
#else // UNICODE
cbDevSpecificLen = sizeof(DWORD) +
sizeof(DWORD) +
lstrlen(pLineDev->szDriverKey) + 1;
#endif // UNICODE
lpLineDevCaps->dwNeededSize += cbDevSpecificLen + cbDWORDPad;
// Copy path if it fits
if (cbAvailMem >= cbDevSpecificLen + cbDWORDPad)
{
lpLineDevCaps->dwUsedSize += cbDWORDPad;
*(LPDWORD)((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize) = 1;
*(LPDWORD)((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize + sizeof(DWORD)) = 8;
#ifdef UNICODE
WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDriverKey,
-1,
(LPSTR)((LPBYTE)lpLineDevCaps
+ lpLineDevCaps->dwUsedSize
+ sizeof(DWORD)
+ sizeof(DWORD)),
cbDeviceKeyLen,
NULL,
NULL);
#else // UNICODE
lstrcpy((LPSTR)lpLineDevCaps
+ lpLineDevCaps->dwUsedSize
+ sizeof(DWORD)
+ sizeof(DWORD),
pLineDev->szDriverKey);
#endif // UNICODE
lpLineDevCaps->dwDevSpecificSize = cbDevSpecificLen;
lpLineDevCaps->dwDevSpecificOffset = lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbDevSpecificLen;
cbAvailMem -= cbDevSpecificLen + cbDWORDPad;
}
#ifdef UNICODE
}
#endif // UNICODE
cbDevClassLen = sizeof(g_szzClassList);
lpLineDevCaps->dwNeededSize += cbDevClassLen;
// Copy device classes if it fits
if (cbAvailMem >= cbDevClassLen)
{
hmemcpy((LPBYTE)lpLineDevCaps + lpLineDevCaps->dwUsedSize,
g_szzClassList, cbDevClassLen);
lpLineDevCaps->dwDeviceClassesSize = cbDevClassLen;
lpLineDevCaps->dwDeviceClassesOffset= lpLineDevCaps->dwUsedSize;
lpLineDevCaps->dwUsedSize += cbDevClassLen;
cbAvailMem -= cbDevClassLen;
}
lRet = ERROR_SUCCESS;
end:
if (pLineDev) RELEASE_LINEDEV(pLineDev);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetDevCaps,
&dwDeviceID,
lRet
);
DBG_DDI_EXIT("TSPI_lineGetDevCaps", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetIcon(DWORD dwDeviceID,
// LPCSTR lpszDeviceClass,
// LPHICON lphIcon)
//
// Functions: Get the icon handle for the specific line
//
// Return: ERROR_SUCCESS if successful
// LINEERR_NODEVICE if the line ID is invalid
// LINEERR_OPERATIONFAILED if the parameter is invalid
//****************************************************************************
LONG TSPIAPI TSPI_lineGetIcon(DWORD dwDeviceID,
LPCTSTR lpszDeviceClass,
LPHICON lphIcon)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineGetIcon");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetIcon,
&dwDeviceID
);
// Validate the buffer pointer
//
if (lphIcon == NULL)
{
goto end;
}
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
lRet = LINEERR_NODEVICE;
goto end;
}
// Have we loaded this icon?
//
if (pLineDev->hIcon == NULL)
{
int iIcon;
switch (pLineDev->bDeviceType)
{
case DT_NULL_MODEM: iIcon = IDI_NULL; break;
case DT_EXTERNAL_MODEM: iIcon = IDI_EXT_MDM; break;
case DT_INTERNAL_MODEM: iIcon = IDI_INT_MDM; break;
case DT_PCMCIA_MODEM: iIcon = IDI_PCM_MDM; break;
default: iIcon = -1; break;
};
// Nope! load one and save it
//
if (iIcon != -1)
{
pLineDev->hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(iIcon));
};
};
// Return this icon (even if NULL, return SUCCESS. tapi will provide
// a default icon if necessary)
//
*lphIcon = pLineDev->hIcon;
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetIcon,
&dwDeviceID,
lRet
);
DBG_DDI_EXIT("TSPI_lineGetIcon", lRet);
return lRet;
}
//****************************************************************************
//************************** The Line Specific Calls**************************
//****************************************************************************
//****************************************************************************
// LONG TSPIAPI TSPI_lineOpen(DWORD dwDeviceID,
// HTAPILINE htLine,
// LPHDRVLINE lphdLine,
// DWORD dwTSPIVersion,
// LINEEVENT lineEventProc)
//
// Functions: Associates the modem CB with the TAPI handle.
//
// Returns: ERROR_SUCCESS if a modem CB can be associated
// LINEERR_NODEVICE if the device ID cannot be found
//
// History:
// Mon 17-Apr-1995 14:45:00 -by- Viroon Touranachun [viroont]
// Created.
//
//****************************************************************************
LONG TSPIAPI TSPI_lineOpen(DWORD dwDeviceID,
HTAPILINE htLine,
LPHDRVLINE lphdLine,
DWORD dwTSPIVersion,
LINEEVENT lineEventProc)
{
PLINEDEV pLineDev=NULL;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineOpen");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineOpen,
&dwDeviceID
);
// Check the version
//
VALIDATE_VERSION(dwTSPIVersion);
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
lRet = LINEERR_NODEVICE;
goto end;
}
#ifdef DYNA_ADDREMOVE
// Fail if out-of-service
//
if (pLineDev->fdwResources&LINEDEVFLAGS_OUTOFSERVICE)
{
lRet = LINEERR_RESOURCEUNAVAIL;
goto end;
}
#endif // DYNA_ADDREMOVE
// Update the line device
//
*lphdLine = (HDRVLINE)pLineDev;
if (TRACINGENABLED())
{
lineEventProc = traceSetEventProc(lineEventProc);
}
#ifdef DEBUG
DebugSetEventProc(lineEventProc);
pLineDev->lpfnEvent = DebugEventProc;
#else // DEBUG
pLineDev->lpfnEvent = lineEventProc;
#endif // DEBUG
pLineDev->htLine = htLine;
// If we need to re-read the default comm config, we do this here.
if (pLineDev->fUpdateDefaultCommConfig)
{
DPRINTF("Updating DefaultCommConfig");
RefreshDefaultCommConfig(pLineDev);
pLineDev->fUpdateDefaultCommConfig = FALSE; // We set it to false
// regardless of whether
// the refresh succeeded
// or not.
}
lRet = ERROR_SUCCESS;
end:
if (pLineDev) {RELEASE_LINEDEV(pLineDev);}
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineOpen,
&dwDeviceID,
lRet
);
DBG_DDI_EXIT("TSPI_lineOpen", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetDefaultMediaDetection(HDRVLINE hdLine,
// DWORD dwMediaModes)
//
// Functions: Enables the opened line to detect an inbound call.
//
// Returns: ERROR_SUCCESS if a modem CB can be associated
// LINEERR_INVALIDHANDLE if the line handle is invalid
// LINEERR_INVALMEDIAMODE if requested media modes not supported
//
// History:
// Mon 17-Apr-1995 14:45:00 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
LONG TSPIAPI TSPI_lineSetDefaultMediaDetection(HDRVLINE hdLine,
DWORD dwMediaModes)
{
PLINEDEV pLineDev;
DWORD dwRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDL_ENTER("TSPI_lineSetDefaultMediaDetection");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetDefaultMediaDetection,
&hdLine
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
dwRet = LINEERR_INVALLINEHANDLE;
goto end;
}
// Check the requested modes. There must be only our media modes.
// In addition, don't allow INTERACTIVEVOICE to be used for listening.
//
if (dwMediaModes & ~(pLineDev->dwMediaModes & ~LINEMEDIAMODE_INTERACTIVEVOICE))
{
dwRet = LINEERR_INVALMEDIAMODE;
}
else
{
// If no detection and a detection is requested
//
if ((pLineDev->dwDetMediaModes == 0) && (dwMediaModes))
{
// Open the modem
//
if ((dwRet = DevlineOpen(pLineDev)) == ERROR_SUCCESS)
{
// Start listening to the port
//
if ((dwRet = DevlineDetectCall(pLineDev)) == ERROR_SUCCESS)
{
// The modem is now monitoring the call.
// Remember the media mode we are monitoring
//
pLineDev->dwDetMediaModes = dwMediaModes;
}
else
{
// We cannot monitor the call, close the modem
//
DevlineClose(pLineDev);
}
}
else
{
// Handle the case of LINEERR_ALLOCATED being returned from DevlineOpen,
// indicating there is an already open port.
//
if (LINEERR_ALLOCATED == dwRet)
{
// Just remember the detection media modes.
// return ERROR_SUCCESS because we will comeback to monitor the call
// when this call is deallocated.
//
pLineDev->dwDetMediaModes = dwMediaModes;
dwRet = ERROR_SUCCESS;
}
}
}
else
{
// we are stopping detection OR adjusting the detection media modes
//
pLineDev->dwDetMediaModes = dwMediaModes;
// If we are detecting and requested not to,
// just close the line if it isn't in use
//
if (pLineDev->dwDetMediaModes &&
dwMediaModes == 0 &&
(DEVST_PORTLISTENING == pLineDev->DevState ||
DEVST_PORTLISTENINIT == pLineDev->DevState))
{
// Close the modem
//
DevlineClose(pLineDev);
#ifdef UNDER_CONSTRUCTION
// If we are out of service
//
if (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)
{
// Clean up the control block
//
DevlineDisabled (pLineDev);
};
#endif // UNDER_CONSTRUCTION
};
dwRet = ERROR_SUCCESS;
};
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetDefaultMediaDetection,
&hdLine,
dwRet
);
DBG_HDL_EXIT("TSPI_lineSetDefaultMediaDetection", dwRet);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineConditionalMediaDetection(HDRVLINE hdLine,
// DWORD dwMediaModes,
// LPLINECALLPARAMS const lpCallParams)
//
// Functions: Determines whether the line supports the specified media modes
// and call parameters.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALLINEHANDLE the line handle is invalid
// LINEERR_INVALMEDIAMODE the media mode or the call parameter is
// not supported
// LINEERR_RESOURCEUNAVAIL the outbound call cannot be made
//****************************************************************************
LONG TSPIAPI TSPI_lineConditionalMediaDetection(HDRVLINE hdLine,
DWORD dwMediaModes,
LPLINECALLPARAMS const lpCallParams)
{
PLINEDEV pLineDev;
DWORD dwRet = ERROR_SUCCESS;
DBG_HDL_ENTER("TSPI_lineConditionalMediaDetection");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineConditionalMediaDetection,
&hdLine
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
dwRet = LINEERR_INVALLINEHANDLE;
goto end;
}
// Check the requested modes. There must be only our media modes.
//
if (dwMediaModes & ~pLineDev->dwMediaModes)
{
dwRet = LINEERR_INVALMEDIAMODE;
}
else
{
// Check the call paramaters
//
if ((lpCallParams->dwBearerMode & (~pLineDev->dwBearerModes)) ||
(lpCallParams->dwMediaMode & (~pLineDev->dwMediaModes)) ||
(lpCallParams->dwAddressMode & (~LINEADDRESSMODE_ADDRESSID)))
{
dwRet = LINEERR_INVALMEDIAMODE;
};
};
if (dwRet == ERROR_SUCCESS)
{
// Check whether we can make an outbound call
//
if (pLineDev->dwCall & (CALL_ACTIVE | CALL_ALLOCATED))
{
dwRet = LINEERR_RESOURCEUNAVAIL;
};
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineConditionalMediaDetection,
&hdLine,
dwRet
);
DBG_HDL_EXIT("TSPI_lineConditionalMediaDetection", dwRet);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetID(HDRVLINE hdLine,
// DWORD dwAddressID,
// HDRVCALL hdCall,
// DWORD dwSelect,
// LPVARSTRING lpDeviceID,
// LPCSTR lpszDeviceClass,
// HANDLE hTargetProcess)
//
// Functions: Get the line information based on the requested class
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALADDRESSID the address ID is invalid
// LINEERR_INVALLINEHANDLE the line handle is invalid
// LINEERR_INVALCALLHANDLE the call handle is invalid
// LINEERR_OPERATIONFAILED the device class is not supported
//****************************************************************************
LONG TSPIAPI TSPI_lineGetID(HDRVLINE hdLine,
DWORD dwAddressID,
HDRVCALL hdCall,
DWORD dwSelect,
LPVARSTRING lpDeviceID,
LPCTSTR lpszDeviceClass,
HANDLE hTargetProcess)
{
PLINEDEV pLineDev;
UINT cbPort;
UINT idClass;
DWORD dwRet = ERROR_SUCCESS;
#ifdef DEBUG
if (dwSelect == LINECALLSELECT_LINE)
{
DBG_HDL_ENTER("TSPI_lineGetID");
}
else
{
if (dwSelect == LINECALLSELECT_CALL)
{
DBG_HDC_ENTER("TSPI_lineGetID");
}
else
{
DBG_ENTER("TSPI_lineGetID");
}
}
#endif // DEBUG
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetID,
&hdLine
);
switch (dwSelect)
{
case LINECALLSELECT_ADDRESS:
if (dwAddressID != 0)
{
dwRet = LINEERR_INVALADDRESSID;
goto end;
}
// FALLTHROUGH
case LINECALLSELECT_LINE:
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
dwRet = LINEERR_INVALLINEHANDLE;
goto end;
}
break;
case LINECALLSELECT_CALL:
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet = LINEERR_INVALCALLHANDLE;
goto end;
}
break;
default:
dwRet = LINEERR_OPERATIONFAILED;
goto end;
}
#ifdef DYNA_ADDREMOVE
// Fail if out-of-service
//
if (pLineDev->fdwResources&LINEDEVFLAGS_OUTOFSERVICE)
{
dwRet = LINEERR_RESOURCEUNAVAIL;
goto end;
}
#endif // DYNA_ADDREMOVE
// Determine the device class
//
for (idClass = 0; idClass < MAX_SUPPORT_CLASS; idClass++)
{
if (lstrcmpi(lpszDeviceClass, aGetID[idClass].szClassName) == 0)
break;
};
// Determine the required size
//
switch (idClass)
{
case TAPILINE:
cbPort = sizeof(DWORD);
break;
case COMM:
#ifdef UNICODE
cbPort = WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDeviceName,
-1,
NULL,
0,
NULL,
NULL);
if (cbPort == 0)
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
cbPort = lstrlen(pLineDev->szDeviceName) + 1;
#endif // UNICODE
break;
case COMMMODEM:
#ifdef UNICODE
cbPort = WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDeviceName,
-1,
NULL,
0,
NULL,
NULL) + sizeof(DWORD);
if (cbPort == 0)
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
cbPort = lstrlen(pLineDev->szDeviceName) + 1 + sizeof(DWORD);
#endif // UNICODE
break;
case COMMMODEMPORTNAME:
{
HKEY hKey;
DWORD dwSize, dwType;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
pLineDev->szDriverKey,
&hKey))
{
// Check on the length of an ANSI return string.
if (ERROR_SUCCESS == RegQueryValueExA(hKey,
szAttachedTo,
NULL,
&dwType,
NULL,
&dwSize))
{
cbPort = dwSize;
}
else
{
// If we aren't attached to anything return a null string.
cbPort = 1;
}
RegCloseKey(hKey);
}
}
break;
case NDIS:
#ifdef UNICODE
cbPort = WideCharToMultiByte(CP_ACP,
0,
g_szDeviceClass,
-1,
NULL,
0,
NULL,
NULL) + sizeof(DWORD);
if (cbPort == 0)
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
cbPort = sizeof(g_szDeviceClass) + sizeof(DWORD);
#endif // UNICODE
break;
default:
dwRet = LINEERR_OPERATIONFAILED;
break;
};
// Calculate the require size
//
// lpDeviceID->dwUsedSize = sizeof(VARSTRING); // TAPI fills it in.
//
if (dwRet == ERROR_SUCCESS)
{
// BUG! BUG! Do we need to check dwTotalSize?
// Tue 03-Oct-1995 09:23:01 -by- Viroon Touranachun [viroont]
//
// Return the structure information
//
lpDeviceID->dwNeededSize = sizeof(VARSTRING) + cbPort;
lpDeviceID->dwStringFormat = aGetID[idClass].dwFormat;
ASSERT(lpDeviceID->dwUsedSize == sizeof(VARSTRING));
// Check for the extra space for more information
//
if ((lpDeviceID->dwTotalSize - lpDeviceID->dwUsedSize) >=
cbPort)
{
// We have enough space to return valid information
//
lpDeviceID->dwStringSize = cbPort;
lpDeviceID->dwStringOffset = sizeof(VARSTRING);
lpDeviceID->dwUsedSize += cbPort;
// Return the useful information
//
switch (idClass)
{
// "tapi/line" returns the line device ID
//
case TAPILINE:
{
LPDWORD lpdwDeviceID;
lpdwDeviceID = (LPDWORD)(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
*lpdwDeviceID = pLineDev->dwID;
break;
}
// "comm" returns the modem name
//
case COMM:
{
#ifdef UNICODE
if (0 ==
WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDeviceName,
-1,
(LPSTR)((LPBYTE)lpDeviceID + sizeof(VARSTRING)),
cbPort,
NULL,
NULL))
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
lstrcpyn(((LPSTR)lpDeviceID) + sizeof(VARSTRING),
pLineDev->szDeviceName, cbPort);
#endif // UNICODE
break;
}
// "comm/datamodem" returns the Win32 comm handle (if any) and
// the modem name
//
case COMMMODEM:
{
LPHANDLE lphClientDevice;
// Duplicate a Win32 comm handle (for the caller process)
//
lphClientDevice = (LPHANDLE)
(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
if (pLineDev->hDevice != INVALID_DEVICE)
{
HANDLE hDevice;
TCHAR szPort[MAXDEVICENAME+1];
// Initialize szPort to be "\\.\"
lstrcpy(szPort, cszDevicePrefix);
// Concatenate FriendlyName onto szPort to form "\\.\Modem Name"
lstrcat(szPort, pLineDev->szDeviceName);
hDevice = CreateFile(szPort,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
if (!DuplicateHandle(GetCurrentProcess(),
hDevice,
hTargetProcess,
lphClientDevice,
0L, FALSE,
DUPLICATE_SAME_ACCESS))
{
DPRINTF1("lineGetID DuplicateHandle() failed! (%d)",
GetLastError);
*lphClientDevice = NULL;
dwRet = LINEERR_OPERATIONFAILED;
}
CloseHandle(hDevice);
}
else
{
DPRINTF1("lineGetID CreateFile() failed! (%d)", GetLastError);
*lphClientDevice = NULL;
}
}
else
{
*lphClientDevice = NULL;
};
// Also return the modem name
//
#ifdef UNICODE
if (ERROR_SUCCESS == dwRet &&
0 == WideCharToMultiByte(CP_ACP,
0,
pLineDev->szDeviceName,
-1,
(LPSTR)(lphClientDevice + 1),
cbPort - sizeof(DWORD),
NULL,
NULL))
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
lstrcpy((LPSTR)(lphClientDevice+1), pLineDev->szDeviceName);
#endif // UNICODE
break;
}
// "comm/datamodem/portname" returns the name of the port the modem
// is attached to or the modem name itself if not attached to anything.
//
case COMMMODEMPORTNAME:
{
HKEY hKey;
DWORD dwSize, dwType;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
pLineDev->szDriverKey,
&hKey))
{
dwSize = cbPort;
// Check on the length of an ANSI return string.
if (ERROR_SUCCESS != RegQueryValueExA(
hKey,
szAttachedTo,
NULL,
&dwType,
(LPBYTE)lpDeviceID
+ sizeof(VARSTRING),
&dwSize))
{
// If we aren't attached to anything return a null
// string.
*(LPSTR)((LPBYTE)lpDeviceID + sizeof(VARSTRING)) = 0;
}
RegCloseKey(hKey);
}
}
break;
// "ndis" returns the device class and handle which can be used by
// the NDIS device driver
//
case NDIS:
{
LPDWORD lpdwDeviceID;
// The NDIS device handle is ring_0 comm handle
//
lpdwDeviceID = (LPDWORD)(((LPBYTE)lpDeviceID) + sizeof(VARSTRING));
DPRINTF ("Someone wants NDIS class info. Return ring-3 comm handle.");
*lpdwDeviceID = (DWORD)(pLineDev->hDevice != INVALID_DEVICE ?
pLineDev->hDevice : NULL);
// Also returns the device class
//
#ifdef UNICODE
if (0 == WideCharToMultiByte(CP_ACP,
0,
g_szDeviceClass,
-1,
(LPSTR)(lpdwDeviceID + 1),
cbPort,
NULL,
NULL))
{
dwRet = LINEERR_OPERATIONFAILED;
}
#else // UNICODE
lstrcpy((LPSTR)(lpdwDeviceID+1), g_szDeviceClass);
#endif // UNICODE
break;
}
};
};
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetID,
&hdLine,
dwRet
);
#ifdef DEBUG
if (dwSelect == LINECALLSELECT_LINE)
{
DBG_HDL_EXIT("TSPI_lineGetID", dwRet);
}
else
{
if (dwSelect == LINECALLSELECT_CALL)
{
DBG_HDC_EXIT("TSPI_lineGetID", dwRet);
}
else
{
DBG_EXIT_UL("TSPI_lineGetID", dwRet);
}
}
#endif // DEBUG
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetLineDevStatus(HDRVLINE hdLine,
// LPLINEDEVSTATUS lpLineDevStatus)
//
// Functions: Get the current state of the line device
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALLINEHANDLE if invalid line handle
//****************************************************************************
LONG TSPIAPI TSPI_lineGetLineDevStatus(HDRVLINE hdLine,
LPLINEDEVSTATUS lpLineDevStatus)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetLineDevStatus,
&hdLine
);
DBG_HDL_ENTER("TSPI_lineGetLineDevStatus");
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
lRet = LINEERR_INVALLINEHANDLE;
goto end;
}
// No device specifc portion
//
lpLineDevStatus->dwUsedSize = sizeof(LINEDEVSTATUS);
lpLineDevStatus->dwNeededSize = sizeof(LINEDEVSTATUS);
// Call information
//
//lpLineDevStatus->dwNumOnHoldCalls = 0;
//lpLineDevStatus->dwNumOnHoldPendCalls = 0;
//lpLineDevStatus->dwNumCallCompletions = 0;
//lpLineDevStatus->dwRingMode = 0;
//
if (pLineDev->dwCall & CALL_ACTIVE)
{
lpLineDevStatus->dwNumActiveCalls = 1;
lpLineDevStatus->dwLineFeatures = 0;
lpLineDevStatus->dwAvailableMediaModes = 0;
}
else
{
lpLineDevStatus->dwNumActiveCalls = 0;
if (pLineDev->dwCall & CALL_ALLOCATED)
{
lpLineDevStatus->dwLineFeatures = 0;
lpLineDevStatus->dwAvailableMediaModes = 0;
}
else
{
lpLineDevStatus->dwLineFeatures = LINEFEATURE_MAKECALL;
lpLineDevStatus->dwAvailableMediaModes = pLineDev->dwMediaModes;
};
};
// Line hardware information
//
lpLineDevStatus->dwSignalLevel = 0x0000FFFF;
lpLineDevStatus->dwBatteryLevel = 0x0000FFFF;
lpLineDevStatus->dwRoamMode = LINEROAMMODE_UNAVAIL;
// Always allow TAPI calls
//
lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED;
if (!(pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE))
{
lpLineDevStatus->dwDevStatusFlags |= LINEDEVSTATUSFLAGS_INSERVICE;
};
// No terminal settings
//
//lpLineDevStatus->dwTerminalModesSize = 0;
//lpLineDevStatus->dwTerminalModesOffset = 0;
// No device specific
//
//lpLineDevStatus->dwDevSpecificSize = 0;
//lpLineDevStatus->dwDevSpecificOffset = 0;
//lpLineDevStatus->dwAppInfoSize = 0;
//lpLineDevStatus->dwAppInfoOffset = 0;
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetLineDevStatus,
&hdLine,
lRet
);
DBG_HDL_EXIT("TSPI_lineGetLineDevStatus", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetNumAddressIDs(HDRVLINE hdLine,
// LPDWORD lpNumAddressIDs)
//
// Functions: Get the number of addresses for the line handle
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALLINEHANDLE if invalid line handle
//****************************************************************************
LONG TSPIAPI TSPI_lineGetNumAddressIDs(HDRVLINE hdLine,
LPDWORD lpNumAddressIDs)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDL_ENTER("TSPI_lineGetNumAddressIDs");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetNumAddressIDs,
&hdLine
);
// Validate the line handle
//
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
lRet = LINEERR_INVALLINEHANDLE;
goto end;
}
RELEASE_LINEDEV(pLineDev);
// We only support one address.
//
*lpNumAddressIDs = 1;
lRet = ERROR_SUCCESS;
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetNumAddressIDs,
&hdLine,
lRet
);
DBG_HDL_EXIT("TSPI_lineGetNumAddressIDs", lRet);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetStatusMessages(HDRVLINE hdLine,
// DWORD dwLineStates,
// DWORD dwAddressStates)
//
// Functions: Sets the line notification mask
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALLINEHANDLE if invalid line handle
//****************************************************************************
LONG TSPIAPI TSPI_lineSetStatusMessages(HDRVLINE hdLine,
DWORD dwLineStates,
DWORD dwAddressStates)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDL_ENTER("TSPI_lineSetStatusMessages");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetStatusMessages,
&hdLine
);
// Validate the line handle
//
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
lRet = LINEERR_INVALLINEHANDLE;
goto end;
}
RELEASE_LINEDEV(pLineDev);
// BUG! BUG! we should record this settings and filter the notification
// based on this settings.
//
// Mon 14-Feb-1994 13:09:57 -by- Viroon Touranachun [viroont]
//
lRet = ERROR_SUCCESS;
end:
DBG_HDL_EXIT("TSPI_lineSetStatusMessages", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetStatusMessages,
&hdLine,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineClose(HDRVLINE hdLine)
//
// Functions: Closes the line
//
// Return: ERROR_SUCCESS if successful
// LINEERR_OPERATIONFAILED if invalid line handle
//****************************************************************************
LONG TSPIAPI TSPI_lineClose(HDRVLINE hdLine)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED;
DBG_HDL_ENTER("TSPI_lineClose");
TRACE3(IDEVENT_TSPFN_ENTER, IDFROM_TSPI_lineClose, &hdLine);
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
goto end;
}
// Make sure that we do not leave anything open
//
DevlineClose(pLineDev);
#ifdef UNDER_CONSTRUCTION
// If we are out of service, clean up and bail out
//
if (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)
{
DevlineDisabled (pLineDev);
}
else
#endif // UNDER_CONSTRUCTION
{
// Reinit the line device
//
NullifyLineDevice(pLineDev);
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet=ERROR_SUCCESS;
end:
TRACE4(IDEVENT_TSPFN_EXIT, IDFROM_TSPI_lineClose, &hdLine, lRet);
DBG_HDL_EXIT("TSPI_lineClose", lRet);
return lRet;
}
//****************************************************************************
//************************** The Call Specific Calls**************************
//****************************************************************************
//****************************************************************************
// LONG TSPIAPI TSPI_lineMakeCall(DRV_REQUESTID dwRequestID,
// HDRVLINE hdLine,
// HTAPICALL htCall,
// LPHDRVCALL lphdCall,
// LPCSTR lpszDestAddress,
// DWORD dwCountryCode,
// LPLINECALLPARAMS const lpCallParams)
//
// Functions: Sets up the outbound call and start dialing if the destination
// number is provided
//
// Return: A positive pending ID number (dwRequestID) if successful
// LINEERR_INVALLINEHANDLE An invalid line handle
// LINEERR_CALLUNAVAIL No call is available for the line
// LINEERR_INVALMEDIAMODE The requested mediamode is invalid
// LINEERR_INVALBEARERMODE The requested bearer mode is invalid
// LINEERR_OPERATIONFAILED The call cannot be made.
//****************************************************************************
LONG TSPIAPI TSPI_lineMakeCall(DRV_REQUESTID dwRequestID,
HDRVLINE hdLine,
HTAPICALL htCall,
LPHDRVCALL lphdCall,
LPCTSTR lpszDestAddress,
DWORD dwCountryCode,
LPLINECALLPARAMS const lpCallParams)
{
PLINEDEV pLineDev;
DWORD dwRet=LINEERR_OPERATIONFAILED;
BOOL fDoTakeover = FALSE;
DBG_HDL_ENTER("TSPI_lineMakeCall");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineMakeCall,
&dwRequestID
);
// Validate the line handle
//
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
DBG_HDL_EXIT("TSPI_lineMakeCall", LINEERR_INVALLINEHANDLE);
dwRet = LINEERR_INVALLINEHANDLE;
goto end;
}
// See if we have a free call struct.
if (pLineDev->dwCall & CALL_ALLOCATED)
{
RELEASE_LINEDEV(pLineDev);
DBG_HDL_EXIT("TSPI_lineMakeCall", LINEERR_CALLUNAVAIL);
dwRet = LINEERR_CALLUNAVAIL;
goto end;
};
ASSERT(pLineDev->pDevCfg != NULL);
// If a line config is specified in the callparams struct,
// set it to the line
//
if (lpCallParams)
{
if (lpCallParams->dwDeviceConfigSize != 0)
{
// We will tolerate the failure if the line config in the callparams
// struct cannot be set.
//
TSPI_lineSetDevConfig(pLineDev->dwID,
(LPVOID)(((LPBYTE)lpCallParams)+lpCallParams->dwDeviceConfigOffset),
lpCallParams->dwDeviceConfigSize,
lpCallParams->dwDeviceClassSize == 0 ? szNull :
(LPTSTR)(((LPBYTE)lpCallParams)+lpCallParams->dwDeviceClassOffset));
};
};
// Set default dwDialOptions
pLineDev->dwDialOptions = pLineDev->dwModemOptions & MDM_MASK; // Get modem caps
pLineDev->dwDialOptions &= ((LPMODEMSETTINGS)&((LPCOMMCONFIG)&(pLineDev->pDevCfg
->commconfig))->wcProviderData[0])->dwPreferredModemOptions;
// Examine LINECALLPARAMS, if present
if (lpCallParams)
{
// verify media mode
#ifdef VOICEVIEW
if ((lpCallParams->dwMediaMode & ~pLineDev->dwMediaModes) ||
(lpCallParams->dwMediaMode == LINEMEDIAMODE_VOICEVIEW) )
#else
if (lpCallParams->dwMediaMode & ~pLineDev->dwMediaModes)
#endif // VOICEVIEW
{
RELEASE_LINEDEV(pLineDev);
DBG_HDL_EXIT("TSPI_lineMakeCall", LINEERR_INVALMEDIAMODE);
dwRet = LINEERR_INVALMEDIAMODE;
goto end;
}
// verify bearer mode
if ((~pLineDev->dwBearerModes) & lpCallParams->dwBearerMode)
{
RELEASE_LINEDEV(pLineDev);
DBG_HDL_EXIT("TSPI_lineMakeCall", LINEERR_INVALBEARERMODE);
dwRet = LINEERR_INVALBEARERMODE;
goto end;
}
// Takeover via BEARERMODE_PASSTHROUGH?
if (lpCallParams->dwBearerMode & LINEBEARERMODE_PASSTHROUGH)
{
fDoTakeover = TRUE;
}
else
{
// We're not requested to do passthrough. Can we actually
// dial the media modes without passthrough? This is to
// prevent G3FAX from being used without passthrough...
// (We can only dial with DATAMODEM or INTERACTIVEVOICE)
if ((lpCallParams->dwMediaMode &
(LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_INTERACTIVEVOICE)) == 0)
{
RELEASE_LINEDEV(pLineDev);
DBG_HDL_EXIT("TSPI_lineMakeCall", LINEERR_INVALMEDIAMODE);
dwRet = LINEERR_INVALMEDIAMODE;
goto end;
}
}
pLineDev->dwCurBearerModes = lpCallParams->dwBearerMode;
pLineDev->dwCurMediaModes = lpCallParams->dwMediaMode;
if (!(lpCallParams->dwCallParamFlags & LINECALLPARAMFLAGS_IDLE))
{
// Turn on blind dialing
pLineDev->dwDialOptions |= MDM_BLIND_DIAL;
}
// BUGBUG: should preserve other fields of call params for call info
}
else
{
// set the standard defaults
// use INTERACTIVEVOICE if we can, else use DATAMODEM
if (pLineDev->dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE)
{
pLineDev->dwCurMediaModes = LINEMEDIAMODE_INTERACTIVEVOICE;
}
else
{
ASSERT(pLineDev->dwMediaModes & LINEMEDIAMODE_DATAMODEM);
pLineDev->dwCurMediaModes = LINEMEDIAMODE_DATAMODEM;
}
pLineDev->dwCurBearerModes = pLineDev->dwBearerModes & ~LINEBEARERMODE_PASSTHROUGH;
}
// Do we have a phone number?
//
if (!fDoTakeover)
{
if (IS_NULL_MODEM(pLineDev) || (GETOPTIONS(pLineDev->pDevCfg) & MANUAL_DIAL))
{
if (IS_NULL_MODEM(pLineDev)) {
*pLineDev->szAddress = '\0';
} else {
dwRet = ValidateAddress(pLineDev, lpszDestAddress, pLineDev->szAddress);
if (ERROR_SUCCESS != dwRet) {
*pLineDev->szAddress = '\0';
}
}
// Turn on blind dialing if this is MANUAL_DIAL.
if (GETOPTIONS(pLineDev->pDevCfg) & MANUAL_DIAL)
{
pLineDev->dwDialOptions |= MDM_BLIND_DIAL;
}
}
else
{
if (lpszDestAddress != NULL) {
//
// Validate lpszDestAddress and get the processed form of it.
//
dwRet = ValidateAddress(pLineDev, lpszDestAddress, pLineDev->szAddress);
if (ERROR_SUCCESS != dwRet)
{
RELEASE_LINEDEV(pLineDev);
DBG_HDL_EXIT("TSPI_lineMakeCall", dwRet);
goto end;
}
if (pLineDev->szAddress[0] == '\0') {
//
// If it is an empty string, I don't think we would expect dial tone
//
pLineDev->dwDialOptions |= MDM_BLIND_DIAL;
}
} else {
//
// if the lpszDestAddress was NULL then we just want to do a
// dialtone detection. We expect that lineDial will be called.
// Setting the szAddress to ";" will do this.
//
lstrcpyA(pLineDev->szAddress, szSemicolon);
}
}
}
// Record the call attributes
pLineDev->htCall = htCall;
pLineDev->dwCall = CALL_ALLOCATED;
pLineDev->dwCallState = LINECALLSTATE_UNKNOWN;
pLineDev->dwCallStateMode = 0;
*lphdCall = (HDRVCALL)pLineDev;
// We allow to make call to an already-opened line if the line is monitoring
// a call. Therefore, if the line is in use, try making a call. The make-call
// routine will return error if the state is not appropriate.
//
if (((dwRet = DevlineOpen(pLineDev)) == ERROR_SUCCESS) ||
(dwRet == LINEERR_ALLOCATED))
{
if (fDoTakeover)
{
if (pLineDev->DevState == DEVST_PORTLISTENING ||
pLineDev->DevState == DEVST_PORTLISTENINIT ||
pLineDev->DevState == DEVST_DISCONNECTED)
{
// do we go into passthrough now or later?
if (pLineDev->DevState == DEVST_PORTLISTENINIT)
{
// later
// 7/96 JosephJ: BUGBUG: why is dwPendingType not changed???
SetPendingRequest(
pLineDev,
dwRequestID,
pLineDev->dwPendingType
);
}
else
{
// now
UnimodemSetPassthrough(pLineDev, PASSTHROUGH_ON);
pLineDev->DevState = DEVST_CONNECTED;
(*gfnCompletionCallback)(dwRequestID, 0L);
NEW_CALLSTATE(pLineDev, LINECALLSTATE_CONNECTED, 0);
}
pLineDev->fTakeoverMode = TRUE;
dwRet = dwRequestID;
}
else
{
dwRet = LINEERR_OPERATIONFAILED;
}
}
else
{
// We can make a call here
SetPendingRequest(pLineDev, dwRequestID, PENDING_LINEMAKECALL);
if (((dwRet = DevlineMakeCall(pLineDev)) != ERROR_SUCCESS) &&
(IS_TAPI_ERROR(dwRet)))
{
DevlineClose(pLineDev);
}
}
};
// Check if an error occurs
//
if (IS_TAPI_ERROR(dwRet))
{
ClearPendingRequest(pLineDev);
// Deallocate the call from this line
//
pLineDev->htCall = NULL;
pLineDev->dwCall = 0;
*lphdCall = NULL;
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineMakeCall,
&dwRequestID,
dwRet
);
DBG_HDL_EXIT("TSPI_lineMakeCall", dwRet);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineDial(DRV_REQUESTID dwRequestID,
// HDRVCALL hdCall,
// LPCSTR lpszDestAddress,
// DWORD dwCountryCode)
//
// Functions: Dials numbers for the outbound call.
//
// Return: A positive pending ID number (dwRequestID) if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
// LINEERR_INVALCALLSTATE Cannot dial in the current call state
//****************************************************************************
LONG TSPIAPI TSPI_lineDial(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCTSTR lpszDestAddress,
DWORD dwCountryCode)
{
PLINEDEV pLineDev;
DWORD dwRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineDial");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineDial,
&dwRequestID
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// We can only be called when our devstate is DEVST_PORTCONNECTWAITFORLINEDIAL.
if (pLineDev->DevState != DEVST_PORTCONNECTWAITFORLINEDIAL)
{
RELEASE_LINEDEV(pLineDev);
dwRet = LINEERR_INVALCALLSTATE;
goto end;
}
// Validate lpszDestAddress and get the processed form of it.
dwRet = ValidateAddress(pLineDev, lpszDestAddress, pLineDev->szAddress);
if (ERROR_SUCCESS != dwRet)
{
RELEASE_LINEDEV(pLineDev);
goto end;
}
// Now we can dial the number
//
if ((dwRet = DevlineDial(pLineDev)) == ERROR_SUCCESS)
{
SetPendingRequest(pLineDev, dwRequestID, PENDING_LINEDIAL);
dwRet = dwRequestID;
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDC_EXIT("TSPI_lineDial", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineDial,
&dwRequestID,
dwRet
);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineAccept(DRV_REQUESTID dwRequestID,
// HDRVCALL hdCall,
// LPCSTR lpsUserUserInfo,
// DWORD dwSize)
//
// Functions: Accepts the offered inbound call
//
// Return: A positive pending ID number (dwRequestID) if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
// LINEERR_INVALCALLSTATE Cannot accept call in the current state
//****************************************************************************
LONG TSPIAPI TSPI_lineAccept(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize)
{
PLINEDEV pLineDev;
DWORD dwRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineAccept");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineAccept,
&dwRequestID
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet = LINEERR_INVALCALLHANDLE;
goto end;
}
if (LINECALLSTATE_OFFERING == pLineDev->dwCallState)
{
NEW_CALLSTATE(pLineDev, LINECALLSTATE_ACCEPTED, 0);
(*gfnCompletionCallback)(dwRequestID, 0L);
dwRet = dwRequestID;
}
else
{
dwRet = LINEERR_INVALCALLSTATE;
}
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDC_EXIT("TSPI_lineAccept", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineAccept,
&dwRequestID,
dwRet
);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineAnswer(HDRVCALL hdCall,
// LPCSTR lpsUserUserInfo,
// DWORD dwSize)
//
// Functions: Answers the offered/accepted inbound call.
//
// Return: A positive pending ID number (dwRequestID) if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
// LINEERR_INVALCALLSTATE Cannot answer call in the current state
// LINEERR_OPERATIONUNAVAIL Invalid mediamode
//****************************************************************************
LONG TSPIAPI TSPI_lineAnswer(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize)
{
PLINEDEV pLineDev;
DWORD dwRet = ERROR_SUCCESS;
DBG_HDC_ENTER("TSPI_lineAnswer");
//DPRINTF1("TSPI_lineAnswer(dwReq=0x%08lx)", dwRequestID);
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineAnswer,
&dwRequestID
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// Validate the line capabilties and call state
//
if (pLineDev->fTakeoverMode)
{
dwRet = LINEERR_OPERATIONUNAVAIL;
}
else
{
if (LINECALLSTATE_OFFERING != pLineDev->dwCallState &&
LINECALLSTATE_ACCEPTED != pLineDev->dwCallState)
{
dwRet = LINEERR_INVALCALLSTATE;
}
else
{
// We can only answer DATAMODEM calls
if ((pLineDev->dwCurMediaModes & LINEMEDIAMODE_DATAMODEM) == 0)
{
dwRet = LINEERR_OPERATIONUNAVAIL;
};
};
};
// If the call state and line capabilties are validated
//
if (dwRet == ERROR_SUCCESS)
{
// Answer the call
//
SetPendingRequest(pLineDev, dwRequestID, PENDING_LINEANSWER);
dwRet = DevlineAnswer(pLineDev);
// If we can answer the call
//
if (!IS_TAPI_ERROR(dwRet))
{
// Notify an async completion since we have grabbed the line
//
(*gfnCompletionCallback)(pLineDev->dwPendingID, 0L);
// if a lineAccept wasn't done, notify acceptance
if (LINECALLSTATE_OFFERING == pLineDev->dwCallState)
{
NEW_CALLSTATE(pLineDev, LINECALLSTATE_ACCEPTED, 0);
};
};
ClearPendingRequest(pLineDev);
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDC_EXIT("TSPI_lineAnswer", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineAnswer,
&dwRequestID,
dwRet
);
//DPRINTF2("TSPI_lineAnswer(dwReq=0x%08lx, ret = 0x%08lx)", dwRequestID, dwRet);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetCallStatus(HDRVCALL hdCall,
// LPLINECALLSTATUS lpCallStatus)
//
// Functions: Get the current status of the call.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineGetCallStatus(HDRVCALL hdCall,
LPLINECALLSTATUS lpCallStatus)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineGetCallStatus");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetCallStatus,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// Current call information
//
lpCallStatus->dwCallState = pLineDev->dwCallState;
lpCallStatus->dwCallStateMode = pLineDev->dwCallStateMode;
// if we are in takeover mode, disallow all dwCallFeatures
//
if (!pLineDev->fTakeoverMode)
{
switch(lpCallStatus->dwCallState)
{
case LINECALLSTATE_OFFERING:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_ACCEPT |
LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DROP;
// We can only answer if a possible media mode is DATAMODEM.
if (pLineDev->dwCurMediaModes & LINEMEDIAMODE_DATAMODEM)
{
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_ANSWER;
}
break;
case LINECALLSTATE_DIALTONE:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_DIALING:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
if (DEVST_PORTCONNECTWAITFORLINEDIAL == pLineDev->DevState)
{
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_DIAL;
}
break;
case LINECALLSTATE_ACCEPTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DROP;
// We can only answer if a possible media mode is DATAMODEM.
if (pLineDev->dwCurMediaModes & LINEMEDIAMODE_DATAMODEM)
{
lpCallStatus->dwCallFeatures |= LINECALLFEATURE_ANSWER;
}
break;
case LINECALLSTATE_CONNECTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_UNKNOWN:
case LINECALLSTATE_PROCEEDING:
case LINECALLSTATE_DISCONNECTED:
lpCallStatus->dwCallFeatures = LINECALLFEATURE_DROP;
break;
case LINECALLSTATE_IDLE:
default:
lpCallStatus->dwCallFeatures = 0;
break;
};
}
else
{
// Make sure the call feature are all off
//
ASSERT(lpCallStatus->dwCallFeatures == 0);
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
DBG_HDC_EXIT("TSPI_lineGetCallStatus", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetCallStatus,
&hdCall,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetCallInfo(HDRVCALL hdCall,
// LPLINECALLINFO lpCallInfo)
//
// Functions: Get the current call information
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineGetCallInfo(HDRVCALL hdCall,
LPLINECALLINFO lpCallInfo)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineGetCallInfo");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetCallInfo,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
//lpCallInfo->dwUsedSize = sizeof(LINECALLINFO);
//lpCallInfo->dwNeededSize = sizeof(LINECALLINFO);
ASSERT(lpCallInfo->dwNeededSize == sizeof(LINECALLINFO));
lpCallInfo->dwLineDeviceID = pLineDev->dwID;
lpCallInfo->dwAddressID = 0;
lpCallInfo->dwBearerMode = pLineDev->dwCurBearerModes;
lpCallInfo->dwRate = pLineDev->dwNegotiatedRate;
lpCallInfo->dwMediaMode = pLineDev->dwCurMediaModes;
lpCallInfo->dwAppSpecific = pLineDev->dwAppSpecific;
//lpCallInfo->dwCallID = 0;
//lpCallInfo->dwRelatedCallID = 0;
//lpCallInfo->dwCallParamFlags= 0;
lpCallInfo->dwCallStates = pLineDev->dwCall & CALL_INBOUND ?
(LINECALLSTATE_IDLE |
LINECALLSTATE_OFFERING |
LINECALLSTATE_ACCEPTED |
LINECALLSTATE_CONNECTED |
LINECALLSTATE_DISCONNECTED |
LINECALLSTATE_UNKNOWN) :
(LINECALLSTATE_IDLE |
LINECALLSTATE_DIALTONE |
LINECALLSTATE_DIALING |
LINECALLSTATE_PROCEEDING |
LINECALLSTATE_CONNECTED |
LINECALLSTATE_DISCONNECTED |
LINECALLSTATE_UNKNOWN);
//lpCallInfo->DialParams.dwDialPause = 0;
//lpCallInfo->DialParams.dwDialSpeed = 0;
//lpCallInfo->DialParams.dwDigitDuration = 0;
//lpCallInfo->DialParams.dwWaitForDialtone = 0;
lpCallInfo->dwOrigin = pLineDev->dwCall & CALL_INBOUND ?
LINECALLORIGIN_INBOUND :
LINECALLORIGIN_OUTBOUND;
lpCallInfo->dwReason = pLineDev->dwCall & CALL_INBOUND ?
LINECALLREASON_UNAVAIL :
LINECALLREASON_DIRECT;
//lpCallInfo->dwCompletionID = 0;
//lpCallInfo->dwCountryCode = 0;
//lpCallInfo->dwTrunk = 0;
lpCallInfo->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL;
//lpCallInfo->dwCallerIDSize = 0;
//lpCallInfo->dwCallerIDOffset = 0;
//lpCallInfo->dwCallerIDNameSize = 0;
//lpCallInfo->dwCallerIDNameOffset = 0;
lpCallInfo->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL;
//lpCallInfo->dwCalledIDSize = 0;
//lpCallInfo->dwCalledIDOffset = 0;
//lpCallInfo->dwCalledIDNameSize = 0;
//lpCallInfo->dwCalledIDNameOffset= 0;
lpCallInfo->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
//lpCallInfo->dwConnectedIDSize = 0;
//lpCallInfo->dwConnectedIDOffset = 0;
//lpCallInfo->dwConnectedIDNameSize = 0;
//lpCallInfo->dwConnectedIDNameOffset = 0;
lpCallInfo->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
//lpCallInfo->dwRedirectionIDSize = 0;
//lpCallInfo->dwRedirectionIDOffset = 0;
//lpCallInfo->dwRedirectionIDNameSize = 0;
//lpCallInfo->dwRedirectionIDNameOffset = 0;
lpCallInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
//lpCallInfo->dwRedirectingIDSize = 0;
//lpCallInfo->dwRedirectingIDOffset = 0;
//lpCallInfo->dwRedirectingIDNameSize = 0;
//lpCallInfo->dwRedirectingIDNameOffset = 0;
//lpCallInfo->dwDisplaySize = 0;
//lpCallInfo->dwDisplayOffset = 0;
//lpCallInfo->dwUserUserInfoSize = 0;
//lpCallInfo->dwUserUserInfoOffset = 0;
//lpCallInfo->dwHighLevelCompSize = 0;
//lpCallInfo->dwHighLevelCompOffset = 0;
//lpCallInfo->dwLowLevelCompSize = 0;
//lpCallInfo->dwLowLevelCompOffset = 0;
//lpCallInfo->dwChargingInfoSize = 0;
//lpCallInfo->dwChargingInfoOffset = 0;
//lpCallInfo->dwTerminalModesSize = 0;
//lpCallInfo->dwTerminalModesOffset = 0;
//lpCallInfo->dwDevSpecificSize = 0;
//lpCallInfo->dwDevSpecificOffset = 0;
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
DBG_HDC_EXIT("TSPI_lineGetCallInfo", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetCallInfo,
&hdCall,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetCallAddressID(HDRVCALL hdCall,
// LPDWORD lpdwAddressID)
//
// Functions: get the address ID for the call
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineGetCallAddressID(HDRVCALL hdCall,
LPDWORD lpdwAddressID)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineGetCallAddressID");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetCallAddressID,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// There is but a single address where a call may exist.
//
*lpdwAddressID = 0;
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
DBG_HDC_EXIT("TSPI_lineGetCallAddressID", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetCallAddressID,
&hdCall,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineDrop(DRV_REQUESTID dwRequestID,
// HDRVCALL hdCall,
// LPCSTR lpsUserUserInfo,
// DWORD dwSize)
//
// Functions: Transition a call to the DISCONNECTED state.
//
// Return: A positive pending ID number (dwRequestID) if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineDrop(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
LPCSTR lpsUserUserInfo,
DWORD dwSize)
{
PLINEDEV pLineDev;
DWORD dwRet=LINEERR_OPERATIONFAILED;
DBG_HDC_ENTER("TSPI_lineDrop");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineDrop,
&dwRequestID
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet= LINEERR_INVALCALLHANDLE;
goto end;
}
if (pLineDev->fTakeoverMode)
{
UnimodemSetPassthrough(pLineDev, PASSTHROUGH_OFF);
pLineDev->fTakeoverMode = FALSE;
pLineDev->DevState = DEVST_DISCONNECTED;
NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0);
(*gfnCompletionCallback)(dwRequestID, 0L);
dwRet = dwRequestID;
}
else
{
if (DEVST_DISCONNECTING == pLineDev->DevState) {
TSPPRINTF("LineDrop called more than once");
(*gfnCompletionCallback)(dwRequestID, 0L);
dwRet = dwRequestID;
} else {
// Disconnect the line
//
SetPendingRequest(pLineDev, dwRequestID, PENDING_LINEDROP);
if ((dwRet = DevlineDrop(pLineDev, FALSE)) != ERROR_SUCCESS)
{
ClearPendingRequest(pLineDev);
}
else
{
dwRet = dwRequestID;
}
}
}
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineDrop,
&dwRequestID,
dwRet
);
DBG_HDC_EXIT("TSPI_lineDrop", dwRet);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineCloseCall(HDRVCALL hdCall)
//
// Functions: Terminates the call.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineCloseCall(HDRVCALL hdCall)
{
PLINEDEV pLineDev;
DWORD dwRet = ERROR_SUCCESS;
DBG_HDC_ENTER("TSPI_lineCloseCall");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineCloseCall,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
dwRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// Turn off takeover mode
//
if (pLineDev->fTakeoverMode)
{
UnimodemSetPassthrough(pLineDev, PASSTHROUGH_OFF);
pLineDev->fTakeoverMode = FALSE;
pLineDev->DevState = DEVST_DISCONNECTED;
}
else
{
// If the line is not disconnected, drop the line synchronously
//
if (pLineDev->DevState != DEVST_DISCONNECTED)
{
DevlineDrop(pLineDev, TRUE);
pLineDev->DevState = DEVST_DISCONNECTED;
};
};
//
// kill lights if it is running
//
if (pLineDev->hLights != NULL) {
TerminateModemLight(pLineDev->hLights);
pLineDev->hLights = NULL;
}
NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0);
// At this point, the call has already been dropped,
// so we only need to deallocate it.
//
pLineDev->htCall = NULL;
pLineDev->dwCall = 0L;
pLineDev->dwNegotiatedRate = 0L;
// If we need to detect the line, reopen and listen to the line
if ((pLineDev->dwDetMediaModes) && !(pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE))
{
if ((dwRet = DevlineDetectCall(pLineDev)) != ERROR_SUCCESS) {
//
// init failed
//
//ASSERT(0);
DPRINTF("***ASSERTION FAILED**** (init failed)");
pLineDev->LineClosed=TRUE;
//
// tell the app
//
(*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE,
0L, 0L, 0L);
}
}
else
{
// No need to detect the line, just close it.
//
DevlineClose(pLineDev);
#ifdef UNDER_CONSTRUCTION
// If we are out of service, clean up and bail out
//
if (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)
{
DevlineDisabled(pLineDev);
};
#endif //UNDER_CONSTRUCTION
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDC_EXIT("TSPI_lineCloseCall", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineCloseCall,
&hdCall,
dwRet
);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetMediaMode(HDRVCALL hdCall,
// DWORD dwMediaMode)
//
// Functions: Set the mediamode for the call.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
// LINEERR_INVALMEDIAMODE An invalid media mode
//****************************************************************************
LONG TSPIAPI TSPI_lineSetMediaMode(HDRVCALL hdCall,
DWORD dwMediaMode)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineSetMediaMode");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetMediaMode,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
// Check the requested modes. There must be only our media modes
//
if (dwMediaMode & ~pLineDev->dwMediaModes)
{
lRet = LINEERR_INVALMEDIAMODE;
}
else
{
// If the specifed media mode is not equal to the current media mode
//
if (pLineDev->dwCurMediaModes != dwMediaMode)
{
// Set it and notify the media mode change
//
pLineDev->dwCurMediaModes = dwMediaMode;
(*(pLineDev->lpfnEvent))(pLineDev->htLine, pLineDev->htCall,
LINE_CALLINFO, LINECALLINFOSTATE_MEDIAMODE,
0, 0);
};
lRet = ERROR_SUCCESS;
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDC_EXIT("TSPI_lineSetMediaMode", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetMediaMode,
&hdCall,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetAppSpecific()
//
// Functions: Set the application specific value for the call.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
//****************************************************************************
LONG TSPIAPI TSPI_lineSetAppSpecific(HDRVCALL hdCall,
DWORD dwAppSpecific)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineSetAppSpecific");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetAppSpecific,
&hdCall
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
pLineDev->dwAppSpecific = dwAppSpecific;
(*(pLineDev->lpfnEvent))(pLineDev->htLine, pLineDev->htCall,
LINE_CALLINFO, LINECALLINFOSTATE_APPSPECIFIC,
0, 0);
RELEASE_LINEDEV(pLineDev);
lRet = ERROR_SUCCESS;
end:
DBG_HDC_EXIT("TSPI_lineSetAppSpecific", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetAppSpecific,
&hdCall,
lRet
);
return lRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineSetCallParams()
//
// Functions: Set the call parameters.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALCALLHANDLE An invalid call handle
// LINEERR_INVALMEDIAMODE An invalid media mode
// LINEERR_INVALCALLSTATE Call params can't be set in this state
//****************************************************************************
LONG TSPIAPI TSPI_lineSetCallParams(DRV_REQUESTID dwRequestID,
HDRVCALL hdCall,
DWORD dwBearerMode,
DWORD dwMinRate,
DWORD dwMaxRate,
LPLINEDIALPARAMS const lpDialParams)
{
PLINEDEV pLineDev;
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDC_ENTER("TSPI_lineSetCallParams");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineSetCallParams,
&dwRequestID
);
if ((pLineDev = GetCBfromHandle ((DWORD)hdCall)) == NULL)
{
lRet = LINEERR_INVALCALLHANDLE;
goto end;
}
if (LINECALLSTATE_OFFERING != pLineDev->dwCallState &&
LINECALLSTATE_ACCEPTED != pLineDev->dwCallState &&
LINECALLSTATE_CONNECTED != pLineDev->dwCallState)
{
RELEASE_LINEDEV(pLineDev);
lRet = LINEERR_INVALCALLSTATE;
goto end;
}
// verify bearer mode
if ((~pLineDev->dwBearerModes) & dwBearerMode)
{
RELEASE_LINEDEV(pLineDev);
lRet = LINEERR_INVALBEARERMODE;
goto end;
}
// Check bearermode for passthrough
if (dwBearerMode & LINEBEARERMODE_PASSTHROUGH)
{
// are we not already in passthrough?
if (!(pLineDev->dwCurBearerModes & LINEBEARERMODE_PASSTHROUGH))
{
// we need to switch into passthrough
pLineDev->dwCurBearerModes = LINEBEARERMODE_PASSTHROUGH;
UnimodemSetPassthrough(pLineDev, PASSTHROUGH_ON);
pLineDev->fTakeoverMode = TRUE;
pLineDev->DevState = DEVST_CONNECTED;
if (LINECALLSTATE_CONNECTED != pLineDev->dwCallState)
{
NEW_CALLSTATE(pLineDev, LINECALLSTATE_CONNECTED, 0);
}
}
}
else
{
// are we already in passthrough?
if (pLineDev->dwCurBearerModes & LINEBEARERMODE_PASSTHROUGH)
{
// we need to switch out of passthrough
UnimodemSetPassthrough(pLineDev, PASSTHROUGH_OFF_BUT_CONNECTED);
pLineDev->fTakeoverMode = FALSE;
if (pLineDev->DevState == DEVST_CONNECTED) {
//
// Start monitoring the remote disconnection here
//
UnimodemMonitorDisconnect(pLineDev);
}
}
pLineDev->dwCurBearerModes = dwBearerMode;
}
RELEASE_LINEDEV(pLineDev);
(*gfnCompletionCallback)(dwRequestID, 0L);
lRet = dwRequestID;
end:
DBG_HDC_EXIT("TSPI_lineSetCallParams", lRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineSetCallParams,
&dwRequestID,
lRet
);
return lRet;
}
//****************************************************************************
//************************ The Address Specific Calls*************************
//****************************************************************************
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetAddressCaps(DWORD dwDeviceID,
// DWORD dwAddressID,
// DWORD dwTSPIVersion,
// DWORD dwExtVersion,
// LPLINEADDRESSCAPS lpAddressCaps)
//
// Functions: Get the capabilities of the specified address.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_NODEVICE An invalid device id
// LINEERR_INVALADDRESSID An invalid address id for the line
//****************************************************************************
LONG TSPIAPI TSPI_lineGetAddressCaps(DWORD dwDeviceID,
DWORD dwAddressID,
DWORD dwTSPIVersion,
DWORD dwExtVersion,
LPLINEADDRESSCAPS lpAddressCaps)
{
PLINEDEV pLineDev;
DWORD dwRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_DDI_ENTER("TSPI_lineGetAddressCaps");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetAddressCaps,
&dwDeviceID
);
// Validate the version number
//
VALIDATE_VERSION(dwTSPIVersion);
// Validate the device ID
//
if ((pLineDev = GetCBfromID(dwDeviceID)) == NULL)
{
dwRet = LINEERR_NODEVICE;
goto end;
}
// Validate the address ID
//
if(dwAddressID != 0)
{
dwRet = LINEERR_INVALADDRESSID;
}
else
{
// Check to see if we have enough memory in the structure.
//
//lpAddressCaps->dwAddressSize = 0;
//lpAddressCaps->dwAddressOffset = 0;
// Other device attributes
//
//lpAddressCaps->dwDevSpecificSize = 0;
//lpAddressCaps->dwDevSpecificOffset = 0;
//
lpAddressCaps->dwLineDeviceID = dwDeviceID;
lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE;
//lpAddressCaps->dwAddressStates = 0;
lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_APPSPECIFIC | LINECALLINFOSTATE_MEDIAMODE;
lpAddressCaps->dwCallerIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwCalledIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwConnectedIDFlags = LINECALLPARTYID_UNAVAIL;
lpAddressCaps->dwRedirectionIDFlags = LINECALLPARTYID_UNAVAIL;
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_UNAVAIL |
LINEDISCONNECTMODE_NORMAL |
LINEDISCONNECTMODE_BUSY |
LINEDISCONNECTMODE_NODIALTONE |
LINEDISCONNECTMODE_NOANSWER;
lpAddressCaps->dwMaxNumActiveCalls = 1;
//lpAddressCaps->dwMaxNumOnHoldCalls = 0;
//lpAddressCaps->dwMaxNumOnHoldPendingCalls = 0;
//lpAddressCaps->dwMaxNumConference = 0;
//lpAddressCaps->dwMaxNumTransConf = 0;
// dwAddrCapFlags
if (!IS_NULL_MODEM(pLineDev))
{
lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_DIALED;
}
if (pLineDev->fPartialDialing)
{
lpAddressCaps->dwAddrCapFlags |= LINEADDRCAPFLAGS_PARTIALDIAL;
}
lpAddressCaps->dwCallFeatures = LINECALLFEATURE_ANSWER |
LINECALLFEATURE_ACCEPT |
LINECALLFEATURE_SETCALLPARAMS |
LINECALLFEATURE_DIAL |
LINECALLFEATURE_DROP;
//lpAddressCaps->dwRemoveFromConfCaps = 0;
//lpAddressCaps->dwRemoveFromConfState = 0;
//lpAddressCaps->dwTransferModes = 0;
//lpAddressCaps->dwParkModes = 0;
//lpAddressCaps->dwForwardModes = 0;
//lpAddressCaps->dwMaxForwardEntries = 0;
//lpAddressCaps->dwMaxSpecificEntries = 0;
//lpAddressCaps->dwMinFwdNumRings = 0;
//lpAddressCaps->dwMaxFwdNumRings = 0;
//lpAddressCaps->dwMaxCallCompletions = 0;
//lpAddressCaps->dwCallCompletionConds = 0;
//lpAddressCaps->dwCallCompletionModes = 0;
//lpAddressCaps->dwNumCompletionMessages = 0;
//lpAddressCaps->dwCompletionMsgTextEntrySize = 0;
//lpAddressCaps->dwCompletionMsgTextSize = 0;
//lpAddressCaps->dwCompletionMsgTextOffset = 0;
lpAddressCaps->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
//lpAddressCaps->dwPredictiveAutoTransferStates = 0;
//lpAddressCaps->dwAgentStates = 0;
//lpAddressCaps->dwNextAgentStates = 0;
//lpAddressCaps->dwMaxNumAgentEntries = 0;
//lpAddressCaps->dwNumCallTreatments = 0;
//lpAddressCaps->dwCallTreatmentListSize = 0;
//lpAddressCaps->dwCallTreatmentListOffset = 0;
lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS);
lpAddressCaps->dwNeededSize = lpAddressCaps->dwUsedSize +
sizeof(LINEADDRESSCAPS);
if (lpAddressCaps->dwTotalSize >= lpAddressCaps->dwNeededSize)
{
lpAddressCaps->dwUsedSize += sizeof(g_szzClassList);
lpAddressCaps->dwDeviceClassesSize = sizeof(g_szzClassList);
lpAddressCaps->dwDeviceClassesOffset= sizeof(LINEADDRESSCAPS);
hmemcpy((LPBYTE)(lpAddressCaps+1), g_szzClassList,
sizeof(g_szzClassList));
}
else
{
lpAddressCaps->dwDeviceClassesSize = 0;
lpAddressCaps->dwDeviceClassesOffset= 0;
};
//lpAddressCaps->dwMaxCallDataSize = 0;
//lpAddressCaps->dwCallFeatures2 = 0;
//lpAddressCaps->dwMaxNoAnswerTimeout= 0;
//lpAddressCaps->dwConnectedModes = 0;
//lpAddressCaps->dwOfferingModes = 0;
lpAddressCaps->dwAvailableMediaModes = pLineDev->dwMediaModes;
dwRet = ERROR_SUCCESS;
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_DDI_EXIT("TSPI_lineGetAddressCaps", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetAddressCaps,
&dwDeviceID,
dwRet
);
return dwRet;
}
//****************************************************************************
// LONG TSPIAPI TSPI_lineGetAddressStatus(HDRVLINE hdLine,
// DWORD dwAddressID,
// LPLINEADDRESSSTATUS lpAddressStatus)
//
// Functions: Get the current status of the specified address for the line.
//
// Return: ERROR_SUCCESS if successful
// LINEERR_INVALLINEHANDLE An invalid line handle
// LINEERR_INVALADDRESSID An invalid address id for the line
//****************************************************************************
LONG TSPIAPI TSPI_lineGetAddressStatus(HDRVLINE hdLine,
DWORD dwAddressID,
LPLINEADDRESSSTATUS lpAddressStatus)
{
PLINEDEV pLineDev;
DWORD dwRet = LINEERR_OPERATIONFAILED; // assume failure
DBG_HDL_ENTER("TSPI_lineGetAddressStatus");
TRACE3(
IDEVENT_TSPFN_ENTER,
IDFROM_TSPI_lineGetAddressStatus,
&hdLine
);
// Validate the line handle
//
if ((pLineDev = GetCBfromHandle ((DWORD)hdLine)) == NULL)
{
dwRet = LINEERR_INVALLINEHANDLE;
goto end;
}
// Validate the address ID
//
if (dwAddressID != 0)
{
dwRet = LINEERR_INVALADDRESSID;
}
else
{
//lpAddressStatus->dwUsedSize = sizeof(LINEADDRESSSTATUS);
//lpAddressStatus->dwNeededSize = sizeof(LINEADDRESSSTATUS);
ASSERT(lpAddressStatus->dwNeededSize == sizeof(LINEADDRESSSTATUS));
if (pLineDev->dwCall & CALL_ACTIVE)
{
lpAddressStatus->dwNumInUse = 1;
lpAddressStatus->dwNumActiveCalls = (pLineDev->dwCallState != LINECALLSTATE_IDLE) ?
1 : 0;
}
else
{
lpAddressStatus->dwNumInUse = 0;
lpAddressStatus->dwNumActiveCalls = 0;
};
lpAddressStatus->dwAddressFeatures = (pLineDev->dwCall & CALL_ALLOCATED) ?
0 : LINEADDRFEATURE_MAKECALL;
//lpAddressStatus->dwNumOnHoldCalls = 0;
//lpAddressStatus->dwNumOnHoldPendCalls = 0;
//lpAddressStatus->dwNumRingsNoAnswer = 0;
//lpAddressStatus->dwForwardNumEntries = 0;
//lpAddressStatus->dwForwardSize = 0;
//lpAddressStatus->dwForwardOffset = 0;
//lpAddressStatus->dwTerminalModesSize = 0;
//lpAddressStatus->dwTerminalModesOffset= 0;
//lpAddressStatus->dwDevSpecificSize = 0;
//lpAddressStatus->dwDevSpecificOffset = 0;
dwRet=ERROR_SUCCESS;
};
// Release the modem CB
//
RELEASE_LINEDEV(pLineDev);
end:
DBG_HDL_EXIT("TSPI_lineGetAddressStatus", dwRet);
TRACE4(
IDEVENT_TSPFN_EXIT,
IDFROM_TSPI_lineGetAddressStatus,
&hdLine,
dwRet
);
return dwRet;
}
void SetPendingRequest(
PLINEDEV pLineDev,
DWORD dwRequestID,
DWORD dwRequestOp
)
{
ASSERT(pLineDev->dwPendingID == INVALID_PENDINGID);
ASSERT(pLineDev->dwPendingType == INVALID_PENDINGOP);
pLineDev->dwPendingID = dwRequestID;
pLineDev->dwPendingType = dwRequestOp;
}
void ClearPendingRequest(
PLINEDEV pLineDev
)
{
pLineDev->dwPendingID = INVALID_PENDINGID;
pLineDev->dwPendingType = INVALID_PENDINGOP;
}