From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/unimodem/tapisp/cfgdlg.c | 578 +++++ private/unimodem/tapisp/client.c | 47 + private/unimodem/tapisp/common.c | 572 +++++ private/unimodem/tapisp/common.h | 88 + private/unimodem/tapisp/debug.c | 214 ++ private/unimodem/tapisp/debug.h | 182 ++ private/unimodem/tapisp/devioctl.c | 1160 +++++++++ private/unimodem/tapisp/log.c | 425 ++++ private/unimodem/tapisp/log.rc | 153 ++ private/unimodem/tapisp/logids.h | 134 + private/unimodem/tapisp/makefile | 6 + private/unimodem/tapisp/manual.c | 170 ++ private/unimodem/tapisp/mcxapi.c | 591 +++++ private/unimodem/tapisp/mcxioctl.h | 107 + private/unimodem/tapisp/mcxp.h | 530 ++++ private/unimodem/tapisp/mcxrw.c | 649 +++++ private/unimodem/tapisp/mcxstate.c | 4675 +++++++++++++++++++++++++++++++++++ private/unimodem/tapisp/mcxutil.c | 781 ++++++ private/unimodem/tapisp/mdmasyn.c | 1325 ++++++++++ private/unimodem/tapisp/mdmutil.c | 1581 ++++++++++++ private/unimodem/tapisp/modem.c | 532 ++++ private/unimodem/tapisp/ov_pool.c | 234 ++ private/unimodem/tapisp/rcids.h | 75 + private/unimodem/tapisp/resource.h | 17 + private/unimodem/tapisp/resource.rc | 324 +++ private/unimodem/tapisp/sources | 82 + private/unimodem/tapisp/talkdrop.c | 137 + private/unimodem/tapisp/terminal.c | 890 +++++++ private/unimodem/tapisp/timer.c | 527 ++++ private/unimodem/tapisp/timer.h | 51 + private/unimodem/tapisp/traceids.h | 130 + private/unimodem/tapisp/tracing.c | 696 ++++++ private/unimodem/tapisp/tracing.h | 192 ++ private/unimodem/tapisp/umdminit.c | 2792 +++++++++++++++++++++ private/unimodem/tapisp/umdmspi.h | 425 ++++ private/unimodem/tapisp/unimdm.c | 3399 +++++++++++++++++++++++++ private/unimodem/tapisp/unimdm.def | 147 ++ private/unimodem/tapisp/unimdm.h | 182 ++ private/unimodem/tapisp/unimdm.rc | 18 + private/unimodem/tapisp/unimdm.rcv | 31 + private/unimodem/tapisp/wndthrd.c | 1538 ++++++++++++ private/unimodem/tapisp/wndthrd.h | 83 + 42 files changed, 26470 insertions(+) create mode 100644 private/unimodem/tapisp/cfgdlg.c create mode 100644 private/unimodem/tapisp/client.c create mode 100644 private/unimodem/tapisp/common.c create mode 100644 private/unimodem/tapisp/common.h create mode 100644 private/unimodem/tapisp/debug.c create mode 100644 private/unimodem/tapisp/debug.h create mode 100644 private/unimodem/tapisp/devioctl.c create mode 100644 private/unimodem/tapisp/log.c create mode 100644 private/unimodem/tapisp/log.rc create mode 100644 private/unimodem/tapisp/logids.h create mode 100644 private/unimodem/tapisp/makefile create mode 100644 private/unimodem/tapisp/manual.c create mode 100644 private/unimodem/tapisp/mcxapi.c create mode 100644 private/unimodem/tapisp/mcxioctl.h create mode 100644 private/unimodem/tapisp/mcxp.h create mode 100644 private/unimodem/tapisp/mcxrw.c create mode 100644 private/unimodem/tapisp/mcxstate.c create mode 100644 private/unimodem/tapisp/mcxutil.c create mode 100644 private/unimodem/tapisp/mdmasyn.c create mode 100644 private/unimodem/tapisp/mdmutil.c create mode 100644 private/unimodem/tapisp/modem.c create mode 100644 private/unimodem/tapisp/ov_pool.c create mode 100644 private/unimodem/tapisp/rcids.h create mode 100644 private/unimodem/tapisp/resource.h create mode 100644 private/unimodem/tapisp/resource.rc create mode 100644 private/unimodem/tapisp/sources create mode 100644 private/unimodem/tapisp/talkdrop.c create mode 100644 private/unimodem/tapisp/terminal.c create mode 100644 private/unimodem/tapisp/timer.c create mode 100644 private/unimodem/tapisp/timer.h create mode 100644 private/unimodem/tapisp/traceids.h create mode 100644 private/unimodem/tapisp/tracing.c create mode 100644 private/unimodem/tapisp/tracing.h create mode 100644 private/unimodem/tapisp/umdminit.c create mode 100644 private/unimodem/tapisp/umdmspi.h create mode 100644 private/unimodem/tapisp/unimdm.c create mode 100644 private/unimodem/tapisp/unimdm.def create mode 100644 private/unimodem/tapisp/unimdm.h create mode 100644 private/unimodem/tapisp/unimdm.rc create mode 100644 private/unimodem/tapisp/unimdm.rcv create mode 100644 private/unimodem/tapisp/wndthrd.c create mode 100644 private/unimodem/tapisp/wndthrd.h (limited to 'private/unimodem/tapisp') diff --git a/private/unimodem/tapisp/cfgdlg.c b/private/unimodem/tapisp/cfgdlg.c new file mode 100644 index 000000000..bc3c0fa18 --- /dev/null +++ b/private/unimodem/tapisp/cfgdlg.c @@ -0,0 +1,578 @@ +//**************************************************************************** +// +// Module: Unimdm.tsp +// File: cfgdlg.c +// Content: This file contains the moudle configuration. +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// History: +// Wed 04-Aug-1993 09:20:24 -by- Viroon Touranachun [viroont] +// Ported from TAPI's atsp +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" +#include "wndthrd.h" +#include +#include +#include "rcids.h" + +#ifdef UNDER_CONSTRUCTION +#include "umdmhelp.h" + +#endif //UNDER_CONSTRUCTION + +// Private prototype exported by MODEMUI.DLL +typedef DWORD (WINAPI *LPFNMDMDLG)(LPWSTR, HWND, LPCOMMCONFIG, LPVOID, DWORD); + +LRESULT UnimdmSettingProc (HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); + +//**************************************************************************** +//*********************** The Device ID Specific Calls************************ +//**************************************************************************** + +//**************************************************************************** +// void DevCfgDialog(HWND hwndOwner, +// DWORD dwType, +// DWORD dwDevCaps, +// DWORD dwOptions, +// LPDEVCFG lpDevCfg) +// +// Functions: Displays the modem property pages +// +// Return: None. +//**************************************************************************** + +void DevCfgDialog (HWND hwndOwner, + PPROPREQ pPropReq, + LPDEVCFG lpDevCfg) +{ + HMODULE hMdmUI; + PROPSHEETPAGE psp; + DCDI dcdi; + LPFNMDMDLG lpfnMdmDlg; + UINT uNumWideChars; +#ifndef UNICODE + LPWSTR lpwszDeviceName; + + // Convert pPropReq->szDeviceName (Ansi) to lpwszDeviceName (Unicode) + + // Get number of wide chars to alloc + uNumWideChars = MultiByteToWideChar(CP_ACP, + MB_PRECOMPOSED, + pPropReq->szDeviceName, + -1, + NULL, + 0); + + // Alloc with room for terminator + lpwszDeviceName = (LPWSTR)LocalAlloc(LPTR, + (1 + uNumWideChars) * sizeof(WCHAR)); + if (NULL == lpwszDeviceName) + { + return; + } + + // Do the conversion and call modemui.dll if it succeeds. + if (MultiByteToWideChar(CP_ACP, + MB_PRECOMPOSED, + pPropReq->szDeviceName, + -1, + lpwszDeviceName, + uNumWideChars)) + { +#endif // UNICODE + + // Load the modemui library + // + if ((hMdmUI = LoadLibrary(TEXT("modemui.dll"))) != NULL) + { + if ((lpfnMdmDlg = (LPFNMDMDLG)GetProcAddress(hMdmUI, + "Mdm_CommConfigDialog")) + != NULL) + { + dcdi.dwType = pPropReq->dwMdmType; + dcdi.dwDevCaps = pPropReq->dwMdmCaps; + dcdi.dwOptions = pPropReq->dwMdmOptions; + dcdi.lpDevCfg = lpDevCfg; + + // Prepare our own property page + // + psp.dwSize = sizeof(PROPSHEETPAGE); + psp.dwFlags = 0; + psp.hInstance = ghInstance; + psp.pszTemplate = MAKEINTRESOURCE(IDD_TERMINALSETTING); + psp.pfnDlgProc = UnimdmSettingProc; + psp.lParam = (LPARAM)(LPDCDI)&dcdi; + psp.pfnCallback = NULL; + + // Bring up property sheets for modems and get the updated commconfig + // +#ifdef UNICODE + (*lpfnMdmDlg)(pPropReq->szDeviceName, hwndOwner, +#else // UNICODE + (*lpfnMdmDlg)(lpwszDeviceName, hwndOwner, +#endif // UNICODE + (LPCOMMCONFIG)&(lpDevCfg->commconfig), + &psp , 1); + }; + FreeLibrary(hMdmUI); + }; +#ifndef UNICODE + }; + LocalFree(lpwszDeviceName); +#endif // UNICODE + return; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TUISPI_lineConfigDialog( +// TUISPIDLLCALLBACK pfnUIDLLCallback, +// DWORD dwDeviceID, +// HWND hwndOwner, +// LPCSTR lpszDeviceClass) +// +// Functions: Allows the user to edit the modem configuration through UI. The +// modification is applied to the line immediately. +// +// Return: ERROR_SUCCESS if successful +// LINEERR_INVALDEVICECLASS if invalid device class +// LINEERR_NODEVICE if invalid device ID +//**************************************************************************** + +LONG +TSPIAPI +TUISPI_lineConfigDialog( + TUISPIDLLCALLBACK pfnUIDLLCallback, + DWORD dwDeviceID, + HWND hwndOwner, + LPCTSTR lpszDeviceClass + ) +{ + PDLGREQ pDlgReq; + DWORD cbSize; + DWORD dwRet; + PROPREQ PropReq; + + DBG_DDI_ENTER("TUISPI_lineConfigDialog"); + + // Validate the requested device class + // + if (lpszDeviceClass != NULL) { + + if (lstrlen(lpszDeviceClass) != 0) { + + if (!ValidateDevCfgClass(lpszDeviceClass)) { + + DBG_DDI_EXIT("TUISPI_lineConfigDialog", LINEERR_INVALDEVICECLASS); + return LINEERR_INVALDEVICECLASS; + } + } + } + + // Get the modem properties + // + PropReq.DlgReq.dwCmd = UI_REQ_GET_PROP; + PropReq.DlgReq.dwParam = 0; + + (*pfnUIDLLCallback)(dwDeviceID, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&PropReq, sizeof(PropReq)); + + // Bring up property sheets for modems and get the updated commconfig + // + cbSize = PropReq.dwCfgSize+sizeof(DLGREQ); + if ((pDlgReq = (PDLGREQ)LocalAlloc(LPTR, cbSize)) != NULL) + { + pDlgReq->dwCmd = UI_REQ_GET_DEVCFG; + pDlgReq->dwParam = PropReq.dwCfgSize; + (*pfnUIDLLCallback)(dwDeviceID, TUISPIDLL_OBJECT_LINEID, + (LPVOID)pDlgReq, cbSize); + + DevCfgDialog(hwndOwner, &PropReq, (PDEVCFG)(pDlgReq+1)); + + // Save the changes back + // + pDlgReq->dwCmd = UI_REQ_SET_DEVCFG; + (*pfnUIDLLCallback)(dwDeviceID, TUISPIDLL_OBJECT_LINEID, + (LPVOID)pDlgReq, cbSize); + + LocalFree(pDlgReq); + dwRet = ERROR_SUCCESS; + } + else + { + dwRet = LINEERR_NOMEM; + }; + + DBG_DDI_EXIT("TUISPI_lineConfigDialog", dwRet); + return dwRet; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TUISPI_lineConfigDialogEdit( +// TUISPIDLLCALLBACK pfnUIDLLCallback, +// DWORD dwDeviceID, +// HWND hwndOwner, +// LPCSTR lpszDeviceClass, +// LPVOID const lpDeviceConfigIn, +// DWORD dwSize, +// LPVARSTRING lpDeviceConfigOut) +// +// Functions: Allows the user to edit the modem configuration through UI. The +// modem configuration is passed in and modified in the config +// structure. The modification does not applied to the line. +// +// Return: ERROR_SUCCESS if successful +// LINEERR_INVALPOINTER if invalid input/output buffer pointer +// LINEERR_INVALDEVICECLASS if invalid device class +// LINEERR_STRUCTURETOOSMALL if output buffer is too small +// LINEERR_NODEVICE if invalid device ID +//**************************************************************************** + +LONG +TSPIAPI +TUISPI_lineConfigDialogEdit( + TUISPIDLLCALLBACK pfnUIDLLCallback, + DWORD dwDeviceID, + HWND hwndOwner, + LPCTSTR lpszDeviceClass, + LPVOID const lpDeviceConfigIn, + DWORD dwSize, + LPVARSTRING lpDeviceConfigOut) +{ + PDLGREQ pDlgReq; + DWORD cbSize; + DWORD dwRet; + PROPREQ PropReq; + + DBG_DDI_ENTER("TUISPI_lineConfigDialogEdit"); + + // Validate the input/output buffer + // + if (lpDeviceConfigOut == NULL) + { + DBG_DDI_EXIT("TUISPI_lineConfigDialogEdit", LINEERR_INVALPOINTER); + return LINEERR_INVALPOINTER; + } + + if (lpDeviceConfigIn == NULL) + { + DBG_DDI_EXIT("TUISPI_lineConfigDialogEdit", LINEERR_INVALPOINTER); + return LINEERR_INVALPOINTER; + } + + if (lpDeviceConfigOut->dwTotalSize < sizeof(VARSTRING)) + { + DBG_DDI_EXIT("TUISPI_lineConfigDialogEdit", LINEERR_STRUCTURETOOSMALL); + return LINEERR_STRUCTURETOOSMALL; + } + + // Validate the requested device class + // + if (lpszDeviceClass != NULL) + { + if (!ValidateDevCfgClass(lpszDeviceClass)) + { + DBG_DDI_EXIT("TUISPI_lineConfigDialogEdit", LINEERR_INVALDEVICECLASS); + return LINEERR_INVALDEVICECLASS; + } + }; + + // Get the modem properties + // + PropReq.DlgReq.dwCmd = UI_REQ_GET_PROP; + PropReq.DlgReq.dwParam = 0; + + (*pfnUIDLLCallback)(dwDeviceID, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&PropReq, sizeof(PropReq)); + + // Bring up property sheets for modems and get the updated commconfig + // + cbSize = PropReq.dwCfgSize+sizeof(DLGREQ); + if ((pDlgReq = (PDLGREQ)LocalAlloc(LPTR, cbSize)) != NULL) + { + PDEVCFG pDevCfg = (PDEVCFG)(pDlgReq+1); + + pDlgReq->dwCmd = UI_REQ_GET_DEVCFG; + pDlgReq->dwParam = PropReq.dwCfgSize; + (*pfnUIDLLCallback)(dwDeviceID, TUISPIDLL_OBJECT_LINEID, + (LPVOID)pDlgReq, cbSize); + + // Validate the device configuration structure + // + cbSize = ((LPDEVCFG)lpDeviceConfigIn)->dfgHdr.dwSize; + if ((cbSize > pDevCfg->dfgHdr.dwSize) || + (pDevCfg->dfgHdr.dwVersion != ((LPDEVCFG)lpDeviceConfigIn)->dfgHdr.dwVersion)) + { + dwRet = LINEERR_INVALPARAM; + } + else + { + dwRet = ERROR_SUCCESS; + }; + + LocalFree(pDlgReq); + } + else + { + dwRet = LINEERR_NOMEM; + }; + + if (dwRet == ERROR_SUCCESS) + { + // Set the output buffer size + // + lpDeviceConfigOut->dwUsedSize = sizeof(VARSTRING); + lpDeviceConfigOut->dwNeededSize = sizeof(VARSTRING) + cbSize; + + // Validate the output buffer size + // + if (lpDeviceConfigOut->dwTotalSize >= lpDeviceConfigOut->dwNeededSize) + { + LPDEVCFG lpDevConfig; + + // Initialize the buffer + // + lpDeviceConfigOut->dwStringFormat = STRINGFORMAT_BINARY; + lpDeviceConfigOut->dwStringSize = cbSize; + lpDeviceConfigOut->dwStringOffset = sizeof(VARSTRING); + lpDeviceConfigOut->dwUsedSize += cbSize; + + lpDevConfig = (LPDEVCFG)(lpDeviceConfigOut+1); + hmemcpy((LPBYTE)lpDevConfig, (LPBYTE)lpDeviceConfigIn, cbSize); + + // Bring up property sheets for modems and get the updated commconfig + // + DevCfgDialog(hwndOwner, &PropReq, (LPDEVCFG)lpDevConfig); + }; + }; + DBG_DDI_EXIT("TUISPI_lineConfigDialogEdit", dwRet); + return dwRet; +} + +//**************************************************************************** +// ErrMsgBox() +// +// Function: Displays an error message box from resource text. +// +// Returns: None. +// +//**************************************************************************** + +void ErrMsgBox(HWND hwnd, UINT idsErr, UINT uStyle) +{ + LPTSTR pszTitle, pszMsg; + int iRet; + + // Allocate the string buffer + if ((pszTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, + (MAXTITLE+MAXMESSAGE) * sizeof(TCHAR))) + == NULL) + return; + + // Fetch the UI title and message + iRet = LoadString(ghInstance, IDS_ERR_TITLE, pszTitle, MAXTITLE) + 1; + pszMsg = pszTitle + iRet; + LoadString(ghInstance, idsErr, pszMsg, MAXTITLE+MAXMESSAGE-iRet)+1; + + // Popup the message + MessageBox(hwnd, pszMsg, pszTitle, uStyle); + + LocalFree(pszTitle); + return; +} + +//**************************************************************************** +// IsInvalidSetting() +// +// Function: Validate the option settings. +// +//**************************************************************************** + +BOOL IsInvalidSetting(HWND hWnd) +{ + BOOL fValid = TRUE; + UINT uSet; + + // Wait-for-bong setting + // + if(IsWindowEnabled(GetDlgItem(hWnd, IDC_WAIT_SEC))) + { + uSet = (UINT)GetDlgItemInt(hWnd, IDC_WAIT_SEC, &fValid, FALSE); + + // Check the valid setting + // + if ((!fValid) || (uSet > MAX_WAIT_BONG) || (uSet < MIN_WAIT_BONG)) + { + HWND hCtrl = GetDlgItem(hWnd, IDC_WAIT_SEC); + + // It is invalid, tell the user to reset. + // + ErrMsgBox(hWnd, IDS_ERR_INV_WAIT, MB_OK | MB_ICONEXCLAMATION); + SetFocus(hCtrl); + Edit_SetSel(hCtrl, 0, 0x7FFFF); + fValid = FALSE; + }; + }; + + return (!fValid); +} + +//**************************************************************************** +// UnimdmSettingProc() +// +// Function: A callback function to handle the terminal setting property page. +// +//**************************************************************************** + +LRESULT UnimdmSettingProc (HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + LPDEVCFG lpDevCfg; + DWORD fdwOptions; + + switch (message) + { + case WM_INITDIALOG: + { + LPDCDI lpdcdi; + + // Remember the pointer to the line device + // + lpdcdi = (LPDCDI)(((LPPROPSHEETPAGE)lParam)->lParam); + + lpDevCfg = lpdcdi->lpDevCfg; + SetWindowLong(hWnd, DWL_USER, (LONG)lpDevCfg); + fdwOptions = GETOPTIONS(lpDevCfg); + + // Initialize the appearance of the dialog box + CheckDlgButton(hWnd, IDC_TERMINAL_PRE, + fdwOptions & TERMINAL_PRE ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hWnd, IDC_TERMINAL_POST, + fdwOptions & TERMINAL_POST ? BST_CHECKED : BST_UNCHECKED); + + // Don't enable manual dial unless the modem supports BLIND dialing + // We need that capability to be able to do it. + // + if (lpdcdi->dwOptions & MDM_BLIND_DIAL) + { + CheckDlgButton(hWnd, IDC_MANUAL_DIAL, + fdwOptions & MANUAL_DIAL ? BST_CHECKED : BST_UNCHECKED); + } + else + { + EnableWindow(GetDlgItem(hWnd, IDC_MANUAL_DIAL), FALSE); + }; + + // Enable for bong UI only for a modem that does not support bong + if ((lpdcdi->dwType != DT_NULL_MODEM) && + !(lpdcdi->dwDevCaps & LINEDEVCAPFLAGS_DIALBILLING)) + { + UDACCEL udac; + + SetDlgItemInt(hWnd, IDC_WAIT_SEC, GETWAITBONG(lpDevCfg), FALSE); + SendDlgItemMessage(hWnd, IDC_WAIT_SEC_ARRW, UDM_SETRANGE, 0, + MAKELPARAM(MAX_WAIT_BONG, MIN_WAIT_BONG)); + SendDlgItemMessage(hWnd, IDC_WAIT_SEC_ARRW, UDM_GETACCEL, 1, + (LPARAM)(LPUDACCEL)&udac); + udac.nInc = INC_WAIT_BONG; + SendDlgItemMessage(hWnd, IDC_WAIT_SEC_ARRW, UDM_SETACCEL, 1, + (LPARAM)(LPUDACCEL)&udac); + } + else + { + EnableWindow(GetDlgItem(hWnd, IDC_WAIT_TEXT), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_WAIT_SEC), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_WAIT_SEC_ARRW), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_WAIT_UNIT), FALSE); + }; + + // Never display lights for null modem + // + if (lpdcdi->dwType == DT_NULL_MODEM) + { + ShowWindow(GetDlgItem(hWnd, IDC_LAUNCH_LIGHTSGRP), SW_HIDE); + ShowWindow(GetDlgItem(hWnd, IDC_LAUNCH_LIGHTSGRP), SW_HIDE); + EnableWindow(GetDlgItem(hWnd, IDC_LAUNCH_LIGHTS), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_LAUNCH_LIGHTS), FALSE); + } + else + { + CheckDlgButton(hWnd, IDC_LAUNCH_LIGHTS, + fdwOptions & LAUNCH_LIGHTS ? BST_CHECKED : BST_UNCHECKED); + }; + break; + } + +#ifdef UNDER_CONSTRUCTION + case WM_HELP: + case WM_CONTEXTMENU: + ContextHelp(gaUmdmOptions, message, wParam, lParam); + break; +#endif // UNDER_CONSTRUCTION + + case WM_NOTIFY: + switch(((NMHDR FAR *)lParam)->code) + { + case PSN_KILLACTIVE: + SetWindowLong(hWnd, DWL_MSGRESULT, (LONG)IsInvalidSetting(hWnd)); + return TRUE; + + case PSN_APPLY: + // + // The property sheet information is permanently applied + // + lpDevCfg = (LPDEVCFG)GetWindowLong(hWnd, DWL_USER); + + // Wait-for-bong setting. We already validate it + // + if(IsWindowEnabled(GetDlgItem(hWnd, IDC_WAIT_SEC))) + { + BOOL fValid; + UINT uWait; + + uWait = (WORD)GetDlgItemInt(hWnd, IDC_WAIT_SEC, &fValid, FALSE); + SETWAITBONG(lpDevCfg, uWait); + ASSERT(fValid); + }; + + // Other options + // + fdwOptions = TERMINAL_NONE; + + if(IsDlgButtonChecked(hWnd, IDC_TERMINAL_PRE)) + fdwOptions |= TERMINAL_PRE; + + if(IsDlgButtonChecked(hWnd, IDC_TERMINAL_POST)) + fdwOptions |= TERMINAL_POST; + + if(IsDlgButtonChecked(hWnd, IDC_MANUAL_DIAL)) + fdwOptions |= MANUAL_DIAL; + + if(IsDlgButtonChecked(hWnd, IDC_LAUNCH_LIGHTS)) + fdwOptions |= LAUNCH_LIGHTS; + + // Record the setting + SETOPTIONS(lpDevCfg, fdwOptions); + + return TRUE; + + default: + break; + }; + break; + + default: + break; + } + return FALSE; +} diff --git a/private/unimodem/tapisp/client.c b/private/unimodem/tapisp/client.c new file mode 100644 index 000000000..ecaec1ecc --- /dev/null +++ b/private/unimodem/tapisp/client.c @@ -0,0 +1,47 @@ +//**************************************************************************** +// +// Module: UNIMDM +// File: SLOT.C +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 3/25/96 JosephJ Created +// +// +// Description: Implements the unimodem TSP notification mechanism: +// The higher level API: UnimodemNotifyTSP() +// +//**************************************************************************** +#define UNICODE +#include +#include "slot.h" +#include "tspnotif.h" + + +BOOL WINAPI UnimodemNotifyTSP(PNOTIFICATION_FRAME pnf) +{ + BOOL fRet=FALSE; + HNOTIFICATION hN=0; + + if (pnf->dwSig!=dwNFRAME_SIG || pnf->dwSizedwSize>MAX_NOTIFICATION_FRAME_SIZE) + { + SetLastError(ERROR_INVALID_PARAMETER); + goto end; + } + + hN = notifCreate(FALSE, SLOTNAME_UNIMODEM_NOTIFY_TSP, 0, 0); + + if (hN) + { + fRet = notifWriteMsg(hN, (LPBYTE) pnf, pnf->dwSize); + notifFree(hN); hN=0; + } + +end: + + return fRet; +} diff --git a/private/unimodem/tapisp/common.c b/private/unimodem/tapisp/common.c new file mode 100644 index 000000000..40ed7600a --- /dev/null +++ b/private/unimodem/tapisp/common.c @@ -0,0 +1,572 @@ +/****************************************************************************** + +(C) Copyright MICROSOFT Corp., 1987-1993 + +Rob Williams, June 93 w/ State machine and parser plagarized from RAS + +******************************************************************************/ + +#include "unimdm.h" +#include "mcxp.h" +#include "common.h" + + +BOOL WINAPI +InitializeModemCommonList( + PCOMMON_MODEM_LIST CommonList + ) + +{ + D_TRACE(McxDpf(999,"InitializeModemCommonList");) + + CommonList->ListHead=NULL; + + InitializeCriticalSection( + &CommonList->CriticalSection + ); + + traceRegisterObject( + &CommonList, + TSP_COMMON_LIST_GUID, + TSP_COMMON_LIST_VERSION, + 0, + 0 + ); + + return TRUE; + +} + +VOID WINAPI +RemoveCommonList( + PCOMMON_MODEM_LIST CommonList + ) + +{ + + EnterCriticalSection(&CommonList->CriticalSection); + + // + // we go through the list removing the final reference count from the modem + // + while (CommonList->ListHead != NULL) { + // + // The call to RemoveReferenceToCommon() will change CommonList->ListHead + // so this is not an infinite loop + // + ASSERT(CommonList->ListHead->Reference == 1); + + RemoveReferenceToCommon( + CommonList, + CommonList->ListHead + ); + + } + + traceUnRegisterObject(&CommonList, 0, 0); + + LeaveCriticalSection(&CommonList->CriticalSection); + + DeleteCriticalSection(&CommonList->CriticalSection); + + return; + +} + +PSTR WINAPI +LoadDialElement( + HKEY hKey, + PSTR SubKeyName + ) + +{ + + CHAR szTemp[MAX_PATH]; + CHAR szTemp2[MAX_PATH]; + DWORD dwSize; + DWORD dwType; + LONG Result; + PSTR StringToReturn; + + dwSize=sizeof(szTemp); + + Result=RegQueryValueExA( + hKey, + SubKeyName, + NULL, + &dwType, + (VOID *)szTemp, + &dwSize + ); + + if (Result != ERROR_SUCCESS || dwType != REG_SZ || dwSize == 0) { + + return NULL; + } + + ExpandMacros(szTemp, szTemp2, NULL, NULL, 0); + + StringToReturn=LocalAlloc(LPTR, lstrlenA(szTemp2) + 1); + + lstrcpyA(StringToReturn,szTemp2); + + return StringToReturn; + +} + + + + +COMMON_MODEM_LIST gCommonList; + +static CHAR szAnswer[] = "Answer"; +static CHAR szMonitor[]= "Monitor"; +static CHAR szInit[] = "Init"; +static CHAR szHangup[] = "Hangup"; + +static CHAR DialComponents[COMMON_DIAL_MAX_INDEX+1][20] = + { {"Prefix"}, + {"DialPrefix"}, + {"Blind_On"}, + {"Blind_Off"}, + {"Tone"}, + {"Pulse"}, + {"DialSuffix"}, + {"Terminator"}}; + + + +PVOID WINAPI +OpenCommonModemInfo( + PCOMMON_MODEM_LIST CommonList, + HKEY hKey + ) + +{ + + CHAR IdString[MAX_PATH]; + DWORD dwRetSize; + LONG Result; + DWORD dwType; + PCOMMON_MODEM_INFO pCommon; + HKEY hSettingsKey; + UINT i; + + dwRetSize = MAX_PATH; + + // + // get the inf file name from the registry + // + Result=RegQueryValueExA( + hKey, + "InfPath", + NULL, + &dwType, + (VOID *)IdString, + &dwRetSize + ); + + + if (ERROR_SUCCESS != Result) { + + return NULL; + } + + lstrcatA(IdString,"\\"); + + dwRetSize = MAX_PATH; + + // + // get the inf section name from the registry + // + Result=RegQueryValueExA( + hKey, + "InfSection", + NULL, + &dwType, + (VOID *)&IdString[lstrlenA(IdString)], + &dwRetSize + ); + + if (ERROR_SUCCESS != Result) { + + return NULL; + } + + // + // the name is now "inf-name\inf-section" + // + D_TRACE(McxDpf(999,"Common modem info name is %s",IdString);) + + + + // + // see if this one is already around + // + EnterCriticalSection(&CommonList->CriticalSection); + + pCommon=CommonList->ListHead; + + while (pCommon != NULL) { + + if (lstrcmpA(IdString, pCommon->IdString) == 0) { + // + // found, up the ref count and return + // + pCommon->Reference++; + + D_TRACE(McxDpf(999,"Found Common modem info Match, ref=%d",pCommon->Reference);) + + LeaveCriticalSection(&CommonList->CriticalSection); + + return pCommon; + } + + pCommon=pCommon->Next; + } + + + // + // did not find it on the list, need to build a new one + // + pCommon=LocalAlloc(LPTR, sizeof(COMMON_MODEM_INFO)); + + if (pCommon == NULL) { + + LeaveCriticalSection(&CommonList->CriticalSection); + + return NULL; + } + + lstrcpyA(pCommon->IdString, IdString); + + + D_TRACE(McxDpf(999,"Creating new Common modem info");) + + + // + // build the response list + // + pCommon->ResponseList=NewBuildResponsesLinkedList(hKey); + + if (pCommon->ResponseList == NULL) { + + D_TRACE(McxDpf(999,"Could not build response list");) + goto Fail; + } + + // + // get statis init string + // + pCommon->ModemCommands[COMMON_INIT_COMMANDS]=NewLoadRegCommands(hKey, szInit, NULL); + + if (pCommon->ModemCommands[COMMON_INIT_COMMANDS] == NULL) { + + D_TRACE(McxDpf(999,"Could not load init string");) + goto Fail; + } + + // + // get monitor string + // + pCommon->ModemCommands[COMMON_MONITOR_COMMANDS]=NewLoadRegCommands(hKey, szMonitor, NULL); + + if (pCommon->ModemCommands[COMMON_MONITOR_COMMANDS] == NULL) { + + D_TRACE(McxDpf(999,"Could not load Monitor string");) + goto Fail; + } + + // + // get answer string + // + pCommon->ModemCommands[COMMON_ANSWER_COMMANDS]=NewLoadRegCommands(hKey, szAnswer, NULL); + + if (pCommon->ModemCommands[COMMON_ANSWER_COMMANDS] == NULL) { + + D_TRACE(McxDpf(999,"Could not Load Answer string");) + goto Fail; + } +#if 0 + // + // get hangup string + // + pCommon->ModemCommands[COMMON_HANGUP_COMMANDS]=NewLoadRegCommands(hKey, szHangup, NULL); + + if (pCommon->ModemCommands[COMMON_HANGUP_COMMANDS] == NULL) { + + D_TRACE(McxDpf(999,"Could not load hangup string");) + goto Fail; + } +#endif + + if (RegOpenKeyA(hKey, szSettings, &hSettingsKey)==ERROR_SUCCESS) { + + for (i=0; iDialComponents[i]=LoadDialElement(hSettingsKey, + DialComponents[i]); + D_TRACE(if (pCommon->DialComponents[i] == NULL) { + McxDpf(999,"Could not load %s", + DialComponents[i]); + } + ) + } + + RegCloseKey(hSettingsKey); + } + + + // + // set the reference count to 2 here so that when the modem is closed + // the common block will stick around until explicitly freed + // + pCommon->Reference=2; + + pCommon->Next=CommonList->ListHead; + + CommonList->ListHead=pCommon; + + LeaveCriticalSection(&CommonList->CriticalSection); + + return pCommon; + +Fail: + + // + // free any dial commands we loaded + // + for (i=0; iDialComponents[i] != NULL) { + + LocalFree(pCommon->DialComponents[i]); + } + } + + // + // free and modem commands that we loaded + // + for (i=0; iModemCommands[i] != NULL) { + + LocalFree(pCommon->ModemCommands[i]); + } + } + + + // + // get rid of the response list if we got it + // + if (pCommon->ResponseList != NULL) { + + LocalFree(pCommon->ResponseList); + } + + + + LocalFree(pCommon); + + LeaveCriticalSection(&CommonList->CriticalSection); + + return NULL; +} + + + +VOID WINAPI +RemoveReferenceToCommon( + PCOMMON_MODEM_LIST CommonList, + HANDLE hCommon + ) + +{ + PCOMMON_MODEM_INFO pCommon=(PCOMMON_MODEM_INFO)hCommon; + PCOMMON_MODEM_INFO Current; + PCOMMON_MODEM_INFO Prev; + UINT i; + + ASSERT(pCommon != NULL); + + EnterCriticalSection(&CommonList->CriticalSection); + + pCommon->Reference--; + + if (pCommon->Reference > 0) { + // + // not done with it yet + // + D_TRACE(McxDpf(999,"RemoveReferenceToCommon, ref=%d", + pCommon->Reference);) + + LeaveCriticalSection(&CommonList->CriticalSection); + + return; + } + + // + // ref count is zero get rid of the common block + // + + Prev=NULL; + Current=CommonList->ListHead; + + while (Current != NULL) { + + if (Current == pCommon) { + + if (Prev == NULL) { + + CommonList->ListHead=Current->Next; + + } else { + + Prev->Next=Current->Next; + } + break; + } + + Prev=Current; + + Current=Current->Next; + + } + + ASSERT(Current != NULL); + + LeaveCriticalSection(&CommonList->CriticalSection); + + D_TRACE(McxDpf(999,"RemoveReferenceToCommon, removing common, %s", + pCommon->IdString);) + + // + // free any dial commands we loaded + // + for (i=0; iDialComponents[i] != NULL) { + + LocalFree(pCommon->DialComponents[i]); + } + } + + // + // free and modem commands that we loaded + // + for (i=0; iModemCommands[i] != NULL) { + + LocalFree(pCommon->ModemCommands[i]); + } + } + + + // + // get rid of the response list if we got it + // + if (pCommon->ResponseList != NULL) { + + LocalFree(pCommon->ResponseList); + } + + + + LocalFree(pCommon); + + return; +} + + + + +HANDLE WINAPI +GetCommonResponseList( + HANDLE hCommon + ) + +{ + PCOMMON_MODEM_INFO pCommon=(PCOMMON_MODEM_INFO)hCommon; + + return (HANDLE)pCommon->ResponseList; + +} + + +PSTR WINAPI +GetCommonCommandStringCopy( + HANDLE hCommon, + UINT Index + ) + +{ + PCOMMON_MODEM_INFO pCommon=(PCOMMON_MODEM_INFO)hCommon; + PSTR Commands; + PSTR pTemp; + + pTemp=pCommon->ModemCommands[Index]; + + while (1) { + + if (*pTemp++ == '\0') { + + if (*pTemp++ == '\0') { + + break; + } + } + } + + + + Commands=LocalAlloc(LPTR, pTemp-pCommon->ModemCommands[Index]); + + if (NULL == Commands) { + + D_TRACE(McxDpf(999,"GetCommonCommandStringCopy: Alloc failed");) + + return NULL; + } + + CopyMemory(Commands,pCommon->ModemCommands[Index],pTemp-pCommon->ModemCommands[Index]); + + return Commands; + +} + + +DWORD WINAPI +GetCommonDialComponent( + HANDLE hCommon, + PSTR DestString, + DWORD DestLength, + DWORD Index + ) + +{ + PCOMMON_MODEM_INFO pCommon=(PCOMMON_MODEM_INFO)hCommon; + DWORD Length; + + if (pCommon->DialComponents[Index] == NULL) { + + lstrcpyA(DestString,""); + + return 0; + } + + Length=lstrlenA(pCommon->DialComponents[Index])+1; + + if (Length+1 > DestLength) { + + return 0; + } + + lstrcpyA( + DestString, + pCommon->DialComponents[Index] + ); + + return Length; + +} diff --git a/private/unimodem/tapisp/common.h b/private/unimodem/tapisp/common.h new file mode 100644 index 000000000..d7d203139 --- /dev/null +++ b/private/unimodem/tapisp/common.h @@ -0,0 +1,88 @@ +#define COMMON_INIT_COMMANDS 0 +#define COMMON_MONITOR_COMMANDS 1 +#define COMMON_ANSWER_COMMANDS 2 +#define COMMON_HANGUP_COMMANDS 3 + +#define COMMON_MAX_COMMANDS 4 + +#define COMMON_DIAL_COMMOND_PREFIX 0 +#define COMMON_DIAL_PREFIX 1 +#define COMMON_DIAL_BLIND_ON 2 +#define COMMON_DIAL_BLIND_OFF 3 +#define COMMON_DIAL_TONE 4 +#define COMMON_DIAL_PULSE 5 +#define COMMON_DIAL_SUFFIX 6 +#define COMMON_DIAL_TERMINATION 7 + +#define COMMON_DIAL_MAX_INDEX COMMON_DIAL_TERMINATION + +typedef struct _COMMON_MODEM_INFO { + + struct _COMMON_MODEM_INFO * Next; + UINT Reference; + + CHAR IdString[MAX_PATH]; + + PVOID ResponseList; + + PSTR ModemCommands[COMMON_MAX_COMMANDS]; + + PSTR DialComponents[COMMON_DIAL_MAX_INDEX+1]; + +} COMMON_MODEM_INFO, *PCOMMON_MODEM_INFO; + +typedef struct _COMMON_MODEM_LIST { + + PCOMMON_MODEM_INFO volatile ListHead; + + CRITICAL_SECTION CriticalSection; + +} COMMON_MODEM_LIST, *PCOMMON_MODEM_LIST; + +extern COMMON_MODEM_LIST gCommonList; + + +BOOL WINAPI +InitializeModemCommonList( + PCOMMON_MODEM_LIST CommonList + ); + +VOID WINAPI +RemoveCommonList( + PCOMMON_MODEM_LIST CommonList + ); + + + +PVOID WINAPI +OpenCommonModemInfo( + PCOMMON_MODEM_LIST CommonList, + HKEY hKey + ); + +VOID WINAPI +RemoveReferenceToCommon( + PCOMMON_MODEM_LIST CommonList, + HANDLE hCommon + ); + + + +HANDLE WINAPI +GetCommonResponseList( + HANDLE hCommon + ); + +PSTR WINAPI +GetCommonCommandStringCopy( + HANDLE hCommon, + UINT Index + ); + +DWORD WINAPI +GetCommonDialComponent( + HANDLE hCommon, + PSTR DestString, + DWORD DestLength, + DWORD Index + ); diff --git a/private/unimodem/tapisp/debug.c b/private/unimodem/tapisp/debug.c new file mode 100644 index 000000000..e6e978008 --- /dev/null +++ b/private/unimodem/tapisp/debug.c @@ -0,0 +1,214 @@ +//**************************************************************************** +// +// Module: UNIMDM.TSP +// File: debug.c +// Content: This file contains miscellaneous debug routines. +// History: +// Wed 12-Apr-1995 11:26:28 -by- Viroon Touranachun [viroont] +// +//**************************************************************************** + +#include "unimdm.h" + +#ifdef DEBUG + +//========== Debug output routines ========================================= + +LINEEVENT glpfnDebugEventProc; + +HLOCAL WINAPI DebugLocalFree(HLOCAL hMem) +{ + HLOCAL hlRet; + +#ifdef LocalFree +#undef LocalFree +#endif // LocalFree + + FillMemory(hMem, (DWORD)LocalSize(LocalHandle(hMem)), 0x69); + + if ((hlRet = LocalFree(hMem)) != NULL) + { + DPRINTF1("UnimodemFree: LocalFree failed, error=%ld", GetLastError()); + } + + return hlRet; +} + +// LineEventProc spewing code. +void DebugSetEventProc(LINEEVENT lineEventProc) +{ + glpfnDebugEventProc = lineEventProc; +} + +void CALLBACK DebugEventProc(HTAPILINE htLine, + HTAPICALL htCall, + DWORD dwMsg, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ + DPRINTF3("EventProc: htLine=0x%0.8x htCall=0x%0.8x dwMsg=0x%0.8x", + htLine, htCall, dwMsg); + DPRINTF3("EventProc:dwParam1=0x%0.8x dwParam2=0x%0.8x dwParam3=0x%0.8x", + dwParam1, dwParam2, dwParam3); + + (*(glpfnDebugEventProc))(htLine, htCall, dwMsg, + dwParam1, dwParam2, dwParam3); +} + + +VOID WINAPIV +TspDpf( + UINT Id, + LPTSTR FormatString, + ... + ) + +{ + va_list VarArg; + TCHAR OutBuffer[1024]; + + if (DisplayDebug(TF_GENERAL)) { + + wsprintf( + OutBuffer, + TEXT("%d - UNIMDM: "), + Id + ); + + va_start(VarArg,FormatString); + + wvsprintf( + OutBuffer+lstrlen(OutBuffer), + FormatString, + VarArg + ); + + lstrcat(OutBuffer,TEXT("\n")); + + OutputDebugString(OutBuffer); + } + + return; + +} + +VOID WINAPIV +McxDpf( + UINT Id, + LPSTR FormatString, + ... + ) + +{ + va_list VarArg; + CHAR OutBuffer[1024]; + + if (DisplayDebug(TF_GENERAL)) { + + wsprintfA( + OutBuffer, + "%d - UNIMDM: ", + Id + ); + + va_start(VarArg,FormatString); + + wvsprintfA( + OutBuffer+lstrlenA(OutBuffer), + FormatString, + VarArg + ); + + lstrcatA(OutBuffer,"\n"); + + OutputDebugStringA(OutBuffer); + } + + return; + +} + +#ifdef TEST_GTC // Function versions of the GTC_macros + +BOOL GTC_AleB(DWORD dwA, DWORD dwB) +{ + BOOL fRet; + +// ((DWORD)(((_A)<=(_B)) \ +// ? (((_B)-(_A))<=GTC_MAXDELTA)\ +// : (((_A)-(_B))>GTC_MAXDELTA))) + + if (dwA<=dwB) + { + if ((dwB-dwA)<=GTC_MAXDELTA) + { + fRet=TRUE; + } + else + { + DPRINTF2("GTC_AleB(%d,%d) !!ROLLOVER!!, returning FALSE\n", + dwA, dwB); + fRet= FALSE; + } + + } + else + { + if ((dwA-dwB)>GTC_MAXDELTA) + { + DPRINTF2("GTC_AleB(%d,%d) !!ROLLOVER!!, returning TRUE\n", + dwA, dwB); + fRet= TRUE; + } + else + { + fRet= FALSE; + } + } + return fRet; +} + +DWORD GTC_DELTA(DWORD dwStart, DWORD dwEnd) +{ + DWORD dwRet; +// ((DWORD) \ +// (((_End)>=(_Start)) \ +// ? ((_End)-(_Start)) \ +// : ((_End)+(GTC_MASK-(_Start))))) + if (dwEnd>=dwStart) + { + dwRet= dwEnd-dwStart; + } + else + { + dwRet=dwEnd+(GTC_MASK-dwStart); + DPRINTF3("GTC_DELTA(%d,%d) !!ROLLOVER!!, returning %d\n", + dwStart, dwEnd, dwRet); + } + + return dwRet; +} + +void fnGTC_AequalsBplusC(LPDWORD lpdwA, DWORD dwB, DWORD dwC) +{ +// ((_A=((_B)+(_C))>C_MASK),(_A)?(_A):((_A)=1)) + DWORD dwA = dwB+dwC; + *lpdwA = dwA>C_MASK; + if (*lpdwA!=dwA) + { + DPRINTF3("GTC_A=B+C(%d,%d,%d) !!ROLLOVER!!\n", + *lpdwA, dwB, dwC); + } + if (!*lpdwA) + { + *lpdwA=1; + DPRINTF3("GTC_A=B+C(%d,%d,%d) !!ROLLOVER TO NULL!!\n", + *lpdwA, dwB, dwC); + } + +} + +#endif // TEST_GTC + +#endif // DEBUG diff --git a/private/unimodem/tapisp/debug.h b/private/unimodem/tapisp/debug.h new file mode 100644 index 000000000..f00723160 --- /dev/null +++ b/private/unimodem/tapisp/debug.h @@ -0,0 +1,182 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: debug.h +// Content: This file contains the declaration for debug macros +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// History: +// +//**************************************************************************** + +// Defines for rovcomm.h + +#define NORTL +#define NOMEM +#define NODA +#define NOSHAREDHEAP +#define NOFILEINFO +#define NOCOLORHELP +#define NODRAWTEXT +#define NODIALOGHELPER +#define NOMESSAGESTRING +#define NOSTRING +#define NOPATH +#define NOSYNC +#define NODI + +#define SZ_MODULEA "UNIMDM" +#define SZ_MODULEW L##"UNIMDM" +#define SZ_DEBUGSECTION L##"UNIMDM" +#define SZ_DEBUGINI L##"unimdm.ini" + +#include + +// Trace flags +#define TF_DWDEVICEID 0x00010000 +#define TF_HDLINE 0x00020000 +#define TF_HDCALL 0x00040000 +#define TF_PLINEDEV 0x00080000 +#define TF_PMODEMINFO 0x00100000 + +// Traditional DPRINTF defines + + +#define DPRINTF(sz) TRACE_MSG(TF_GENERAL, sz) +#define DPRINTF1(sz,x) TRACE_MSG(TF_GENERAL, sz, x) +#define DPRINTF2(sz,x,y) TRACE_MSG(TF_GENERAL, sz, x, y) +#define DPRINTF3(sz,x,y,z) TRACE_MSG(TF_GENERAL, sz, x, y, z) +#define DPRINTF4(sz,w,x,y,z) TRACE_MSG(TF_GENERAL, sz, w, x, y, z) + +#define DPRINTFA(sz) TRACE_MSGA(TF_GENERAL, sz) +#define DPRINTFA1(sz,x) TRACE_MSGA(TF_GENERAL, sz, x) +#define DPRINTFA2(sz,x,y) TRACE_MSGA(TF_GENERAL, sz, x, y) +#define DPRINTFA3(sz,x,y,z) TRACE_MSGA(TF_GENERAL, sz, x, y, z) +#define DPRINTFA4(sz,w,x,y,z) TRACE_MSGA(TF_GENERAL, sz, w, x, y, z) + +#define SPTrace(x) DBG_ENTER(x) + +// Supplementary debug print macros + +#define DBG_DDI_ENTER(fn) \ + TRACE_MSG(TF_FUNC | TF_DWDEVICEID, \ + ">" fn "(dwDeviceID = %#08lx)", \ + (ULONG)(dwDeviceID)) + +#define DBG_HDL_ENTER(fn) \ + TRACE_MSG(TF_FUNC | TF_HDLINE, \ + ">" fn "(hdLine = %#08lx)", \ + (ULONG)(hdLine)) + +#define DBG_HDC_ENTER(fn) \ + TRACE_MSG(TF_FUNC | TF_HDCALL, \ + ">" fn "(hdCall = %#08lx)", \ + (ULONG)(hdCall)) + +#define DBG_PLD_ENTER(fn) \ + TRACE_MSG(TF_FUNC | TF_PLINEDEV, \ + ">" fn "(pLineDev = %#08lx)", \ + (ULONG)(pLineDev)) + +#define DBG_PMI_ENTER(fn) \ + TRACE_MSG(TF_FUNC | TF_PMODEMINFO, \ + ">" fn "(pModemInfo = %#08lx)", \ + (ULONG)(pModemInfo)) + +#define DBG_DDI_EXIT(fn, ul) \ + TRACE_MSG(TF_FUNC | TF_DWDEVICEID, \ + "<" fn "(dwDeviceID = %#08lx) with %#08lx", \ + (ULONG)(dwDeviceID), (ULONG)(ul)) + +#define DBG_HDL_EXIT(fn, ul) \ + TRACE_MSG(TF_FUNC | TF_HDLINE, \ + "<" fn "(hdLine = %#08lx) with %#08lx", \ + (ULONG)(hdLine), (ULONG)(ul)) + +#define DBG_HDC_EXIT(fn, ul) \ + TRACE_MSG(TF_FUNC | TF_HDCALL, \ + "<" fn "(hdCall = %#08lx) with %#08lx", \ + (ULONG)(hdCall), (ULONG)(ul)) + +#define DBG_PLD_EXIT(fn, ul) \ + TRACE_MSG(TF_FUNC | TF_PLINEDEV, \ + "<" fn "(pLineDev = %#08lx) with %#08lx", \ + (ULONG)(pLineDev), (ULONG)(ul)) + +#define DBG_PMI_EXIT(fn, ul) \ + TRACE_MSG(TF_FUNC | TF_PMODEMINFO, \ + "<" fn "(pModemInfo = %#08lx) with %#08lx", \ + (ULONG)(pModemInfo), (ULONG)(ul)) + +// Debug Messages +// +#ifdef DEBUG + +// LineEventProc spewing code. +void DebugSetEventProc(LINEEVENT lineEventProc); +void CALLBACK DebugEventProc(HTAPILINE htLine, + HTAPICALL htCall, + DWORD dwMsg, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3); + +HLOCAL WINAPI DebugLocalFree(HLOCAL hMem); + +#define LocalFree(hMem) DebugLocalFree(hMem) + +// Non-Unicode +VOID WINAPIV +McxDpf( + UINT Id, + LPSTR FormatString, + ... + ); + +// Unicode +VOID WINAPIV +TspDpf( + UINT Id, + LPTSTR FormatString, + ... + ); + + +#define D_TRACE(_x) {_x} + +#define MCXPRINTF(sz) McxDpf(pModemInfo->mi_dwID, sz) +#define MCXPRINTF1(sz,x) McxDpf(pModemInfo->mi_dwID, sz,x) +#define MCXPRINTF2(sz,x,y) McxDpf(pModemInfo->mi_dwID, sz,x,y) +#define MCXPRINTF3(sz,x,y,z) McxDpf(pModemInfo->mi_dwID, sz,x,y,z) +#define MCXPRINTF4(sz,w,x,y,z) McxDpf(pModemInfo->mi_dwID, sz,w,x,y,z) + +#define TSPPRINTF(sz) TspDpf(pLineDev->dwID, TEXT(sz)) +#define TSPPRINTF1(sz,x) TspDpf(pLineDev->dwID, TEXT(sz),x) +#define TSPPRINTF2(sz,x,y) TspDpf(pLineDev->dwID, TEXT(sz),x,y) +#define TSPPRINTF3(sz,x,y,z) TspDpf(pLineDev->dwID, TEXT(sz),x,y,z) +#define TSPPRINTF4(sz,w,x,y,z) TspDpf(pLineDev->dwID, TEXT(sz),w,x,y,z) + + + + +#else + +#define D_TRACE(_x) + +#define MCXPRINTF(sz) +#define MCXPRINTF1(sz,x) +#define MCXPRINTF2(sz,x,y) +#define MCXPRINTF3(sz,x,y,z) +#define MCXPRINTF4(sz,w,x,y,z) + +#define TSPPRINTF(sz) +#define TSPPRINTF1(sz,x) +#define TSPPRINTF2(sz,x,y) +#define TSPPRINTF3(sz,x,y,z) +#define TSPPRINTF4(sz,w,x,y,z) + + + + +#endif //ifdef DEBUG diff --git a/private/unimodem/tapisp/devioctl.c b/private/unimodem/tapisp/devioctl.c new file mode 100644 index 000000000..a51898cb6 --- /dev/null +++ b/private/unimodem/tapisp/devioctl.c @@ -0,0 +1,1160 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: devioctl.c +// +// Copyright (c) 1992-1995, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 5/16/95 Viroon Touranachun Moved from mdmutil.c +// +// +// Description: Interface to kernel-mode unimodem +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" + + +#ifdef WINNT +#ifndef USE_SERVICECONTROLLER +// # error "Unimplemented" + +#define MODEM_SERVICE_NAME \ + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\modem" + +#endif // USE_SERVICECONTROLLER + + +// Global variable for the modem.sys service +BOOL bModemSysStarted = FALSE; +CRITICAL_SECTION ServiceControlerCriticalSection; +#endif // WINNT + + +LONG WINAPI +MCXSetModemSettings( + HANDLE hModem, + PMODEMSETTINGS lpMS + ); + + +//**************************************************************************** +// DWORD MapMcxResult (DWORD) +// +// Function: Maps internal error to a standard error code. +// +// Returns: standard error code +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD MapMcxResult (DWORD dwResult) +{ + switch (dwResult) + { + case MDM_SUCCESS: + return ERROR_SUCCESS; + + case MDM_PENDING: + return ERROR_IO_PENDING; + + default: + return ERROR_IO_DEVICE; + } +} + + +#ifdef USE_SERVICECONTROLLER + +LONG WINAPI +StartModemDriver( + VOID + ) + +{ + + LONG lResult=ERROR_SUCCESS; // Assume success + BOOL bResult; + + SC_HANDLE schModemSys; + SC_HANDLE schSCManager; + SERVICE_STATUS ServiceStatus; + + EnterCriticalSection( + &ServiceControlerCriticalSection + ); + + + if (!bModemSysStarted) { + + schSCManager=OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager != NULL) { + // + // now on service + // + schModemSys=OpenService( + schSCManager, + TEXT("modem"), + SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS + ); + + if (schModemSys == NULL) { + + DPRINTF("OpenService() for modem.sys failed!"); + CloseServiceHandle(schSCManager); + + lResult=ERROR_IO_DEVICE; + + goto Leave; + + + } + + bResult=QueryServiceStatus( + schModemSys, + &ServiceStatus + ); + + if (bResult) { + + if (ServiceStatus.dwCurrentState != SERVICE_RUNNING) { + + bResult=StartService( + schModemSys, + 0, + NULL + ); + + if (bResult) { + + DPRINTF("StartService() for modem.sys succeeded!"); + + bModemSysStarted=TRUE; + + } else { + + DPRINTF("StartService() for modem.sys FAILED!"); + + lResult = GetLastError(); + + } + + } else { + + bModemSysStarted=TRUE; + } + + } else { + + lResult = GetLastError(); + + DPRINTF1("QueryServiceStatus() for modem.sys failed (%d)!", lResult); + + } + + CloseServiceHandle(schModemSys); + + CloseServiceHandle(schSCManager); + + } else { + + DPRINTF("OpenSCManager() failed!"); + + lResult=ERROR_IO_DEVICE; + + } // if opened SC macanger + + } else { + // + // already running + // + } + +Leave: + + LeaveCriticalSection( + &ServiceControlerCriticalSection + ); + + + return lResult; + +} + + + +LONG WINAPI +StopModemDriver( + VOID + ) + +{ + + LONG lResult; + BOOL bResult; + + SC_HANDLE schModemSys; + SC_HANDLE schSCManager; + SERVICE_STATUS ServiceStatus; + + EnterCriticalSection( + &ServiceControlerCriticalSection + ); + + + if (bModemSysStarted) { + + schSCManager=OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager != NULL) { + // + // now on service + // + schModemSys=OpenService( + schSCManager, + TEXT("modem"), + SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS + ); + + if (schModemSys != NULL) { + + bResult=ControlService( + schModemSys, + SERVICE_CONTROL_STOP, + &ServiceStatus + ); + + if (bResult) { + + bModemSysStarted=TRUE; + } + + CloseServiceHandle(schModemSys); + + } + + CloseServiceHandle(schSCManager); + + } + } + + LeaveCriticalSection( + &ServiceControlerCriticalSection + ); + + return ERROR_SUCCESS; + +} + +#else // !USE_SERVICECONTROLLER + + +BOOL WINAPI +ObtainLoadDriverPrivilege( + IN PBOOLEAN WasEnabled + ) { + + NTSTATUS Status; + + DPRINTF("ObtainLoadDriverPrivilege"); + + + // + // Obtain the process's access token for the current thread + // + + Status = RtlImpersonateSelf(SecurityImpersonation); + + if (!NT_SUCCESS(Status)) { + DPRINTF1("RtlImpersonateSelf returned 0x%08x", Status); + return FALSE; + } + + + // + // request "Load-Driver" privileges for this thread + // + + Status = RtlAdjustPrivilege( + SE_LOAD_DRIVER_PRIVILEGE, + TRUE, + TRUE, + WasEnabled + ); + + if (!NT_SUCCESS(Status)) { + DPRINTF1("RtlAdjustPrivileges returned 0x%08x", Status); + RevertToSelf(); + return FALSE; + } + + return TRUE; +} + + +VOID WINAPI +ReleaseLoadDriverPrivilege( + IN PBOOLEAN WasEnabled + ) { + + NTSTATUS Status; + + DPRINTF("ReleaseLoadDriverPrivilege"); + + + // + // See if we had to enable SE_LOAD_DRIVER_PRIVILEGE + // + + if (!*WasEnabled) { + + // + // relinquish "Load-Driver" privileges for this thread + // + + Status = RtlAdjustPrivilege( + SE_LOAD_DRIVER_PRIVILEGE, + FALSE, + TRUE, + WasEnabled + ); + } + + + // + // return the thread to its previous access token + // + + RevertToSelf(); +} + + +// # error "Unimplemented" + +static WCHAR g_rgwchBuffer[] = MODEM_SERVICE_NAME; +static UNICODE_STRING g_usDriverName = { + sizeof(g_rgwchBuffer)-sizeof(WCHAR), //Length + sizeof(g_rgwchBuffer), //MaximumLength + g_rgwchBuffer //Buffer + }; + + +LONG WINAPI +StartModemDriver( + VOID + ) + +{ + + LONG lResult=ERROR_SUCCESS; + + EnterCriticalSection( + &ServiceControlerCriticalSection + ); + + while (!bModemSysStarted) { // breakout-construct + + NTSTATUS nts; + BOOLEAN WasEnabled; + + + // + // Enable our load-driver privilege + // + + if (!ObtainLoadDriverPrivilege(&WasEnabled)) { + lResult = ERROR_ACCESS_DENIED; + break; + } + + + // + // Load modem.sys + // + + nts = NtLoadDriver(&g_usDriverName); + if (NT_SUCCESS(nts) || nts==STATUS_IMAGE_ALREADY_LOADED) + { + DPRINTF1("NtLoadDriver returns %s", + (nts==STATUS_IMAGE_ALREADY_LOADED) + ? TEXT("Already loaded") + : TEXT("Success")); + bModemSysStarted=TRUE; + } + else + { + DPRINTF1("ERROR: NtLoadDriver fails(0x%lx)", (DWORD) nts); + lResult=ERROR_IO_DEVICE; + } + + + // + // relinquish "Load-Driver" privileges for this thread + // + + ReleaseLoadDriverPrivilege(&WasEnabled); + + break; + } + + LeaveCriticalSection( + &ServiceControlerCriticalSection + ); + + return lResult; + +} + + + +LONG WINAPI +StopModemDriver( + VOID + ) + +{ + + LONG lResult=ERROR_SUCCESS; + + EnterCriticalSection( + &ServiceControlerCriticalSection + ); + + while (bModemSysStarted) { // break-out construct + + NTSTATUS nts; + BOOLEAN WasEnabled; + + + // + // Enable our load-driver privilege + // + + if (!ObtainLoadDriverPrivilege(&WasEnabled)) { + lResult = ERROR_ACCESS_DENIED; + break; + } + + + // + // Unload modem.sys + // + + nts = NtUnloadDriver(&g_usDriverName); + + if (NT_SUCCESS(nts)) + { + DPRINTF("NtUnloadDriver succeeded"); + bModemSysStarted=FALSE; + } + else + { + DPRINTF1("ERROR: NtUnloadDriver fails(0x%lx)", (DWORD) nts); + lResult=ERROR_IO_DEVICE; + } + + + // + // relinquish "Load-Driver" privileges for this thread + // + + ReleaseLoadDriverPrivilege(&WasEnabled); + + break; + } + + LeaveCriticalSection( + &ServiceControlerCriticalSection + ); + + return lResult; + +} + +#endif // !USE_SERVICECONTROLLER + +//**************************************************************************** +// DWORD OpenModem (PLINEDEV) +// +// Function: Opens the modem device. +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD OpenModem(PLINEDEV pLineDev, LPBYTE lpComConfig, DWORD dwSize) +{ + HANDLE hComm; + DCB dcb; + TCHAR szPort[MAXDEVICENAME+1]; + DWORD dwRet; + SERVICE_STATUS ServiceStatus; + BOOL bResult; + + + TSPPRINTF("Open modem"); + + dwRet=StartModemDriver(); + + if (dwRet != ERROR_SUCCESS) { + + return dwRet; + + } + + + // Initialize szPort to be "\\.\" + lstrcpy(szPort, cszDevicePrefix); + + // Concatenate FriendlyName onto szPort to form "\\.\Modem Name" + lstrcat(szPort, pLineDev->szDeviceName); + + TSPPRINTF1("Device Name = %s", szPort); + + // Open the modem port + // + hComm = CreateFile(szPort, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (hComm == INVALID_HANDLE_VALUE) + { + dwRet = GetLastError(); + TSPPRINTF1("hComm CreateFile() failed! (%d)", dwRet); + return dwRet; + }; + + if (!PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) ) { + + dwRet = GetLastError(); + CloseHandle(hComm); + return dwRet; + } + + + + ASSERT(ghCompletionPort != NULL); + + if (CreateIoCompletionPort(hComm, + ghCompletionPort, + (DWORD)pLineDev, + 0) == NULL) + { + dwRet = GetLastError(); + CloseHandle(hComm); + return dwRet; + } + + SetupComm (hComm, 4096, 4096); + + // Open Mcx handle + // + if ((dwRet = MCXOpen(pLineDev->szDeviceName, + hComm, + pLineDev->szDriverKey, + &pLineDev->hModem, + pLineDev->dwID, + (DWORD)pLineDev)) + == ERROR_SUCCESS) + { + pLineDev->hDevice = hComm; + + // Set the modem configuration + // + UnimodemSetCommConfig(pLineDev, (LPCOMMCONFIG)lpComConfig, dwSize); + } + else + { + CloseHandle(hComm); + }; + + return (MapMcxResult(dwRet)); +} + +//**************************************************************************** +// DWORD CloseModem (PLINEDEV) +// +// Function: Opens the modem device. +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD CloseModem (PLINEDEV pLineDev) +{ + TSPPRINTF("Close modem"); + + // + // close comm handle as well + // + MCXClose( + pLineDev->hModem, + pLineDev->hDevice, + pLineDev->LineClosed + ); + + pLineDev->hModem = NULL; + pLineDev->hDevice = INVALID_DEVICE; + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD UnimodemInit (PLINEDEV) +// +// Function: Initializes the modem device. +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemInit (PLINEDEV pLineDev) +{ + MCX_IN mcxi; + DWORD dwRet; + LPCOMMCONFIG lpCommConfig; + + lpCommConfig = (LPCOMMCONFIG)&(pLineDev->pDevCfg->commconfig); + + // set the new configuration + // + UnimodemSetCommConfig(pLineDev, + lpCommConfig, lpCommConfig->dwSize); + + + + // Prepare the input/output information + // + pLineDev->dwVxdPendingID++; + + mcxi.dwReqID = pLineDev->dwVxdPendingID; + mcxi.pMcxOut = &pLineDev->McxOut; + + pLineDev->McxOut.dwReqID = mcxi.dwReqID; + pLineDev->McxOut.dwResult = MDM_FAILURE; + + TSPPRINTF1("UnimodemInit id: %d", pLineDev->dwVxdPendingID); + + pLineDev->InitStringsAreValid=TRUE; + + dwRet = MCXInit(pLineDev->hModem, &mcxi); + dwRet = MapMcxResult(dwRet); + + // If the MCX call returns success, converts it to async success + // + if (dwRet == ERROR_SUCCESS) + { + // The operation completes successfully synchronously + // + dwRet = ERROR_IO_PENDING; + pLineDev->McxOut.dwResult = MDM_SUCCESS; + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD UnimodemDial (PLINEDEV, LPSTR) +// +// Function: dials the modem device with the provided dialable string. A dial- +// able string can be: +// "" - originate +// ";" - dialtone detection +// "5551212" - dial and originate +// "5551212;" - dial +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD +UnimodemDial( + PLINEDEV pLineDev, + LPSTR szAddress, + DWORD DialOptions + ) +{ + MCX_IN mcxi; + DWORD dwRet; + char szPhone[MAXADDRESSLEN+1]; + + // Prepare the input/output information + // + pLineDev->dwVxdPendingID++; + + mcxi.dwReqID = pLineDev->dwVxdPendingID; + mcxi.pMcxOut = &pLineDev->McxOut; + + pLineDev->McxOut.dwReqID = mcxi.dwReqID; + pLineDev->McxOut.dwResult = MDM_FAILURE; + + lstrcpyA(szPhone, szAddress); + + TSPPRINTF1("UnmodemDial id: %d", pLineDev->dwVxdPendingID); + + dwRet = MCXDial(pLineDev->hModem, szPhone, &mcxi, DialOptions); + dwRet = MapMcxResult(dwRet); + + // If the MCX call returns success, converts it to async success + // + if (dwRet == ERROR_SUCCESS) + { + // The operation completes successfully synchronously + // + dwRet = ERROR_IO_PENDING; + pLineDev->McxOut.dwResult = MDM_SUCCESS; + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD UnimodemMonitor (PLINEDEV, DWORD) +// +// Function: Monitors the modem for an incoming call in two modes: +// MONITOR_NON_CONTINUOUS - Notify the first ring only +// MONITOR_CONTINUOUS - Notify each ring +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemMonitor (PLINEDEV pLineDev, DWORD dwType) +{ + MCX_IN mcxi; + DWORD dwRet; + + // Prepare the input/output information + // + pLineDev->dwVxdPendingID++; + + mcxi.dwReqID = pLineDev->dwVxdPendingID; + mcxi.pMcxOut = &pLineDev->McxOut; + + pLineDev->McxOut.dwReqID = mcxi.dwReqID; + pLineDev->McxOut.dwResult = MDM_FAILURE; + + TSPPRINTF1("UnmodemMonitor id: %d", pLineDev->dwVxdPendingID); + + dwRet = MCXMonitor(pLineDev->hModem, dwType, &mcxi); + dwRet = MapMcxResult(dwRet); + + // If the MCX call returns success, converts it to async success + // + if (dwRet == ERROR_SUCCESS) + { + // The operation completes successfully synchronously + // + dwRet = ERROR_IO_PENDING; + pLineDev->McxOut.dwResult = MDM_SUCCESS; + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD UnimodemAnswer (PLINEDEV) +// +// Function: Answers the incoming call.. +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemAnswer (PLINEDEV pLineDev) +{ + MCX_IN mcxi; + DWORD dwRet; + + // Prepare the input/output information + // + pLineDev->dwVxdPendingID++; + + mcxi.dwReqID = pLineDev->dwVxdPendingID; + mcxi.pMcxOut = &pLineDev->McxOut; + + pLineDev->McxOut.dwReqID = mcxi.dwReqID; + pLineDev->McxOut.dwResult = MDM_FAILURE; + + TSPPRINTF1("UnmodemAnswer id: %d", pLineDev->dwVxdPendingID); + + dwRet = MCXAnswer(pLineDev->hModem, &mcxi); + dwRet = MapMcxResult(dwRet); + + // If the MCX call returns success, converts it to async success + // + if (dwRet == ERROR_SUCCESS) + { + // The operation completes successfully synchronously + // + dwRet = ERROR_IO_PENDING; + pLineDev->McxOut.dwResult = MDM_SUCCESS; + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + }; + + return dwRet; +} + +VOID WINAPI +DisconnectHandler( + PLINEDEV pLineDev + ) + +{ + TSPPRINTF("DisconnectHandle:"); + + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NORMAL); + + return; + +} + + + +//**************************************************************************** +// DWORD UnimodemMonitorDisconnect (PLINEDEV) +// +// Function: Monitors the remote disconnection. When the remote disconnection +// occurs, the function completes successfully in the async thread. +// +// Notes: This function never returns success synchrnously +// +// Returns: ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for synchrnous failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemMonitorDisconnect (PLINEDEV pLineDev) +{ + + DWORD Result; + + Result=McxRegisterDisconectHandler( + pLineDev->hModem, + DisconnectHandler, + pLineDev + ); + + + return Result; + +} + +//**************************************************************************** +// DWORD UnimodemCancelMonitorDisconnect (PLINEDEV) +// +// Function: Cancel the pending monitoring remote disconnection request. +// The async thread always ignore the cancellation result. +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemCancelMonitorDisconnect (PLINEDEV pLineDev) +{ + DWORD dwRet; + + dwRet=McxDeregisterDisconnectHandler( + pLineDev->hModem + ); + + return dwRet; +} + +//**************************************************************************** +// DWORD UnimodemHangup (PLINEDEV, BOOL) +// +// Function: Disconnect the modem locally. The caller can specifies whether +// the function should complete synchrnously or asynchronously. +// +// Returns: ERROR_SUCCESS if success synchronously. +// ERROR_IO_PENDING if the operation will complete asynchronously +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemHangup (PLINEDEV pLineDev, BOOL fSync) +{ + MCX_IN mcxi; + DWORD dwRet; + + if(!fSync) + { + // Asynchronous request, use the default event + // + pLineDev->dwVxdPendingID++; + + TSPPRINTF1("UnmodemAsyncHangup id: %d", pLineDev->dwVxdPendingID); + } + else + { + // Synchronous request, create a local event so we can wait for it here + // + if ((pLineDev->hSynchronizeEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) + { + return ERROR_OUTOFMEMORY; + }; + + TSPPRINTF("UnmodemSyncHangup"); + }; + + // Prepare the input/output information + // + mcxi.dwReqID = pLineDev->dwVxdPendingID; + mcxi.pMcxOut = &pLineDev->McxOut; + + pLineDev->McxOut.dwReqID = mcxi.dwReqID; + pLineDev->McxOut.dwResult = MDM_FAILURE; + + // Hang up the line + // + dwRet = MCXHangup(pLineDev->hModem, &mcxi); + dwRet = MapMcxResult(dwRet); + + switch(dwRet) + { + case ERROR_SUCCESS: + // + // The operation completes successfully synchronously + // + pLineDev->McxOut.dwResult = MDM_SUCCESS; + + // If the operation is an async request, handles the result asynchronously + // + if (fSync) + { + TSPPRINTF("UnmodemSyncHangup completes"); + CloseHandle(pLineDev->hSynchronizeEvent); + pLineDev->hSynchronizeEvent = NULL; + } + else + { + dwRet = ERROR_IO_PENDING; + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + }; + break; + + case ERROR_IO_PENDING: + // + // If it is synchronous request, need to wait until it is done + // + if (fSync) + { + RELEASE_LINEDEV(pLineDev); + WaitForSingleObject(pLineDev->hSynchronizeEvent, INFINITE); + CLAIM_LINEDEV(pLineDev); + CloseHandle(pLineDev->hSynchronizeEvent); + pLineDev->hSynchronizeEvent = NULL; + dwRet = ERROR_SUCCESS; + }; + break; + + default: + break; + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD UnimodemGetCommConfig (PLINEDEV, LPCOMMCONFIG, LPDWORD) +// +// Function: Gets the modem comm configuration +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemGetCommConfig (PLINEDEV pLineDev, LPCOMMCONFIG lpCommConfig, + LPDWORD lpcb) +{ + DWORD dwRet; + TSPPRINTF("UnimodemGetCommConfig."); + + dwRet = MCXGetCommConfig(pLineDev->hModem, lpCommConfig, lpcb); + return (MapMcxResult(dwRet)); +} + +//**************************************************************************** +// DWORD UnimodemSetCommConfig (PLINEDEV, LPCOMMCONFIG, DWORD) +// +// Function: Sets the modem comm configuration +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemSetCommConfig (PLINEDEV pLineDev, LPCOMMCONFIG lpCommConfig, + DWORD cb) +{ + DWORD dwRet; + TSPPRINTF("UnimodemSetCommConfig."); + + dwRet = MCXSetCommConfig(pLineDev->hModem, lpCommConfig, cb); + return (MapMcxResult(dwRet)); +} + + +#if 0 +//**************************************************************************** +// DWORD UnimodemSetCommConfig (PLINEDEV, LPCOMMCONFIG, DWORD) +// +// Function: Sets the modem comm configuration +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD WINAPI +UnimodemSetModemSettings( + PLINEDEV pLineDev, + LPMODEMSETTINGS lpModemSettings + ) +{ + DWORD dwRet; + TSPPRINTF("UnimodemSetModemSettings."); + + dwRet = MCXSetModemSettings(pLineDev->hModem, lpModemSettings); + + return (MapMcxResult(dwRet)); +} +#endif + + + + +//**************************************************************************** +// DWORD UnimodemSetPassthrough (PLINEDEV, DWORD) +// +// Function: Sets the modem passthrough mode to: +// PASSTHROUGH_ON +// PASSTHROUGH_OFF +// PASSTHROUGH_OFF_BUT_CONNECTED +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemSetPassthrough (PLINEDEV pLineDev, DWORD dwMode) +{ + DWORD dwRet; + TSPPRINTF1("UnimodemSetPassthrough mode: %d", dwMode); + + dwRet = MCXSetPassthrough(pLineDev->hModem, dwMode); + return (MapMcxResult(dwRet)); +} + +//**************************************************************************** +// DWORD UnimodemGetNegotiatedRate (PLINEDEV, LPDWORD) +// +// Function: Gets the modem connection speed +// +// Notes: This function is synchronous. +// +// Returns: ERROR_SUCCESS if success +// an error code for failure +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD UnimodemGetNegotiatedRate (PLINEDEV pLineDev, LPDWORD lpdwRate) +{ + DWORD dwRet; + + dwRet = MCXGetNegotiatedRate(pLineDev->hModem, lpdwRate); + return (MapMcxResult(dwRet)); +} diff --git a/private/unimodem/tapisp/log.c b/private/unimodem/tapisp/log.c new file mode 100644 index 000000000..30589a2ae --- /dev/null +++ b/private/unimodem/tapisp/log.c @@ -0,0 +1,425 @@ + +#include "unimdm.h" +#include "mcxp.h" + +#include + +#define MAX_LOG_SIZE (128 * 1024) +#define LOG_TEMP_BUFFER_SIZE (4096) + + + +VOID WINAPI +ResizeLogFile( + HANDLE FileHandle + ); + + + + +HANDLE WINAPI +ModemOpenLog( + LPSTR pszName + ) + +{ + HANDLE FileHandle; + + FileHandle=CreateFileA( + pszName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (INVALID_HANDLE_VALUE == FileHandle) { + + return NULL; + + } + + SetFilePointer( + FileHandle, + 0, + NULL, + FILE_END + ); + + return FileHandle; + +} + + +VOID WINAPIV +LogPrintf( + HANDLE FileHandle, + DWORD dwDeviceID, + LPSTR FormatString, + ... + ) + +{ + DWORD BytesWritten; + BOOL Result; + va_list VarArg; + SYSTEMTIME SysTime; + char OutBuffer[1024]; + + TRACE3(IDEVENT_LOG_PRINTF, dwDeviceID, &FormatString); + + if (FileHandle == NULL) { + + return; + } + + va_start(VarArg,FormatString); + + GetLocalTime( + &SysTime + ); + + wsprintfA( + OutBuffer, + "%02d-%02d-%04d %02d:%02d:%02d.%03d - ", + SysTime.wMonth, + SysTime.wDay, + SysTime.wYear, + SysTime.wHour, + SysTime.wMinute, + SysTime.wSecond, + SysTime.wMilliseconds + ); + + + wvsprintfA( + OutBuffer+lstrlenA(OutBuffer), + FormatString, + VarArg + ); + + Result=WriteFile( + FileHandle, + OutBuffer, + lstrlenA(OutBuffer), + &BytesWritten, + NULL + ); + +#ifdef DEBUG + if (!Result) { + + DPRINTF("Write to log failed."); + } +#endif + + ResizeLogFile( + FileHandle + ); + + return; + + +} + + + + +VOID WINAPI +ModemCloseLog( + HANDLE FileHandle + ) + +{ + if (FileHandle == NULL) { + + return; + } + + CloseHandle( + FileHandle + ); + + return; + +} + +VOID WINAPI +FlushLog( + HANDLE FileHandle + ) + +{ + if (FileHandle == NULL) { + + return; + } + + + FlushFileBuffers(FileHandle); + + return; + +} + + + +VOID WINAPI +LogString( + HANDLE FileHandle, + DWORD dwDeviceID, + DWORD StringID, + ... + ) + +{ + + + + DWORD BytesWritten; + BOOL Result; + va_list VarArg; + SYSTEMTIME SysTime; + char OutBuffer[1024]; + char FormatString[256]; + int Length; + + TRACE3(IDEVENT_LOG_STRING, dwDeviceID, &StringID); + + if (FileHandle == NULL) { + + return; + } + + Length=LoadStringA( + ghInstance, + StringID, + FormatString, + sizeof(FormatString) + ); + + if (Length == 0) { + +#ifdef DEBUG + lstrcpyA(FormatString,"Bad String resource"); +#else + return; +#endif + + } + + + + va_start(VarArg,StringID); + + GetLocalTime( + &SysTime + ); + + wsprintfA( + OutBuffer, + "%02d-%02d-%04d %02d:%02d:%02d.%03d - ", + SysTime.wMonth, + SysTime.wDay, + SysTime.wYear, + SysTime.wHour, + SysTime.wMinute, + SysTime.wSecond, + SysTime.wMilliseconds + ); + + + wvsprintfA( + OutBuffer+lstrlenA(OutBuffer), + FormatString, + VarArg + ); + + Result=WriteFile( + FileHandle, + OutBuffer, + lstrlenA(OutBuffer), + &BytesWritten, + NULL + ); + +#ifdef DEBUG + if (!Result) { + + DPRINTF("Write to log failed."); + } +#endif + + ResizeLogFile( + FileHandle + ); + + return; + + +} + + + + + +VOID WINAPI +ResizeLogFile( + HANDLE FileHandle + ) + +{ + + DWORD FileSize; + LPBYTE TempBuffer; + OVERLAPPED OverLapped; + DWORD BytesRead; + BOOL bResult; + UINT i; + DWORD DestFileOffset; + DWORD SourceFileOffset; + DWORD BytesToMove; + + + FileSize=GetFileSize(FileHandle,NULL); + + if (FileSize < MAX_LOG_SIZE) { + + return; + + } + + D_TRACE(McxDpf(999,"Resizing log File, size=%d",FileSize);) + + TempBuffer=LocalAlloc(LPTR,(LOG_TEMP_BUFFER_SIZE)); + + if (TempBuffer == NULL) { + + return; + + } + + OverLapped.hEvent=NULL; + OverLapped.OffsetHigh=0; + OverLapped.Offset=FileSize-(MAX_LOG_SIZE/2); + + + bResult=ReadFile( + FileHandle, + TempBuffer, + LOG_TEMP_BUFFER_SIZE, + &BytesRead, + &OverLapped + ); + + + if (!bResult) { + + LocalFree(TempBuffer); + + return; + + } + + // + // find the first character following a line feed + // + for (i=0; i < LOG_TEMP_BUFFER_SIZE; i++) { + + if (TempBuffer[i] == '\n') { + + break; + + } + } + + // + // source starts first char after LF + // + SourceFileOffset=(FileSize-(MAX_LOG_SIZE/2)) + i + 1; + + DestFileOffset=0; + + BytesToMove=FileSize-SourceFileOffset; + + while (BytesToMove > 0) { + + DWORD BytesNow; + DWORD BytesWritten; + + OverLapped.hEvent=NULL; + OverLapped.OffsetHigh=0; + OverLapped.Offset=SourceFileOffset; + + BytesNow= BytesToMove < LOG_TEMP_BUFFER_SIZE ? BytesToMove : LOG_TEMP_BUFFER_SIZE; + + bResult=ReadFile( + FileHandle, + TempBuffer, + BytesNow, + &BytesRead, + &OverLapped + ); + + if (!bResult || BytesRead != BytesNow) { + // + // something bad happened, truncate the file + // + DestFileOffset=0; + + break; + + } + + OverLapped.hEvent=NULL; + OverLapped.OffsetHigh=0; + OverLapped.Offset=DestFileOffset; + + + bResult=WriteFile( + FileHandle, + TempBuffer, + BytesRead, + &BytesWritten, + &OverLapped + ); + + if (!bResult || BytesWritten != BytesNow) { + // + // something bad happened, truncate the file + // + DestFileOffset=0; + + break; + + } + + + BytesToMove-=BytesRead; + SourceFileOffset+=BytesRead; + DestFileOffset+=BytesRead; + + } + + SetFilePointer( + FileHandle, + DestFileOffset, + NULL, + FILE_BEGIN + ); + + SetEndOfFile( + FileHandle + ); + + + LocalFree( + TempBuffer + ); + + + return; + +} diff --git a/private/unimodem/tapisp/log.rc b/private/unimodem/tapisp/log.rc new file mode 100644 index 000000000..4b5724c5d --- /dev/null +++ b/private/unimodem/tapisp/log.rc @@ -0,0 +1,153 @@ +//Microsoft Developer Studio generated resource script. +// +#include "logids.h" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_OK "OK" + IDS_RESP_INFORMATIVE "Informative" + IDS_RESP_CONNECT "Connect" + IDS_RESP_ERROR "Error" + IDS_RESP_NO_CARRIER "No Carrier" + IDS_RESP_NO_DIALTONE "No Dialtone" + IDS_RESP_BUSY "Busy" + IDS_RESP_NO_ANSWER "No Answer" + IDS_RESP_RING "Ring" + IDS_RESP_SSV "SSV" + IDS_RESP_SMD "SMD" + IDS_RESP_SFA "SFA" + IDS_RESP_SRA "SRA" + IDS_RESP_SRQ "SRQ" + IDS_RESP_SRC "SRC" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_STO "STO" + IDS_RESP_SVM "SVM" + IDS_RESP_DRON "DRON" + IDS_RESP_DROF "DROF" + IDS_RESP_DATE "DATE" + IDS_RESP_TIME "TIME" + IDS_RESP_NMBR "NMBR" + IDS_RESP_NAME "NAME" + IDS_RESP_MESG "MESG" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_UNKNOWN "Unknown Response\r\n" + + + + + IDS_MSGLOG_CONNECTED "Connection established.\r\n" + IDS_MSGLOG_CONNECTEDBPS "Connection established at %dbps.\r\n" + IDS_MSGLOG_UNKNOWNERRORCONTROL "Error-control off or unknown.\r\n" + IDS_MSGLOG_CELLULAR "Cellular error-control on.\r\n" + IDS_MSGLOG_ERRORCONTROL "Error-control on.\r\n" + IDS_MSGLOG_COMPRESSION "Data compression on.\r\n" + IDS_MSGLOG_UNKNOWNCOMPRESSION "Data compression off or unknown.\r\n" + + IDS_MSGPERF_WRDESC "Bytes sent to modem per second.\r\n" + IDS_MSGPERF_WRNAME "Bytes sent/sec\r\n" + IDS_MSGPERF_WRREG "SendRate\r\n" + IDS_MSGPERF_RDDESC "Bytes received from modem per second.\r\n" + IDS_MSGPERF_RDNAME "Bytes received/sec\r\n" + IDS_MSGPERF_RDREG "ReceiveRate\r\n" + IDS_MSGPERF_UNITS "Bytes\r\n" + + IDS_MSGLOG_STATISTICS "Session Statistics:\r\n" + IDS_MSGLOG_READSTATS " Reads : %d bytes\r\n" + IDS_MSGLOG_WRITESTATS " Writes: %d bytes\r\n" + IDS_MSGLOG_FRAMEERRORSTATS " Frame Errors: %d\r\n" + IDS_MSGLOG_SERIALOVERRUNERRORSTATS "Serial Overrun Errors: %d\r\n" + IDS_MSGLOG_BUFFEROVERRUNERRORSTATS "Buffer Overrun Errors: %d\r\n" + IDS_MSGLOG_PARITYERRORSTATS " Parity Errors: %d\r\n" + + IDS_MSGERR_FAILED_INITSTRINGCONSTRUCTION "ERROR: Init string construction failed.\r\n" + IDS_MSGERR_FAILED_INIT "ERROR: Init failed.\r\n" + IDS_MSGERR_FAILED_DIALSTRINGCONSTRUCTION "ERROR: Dial string construction failed for '%s'.\r\n" + IDS_MSGERR_FAILED_DIAL "ERROR: Dial failed.\r\n" + IDS_MSGERR_FAILED_MONITOR "ERROR: Monitor failed.\r\n" + IDS_MSGERR_FAILED_ANSWER "ERROR: Answer failed.\r\n" + IDS_MSGERR_FAILED_HANGUP "ERROR: Hangup failed.\r\n" + IDS_MSGERR_FAILED_FLUSH "ERROR: Unable to send command to the device.\r\n" + IDS_MSGERR_FAILED_RESPONSE "ERROR: Unable to recover from unrecognized response.\r\n" + + IDS_MSGERR_FAILED_VOICE_ANSWER "ERROR: Voice Answer failed.\r\n" + + IDS_MSGERR_FAILED_VOICE_DIALSETUP "ERROR: Voice dial setup failed.\r\n" + + IDS_MSGERR_FAILED_VOICE_COMMAND "ERROR: Voice Command failed. %s\r\n" + + IDS_MSGERR_FAILED_VOICE_STARTWAVE "ERROR: Start wave play/record failed.\r\n" + IDS_MSGERR_FAILED_VOICE_STOPWAVE "ERROR: Stop wave play/record failed.\r\n" + IDS_MSGERR_FAILED_VOICE_SETFORMAT "ERROR: Failed to set wave foramt.\r\n" + + IDS_MSGERR_FAILED_VOICE_WAVEOPEN "ERROR: Failed Wave Open.\r\n" + + IDS_MSGERR_FAILED_VOICE_WAVECLOSE "ERROR: Failed Wave Close.\r\n" + + IDS_MSGERR_FAILED_VOICE_SPEAKERPHONECOMMAND "ERROR: Speaker Phaone Command Failed.\r\n" + + IDS_MSGERR_FAILED_VOICE_GENERATEDTMF "ERROR: Generate DTMF failed.\r\n" + + + IDS_MSGWARN_UNRECOGNIZEDRESPONSE "WARNING: Unrecognized response. Retrying...\r\n" + IDS_MSGWARN_FAILEDTOQUERYVALUE "WARNING: Unable to load the '%s' string.\r\n" + IDS_MSGWARN_FAILEDDTRDROPPAGE "WARNING: The modem did not respond to lowering DTR. Trying software hangup...\r\n" + IDS_MSGWARN_PREVIOUSCONNECTIONNOTHUNGUP "WARNING: A previous program left a connection established. Hanging up previous connection...\r\n" + + IDS_MSGLOG_OPENED "%s in use.\r\n" + IDS_MSGLOG_DRIVERDESC "Modem type: %s\r\n" + IDS_MSGLOG_INFPATH "Modem inf path: %s\r\n" + IDS_MSGLOG_INFSECTION "Modem inf section: %s\r\n" + IDS_MSGLOG_CLOSED "Modem closed.\r\n" + + + IDS_MSGLOG_DIAL "Dialing.\r\n" + IDS_MSGLOG_MONITOR "Waiting for a call.\r\n" + IDS_MSGLOG_ANSWER "Answering the call.\r\n" + IDS_MSGLOG_INIT "Initializing modem.\r\n" + IDS_MSGLOG_HANGUP "Hanging up the modem.\r\n" + + + IDS_MSGLOG_VOICE_ANSWER "Answering the voice call.\r\n" + + IDS_MSGLOG_VOICE_DIALSETUP "Setup to dial voice call.\r\n" + + IDS_MSGLOG_VOICE_COMMAND "Issueing voice command.\r\n" + + + IDS_MSGLOG_VOICE_STARTWAVE "Starting wave play/record.\r\n" + IDS_MSGLOG_VOICE_STOPWAVE "Ending wave play/record.\r\n" + + IDS_MSGLOG_VOICE_SETWAVEFORMAT "Setting wave format.\r\n" + + IDS_MSGLOG_VOICE_WAVEOPEN "Voice Modem Wave Open.\r\n" + + IDS_MSGLOG_VOICE_WAVECLOSE "Voice Modem Wave Close.\r\n" + + IDS_MSGLOG_VOICE_SPEAKERPHONECOMMAND "Issueing Speakerphone command.\r\n" + + IDS_MSGLOG_VOICE_GENTERAEDTMF "Generating DTMF.\r\n" + + IDS_MSGLOG_VOICE_DLERECEIVED "Received DLE Raw=%d, Translated=%d.\r\n" + + +IDS_MSGLOG_HARDWAREHANGUP "Hardware hangup by lowering DTR.\r\n" +IDS_MSGLOG_REMOTEHANGUP "Remote modem hung up.\r\n" +IDS_MSGLOG_COMMAND "Send: %s\r\n" +IDS_MSGLOG_RAWRESPONSE "Recv: %s\r\n" +IDS_MSGLOG_EMPTYRESPONSE "\r\n" +IDS_MSGLOG_RESPONSE "Interpreted response: %s\r\n" + + + +END diff --git a/private/unimodem/tapisp/logids.h b/private/unimodem/tapisp/logids.h new file mode 100644 index 000000000..0b666097e --- /dev/null +++ b/private/unimodem/tapisp/logids.h @@ -0,0 +1,134 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by log.rc +// +#define IDS_RESP_OK 1 +#define IDS_RESP_INFORMATIVE 2 +#define IDS_RESP_CONNECT 3 +#define IDS_RESP_ERROR 4 +#define IDS_RESP_NO_CARRIER 5 +#define IDS_RESP_NO_DIALTONE 6 +#define IDS_RESP_BUSY 7 +#define IDS_RESP_NO_ANSWER 8 +#define IDS_RESP_RING 9 +#define IDS_RESP_SSV 10 +#define IDS_RESP_SMD 11 +#define IDS_RESP_SFA 12 +#define IDS_RESP_SRA 13 +#define IDS_RESP_SRQ 14 +#define IDS_RESP_SRC 15 +#define IDS_RESP_STO 16 +#define IDS_RESP_SVM 17 +#define IDS_RESP_DRON 18 +#define IDS_RESP_DROF 19 +#define IDS_RESP_DATE 20 +#define IDS_RESP_TIME 21 +#define IDS_RESP_NMBR 22 +#define IDS_RESP_NAME 23 +#define IDS_RESP_MESG 24 +#define IDS_RESP_UNKNOWN 50 + + + +#define IDS_MSGLOG_CONNECTED 51 +#define IDS_MSGLOG_CONNECTEDBPS 52 +#define IDS_MSGLOG_UNKNOWNERRORCONTROL 53 +#define IDS_MSGLOG_CELLULAR 54 +#define IDS_MSGLOG_ERRORCONTROL 55 +#define IDS_MSGLOG_COMPRESSION 56 +#define IDS_MSGLOG_UNKNOWNCOMPRESSION 57 + +#define IDS_MSGPERF_WRDESC 59 +#define IDS_MSGPERF_WRNAME 60 +#define IDS_MSGPERF_WRREG 61 +#define IDS_MSGPERF_RDDESC 62 +#define IDS_MSGPERF_RDNAME 63 +#define IDS_MSGPERF_RDREG 64 +#define IDS_MSGPERF_UNITS 65 + +#define IDS_MSGLOG_STATISTICS 67 +#define IDS_MSGLOG_READSTATS 68 +#define IDS_MSGLOG_WRITESTATS 69 +#define IDS_MSGLOG_FRAMEERRORSTATS 71 +#define IDS_MSGLOG_SERIALOVERRUNERRORSTATS 73 +#define IDS_MSGLOG_BUFFEROVERRUNERRORSTATS 74 +#define IDS_MSGLOG_PARITYERRORSTATS 75 + +#define IDS_MSGERR_FAILED_INITSTRINGCONSTRUCTION 77 +#define IDS_MSGERR_FAILED_INIT 78 +#define IDS_MSGERR_FAILED_DIALSTRINGCONSTRUCTION 79 +#define IDS_MSGERR_FAILED_DIAL 80 +#define IDS_MSGERR_FAILED_MONITOR 81 +#define IDS_MSGERR_FAILED_ANSWER 82 +#define IDS_MSGERR_FAILED_HANGUP 83 +#define IDS_MSGERR_FAILED_FLUSH 84 +#define IDS_MSGERR_FAILED_RESPONSE 85 + +#define IDS_MSGERR_FAILED_VOICE_ANSWER 87 + +#define IDS_MSGERR_FAILED_VOICE_DIALSETUP 89 + +#define IDS_MSGERR_FAILED_VOICE_COMMAND 91 + +#define IDS_MSGERR_FAILED_VOICE_STARTWAVE 93 +#define IDS_MSGERR_FAILED_VOICE_STOPWAVE 94 +#define IDS_MSGERR_FAILED_VOICE_SETFORMAT 95 + +#define IDS_MSGERR_FAILED_VOICE_WAVEOPEN 97 + +#define IDS_MSGERR_FAILED_VOICE_WAVECLOSE 99 + +#define IDS_MSGERR_FAILED_VOICE_SPEAKERPHONECOMMAND 202 + +#define IDS_MSGERR_FAILED_VOICE_GENERATEDTMF 203 + + +#define IDS_MSGWARN_UNRECOGNIZEDRESPONSE 204 +#define IDS_MSGWARN_FAILEDTOQUERYVALUE 205 +#define IDS_MSGWARN_FAILEDDTRDROPPAGE 206 +#define IDS_MSGWARN_PREVIOUSCONNECTIONNOTHUNGUP 207 + +#define IDS_MSGLOG_OPENED 211 +#define IDS_MSGLOG_DRIVERDESC 212 +#define IDS_MSGLOG_INFPATH 213 +#define IDS_MSGLOG_INFSECTION 214 +#define IDS_MSGLOG_CLOSED 215 + + + +#define IDS_MSGLOG_DIAL 216 +#define IDS_MSGLOG_MONITOR 217 +#define IDS_MSGLOG_ANSWER 218 +#define IDS_MSGLOG_INIT 219 +#define IDS_MSGLOG_HANGUP 220 + + +#define IDS_MSGLOG_VOICE_ANSWER 221 + +#define IDS_MSGLOG_VOICE_DIALSETUP 222 + +#define IDS_MSGLOG_VOICE_COMMAND 223 + + +#define IDS_MSGLOG_VOICE_STARTWAVE 224 +#define IDS_MSGLOG_VOICE_STOPWAVE 225 + +#define IDS_MSGLOG_VOICE_SETWAVEFORMAT 226 + +#define IDS_MSGLOG_VOICE_WAVEOPEN 227 + +#define IDS_MSGLOG_VOICE_WAVECLOSE 228 + +#define IDS_MSGLOG_VOICE_SPEAKERPHONECOMMAND 229 + +#define IDS_MSGLOG_VOICE_GENTERAEDTMF 230 + +#define IDS_MSGLOG_VOICE_DLERECEIVED 231 + + +#define IDS_MSGLOG_HARDWAREHANGUP 232 +#define IDS_MSGLOG_REMOTEHANGUP 233 +#define IDS_MSGLOG_COMMAND 234 +#define IDS_MSGLOG_RAWRESPONSE 235 +#define IDS_MSGLOG_EMPTYRESPONSE 236 +#define IDS_MSGLOG_RESPONSE 237 diff --git a/private/unimodem/tapisp/makefile b/private/unimodem/tapisp/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/unimodem/tapisp/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/unimodem/tapisp/manual.c b/private/unimodem/tapisp/manual.c new file mode 100644 index 000000000..4731252e0 --- /dev/null +++ b/private/unimodem/tapisp/manual.c @@ -0,0 +1,170 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: manual.c +// +// Copyright (c) 1992-1995, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 3/1/94 Chris Caputo Created +// +// +// Description: Manual dial dialog. +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" +#include "wndthrd.h" +#include "rcids.h" + +//**************************************************************************** +// Function prototypes +//**************************************************************************** + +LRESULT ManualDialDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam); + +//**************************************************************************** +// HWND CreateManualDlg(HWND hwndOwner, DWORD idLine) +// +// Function: creates a modeless talk/drop dialog box +// +// Returns: the modeless window handle +// +//**************************************************************************** + +HWND CreateManualDlg(HWND hwndOwner, DWORD idLine) +{ + HWND hwnd; + + // Create dialog + // + hwnd = CreateDialogParam(ghInstance, + MAKEINTRESOURCE(IDD_MANUAL_DIAL), + hwndOwner, + ManualDialDlgProc, + (LPARAM)idLine); + return hwnd; +} + +//**************************************************************************** +// LRESULT ManualDialDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam) +// +// Function: Talk-Drop dialog routine +// +// Returns: varies +// +//**************************************************************************** + +LRESULT ManualDialDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) +{ + DWORD idLine; + + switch(wMsg) + { + case WM_INITDIALOG: + + { + NUMBERREQ NumberReq; + TCHAR szUnicodeBuf[MAXDEVICENAME+1]; + PDLGNODE pDlgNode; + TUISPIDLLCALLBACK Callback; + + pDlgNode=(PDLGNODE)lParam; + + idLine = pDlgNode->idLine; + + // remember the Line ID passed in + // + SetWindowLong(hwnd, DWL_USER, (LONG)lParam); + + NumberReq.DlgReq.dwCmd = UI_REQ_GET_PHONENUMBER; + NumberReq.DlgReq.dwParam = MANUAL_DIAL_DLG; + + Callback=GetCallbackProc(pDlgNode->Parent); + + lstrcpyA(NumberReq.szPhoneNumber,""); + + (*Callback)(idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&NumberReq, sizeof(NumberReq)); + +#ifdef UNICODE + if (MultiByteToWideChar(CP_ACP, + 0, + NumberReq.szPhoneNumber, + -1, + szUnicodeBuf, + sizeof(szUnicodeBuf))) + { + SetDlgItemText( + hwnd, + IDC_PHONENUMBER, + szUnicodeBuf + ); + + + } +#else // UNICODE + + SetDlgItemText( + hwnd, + IDC_PHONENUMBER, + NumberReq.szPhoneNumber + ); + + +#endif // UNICODE + + + + return 1; + break; + } + case WM_COMMAND: + { + UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam); + + + + if (idCmd == IDCONNECT || idCmd == IDCANCEL) + { + PDLGNODE pDlgNode; + + pDlgNode= (PDLGNODE)GetWindowLong(hwnd, DWL_USER); + + idLine = pDlgNode->idLine; + + EndMdmDialog(pDlgNode->Parent,idLine, MANUAL_DIAL_DLG, + (idCmd == IDCONNECT) ? MDM_SUCCESS : MDM_FAILURE); + return 1; + break; + } + break; + } + case WM_DESTROY: + { + DLGREQ DlgReq; + TUISPIDLLCALLBACK Callback; + + PDLGNODE pDlgNode; + + pDlgNode= (PDLGNODE)GetWindowLong(hwnd, DWL_USER); + + idLine = pDlgNode->idLine; + + + DlgReq.dwCmd = UI_REQ_END_DLG; + DlgReq.dwParam = MANUAL_DIAL_DLG; + + Callback=GetCallbackProc(pDlgNode->Parent); + + (*Callback)(idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&DlgReq, sizeof(DlgReq)); + break; + } + } + + return 0; +} diff --git a/private/unimodem/tapisp/mcxapi.c b/private/unimodem/tapisp/mcxapi.c new file mode 100644 index 000000000..634873cd1 --- /dev/null +++ b/private/unimodem/tapisp/mcxapi.c @@ -0,0 +1,591 @@ +/* + mcxapi.c + + MCX - Modem Configuration Extensions API + + Chris Caputo - January 1994 +*/ + +#include "unimdm.h" +#include "mcxp.h" + +char szSettings[] = "Settings"; +char szSettingsInit[] = "Settings\\Init"; +char szPrefix[] = "Prefix"; +char szTerminator[] = "Terminator"; + +#define MAX_REG_COMMAND_LEN 30 // BUGBUG - verify this with each change to the inf file + +//**************************************************************************** +// BOOL CreateSettingsInitEntry(MODEMINFORMATION *) +// +// Function: Creates a Settings\Init section in the registry, ala: +// Settings\Init\0 = "AT ... " +// Settings\Init\1 = "AT ... " +// ... +// +// Returns: TRUE on success +// FALSE on failure (note: leaves SettingsInit key in registry, if created. Not harmful) +// +// Note: Trusted function - don't need to verify hPort... +//**************************************************************************** + +BOOL CreateSettingsInitEntry(MODEMINFORMATION *pModemInfo) +{ + DWORD dwOptions = pModemInfo->mi_dwPreferredModemOptions; + DWORD dwCaps = pModemInfo->mi_dwModemOptionsCap; + CHAR *pszTemp; + CHAR *pszPrefix; + CHAR *pszTerminator; + CHAR *pszCommand; + DWORD dwResult; + HKEY hSettingsInitKey; + HKEY hSettingsKey; + DWORD dwType; + DWORD dwSize; + DWORD dwCounter = CMD_INDEX_START; + BOOL fRet = FALSE; + static char szCallSetupFailTimer[] = "CallSetupFailTimer"; + static char szInactivityTimeout[] = "InactivityTimeout"; + static char szSpeakerVolume[] = "SpeakerVolume"; + static char szSpeakerMode[] = "SpeakerMode"; + static char szFlowControl[] = "FlowControl"; + static char szErrorControl[] = "ErrorControl"; + static char szCompression[] = "Compression"; + static char szModulation[] = "Modulation"; + static char szCCITT[] = "_CCITT"; + static char szBell[] = "_Bell"; + static char szCCITT_V23[] = "_CCITT_V23"; + static char szSpeedNegotiation[] = "SpeedNegotiation"; + static char szLow[] = "_Low"; + static char szMed[] = "_Med"; + static char szHigh[] = "_High"; + static char szSpkrModeDial[] = "_Dial"; + static char szSetup[] = "_Setup"; + static char szForced[] = "_Forced"; + static char szCellular[] = "_Cellular"; + static char szHard[] = "_Hard"; + static char szSoft[] = "_Soft"; + static char szOff[] = "_Off"; + static char szOn[] = "_On"; + + pszTemp = (LPSTR)LocalAlloc(LPTR, + HAYES_COMMAND_LENGTH + 1 + // pszTemp + HAYES_COMMAND_LENGTH + 1 + // pszPrefix + HAYES_COMMAND_LENGTH + 1 + // pszTerminator + MAX_REG_COMMAND_LEN); // pszCommand + if (!pszTemp) + { + DPRINTF("out of memory."); + LocalFree(pszTemp); + return fRet; + } + + pszPrefix = pszTemp + HAYES_COMMAND_LENGTH + 1; + pszTerminator = pszPrefix + HAYES_COMMAND_LENGTH + 1; + pszCommand = pszTerminator + HAYES_COMMAND_LENGTH + 1; + + // deleted existing szSettingsInit key tree + // + dwResult = RegDeleteKeyA(pModemInfo->mi_hKeyModem, szSettingsInit); + + // create new szSettingsInit key + // + // BUGBUG: JosephJ 7/3/96: We want to change this post 4.0 to not write to + // the registry -- keep this stuff in memory. I tried RegCreateKeyEx(REG_VOLATILE), + // but couldn't get measurable performance difference so I left things the way they + // are now. + if (RegCreateKeyA(pModemInfo->mi_hKeyModem, szSettingsInit, &hSettingsInitKey) + != ERROR_SUCCESS) + { + DPRINTF("RegCreateKey failed."); + LocalFree(pszTemp); + return fRet; + } + + // get Settings key + // + if (RegOpenKeyA(pModemInfo->mi_hKeyModem, szSettings, &hSettingsKey) + != ERROR_SUCCESS) + { + DPRINTFA1("RegOpenKey failed when opening %s.", szSettings); + RegCloseKey(hSettingsInitKey); + LocalFree(pszTemp); + return fRet; + } + + // read in prefix and terminator + // + dwSize = HAYES_COMMAND_LENGTH; + if (RegQueryValueExA(hSettingsKey, szPrefix, NULL, &dwType, (VOID *)pszTemp, &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s.", szPrefix); + goto Failure; + } + if (dwType != REG_SZ) + { + DPRINTFA1("'%s' wasn't REG_SZ.", szPrefix); + goto Failure; + } + ExpandMacros(pszTemp, pszPrefix, NULL, NULL, 0); + + dwSize = HAYES_COMMAND_LENGTH; + if (RegQueryValueExA(hSettingsKey, szTerminator, NULL, &dwType, (VOID *)pszTemp, &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s.", szTerminator); + goto Failure; + } + if (dwType != REG_SZ) + { + DPRINTFA1("'%s' wasn't REG_SZ.", szTerminator); + goto Failure; + } + ExpandMacros(pszTemp, pszTerminator, NULL, NULL, 0); + + ASSERT (lstrlenA(pszPrefix) + lstrlenA(pszTerminator) <= HAYES_COMMAND_LENGTH); + + // set temp length to 0 and initialize first command string for use in CreateCommand() + // + lstrcpyA(pszTemp, pszPrefix); + + // CallSetupFailTimer + // + if (pModemInfo->mi_dwCallSetupFailTimerCap) + { + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, szCallSetupFailTimer, + pModemInfo->mi_dwCallSetupFailTimerSetting, pszPrefix, pszTerminator, + &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // InactivityTimeout + // + if (pModemInfo->mi_dwInactivityTimeoutCap) + { + DWORD dwInactivityTimeout; + + // Convert from seconds to the units used on the modem, rounding up if not an exact division. + // + dwInactivityTimeout = pModemInfo->mi_dwInactivityTimeoutSetting / pModemInfo->mi_dwInactivityScale + + (pModemInfo->mi_dwInactivityTimeoutSetting % pModemInfo->mi_dwInactivityScale ? 1 : 0); + + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, szInactivityTimeout, + dwInactivityTimeout, pszPrefix, pszTerminator, + &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // BUGBUG - these could be optimized with a lookup-table + // SpeakerVolume + if (pModemInfo->mi_dwSpeakerVolumeCap) + { + lstrcpyA(pszCommand, szSpeakerVolume); + switch (pModemInfo->mi_dwSpeakerVolumeSetting) + { + case MDMVOL_LOW: + lstrcatA(pszCommand, szLow); + break; + case MDMVOL_MEDIUM: + lstrcatA(pszCommand, szMed); + break; + case MDMVOL_HIGH: + lstrcatA(pszCommand, szHigh); + break; + default: + DPRINTF("invalid SpeakerVolume."); + } + + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // SpeakerMode + // + if (pModemInfo->mi_dwSpeakerModeCap) + { + lstrcpyA(pszCommand, szSpeakerMode); + switch (pModemInfo->mi_dwSpeakerModeSetting) + { + case MDMSPKR_OFF: + lstrcatA(pszCommand, szOff); + break; + case MDMSPKR_DIAL: + lstrcatA(pszCommand, szSpkrModeDial); + break; + case MDMSPKR_ON: + lstrcatA(pszCommand, szOn); + break; + case MDMSPKR_CALLSETUP: + lstrcatA(pszCommand, szSetup); + break; + default: + DPRINTF("invalid SpeakerMode."); + } + + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // PreferredModemOptions + + // NOTE: ERRORCONTROL MUST BE DONE BEFORE COMPRESSION BECAUSE OF ZYXEL MODEMS + // NOTE: THEY HAVE A SINGLE SET OF COMMANDS FOR BOTH EC AND COMP, AND WE CAN + // NOTE: ONLY DO THINGS IF WE HAVE THIS ORDER. UGLY BUT TRUE. + + // - ErrorControl (On,Off,Forced) + // + if (dwCaps & MDM_ERROR_CONTROL) + { + lstrcpyA(pszCommand, szErrorControl); + switch (dwOptions & (MDM_ERROR_CONTROL | MDM_FORCED_EC | MDM_CELLULAR)) + { + case MDM_ERROR_CONTROL: + lstrcatA(pszCommand, szOn); + break; + case MDM_ERROR_CONTROL | MDM_FORCED_EC: + lstrcatA(pszCommand, szForced); + break; + case MDM_ERROR_CONTROL | MDM_CELLULAR: + lstrcatA(pszCommand, szCellular); + break; + case MDM_ERROR_CONTROL | MDM_FORCED_EC | MDM_CELLULAR: + lstrcatA(pszCommand, szCellular); + lstrcatA(pszCommand, szForced); + break; + default: // no error control + lstrcatA(pszCommand, szOff); + break; + } + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // - Compression (On,Off) + // + if (dwCaps & MDM_COMPRESSION) + { + lstrcpyA(pszCommand, szCompression); + lstrcatA(pszCommand, (dwOptions & MDM_COMPRESSION ? szOn : szOff)); + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // - FlowControl + // + if (dwCaps & (MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT)) + { + lstrcpyA(pszCommand, szFlowControl); + switch (dwOptions & (MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT)) + { + case MDM_FLOWCONTROL_HARD: + lstrcatA(pszCommand, szHard); + break; + case MDM_FLOWCONTROL_SOFT: + lstrcatA(pszCommand, szSoft); + break; + case MDM_FLOWCONTROL_HARD | MDM_FLOWCONTROL_SOFT: + if (dwCaps & MDM_FLOWCONTROL_HARD) + { + lstrcatA(pszCommand, szHard); + } + else + { + lstrcatA(pszCommand, szSoft); + } + break; + default: + lstrcatA(pszCommand, szOff); + } + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // - CCITT Override + // + if (dwCaps & MDM_CCITT_OVERRIDE) + { + lstrcpyA(pszCommand, szModulation); + if (dwOptions & MDM_CCITT_OVERRIDE) + { + // use szCCITT or V.23 + if (dwCaps & MDM_V23_OVERRIDE && dwOptions & MDM_V23_OVERRIDE) + { + lstrcatA(pszCommand, szCCITT_V23); + } + else + { + lstrcatA(pszCommand, szCCITT); + } + } + else + { + lstrcatA(pszCommand, szBell); + } + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // - SpeedAdjust + // + if (dwCaps & MDM_SPEED_ADJUST) + { + lstrcpyA(pszCommand, szSpeedNegotiation); + lstrcatA(pszCommand, (dwOptions & MDM_SPEED_ADJUST ? szOn : szOff)); + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0L, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // - Blind Dial + // + if (dwCaps & MDM_BLIND_DIAL) + { + lstrcpyA(pszCommand, (dwOptions & MDM_BLIND_DIAL ? szBlindOn : szBlindOff)); + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, pszCommand, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + } + + // finish the current command line by passing in a NULL command name + if (!CreateCommand(pModemInfo->mi_hKeyModem, hSettingsKey, hSettingsInitKey, NULL, 0, + pszPrefix, pszTerminator, &dwCounter, pszTemp)) + { + goto Failure; + } + + // Success + fRet = TRUE; + +Failure: + // close keys + RegCloseKey(hSettingsInitKey); + RegCloseKey(hSettingsKey); + LocalFree(pszTemp); + return fRet; +} + +//**************************************************************************** +// BOOL CreateCommand(HKEY hKeyModem, HKEY hSettings, HKEY hInit, +// LPSTR pszRegName, DWORD dwNumber, LPSTR pszPrefix, +// LPSTR pszTerminator, LPDWORD pdwCounter, +// LPSTR pszString) +// +// Function: Creates a command string +// +// Returns: TRUE on success, FALSE otherwise +// +// Note: if pszRegName is NULL then it is the last command +//**************************************************************************** + +BOOL CreateCommand(HKEY hKeyModem, + HKEY hSettings, + HKEY hInit, + LPSTR pszRegName, + DWORD dwNumber, + LPSTR pszPrefix, + LPSTR pszTerminator, + LPDWORD pdwCounter, + LPSTR pszString) +{ + CHAR pszCommand[HAYES_COMMAND_LENGTH + 1]; + CHAR pszCommandExpanded[HAYES_COMMAND_LENGTH + 1]; + CHAR pszNumber[MAXUINTSTRLENGTH]; + DWORD dwCommandLength; + DWORD dwSize; + DWORD dwType; + struct _ModemMacro ModemMacro; + static char szUserInit[] = "UserInit"; + static char szNumberMacro[] = "<#>"; + + // do we really have a command to add? + // + if (pszRegName) + { + // read in command text (ie. SpeakerMode_Off = "M0") + // + dwSize = HAYES_COMMAND_LENGTH; + if (RegQueryValueExA(hSettings, pszRegName, NULL, &dwType, (VOID *)pszCommand, &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s. Continuing...", pszRegName); +// LOGPRINTF((hLogFile,GET_MESSAGE_PTR(MsgWrnFailedToQueryValue), pszRegName)); + return TRUE; // we will not consider this fatal + } + if (dwType != REG_SZ) + { + DPRINTFA1("'%s' wasn't REG_SZ.", pszRegName); + return FALSE; + } + + // expand macros pszCommandExpanded <= pszCommand + // + lstrcpyA(ModemMacro.MacroName, szNumberMacro); + wsprintfA(pszNumber, "%d", dwNumber); + lstrcpyA(ModemMacro.MacroValue, pszNumber); + dwCommandLength = dwSize; + if (!ExpandMacros(pszCommand, pszCommandExpanded, &dwCommandLength, &ModemMacro, 1)) + { + DPRINTF("ExpandMacro Error. State <- Unknown"); + return FALSE; + } + + // check string + new command + terminator, flush if too big and start a new one. + // will new command fit on existing string? If not, flush it and start new one. + // + if (lstrlenA(pszString) + lstrlenA(pszCommandExpanded) + lstrlenA(pszTerminator) + > HAYES_COMMAND_LENGTH) + { + lstrcatA(pszString, pszTerminator); + wsprintfA(pszNumber, "%d", *pdwCounter); + *pdwCounter = *pdwCounter + 1; + if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszString, lstrlenA(pszString) + 1) + != ERROR_SUCCESS) + { + DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszString); + return FALSE; + } + lstrcpyA(pszString, pszPrefix); + } + + lstrcatA(pszString, pszCommandExpanded); + } + else + { + // finish off the current string + // + lstrcatA(pszString, pszTerminator); + wsprintfA(pszNumber, "%d", *pdwCounter); + *pdwCounter = *pdwCounter + 1; + if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszString, lstrlenA(pszString) + 1) + != ERROR_SUCCESS) + { + DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszString); + return FALSE; + } + + // now write the UserInit string, if there is one... + + // get the UserInit string length (including null), don't ExpandMacros on it + // + if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, NULL, &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s (this can be okay).", szUserInit); + return TRUE; // it is okay to not have a UserInit + } + else + { + LPSTR pszUserInit; + + if (dwType != REG_SZ) + { + DPRINTFA1("'%s' wasn't REG_SZ.", szUserInit); + return FALSE; // this is not okay + } + + // check for 0 length string + // BUGBUG this could be folded into the above if. CPC 12/14/94 + // + if (dwSize == 1) + { + DPRINTFA1("ignoring zero length %s entry.", szUserInit); + return TRUE; + } + + // we allow the size of this string to be larger than 40 chars, because the user + // should have enough knowledge about what the modem can do, if they are using this + // allocate enough for if we need to add a prefix and terminator + // + if (!(pszUserInit = (LPSTR)LocalAlloc(LPTR, + dwSize + + lstrlenA(pszPrefix) + + lstrlenA(pszTerminator) + + 1))) + { + DPRINTF("unable to allocate memory for building the UserInit string."); + return FALSE; + } + + if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, (VOID *)pszUserInit, &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s.", szUserInit); + LocalFree(pszUserInit); + return FALSE; // it is not okay at this point + } + + // check for prefix + // + if (strncmpi(pszUserInit, pszPrefix, lstrlenA(pszPrefix))) + { + // prepend a prefix string + lstrcpyA(pszUserInit, pszPrefix); + + // reload string; it's easier than shifting... + if (RegQueryValueExA(hKeyModem, szUserInit, NULL, &dwType, (VOID *)(pszUserInit+lstrlenA(pszPrefix)), &dwSize) + != ERROR_SUCCESS) + { + DPRINTFA1("RegQueryValueEx failed when opening %s.", szUserInit); + LocalFree(pszUserInit); + return FALSE; // it is not okay at this point + } + } + + // check for terminator + // + if (strncmpi(pszUserInit+lstrlenA(pszUserInit)-lstrlenA(pszTerminator), + pszTerminator, lstrlenA(pszTerminator))) + { + // append a terminator + // + lstrcatA(pszUserInit, pszTerminator); + } + + // we have one, so add it to the init strings + // + wsprintfA(pszNumber, "%d", *pdwCounter); + *pdwCounter = *pdwCounter + 1; + if (RegSetValueExA(hInit, pszNumber, 0, REG_SZ, (VOID *)pszUserInit, lstrlenA(pszUserInit) + 1) + != ERROR_SUCCESS) + { + DPRINTFA2("RegSetValueEx failed when writing '%s=%s'.", pszNumber, pszUserInit); + LocalFree(pszUserInit); + return FALSE; + } + + // free pszUserInit + // + LocalFree(pszUserInit); + } + } + + return TRUE; +} diff --git a/private/unimodem/tapisp/mcxioctl.h b/private/unimodem/tapisp/mcxioctl.h new file mode 100644 index 000000000..06e203d60 --- /dev/null +++ b/private/unimodem/tapisp/mcxioctl.h @@ -0,0 +1,107 @@ +//**************************************************************************** +// +// File: mcxioctl.h +// Content: This file contains the declaration for Unimodem +// DeviceIOControl. +// +// Copyright (c) 1992-1995, Microsoft Corporation, all rights reserved +// +//**************************************************************************** + +#ifndef _MCXIOCTL_H_ +#define _MCXIOCTL_H_ + +typedef struct tagMcxOut { + DWORD dwReqID; + DWORD dwResult; +} MCX_OUT, *PMCX_OUT; + +typedef struct tagMcxIn { + DWORD dwReqID; + PMCX_OUT pMcxOut; +} MCX_IN, *PMCX_IN; + +// Monitor modes for IOCTL_UMDM_START_MONITOR +// +#define MONITOR_NON_CONTINUOUS 0 +#define MONITOR_CONTINUOUS 1 + +// Passthrough modes for IOCTL_UMDM_PASSTHROUGH +// +#define PASSTHROUGH_ON 1 +#define PASSTHROUGH_OFF 2 +#define PASSTHROUGH_OFF_BUT_CONNECTED 3 + +// DeviceIOControl operation result +// +#define MDM_SUCCESS 0 +#define MDM_PENDING 1 +#define MDM_FAILURE 2 +#define MDM_HANGUP 3 +#define MDM_BUSY 4 +#define MDM_NOANSWER 5 +#define MDM_NOCARRIER 6 +#define MDM_NODIALTONE 7 + +// Invalid Pending operation ID +// +#define MDM_ID_NULL 0xFFFFFFFF + +// MCX interface prototypes +// +LONG MCXOpen (LPTSTR szModemName, + HANDLE hDevice, + LPTSTR szKey, + LPHANDLE lph, + DWORD dwID, + DWORD dwCompletionKey); + +LONG +MCXDial( + HANDLE hModem, + LPSTR szData, + MCX_IN *pmcxi, + DWORD DialOptions + ); + + +LONG +MCXClose( + HANDLE hModem, + HANDLE hComm, + BOOL LineClosed + ); + + +LONG MCXInit(HANDLE hModem, MCX_IN *pmcxi); +LONG MCXMonitor(HANDLE hModem, DWORD dwType, MCX_IN *pmcxi); +LONG MCXAnswer(HANDLE hModem, MCX_IN *pmcxi); +LONG MCXHangup(HANDLE hModem, MCX_IN *pmcxi); +LONG MCXGetCommConfig (HANDLE hModem, LPCOMMCONFIG lpCommConfig, LPDWORD lpcb); +LONG MCXSetCommConfig (HANDLE hModem, LPCOMMCONFIG lpCommConfig, DWORD cb); +LONG MCXSetPassthrough(HANDLE hModem, DWORD dwType); +LONG MCXGetNegotiatedRate(HANDLE hModem, LPDWORD lpdwRate); +LONG MCXMonitorRemoteHangup(HANDLE hModem, MCX_IN *pmcxi); +void MCXAsyncComplete (HANDLE hModem, LPOVERLAPPED lpOverlapped); + +typedef VOID WINAPI +DISCONNECT_HANDLER( + HANDLE pLineDev + ); + + +LONG WINAPI +McxRegisterDisconectHandler( + HANDLE hModem, + DISCONNECT_HANDLER Handler, + HANDLE Context + ); + +LONG WINAPI +McxDeregisterDisconnectHandler( + HANDLE hModem + ); + + + +#endif // _MCXIOCTL_H_ diff --git a/private/unimodem/tapisp/mcxp.h b/private/unimodem/tapisp/mcxp.h new file mode 100644 index 000000000..a85e00044 --- /dev/null +++ b/private/unimodem/tapisp/mcxp.h @@ -0,0 +1,530 @@ +#include "logids.h" +//#define VOICEVIEW 1 // turn on VoiceView stuff + + +// +// compatibility flags +// +#define COMPAT_FLAG_LOWER_DTR (0x00000001) // lower DTR and sleep before closeing com port + + +#define MDM_V23_OVERRIDE 0x00000400 + +// device types (from rover\rna\inc\modem.h) +#define DT_NULL_MODEM 0 +#define DT_EXTERNAL_MODEM 1 +#define DT_INTERNAL_MODEM 2 +#define DT_PCMCIA_MODEM 3 +#define DT_PARALLEL_PORT 4 +#define DT_PARALLEL_MODEM 5 + +#define MAXSTRINGLENGTH 256 +#define MAXUINTSTRLENGTH 11 // Max UINT in ascii + terminator +#define MAX_REG_KEY_LEN 256 + +#define REG_NULL 0xFFFFFFFF // indicates an invalid registry handle + +#define FLUSH_WRITE_QUEUE 1 +#define START_READ 2 +#define RESTART_READ 3 +#define TRY_READ 4 +#define SET_READ_CALLBACK 5 +#define POST_READ_CALLBACK 6 +#define CHECK_RESPONSE 7 +#define BAD_RESPONSE_CLEANUP_END 8 +#define BAIL_O_RAMA_MORE_DATA 9 // bad response, but finish reading in the bad response +#define BAIL_O_RAMA_NO_MORE_DATA 10 +#define USE_WHOLE_RESPONSE 11 +#define USE_POSSIBLE_RESPONSE 12 +#define GOOD_RESPONSE 13 +#define END_READ 14 +#define SET_TIMEOUT 15 +#define POST_TIMEOUT 16 + +#define MODEM_NO_UNCONDITIONAL (DWORD)-1 // for mi_dwUnconditionalReturnValue. Indicates not to use it. + +#define MODEM_SUCCESS MDM_SUCCESS +#define MODEM_PENDING MDM_PENDING +#define MODEM_FAILURE MDM_FAILURE +#define MODEM_HANGUP MDM_HANGUP +#define MODEM_BUSY MDM_BUSY +#define MODEM_NOANSWER MDM_NOANSWER +#define MODEM_NOCARRIER MDM_NOCARRIER +#define MODEM_NODIALTONE MDM_NODIALTONE + +#define SUCCESS 0 +#define ECHO 1 +#define PARTIAL_RESPONSE 2 +#define UNRECOGNIZED_RESPONSE 3 +#define POSSIBLE_RESPONSE 4 + +// time in miliseconds +#define MILISECONDS_PER_SECOND 1000 +#define TO_FLUSH 2000 // 40 chars / 30 chars/sec (at 300bps) + safety = 2000 ms +#define TO_INFINITE 0 +#define TO_FIRST_CHAR_AFTER_INIT_CMD 2000 // 2 seconds (9/21/94 - CPC - consider bumping up, now that we have TO_FLUSH) +#define TO_ADDITIONAL_TO_CALL_SETUP_FAIL_TIMER 10000 // 10 seconds +#define TO_FIRST_CHAR_AFTER_CONNECTION_CMD 60000 // 1 minute (used if we don't have CallSetupFailTimer support) + // BUGBUG we might want to make this match + // the cpl, even when the feature isn't supported. +#define TO_FIRST_CHAR_AFTER_CONNECTION_CMD_NON_MODEM 2000 // 2 seconds, null-modems connect faster +#define TO_NEXT_CHAR_RCV_INTERVAL 1000 // 1 second +#define TO_DTR_DROP 1200 // 1200 ms (for STATE_HANGING_UP_DTR) + +#define CMD_INDEX_START 1 // "1", "2", "3", "4", ... + +#define HAYES_COMMAND_LENGTH 40 + +typedef struct _ModemMacro { + CHAR MacroName[MAXSTRINGLENGTH]; + CHAR MacroValue[MAXSTRINGLENGTH]; +} MODEMMACRO; + +#define LMSCH '<' +#define RMSCH '>' + +#define CR_MACRO "" +#define CR_MACRO_LENGTH 4 +#define LF_MACRO "" +#define LF_MACRO_LENGTH 4 + +#define CR '\r' // 0x0D +#define LF '\n' // 0x0A + +#define PARTIAL_MATCH 0x01 +#define FULL_MATCH 0x02 + +// must start at 1 +#define STATE_UNKNOWN 1 +#define STATE_INITIALIZING 2 +#define STATE_DISCONNECTED 3 +#define STATE_MONITORING 4 +#define STATE_DIALING 5 +#define STATE_ANSWERING 6 +#define STATE_CONNECTED 7 +#define STATE_DIALED 8 +#define STATE_ORIGINATING 9 +#define STATE_HANGING_UP_REMOTE 10 // This is when the remote side hangs up. + // modem: Wait for response and then: + // - send MODEM_HANGUP + // - set state to STATE_DISCONNECTED + + + +#define STATE_HANGING_UP_DTR 11 // After dropping DTR and waiting for 1200ms, check RLSD: + // If RLSD is low, raise DTR and set state to + // modem: STATE_HANGING_UP_NON_CMD + // null-modem: STATE_DISCONNECTED + // Else set state to: + // modem: STATE_HANGING_UP_NON_COMMAND and send "+++" + // null-modem: same, wait another 200ms (keeping count, stop at 3 or so) +#define STATE_HANGING_UP_NON_CMD 12 // After sending a \r to hangup or sending +++ or getting RLSD low: + // Wait for any response or timeout and then: + // - send ATH + // - set state to STATE_HANGING_UP_CMD +#define STATE_HANGING_UP_CMD 13 // Wait for a response to ATH + // If you get one, you are hung up, raise DTR, set state to + // STATE_DISCONNECTED and return MODEM_SUCCESS. + // Else if you don't get one, consider dropping DTR, waiting 200ms more + // and setting state to STATE_HANGING_UP_DTR. (keep track of + // how many times you do this, max out at 3 or so.) + +#define STATE_REMOTE_DROPPED 14 // The remote disconnected, wait here for Hangup and goto + // STATE_HANGING_UP_REMOTE + +#define STATE_WAIT_FOR_RLSD 15 // if we got the connect message, but rlsd was not high + + +#define MAX_COMMAND_TRIES 5 // # of times to try a command before giving up. +#define MAX_HANGUP_TRIES 3 // # of times to try hanging up before giving up. +#define MODEM_ESCAPE_SEQUENCE "+++" +#define MODEM_ESCAPE_SEQUENCE_LEN 3 + + + +/* Modem State Structure */ +#pragma pack(1) +typedef struct _MSS { + BYTE bResponseState; // See below + BYTE bNegotiatedOptions; // bitmap, 0 = no info, matches MDM_ options for now, since what we are + // interested in fits in 8 bits (error-correction (ec and cell) and compression) + DWORD dwNegotiatedDCERate; // 0 = no info + DWORD dwNegotiatedDTERate; // 0 = no info and if dwNegotiatedDCERate is 0 on connect, then + // the dte baudrate is actually changed. +} MSS; +#pragma pack() + +/* Structure for linked-list of response nodes */ +#pragma pack(1) +typedef struct _RESPONSE_NODE { + struct _RESPONSE_NODE *pNext; // Pointer to next RESPONSE_NODE + MSS Mss; // Modem State Structure for this response + BYTE bLen; // Offset from 1, ie. 0=1, 1=2,... ,255=256 + char szResponse[1]; // The actual response (not null terminated) +} RESPONSE_NODE, *PRESPONSE_NODE, *LPRESPONSE_NODE; +#pragma pack() + +/* DWORD dwResponseState */ +#define RESPONSE_OK 0x0 +#define RESPONSE_LOOP 0x1 +#define RESPONSE_CONNECT 0x2 +#define RESPONSE_ERROR 0x3 +#define RESPONSE_NOCARRIER 0x4 +#define RESPONSE_NODIALTONE 0x5 +#define RESPONSE_BUSY 0x6 +#define RESPONSE_NOANSWER 0x7 +#define RESPONSE_RING 0x8 + +#define RESPONSE_START RESPONSE_OK +#ifdef VOICEVIEW +#define RESPONSE_VV_SSV 0x09 // VoiceView Data Mode Start Sequence Event +#define RESPONSE_VV_SMD 0x0A // Modem Data Mode Start Sequence Event +#define RESPONSE_VV_SFA 0x0B // Facisimile Data Mode Start Sequence Event +#define RESPONSE_VV_SRA 0x0C // Receive ADSI Response Event +#define RESPONSE_VV_SRQ 0x0D // Receive Capabilities Query Event +#define RESPONSE_VV_SRC 0x0E // Receive Capabilities Information Event +#define RESPONSE_VV_STO 0x0F // Talk-off Event (VoiceView start tone w/o a valid mode indicator) +#define RESPONSE_VV_SVM 0x10 // VoiceView Message Available +#define RESPONSE_VV_BASE (RESPONSE_VV_SSV - 1) // used to set proper call back values +#define RESPONSE_END RESPONSE_VV_SVM +#else +#define RESPONSE_END RESPONSE_RING +#endif // VOICEVIEW + +typedef struct _MODEM_REG_PROP { + DWORD dwDialOptions; // bitmap of supported options + DWORD dwCallSetupFailTimer; // Maximum value in seconds + DWORD dwInactivityTimeout; // Maximum value in units specific by InactivityScale + DWORD dwSpeakerVolume; // bitmap of supported values + DWORD dwSpeakerMode; // bitmap of supported values + DWORD dwModemOptions; // bitmap of supported values + DWORD dwMaxDTERate; // Maximum value in bit/s + DWORD dwMaxDCERate; // Maximum value in bit/s +} MODEM_REG_PROP; + +typedef struct _MODEM_REG_DEFAULT { + DWORD dwCallSetupFailTimer; // seconds + DWORD dwInactivityTimeout; // units specific by InactivityScale + DWORD dwSpeakerVolume; // level + DWORD dwSpeakerMode; // mode + DWORD dwPreferredModemOptions; // bitmap +} MODEM_REG_DEFAULT; + +#define COMMCONFIG_VERSION_1 1 + +#define MODEMSETTINGS_FILLER 0 // # of bytes to make ring 0 modemsettings = ring 3 modemsettings + +#ifdef VOICEVIEW +// Voice View information and states - on a per port bases +typedef struct _VVINFO { + WORD wState; // state of monitoring see VVSTATE_x + WORD wClass; // what class the modem better be in + DWORD dwCallBackRef; // data to be passed back in the call back + int (*fpNotifyProc)(); // voice view call back function + DWORD fContinuousMonitoring; // old monitoring state + DWORD hSemaphore; // wait to switch fclasses + HTIMEOUT hTimer; // wait to switch fclasses +} VVINFO, *PVVINFO, *LPVVINFO; + +// VoiceView states +#define VVSTATE_NONE 0x00 // nothing going on +#define VVSTATE_INIT 0x01 // want to look for VV stuff +#define VVSTATE_MONITOR 0x02 // want to look for VV stuff + +// VoiceView current monitering states +#define VVCLASS_0 0x00 // should be in fclass 0 +#define VVCLASS_80 0x80 // should be in fclass 80 +#endif // VOICEVIEW + +// Pending operation +#define PO_NONE 0 +#define PO_WRITE 1 +#define PO_READ 2 +#define PO_EVENT 3 + +// PrintString Options +#define PS_SEND 0 +#define PS_SEND_SECURE 1 +#define PS_RECV 2 + +// Overrides to hard-coded defaults. +typedef struct +{ + DWORD dwFlags; // one of the fMDMDEF_* flags below + DWORD dwPortLatency; // Port latency in milliseconds. +} MODEMDEFAULTS; + +// fMDMDEF flags: +// Add a 100ms delay before sending a command. + #define fMDMDEF_UseInterCommandDelay (0x1<<0) + +#define GET_PORT_LATENCY(_pmi)\ + (\ + ((_pmi)->mi_pNonStandardDefaults)\ + ? (_pmi)->mi_pNonStandardDefaults->dwPortLatency\ + : 0\ + ) + +#define GET_INTERCOMMAND_DELAY(_pmi)\ + (\ + ((_pmi)->mi_pNonStandardDefaults\ + && ((_pmi)->mi_pNonStandardDefaults->dwFlags & fMDMDEF_UseInterCommandDelay))\ + ? 100\ + : 0\ + ) + +// BUGBUG, flags should be consolidated to save a few DWORDs of memory +typedef struct _ModemInformation { + HANDLE mi_PortHandle; // Handle of the com. port that the modem is attached to. + DWORD mi_ReqID; // async request ID + PMCX_OUT mi_pmcxo; // async output info + + DWORD mi_dwRWIOExpected; // Token used to indicate what I/O operation we are currently expecting to finish + DWORD mi_dwEventIOExpected; // Token used to indicate what I/O operation we are currently expecting to finish + DWORD mi_dwDeferedExpected; // Token used to indicate what I/O operation we are currently expecting to finish + + DWORD mi_dwCompletionKey; // CompletionKey to be passed to PostQueuedCompletionStatus. + + DWORD mi_ModemState; + HKEY mi_hKeyModem; // state machine - reg key for drv + char mi_szCmd[MAXSTRINGLENGTH]; // state machine - current command value + DWORD mi_cbCmd; // state machine - length of current command value + char mi_szResponse[MAXSTRINGLENGTH]; // state machine - response string from modem + DWORD mi_RcvState; // state machine - receive state + DWORD mi_cbTotalResponse; // state machine - total length of modem responses + char * mi_pszStartReadSpoof; + char * mi_pszEndReadSpoof; + DWORD mi_dwInactivityScale; // Indicates how many seconds per unit for inactivity timeout + DWORD mi_fContinuousMonitoring; // TRUE = continuous, TRUE = one shot + DWORD mi_fSettingsInitStringsBuilt; // TRUE = SettingsInit built, FALSE = needs to be built + + DWORD mi_dwNegotiatedDTERate; + DWORD mi_dwNegotiatedDCERate; + DWORD mi_dwNegotiatedModemOptions; + + DWORD mi_dwModemOptionsCap; + DWORD mi_dwCallSetupFailTimerCap; + DWORD mi_dwInactivityTimeoutCap; + DWORD mi_dwSpeakerVolumeCap; + DWORD mi_dwSpeakerModeCap; + + DWORD mi_dwPreferredModemOptions; + DWORD mi_dwCallSetupFailTimerSetting; + DWORD mi_dwInactivityTimeoutSetting; + DWORD mi_dwSpeakerVolumeSetting; + DWORD mi_dwSpeakerModeSetting; + + DWORD mi_dwCommandTryCount; // count of the number of command attempts + DWORD mi_dwHangupTryCount; // count of the number of hangup attempts + DWORD mi_dwPostHangupModemState; // if non-0 then we want to do a command after hangup, and set this state + char * mi_pszzPostHangupCmds; // non-NULL if there are cmds to be done after hangup + char * mi_pszzHangupCmds; // in memory modem commands for hangup, freed when modem closed + char * mi_pszzCmds; // in memory modem commands, free mem after use except if == to mi_pszzHangupCmds + char * mi_pszCurCmd; // current command in mi_pszzCmds + char * mi_pszPrevCmd; // previous command in mi_pszzCmds + char * mi_pszReset; // reset command to be slammed to the modem just before closing + DWORD mi_dwResetLen; // length of the reset string + RESPONSE_NODE * mi_prnResponseHead; // Pointer to the head of the linked-list of responses. + struct _MSS mi_mssPossible; // MSS of a POSSIBLE_RESPONSE + DWORD mi_dwPossibleResponseLen; // 0 if there isn't a current POSSIBLE_RESPONSE. + // >0 indicates the length of the POSSIBLE_RESPONSE + BOOL mi_fBadResponseCleanupMode; // TRUE if we are in the midst of a bad response cleanup + BOOL mi_fModem; // TRUE if the port is an modem and not a null-modem + DWORD mi_dwUnconditionalReturnValue; // MODEM_NO_UNCONDITIONAL means don't use. Otherwise, use. + + LPOVERNODE mi_lpOverlappedRW; // ptr to the current overlapped struct + LPOVERNODE mi_lpOverlappedEvent; // ptr to the current overlapped struct + + DWORD mi_waitEvent; // wait event + DWORD mi_timeout; // wait event timeout + + DWORD mi_dwCommError; // Current comm error (0 = no error) + + HANDLE mi_SyncReadEvent; // event to be used for sync reads + + HANDLE mi_hLogFile; + + DWORD mi_dwID; // debug display number + + HANDLE mi_hCommon; + + DWORD mi_dwWaitForCDTime; + + DISCONNECT_HANDLER *mi_DisconnectHandler; + HANDLE mi_DisconnectContext; + + DWORD mi_CompatibilityFlags; + + MODEMDEFAULTS *mi_pNonStandardDefaults; // Overrides to hard-coded defaults;. + +#ifdef VOICEVIEW + VVINFO VVInfo; // all the VoiceView info for this port +#endif // VOICEVIEW +} MODEMINFORMATION, *PMODEMINFORMATION; + +#define DWORDFROMFOURCHAR( ch0, ch1, ch2, ch3 ) \ + ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \ + ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) ) + +#define SMTF DWORDFROMFOURCHAR('S', 'M', 'T', 'F') + +// dwEventMaskLoc == NULL means no change from previous setting +// +#define SETCOMMEVENTMASK(hPort, dwClientEventMask, dwMyEventMask, dwEventMaskLoc) \ + VCOMM_SetCommEventMask((HPORT)(hPort)->mi_PortHandle, \ + (dwClientEventMask) | ((hPort)->mi_dwMyEventMask = (dwMyEventMask)), \ + (dwEventMaskLoc)) + +/* NOINC */ +MODEMINFORMATION * AllocateModem(LPTSTR szKey, + LPTSTR szModemName, + HANDLE hDevice); +void FreeModem(MODEMINFORMATION * pModemInfo, HANDLE hComm); +BOOL BuildResponsesLinkedList(MODEMINFORMATION * pModemInfo); + +BOOL CreateSettingsInitEntry(HANDLE hPort); +BOOL CreateCommand(HKEY hKeyModem, + HKEY hSettings, + HKEY hInit, + LPSTR pszRegName, + DWORD dwNumber, + LPSTR pszPrefix, + LPSTR pszTerminator, + LPDWORD pdwCounter, + LPSTR pszString); + +DWORD ModemCommand(MODEMINFORMATION * pModemInfo, + DWORD dwReqID, + MCX_OUT *pmcxo, + LPSTR pszzCmdInMem); +DWORD ModemWriteCommand(MODEMINFORMATION * pModemInfo); +DWORD ReadComm(MODEMINFORMATION *pModemInfo, LPBYTE lpBuf, DWORD dwToRead, + LPDWORD pdwRead, DWORD dwTimeout); +DWORD CheckResponse(MODEMINFORMATION * hPort, MSS * pMss); +DWORD MatchResponse(MODEMINFORMATION * hPort, MSS * pMss); +void ReadNotifyClient(MODEMINFORMATION * hPort, DWORD Param); +DWORD HandleCommErrors(MODEMINFORMATION * hPort, ULONG ulError); + +void ModemCallClient(MODEMINFORMATION * hPort, DWORD wParam); +BOOL ExpandMacros(LPSTR pszRegResponse, + LPSTR pszExpanded, + LPDWORD pdwValLen, + MODEMMACRO * pMdmMacro, + DWORD cbMacros); +VOID ReadCompletionRoutine2(MODEMINFORMATION * hPort); +LPSTR LoadRegCommands(MODEMINFORMATION *hPort, + LPSTR szRegCommand, + LPSTR pszzAppend); +int strncmpi(char *dst, char *src, long count); +int Mystrncmp(char *dst, char *src, long count); + +DWORD ModemWrite (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, + DWORD cbWrite, LPDWORD lpcbWritten, DWORD dwTimeout); +DWORD ModemRead (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, + DWORD cbRead, LPDWORD lpcbRead, DWORD dwTimeout); +DWORD ModemRWAsyncComplete (MODEMINFORMATION * pModemInfo, LPDWORD lpcb); +DWORD ModemWaitEvent (MODEMINFORMATION * pModemInfo, DWORD dwEvent, DWORD dwTimeOut); + +DWORD WINAPI +ModemWaitEventComplete( + MODEMINFORMATION * pModemInfo, + LPOVERNODE pNode + ); + + +BOOL WINAPI +CurrentlyWaitingForCommEvent( + MODEMINFORMATION * pModemInfo + ); + + +BOOL WINAPI +CreateDeferedWorkItem( + MODEMINFORMATION * pModemInfo + ); + + +VOID ModemSetPassthrough (MODEMINFORMATION * pModemInfo, DWORD dwMode); + + +HANDLE WINAPI +ModemOpenLog( + LPSTR pszName + ); + +VOID WINAPIV +LogPrintf( + HANDLE FileHandle, + DWORD dwID, + LPSTR FormatString, + ... + ); + +VOID WINAPI +ModemCloseLog( + HANDLE FileHandle + ); + +VOID WINAPI +FlushLog( + HANDLE FileHandle + ); + +void WINAPI +PrintString( + HANDLE hLogFile, + DWORD dwID, + char *pchStr, + DWORD dwLength, + DWORD dwOption + ); + +void WINAPI +PrintCommSettings( + HANDLE hLogFile, + DWORD dwID, + DCB * pDcb + ); + +VOID WINAPI +LogString( + HANDLE FileHandle, + DWORD dwID, + DWORD StringID, + ... + ); + +void WINAPI +PrintGoodResponse( + HANDLE hLogFile, + DWORD dwID, + DWORD ResponseState + ); + +LPSTR WINAPI +NewLoadRegCommands( + HKEY hKey, + LPSTR szRegCommand, + LPSTR pszzAppend + ); + +PRESPONSE_NODE WINAPI +NewBuildResponsesLinkedList( + HKEY hKey + ); + + + +#define toupper(ch) (((ch >= 'a') && (ch <= 'z')) ? ch-'a'+'A':ch) +#define ctox(ch) (((ch >='0') && (ch <= '9')) ? ch-'0': toupper(ch)-'A'+10) + +extern char szSettingsInit[]; +extern char szSettings[]; +extern char szPrefix[]; +extern char szTerminator[]; +extern char szBlindOn[]; +extern char szBlindOff[]; + +#define MAXADDRESSLEN 80 // From tapi.h - TAPIMAXDESTADDRESSSIZE + +/* INC */ diff --git a/private/unimodem/tapisp/mcxrw.c b/private/unimodem/tapisp/mcxrw.c new file mode 100644 index 000000000..ec2829317 --- /dev/null +++ b/private/unimodem/tapisp/mcxrw.c @@ -0,0 +1,649 @@ +/****************************************************************************** + +(C) Copyright MICROSOFT Corp., 1987-1993 + +Rob Williams, June 93 w/ State machine and parser plagarized from RAS + +******************************************************************************/ + +#include "unimdm.h" +#include "mcxp.h" + +#include +#include + + +BOOL WINAPI +CreateDeferedWorkItem( + MODEMINFORMATION * pModemInfo + ) + +{ + LPOVERNODE pNode; + BOOL bResult; + + pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwDeferedExpected, 1); + + if (pNode == NULL) { + + return FALSE; + } + + + pNode->Type=OVERNODE_TYPE_WORKITEM; + + bResult=PostQueuedCompletionStatus( + ghCompletionPort, + 0, + pModemInfo->mi_dwCompletionKey, + &pNode->overlapped + ); + + + if (!bResult) { + + OverPoolFree((LPOVERLAPPED)pNode); + } + + return bResult; + +} + + + +//**************************************************************************** +//DWORD ModemWrite (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, +// DWORD cbWrite, LPDWORD lpcbWritten, DWORD dwTimeout) +// +// Function: Write a string to the modem. Always perform asynchronously, +// even if WriteFile finishes synchronously. +// +// Returns: MODEM_PENDING if pending +// MODEM_FAILURE if fails +// (Never returns MODEM_SUCCESS) +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD ModemWrite (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, + DWORD cbWrite, LPDWORD lpcbWritten, DWORD dwTimeout) +{ + COMMTIMEOUTS commtimeout; + DWORD dwResult; + LPOVERNODE pNode; + +// MCXPRINTF("ModemWrite"); + + ASSERT(pModemInfo->mi_lpOverlappedRW == NULL); + + // Set timeout + // + commtimeout.ReadIntervalTimeout = 0; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = 0; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = dwTimeout; + SetCommTimeouts(pModemInfo->mi_PortHandle, &commtimeout); + + pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwRWIOExpected, 1); + + if (pNode == NULL) { + + dwResult = MODEM_FAILURE; + } + else + { + SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_READWRITE); + + // Make the asynchronous write call + // + if (WriteFile(pModemInfo->mi_PortHandle, lpBuf, cbWrite, lpcbWritten, + &pNode->overlapped)) + { + dwResult = MODEM_PENDING; // I/O will show up on the completion port + } + else + { + // Determine the result + // + dwResult = GetLastError(); + + if (dwResult == ERROR_IO_PENDING) + { + dwResult = MODEM_PENDING; + } + else + { + OverPoolFree((LPOVERLAPPED)pNode); + pNode=NULL; + dwResult = MODEM_FAILURE; + }; + }; + } + + pModemInfo->mi_lpOverlappedRW=pNode; + return dwResult; +} + +//**************************************************************************** +//DWORD ModemRead (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, +// DWORD cbRead, LPDWORD lpcbRead, DWORD dwTimeout) +// +// Function: Read a string from the modem Always perform asynchronously, +// even if ReadFile finishes synchronously. +// +// Returns: MODEM_PENDING if pending +// MODEM_FAILURE if fails +// (Never returns MODEM_SUCCESS) +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD ModemRead (MODEMINFORMATION * pModemInfo, LPBYTE lpBuf, + DWORD cbRead, LPDWORD lpcbRead, DWORD dwTimeout) +{ + COMMTIMEOUTS commtimeout; + DWORD dwResult; + LPOVERNODE pNode; + +// MCXPRINTF("ModemRead"); + + ASSERT(pModemInfo->mi_lpOverlappedRW == NULL); + + // Set timeout + // + commtimeout.ReadIntervalTimeout = 0; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = dwTimeout; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(pModemInfo->mi_PortHandle, &commtimeout); + + pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwRWIOExpected, 1); + + if (pNode == NULL) { + + dwResult = MODEM_FAILURE; + } + else + { + SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_READWRITE); + + // Make the asynchronous write call + // + if (ReadFile(pModemInfo->mi_PortHandle, lpBuf, cbRead, lpcbRead, + &pNode->overlapped)) + { + dwResult = MODEM_PENDING; // I/O will show up on the completion port + } + else + { + // Determine the result + // + dwResult = GetLastError(); + + if (dwResult == ERROR_IO_PENDING) + { + dwResult = MODEM_PENDING; + } + else + { + OverPoolFree((LPOVERLAPPED)pNode); + pNode=NULL; + dwResult = MODEM_FAILURE; + }; + }; + } + + pModemInfo->mi_lpOverlappedRW=pNode; + return dwResult; +} + +//**************************************************************************** +// DWORD ModemRWAsyncComplete (MODEMINFORMATION * pModemInfo, LPDWORD lpcb) +// +// Function: Complete the asynchronous read/write operation +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD ModemRWAsyncComplete (MODEMINFORMATION * pModemInfo, LPDWORD lpcb) +{ + DWORD dwRet; + + if (pModemInfo->mi_lpOverlappedRW == NULL) { + + *lpcb = 0; + return MODEM_FAILURE; + } + + // Has all of the write buffer been emptied? + if (GetOverlappedResult(pModemInfo->mi_PortHandle, + &pModemInfo->mi_lpOverlappedRW->overlapped, + lpcb, + FALSE)) + { + // Very Funny!! sometimes GetOverlappedResult returns success but nothing + // was written nor read. In this case it should mean timeout. + // + if (*lpcb) + { + dwRet = MODEM_SUCCESS; + } + else + { + dwRet = MODEM_PENDING; + }; + } + else + { + if (GetLastError() == ERROR_IO_INCOMPLETE) + { + dwRet = MODEM_PENDING; + } + else + { + dwRet = MODEM_FAILURE; + }; + }; + + pModemInfo->mi_lpOverlappedRW=NULL; + + return dwRet; +} + +//**************************************************************************** +//DWORD ModemWaitEvent (MODEMINFORMATION * pModemInfo, DWORD dwEvent, +// DWORD dwTimeout) +// +// Function: Monitor the modem's control signal +// +// Returns: MODEM_SUCCESS if the control is signalled +// MODEM_PENDING if the control line is being monitored +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD ModemWaitEvent (MODEMINFORMATION * pModemInfo, DWORD dwEvent, + DWORD dwTimeOut) +{ + DWORD dwWaitEvent; + DWORD dwResult; + LPOVERNODE pNode; + + + MCXPRINTF("ModemWaitEvent"); + ASSERT(dwTimeOutmi_lpOverlappedEvent == NULL); + + // Make the asynchronous wait call + // + SetCommMask(pModemInfo->mi_PortHandle, dwEvent); + + pModemInfo->mi_waitEvent = dwEvent; + + pNode=(LPOVERNODE)OverPoolAlloc(++pModemInfo->mi_dwEventIOExpected, + dwTimeOut ? 2 : 1); + + if (pNode == NULL) { + + dwResult = MODEM_FAILURE; + } + else + { + + SET_OVERNODE_TYPE(pNode,OVERNODE_TYPE_COMMEVENT); + + pNode->CommEvent=0; + + if (WaitCommEvent(pModemInfo->mi_PortHandle, &pNode->CommEvent, + &pNode->overlapped)) + { + MCXPRINTF1("WaitCommEvent returned TRUE! Returning PENDING anyways.%08lx",pNode->overlapped.Internal); + + dwResult = MODEM_PENDING; // The event will be signaled. + } + else + { + // Determine the result + // + dwResult = GetLastError(); + + if (dwResult == ERROR_IO_PENDING) + { + if (dwTimeOut) + { + + // Mark the timeout + // + GTC_AequalsBplusC(pModemInfo->mi_timeout, GETTICKCOUNT(),dwTimeOut); + + if (SetMdmTimer(pModemInfo->mi_dwCompletionKey, + &pNode->overlapped, + dwTimeOut) == ERROR_SUCCESS) + { + MCXPRINTF2("SET_TIMEOUT (%d ms dtr droppage) @%d", + dwTimeOut, GETTICKCOUNT()); + } + else + { + MCXPRINTF("SetMdmTimer did not return ERROR_SUCCESS"); + + pModemInfo->mi_timeout=GETTICKCOUNT(); + + SetCommMask(pModemInfo->mi_PortHandle, 0); + + PostQueuedCompletionStatus(ghCompletionPort, + 0, + pModemInfo->mi_dwCompletionKey, + &pNode->overlapped); + + + }; + + }; + + dwResult = MODEM_PENDING; + } + else + { + OverPoolFree((LPOVERLAPPED)pNode); + + + if (dwTimeOut) { + + // Free it twice because the reference count was 2. + // + OverPoolFree((LPOVERLAPPED)pNode); + } + + pNode=NULL; + + MCXPRINTF1("GetLastError() in ModemWaitEvent returned %ld", dwResult); + dwResult = MODEM_FAILURE; + }; + }; + } + + MCXPRINTF3("ModemWaitEvent returned %ld, id=%d, %08lx", dwResult,pNode ? pNode->dwToken : (DWORD)-1 , pNode); + + pModemInfo->mi_lpOverlappedEvent=pNode; + + return dwResult; +} + +//**************************************************************************** +// DWORD ModemWaitEventComplete (MODEMINFORMATION * pModemInfo) +// +// Function: Complete the asynchronous wait-event operation +// +// Returns: MODEM_SUCCESS if success +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD WINAPI +ModemWaitEventComplete( + MODEMINFORMATION * pModemInfo, + LPOVERNODE pNode + ) +{ + + + + // If we are not waiting for an event, return failure + // + if (pModemInfo->mi_lpOverlappedEvent != pNode) { + + MCXPRINTF("ModemWaitEventComplete returning failure 1."); + return MODEM_FAILURE; + } + + pModemInfo->mi_lpOverlappedEvent=NULL; + + if ((pNode->CommEvent & pModemInfo->mi_waitEvent) || (pModemInfo->mi_waitEvent == 0)) + + { + // Disable HW detection + // + SetCommMask(pModemInfo->mi_PortHandle, 0L); + + // If we have a timer pending, clear timer + // + if (pModemInfo->mi_timeout) + { + pModemInfo->mi_timeout = 0; + if (KillMdmTimer(pModemInfo->mi_dwCompletionKey, + (LPOVERLAPPED)pNode) == TRUE) + { + OverPoolFree((LPOVERLAPPED)pNode); + } + }; + return MODEM_SUCCESS; + } + else + { + // We may have a timeout + // + if (pModemInfo->mi_timeout) + { + DWORD tcNow = GETTICKCOUNT(); + if (GTC_AleB(pModemInfo->mi_timeout, tcNow)) + { + // Timeout expired + pModemInfo->mi_timeout = 0; + MCXPRINTF1("HW timeout expired @%d.", GetTickCount()); + + // Disable HW detection + // + SetCommMask(pModemInfo->mi_PortHandle, 0L); + return MODEM_PENDING; + } + else + { + // We got an event that we did not want, We will just return success, + // to keep things from hanging, and hope for the best. This should no happen. + // + // Kill the timer too + // +#ifdef DEBUG + { + DWORD RealMask; + + GetCommMask( + pModemInfo->mi_PortHandle, + &RealMask + ); + + MCXPRINTF2("ModemWaitEventComplete: got unexpected event (signalEvent = %d, mask=%d).", + pNode->CommEvent,RealMask); + +// LogPrintf(pModemInfo->mi_hLogFile, pModemInfo->mi_dwID, +// "ModemWaitEventComplete: got unexpected event (signalEvent = %d, mask=%d).\n", +// pNode->CommEvent,RealMask); +// ASSERT(0); + } +#endif + + SetCommMask(pModemInfo->mi_PortHandle, 0L); + + // If we have a timer pending, clear timer + // + pModemInfo->mi_timeout = 0; + if (KillMdmTimer(pModemInfo->mi_dwCompletionKey, + (LPOVERLAPPED)pNode) == TRUE) + { + OverPoolFree((LPOVERLAPPED)pNode); + } + + return MODEM_PENDING; + + }; + } + else + { + // We should not be here at all. + // Disable HW detection so we do not get a spurious event and + // get stuck in a infinite loop + // + SetCommMask(pModemInfo->mi_PortHandle, 0L); + MCXPRINTF("ModemWaitEventComplete returning failure 3."); + return MODEM_FAILURE; + }; + }; +} + +BOOL WINAPI +CurrentlyWaitingForCommEvent( + MODEMINFORMATION * pModemInfo + ) + +{ + return (pModemInfo->mi_lpOverlappedEvent != NULL); + +} + + + +//**************************************************************************** +// VOID ModemSetPassthrough (MODEMINFORMATION * pModemInfo, +// DWORD dwMode) +// +// Function: Sets the device driver passthrough mode. +// +// Input: dwMode can be one of: +// MODEM_NOPASSTHROUGH +// MODEM_PASSTHROUGH +// MODEM_DCDSNIFF +// +// Returns: nothing. always assumed to succeed +// +// Fri 13-Oct-1995 18:11:26 -by- Chris Caputo [ccaputo] +// created +//**************************************************************************** +#if 0 +VOID ModemSetPassthrough (MODEMINFORMATION * pModemInfo, + DWORD dwMode) +{ + DWORD dwBytesReturned; + + if (FALSE == DeviceIoControl(pModemInfo->mi_PortHandle, + IOCTL_MODEM_SET_PASSTHROUGH, + &dwMode, + sizeof(dwMode), + NULL, + 0, + &dwBytesReturned, + NULL)) + { + MCXPRINTF1("SET_PASSTHROUGH - %s - failed.", dwMode == MODEM_NOPASSTHROUGH ? + "NOPASSTHROUGH" : + dwMode == MODEM_PASSTHROUGH ? + "PASSTHROUGH" : + dwMode == MODEM_DCDSNIFF ? + "DCDSNIFF" : + "INVALID_SETTING"); + MCXPRINTF1("DevioceIoControl(IOCTL_SET_PASSTHROUGH) returned %d", + GetLastError()); + MCXPRINTF1("pModemInfo->mi_PortHandle = %d", pModemInfo->mi_PortHandle); + ASSERT(0); + } + else + { + MCXPRINTF1("SET_PASSTHROUGH - %s - worked.", dwMode == MODEM_NOPASSTHROUGH ? + "NOPASSTHROUGH" : + dwMode == MODEM_PASSTHROUGH ? + "PASSTHROUGH" : + dwMode == MODEM_DCDSNIFF ? + "DCDSNIFF" : + "INVALID_SETTING"); + } +} +#endif + + + +VOID WINAPI +ModemSetPassthrough ( + MODEMINFORMATION * pModemInfo, + DWORD dwMode + ) + +{ + + DWORD BytesWritten; + OVERLAPPED OverLapped; + BOOL bResult; + + OverLapped.hEvent=(HANDLE)((DWORD)pModemInfo->mi_SyncReadEvent | 1); + + bResult=DeviceIoControl( + pModemInfo->mi_PortHandle, + IOCTL_MODEM_SET_PASSTHROUGH, + &dwMode, + sizeof(dwMode), + NULL, + 0, + &BytesWritten, + NULL + ); + + if (!bResult) { + + if (GetLastError() == ERROR_IO_PENDING) { + // + // pending + // + bResult=GetOverlappedResult( + pModemInfo->mi_PortHandle, + &OverLapped, + &BytesWritten, + TRUE + ); + + } + + } + + + if (bResult) { + + MCXPRINTF1("SET_PASSTHROUGH - %s - worked.", dwMode == MODEM_NOPASSTHROUGH ? + "NOPASSTHROUGH" : + dwMode == MODEM_PASSTHROUGH ? + "PASSTHROUGH" : + dwMode == MODEM_DCDSNIFF ? + "DCDSNIFF" : + "INVALID_SETTING"); + + } else { + + + MCXPRINTF1("SET_PASSTHROUGH - %s - failed.", dwMode == MODEM_NOPASSTHROUGH ? + "NOPASSTHROUGH" : + dwMode == MODEM_PASSTHROUGH ? + "PASSTHROUGH" : + dwMode == MODEM_DCDSNIFF ? + "DCDSNIFF" : + "INVALID_SETTING"); + MCXPRINTF1("DevioceIoControl(IOCTL_SET_PASSTHROUGH) returned %d", + GetLastError()); + MCXPRINTF1("pModemInfo->mi_PortHandle = %d", pModemInfo->mi_PortHandle); + ASSERT(0); + + } + + return ; + +} diff --git a/private/unimodem/tapisp/mcxstate.c b/private/unimodem/tapisp/mcxstate.c new file mode 100644 index 000000000..4d90f64e5 --- /dev/null +++ b/private/unimodem/tapisp/mcxstate.c @@ -0,0 +1,4675 @@ +/****************************************************************************** + +(C) Copyright MICROSOFT Corp., 1987-1994 + +Rob Williams, June 93 w/ State machine and parser plagarized from RAS + +Chris Caputo, 1994 - and superheavily modified since then... + +******************************************************************************/ + +#include "unimdm.h" +#include "mcxp.h" +#include "common.h" + +#include + +#ifdef VOICEVIEW +#include "voicview.h" +int VVSetClass(MODEMINFORMATION *hPort, WORD wClass); +int VVCallBackFunc(MODEMINFORMATION *hPort, WORD wFunction); +void VVTimerCallback( void ); +RealMonitor(APIINFO *pInfo); + + +char szMonitorVVon[] = "MonitorVoiceViewOn"; +char szMonitorVVoff[] = "MonitorVoiceViewOff"; +#endif // VOICEVIEW + +VOID WINAPI +HWDetectionRoutine( + MODEMINFORMATION * pModemInfo, + LPOVERNODE pNode + ); + +void WINAPI +CancelPendingIoAndPurgeCommBuffers( + PMODEMINFORMATION pModemInfo, + BOOL Purge + ); + +LPSTR +CreateDialCommands( + MODEMINFORMATION *pModemInfo, + LPSTR szPhoneNumber, + BOOL *fOriginate, + DWORD DialOptions + ); + + + +VOID SynchronizeCommConfigSettings(MODEMINFORMATION * pModemInfo, + BOOL fUpdateModemSys); + + +//**************************************************************************** +// LONG MCXOpen (LPTSTR, HANDLE, LPTSTR, LPHANDLE, DWORD, DWORD) +// +// Function: Open the modem port +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXOpen (LPTSTR szModemName, + HANDLE hDevice, + LPTSTR szKey, + LPHANDLE lph, + DWORD dwID, + DWORD dwCompletionKey) +{ + PMODEMINFORMATION pModemInfo; + + ASSERT(*lph == NULL); + + // Allocate the modeminfo control block + // + pModemInfo = AllocateModem(szKey, szModemName, hDevice); + + if (pModemInfo != NULL) + { + // We can get the control block + // + pModemInfo->mi_PortHandle = hDevice; + pModemInfo->mi_dwID = dwID; + pModemInfo->mi_dwCompletionKey = dwCompletionKey; + + *lph = (HANDLE)pModemInfo; + + MCXPRINTF("MCXOpen"); + + return MODEM_SUCCESS; + } + else + { + *lph = NULL; + return MODEM_FAILURE; + }; +} + +//**************************************************************************** +// LONG MCXClose (HANDLE, HANDLE) +// +// Function: Close the modem port +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG +MCXClose( + HANDLE hModem, + HANDLE hComm, + BOOL LineClosed + ) +{ + PMODEMINFORMATION pModemInfo; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXClose"); + + // Sets CommMask to 0, waits for any I/O to complete and purges buffers. + CancelPendingIoAndPurgeCommBuffers(pModemInfo, TRUE); + + // Reset the modem if it is not connected + // + if ((pModemInfo->mi_ModemState != STATE_CONNECTED) + && + (pModemInfo->mi_pszReset != NULL) + && + (!LineClosed)) + { + COMMTIMEOUTS commtimeout; + HANDLE hEvent; + + // Set write timeout to one second + // + commtimeout.ReadIntervalTimeout = 100; + commtimeout.ReadTotalTimeoutMultiplier = 10; + commtimeout.ReadTotalTimeoutConstant = 5000; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 1000; + + SetCommTimeouts(pModemInfo->mi_PortHandle, &commtimeout); + + if ((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL) + { + DWORD cb; + OVERLAPPED ov; + + ov.Internal = 0; + ov.InternalHigh = 0; + ov.Offset = 0; + ov.OffsetHigh = 0; + + // OR with 1 to prevent it from being posted to the completion port. + // + ov.hEvent = (HANDLE)((DWORD)hEvent | 1); + + MCXPRINTF("Sending Reset string."); + + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + pModemInfo->mi_pszReset, + pModemInfo->mi_dwResetLen, + PS_SEND); + + if (FALSE == WriteFile(pModemInfo->mi_PortHandle, pModemInfo->mi_pszReset, + pModemInfo->mi_dwResetLen, &cb, &ov)) + { + DWORD dwResult = GetLastError(); + + if (ERROR_IO_PENDING == dwResult) + { + GetOverlappedResult(pModemInfo->mi_PortHandle, + &ov, + &cb, + TRUE); + } else { + + MCXPRINTF1("WriteFile() in MCXClose() failed (0x%8x)!", dwResult); + cb=0; + + } + } + + if (cb == pModemInfo->mi_dwResetLen) { + // + // wrote the reset string, see if can get a response + // + + BYTE ResponseBuffer[20]; + + ResetEvent(hEvent); + + if (!ReadFile( + pModemInfo->mi_PortHandle, + ResponseBuffer, + 20, + &cb, + &ov + )) { + + + if (GetLastError() == ERROR_IO_PENDING) { + + GetOverlappedResult( + pModemInfo->mi_PortHandle, + &ov, + &cb, + TRUE + ); + } + + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + ResponseBuffer, + cb, + PS_RECV + ); + + } + + } else { + + MCXPRINTF1("WriteFile() in MCXClose() only wrote %d bytes!", + cb); + } + + CloseHandle(hEvent); + } + + SetCommMask( + pModemInfo->mi_PortHandle, + 0 + ); + + PurgeComm( + pModemInfo->mi_PortHandle, + PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR + ); + + + } + + if (pModemInfo->mi_CompatibilityFlags & COMPAT_FLAG_LOWER_DTR) { + // + // For USR 33.6 modem that stop working after being open and closed + // + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + + Sleep(50); + } + + + ASSERT(pModemInfo->mi_lpOverlappedRW == NULL); + ASSERT(pModemInfo->mi_lpOverlappedEvent == NULL); + + // Free the modem control block + // + FreeModem(pModemInfo, hComm); + return MODEM_SUCCESS; +} + +//**************************************************************************** +// LONG MCXInit (HANDLE, HANDLE) +// +// Function: Initializes the modem port +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if operation is pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXInit(HANDLE hModem, MCX_IN *pmcxi) +{ + PMODEMINFORMATION pModemInfo; + LPSTR pszzCmdInMem1, pszzCmdInMem2; + DWORD dwRet = MODEM_FAILURE; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXInit"); + + if (pModemInfo->mi_ModemState == STATE_UNKNOWN || + pModemInfo->mi_ModemState == STATE_DISCONNECTED || + pModemInfo->mi_ModemState == STATE_MONITORING) + { +#ifdef VOICEVIEW + VVSetClass( pModemInfo, VVCLASS_0 ); // verify modem is in correct fclass +#endif // VOICEVIEW + + pModemInfo->mi_dwNegotiatedModemOptions = 0; + pModemInfo->mi_dwNegotiatedDCERate = 0; + pModemInfo->mi_dwNegotiatedDTERate = 0; + + // Get the current comm config modem settings from modem.sys and set + // the current DCE rate and modem options. Also, fSettingsInitStringsBuilt + // will be set appropriately. + // + SynchronizeCommConfigSettings(pModemInfo, + TRUE); + + if (pszzCmdInMem1 = GetCommonCommandStringCopy(pModemInfo->mi_hCommon, + COMMON_INIT_COMMANDS)) + { + MCXPRINTF("Initializing modem..."); + if (pModemInfo->mi_fSettingsInitStringsBuilt == FALSE) + { + MCXPRINTF("building SettingsInit."); + if (!CreateSettingsInitEntry(pModemInfo)) + { + // only catastrophic if it is a modem + // + if (pModemInfo->mi_fModem) + { + MCXPRINTF("CreateSettingsInitEntry failed!!!"); + LogString(pModemInfo->mi_hLogFile, pModemInfo->mi_dwID, + IDS_MSGERR_FAILED_INITSTRINGCONSTRUCTION); + LocalFree(pszzCmdInMem1); + goto Failure; + } + } + pModemInfo->mi_fSettingsInitStringsBuilt = TRUE; + } + else + { + MCXPRINTF("using cached SettingsInit."); + } + + if (pszzCmdInMem2 = LoadRegCommands(pModemInfo, szSettingsInit, + pszzCmdInMem1)) + { + pModemInfo->mi_ModemState = STATE_INITIALIZING; + MCXPRINTF("State <- Initializing"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,IDS_MSGLOG_INIT); + dwRet = ModemCommand(pModemInfo, pmcxi->dwReqID, + pmcxi->pMcxOut, pszzCmdInMem2); + }; + + // Free the first buffer + // + LocalFree(pszzCmdInMem1); + } + } + + if (MODEM_FAILURE == dwRet) + { +Failure: + MCXPRINTF("Init failed."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_INIT); + } + return dwRet; +} + +//**************************************************************************** +// LONG MCXDial (HANDLE, LPSTR, HANDLE) +// +// Function: Dials the modem with the provided number. The number could be in +// the following formats: +// "" - originate +// ";" - dialtone detection +// "5551212" - dial and originate +// "5551212;" - dial +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if operation is pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG +MCXDial( + HANDLE hModem, + LPSTR szData, + MCX_IN *pmcxi, + DWORD DialOptions + ) +{ + PMODEMINFORMATION pModemInfo; + LPSTR pszzCmdInMem; + DWORD dwRet = MODEM_FAILURE; + BOOL fOriginate; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXDial"); + + if (pModemInfo->mi_ModemState == STATE_DISCONNECTED || + pModemInfo->mi_ModemState == STATE_MONITORING || + pModemInfo->mi_ModemState == STATE_DIALED) + { +#ifdef VOICEVIEW + VVSetClass( pModemInfo, VVCLASS_0 ); // verify modem is in correct fclass +#endif // VOICEVIEW + + MCXPRINTF("building dial strings..."); + + // build dial commands in memory (as opposed to the registry) + // + if (pszzCmdInMem = CreateDialCommands(pModemInfo, szData, &fOriginate, DialOptions)) + { + MCXPRINTF("Dialing..."); + pModemInfo->mi_ModemState = fOriginate ? STATE_ORIGINATING : STATE_DIALING; + + + if (fOriginate) + { + MCXPRINTF("State <- Dialing and Originating"); + } + else + { + MCXPRINTF("State <- Dialing"); + } + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_DIAL); + dwRet = ModemCommand(pModemInfo, pmcxi->dwReqID, + pmcxi->pMcxOut, pszzCmdInMem); + } + else + { + MCXPRINTF("couldn't build dial strings..."); + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_DIALSTRINGCONSTRUCTION, szData); + } + } + + if (MODEM_FAILURE == dwRet) + { + MCXPRINTF("Dial failed."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_DIAL); + } + return dwRet; +} + +//**************************************************************************** +// LONG MCXMonitor (HANDLE, DWORD, HANDLE) +// +// Function: initializes the modem to monitor the incoming call +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if operation is pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXMonitor(HANDLE hModem, DWORD dwType, MCX_IN *pmcxi) +{ +#ifdef VOICEVIEW + MCXPRINTF("MCXMonitoring...-go to fclass80"); + VVSetClass( pInfo->hPort, VVCLASS_80 ); // verify modem is in correct fclass + return( RealMonitor(pInfo)); +} + +LONG RealMonitor(HANDLE hModem, DWORD dwType, HANDLE hEvent) +{ +#endif // VOICEVIEW + PMODEMINFORMATION pModemInfo; + LPSTR pszzCmdInMem; +// LPSTR pszMonitorKey = szMonitor; // default reg key + DWORD dwRet = MODEM_FAILURE; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXMonitor"); + + if (pModemInfo->mi_ModemState == STATE_DISCONNECTED || + pModemInfo->mi_ModemState == STATE_MONITORING) + { +#ifdef VOICEVIEW + if ( pModemInfo->VVInfo.wState != VVSTATE_NONE ) + { + // only enabled when voiceview is waiting for stuff + // use the commands to set the modem into fclass80 (voiceview) + // or use the commands to set default fclass0 + if ( pModemInfo->VVInfo.wClass == VVCLASS_80 ) + { + pszMonitorKey = szMonitorVVon; + // we will tell VV can use the port after the OK + } + else + { + pszMonitorKey = szMonitorVVoff; + VVCallBackFunc( pModemInfo, VVR_LINE_GONE ); // tell VV CAN'T use port + } + } +#endif // VOICEVIEW + + if (pszzCmdInMem = GetCommonCommandStringCopy(pModemInfo->mi_hCommon, + COMMON_MONITOR_COMMANDS)) + { + MCXPRINTF("Monitoring..."); + pModemInfo->mi_ModemState = STATE_MONITORING; + MCXPRINTF("State <- Monitoring"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_MONITOR); + + // does the caller want continuous monitoring? + // + pModemInfo->mi_fContinuousMonitoring = dwType; + dwRet = ModemCommand(pModemInfo, pmcxi->dwReqID, + pmcxi->pMcxOut, pszzCmdInMem); + } + } + + if (MODEM_FAILURE == dwRet) + { + MCXPRINTF("Monitor failed."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_MONITOR); + } + return dwRet; +} + +//**************************************************************************** +// LONG MCXAnswer (HANDLE, HANDLE) +// +// Function: Answers the incoming call +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if operation is pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXAnswer(HANDLE hModem, MCX_IN *pmcxi) +{ + PMODEMINFORMATION pModemInfo; + LPSTR pszzCmdInMem; + DWORD dwRet = MODEM_FAILURE; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXAnswer"); + + if (pModemInfo->mi_ModemState == STATE_DISCONNECTED || + pModemInfo->mi_ModemState == STATE_MONITORING || + pModemInfo->mi_ModemState == STATE_DIALED) + { +#ifdef VOICEVIEW + VVSetClass( pModemInfo, VVCLASS_0 ); // verify modem is in correct fclass +#endif // VOICEVIEW + + if (pszzCmdInMem = GetCommonCommandStringCopy(pModemInfo->mi_hCommon, COMMON_ANSWER_COMMANDS)) + { + MCXPRINTF("Answering..."); + pModemInfo->mi_ModemState = STATE_ANSWERING; + MCXPRINTF("State <- Answering"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_ANSWER); + dwRet = ModemCommand(pModemInfo, pmcxi->dwReqID, + pmcxi->pMcxOut, pszzCmdInMem); + } + } + + if (MODEM_FAILURE == dwRet) + { + MCXPRINTF("Answer failed."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_ANSWER); + } + return dwRet; +} + +//**************************************************************************** +// LONG MCXHangup (HANDLE, HANDLE) +// +// Function: hangs up the modem +// +// Returns: MODEM_SUCCESS if success +// MODEM_PENDING if operation is pending +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXHangup(HANDLE hModem, MCX_IN *pmcxi) +{ + PMODEMINFORMATION pModemInfo; + DWORD dwTmp; + ULONG ulError; + DWORD dwRet = MODEM_FAILURE; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXHangup"); + + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_HANGUP); + MCXPRINTF("Hanging up..."); + + // Since a hangup was requested, make sure we always return MODEM_SUCCESS + // when we complete the hangup. + // (Note: this even applies to STATE_HANGING_UP_REMOTE!) + // + pModemInfo->mi_dwUnconditionalReturnValue = MODEM_SUCCESS; + + pModemInfo->mi_DisconnectHandler=NULL; + + + // Handle hangup requests for when we are already hanging up by returning PENDING + // + if (STATE_HANGING_UP_REMOTE == pModemInfo->mi_ModemState || + STATE_HANGING_UP_DTR == pModemInfo->mi_ModemState || + STATE_HANGING_UP_NON_CMD == pModemInfo->mi_ModemState || + STATE_HANGING_UP_CMD == pModemInfo->mi_ModemState) + { + MCXPRINTF("received a hang up request while already hanging up. Returning PENDING..."); + + pModemInfo->mi_ReqID = pmcxi->dwReqID; + pModemInfo->mi_pmcxo = pmcxi->pMcxOut; + + return MODEM_PENDING; + } + + // Flush the port and close all of the gates! + // + // + ModemSetPassthrough(pModemInfo, MODEM_NOPASSTHROUGH); + + // Sets CommMask to 0, waits for any I/O to complete and purges buffers. + CancelPendingIoAndPurgeCommBuffers( + pModemInfo, + (pModemInfo->mi_ModemState != STATE_REMOTE_DROPPED) + ); + + // Make sure RTS is high. + EscapeCommFunction(pModemInfo->mi_PortHandle, SETRTS); + + // Free the current cmd if one exists + if (pModemInfo->mi_pszzCmds) + { + if (pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzCmds); + } + pModemInfo->mi_pszzCmds = NULL; + } + + // Reset hangup counter to 1. + // + pModemInfo->mi_dwHangupTryCount = 1; + + switch (pModemInfo->mi_ModemState) + { + case STATE_DIALED: + // + // need to send "ATH" + // + MCXPRINTF("State <- Hanging up cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_CMD; + dwRet = ModemCommand(pModemInfo, pmcxi->dwReqID, + pmcxi->pMcxOut, pModemInfo->mi_pszzHangupCmds); + break; + + + + case STATE_DIALING: + case STATE_ANSWERING: + case STATE_ORIGINATING: +// case STATE_INITIALIZING: + if (pModemInfo->mi_fModem) + { + // send a character to cancel the call/answer + // don't need to #define \r because modems only care about it being a character, + // not a specific one. + // + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + "\r", + 1, + PS_SEND); + dwRet = ModemWrite(pModemInfo, "\r", 1, &dwTmp, TO_FLUSH); + if (dwRet == MODEM_FAILURE) + { + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("WriteComm Error. State <- Unknown"); + } + else + { + pModemInfo->mi_ReqID = pmcxi->dwReqID; + pModemInfo->mi_pmcxo = pmcxi->pMcxOut; + + pModemInfo->mi_RcvState = FLUSH_WRITE_QUEUE; + + // Initialize receive state machine + // + MCXPRINTF("State <- Hanging up non-cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_NON_CMD; + dwRet = MODEM_PENDING; + } + } + else + { + // nothing to do for null-modems + // + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + dwRet = MODEM_SUCCESS; + } + break; + + case STATE_WAIT_FOR_RLSD: + case STATE_CONNECTED: + // + // Drop the DTR line + // + MCXPRINTF("lowering DTR"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_HARDWAREHANGUP); + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + + pModemInfo->mi_ReqID = pmcxi->dwReqID; + pModemInfo->mi_pmcxo = pmcxi->pMcxOut; + + MCXPRINTF("State <- Hanging up dtr"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_DTR; + + // Initialize receive state machine + // + pModemInfo->mi_RcvState = SET_TIMEOUT; + + ReadCompletionRoutine2(pModemInfo); + + dwRet = MODEM_PENDING; + break; + + case STATE_INITIALIZING: + case STATE_MONITORING: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + dwRet = MODEM_SUCCESS; + break; + + case STATE_UNKNOWN: + case STATE_DISCONNECTED: + // no need to change state + // + dwRet = MODEM_SUCCESS; + break; + + case STATE_REMOTE_DROPPED: + + pModemInfo->mi_ReqID = pmcxi->dwReqID; + pModemInfo->mi_pmcxo = pmcxi->pMcxOut; + + pModemInfo->mi_ModemState=STATE_HANGING_UP_REMOTE; + + pModemInfo->mi_RcvState = START_READ; + ReadCompletionRoutine2(pModemInfo); + + dwRet = MODEM_PENDING; + + break; + +// case STATE_HANGING_UP_REMOTE: +// case STATE_HANGING_UP_DTR: +// case STATE_HANGING_UP_NON_CMD: +// case STATE_HANGING_UP_CMD: + default: + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("being hung up at a non-standard time. Why??? State <- Unknown"); + dwRet = MODEM_SUCCESS; + break; + } // switch + + ClearCommError(pModemInfo->mi_PortHandle, &ulError, NULL); + + if (MODEM_FAILURE == dwRet) + { + MCXPRINTF("hangup failed."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_HANGUP); + } + return dwRet; +} + +//**************************************************************************** +// LONG MCXGetCommConfig (HANDLE, LPCOMMCONFIG, LPDWORD) +// +// Function: Gets modem config +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXGetCommConfig (HANDLE hModem, LPCOMMCONFIG lpCommConfig, LPDWORD lpcb) +{ + return GetCommConfig(((PMODEMINFORMATION)hModem)->mi_PortHandle, + lpCommConfig, + lpcb) + ? MODEM_SUCCESS + : MODEM_FAILURE; +} + +//**************************************************************************** +// LONG MCXSetCommConfig (HANDLE, LPCOMMCONFIG, DWORD) +// +// Function: Sets modem config +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXSetCommConfig (HANDLE hModem, LPCOMMCONFIG lpCommConfig, DWORD cb) +{ + PMODEMINFORMATION pModemInfo = (PMODEMINFORMATION)hModem; + BOOL fRet; + + + LPMODEMSETTINGS lpMS; + + lpMS = (LPMODEMSETTINGS)((LPBYTE)lpCommConfig + + lpCommConfig->dwProviderOffset); + + + if (lpMS->dwPreferredModemOptions & MDM_FLOWCONTROL_HARD) { + + DPRINTF("McxSetCommConfig: enabling rts/cts control in DCB."); + + lpCommConfig->dcb.fOutxCtsFlow=1; + lpCommConfig->dcb.fRtsControl=RTS_CONTROL_HANDSHAKE; + + lpCommConfig->dcb.fOutX=FALSE; + lpCommConfig->dcb.fInX=FALSE; + + } else { + + lpCommConfig->dcb.fOutxCtsFlow=0; + lpCommConfig->dcb.fRtsControl=RTS_CONTROL_ENABLE; + } + + + + + fRet = SetCommConfig(pModemInfo->mi_PortHandle, + lpCommConfig, + cb); + + if (fRet == TRUE) + { + PrintCommSettings(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + &lpCommConfig->dcb); + + // Set DTR so modems will talk to us. + // + if (EscapeCommFunction(pModemInfo->mi_PortHandle, SETDTR) == FALSE) + { + DPRINTF("EscapeCommFunction SETDTR in SetCommConfig failed."); + return MODEM_FAILURE; + } + + // Set RTS initially to high, so modems will talk to us. This is important + // even if we aren't doing HW flow control. (ex. USR Sportster 14,400, + // Microcom Desporte FAST) + // Of course, it won't help the case where we have one of these modems and + // only 3 wires. + // + if (EscapeCommFunction(pModemInfo->mi_PortHandle, SETRTS) == FALSE) + { + DPRINTF("EscapeCommFunction SETRTS in SetCommConfig failed."); + // + // BUGBUG: this call fails on the digiboard, preventing the lower code + // BUGBUG: from running. + // BUGBUG: nothing that calls this function bothers to check the return + // BUGBUG: code anyway + // + //return MODEM_FAILURE; + } + + // Synchronize with modem.sys + SynchronizeCommConfigSettings(pModemInfo, + FALSE); + } + + return fRet ? MODEM_SUCCESS : MODEM_FAILURE; +} + + +LONG WINAPI +MCXSetModemSettings( + HANDLE hModem, + PMODEMSETTINGS lpMS + ) + +{ + PMODEMINFORMATION pModemInfo = (PMODEMINFORMATION)hModem; + + + // Need to rebuild init string? + // + if (pModemInfo->mi_dwCallSetupFailTimerSetting != lpMS->dwCallSetupFailTimer + || pModemInfo->mi_dwInactivityTimeoutSetting != lpMS->dwInactivityTimeout + || pModemInfo->mi_dwSpeakerVolumeSetting != lpMS->dwSpeakerVolume + || pModemInfo->mi_dwSpeakerModeSetting != lpMS->dwSpeakerMode + || pModemInfo->mi_dwPreferredModemOptions != lpMS->dwPreferredModemOptions) + { + pModemInfo->mi_fSettingsInitStringsBuilt = FALSE; + } + + pModemInfo->mi_dwCallSetupFailTimerSetting = + lpMS->dwCallSetupFailTimer; + + pModemInfo->mi_dwInactivityTimeoutSetting = + lpMS->dwInactivityTimeout; + + pModemInfo->mi_dwSpeakerVolumeSetting = + lpMS->dwSpeakerVolume; + + pModemInfo->mi_dwSpeakerModeSetting = + lpMS->dwSpeakerMode; + + pModemInfo->mi_dwPreferredModemOptions = + lpMS->dwPreferredModemOptions; + + + return MODEM_SUCCESS; + +} + + + + + +//**************************************************************************** +// LONG MCXSetPassthrough (HANDLE, DWORD) +// +// Function: Sets modem passthrough modes +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXSetPassthrough(HANDLE hModem, DWORD dwType) +{ + PMODEMINFORMATION pModemInfo; + ULONG ulError; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("MCXSetPassthrough"); + + // Clear any outstanding timer callbacks + // + //;ClearReadTimer(pModemInfo); + + // Determine Passthrough enabled/disabled/disabled and connected + // + switch(dwType) + { + case PASSTHROUGH_ON: + MCXPRINTF("Passthrough ON..."); + + CancelPendingIoAndPurgeCommBuffers(pModemInfo, TRUE); + + // Put the port in the connected state + // + pModemInfo->mi_ModemState = STATE_CONNECTED; + + ModemSetPassthrough(pModemInfo, MODEM_PASSTHROUGH); + break; + + case PASSTHROUGH_OFF: + MCXPRINTF("Passthrough OFF..."); + + + // Take the port out of connected state + // + pModemInfo->mi_ModemState = STATE_UNKNOWN; + + ModemSetPassthrough(pModemInfo, MODEM_NOPASSTHROUGH); + break; + + case PASSTHROUGH_OFF_BUT_CONNECTED: + MCXPRINTF("Passthrough OFF (but connected)..."); + + ModemSetPassthrough(pModemInfo, MODEM_DCDSNIFF); + break; + } + return MODEM_SUCCESS; +} + +//**************************************************************************** +// LONG MCXGetNegotiatedRate (HANDLE, LPDWORD) +// +// Function: Gets the modem connection speed +// +// Returns: MODEM_SUCCESS if success +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG MCXGetNegotiatedRate(HANDLE hModem, LPDWORD lpdwRate) +{ + PMODEMINFORMATION pModemInfo; + DWORD dwRet; + + pModemInfo = (PMODEMINFORMATION)hModem; + + if (STATE_CONNECTED == pModemInfo->mi_ModemState) + { + *lpdwRate = pModemInfo->mi_dwNegotiatedDCERate; + dwRet = MODEM_SUCCESS; + } + else + { + *lpdwRate = 0; + MCXPRINTF("GetNegotiatedRate failed."); + dwRet = MODEM_FAILURE; + } + + return dwRet; +} + +//**************************************************************************** +// LONG MCXRegisterDisconneectHandler(HANDLE, MCX_IN *) +// +// Function: Start monitoring remote disconnection +// +// Returns: MODEM_PENDING if start successfully +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG WINAPI +McxRegisterDisconectHandler( + HANDLE hModem, + DISCONNECT_HANDLER Handler, + HANDLE Context + ) + +{ + PMODEMINFORMATION pModemInfo; + DWORD dwRet; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("McxRegisterDisconnectHandler:"); + + pModemInfo->mi_DisconnectHandler=Handler; + pModemInfo->mi_DisconnectContext=Context; + + dwRet = ModemWaitEvent(pModemInfo, EV_DSR | EV_RLSD, 0); + + return dwRet; + +} + + +//**************************************************************************** +// LONG MCXDeregisterDisconneectHandler(HANDLE, MCX_IN *) +// +// Function: Stop monitoring remote disconnection +// +// Returns: MODEM_PENDING if start successfully +// MODEM_FAILURE if fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG WINAPI +McxDeregisterDisconnectHandler( + HANDLE hModem + ) + +{ + PMODEMINFORMATION pModemInfo; + + pModemInfo = (PMODEMINFORMATION)hModem; + + MCXPRINTF("McxDeregisterDisconnectHandler:"); + + pModemInfo->mi_DisconnectHandler=NULL; + pModemInfo->mi_DisconnectContext=NULL; + + return MODEM_SUCCESS; +} + +//**************************************************************************** +// void MCXAsyncComplete (HANDLE, LPOVERLAPPED) +// +// Function: Completes an async operation +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//****************************************************************************/ + +void MCXAsyncComplete (HANDLE hModem, LPOVERLAPPED lpOverlapped) +{ + PMODEMINFORMATION pModemInfo = (PMODEMINFORMATION)hModem; + LPOVERNODE pNode = (LPOVERNODE)lpOverlapped; + + ASSERT(lpOverlapped != NULL); + + if (pNode->Type == OVERNODE_TYPE_READWRITE) { + // + // it's a read/write op + // + if (pNode->dwToken == pModemInfo->mi_dwRWIOExpected) { + // + // It the one we wanted + // + MCXPRINTF1("MCXAsyncComplete() handling RW i/o. # %d",pNode->dwToken); + + pModemInfo->mi_dwRWIOExpected++; + + ReadCompletionRoutine2(pModemInfo); + + } else { + + MCXPRINTF1("MCXAsyncComplete() ignoring old RW i/o. # %d",pNode->dwToken); + } + + } else { + + if (pNode->Type == OVERNODE_TYPE_COMMEVENT) { + // + // WaitCommEvent completion + // + if (pNode->dwToken == pModemInfo->mi_dwEventIOExpected) { + + MCXPRINTF2("MCXAsyncComplete() handling Event i/o, # %d, %08lx.",pNode->dwToken, pNode); + + pModemInfo->mi_dwEventIOExpected++; + + HWDetectionRoutine(pModemInfo, pNode); + + } else { + + MCXPRINTF2("MCXAsyncComplete() ignoring old Event i/o, # %d, %08lx.",pNode->dwToken, pNode); + } + + } else { + + if (pNode->Type == OVERNODE_TYPE_WORKITEM) { + + if (pNode->dwToken == pModemInfo->mi_dwDeferedExpected) { + + pModemInfo->mi_dwDeferedExpected++; + + MCXPRINTF1("MCXAsyncComplete() handling defered work item # %d.",pNode->dwToken); + + ReadCompletionRoutine2(pModemInfo); + + } else { + + MCXPRINTF1("MCXAsyncComplete() ignoring old defered work item # %d.",pNode->dwToken); + } + + } else { + // + // unknown io type + // + ASSERT(0); + + } + } + } + + return; +} + +//**************************************************************************** +// void ModemCallClient () +// +// Function: Completes an async operation +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +void ModemCallClient (MODEMINFORMATION * pModemInfo, DWORD Param) +{ + MCX_OUT *pMcxOut; + + MCXPRINTF1("ModemCallClient: %d",Param); + + // There must be an output buffer + // + if ((pMcxOut = pModemInfo->mi_pmcxo) != NULL) + { + pMcxOut->dwReqID = pModemInfo->mi_ReqID; + + if (pModemInfo->mi_dwUnconditionalReturnValue == MODEM_NO_UNCONDITIONAL) + { + pMcxOut->dwResult= Param; + } + else + { + pMcxOut->dwResult= pModemInfo->mi_dwUnconditionalReturnValue; + }; + pModemInfo->mi_dwUnconditionalReturnValue = MODEM_NO_UNCONDITIONAL; + + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + pModemInfo->mi_dwCompletionKey, + NULL); + }; + return; +} + +//**************************************************************************** +// void ReadNotifyClient(MODEMINFORMATION *, DWORD) +// +// Function: The modem's state machine +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +void ReadNotifyClient(MODEMINFORMATION * pModemInfo, DWORD Param) +{ + ULONG ulError; + + pModemInfo->mi_RcvState = END_READ; + + switch (pModemInfo->mi_ModemState) + { + case STATE_DIALING: + switch (Param) + { + case MODEM_SUCCESS: + pModemInfo->mi_ModemState = STATE_DIALED; + MCXPRINTF("State <- Dialed"); + break; + + case MODEM_BUSY: + case MODEM_NOANSWER: + case MODEM_NOCARRIER: + case MODEM_NODIALTONE: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + break; + + default: + Param = MODEM_FAILURE; + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + break; + } // switch (Param) + break; + + case STATE_WAIT_FOR_RLSD: + // + // fall through + // + + + case STATE_ORIGINATING: + case STATE_ANSWERING: + switch (Param) + { + case MODEM_SUCCESS: + + if (pModemInfo->mi_fModem && (pModemInfo->mi_ModemState != STATE_WAIT_FOR_RLSD)) { + // + // real mode and we are not already waiting + // + + DWORD dwStat; + DWORD dwRet; + + GetCommModemStatus(pModemInfo->mi_PortHandle, &dwStat); + + // + // does it look like the modem is connected + // + if (!(dwStat & MS_RLSD_ON)) { + // + // got connect, but rlsd not high + // + MCXPRINTF("Got Connect, but rlsd is low, waiting"); + + pModemInfo->mi_ModemState=STATE_WAIT_FOR_RLSD; + + dwRet=ModemWaitEvent(pModemInfo, EV_RLSD, pModemInfo->mi_dwWaitForCDTime); + + if (dwRet == MODEM_PENDING) { + + return; + } + } + } + + + pModemInfo->mi_ModemState = STATE_CONNECTED; + MCXPRINTF("State <- Connected"); + + // do we need to adjust the dwNegotiatedDCERate? + // + if (pModemInfo->mi_dwNegotiatedDCERate == 0) + { + DCB Dcb; + + // get the DCB + // + if (!GetCommState(pModemInfo->mi_PortHandle, &Dcb)) + { + MCXPRINTF("was unable to get the comm state!"); + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + Param = MODEM_FAILURE; + break; + } + + // Did we have any DTE rate info reported + // + if (pModemInfo->mi_dwNegotiatedDTERate) + { + // Yes, use it. + // + pModemInfo->mi_dwNegotiatedDCERate = pModemInfo->mi_dwNegotiatedDTERate; + + if (pModemInfo->mi_dwNegotiatedDTERate != Dcb.BaudRate) + { + // set DCB + // + MCXPRINTF("adjusting DTE to match reported DTE"); + Dcb.BaudRate = pModemInfo->mi_dwNegotiatedDTERate; + PrintCommSettings(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,&Dcb); + if (!SetCommState(pModemInfo->mi_PortHandle, &Dcb)) + { + MCXPRINTF("was unable to set the comm state!"); + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + Param = MODEM_FAILURE; + break; + } + } + } + else + { + // No, use the current DTE baud rate + // + MCXPRINTF("using current DTE"); + pModemInfo->mi_dwNegotiatedDCERate = Dcb.BaudRate; + } + } + + + if (pModemInfo->mi_dwNegotiatedDCERate) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_CONNECTEDBPS, pModemInfo->mi_dwNegotiatedDCERate); + } + else + { + if (pModemInfo->mi_dwNegotiatedDTERate) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_CONNECTEDBPS, pModemInfo->mi_dwNegotiatedDTERate); + } + else + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_CONNECTED); + } + } + + if (pModemInfo->mi_dwNegotiatedModemOptions & MDM_ERROR_CONTROL) + { + if (pModemInfo->mi_dwNegotiatedModemOptions & MDM_CELLULAR) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_CELLULAR); + } + else + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_ERRORCONTROL); + } + } + else + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_UNKNOWNERRORCONTROL); + } + + if (pModemInfo->mi_dwNegotiatedModemOptions & MDM_COMPRESSION) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_COMPRESSION); + } + else + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_UNKNOWNCOMPRESSION); + } + + MCXPRINTF1("Negotiated DCE is %d bits per second.", pModemInfo->mi_dwNegotiatedDCERate); + MCXPRINTF1("Error Correction is %s.", + pModemInfo->mi_dwNegotiatedModemOptions & MDM_ERROR_CONTROL ? + (pModemInfo->mi_dwNegotiatedModemOptions & MDM_CELLULAR ? "CELLULAR" : "ON") : + "OFF"); + MCXPRINTF1("Data Compression is %s.", + pModemInfo->mi_dwNegotiatedModemOptions & MDM_COMPRESSION ? "ON" : "OFF"); + + if (pModemInfo->mi_hLogFile) + FlushLog(pModemInfo->mi_hLogFile); + + // Send down the negotiated parts of MODEMSETTINGS struct to + // modem.sys. + SynchronizeCommConfigSettings(pModemInfo, + TRUE); + break; + + case MODEM_BUSY: + case MODEM_NOANSWER: + case MODEM_NOCARRIER: + case MODEM_NODIALTONE: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + break; + + default: + Param = MODEM_FAILURE; + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + break; + } // switch (Param) + break; + + case STATE_INITIALIZING: + switch (Param) + { + case MODEM_SUCCESS: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + break; + + case MODEM_BUSY: + case MODEM_NOANSWER: + case MODEM_NOCARRIER: + case MODEM_NODIALTONE: + if (pModemInfo->mi_dwCommandTryCount < MAX_COMMAND_TRIES) + { + pModemInfo->mi_dwCommandTryCount++; + + MCXPRINTF("received an unanticipated response. Retrying previous command..."); + pModemInfo->mi_pszCurCmd = pModemInfo->mi_pszPrevCmd; + + switch(ModemWriteCommand(pModemInfo)) + { + case MODEM_PENDING: + return; + + case MODEM_SUCCESS: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + break; + + case MODEM_FAILURE: + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + break; + + default: + MCXPRINTF("hit a default in ReadNotifyClient (STATE_INITIALIZING)! BAD!"); + break; + } + break; + } + else + { + MCXPRINTF("gave up trying to do the command."); + } + // FALLTHROUGH... + + default: + Param = MODEM_FAILURE; + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + break; + } + break; + + + case STATE_HANGING_UP_REMOTE: + switch (Param) + { + case MODEM_SUCCESS: + case MODEM_BUSY: + case MODEM_NOANSWER: + case MODEM_NOCARRIER: + case MODEM_NODIALTONE: + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + break; + default: + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + break; + } + // Set HIWORD to MDM_ID_NULL to indicate this was an unexpected message + // + Param = MODEM_SUCCESS; // inform the app of the hangup, not matter what + break; + + case STATE_HANGING_UP_DTR: + { + DWORD dwStat = 0; + + // Did RLSD or DSR go down? + // + GetCommModemStatus(pModemInfo->mi_PortHandle, &dwStat); + if (dwStat & MS_RLSD_ON && dwStat & MS_DSR_ON) + { + // nope, RLSD/RSD are both high + // + if (pModemInfo->mi_fModem) + { + static char cszEscapeSequence[] = MODEM_ESCAPE_SEQUENCE; + DWORD dwTmp; + DWORD dwRet; + + MCXPRINTF("DTR droppage failed to hangup modem. Trying '+++'"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGWARN_FAILEDDTRDROPPAGE); + + // send "+++" + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + cszEscapeSequence, + MODEM_ESCAPE_SEQUENCE_LEN, + PS_SEND); + dwRet = ModemWrite(pModemInfo, cszEscapeSequence, + MODEM_ESCAPE_SEQUENCE_LEN, &dwTmp, TO_FLUSH); + if (dwRet == MODEM_FAILURE) + { + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("WriteComm Error. State <- Unknown"); + Param = MODEM_FAILURE; + } + else + { + pModemInfo->mi_RcvState = FLUSH_WRITE_QUEUE; + + // Initialize receive state machine + // + MCXPRINTF("State <- Hanging up non-cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_NON_CMD; + return; + } + } + else + { + // only try once to hangup a null-modem connection + MCXPRINTF("failed to hangup the null-modem connection!"); + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + Param = MODEM_FAILURE; + } + } + else + { + // yep, RLSD and/or DSR went low + // Raise DTR line + // + MCXPRINTF("raising DTR"); + EscapeCommFunction(pModemInfo->mi_PortHandle, SETDTR); + if (pModemInfo->mi_fModem) + { + // Initialize receive state machine + pModemInfo->mi_RcvState = START_READ; + MCXPRINTF("State <- Hanging up non-cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_NON_CMD; + ReadCompletionRoutine2(pModemInfo); + return; + } + else + { + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + Param = MODEM_SUCCESS; + } + } + break; + } + case STATE_HANGING_UP_NON_CMD: + if (MODEM_FAILURE != Param) + { + // need to send "ATH" + MCXPRINTF("State <- Hanging up cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_CMD; + + // free the memory for non-hangup commands + if (pModemInfo->mi_pszzCmds) + { + if (pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzCmds); + } + pModemInfo->mi_pszzCmds = NULL; + } + Param = ModemCommand(pModemInfo, + pModemInfo->mi_ReqID, pModemInfo->mi_pmcxo, + pModemInfo->mi_pszzHangupCmds); + if (MODEM_PENDING == Param) + { + return; + } + // SUCCESS or FAILURE hits the below if statement + } + + if (MODEM_SUCCESS == Param) + { + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + } + else + { + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + } + break; + + case STATE_HANGING_UP_CMD: + if (MODEM_FAILURE != Param) + { + // Raise DTR line + // + MCXPRINTF("raising DTR"); + EscapeCommFunction(pModemInfo->mi_PortHandle, SETDTR); + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + Param = MODEM_SUCCESS; + } + else + { + if (pModemInfo->mi_dwHangupTryCount < MAX_HANGUP_TRIES) + { + pModemInfo->mi_dwHangupTryCount++; + + // Lower DTR line + // + MCXPRINTF("lowering DTR"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_HARDWAREHANGUP); + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + MCXPRINTF("State <- Hanging up dtr"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_DTR; + + // Initialize receive state machine + // + pModemInfo->mi_RcvState = SET_TIMEOUT; + ReadCompletionRoutine2(pModemInfo); + return; + } + else + { + MCXPRINTF("failed to hangup!"); + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + } + } + break; + + case STATE_MONITORING: + if (MODEM_SUCCESS == Param) + { + // do we monitor again? + // + if (pModemInfo->mi_fContinuousMonitoring) + { + MCXPRINTF("Monitoring again."); + + // + // send up ring notification to the completion port + // they are handled differently because the BytesWritten field is non-zero + // + + PostQueuedCompletionStatus( + ghCompletionPort, + CP_BYTES_WRITTEN(CP_TYPE_RING), + pModemInfo->mi_dwCompletionKey, + NULL + ); + + + // Initialize receive state machine + pModemInfo->mi_RcvState = START_READ; + ReadCompletionRoutine2(pModemInfo); + return; + } + else + { + MCXPRINTF("not monitoring again."); + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + } + } + else + { + Param = MODEM_FAILURE; + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("State <- Unknown"); + } + break; + + default: + Param = MODEM_FAILURE; + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("hit a default in ReadNotifyClient(). State <- Unknown"); + break; + } + + // do we have a post hangup command that we would like to do? + // + if (pModemInfo->mi_dwPostHangupModemState && + pModemInfo->mi_pszzPostHangupCmds) + { + MCXPRINTF1("State <- %d (numeric because we are doing a post hangup command)", pModemInfo->mi_dwPostHangupModemState); + pModemInfo->mi_ModemState = pModemInfo->mi_dwPostHangupModemState; + + pModemInfo->mi_pszzCmds = NULL; + + Param = ModemCommand(pModemInfo, + pModemInfo->mi_ReqID, pModemInfo->mi_pmcxo, + pModemInfo->mi_pszzPostHangupCmds); + + // don't clear mi_dwPostHangupModemState, because we use that to indicate if we are doing a post hangup command + pModemInfo->mi_pszzPostHangupCmds = NULL; + + if (MODEM_PENDING == Param) + { + return; + } + } + else + { + // make sure BOTH are clear + pModemInfo->mi_pszzPostHangupCmds = NULL; + pModemInfo->mi_dwPostHangupModemState = 0; + } + + // Free the current command. + // Don't worry about affecting continuous monitoring; it will bail out + // earlier than this with a "return". + // + if (pModemInfo->mi_pszzCmds) + { + if (pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzCmds); + } + pModemInfo->mi_pszzCmds = NULL; + } + + ClearCommError(pModemInfo->mi_PortHandle, &ulError, NULL); + + if (pModemInfo->mi_ModemState == STATE_CONNECTED) + { + if (pModemInfo->mi_pszStartReadSpoof) + { + MCXPRINTF("spoofing remains:"); + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + pModemInfo->mi_pszStartReadSpoof, + pModemInfo->mi_pszEndReadSpoof - + pModemInfo->mi_pszStartReadSpoof + 1, + PS_RECV); + } + + ModemSetPassthrough(pModemInfo, MODEM_DCDSNIFF); + } + else + { + // If we didn't switch to data mode, then we still want to make sure that + // read callbacks are turned off until the next commad. We can get here + // because of a succesful init command or any unsuccesful command + // + ModemSetPassthrough(pModemInfo, MODEM_NOPASSTHROUGH); + } + + ModemCallClient(pModemInfo, Param); + return; +} + +/****************************************************************************** + + @doc INTERNAL + + @api DWORD | ModemCommand | This function sends a meta-command to the + modem. A meta-command is a command read from the registry + + @parm MODEMINFORMATION * | pModemInfo | port handle + + @parm DWORD | hWnd | The window handle to callback to when the command completes + + @parm DWORD | msg | message + + @parm DWORD | lParam | lparam + + @parm char * | pszzCmdInMem | ptr to doubly-null terminated buffer of psz's. + + @rdesc TRUE, PENDING or FALSE + +******************************************************************************/ +DWORD ModemCommand(MODEMINFORMATION * pModemInfo, + DWORD dwReqID, + MCX_OUT *pmcxo, + LPSTR pszzCmdInMem) +{ + DWORD result; + ULONG ulError; + +#ifdef VOICEVIEW + if (pModemInfo->VVInfo.wState == VVSTATE_NONE) + return MODEM_FAILURE; +#endif // VOICEVIEW + + pModemInfo->mi_ReqID = dwReqID; + pModemInfo->mi_pmcxo = pmcxo; + + // are we interrupting a command in progress? + // + if (pModemInfo->mi_pszzCmds) + { + MCXPRINTF("memory command interrupted. (ok, if monitoring)"); + } + + if (pszzCmdInMem) + { + pModemInfo->mi_pszzCmds = pszzCmdInMem; + pModemInfo->mi_pszCurCmd = pszzCmdInMem; + } + else + { + return MODEM_FAILURE; + } + + // Flush the port + // + ModemSetPassthrough(pModemInfo, MODEM_NOPASSTHROUGH); + ClearCommError(pModemInfo->mi_PortHandle, &ulError, NULL); + + // Sets CommMask to 0, waits for any I/O to complete and purges buffers. + CancelPendingIoAndPurgeCommBuffers(pModemInfo, TRUE); + + // Raise DTR line + // + if (STATE_HANGING_UP_CMD != pModemInfo->mi_ModemState) + { + MCXPRINTF("raising DTR to make sure it is high"); + EscapeCommFunction(pModemInfo->mi_PortHandle, SETDTR); + } + + pModemInfo->mi_dwCommandTryCount = 1; + result = ModemWriteCommand(pModemInfo); + + if (result != MODEM_PENDING) + { + if (pModemInfo->mi_pszzCmds) + { + if (pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzCmds); + } + pModemInfo->mi_pszzCmds = NULL; + } + } + + return (result); +} + +/****************************************************************************** + + @doc INTERNAL + + @api DWORD | ModemWriteCommand | This function writes a modem command to the + modem. + + @parm MODEMINFORMATION * | pModemInfo | port handle + + @rdesc TRUE, PENDING or FALSE + +******************************************************************************/ + +DWORD ModemWriteCommand(MODEMINFORMATION * pModemInfo) +{ + BYTE szData[MAXSTRINGLENGTH]; + static char cszNullCmd[] = "None"; + DWORD dwRet = MODEM_SUCCESS; + + + // check to see if we are doing commands in memory, and if there are any left + // + if (pModemInfo->mi_pszzCmds && *pModemInfo->mi_pszCurCmd) + { + // set szData to the current string + // + lstrcpyA(szData, pModemInfo->mi_pszCurCmd); + pModemInfo->mi_cbCmd = lstrlenA(szData); + + // save away a pointer to this current string + // + pModemInfo->mi_pszPrevCmd = pModemInfo->mi_pszCurCmd; + + // point to the next string + // + pModemInfo->mi_pszCurCmd += pModemInfo->mi_cbCmd + 1; + } + else + { + return MODEM_SUCCESS; // not really success, but it means we don't have any commands + } + + if (!ExpandMacros(szData, pModemInfo->mi_szCmd, &(pModemInfo->mi_cbCmd), NULL, 0)) + { + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("ExpandMacro Error. State <- Unknown"); + return MODEM_FAILURE; + } + + // only send command if it is not "None"/Null + // + if (lstrcmpA(pModemInfo->mi_szCmd, cszNullCmd)) + { + DWORD cbWrite; + + // Don't log the actual digits of the phone number when dialing. + // + PrintString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + pModemInfo->mi_szCmd, + pModemInfo->mi_cbCmd, + (STATE_DIALING == pModemInfo->mi_ModemState || + STATE_ORIGINATING == pModemInfo->mi_ModemState) ? + PS_SEND_SECURE : PS_SEND); + + // Make sure there nothing in the receive queue + // + PurgeComm(pModemInfo->mi_PortHandle, PURGE_RXCLEAR); + + // Send the command to the Port + // + dwRet = ModemWrite(pModemInfo, pModemInfo->mi_szCmd, + pModemInfo->mi_cbCmd, &cbWrite, TO_FLUSH); + + if (dwRet == MODEM_FAILURE) + { + // There is a failure, bail now + // + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("WriteComm Error. State <- Unknown"); + return MODEM_FAILURE; + } + } + else + { + MCXPRINTF("'None' command. Just waiting to read..."); + + } + + // Initialize receive state machine + // + ASSERT(dwRet == MODEM_SUCCESS || dwRet == MODEM_PENDING); + if(dwRet == MODEM_SUCCESS) // ModemWrite can not return SUCCESS, so this + // must be from a "None"/Null command. + { + // Start receiving response immediately + // + + pModemInfo->mi_RcvState = START_READ; + + if (!CreateDeferedWorkItem(pModemInfo)) { + + pModemInfo->mi_ModemState = STATE_UNKNOWN; + MCXPRINTF("WriteComm Error. State <- Unknown"); + return MODEM_FAILURE; + } + + } + else + { + // Pending and come back to check the result from write operation + // + pModemInfo->mi_RcvState = FLUSH_WRITE_QUEUE; + }; + + return MODEM_PENDING; +} + + + +BOOL WINAPI +SyncRead( + HANDLE CommHandle, + HANDLE Event, + LPVOID Buffer, + DWORD BufferLength, + LPDWORD BytesRead + ) + +{ + OVERLAPPED OverLapped; + BOOL bResult; + COMMTIMEOUTS commtimeout; + + commtimeout.ReadIntervalTimeout = MAXDWORD; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = 0; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 0; + SetCommTimeouts( + CommHandle, + &commtimeout + ); + + *BytesRead=0; + + // OR with 1 to prevent it from being posted to the completion port. + // + OverLapped.hEvent = (HANDLE)((DWORD)Event | 1); + + bResult=ReadFile( + CommHandle, + Buffer, + BufferLength, + BytesRead, + &OverLapped + ); + +#ifdef DEBUG + if (!bResult) { + + ASSERT(GetLastError() != ERROR_IO_PENDING); + } +#endif + + + return bResult; + +} + + + +//**************************************************************************** +// DWORD ReadComm(MODEMINFORMATION *, LPBYTE lpBuf, DWORD dwToRead, +// LPDWORD pdwRead, DWORD dwTimeout) +// +// Function: Check the spoof buffer and read from it if characters are +// available. Otherwise, call ModemRead. +// +// Returns: Spoof buffer: MODEM_SUCCESS or MODEM_FAILURE +// ModemRead : MODEM_PENDING or MODEM_FAILURE (never MODEM_SUCCESS) +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD ReadComm(MODEMINFORMATION *pModemInfo, LPBYTE lpBuf, DWORD dwToRead, + LPDWORD pdwRead, DWORD dwTimeout) +{ + DWORD dwRet; + + if (pModemInfo->mi_pszStartReadSpoof) + { + if (!pModemInfo->mi_pszEndReadSpoof) + { + MCXPRINTF("ACK! StartReadSpoof was real when EndReadSpoof was NULL!"); + } + + *pdwRead = 0; + + while (dwToRead-- && + pModemInfo->mi_pszStartReadSpoof <= pModemInfo->mi_pszEndReadSpoof) + { +// MCXPRINTF3("SPOOF mode! %8x %8x %8x", pModemInfo->mi_szResponse, +// pModemInfo->mi_pszStartReadSpoof, +// pModemInfo->mi_pszEndReadSpoof); + *lpBuf++ = *pModemInfo->mi_pszStartReadSpoof++; + (*pdwRead)++; + } + + // have we run out of spoofing material? + if (pModemInfo->mi_pszStartReadSpoof > pModemInfo->mi_pszEndReadSpoof) + { + pModemInfo->mi_pszStartReadSpoof = NULL; + pModemInfo->mi_pszEndReadSpoof = NULL; + } + + dwRet = MODEM_SUCCESS; + } + else + { + + dwRet = MODEM_SUCCESS; + + SyncRead( + pModemInfo->mi_PortHandle, + pModemInfo->mi_SyncReadEvent, + lpBuf, + dwToRead, + pdwRead + ); + + if (*pdwRead==0) { + + dwRet = ModemRead(pModemInfo, lpBuf, dwToRead, pdwRead, dwTimeout); + + if (MODEM_PENDING != dwRet) + { + // ReadComm failed + MCXPRINTF1("ReadComm error = %ld", dwRet); + } + + } + + } + + return dwRet; +} + + +//**************************************************************************** +// VOID ReadCompletionRoutine2(MODEMINFORMATION *) +// +// Function: Response Read State Machine and Timeout handler +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +VOID ReadCompletionRoutine2(MODEMINFORMATION * pModemInfo) +{ + DWORD dwResult; + MSS Mss; + static char cszNoResponse[] = "NoResponse"; + + // A good ole state machine + while (TRUE) + { + switch (pModemInfo->mi_RcvState) + { + // ****************************************************************** + // + // ModemWrite was pending and now completes or times out + // + // ****************************************************************** + // + case FLUSH_WRITE_QUEUE: + { + DWORD cb; + + // Assume success and we will start receiving the response + // + pModemInfo->mi_RcvState = START_READ; + + // Comm Errors? + HandleCommErrors(pModemInfo, 0); + + // Has all of the write buffer been emptied? + // + if (ModemRWAsyncComplete(pModemInfo, &cb) != MODEM_SUCCESS) + { + MCXPRINTF1("Write error = %ld", GetLastError()); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } + } + break; + + // ****************************************************************** + // + // Start receiving a response + // + // ****************************************************************** + // + case START_READ: + // + // Has all of the write buffer been emptied? + // + + ASSERT(pModemInfo->mi_lpOverlappedRW == NULL); + + // If we are doing commands, check for "NoResponse" on the + // next command and handle it. + // + if (pModemInfo->mi_pszzCmds && + !lstrcmpA(pModemInfo->mi_pszCurCmd, cszNoResponse)) + { + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + return; + } + + + // If we get here, it means that the write queue is empty + // + pModemInfo->mi_pszStartReadSpoof = NULL; + pModemInfo->mi_pszEndReadSpoof = NULL; + // + //***************************************************************** + // FALLTHROUGH + //***************************************************************** + // + + // ****************************************************************** + // + // Continue receiving the response + // + // ****************************************************************** + // + case RESTART_READ: + pModemInfo->mi_cbTotalResponse = 0; + pModemInfo->mi_dwPossibleResponseLen = 0; + pModemInfo->mi_RcvState = TRY_READ; + pModemInfo->mi_fBadResponseCleanupMode = FALSE; + break; + + // ****************************************************************** + // + // Try receiving the response now + // + // ****************************************************************** + // + case TRY_READ: + { + DWORD dwTimeOut; + DWORD dwCharsReceived; + DWORD dwRet; + + if (pModemInfo->mi_cbTotalResponse >= sizeof(pModemInfo->mi_szResponse)) + { + MCXPRINTF("read in the maximum # of chars and still couldn't identify the response!"); + pModemInfo->mi_RcvState = BAIL_O_RAMA_NO_MORE_DATA; + break; + } + + // Determine the read timeout for the response + // Is this the first character? (either, at all, or after an echo) + // + if (pModemInfo->mi_cbTotalResponse == 0) + { + // set timeout for waiting for the first character + switch(pModemInfo->mi_ModemState) + { + case STATE_MONITORING: + // BUGBUG: (Chris Caputo - 1/22/96) + // BUGBUG: It seems that if we send some init commands for the + // BUGBUG: monitor (like ATS0=0), that we are screwed here + // BUGBUG: because the infinite timeout is not appropriate for + // BUGBUG: waiting to see if a command was accepted. + dwTimeOut = TO_INFINITE; // wait forever + break; + + case STATE_INITIALIZING: + case STATE_HANGING_UP_NON_CMD: + case STATE_HANGING_UP_CMD: + case STATE_HANGING_UP_REMOTE: + dwTimeOut = TO_FIRST_CHAR_AFTER_INIT_CMD; // should be short (ie. 2 seconds) + break; + + case STATE_DIALING: + case STATE_ANSWERING: + case STATE_ORIGINATING: + // do we support dwCallSetupFailTimer? + if (pModemInfo->mi_dwCallSetupFailTimerCap && + pModemInfo->mi_dwCallSetupFailTimerSetting) + { + dwTimeOut = pModemInfo->mi_dwCallSetupFailTimerSetting + * MILISECONDS_PER_SECOND + + TO_ADDITIONAL_TO_CALL_SETUP_FAIL_TIMER; + } + else + { + dwTimeOut = pModemInfo->mi_fModem ? + TO_FIRST_CHAR_AFTER_CONNECTION_CMD : + TO_FIRST_CHAR_AFTER_CONNECTION_CMD_NON_MODEM; + } + break; + + default: + MCXPRINTF("hit a default in SET_READ_CALLBACK!"); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } + + MCXPRINTF2("waits for a new response for %d secs @%d.", dwTimeOut/1000, + GETTICKCOUNT()); + } + else + { + dwTimeOut = TO_NEXT_CHAR_RCV_INTERVAL; + } + + if (dwTimeOut) + { + dwTimeOut += GET_PORT_LATENCY(pModemInfo); + } + +#ifdef DEBUG + if (GET_PORT_LATENCY(pModemInfo)) + { + ASSERT(gRegistryFlags & fGRF_PORTLATENCY); + // DPRINTF2( + // "PL:%lu. New TO:%lu", + // GET_PORT_LATENCY(pModemInfo), + // dwTimeOut + // ); + } +#endif + + // Read the next character + // + dwRet = ReadComm(pModemInfo, + pModemInfo->mi_szResponse + + pModemInfo->mi_cbTotalResponse, + 1, &dwCharsReceived, dwTimeOut); + switch (dwRet) + { + case MODEM_SUCCESS: // Only Spoof mode returns SUCCESS here. + pModemInfo->mi_cbTotalResponse += dwCharsReceived; + pModemInfo->mi_RcvState = CHECK_RESPONSE; + break; + + case MODEM_PENDING: + pModemInfo->mi_RcvState = POST_READ_CALLBACK; + return; + + default: + MCXPRINTF("had errors while trying to read from the port."); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } + break; + } + + // ****************************************************************** + // + // The pending read completes successfully or fails + // + // ****************************************************************** + // + case POST_READ_CALLBACK: + { + DWORD dwCharsReceived; + DWORD dwRet; + + // Comm Errors? + HandleCommErrors(pModemInfo, 0); + + // Has all of the write buffer been emptied? + dwRet = ModemRWAsyncComplete(pModemInfo, &dwCharsReceived); + + switch (dwRet) + { + case MODEM_SUCCESS: + pModemInfo->mi_cbTotalResponse += dwCharsReceived; + pModemInfo->mi_RcvState = CHECK_RESPONSE; + break; + + case MODEM_PENDING: + // Timeout on read + // did we have a possible response? + // + if (pModemInfo->mi_dwPossibleResponseLen) + { + MCXPRINTF("SUCCESS (Timeout)"); + pModemInfo->mi_RcvState = USE_POSSIBLE_RESPONSE; + } + else + { + if (!pModemInfo->mi_fBadResponseCleanupMode) + { + MCXPRINTF1("timeout expired while waiting for a response @%d.", + GETTICKCOUNT()); + } + + // timeouts while in non-cmd stage of hanging up will be followed + // by a command hangup (ATH) started in ReadNotifyClient. + // + if (STATE_HANGING_UP_NON_CMD == pModemInfo->mi_ModemState) + { + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + return; + } + + pModemInfo->mi_RcvState = BAIL_O_RAMA_NO_MORE_DATA; + } + break; + + default: + // Fail on read + // + MCXPRINTF("had errors while trying to read from the port."); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + }; + break; + } + + // ****************************************************************** + // + // The read completes successfully, checks new response + // + // ****************************************************************** + // + case CHECK_RESPONSE: + if (pModemInfo->mi_fBadResponseCleanupMode) + { + pModemInfo->mi_RcvState = TRY_READ; + break; + } + + switch (CheckResponse(pModemInfo, &Mss)) + { + case SUCCESS: + pModemInfo->mi_RcvState = USE_WHOLE_RESPONSE; + break; + + case ECHO: + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_cbTotalResponse, PS_RECV); + pModemInfo->mi_RcvState = START_READ; + break; + + case PARTIAL_RESPONSE: + pModemInfo->mi_RcvState = TRY_READ; + break; + + case UNRECOGNIZED_RESPONSE: + if (pModemInfo->mi_dwPossibleResponseLen) + { + pModemInfo->mi_RcvState = USE_POSSIBLE_RESPONSE; + } + else + { + if (STATE_MONITORING == pModemInfo->mi_ModemState) + { + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_cbTotalResponse, PS_RECV); + + // BUGBUG possibly put some autobauding crap in here. For now, just + // BUGBUG continue waiting. +#ifdef DEBUG + // Probably have to listen at 115200 for this to resolve the + // ambiguities. Scrap the lower baud rates too. + switch (pModemInfo->mi_szResponse[0] & 0xff) + { + case 0x00: + MCXPRINTF("looks like client is at 300 or 1200 bps"); + break; + case 0x80: + MCXPRINTF("looks like client is at 2400 bps"); + break; + case 0xf8: + MCXPRINTF("looks like client is at 4800 bps"); + break; + case 0x1e: + MCXPRINTF("looks like client is at 9600 bps"); + break; + case 0xf1: + case 0xf9: + case 0xfe: + MCXPRINTF("looks like client is at 38400 bps"); + break; + case 0xff: + MCXPRINTF("looks like client is at 57600 or 115200 bps"); + break; + } +#endif // DEBUG + + // ignore the error and keep monitoring + pModemInfo->mi_RcvState = START_READ; + } + else + { + MCXPRINTF("unrecognized response! (inf file bad?) Reading rest of input..."); + pModemInfo->mi_RcvState = BAIL_O_RAMA_MORE_DATA; + } + } + break; + + case POSSIBLE_RESPONSE: + pModemInfo->mi_RcvState = TRY_READ; + CopyMemory(&pModemInfo->mi_mssPossible, &Mss, sizeof(MSS)); + + // store the length of this possible response + pModemInfo->mi_dwPossibleResponseLen = pModemInfo->mi_cbTotalResponse; + break; + + default: + MCXPRINTF("hit a default in CHECK_RESPONSE!"); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } + break; + + // ****************************************************************** + // + // We got a bad response from modem + // + // ****************************************************************** + // + case BAD_RESPONSE_CLEANUP_END: + // were we trying to connect? if yes, then check RLSD + if (pModemInfo->mi_fModem) + { + if (pModemInfo->mi_ModemState == STATE_ANSWERING || + pModemInfo->mi_ModemState == STATE_ORIGINATING) + { + DWORD dwStat = 0; + + // Is RLSD on? + // + GetCommModemStatus(pModemInfo->mi_PortHandle, &dwStat); + if (dwStat & MS_RLSD_ON) + { + MCXPRINTF("couldn't recognize connection response, but it did detect a successful connection."); + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + } + else + { + MCXPRINTF("couldn't recognize connection response, and it appears that the connection failed."); + + // Drop the DTR line + MCXPRINTF("lowering DTR"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_HARDWAREHANGUP); + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + } + return; + } + else + { + if (pModemInfo->mi_ModemState == STATE_DIALING) // check for DIALING + { + MCXPRINTF("couldn't recognize response to a dial command and since we are dialing, we can't retry, nor continue. Hanging up..."); + pModemInfo->mi_dwUnconditionalReturnValue = MODEM_FAILURE; // make sure the Dialing command gets a failure return + + // need to send "ATH" + MCXPRINTF("State <- Hanging up cmd"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_CMD; + + // Reset hangup counter to 0. + pModemInfo->mi_dwHangupTryCount = 1; + + // free the memory for non-hangup commands + if (pModemInfo->mi_pszzCmds) + { + if (pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzCmds); + } + pModemInfo->mi_pszzCmds = NULL; + } + dwResult = ModemCommand(pModemInfo, + pModemInfo->mi_ReqID, pModemInfo->mi_pmcxo, + pModemInfo->mi_pszzHangupCmds); + if (dwResult != MODEM_PENDING) + { + ReadNotifyClient(pModemInfo, dwResult); + } + return; + } + } + } + + // still no luck... then adjust speed after trying at this speed 2 times + // BUGBUG - adjust speed + + // and try the command again (if there was one) + if (pModemInfo->mi_pszzCmds) + { + MCXPRINTF("retrying last command..."); + pModemInfo->mi_pszCurCmd = pModemInfo->mi_pszPrevCmd; + dwResult = ModemWriteCommand(pModemInfo); + if (dwResult != MODEM_PENDING) + { + ReadNotifyClient(pModemInfo, dwResult); + } + } + else + { + // I think we only get here if we failed to read a response for a hangup. + MCXPRINTF("failed to read a response for a hangup. Returning SUCCESS anyways."); + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + } + return; + + // ****************************************************************** + // + // we get here if we had an unrecognized response + // + // ****************************************************************** + // + case BAIL_O_RAMA_MORE_DATA: + // get the rest of the bad response + pModemInfo->mi_dwPossibleResponseLen = 0; // ditch any possible responses + pModemInfo->mi_fBadResponseCleanupMode = TRUE; // turn on cleanup mode + pModemInfo->mi_RcvState = TRY_READ; + break; + + // ****************************************************************** + // + // we get here if a timeout has occured and no data was available or + // if we read too much data also after cleaning up an unrecognized + // response + // + // ****************************************************************** + // + case BAIL_O_RAMA_NO_MORE_DATA: + switch (pModemInfo->mi_ModemState) + { + case STATE_INITIALIZING: + { + DWORD dwStat = 0; + + // Check modem control signals. + // + GetCommModemStatus(pModemInfo->mi_PortHandle, &dwStat); + + // does it look like the modem is still online from a previous call? + if (dwStat & MS_RLSD_ON) + { + MCXPRINTF("It appears that a previous connection was not hung up! Attempting hangup..."); + + // are we already in the midst of a post hangup command? + if (pModemInfo->mi_dwPostHangupModemState) + { + MCXPRINTF("won't do a second hangup attempt of the existing call. Bail!"); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + } + else + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGWARN_PREVIOUSCONNECTIONNOTHUNGUP); + + // save state + pModemInfo->mi_dwPostHangupModemState = STATE_INITIALIZING; + pModemInfo->mi_pszzPostHangupCmds = pModemInfo->mi_pszzCmds; + pModemInfo->mi_pszzCmds = NULL; + + // do hangup + // Reset hangup counter to 1. + pModemInfo->mi_dwHangupTryCount = 1; + + // Drop the DTR line + MCXPRINTF("lowering DTR"); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_HARDWAREHANGUP); + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + MCXPRINTF("State <- Hanging up dtr"); + pModemInfo->mi_ModemState = STATE_HANGING_UP_DTR; + + // Initialize receive state machine + pModemInfo->mi_RcvState = SET_TIMEOUT; + ReadCompletionRoutine2(pModemInfo); + } + return; + } + } + // FALLTHROUGH + + default: + // Print out what we were able to get + MCXPRINTF("data from failed or unrecognized response:"); + if (pModemInfo->mi_dwCommandTryCount < MAX_COMMAND_TRIES) + { + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_cbTotalResponse, PS_RECV); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGWARN_UNRECOGNIZEDRESPONSE); + pModemInfo->mi_dwCommandTryCount++; + pModemInfo->mi_RcvState = BAD_RESPONSE_CLEANUP_END; + } + else + { + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_cbTotalResponse, PS_RECV); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGERR_FAILED_RESPONSE); + MCXPRINTF("gave up trying to do the command."); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } + break; + } + break; + + // ****************************************************************** + // + // The entire modem response is good. + // + // ****************************************************************** + // + case USE_WHOLE_RESPONSE: + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_cbTotalResponse, PS_RECV); + pModemInfo->mi_RcvState = GOOD_RESPONSE; + break; + + // ****************************************************************** + // + // Some part of the response matches one of the possible responses + // + // ****************************************************************** + // + case USE_POSSIBLE_RESPONSE: + + // use the stored MSS + CopyMemory(&Mss, &pModemInfo->mi_mssPossible, sizeof(MSS)); + + // setup up the ReadComm spoofing mechanism if it isn't already active + if (!pModemInfo->mi_pszStartReadSpoof) + { + pModemInfo->mi_pszStartReadSpoof = pModemInfo->mi_szResponse + pModemInfo->mi_dwPossibleResponseLen; + pModemInfo->mi_pszEndReadSpoof = pModemInfo->mi_szResponse + pModemInfo->mi_cbTotalResponse - 1; + } + else + { + MCXPRINTF("USE_POSSIBLE_RESPONSE while in Spoof mode!"); + } + + PrintString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID,pModemInfo->mi_szResponse, pModemInfo->mi_dwPossibleResponseLen, PS_RECV); + pModemInfo->mi_RcvState = GOOD_RESPONSE; + break; + + // ****************************************************************** + // + // We have a good modem response + // + // ****************************************************************** + // + case GOOD_RESPONSE: + + + PrintGoodResponse( + pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + Mss.bResponseState + ); + + // negotiated modem options... only allow compression and error correction results + pModemInfo->mi_dwNegotiatedModemOptions |= (Mss.bNegotiatedOptions & + (MDM_COMPRESSION | + MDM_ERROR_CONTROL | + MDM_CELLULAR)); + + // check for DCE and DTE info + if (Mss.dwNegotiatedDCERate) + pModemInfo->mi_dwNegotiatedDCERate = Mss.dwNegotiatedDCERate; + + if (Mss.dwNegotiatedDTERate) + pModemInfo->mi_dwNegotiatedDTERate = Mss.dwNegotiatedDTERate; + + // BUGBUG: Consolidate ReadNotifyClients + switch (Mss.bResponseState) + { + case RESPONSE_OK: // more commands + if (STATE_HANGING_UP_NON_CMD == pModemInfo->mi_ModemState) + { + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + return; + } + // fallthrough + + case RESPONSE_CONNECT: + pModemInfo->mi_dwCommandTryCount = 1; + dwResult = ModemWriteCommand(pModemInfo); + if (dwResult != MODEM_PENDING) + { + ReadNotifyClient(pModemInfo, dwResult); + } + + if (STATE_MONITORING == pModemInfo->mi_ModemState) { + // + // monitoring, wait for DSR changes + // + if (pModemInfo->mi_fModem) { + // + // only if we are a real modem + // + if (!CurrentlyWaitingForCommEvent(pModemInfo)) { + // + // and if we ain't already waiting, ie. more that on monitor command + // + ModemWaitEvent(pModemInfo, EV_DSR , 0); + } + } + } + +#ifdef VOICEVIEW + if (STATE_MONITORING == pModemInfo->mi_ModemState) + { + if (VVCLASS_80 == pModemInfo->VVInfo.wClass) + { + // modem is now in fclass+80, notify VxD ddi + MCXPRINTF("VVR_LINE_BACK"); + VVCallBackFunc( pModemInfo, VVR_LINE_BACK ); // tell VV CAN use port + } + + if (pModemInfo->VVInfo.hSemaphore) + { + // unblock the waiting command + MCXPRINTF("received OK - signaled semaphore"); + Signal_Semaphore( pModemInfo->VVInfo.hSemaphore ); + } + } +#endif // VOICEVIEW + return; + +#ifdef VOICEVIEW + case RESPONSE_VV_SSV: + // got a DATA VoiceView response from the modem + // call VoiceView ddi VxD and let him know + MCXPRINTF("VOICEVIEW DATA"); + VVCallBackFunc( pModemInfo, (WORD)(Mss.bResponseState - RESPONSE_VV_BASE) ); + return; + + case RESPONSE_VV_SMD: + case RESPONSE_VV_SFA: + case RESPONSE_VV_SRA: + case RESPONSE_VV_SRQ: + case RESPONSE_VV_SRC: + case RESPONSE_VV_STO: + case RESPONSE_VV_SVM: + // got a VoiceView response from the modem + // call VoiceView ddi VxD and let him know + MCXPRINTF("RESPONSE_VOICEVIEW"); + VVCallBackFunc( pModemInfo, (WORD)(Mss.bResponseState - RESPONSE_VV_BASE) ); + + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + return; +#endif // VOICEVIEW + + case RESPONSE_RING: + // try to resend the previous command if we aren't connecting or monitoring + if (!(pModemInfo->mi_ModemState == STATE_ANSWERING || + pModemInfo->mi_ModemState == STATE_ORIGINATING) && + pModemInfo->mi_pszzCmds) + { + if (STATE_MONITORING != pModemInfo->mi_ModemState) + { + // We got a RING while we were trying to do a command unrelated to + // monitoring. Retry the command... + MCXPRINTF("retrying last command due to unexpected RESPONSE_RING"); + pModemInfo->mi_pszCurCmd = pModemInfo->mi_pszPrevCmd; + } + + pModemInfo->mi_dwCommandTryCount = 1; + dwResult = ModemWriteCommand(pModemInfo); + if (dwResult != MODEM_PENDING) + { + ReadNotifyClient(pModemInfo, dwResult); + } + return; + } + // fall through (when we are doing a connection command of some type) + + case RESPONSE_LOOP: // more responses + pModemInfo->mi_RcvState = RESTART_READ; + break; + + case RESPONSE_BUSY: + ReadNotifyClient(pModemInfo, MODEM_BUSY); + return; + + case RESPONSE_NOCARRIER: + ReadNotifyClient(pModemInfo, MODEM_NOCARRIER); + return; + + case RESPONSE_NODIALTONE: + ReadNotifyClient(pModemInfo, MODEM_NODIALTONE); + return; + + case RESPONSE_NOANSWER: + ReadNotifyClient(pModemInfo, MODEM_NOANSWER); + return; + + case RESPONSE_ERROR: + // If we get an ERROR while HANGING_UP_NON_CMD, that is okay. + // During any other states, it is bad. + if (STATE_HANGING_UP_NON_CMD == pModemInfo->mi_ModemState) + { + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + } + else + { + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + } +#ifdef VOICEVIEW + if (STATE_MONITORING == pModemInfo->mi_ModemState) + { + if (VVCLASS_80 == pModemInfo->VVInfo.wClass) + { + // modem could not get into fclass+80, notify VxD ddi + MCXPRINTF("VVRS_NO_CLS80_SUPPORT"); + VVCallBackFunc( pModemInfo, VVRS_NO_CLS80_SUPPORT ); // tell VV CAN'T work + VVSetClass( pModemInfo, VVCLASS_0 ); // make sure we are in fclass=0 now + } + + if (pModemInfo->VVInfo.hSemaphore) + { + // unblock the waiting command + MCXPRINTF("Received ERROR - signaled semaphore"); + Signal_Semaphore( pModemInfo->VVInfo.hSemaphore ); + } + } +#endif // VOICEVIEW + return; + + default: + MCXPRINTF("hit a default!"); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } /* Switch on dwResponseState */ + break; + + // ****************************************************************** + // + // End of recieving response phase + // + // ****************************************************************** + // + case END_READ: + MCXPRINTF("had an extra callback caught by END_READ!"); + ASSERT(0); + return; + + // ****************************************************************** + case SET_TIMEOUT: + { + DWORD dwTimeOut; + + // set timeout based on current modem state + switch (pModemInfo->mi_ModemState) + { + case STATE_HANGING_UP_DTR: + // Enable a few events that we would like to hear about + // + dwTimeOut = TO_DTR_DROP * pModemInfo->mi_dwHangupTryCount; // wait longer on successive hangup tries + + switch (ModemWaitEvent(pModemInfo, EV_DSR | EV_RLSD, dwTimeOut)) + { + case MODEM_SUCCESS: + case MODEM_PENDING: + pModemInfo->mi_RcvState = POST_TIMEOUT; + break; + + default: + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + break; + } + break; + + default: + MCXPRINTF1("in state SET_TIMEOUT for a state that doesn't make sense (%d)", + pModemInfo->mi_ModemState); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + break; + } + + return; + } + + // ****************************************************************** + case POST_TIMEOUT: + + if (pModemInfo->mi_ModemState != STATE_HANGING_UP_DTR) + { + MCXPRINTF("hit POST_TIMEOUT when it shouldn't have."); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + } + else + { + MCXPRINTF("POST_TIMEOUT"); + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + } + return; + + // ****************************************************************** + default: + MCXPRINTF("hit a default in ReadCompletionRoutine2!"); + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + return; + } /* Switch on RcvState */ + } /* While */ +} + +//**************************************************************************** +// VOID HWDetectionRoutine(MODEMINFORMATION *) +// +// Function: Called when: +// EV_RLSD, EV_DSR, or EV_ERR during STATE_CONNECTED (non-passthrough) +// EV_ERR during STATE_CONNECTED (passthrough) +// EV_RLSD or EV_DSR during STATE_HANGING_UP_DTR +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +VOID WINAPI +HWDetectionRoutine( + MODEMINFORMATION * pModemInfo, + LPOVERNODE pNode + ) +{ + DWORD dwDummy; + BOOL fClearEventHandle = TRUE; + DWORD dwRet; + + + // are we listening for this event? + + dwRet=ModemWaitEventComplete( + pModemInfo, + pNode + ); + + + if (((dwRet) == MODEM_SUCCESS) || (dwRet == MODEM_PENDING)) { + + + switch (pModemInfo->mi_ModemState) + { + case STATE_HANGING_UP_DTR: + ReadCompletionRoutine2(pModemInfo); + + + break; + + case STATE_MONITORING: + + MCXPRINTF("DSR drop while monitoring, monitor fails"); + + CancelPendingIoAndPurgeCommBuffers(pModemInfo, TRUE); + + ReadNotifyClient(pModemInfo, MODEM_FAILURE); + + break; + + case STATE_WAIT_FOR_RLSD: + + MCXPRINTF("RLSD went high, completing connection."); + + ReadNotifyClient(pModemInfo, MODEM_SUCCESS); + + break; + + case STATE_CONNECTED: + + MCXPRINTF("reporting dropped line."); + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_REMOTEHANGUP); + + + ModemSetPassthrough(pModemInfo, MODEM_NOPASSTHROUGH); + + // purge only the transmit queue. We want to receive the 3 / NO CARRIER msg + PurgeComm(pModemInfo->mi_PortHandle, PURGE_TXCLEAR); + + if (pModemInfo->mi_fModem) + { + MCXPRINTF("State <- Remote dropped"); + pModemInfo->mi_ModemState = STATE_REMOTE_DROPPED; +#if 0 + // Initialize receive state machine + pModemInfo->mi_RcvState = START_READ; + ReadCompletionRoutine2(pModemInfo); + fClearEventHandle = FALSE; // Same reason as above. +#endif + } + else // we don't need to wait for a response from a null-modem + { + // Drop the DTR line to let the other side know you acknowledge + MCXPRINTF("dropping DTR to acknowledge remote hangup"); + EscapeCommFunction(pModemInfo->mi_PortHandle, CLRDTR); + pModemInfo->mi_ModemState = STATE_DISCONNECTED; + MCXPRINTF("State <- Disconnected"); + +#if 0 + // Set HIWORD to MDM_ID_NULL to indicate this was an unexpected message + // + ModemCallClient(pModemInfo, MODEM_HANGUP); // inform the app of the hangup +#endif + } + + if (NULL != pModemInfo->mi_DisconnectHandler) { + // + // the upper level code has register a disconnect hanlder + // + (*pModemInfo->mi_DisconnectHandler)( + pModemInfo->mi_DisconnectContext + ); + } + + + break; + + default: + MCXPRINTF("got a CN_EVENT when it didn't expect one!!! (bad)"); + break; + } + } + else + { + MCXPRINTF("HWDetectionRoutine called with an event it wasn't interested in."); + ASSERT(0); + } + + +} + +/****************************************************************************** + + @doc INTERNAL + + @api DWORD | CheckResponse | This function checks to see if the response is + an echo, and if it isn't it call MatchResponse(). + + @parm MODEMINFORMATION * | pModemInfo | Modem port handle + + @parm MSS * | pMss | ptr to a buffer to copy the Modem State Structure data + into. Valid on SUCCES return. + + @rdesc returns SUCCESS if there is 1 match and 0 partials. + Otherwise, a non-zero error code is returned: + + @flag ECHO if the response was an echo of the command + + @flag PARTIAL_RESPONSE if there no match and 1 or more partials. + + @flag UNRECOGNIZED_RESPONSE if there are no matches or partials. + + @flag POSSIBLE_RESPONSE if there is 1 match and 1 or more partials. + +*****************************************************************************/ + +DWORD CheckResponse(MODEMINFORMATION * pModemInfo, MSS *pMss) +{ + DWORD dwResult; + + ASSERT (pModemInfo->mi_cbTotalResponse <= sizeof(pModemInfo->mi_szResponse)); + + if ((dwResult = MatchResponse(pModemInfo, pMss)) == UNRECOGNIZED_RESPONSE) + { + // Is it an echo so far? + // + if (!Mystrncmp(pModemInfo->mi_szCmd, pModemInfo->mi_szResponse, + pModemInfo->mi_cbTotalResponse)) + { + // is it a complete echo? + // + if (pModemInfo->mi_cbCmd == pModemInfo->mi_cbTotalResponse) + { + dwResult = ECHO; + } + else + { + dwResult = PARTIAL_RESPONSE; + } + } + } + + return(dwResult); +} + +/****************************************************************************** + + @doc INTERNAL + + @api DWORD | MatchResponse | Scans the responses linked-list for a response + keyword that matches the response. + + @parm MODEMINFORMATION * | pModemInfo | The modem port handle. + + @parm MSS * | pMss | ptr to a buffer to copy the Modem State Structure data + into. Valid on SUCCESS return. + + @rdesc returns SUCCESS if there is 1 match and 0 partials. + Otherwise, a non-zero error code is returned: + + @flag PARTIAL_RESPONSE if there no match and 1 or more partials. + + @flag UNRECOGNIZED_RESPONSE if there are no matches or partials. + + @flag POSSIBLE_RESPONSE if there is 1 match and 1 or more partials. + +*****************************************************************************/ + +DWORD MatchResponse(MODEMINFORMATION * pModemInfo, MSS * pMss) +{ + PRESPONSE_NODE pRN = pModemInfo->mi_prnResponseHead; + DWORD dwMatch = 0; // match is defined as strings being equal up to the length of the reference string + // strcmpn(incoming, reference, incoming_len) == 0 && incoming_len == reference_len + DWORD dwPartials = 0; // partial is defined as strings being equal up to the length of the incoming string + // strcmpn(incoming, reference, incoming_len) == 0 && incoming_len != reference_len + DWORD dwResponseLength = pModemInfo->mi_cbTotalResponse; + LPSTR pszResponse = pModemInfo->mi_szResponse; + + while(pRN) + { + if (!strncmpi(pszResponse, pRN->szResponse, dwResponseLength)) + { + // match or partial? + if (dwResponseLength == (DWORD)(pRN->bLen + 1)) // add 1 (range = 1..256) + { + dwMatch = 1; + CopyMemory(pMss, &pRN->Mss, sizeof(MSS)); + } + else + { + dwPartials = 1; + } + } + pRN = pRN->pNext; + } + + switch ((dwMatch << 1) + dwPartials) + { + case 0: // 00 - nothing + return UNRECOGNIZED_RESPONSE; + + case 1: // 01 - partials + return PARTIAL_RESPONSE; + + case 2: // 10 - match + return SUCCESS; + + case 3: // 11 - match and partials + return POSSIBLE_RESPONSE; + + default: + MCXPRINTF("hit a default in MatchResponse!"); + return UNRECOGNIZED_RESPONSE; + } +} + +/****************************************************************************** + + @doc INTERNAL + + @api BOOL | ExpandMacros | Takes the string pszLine, and copies it to + lpszVal after expanding macros + + @parm LPSTR | pszRegResponse | ptr to response string from registry. + + @parm LPSTR | pszExpanded | ptr to buffer to copy string to w/ macros expanded + + @parm LPDWORD | pdwValLen | length of pszVal w/ expanded macros. + + @rdesc Returns FALSE if a needed macro translation could not be found in the + pMacroXlations table, TRUE otherwise. + +*****************************************************************************/ + +// BUGBUG: this should be fixed to allow a max length to be passed in +// +BOOL ExpandMacros(LPSTR pszRegResponse, + LPSTR pszExpanded, + LPDWORD pdwValLen, + MODEMMACRO * pMdmMacro, + DWORD cbMacros) +{ + LPSTR pszValue; + DWORD cbTmp; + BOOL bFound; + LPSTR pchTmp; + DWORD i; + + pszValue = pszExpanded; + + for ( ; *pszRegResponse; ) + { + // check for a macro + // + if ( *pszRegResponse == LMSCH ) + { + // + // + if (!strncmpi(pszRegResponse,CR_MACRO,CR_MACRO_LENGTH)) + { + *pszValue++ = CR; + pszRegResponse += CR_MACRO_LENGTH; + continue; + } + + // + // + if (!strncmpi(pszRegResponse,LF_MACRO,LF_MACRO_LENGTH)) + { + *pszValue++ = LF; + pszRegResponse += LF_MACRO_LENGTH; + continue; + } + + // + // + if ((pszRegResponse[1] == 'h' || pszRegResponse[1] == 'H') && + isxdigit(pszRegResponse[2]) && + isxdigit(pszRegResponse[3]) && + pszRegResponse[4] == RMSCH ) + { + *pszValue++ = (char) ((ctox(pszRegResponse[2]) << 4) + ctox(pszRegResponse[3])); + pszRegResponse += 5; + continue; + } + + // + // + if (pMdmMacro) + { + bFound = FALSE; + + // Check for a matching macro. + // + for (i = 0; i < cbMacros; i++) + { + cbTmp = lstrlenA(pMdmMacro[i].MacroName); + if (!strncmpi(pszRegResponse, pMdmMacro[i].MacroName, cbTmp)) + { + pchTmp = pMdmMacro[i].MacroValue; + while (*pchTmp) + { + *pszValue++ = *pchTmp++; + } + pszRegResponse += cbTmp; + bFound = TRUE; + break; + } + } + + // Did we get a match? + // + if (bFound) + { + continue; + } + } // + } // LMSCH + + // No matches, copy the character verbatim. + // + *pszValue++ = *pszRegResponse++; + } // for + + *pszValue = 0; + if (pdwValLen) + { + *pdwValLen = pszValue - pszExpanded; + } + + return TRUE; +} + +int Mystrncmp(char *dst, char *src, long count) +{ + while (count) { + if (*dst != *src) + return 1; + if (*src == 0) + return 0; + dst++; + src++; + count--; + } + return 0; +} + +int strncmpi(char *dst, char *src, long count) +{ + while (count) { + if (toupper(*dst) != toupper(*src)) + return 1; + if (*src == 0) + return 0; + dst++; + src++; + count--; + } + return 0; +} + + +LPSTR WINAPI +NewLoadRegCommands( + HKEY hKey, + LPSTR szRegCommand, + LPSTR pszzAppend + ) +{ + LPSTR pszzNew, pszStr; + ULONG ulAllocSize = 0; + HKEY hKeyCommand; + DWORD dwIndex; + char szValue[MAXUINTSTRLENGTH]; + DWORD dwType, dwSize; + DWORD dwRet; + + // open zee key + // + if (RegOpenKeyA(hKey, szRegCommand, &hKeyCommand) + != ERROR_SUCCESS) + { + DPRINTFA1("was unable to open the '%s' key in LoadRegCommands.", szRegCommand); + return NULL; + } + + // Calculate size of the registry command, including null-terminators for each command. + // + dwIndex = CMD_INDEX_START; + do + { + wsprintfA(szValue, "%d", dwIndex); + if ((dwRet = RegQueryValueExA(hKeyCommand, szValue, NULL, &dwType, NULL, + &dwSize)) == ERROR_SUCCESS) + { + if (dwType != REG_SZ) + { + DPRINTF("command wasn't REG_SZ in LoadRegCommands."); + pszzNew = NULL; + goto Exit; + } + ulAllocSize += dwSize; + } + dwIndex++; + } + while(dwRet == ERROR_SUCCESS); + + if (dwRet != ERROR_FILE_NOT_FOUND) + { + DPRINTF("RegQueryValueEx in LoadRegCommands failed for a reason besides ERROR_FILE_NOT_FOUND."); + pszzNew = NULL; + goto Exit; + } + + // ReAllocate or Allocate memory depending on whether we are appending... + // + if (pszzAppend) + { + ULONG ulAppendSize; + + if (!(ulAppendSize = LocalSize(pszzAppend))) + { + DPRINTF("failed to get the size of an append heap pointer in LoadRegCommands."); + pszzNew = NULL; + goto Exit; + } + + // ReAllocate + // + ulAllocSize += ulAppendSize; // double-null already accounted for + //pszzNew = (LPSTR)LocalReAlloc(pszzAppend, ulAllocSize, LMEM_ZEROINIT); + if (pszzNew = (LPSTR)LocalAlloc(LMEM_ZEROINIT, ulAllocSize)) + { + CopyMemory(pszzNew, pszzAppend, ulAppendSize); + }; + } + else + { + // Allocate + // + ulAllocSize++; // double-null terminator accounting + pszzNew = (LPSTR)LocalAlloc(LPTR, ulAllocSize); + } + + // Check errors for either the Alloc or ReAlloc + if (!pszzNew) + { + DPRINTF1("had a failure doing an alloc or a realloc in LoadRegCommands. Heap size %d", + ulAllocSize); + goto Exit; // pszzNew already NULL + } + + // Set pszStr to point to the next location to load. + pszStr = pszzNew; + while (*pszStr) // move to next open slot in buffer if need be (append only) + { + pszStr += lstrlenA(pszStr) + 1; + } + + // Did we go to far? + // + ASSERT ((ULONG)(pszStr - pszzNew) < ulAllocSize); + + // Read in and add strings to the (rest of the) buffer. + // + dwIndex = CMD_INDEX_START; + dwSize = ulAllocSize - (pszStr - pszzNew); + do + { + wsprintfA(szValue, "%d", dwIndex); + if ((dwRet = RegQueryValueExA(hKeyCommand, szValue, + NULL, NULL, (VOID *)pszStr, &dwSize)) + == ERROR_SUCCESS) + { + pszStr += dwSize; // includes terminating null + } + dwIndex++; + dwSize = ulAllocSize - (pszStr - pszzNew); + } + while (dwRet == ERROR_SUCCESS); + + if (dwRet != ERROR_FILE_NOT_FOUND) + { + DPRINTF("2nd RegQueryValueEx in LoadRegCommands failed for a reason besides ERROR_FILE_NOT_FOUND."); + LocalFree(pszzNew); + pszzNew = NULL; + goto Exit; + } + + // Did we go to far? + // + ASSERT ((ULONG)(pszStr - pszzNew) < ulAllocSize); + + // no need to put in the final double-null null, size this buffer was already zerod. + +Exit: + RegCloseKey(hKeyCommand); + return pszzNew; +} + + +//**************************************************************************** +// LPSTR LoadRegCommands(MODEMINFORMATION *pModemInfo, +// LPSTR szRegCommand, LPSTR pszzAppend) +// +// Function: Loads a registry command into memory. Memory is allocated if +// pszzAppend is NULL. Memory is re-allocated/enlarged if +// pszzAppend is not NULL. In this case, the registry command +// will be appended to the existing buffer. +// +// Returns: NULL on failure. +// A doubly-null terminated buffer of singly-null terminated strings +// on success. +//**************************************************************************** + +LPSTR LoadRegCommands(MODEMINFORMATION *pModemInfo, + LPSTR szRegCommand, + LPSTR pszzAppend) +{ + + return NewLoadRegCommands( + pModemInfo->mi_hKeyModem, + szRegCommand, + pszzAppend + ); + +} + +char szBlindOn[] = "Blind_On"; // explicit for stack memory optimizations below +char szBlindOff[] = "Blind_Off"; // explicit for stack memory optimizations below + +//**************************************************************************** +// LPSTR CreateDialCommands(MODEMINFORMATION *pModemInfo, LPSTR szPhoneNumber, +// BOOL *fOriginate) +// +// Function: Create the dial strings in memory ala: +// " " +// ... more dial strings for long phone numbers... +// "" <- final null of a doubly null terminated list +// +// if no dial prefix, then return NULL +// if no dial suffix, then don't do any commands after the first dial command +// +// Set fOriginate to TRUE if these dial strings will cause a connection origination. +// FALSE otherwise. +// +// break lines longer then HAYES_COMMAND_LENGTH +// +// WARNING - this function is reall cheesy and hacked. The main reason for this +// is that it attempts to be memory (read: stack) optimized. +// +// szPhoneNumber is a null terminated string of digits (0-9, $, @, W), with a possible +// ';' at the end. The semicolon can only be at the end. +// +// Examples: +// +// "" -> originate -> ATX_DT fOriginate = TRUE +// ";" -> dialtone detection -> ATX_DT; fOriginate = FALSE +// "5551212" -> dial and originate -> ATX_DT5551212 fOriginate = TRUE +// "5551212;" -> dial -> ATX_DT5551212; fOriginate = FALSE +// "123456789012345678901234567890123456789012345678901234567890" +// -> dial and originate -> ATX_DT12345678901234567890123456789012; +// ATX_DT3456789012345678901234567890 +// fOriginate = TRUE +// "123456789012345678901234567890123456789012345678901234567890;" +// -> dial -> ATX_DT12345678901234567890123456789012; +// ATX_DT3456789012345678901234567890; +// fOriginate = FALSE +// +// Returns: NULL on failure. +// A null terminated buffer of the dial command on success. +//**************************************************************************** + +LPSTR +CreateDialCommands( + MODEMINFORMATION *pModemInfo, + LPSTR szPhoneNumber, + BOOL *fOriginate, + DWORD DialOptions + ) +{ +// HKEY hSettingsKey; + DWORD dwSize; + DWORD dwType; + LPSTR pszTemp; + LPSTR pszDialPrefix; // ex. "ATX4DT" or "ATX3DT" + LPSTR pszDialSuffix; // ex. ";" + LPSTR pszOrigSuffix; // ex. "" + LPSTR pchDest, pchSrc; + LPSTR pszzDialCommands = NULL; + CHAR pszShortTemp[2]; +#ifdef DEBUG + static char szDialPrefix[] = "DialPrefix"; + static char szDialSuffix[] = "DialSuffix"; + static char szTone[] = "Tone"; + static char szPulse[] = "Pulse"; +#endif + DWORD Length; + + BOOL fHaveDialSuffix=TRUE; + + // Figure out fOriginate + pchSrc = szPhoneNumber; + *fOriginate = TRUE; + while (*pchSrc) + { + if (';' == *pchSrc) + { + // make sure the string is correctly formed. + // + ASSERT(pchSrc[1] == '\0'); + + *fOriginate = FALSE; + } + pchSrc++; + } + + // Trim the semicolon off the end, now that we know this is not an origination string. + if (!(*fOriginate)) + { + ASSERT(pchSrc[-1] == ';'); + pchSrc[-1] = 0; + } + + // At this point, szPhoneNumber is just a string of digits to be dialed, with no semicolon at + // the end. Plus we know whether to originate or not. + + // make some temp space + + pszTemp = (LPSTR)LocalAlloc(LPTR, + HAYES_COMMAND_LENGTH + 1 + // pszTemp + HAYES_COMMAND_LENGTH + 1 + // pszDialPrefix + HAYES_COMMAND_LENGTH + 1 + // pszDialSuffix + HAYES_COMMAND_LENGTH + 1); // pszOrigSuffix + if (!pszTemp) + { + MCXPRINTF("out of memory."); + return NULL; + } + pszDialPrefix = pszTemp + HAYES_COMMAND_LENGTH + 1; + pszDialSuffix = pszDialPrefix + HAYES_COMMAND_LENGTH + 1; + pszOrigSuffix = pszDialSuffix + HAYES_COMMAND_LENGTH + 1; + + + lstrcpyA(pszDialPrefix,""); + // + // read in prefix + // + GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszDialPrefix, + HAYES_COMMAND_LENGTH, + COMMON_DIAL_COMMOND_PREFIX + ); + + + // + // do we support blind dialing and do we need to set the blind dialing state? + // + if ((MDM_BLIND_DIAL & pModemInfo->mi_dwModemOptionsCap) + && + ((DialOptions & MDM_BLIND_DIAL) != (pModemInfo->mi_dwPreferredModemOptions & MDM_BLIND_DIAL))) { + + // + // read in blind options + // + Length=GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszDialPrefix+lstrlenA(pszDialPrefix), + HAYES_COMMAND_LENGTH, + DialOptions & MDM_BLIND_DIAL ? COMMON_DIAL_BLIND_ON : COMMON_DIAL_BLIND_OFF + ); + + if (Length == 0) { + MCXPRINTF1("RegQueryValueEx failed when opening %s.", + DialOptions & MDM_BLIND_DIAL ? szBlindOn : szBlindOff); + goto Failure; + } + + + } + + + // read in dial prefix + + Length=GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszDialPrefix+lstrlenA(pszDialPrefix), + HAYES_COMMAND_LENGTH, + COMMON_DIAL_PREFIX + ); + + if (Length == 0) { + MCXPRINTF1("'%s' wasn't REG_SZ.", szDialPrefix); + goto Failure; + } + + + // can we do tone or pulse dialing? + if (MDM_TONE_DIAL & pModemInfo->mi_dwModemOptionsCap) + { + // + // read in dial mode (tone or pulse) + // + Length=GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszDialPrefix+lstrlenA(pszDialPrefix), + HAYES_COMMAND_LENGTH, + DialOptions & MDM_TONE_DIAL ? COMMON_DIAL_TONE : COMMON_DIAL_PULSE + ); + + if (Length == 0) { + MCXPRINTF1("'%s' wasn't REG_SZ.", + DialOptions & MDM_TONE_DIAL ? szTone : szPulse); + goto Failure; + } + + + } + + // + // read in dial suffix + // + Length=GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszDialSuffix, + HAYES_COMMAND_LENGTH, + COMMON_DIAL_SUFFIX + ); + + if (Length <= 1) { + + MCXPRINTF1("RegQueryValueEx failed when opening %s.", szDialSuffix); + lstrcpyA(pszDialSuffix, ""); + fHaveDialSuffix = FALSE; + + } + + // + // read in prefix terminator + // + Length=GetCommonDialComponent( + pModemInfo->mi_hCommon, + pszOrigSuffix, + HAYES_COMMAND_LENGTH, + COMMON_DIAL_TERMINATION + ); + + if (Length != 0) { + + lstrcatA(pszDialSuffix, pszOrigSuffix); + ASSERT(lstrlenA(pszOrigSuffix) <= lstrlenA(pszDialSuffix)); + } + + + ASSERT ((lstrlenA(pszDialPrefix) + lstrlenA(pszDialSuffix)) <= HAYES_COMMAND_LENGTH); + + // allocate space for the phone number lines + { + DWORD dwBytesAlreadyTaken = lstrlenA(pszDialPrefix) + lstrlenA(pszDialSuffix); + DWORD dwAvailBytesPerLine = (HAYES_COMMAND_LENGTH - dwBytesAlreadyTaken); + DWORD dwPhoneNumLen = lstrlenA(szPhoneNumber); + DWORD dwNumLines = dwPhoneNumLen ? (dwPhoneNumLen / dwAvailBytesPerLine + + (dwPhoneNumLen % dwAvailBytesPerLine ? 1 : 0)) + : 1; // handle null string + dwSize = dwPhoneNumLen + dwNumLines * (dwBytesAlreadyTaken + 1) + 1; + } + + MCXPRINTF1("HeapAllocate %d bytes for Dial Commands.", dwSize); + if (!(pszzDialCommands = (LPSTR)LocalAlloc(LPTR, dwSize))) + { + MCXPRINTF("ran out of memory and failed a HeapAllocate!"); + goto Failure; + } + + pchDest = pszzDialCommands; // point to the beginning of the commands + + // build dial line(s): + // do we have a dial suffix + if (!fHaveDialSuffix) + { + // we can't do much except just use the whole string and pray... + // but, can we fit the dial string? + ASSERT (lstrlenA(pszDialPrefix) + lstrlenA(szPhoneNumber) + + lstrlenA(pszDialSuffix) <= HAYES_COMMAND_LENGTH); + + // did we not want to originate? + ASSERT(*fOriginate); + + // build it + lstrcpyA(pchDest, pszDialPrefix); + lstrcatA(pchDest, szPhoneNumber); + lstrcatA(pchDest, pszDialSuffix); + } + else + { + // we have a dial suffix. + + // populate new pszzDialCommands with semi-colons as necessary. + + // go through and add suffixi, making sure lines don't exceed HAYES_COMMAND_LENGTH + pchSrc = szPhoneNumber; // moves a character at a time. + pszShortTemp[1] = 0; + + // prime the pump + lstrcpyA(pchDest, pszDialPrefix); + + // step through the source + while (*pchSrc) + { + if (lstrlenA(pchDest) + lstrlenA(pszDialSuffix) + 1 > HAYES_COMMAND_LENGTH) + { + // finish up this string + lstrcatA(pchDest, pszDialSuffix); + + // begin a new string + pchDest += lstrlenA(pchDest) + 1; + lstrcpyA(pchDest, pszDialPrefix); + } + else + { + // copy char + pszShortTemp[0] = *pchSrc; + lstrcatA(pchDest, pszShortTemp); + pchSrc++; + } + } + + // conclude with the approprate Suffix. + lstrcatA(pchDest, (*fOriginate ? pszOrigSuffix : pszDialSuffix)); + } + + // close keys +Exit: +// RegCloseKey(hSettingsKey); + LocalFree(pszTemp); + return pszzDialCommands; + +Failure: + if (pszzDialCommands) + { + LocalFree(pszzDialCommands); + pszzDialCommands = NULL; + } + goto Exit; +} + + +//**************************************************************************** +// DWORD HandleCommErrors(MODEMINFORMATION *pModemInfo, ULONG ulError) +// +// Function: Calls ClearCommError and returns the error. +// +// ulError is passed in if the error(s) are already known and +// ClearCommError doesn't need to be called. +// If ulError is NULL then ClearCommError is called. +//**************************************************************************** + +DWORD HandleCommErrors(MODEMINFORMATION *pModemInfo, ULONG ulError) +{ + if (!ulError) + { + // failed to read or write due to a possible communication error + // determine if this was actually an error, or just no chars (in the read case) + if (!ClearCommError(pModemInfo->mi_PortHandle, &ulError, NULL)) + { + // ClearCommError failed + MCXPRINTF("ClearCommError error"); + return 0; + } + } + +#ifdef DEBUG + if (ulError) + { + if (ulError & CE_BREAK) + {MCXPRINTF("CE_BREAK");} + if (ulError & CE_DNS) + {MCXPRINTF("CE_DNS");} + if (ulError & CE_MODE) + {MCXPRINTF("CE_MODE");} + if (ulError & CE_OOP) + {MCXPRINTF("CE_OOP");} + if (ulError & CE_PTO) + {MCXPRINTF("CE_PTO");} + if (ulError & CE_TXFULL) + {MCXPRINTF("CE_TXFULL");} + if (ulError & CE_FRAME) + {MCXPRINTF("CE_FRAME");} + if (ulError & CE_IOE) + {MCXPRINTF("CE_IOE");} + if (ulError & CE_OVERRUN) + {MCXPRINTF("CE_OVERRUN");} + if (ulError & CE_RXOVER) + {MCXPRINTF("CE_RXOVER");} + if (ulError & CE_RXPARITY) + {MCXPRINTF("CE_RXPARITY");} + } + //else + //{ + // MCXPRINTF("tried to read, but nothing was there."); + //} +#endif // DEBUG + + return ulError; +} + + +// SynchrnonizeCommConfigSettings +// +// Do a GetCommConfig from modem.sys and update our settings info. +// Check to see if we need to set fSettingsInitStringsBuilt to FALSE. +// If flagged, write down our Negotiated stuff to modem.sys using +// SetCommConfig. +// +VOID SynchronizeCommConfigSettings(MODEMINFORMATION * pModemInfo, + BOOL fUpdateModemSys) +{ +#define COMMCONFIG_AND_MODEMSETTINGS_LEN (60*2) + + BYTE byteTmp[COMMCONFIG_AND_MODEMSETTINGS_LEN]; + LPCOMMCONFIG lpCC = (LPCOMMCONFIG)byteTmp; + DWORD dwSize = sizeof(byteTmp); + + ASSERT(sizeof(byteTmp) >= + sizeof(COMMCONFIG) + sizeof(MODEMSETTINGS)); + + if (GetCommConfig(pModemInfo->mi_PortHandle, + lpCC, + &dwSize) == TRUE) + { + LPMODEMSETTINGS lpMS; + + lpMS = (LPMODEMSETTINGS)((LPBYTE)lpCC + + lpCC->dwProviderOffset); + + MCXSetModemSettings( + pModemInfo, + lpMS + ); + +#if 0 + // Need to rebuild init string? + // + if (pModemInfo->mi_dwCallSetupFailTimerSetting != lpMS->dwCallSetupFailTimer + || pModemInfo->mi_dwInactivityTimeoutSetting != lpMS->dwInactivityTimeout + || pModemInfo->mi_dwSpeakerVolumeSetting != lpMS->dwSpeakerVolume + || pModemInfo->mi_dwSpeakerModeSetting != lpMS->dwSpeakerMode + || pModemInfo->mi_dwPreferredModemOptions != lpMS->dwPreferredModemOptions) + { + pModemInfo->mi_fSettingsInitStringsBuilt = FALSE; + } + + pModemInfo->mi_dwCallSetupFailTimerSetting = + lpMS->dwCallSetupFailTimer; + + pModemInfo->mi_dwInactivityTimeoutSetting = + lpMS->dwInactivityTimeout; + + pModemInfo->mi_dwSpeakerVolumeSetting = + lpMS->dwSpeakerVolume; + + pModemInfo->mi_dwSpeakerModeSetting = + lpMS->dwSpeakerMode; + + pModemInfo->mi_dwPreferredModemOptions = + lpMS->dwPreferredModemOptions; +#endif + + + if (fUpdateModemSys) + { + lpMS->dwNegotiatedModemOptions = + pModemInfo->mi_dwNegotiatedModemOptions; + + lpMS->dwNegotiatedDCERate = + pModemInfo->mi_dwNegotiatedDCERate; + + if (SetCommConfig(pModemInfo->mi_PortHandle, + lpCC, + sizeof(byteTmp)) != TRUE) + { + MCXPRINTF1("SetCommConfig() failed and returned %d", + GetLastError()); + ASSERT(0); + } + } + } + else + { + MCXPRINTF1("GetCommConfig() failed and returned %d", + GetLastError()); + ASSERT(0); + } +} + +void WINAPI +PrintGoodResponse( + HANDLE hLogFile, + DWORD dwID, + DWORD ResponseState + ) + +{ + + char Response[128]; + char ResponseType[128]; + DWORD StringID; + INT StringLength; + + +#ifndef DEBUG + if (!hLogFile && !TRACINGENABLED()) return; +#endif // !DEBUG + + StringID=(ResponseState >= RESPONSE_START || ResponseState <= RESPONSE_END) + ? (IDS_RESP_OK + ResponseState) : IDS_RESP_UNKNOWN; + + + StringLength=LoadStringA( + ghInstance, + IDS_MSGLOG_RESPONSE, + Response, + sizeof(Response) + ); + + if (StringLength == 0) { + + return; + } + + StringLength=LoadStringA( + ghInstance, + StringID, + ResponseType, + sizeof(ResponseType) + ); + + if (StringLength == 0) { + + return; + } + + LogPrintf( + hLogFile, + dwID, + Response, + ResponseType + ); + + + D_TRACE(McxDpf(dwID,Response,ResponseType);) + + D_TRACE(McxDpf(dwID,"Good Response");) + +} + +//**************************************************************************** +// PrintString +// dwOption: +// PS_SEND - Send prefix used +// PS_SEND_SECURE - Send prefix used and numbers replaced with #s +// PS_RECV - Recv prefix used +// Send the response string to VxDWin and Log +// We only care about seeing 50 chars under RETAIL, +// and MAXSTRINGLENGTH * MAX_DBG_CHARS_PER_BIN_CHAR under DEBUG +// BUGBUG - any number chars on a dialing line will be changed to #. +// BUGBUG - this includes X3 -> X#. The extra code to handle this isn't +// BUGBUG - worth it. +//**************************************************************************** + +#define MAX_DBG_CHARS_PER_BIN_CHAR 4 +#ifdef DEBUG +#define RAWRESPONSELEN 100 +#else +#define RAWRESPONSELEN 50 // good number for remaining chars on a line after the time stamp +#endif + +void WINAPI +PrintString( + HANDLE hLogFile, + DWORD dwID, + char *pchStr, + DWORD dwLength, + DWORD dwOption + ) +{ + char temp[RAWRESPONSELEN + 1]; + char *src,*dest; + static const char szHex[] = "0123456789abcdef"; + int i; + +#ifndef DEBUG + if (!hLogFile && !TRACINGENABLED()) return; +#endif // !DEBUG + + i = dwLength; + src = pchStr; + dest = temp; + + while (i-- && (dest - temp < RAWRESPONSELEN - MAX_DBG_CHARS_PER_BIN_CHAR)) + { + // ascii printable chars are between 0x20 and 0x7e, inclusive + if (*src >= 0x20 && *src <= 0x7e) + { +#ifdef DEBUG // only blank out digits under RETAIL + *dest++ = *src; +#else // DEBUG + // printable text + if (PS_SEND_SECURE == dwOption && isdigit(*src)) + { + *dest++ = '#'; + } + else + { + *dest++ = *src; + } +#endif // DEBUG + } + else + { + // binary + switch (*src) + { + case CR: + *dest++ = '<'; *dest++ = 'c'; *dest++ = 'r'; *dest++ = '>'; + break; + case LF: + *dest++ = '<'; *dest++ = 'l'; *dest++ = 'f'; *dest++ = '>'; + break; + default: + *dest++ = '<'; + *dest++ = szHex[(*src>>4) & 0xf]; + *dest++ = szHex[*src & 0xf]; + *dest++ = '>'; + } + } + src++; + } + *dest = 0; + + switch (dwOption) + { + case PS_SEND: + case PS_SEND_SECURE: + + LogString(hLogFile,dwID, IDS_MSGLOG_COMMAND, temp); + D_TRACE(McxDpf(dwID, "Send: %s\r\n", temp);) + + break; + + case PS_RECV: + { + + char Response[128]; + char EmptyResponse[128]; + INT StringLength; + + + + StringLength=LoadStringA( + ghInstance, + IDS_MSGLOG_RAWRESPONSE, + Response, + sizeof(Response) + ); + + if (StringLength == 0) { + + return; + } + + StringLength=LoadStringA( + ghInstance, + IDS_MSGLOG_EMPTYRESPONSE, + EmptyResponse, + sizeof(EmptyResponse) + ); + + if (StringLength == 0) { + + return; + } + + LogPrintf( + hLogFile, + dwID, + Response, + dwLength ? temp : EmptyResponse + ); + + + + D_TRACE(McxDpf(dwID,Response, + dwLength ? temp : EmptyResponse);) + } + + break; + } + +} + +//**************************************************************************** +// void PrintCommSettings(DCB * pDcb) +// +// Function: Dumps a portion of the Ring0 DCB. +//**************************************************************************** + +void WINAPI +PrintCommSettings( + HANDLE hLogFile, + DWORD dwID, + DCB * pDcb + ) +{ + static const char achParity[] = "NOEMS"; + static const char *aszStopBits[] = { "1", + "1.5", + "2" }; + +#ifndef DEBUG + if (!hLogFile && !TRACINGENABLED()) return; +#endif // !DEBUG + + LogPrintf( + hLogFile, + dwID, + "%d,%c,%d,%s\r\n", + pDcb->BaudRate, + achParity[pDcb->Parity], + pDcb->ByteSize, + aszStopBits[pDcb->StopBits] + ); + + D_TRACE(McxDpf(dwID, + "%d,%c,%d,%s, ctsfl=%d, rtsctl=%d", + pDcb->BaudRate, + achParity[pDcb->Parity], + pDcb->ByteSize, + aszStopBits[pDcb->StopBits], + pDcb->fOutxCtsFlow, + pDcb->fRtsControl + );) +} + + +//**************************************************************************** +// void CancelPendingIOAndPurgeCommBuffers(PMODEMINFORMATION pModemInfo) +// +// Function: Sets CommMask to 0, waits for any I/O to complete and purges +// buffers. +//**************************************************************************** + +void WINAPI +CancelPendingIoAndPurgeCommBuffers( + PMODEMINFORMATION pModemInfo, + BOOL Purge + ) +{ + // Set these, even if there isn't some I/O currently going on. We want to + // make sure the recv and xmit buffers are empty, plus it doesn't hurt to + // have the mask set to 0. + // +#ifdef DEBUG + if (Purge) { + + MCXPRINTF("CancelPendingIOAndPurgeBuffers: purging"); + + } else { + + MCXPRINTF("CancelPendingIOAndPurgeBuffers"); + } +#endif + + SetCommMask(pModemInfo->mi_PortHandle, 0); + PurgeComm(pModemInfo->mi_PortHandle, PURGE_TXABORT | PURGE_RXABORT | + (Purge ? (PURGE_TXCLEAR | PURGE_RXCLEAR) : 0)); + + if (pModemInfo->mi_timeout) + { + MCXPRINTF("CancelPendingIOAndPurgeBuffers: killing timer"); + pModemInfo->mi_timeout = 0; + if (KillMdmTimer(pModemInfo->mi_dwCompletionKey, + (LPOVERLAPPED)pModemInfo->mi_lpOverlappedEvent) == TRUE) + { + OverPoolFree((LPOVERLAPPED)pModemInfo->mi_lpOverlappedEvent); + } + } + + + pModemInfo->mi_lpOverlappedRW=NULL; + pModemInfo->mi_lpOverlappedEvent=NULL; + // + // mark this io as old, so it will be ignored. + // + pModemInfo->mi_dwRWIOExpected++; + pModemInfo->mi_dwEventIOExpected++; + + pModemInfo->mi_dwDeferedExpected++; +} + + +#ifdef VOICEVIEW +/****************************************************************************** + + @doc INTERNAL + + @api void | VVEscapeFunc | This function handles requests + from the VoiceView DDI + + @parm MODEMINFORMATION * | hPort | port handle of modem + + @parm long | function | escape code + + @parm long | Indata | Optional data (escape function specific) + + @rdesc Returns VVR_??? return results. + + Escape functions and parameters: + VVF_OPEN init - pass in callback function pointer + VVF_CLOSE your done, bye... + VVF_MONITOR swithc to fclass 80 + VVF_UNMONITOR fclass 0 + VVF_TAKEOVER using the port + VVF_RELEASE no longer using + + This function is called from the VoiceView DDI VxD. This is called through + the VCOMM modem escape function and we hook/look for any of these functions + + This whole mess is so that we can put the modem into fclass 80 (voiceview) + and look for VV responses from the modem while no one is using it + +*****************************************************************************/ +int _cdecl VVEscapeFunc(MODEMINFORMATION *hPort, long lFunction, long lIndata) +{ + APIINFO apiInfo; + VMMHKEY hKeyCommand; + int nResult = VVS_SUCCESS; + + MCXPRINTF("VVEscapeFunc"); + + if ( hPort == NULL ) // verify hPort + return( VVS_INVALID_FUNC ); // should try to catch others also + + switch ( lFunction ) + { + case VVF_OPEN: + MCXPRINTF("VVF_OPEN:"); + // init all VoiceView info for this port + //-------------------------------------- + if ( _RegOpenKeyA( hPort->mi_hKeyModem, szMonitorVVon, &hKeyCommand ) != ERROR_SUCCESS ) + nResult = VVS_INVALID_PARM; // invalid port passed in, doesn't support VV + else if ( hPort->VVInfo.wState != VVSTATE_NONE ) + nResult = VVS_BAD_STATE; + else if ( lIndata == NULL ) + nResult = VVS_INVALID_PARM; // invalid func pointer + else + { + // set the state and the VV call back function pointer + hPort->VVInfo.wState = VVSTATE_INIT; + (DWORD)hPort->VVInfo.fpNotifyProc = (DWORD)lIndata; + } // end if + break; + + case VVF_CLOSE: + MCXPRINTF("VVF_CLOSE:"); + // shut down all the VoiceView stuff on this port + //----------------------------------------------- + if ( hPort->VVInfo.wState != VVSTATE_INIT ) + nResult = VVS_BAD_STATE; + else + { + // re-init to default values + hPort->VVInfo.wState = VVSTATE_NONE; + hPort->VVInfo.wClass = VVCLASS_0; + hPort->VVInfo.dwCallBackRef = NULL; + hPort->VVInfo.fpNotifyProc = NULL; + } // end if + break; + + case VVF_MONITOR: + MCXPRINTF("VVF_MONITOR:"); + // start monitoring VoiceView activity, switch to FCLASS+80 + //--------------------------------------------------------- + if ( hPort->VVInfo.wState != VVSTATE_INIT ) + nResult = VVS_BAD_STATE; + else + { + hPort->VVInfo.wState = VVSTATE_MONITOR; + hPort->VVInfo.dwCallBackRef = lIndata; + VVSetClass( hPort, VVCLASS_80 ); + } // end if + break; + + case VVF_UNMONITOR: + MCXPRINTF("VVF_UNMONITOR:"); + // end monitoring VoiceView, switch to FCLASS+0 + //--------------------------------------------- + if ( hPort->VVInfo.wState != VVSTATE_MONITOR ) + nResult = VVS_BAD_STATE; + else + { + hPort->VVInfo.wState = VVSTATE_INIT; + VVSetClass( hPort, VVCLASS_0 ); + } // end if + break; + + case VVF_TAKEOVER: + MCXPRINTF("VVF_TAKEOVER:"); + // VoiceView is going to use the port + //----------------------------------- + if ( hPort->VVInfo.wState != VVSTATE_MONITOR ) + nResult = VVS_BAD_STATE; + else if ( hPort->VVInfo.wClass != VVCLASS_80 ) + nResult = VVS_BUSY; // not in VV mode + else + { + // setup dummy struct to call existing function + apiInfo.hPort = hPort; // set the port + apiInfo.lParam = TRUE; // turn ON takeover + apiInfo.hWnd = NULL; // dummy arg + apiInfo.msg = NULL; // dummy arg + apiInfo.szData[0] = NULL; // dummy arg + + MCXSetPassthrough( &apiInfo ); + } // end if + break; + + case VVF_RELEASE: + MCXPRINTF("VVF_RELEASE:"); + // VoiceView is done with the port + //-------------------------------- + if ((hPort->VVInfo.wState != VVSTATE_MONITOR) || (hPort->VVInfo.wClass != VVCLASS_80)) + nResult = VVS_BAD_STATE; + else + { + // setup dummy struct to call existing function + apiInfo.hPort = hPort; // set the port + apiInfo.lParam = FALSE; // turn OFF takeover + apiInfo.hWnd = NULL; // dummy arg + apiInfo.msg = NULL; // dummy arg + apiInfo.szData[0] = NULL; // dummy arg + + MCXSetPassthrough( &apiInfo ); + + // reset the modem to monitor! + hPort->mi_ModemState = STATE_MONITORING; + + ReadNotifyClient(hPort, MODEM_SUCCESS); + } // end if + break; + + default: + MCXPRINTF("VVS_INVALID_FUNC:"); + // this is an invalid escape + //-------------------------- + nResult = VVS_INVALID_FUNC; + } // end switch + + return( nResult ); +} // end VVEscapeFunc + + + +/****************************************************************************** + + @doc INTERNAL + + @api void | VVCallBackFunc | This function will call the VoiceView + DDI callback routine + + @parm MODEMINFORMATION * | hPort | port handle of modem + + @parm long | function | escape code + + @rdesc Returns TRUE if successful, FALSE otherwise. + + async events to notify about: + VVR_SSV VoiceView Data Mode Start Sequence Event + VVR_SMD Modem Data Mode Start Sequence Event + VVR_SFA Facisimile Data Mode Start Sequence Event + VVR_SRA Receive ADSI Response Event + VVR_SRQ Receive Capabilities Query Event + VVR_SRC Receive Capabilities Information Event + VVR_STO Talk-off Event (VoiceView start tone w/o a de indicator) + VVR_SVM VoiceView Message Available + + VVR_LINE_GONE call has been ended + VVR_LINE_BACK call is back... + + VVRS_NO_CLS80_SUPPORT can't get into fclass80 + + When the VxD sees some of these, he will probably take over the port + and read or write some stuff, or he will decide to go away + +*****************************************************************************/ +int VVCallBackFunc(MODEMINFORMATION *hPort, WORD wFunction) +{ + int nResult; + + MCXPRINTF("VVCallBackFunc"); + + if ((hPort == NULL) || // verify hPort + ((wFunction < VVR_FIRST) || (wFunction > VVR_LAST))) // verify func + return( FALSE ); + + // go and call the VoiceView VxD + //------------------------------ + nResult = (*hPort->VVInfo.fpNotifyProc)( hPort, hPort->VVInfo.dwCallBackRef, wFunction ); + + return( nResult ); +} // end VVCallBackFunc + + +/****************************************************************************** + + @doc INTERNAL + + @api void | VVSetClass | This function will set the modem into the correct + fclass + + @parm MODEMINFORMATION * | hPort | port handle of modem + + @parm long | wClass | class to be set + + @rdesc Returns TRUE if successful, FALSE otherwise. + + We are going to put the modem into either fclass 80 (for VoiceView) or + going to put it into fclass 0 for normal stuff. The modem will spend + most if it's time in fclass80 waiting for VV stuff, but if anyone else + wants to use it, we put it back into fclass0 + +*****************************************************************************/ +int VVSetClass(MODEMINFORMATION *hPort, WORD wClass) +{ + int nResult; + APIINFO apiInfo; + + if ((hPort == NULL) || // verify hPort + ((hPort->VVInfo.wState != VVSTATE_INIT) && // verify state + (hPort->VVInfo.wState != VVSTATE_MONITOR)) || + ((wClass != VVCLASS_0) && (wClass != VVCLASS_80))) // verify param + return( FALSE ); + + if ( hPort->VVInfo.wClass == wClass ) + return( TRUE ); // redundent call - ignore + + // setup the voiceview states correctly + //------------------------------------- + hPort->VVInfo.wClass = wClass; + + if ( hPort->mi_ModemState != STATE_MONITORING ) + return( TRUE ); // we are in a invalid state, don't switch modem + + // setup dummy struct and call the Monitor function + //------------------------------------------------- + apiInfo.hPort = hPort; // set the port + apiInfo.lParam = FALSE; // turn OFF takeover + apiInfo.hWnd = NULL; // dummy arg + apiInfo.msg = NULL; // dummy arg + + // set the continuous monitoring state + if ( wClass == VVCLASS_80 ) + { + hPort->mi_fContinuousMonitoring = TRUE; + hPort->VVInfo.fContinuousMonitoring = hPort->mi_fContinuousMonitoring; + } + else // VVCLASS_0 + { + // restore old continuous monitoring state + hPort->mi_fContinuousMonitoring = hPort->VVInfo.fContinuousMonitoring; + } // end if + *((DWORD *)(&apiInfo.szData[0])) = hPort->mi_fContinuousMonitoring; // continuously monitor? + + // switch the fclass! + //------------------- + nResult = RealMonitor( &apiInfo ); // implicitly sets fclass... + + if ( nResult == MODEM_PENDING ) + { + DWORD hTempSem; + + // wait until fclass has been switched + //------------------------------------ + hPort->VVInfo.hSemaphore = Create_Semaphore( 0L ); + hPort->VVInfo.hTimer = Set_Global_Time_Out( VVTimerCallback, TO_FIRST_CHAR_AFTER_INIT_CMD, (ULONG)hPort ); + + // block until command is done or time out has occured + MCXPRINTF("waiting for the semaphore (class switch) to complete"); + + Wait_Semaphore( hPort->VVInfo.hSemaphore, BLOCK_ENABLE_INTS ); + if( hPort->VVInfo.hTimer ) + { + Cancel_Time_Out( hPort->VVInfo.hTimer ); + hPort->VVInfo.hTimer = 0; + } + + MCXPRINTF("returned from the semaphore!"); + + // get rid of this semapore + hTempSem = hPort->VVInfo.hSemaphore; + hPort->VVInfo.hSemaphore = 0; + Destroy_Semaphore( hTempSem ); + } // end if + + return( nResult ); +} // end VVSetClass + + +/****************************************************************************** + + @doc INTERNAL + + @api void | VVTimerCallback | This function gets called when a timer + event happens. This routine is to be used to wait for the switching + into the correct fclass for a modem. + + @parm hPort is passed in in edx + + @rdesc Returns void + + If another command comes in while we are switching the modem into + fclass 0 or 80, we will wait for the command to complete before issuing + the new command. + +*****************************************************************************/ +void VVTimerCallback( void ) +{ + MODEMINFORMATION *hPort; + + _asm mov [hPort], edx + + // clear timer + hPort->VVInfo.hTimer = 0L; + + MCXPRINTF("Got VV semaphore timeout!"); + // unblock the waiting command + if( hPort->VVInfo.hSemaphore ) + { + Signal_Semaphore( hPort->VVInfo.hSemaphore ); + } + + return; +} // end VVTimerCallback + +#endif // VOICEVIEW diff --git a/private/unimodem/tapisp/mcxutil.c b/private/unimodem/tapisp/mcxutil.c new file mode 100644 index 000000000..fcc6fd043 --- /dev/null +++ b/private/unimodem/tapisp/mcxutil.c @@ -0,0 +1,781 @@ +/****************************************************************************** + +(C) Copyright MICROSOFT Corp., 1987-1993 + +Rob Williams, June 93 w/ State machine and parser plagarized from RAS + +******************************************************************************/ + +#include "unimdm.h" +#include "mcxp.h" +#include "common.h" +#include +#include + +#define LOGGING_ON 1 + +#define DEFAULT_INACTIVITY_SCALE 10 // == decasecond units + + +// common code from ../rovcomm.lib +BOOL PUBLIC OpenResponsesKey(IN HKEY hkeyDrv, OUT PHKEY phkeyResp); + + +/****************************************************************************** + + @doc INTERNAL + + @api void | FreeModem | This function deallocates a modeminfo. structure + + @parm char * | pModemName | name of modem to find + + @rdesc Returns TRUE if the modem is, else FALSE +*****************************************************************************/ + +void FreeModem(MODEMINFORMATION * pModemInfo, HANDLE hComm) +{ + MODEMINFORMATION * pModem; + SERIALPERF_STATS serialstats; + DWORD dwBytes; + DWORD dwRet; + OVERLAPPED ov; + + RegCloseKey(pModemInfo->mi_hKeyModem); + + if (pModemInfo->mi_pNonStandardDefaults) + { + ASSERT(gRegistryFlags & fGRF_PORTLATENCY); + LocalFree(pModemInfo->mi_pNonStandardDefaults); + } + + if (pModemInfo->mi_pszReset) + { + LocalFree(pModemInfo->mi_pszReset); + } + if (pModemInfo->mi_pszzHangupCmds) + { + LocalFree(pModemInfo->mi_pszzHangupCmds); + } + if (pModemInfo->mi_pszzCmds && + pModemInfo->mi_pszzCmds != pModemInfo->mi_pszzHangupCmds) + { + MCXPRINTF("FreeModem() had to free mi_pszzCmds because someone else didn't!"); + LocalFree(pModemInfo->mi_pszzCmds); + } + + // Get Statistics + // + ov.hEvent = (HANDLE)((DWORD)pModemInfo->mi_SyncReadEvent | 1); + + dwRet = DeviceIoControl(hComm, + IOCTL_SERIAL_GET_STATS, + &serialstats, + sizeof(SERIALPERF_STATS), + &serialstats, + sizeof(SERIALPERF_STATS), + &dwBytes, + &ov); + + if (!dwRet) + { + if (ERROR_IO_PENDING == GetLastError()) + { + dwRet = GetOverlappedResult(hComm, + &ov, + &dwBytes, + TRUE); + } + } + + if (dwRet) + { + MCXPRINTF("statistics:"); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_STATISTICS); + + MCXPRINTF1(" Reads : %d bytes", + serialstats.ReceivedCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_READSTATS, + serialstats.ReceivedCount); + + MCXPRINTF1(" Writes: %d bytes", + serialstats.TransmittedCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_WRITESTATS, + serialstats.TransmittedCount); + + if (serialstats.FrameErrorCount) + { + MCXPRINTF1(" Frame Errors: %d", + serialstats.FrameErrorCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_FRAMEERRORSTATS, + serialstats.FrameErrorCount); + } + if (serialstats.SerialOverrunErrorCount) + { + MCXPRINTF1("Serial Overrun Errors: %d", + serialstats.SerialOverrunErrorCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_SERIALOVERRUNERRORSTATS, + serialstats.SerialOverrunErrorCount); + } + if (serialstats.BufferOverrunErrorCount) + { + MCXPRINTF1("Buffer Overrun Errors: %d", + serialstats.BufferOverrunErrorCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_BUFFEROVERRUNERRORSTATS, + serialstats.BufferOverrunErrorCount); + } + if (serialstats.ParityErrorCount) + { + MCXPRINTF1(" Parity Errors: %d", + serialstats.ParityErrorCount); + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_PARITYERRORSTATS, + serialstats.ParityErrorCount); + } + } + + + if (pModemInfo->mi_SyncReadEvent != NULL) { + + CloseHandle(pModemInfo->mi_SyncReadEvent); + } + + RemoveReferenceToCommon( + &gCommonList, + pModemInfo->mi_hCommon + ); + + // + // close the comm handle here so all i/o will complete, and waitcommevent + // won't corrupt the freed ModemInfo Structure + // + + MCXPRINTF1("Closing comm handle %08lx", hComm); + CloseHandle(hComm); + + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_CLOSED); + + ModemCloseLog(pModemInfo->mi_hLogFile); + MCXPRINTF("closed modem."); + + LocalFree(pModemInfo); +} + +/****************************************************************************** + + @doc INTERNAL + + @api void | BuildResponsesLinkedList | This function builds a + linked list of the responses it finds in the registry. + + @parm MODEMINFORMATION * | hPort | port handle of modem + + @rdesc Returns TRUE if successful, FALSE otherwise. + +*****************************************************************************/ + + +PRESPONSE_NODE WINAPI +NewBuildResponsesLinkedList( + HKEY hKey + ) +{ + DWORD dwRegRet; + HKEY hKeyResponses; + DWORD dwValueSize, dwDataSize, dwDataType; + DWORD dwAllocSize = 0; + DWORD dwNumResponses; + DWORD dwIndex; + CHAR *pszTemp, *pszValue, *pszExpandedValue; + PRESPONSE_NODE prnNew; + + PRESPONSE_NODE prnResponseHead; + + + // Open the Responses key. +#if 0 + if (RegOpenKeyA(hKey, szResponses, &hKeyResponses) + != ERROR_SUCCESS) +#endif + if (!OpenResponsesKey(hKey, &hKeyResponses)) + { + DPRINTF("was unable to open the Responses key."); + return FALSE; + } + + // set our pszTemp to point to some heap space to be used temporarily + // + if (!(pszTemp = (LPSTR)LocalAlloc(LPTR, + MAX_REG_KEY_LEN + MAX_REG_KEY_LEN))) + { + DPRINTF("out of memory."); + RegCloseKey(hKeyResponses); + return FALSE; + } + pszValue = pszTemp; + pszExpandedValue = pszValue + MAX_REG_KEY_LEN; + + // Calculate the size of the responses linked-list. + // + for (dwIndex = 0, dwValueSize = MAX_REG_KEY_LEN, dwDataSize = sizeof(MSS); + (dwRegRet = RegEnumValueA(hKeyResponses, dwIndex, pszValue, &dwValueSize, + NULL, &dwDataType, NULL, &dwDataSize)) + == ERROR_SUCCESS; + dwIndex++, dwValueSize = MAX_REG_KEY_LEN, dwDataSize = sizeof(MSS)) + { + // Check entry + // + if (dwDataSize != sizeof(MSS) || dwDataType != REG_BINARY) + { + DPRINTF("response data from registry was in an invalid format."); + goto Exit; + } + + // expand , , , and << macros + // + if (!ExpandMacros(pszValue, pszExpandedValue, &dwValueSize, NULL, 0)) + { + DPRINTFA1("couldn't expand macro for '%s'.", pszValue); + goto Exit; + } + + dwAllocSize += sizeof(struct _RESPONSE_NODE *) + + sizeof(MSS) + + sizeof(BYTE) + + dwValueSize; + } + + dwNumResponses = dwIndex; + DPRINTF2("response count = %d, size = %d bytes", dwNumResponses, dwAllocSize); + + // Did we fail in a bad way? + // + if (dwRegRet != ERROR_NO_MORE_ITEMS) + { + DPRINTF("RegEnumValue failed for another reason besides ERROR_NO_MORE_ITEMS."); + goto Exit; + } + + // Allocate the linked-list memory + // add 1 for the null that ExpandMacros will add to the end of the last string (it is a waste!) + // + if (!(prnResponseHead = (PRESPONSE_NODE)LocalAlloc(LPTR, + dwAllocSize + 1))) + { + DPRINTF("out of memory (trying to alloc prnResponseHead)"); + goto Exit; + } + + // Read in responses and build the list + // + for (dwIndex = 0, prnNew = prnResponseHead; + dwIndex < dwNumResponses; + dwIndex++, prnNew = prnNew->pNext) + { + dwValueSize = MAX_REG_KEY_LEN; + dwDataSize = sizeof(MSS); + if ((dwRegRet = RegEnumValueA(hKeyResponses, dwIndex, pszValue, &dwValueSize, + NULL, &dwDataType, (BYTE *)&prnNew->Mss, + &dwDataSize)) + != ERROR_SUCCESS) + { + DPRINTF2("couldn't read response #%d from the registry. (error = %d)", dwIndex, dwRegRet); + LocalFree(prnResponseHead); + goto Exit; + } + + // expand , , , and << macros + // + if (!ExpandMacros(pszValue, prnNew->szResponse, &dwValueSize, NULL, 0)) + { + DPRINTFA1("couldn't expand macro for '%s'.", pszValue); + LocalFree(prnResponseHead); + goto Exit; + } + + // subtract 1 for offset, ie. 255 = 256, 0 = 1,... + // + prnNew->bLen = (BYTE) dwValueSize - 1; + + // Only set pNext if this isn't the last one. + // + if ((dwIndex + 1) != dwNumResponses) + { + prnNew->pNext = (PRESPONSE_NODE)((LPSTR)&prnNew->szResponse + dwValueSize); + } + } + + RegCloseKey(hKeyResponses); + LocalFree(pszTemp); + return prnResponseHead; + + + +Exit: + RegCloseKey(hKeyResponses); + LocalFree(pszTemp); + return NULL; +} + + + +/****************************************************************************** + + @doc INTERNAL + + @api MODEMINFORMATION * | AllocateModem | This function allocates a MODEMINFORMATION structure + and fills it using information from the registry. + + @parm HKEY | hKey | information registry key + + @parm char * | szModemName | Modem's name + + @rdesc Returns pointer to MODEMINFORMATION if successful, else NULL +*****************************************************************************/ + +#define ALLOCATEMODEM_TEMP_SIZE 4096 + +MODEMINFORMATION * AllocateModem(LPTSTR szKey, + LPTSTR szModemName, + HANDLE hDevice) +{ + HKEY hKey; + DWORD dwRetSize; + DWORD dwType; + DWORD dwResult; + int i; + MODEMINFORMATION * pModemInfo; + CHAR * pszTemp=NULL; + BYTE bLogging; + BYTE bDeviceType; + static char szLogging[] = "Logging"; + static char szLoggingPath[] = "LoggingPath"; + static char szDriverDesc[] = "DriverDesc"; + static char szInfPath[] = "InfPath"; + static char szInfSection[] = "InfSection"; + static char szReset[] = "Reset"; + static char szDeviceType[] = "DeviceType"; + static char szHangup[] = "Hangup"; + static char szInactivityScale[] = "InactivityScale"; + static char szCDWaitPeriod[] = "CDWaitPeriod"; + static char szCompatFlags[] = "CompatibilityFlags"; + DPRINTF1("opening modem '%s'.", szModemName); + + // Open the registry key + // + if (RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) + { + DPRINTF("bad registry key."); + return NULL; + }; + + // Allocate MODEMINFORMATION structure + // + pModemInfo = (MODEMINFORMATION *)LocalAlloc(LPTR, sizeof(MODEMINFORMATION)); + if (!pModemInfo) + { + DPRINTF("out of memory."); + return NULL; + } + + pModemInfo->mi_SyncReadEvent=CreateEvent( + NULL, + TRUE, + FALSE, + NULL + ); + + if (pModemInfo->mi_SyncReadEvent == NULL) { + + DPRINTF("Could not create SyncRead Event."); + goto Failure; + } + + pModemInfo->mi_hCommon=OpenCommonModemInfo( + &gCommonList, + hKey + ); + + if (pModemInfo->mi_hCommon == NULL) { + + DPRINTF("Could not open common info."); + goto Failure; + } + + // set our pszTemp to point to some heap space to be used temporarily + // + pszTemp = (LPSTR)LocalAlloc(LPTR, ALLOCATEMODEM_TEMP_SIZE); + if (!pszTemp) + { + DPRINTF("out of memory."); + LocalFree(pModemInfo); + goto Failure; + } + + // Initialize the MODEMINFORMATION structure + // + pModemInfo->mi_ModemState = STATE_UNKNOWN; + pModemInfo->mi_pszzCmds = NULL; + pModemInfo->mi_dwUnconditionalReturnValue = MODEM_NO_UNCONDITIONAL; + pModemInfo->mi_hKeyModem = hKey; + + // Read the Logging line from the registry and turn on logging if it is present and set to 1. + // + dwRetSize = sizeof(BYTE); + dwResult = RegQueryValueExA(hKey, szLogging, NULL, &dwType, + &bLogging, + &dwRetSize); + if (dwRetSize == sizeof(BYTE) && + dwResult == ERROR_SUCCESS && + bLogging == LOGGING_ON) + { + dwRetSize = ALLOCATEMODEM_TEMP_SIZE; + if (RegQueryValueExA(hKey, szLoggingPath, NULL, + &dwType, (VOID *)pszTemp, &dwRetSize) != ERROR_SUCCESS || + dwType != REG_SZ) + { + DPRINTF("failed to open because the filename for the log was invalid or missing."); +// goto Failure; + } + else + { + pModemInfo->mi_hLogFile=ModemOpenLog(pszTemp); + + if ((pModemInfo->mi_hLogFile)==NULL) + { + DPRINTF("failed to open the log file."); + } + +#ifdef UNICODE + // Convert Unicode modem name to Ansi so we can log it. + { + LPSTR szAnsiModemName; + DWORD dwLen; + + dwLen = WideCharToMultiByte(CP_ACP, + 0, + szModemName, + -1, + NULL, + 0, + NULL, + NULL); + + if (dwLen != 0) + { + szAnsiModemName = (LPSTR) LocalAlloc(LPTR, dwLen); + if (szAnsiModemName != NULL) + { + dwLen = WideCharToMultiByte(CP_ACP, + 0, + szModemName, + -1, + szAnsiModemName, + dwLen, + NULL, + NULL); + + LogString(pModemInfo->mi_hLogFile, + pModemInfo->mi_dwID, + IDS_MSGLOG_OPENED, + szAnsiModemName); + + LocalFree(szAnsiModemName); + } + } + } +#else // UNICODE + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_OPENED, szModemName); +#endif // UNICODE + } + } + + // + // Read in the compat flags + // + dwRetSize = sizeof(DWORD); + + dwResult = RegQueryValueExA( + hKey, + szCompatFlags, + NULL, + &dwType, + (PBYTE)&pModemInfo->mi_CompatibilityFlags, + &dwRetSize + ); + + if (dwRetSize != sizeof(DWORD) || + dwResult != ERROR_SUCCESS ) + { + // reg query failed + // + pModemInfo->mi_CompatibilityFlags=0; + + } + + + + // + // Read in the CD wait period + // + dwRetSize = sizeof(DWORD); + + dwResult = RegQueryValueExA( + hKey, + szCDWaitPeriod, + NULL, + &dwType, + (PBYTE)&pModemInfo->mi_dwWaitForCDTime, + &dwRetSize + ); + + if (dwRetSize != sizeof(DWORD) || + dwResult != ERROR_SUCCESS || + 0 == pModemInfo->mi_dwWaitForCDTime) + { + // reg query failed + // + pModemInfo->mi_dwWaitForCDTime=5000; + + } + + + + // Read in the InactivityScale + dwRetSize = sizeof(DWORD); + dwResult = RegQueryValueExA(hKey, szInactivityScale, NULL, &dwType, + (PBYTE)&pModemInfo->mi_dwInactivityScale, + &dwRetSize); + if (dwRetSize != sizeof(DWORD) || + dwResult != ERROR_SUCCESS || + 0 == pModemInfo->mi_dwInactivityScale) + { + // reg query failed + // + pModemInfo->mi_dwInactivityScale = DEFAULT_INACTIVITY_SCALE; + } + + // Get some capabilities from modem.sys. + { + LPCOMMPROP lpCommProp = (LPCOMMPROP) pszTemp; + + lpCommProp->dwProvSpec1 = COMMPROP_INITIALIZED; + lpCommProp->wPacketLength = ALLOCATEMODEM_TEMP_SIZE; + + if (GetCommProperties(hDevice, lpCommProp) == TRUE) + { + LPMODEMDEVCAPS lpModemDevCaps = (LPMODEMDEVCAPS) + &lpCommProp->wcProvChar[0]; + + pModemInfo->mi_dwModemOptionsCap = lpModemDevCaps->dwModemOptions; + pModemInfo->mi_dwCallSetupFailTimerCap = lpModemDevCaps->dwCallSetupFailTimer; + pModemInfo->mi_dwInactivityTimeoutCap = lpModemDevCaps->dwInactivityTimeout; + pModemInfo->mi_dwSpeakerVolumeCap = lpModemDevCaps->dwSpeakerVolume; + pModemInfo->mi_dwSpeakerModeCap = lpModemDevCaps->dwSpeakerMode; + } + else + { + MCXPRINTF1("GetCommProperties() failed with %d", GetLastError()); + ASSERT(0); + + pModemInfo->mi_dwModemOptionsCap = 0; + pModemInfo->mi_dwCallSetupFailTimerCap = 0; + pModemInfo->mi_dwInactivityTimeoutCap = 0; + pModemInfo->mi_dwSpeakerVolumeCap = 0; + pModemInfo->mi_dwSpeakerModeCap = 0; + } + } + + pModemInfo->mi_fSettingsInitStringsBuilt = FALSE; + + // Read in the Reset command, if present + // + dwRetSize = MAXSTRINGLENGTH; + if (RegQueryValueExA(hKey, szReset, NULL, + &dwType, (VOID *)pszTemp, &dwRetSize) != ERROR_SUCCESS || + dwType != REG_SZ || + dwRetSize <= 1) + { + DPRINTFA1("didn't find a %s (or it wasn't REG_SZ).", szReset); + pModemInfo->mi_pszReset = NULL; + } + else + { + LPSTR pszExpanded = pszTemp + MAXSTRINGLENGTH; + + ExpandMacros(pszTemp, pszExpanded, NULL, NULL, 0); + + // allocate some memory + // + if (pModemInfo->mi_pszReset = (LPSTR)LocalAlloc(LPTR, + lstrlenA(pszExpanded) + + 1)) + + { + lstrcpyA(pModemInfo->mi_pszReset, pszExpanded); + pModemInfo->mi_dwResetLen = lstrlenA(pModemInfo->mi_pszReset); + } + else + { + DPRINTF("_HeapAllocate failed for mi_pszReset!"); + } + } + + pModemInfo->mi_prnResponseHead=GetCommonResponseList(pModemInfo->mi_hCommon); + +#if (MAXSTRINGLENGTH > ALLOCATEMODEM_TEMP_SIZE) +#error "MAXSTRINGLENGTH > ALLOCATEMODEM_TEMP_SIZE" +#endif + + // Write out some inf identification info for PSS + // + dwRetSize = MAXSTRINGLENGTH; + if (RegQueryValueExA(hKey, szDriverDesc, NULL, + &dwType, pszTemp, &dwRetSize) == ERROR_SUCCESS) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_DRIVERDESC, pszTemp); + } + + dwRetSize = MAXSTRINGLENGTH; + if (RegQueryValueExA(hKey, szInfPath, NULL, + &dwType, pszTemp, &dwRetSize) == ERROR_SUCCESS) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_INFPATH, pszTemp); + } + + dwRetSize = MAXSTRINGLENGTH; + if (RegQueryValueExA(hKey, szInfSection, NULL, + &dwType, pszTemp, &dwRetSize) == ERROR_SUCCESS) + { + LogString(pModemInfo->mi_hLogFile,pModemInfo->mi_dwID, IDS_MSGLOG_INFSECTION, pszTemp); + } + + // Set mi_fModem based on the DeviceType + // + dwRetSize = sizeof(BYTE); + if (RegQueryValueExA(hKey, szDeviceType, NULL, + &dwType, &bDeviceType, &dwRetSize) == ERROR_SUCCESS && + dwRetSize == sizeof(BYTE)) + { + switch(bDeviceType) + { + case DT_NULL_MODEM: + case DT_PARALLEL_PORT: + DPRINTF("device type = Null-Modem"); + pModemInfo->mi_fModem = FALSE; + break; + + case DT_EXTERNAL_MODEM: + case DT_INTERNAL_MODEM: + case DT_PCMCIA_MODEM: + case DT_PARALLEL_MODEM: + default: + DPRINTF("device type = Modem"); + pModemInfo->mi_fModem = TRUE; + + // Load in Hangup commands + // + if (!(pModemInfo->mi_pszzHangupCmds = LoadRegCommands(pModemInfo, szHangup, NULL))) + { + DPRINTF("failed to load Hangup commands on start."); + goto Failure; + } + break; + } + } + else + { + DPRINTFA1("failed to open because the '%s' line was missing from the registry or was not the right size.", szDeviceType); + goto Failure; + } + + // Create nonstandard MODEMDEFAULTS section if there is one + if (gRegistryFlags & fGRF_PORTLATENCY) + { + TCHAR rgtch[] = szUNIMODEM_REG_PATH TEXT("\\PortSpecific\\Defaults"); + DWORD dwLatency = 0; + DWORD dwSize=sizeof(dwLatency); + DWORD dwType = 0; + HKEY hKey=NULL; + LONG l; + + pModemInfo->mi_pNonStandardDefaults = NULL; + + l=RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + rgtch, // address of name of subkey to open + 0, // reserved + KEY_READ, // desired security access + &hKey // address of buffer for opened handle + ); + + if (l!=ERROR_SUCCESS) goto Success; + + l=RegQueryValueEx( + hKey, + TEXT("PortLatency"), + NULL, + &dwType, + (LPBYTE) &dwLatency, + &dwSize + ); + if ( l==ERROR_SUCCESS + && dwType == REG_DWORD + && dwSize == sizeof(dwLatency) + && dwLatency < 20000) + { + MODEMDEFAULTS * pMD = LocalAlloc(LPTR, sizeof (MODEMDEFAULTS)); + if (pMD) + { + pMD->dwFlags = 0; + pMD->dwPortLatency = dwLatency; + pModemInfo->mi_pNonStandardDefaults = pMD; + } + DPRINTF2( + "WARNING: [%s]: NON STANDARD PORT LATENCY: %lu", + szModemName, + dwLatency + ); + } + RegCloseKey(hKey); hKey = NULL; + } + + +Success: + // free temp memory + // + if (pszTemp) LocalFree(pszTemp); + return (pModemInfo); + +Failure: + + if (pModemInfo->mi_SyncReadEvent != NULL) { + + CloseHandle(pModemInfo->mi_SyncReadEvent); + } + + if (pModemInfo->mi_hCommon != NULL) { + + RemoveReferenceToCommon( + &gCommonList, + pModemInfo->mi_hCommon + ); + } + + ModemCloseLog(pModemInfo->mi_hLogFile); + LocalFree(pModemInfo); + pModemInfo = NULL; + goto Success; +} diff --git a/private/unimodem/tapisp/mdmasyn.c b/private/unimodem/tapisp/mdmasyn.c new file mode 100644 index 000000000..bc2a99c13 --- /dev/null +++ b/private/unimodem/tapisp/mdmasyn.c @@ -0,0 +1,1325 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: mdmasyn.c +// +// Copyright (c) 1992-1995, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 5/4/95 Viroon Touranachun Moved from modem.c +// +// +// Description: Asynchronous thread entry and state machine +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" + +typedef struct tagMdmThrd { + struct tagMdmThrd* pNext; + HANDLE hThrd; + DWORD tid; +} MDMTHRD, *PMDMTHRD; + +// Global asynchronous elements +// +PMDMTHRD gpMdmThrdList = NULL; +HANDLE ghCompletionPort = NULL; + +extern MDMLIST gMdmList; + +void MdmCompleteAsync (PLINEDEV pLineDev, DWORD dwStatus, DWORD dwAsyncID); +void HandleMdmError (PLINEDEV pLineDev, DWORD dwStatus); +DWORD DetectDialtone (PLINEDEV pLineDev); + +VOID WINAPI +ProcessRings( + PLINEDEV pLineDev, + DWORD Type + ); + + +//**************************************************************************** +// DWORD InitializeMdmThreads() +// +// Function: Initialize threads to handle modem's asynchronous operations. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//****************************************************************************/ + +DWORD InitializeMdmThreads() +{ + PMDMTHRD pMdmThrd; + DWORD dwRet = ERROR_SUCCESS; // assume success + SYSTEM_INFO systeminfo; + DWORD dwNumThreadsRunning = 0; + + // We are going to create a thread per processor, so get the system info + // which contains the number of processors in the system. + // + GetSystemInfo(&systeminfo); + + // Create the completion port. This starts without any file handles being + // associated with it. + // + ASSERT(ghCompletionPort == NULL); + ghCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, + 0, + 0); + if (ghCompletionPort == NULL) + { + dwRet = GetLastError(); + DPRINTF1("CreateIoCompletionPort failed with %d", dwRet); + } + else + { + // Create the threads. + // + while (dwNumThreadsRunning < systeminfo.dwNumberOfProcessors) + { + if ((pMdmThrd = (PMDMTHRD)LocalAlloc(LPTR, sizeof(*pMdmThrd))) != NULL) + { + // Create thread + // + pMdmThrd->hThrd = CreateThread(NULL, // default security + 0, // default stack size + MdmAsyncThread, // thread entry point + pMdmThrd, // thread info + CREATE_SUSPENDED, // Start suspended + &pMdmThrd->tid); // thread id + + if (pMdmThrd->hThrd != NULL) + { + dwNumThreadsRunning++; + + // Put it in the thread list + // + pMdmThrd->pNext = gpMdmThrdList; + gpMdmThrdList = pMdmThrd; + + DPRINTF1("Async Thread id: %x was created but suspended", pMdmThrd->tid); + + // Send thread on its way... + // + ResumeThread(pMdmThrd->hThrd); + + DPRINTF1("Async Thread id: %x is in operation", pMdmThrd->tid); + } + else + { + LocalFree(pMdmThrd); + + // If we were able to get at least one thread going, indicate success. + // + if (dwNumThreadsRunning == 0) + { + DPRINTF("InitializeMdmThreads was unable to create all of the threads! (CreateThread failed)"); + dwRet = LINEERR_OPERATIONFAILED; + } + break; + } + } + else + { + // If we were able to get at least one thread going, indicate success. + // + if (dwNumThreadsRunning == 0) + { + DPRINTF("InitializeMdmThreads was unable to create all of the threads! (LocalAlloc failed)"); + dwRet = ERROR_OUTOFMEMORY; + } + break; + } + } + } + + // If we failed in some way, delete the completion port, it isn't being used. + // + if (dwRet != ERROR_SUCCESS) + { + ASSERT(dwNumThreadsRunning == 0); + + if (ghCompletionPort != NULL) + { + CloseHandle(ghCompletionPort); + ghCompletionPort = NULL; + } + } + + return dwRet; +} + +//**************************************************************************** +// DWORD DeinitializeMdmThreads() +// +// Function: Deinitialize threads to handle modem's asynchronous operations. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//****************************************************************************/ + +DWORD DeinitializeMdmThreads() +{ + PMDMTHRD pMdmThrd; + DWORD dwCount = 0; + HANDLE WaitHandles[MAXIMUM_WAIT_OBJECTS]; + + DPRINTF("DeinitializeMdmThreads() called."); + + // Post a termination request to the completion port. + // Do one for each thread running. Keep count for later in this routine. + // + pMdmThrd = gpMdmThrdList; + while (pMdmThrd) + { + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), // indicates nothing + 0, // indicates this is a termination message + NULL); // indicates nothing + dwCount++; + + pMdmThrd = pMdmThrd->pNext; + } + + ASSERT(dwCount <= MAXIMUM_WAIT_OBJECTS); // Make sure the world hasn't turned upside down. + + // Do a WaitForMultipleObjects on all of the thread handles to wait for + // them to complete. + // + // Build array to wait on. + // + dwCount = 0; + pMdmThrd = gpMdmThrdList; + while (pMdmThrd) + { + WaitHandles[dwCount++] = pMdmThrd->hThrd; + + pMdmThrd = pMdmThrd->pNext; + } + + WaitForMultipleObjects(dwCount, // number of threads to wait to end + WaitHandles, // array of threads + TRUE, // wait until all have been terminated + INFINITE); // wait forever, if necessary + + while (pMdmThrd = gpMdmThrdList) + { + CloseHandle(pMdmThrd->hThrd); + + gpMdmThrdList = pMdmThrd->pNext; + LocalFree(pMdmThrd); + } + + // + // close completion port handle + // + CloseHandle(ghCompletionPort); + + DPRINTF("Async Threads terminated succesfully."); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD APIENTRY MdmAsyncThread (PMDMTHRD) +// +// Function: An entry point to the asynchronous modem thread. +// +// Returns: None +// +//****************************************************************************/ + +DWORD APIENTRY MdmAsyncThread (PMDMTHRD pMdmThrd) +{ + DWORD dwNumberOfBytesTransferred; + DWORD dwCompletionKey; + LPOVERLAPPED lpOverlapped; + PLINEDEV pLineDev; + + DPRINTF1("Async thread id: %x is running", pMdmThrd->tid); + + ASSERT(ghCompletionPort != NULL); + + // Read from the completion port until we get signalled to exit the thread. + // This is done by having a completion posted that has a dwCompletionKey of 0. + // dwCompletionKey is normally the pLineDev associated with an operation. + // + for (;;) + { + if (GetQueuedCompletionStatus(ghCompletionPort, + &dwNumberOfBytesTransferred, + &dwCompletionKey, + &lpOverlapped, + (DWORD)-1) == FALSE && + lpOverlapped == NULL) + { + DPRINTF1("GetQueuedCompletionStatus() returned FALSE and lpOverlapped was NULL (GetLastError() = %d)", + GetLastError()); + ASSERT(0); + continue; + } + + TRACE4( + IDEVENT_CP_GET, + dwNumberOfBytesTransferred, + dwCompletionKey, + lpOverlapped + ); + + if (dwCompletionKey == 0) + { + DPRINTF1("Async Thread id: %d being asked to exit", pMdmThrd->tid); + break; // NULL dwCompletionKey indicates we were asked to terminate. + } + else + { + pLineDev = (PLINEDEV)dwCompletionKey; + CLAIM_LINEDEV(pLineDev); + + // BUGBUG: CCaputo 2/20/96: pLineDev could have disappeard. + // BUGBUG: Might want to do something here to verify existence. + + // Is this completion for the upper layer state machine (unimdm) or the + // lower layer state machine (mcx)? + // + if (lpOverlapped == NULL) + { + DWORD dwType = CP_TYPE(dwNumberOfBytesTransferred); + if (dwType != 0) { + // + // it is a ring related event + // + ProcessRings( + pLineDev, + dwType + ); + + } else { + // + // Is the purpose of this completion to signal an event or + // continue in the normal unimdm state machine? + // + if (pLineDev->hSynchronizeEvent == NULL) + { + DWORD dwPendingID; + + dwPendingID = pLineDev->McxOut.dwReqID; + pLineDev->McxOut.dwReqID = MDM_ID_NULL; + + // Call the operation handler + // + MdmCompleteAsync(pLineDev, pLineDev->McxOut.dwResult, dwPendingID); + } + else + { + SetEvent(pLineDev->hSynchronizeEvent); + } + } + } + else + { + // non-NULL lpOverlapped indicates this is for MCXAsyncComplete() + // + if (pLineDev->hModem) + { + MCXAsyncComplete (pLineDev->hModem, lpOverlapped); + } + + OverPoolFree(lpOverlapped); + } + + RELEASE_LINEDEV(pLineDev); + } + } + + // Exit the thread properly + // + DPRINTF1("Async Thread id: %d exits", pMdmThrd->tid); + ExitThread(ERROR_SUCCESS); + return ERROR_SUCCESS; +} + + +// +// Rings are handle here instead of the main async handler beacuse they get built +// up in the completion port and extra one mess up the state machine +// +VOID WINAPI +ProcessRings( + PLINEDEV pLineDev, + DWORD Type + ) + +{ + + + switch (pLineDev->DevState) { + + case DEVST_PORTLISTENING: + // + // The line is being monitored and the first ring is coming in. + // + + // Make sure call hasn't already been allocated. + // If this isn't the first set of rings, then make + // sure the previous "hdcall" has been deallocated. + // In other words, ignore rings until this happens! + // + if (pLineDev->dwCall & CALL_ALLOCATED) + { + TSPPRINTF("RING ignored because IDLE call hasn't been deallocated!"); + break; + }; + + // We need to notify a new call to TAPI + // + (*(pLineDev->lpfnEvent))(pLineDev->htLine, NULL, LINE_NEWCALL, + (DWORD)pLineDev, + (DWORD)((LPHANDLE)&(pLineDev->htCall)), + 0); + + // Allocate the call + // + pLineDev->dwCall = CALL_ALLOCATED | CALL_INBOUND | CALL_ACTIVE; + + // Then offer the call to TAPI + // + pLineDev->DevState = DEVST_PORTLISTENOFFER; + + // OR in UNKNOWN since we don't know what kind of media mode this call is + // + pLineDev->dwCurMediaModes = pLineDev->dwDetMediaModes | LINEMEDIAMODE_UNKNOWN; + + // default our bearermode to be what we support, excluding the passthrough bit + // + pLineDev->dwCurBearerModes = pLineDev->dwBearerModes & ~LINEBEARERMODE_PASSTHROUGH; + + // Notify TAPI + // + NEW_CALLSTATE(pLineDev, LINECALLSTATE_OFFERING, 0); + + // + // fall through + // + + + case DEVST_PORTLISTENOFFER: + { + // + // A ring is coming in (either the first ring or a subsequent one.) + // Handle the ring count + // + DWORD dwCurrent = GETTICKCOUNT(); + + // If this is the second or greater ring, + // then we may have a timer to kill. + // + if (pLineDev->dwRingCount) + { + KillMdmTimer((DWORD)pLineDev, NULL); + + // Check whether the timeout expired + // + if (GTC_DELTA(pLineDev->dwRingTick, dwCurrent) >= TO_MS_RING_SEPARATION) + { + // Timeout has expired, indicating call has stopped ringing + // + pLineDev->dwRingTick = 0; + pLineDev->dwRingCount = 0; + pLineDev->DevState = DEVST_PORTLISTENING; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0); + break; + }; + }; + + pLineDev->dwRingCount++; + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_LINEDEVSTATE, + LINEDEVSTATE_RINGING, 1L, pLineDev->dwRingCount); + TSPPRINTF1("RING#%d notfied", pLineDev->dwRingCount); + + pLineDev->dwRingTick = dwCurrent; + if (SetMdmTimer((DWORD)pLineDev, NULL, TO_MS_RING_SEPARATION) + != ERROR_SUCCESS) + { + TSPPRINTF("SetTimer failed!"); + } + break; + } + + default: + + TSPPRINTF("ProcessRings: extra ring queued!"); + + break; + + } // switch + + return; + +} + + + + +//**************************************************************************** +// void MdmCompleteAsync(PLINEDEV, DWORD, DWORD) +// +// Function: A caller invokes this function when it receives WM_COMNOTIFY +// message in order to complete the pending asynchronous operation +// or asynchronous event. +// +// Note: The dialing process is pretty complex. See dialing.txt for more info. +// +// Returns: nothing +// +//**************************************************************************** + +void MdmCompleteAsync (PLINEDEV pLineDev, DWORD dwStatus, DWORD dwAsyncID) +{ + DWORD dwRet; + + ASSERT(pLineDev->pDevCfg != NULL); + TSPPRINTF2("MdmCompleteAsync services id: %d status: %d", dwAsyncID, dwStatus); + + // We only care about messages we are expecting or + // MDM_ID_NULL (unexpected) messages + // + if (dwAsyncID != MDM_ID_NULL) + { + if (pLineDev->dwVxdPendingID == dwAsyncID) + { + // Reset the pending ID, except for when we are doing + // continuous monitoring from the VxD. + // + if (DEVST_PORTLISTENING != pLineDev->DevState && + DEVST_PORTLISTENOFFER != pLineDev->DevState) + { + pLineDev->dwVxdPendingID = MDM_ID_NULL; + }; + } + else + { + TSPPRINTF1("rejecting obsolete async id: %d", dwAsyncID); + return; + }; + }; + + // Messages from the VxD when we are in takeover mode are used to do the + // async completion for the switch to takeover mode. + // + if (pLineDev->fTakeoverMode) + { + if (pLineDev->dwPendingID != INVALID_PENDINGID) + { + UnimodemSetPassthrough(pLineDev, PASSTHROUGH_ON); + pLineDev->DevState = DEVST_CONNECTED; + (*gfnCompletionCallback)(pLineDev->dwPendingID, ERROR_SUCCESS); + pLineDev->dwPendingID = INVALID_PENDINGID; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_CONNECTED, 0); + }; + return; + }; + + // If it is the success notification, we continue the state machine + // + if (MDM_SUCCESS == dwStatus) + { + do + { + // Yes, it is. Determine the current line state + // + dwRet = ERROR_IO_PENDING; + + switch (pLineDev->DevState) + { + case DEVST_PORTLISTENINIT: + // + // Put modem to non-continuous Monitor + // + pLineDev->DevState = DEVST_PORTLISTENING; + pLineDev->dwRingCount = 0; + pLineDev->dwRingTick = 0; + + // Start monitoring the line + // + dwRet = UnimodemMonitor(pLineDev, MONITOR_CONTINUOUS); + break; + + case DEVST_PORTSTARTPRETERMINAL: + // + // Start the terminal screen + // + pLineDev->DevState = DEVST_PORTCONNECTINIT; + dwRet = ERROR_SUCCESS; + + // Turn-on passthrough mode + // + if (UnimodemSetPassthrough(pLineDev, PASSTHROUGH_ON) == ERROR_SUCCESS) + { + // Put the terminal screen up here + // + pLineDev->DevState = DEVST_PORTPRETERMINAL; + + if (TerminalDialog(pLineDev) == ERROR_SUCCESS) + { + // Wait until the terminal screen completes + // + dwRet = ERROR_IO_PENDING; + }; + }; + break; + + case DEVST_PORTPRETERMINAL: + // + // Destroy the terminal window + // + DestroyTerminalDialog(pLineDev); + + // Turn-off passthrough mode + // + UnimodemSetPassthrough(pLineDev, PASSTHROUGH_OFF); + + // Put it to init mode + // + pLineDev->DevState = DEVST_PORTCONNECTINIT; + dwRet = UnimodemInit(pLineDev); + break; + + case DEVST_PORTCONNECTINIT: + // + // The modem was sucessfully initialized for dialing out. + // + if (!pLineDev->InitStringsAreValid) { + // + // some one call lineSetDevConfig, redo the init + // + pLineDev->DevState = DEVST_PORTCONNECTINIT; + dwRet = UnimodemInit(pLineDev); + + break; + } + + + pLineDev->DevState = DEVST_PORTCONNECTDIALTONEDETECT; + pLineDev->dwCall |= CALL_ACTIVE; + + // Detect dialtone + // + dwRet = DetectDialtone(pLineDev); + break; + + case DEVST_PORTCONNECTWAITFORLINEDIAL: + case DEVST_PORTCONNECTDIALTONEDETECT: + // + // The dialtone was detected or we did not need to detect it. Now we + // are ready to dial. + // + // Note: The dialing process is pretty complex. + // (See dialing.txt for more info.) + // + pLineDev->dwCall |= CALL_ACTIVE; + + // Check for needed async completion. + // (for the lineMakeCall) + // + if (pLineDev->dwPendingID != INVALID_PENDINGID && + pLineDev->dwPendingType == PENDING_LINEMAKECALL) + { + (*gfnCompletionCallback)(pLineDev->dwPendingID, 0L); + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DIALTONE, LINEDIALTONEMODE_UNAVAIL); + }; + + // Fall through to common code path + // + case DEVST_MANUALDIALING: + // + // If it is an originate address (no semi-colone at the end,) this is + // the last string we are dialing before connecting. + // + if (IsOriginateAddress(pLineDev->szAddress)) + { + // If we re-enter after manual dialing, + // do not repeat manual dialing + // + if (pLineDev->DevState != DEVST_MANUALDIALING) + { + // Don't optimize this and the one below!!! (see lineGetCallStatus) + // + pLineDev->DevState = DEVST_PORTCONNECTING; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DIALING, 0); + + // Handle Manual Dial + // + if (GETOPTIONS(pLineDev->pDevCfg) & MANUAL_DIAL) + { + + // bring up modal manual dial dialog, + // it will return ERROR_SUCCESS or a non-pending error code + // when it is done... + // + dwRet = ManualDialog(pLineDev); + + // If there is no error, wait for dialog to finish + // + if (ERROR_SUCCESS == dwRet) + { + dwRet = ERROR_IO_PENDING; + pLineDev->DevState = DEVST_MANUALDIALING; + }; + break; + }; + } + else + { + *pLineDev->szAddress = '\0'; + + // We finish manual dialing, continue + // + pLineDev->DevState = DEVST_PORTCONNECTING; + }; + + NEW_CALLSTATE(pLineDev, LINECALLSTATE_PROCEEDING, 0); + + // Handle INTERACTIVEVOICE + // + if (LINEMEDIAMODE_INTERACTIVEVOICE == pLineDev->dwCurMediaModes) + { + // if we have partial dialing capability and enough room to do it, + // then make it so we wait indefinitely. + // + if (pLineDev->fPartialDialing && + lstrlenA(pLineDev->szAddress) + lstrlenA(szSemicolon) + < sizeof(pLineDev->szAddress)) + { + lstrcatA(pLineDev->szAddress, szSemicolon); + }; + + // bring up talk drop dialog, + // + if ((dwRet = TalkDropDialog(pLineDev)) == ERROR_SUCCESS) + { + // Don't dial if we are MANUAL dialing. + // + if (!(GETOPTIONS(pLineDev->pDevCfg) & MANUAL_DIAL)) + { + // Dial the number and either: + // 1) wait indefinitely, if we support partial dialing, or + // 2) begin busy monitoring for several seconds + // (register S7, dwCallSetupFailTimer) + // + if ((dwRet = UnimodemDial(pLineDev, pLineDev->szAddress, pLineDev->dwDialOptions)) + == ERROR_IO_PENDING) + { + pLineDev->DevState = DEVST_TALKDROPDIALING; + }; + } + else + { + // Wait until the user takes an action + // + dwRet = ERROR_IO_PENDING; + }; + }; + }; + } + else + { + // Don't optimize this and the one above!!! (see lineGetCallStatus) + // + pLineDev->DevState = DEVST_PORTCONNECTDIAL; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DIALING, 0); + }; + + // INTERACTIVEVOICE Originate's are handled above! + // + if (LINEMEDIAMODE_INTERACTIVEVOICE != pLineDev->dwCurMediaModes || + DEVST_PORTCONNECTDIAL == pLineDev->DevState) + { + // Do we have anything useful to dial? (more than just ";"?) + // + if (lstrcmpA(pLineDev->szAddress, szSemicolon)) + { + // Start the dialing process + // + dwRet = UnimodemDial(pLineDev, pLineDev->szAddress, pLineDev->dwDialOptions); + } + else + { + // just skip to the next stage + // + dwRet = ERROR_SUCCESS; + }; + } + + // Check for needed async completion. + // (for the lineDial) + // + if (pLineDev->dwPendingID != INVALID_PENDINGID && + pLineDev->dwPendingType == PENDING_LINEDIAL) + { + (*gfnCompletionCallback)(pLineDev->dwPendingID, 0L); + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + }; + + break; + + case DEVST_PORTCONNECTDIAL: + // + // The line was previously dialed with a non-originate address + // Wait for another lineDial + // + pLineDev->DevState = DEVST_PORTCONNECTWAITFORLINEDIAL; + pLineDev->dwCall |= CALL_ACTIVE; + + // Send up another LINECALLSTATE_DIALING so that app knows + // to check the call status to see that lineDial is usable again. + // + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DIALING, 0); + break; + + case DEVST_TALKDROPDIALING: + // + // Result from UnimodemDial + // + pLineDev->DevState = DEVST_PORTCONNECTING; + + // Only pay attention to these messages if we are actually originating + // (monitoring) or if it is an error from the partial dial. + // (ignore MDM_SUCCESS from partial dial) + // + if (IsOriginateAddress(pLineDev->szAddress)) + { + DestroyTalkDropDialog(pLineDev); + dwRet = ERROR_SUCCESS; + } + break; + + + case DEVST_PORTCONNECTING: + // + // The modem sucessfully dial the originate address. + // The modem is connected. + // + pLineDev->DevState = DEVST_PORTLISTENANSWER; + dwRet = ERROR_SUCCESS; + + // Post-dial Terminal Mode + // + if (GETOPTIONS(pLineDev->pDevCfg) & TERMINAL_POST) + { + pLineDev->DevState = DEVST_PORTPOSTTERMINAL; + if (TerminalDialog(pLineDev) == ERROR_SUCCESS) + { + dwRet = ERROR_IO_PENDING; + }; + }; + break; + + case DEVST_PORTPOSTTERMINAL: + // + // Destroy the termnal window + // + DestroyTerminalDialog(pLineDev); + pLineDev->DevState = DEVST_PORTLISTENANSWER; + dwRet = ERROR_SUCCESS; + break; + + case DEVST_PORTLISTENANSWER: + // + // The modem is connected (with either incoming or outgoing call.) + // Ready to notify TAPI of the connected line. + // + // Treat INTERACTIVEVOICE connections differently. + // + if (LINEMEDIAMODE_INTERACTIVEVOICE != pLineDev->dwCurMediaModes) + { + // Get the call information + // + UnimodemGetNegotiatedRate(pLineDev, (LPDWORD)&pLineDev->dwNegotiatedRate); + + // + // Start monitoring the remote disconnection here + // + UnimodemMonitorDisconnect(pLineDev); + + // Do we need to lauch modem light? + // We launch the light when the light was selected. + // + if (!IS_NULL_MODEM(pLineDev) && + (GETOPTIONS(pLineDev->pDevCfg) & LAUNCH_LIGHTS)) + { + HANDLE hLight; + + if (LaunchModemLight(pLineDev->szDeviceName, + pLineDev->hDevice, + &hLight) == ERROR_SUCCESS) + pLineDev->hLights = hLight; + }; + }; + + // Notify TAPI of the connected line + // + pLineDev->DevState = DEVST_CONNECTED; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_CONNECTED, 0); + break; + + case DEVST_DISCONNECTING: + + TSPPRINTF("Setting Drop Event"); + + + SetEvent( + pLineDev->DroppingEvent + ); + +// case DEVST_DISCONNECTED: + // + // The modem was hung up successfully. + // + if (pLineDev->dwPendingID != INVALID_PENDINGID) + { + // Notify TAPI of the idle line + // + NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0); + + (*(gfnCompletionCallback))(pLineDev->dwPendingID, 0L); + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + }; + + pLineDev->DevState = DEVST_DISCONNECTED; + + break; + + default: + pLineDev->DevState = DEVST_DISCONNECTED; + break; + }; + + // We may have a new failure + // + if ((dwRet != ERROR_IO_PENDING) && (dwRet != ERROR_SUCCESS)) + { + dwStatus = MDM_FAILURE; + }; + + } while (dwRet == ERROR_SUCCESS); + }; + + // Handle failure + // + if ((dwStatus != MDM_SUCCESS) && (dwStatus != MDM_PENDING)) + { + HandleMdmError(pLineDev, dwStatus); + }; + return; +} + +//**************************************************************************** +// DWORD MdmAsyncContinue(PLINEDEV, DWORD) +// +// Function: continues the next state for the modem device +// +// Returns: ERROR_SUCCESS +// +//**************************************************************************** + +DWORD MdmAsyncContinue (PLINEDEV pLineDev, DWORD dwStatus) +{ + pLineDev->dwVxdPendingID++; + pLineDev->McxOut.dwReqID = pLineDev->dwVxdPendingID; + pLineDev->McxOut.dwResult = dwStatus; + + PostQueuedCompletionStatus(ghCompletionPort, + CP_BYTES_WRITTEN(0), + (DWORD)pLineDev, + NULL); + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// void HandleMdmError(PLINEDEV, DWORD) +// +// Function: Handles the modem line when the status is not successful. +// +// Returns: nothing +// +//**************************************************************************** + +void HandleMdmError(PLINEDEV pLineDev, DWORD dwStatus) +{ + // Do we have a call? + // + if ((pLineDev->dwCall & CALL_ALLOCATED) && + (pLineDev->dwCallState != LINECALLSTATE_DISCONNECTED)) + { + DWORD dwDisconnectMode = 0; + LONG lAsyncResult = 0; + + // Terminate all UI windows + // + DestroyTalkDropDialog(pLineDev); + DestroyManualDialog(pLineDev); + + // Determine the failure + // + switch (dwStatus) + { + case MDM_HANGUP: + // + // The line is disconnected remotely, or the user cancel the line + // Destroy the terminal window + // + + if ((DEVST_PORTPRETERMINAL == pLineDev->DevState) + || + (DEVST_PORTPOSTTERMINAL == pLineDev->DevState)) { + + DestroyTerminalDialog(pLineDev); + lAsyncResult = LINEERR_OPERATIONFAILED; + } + + dwDisconnectMode = LINEDISCONNECTMODE_NORMAL; + break; + + case MDM_BUSY: + // + // We dialed out and the line is busy + // + dwDisconnectMode = LINEDISCONNECTMODE_BUSY; + break; + + case MDM_NOANSWER: + case MDM_NOCARRIER: + // + // We dialed out and nobody answered the phone + // + dwDisconnectMode = LINEDISCONNECTMODE_NOANSWER; + break; + + case MDM_NODIALTONE: + // + // We were dialing out but no dial tone on the line + // were we checking for a dialtone? + // + if (DEVST_PORTCONNECTDIALTONEDETECT == pLineDev->DevState && + !(pLineDev->dwDialOptions & MDM_BLIND_DIAL)) + { + lAsyncResult = LINEERR_CALLUNAVAIL; + }; + dwDisconnectMode = LINEDISCONNECTMODE_NODIALTONE; + break; + + case MDM_FAILURE: + default: + // + // The pending operation failed + // + if (DEVST_MANUALDIALING == pLineDev->DevState) { + // + // cancel was pressed on the manual dial dialog + // + dwDisconnectMode = LINEDISCONNECTMODE_CANCELLED; + + } else { + + dwDisconnectMode = LINEDISCONNECTMODE_UNAVAIL; + } + + // If it is a failed makecall, need to return a failure + // + if (pLineDev->dwPendingType == PENDING_LINEMAKECALL) + { + + lAsyncResult = LINEERR_OPERATIONFAILED; + }; + break; + }; + + // No need for further UI + // + DestroyMdmDlgInstance(pLineDev); + + // In any case, we need to notify TAPI to clean up the line + // + NEW_CALLSTATE(pLineDev, LINECALLSTATE_DISCONNECTED, dwDisconnectMode); + NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0); + pLineDev->DevState = DEVST_DISCONNECTED; + + // Notify the caller async completion + // + if (pLineDev->dwPendingID != INVALID_PENDINGID) + { + (*gfnCompletionCallback)(pLineDev->dwPendingID, lAsyncResult); + pLineDev->dwPendingID = INVALID_PENDINGID; + + // If it is a failed makecall, we need to close the line + // + if (pLineDev->dwPendingType == PENDING_LINEMAKECALL) + { + + if ((pLineDev->dwDetMediaModes) && !(pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)) { + + if ((DevlineDetectCall(pLineDev)) != ERROR_SUCCESS) { + // + // init failed, tell the app + // + pLineDev->LineClosed=TRUE; + + (*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 (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE) + { + DevlineDisabled(pLineDev); + } + else +#endif // UNDER_CONSTRUCTION + { + pLineDev->dwPendingType = INVALID_PENDINGOP; + + // Clean up the call state of this line + // + // pLineDev->htCall = NULL; will be cleaned up TSPI_lineClosecall + pLineDev->dwCall = 0L; + }; + } + else + { + pLineDev->dwPendingType = INVALID_PENDINGOP; + }; + }; + } + else + { + // A call has not been allocated but + // We may fail while start monitoring + // + if ((pLineDev->DevState == DEVST_PORTLISTENINIT) || + (pLineDev->DevState == DEVST_PORTLISTENING)) + { + // Notify the monitoring application + // + pLineDev->LineClosed=TRUE; + + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE, + 0L, 0L, 0L); + + } + } + return; +} + +//**************************************************************************** +// DWORD DetectDialtone(PLINEDEV) +// +// Function: detects the dialtone on the phone line if the modem is capable. +// Otherwise assume there is dialtone. +// +// Returns: ERROR_SUCCESS, ERROR_IO_PENDING or an error code +// +//**************************************************************************** + +DWORD DetectDialtone(PLINEDEV pLineDev) +{ + DWORD dwRet; + + // Skip dialtone detection if Manual Dial or Blind Dial or null modem + // + if (!(GETOPTIONS(pLineDev->pDevCfg) & MANUAL_DIAL || + pLineDev->dwDialOptions & MDM_BLIND_DIAL || + IS_NULL_MODEM(pLineDev) || + pLineDev->fPartialDialing == FALSE)) + { + // Start the dialtone detection process + // + dwRet = UnimodemDial(pLineDev, szSemicolon, pLineDev->dwDialOptions); + } + else + { + dwRet = ERROR_SUCCESS; + }; + + return dwRet; +} + +#ifdef UNDER_CONSTRUCTION +//**************************************************************************** +// linWindowProc() +// +// Function: Private message handling proc +// +//**************************************************************************** + +long FAR PASCAL _loadds MdmWindowProc(hWnd, message, wParam, lParam) +HWND hWnd; /* window handle */ +unsigned message; /* type of message */ +WPARAM wParam; /* additional information */ +LPARAM lParam; /* additional information */ +{ + PLINEDEV pLineDev; + + switch (message) + { + //********************************************************************** + // State machine driven notification + //********************************************************************** + + case WM_MDMMESSAGE: + pLineDev = (PLINEDEV)LOWORD(lParam); + + MdmCompleteAsync(pLineDev, wParam, HIWORD(lParam)); + break; + + //********************************************************************** + // line cancellation + //********************************************************************** + + case WM_MDMCANCEL: + pLineDev = (PLINEDEV)LOWORD(lParam); + + // Destroy the termnal window + // + if (IS_UI_DLG_UP(pLineDev, UI_DLG_TERMINAL)) + { + CloseTerminalDlg(pLineDev); + }; + + // Notify the caller async completion + // + if (pLineDev->dwPendingID != INVALID_PENDINGID) + { + (*gfnCompletionCallback)(pLineDev->dwPendingID, 0L); + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + }; + + // Turn off passthrough for the preterminal. + // + if (DEVST_PORTPRETERMINAL == pLineDev->DevState) + { + UnimodemSetPassthrough(pLineDev, PASSTHROUGH_OFF); + } + UnimodemHangup(pLineDev, TRUE); + pLineDev->DevState = DEVST_DISCONNECTED; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0); + break; + + //********************************************************************** + // Notification from PnP for a modem enabling/disabling + //********************************************************************** + + case WM_DEVICECHANGE: + MdmDeviceServiceChanged((UINT)wParam, lParam); + return (DefWindowProc(hWnd, message, wParam, lParam)); + + //********************************************************************** + // Notification from Modem CPL for a modem installation/removal + //********************************************************************** + + case WM_DEVICEINSTALL: + MdmDeviceChangeNotify((UINT)wParam, (LPSTR)lParam); + break; + + //********************************************************************** + // Handle the changes in the modem status + //********************************************************************** + + case WM_MDMCHANGE: + MdmDeviceChanged(wParam, lParam); + break; + + //********************************************************************** + // Ring count timer + //********************************************************************** + + case WM_TIMER: + pLineDev = GetCBfromHandle(MAKELONG(wParam, 0)); // Timer ID is the pLineDev + if(pLineDev) + { + DWORD tcNow = GETTICKCOUNT(); + KillTimer(pLineDev->hwndLine, (UINT)pLineDev); + if (DEVST_PORTLISTENOFFER == pLineDev->DevState && + GTC_DELTA(pLineDev->dwRingTick, tcNow) >= TO_MS_RING_SEPARATION) + { + // Timeout has expired, indicating call has stopped ringing + pLineDev->dwRingTick = 0; + pLineDev->dwRingCount = 0; + pLineDev->DevState = DEVST_PORTLISTENING; + NEW_CALLSTATE(pLineDev, LINECALLSTATE_IDLE, 0); + } + else + { + DPRINTF("WM_TIMER!"); + } + break; + } + + // Fall through + // + default: /* Passes it on if unproccessed */ + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + return (NULL); +} + +//**************************************************************************** +// MdmDeviceServiceChanged() +// +// Function: Handle a device change notification. +// +// Returns: SUCCESS +// PENDING +// ERROR_PORT_DISCONNECTED +// +//**************************************************************************** + +DWORD NEAR PASCAL MdmDeviceServiceChanged (UINT uEvent, LPARAM lParam) +{ + PDEV_BROADCAST_HDR pdbHdr = (PDEV_BROADCAST_HDR)lParam; + PDEV_BROADCAST_PORT pdbp; + + // Determine the event type + // + switch(uEvent) + { + case DBT_DEVICEARRIVAL: + case DBT_DEVICEREMOVECOMPLETE: + // + // Check the device type, must be a port type + // + if (pdbHdr->dbch_devicetype == DBT_DEVTYP_PORT) + { + pdbp = (PDEV_BROADCAST_PORT)pdbHdr; + MdmDeviceChangeNotify( uEvent == DBT_DEVICEARRIVAL ? + UMDM_ENABLE : UMDM_DISABLE, + (LPSTR)pdbp->dbcp_name); + }; + break; + + default: + break; + }; + return SUCCESS; +} +#endif // UNDER_CONSTRUCTION diff --git a/private/unimodem/tapisp/mdmutil.c b/private/unimodem/tapisp/mdmutil.c new file mode 100644 index 000000000..665b65860 --- /dev/null +++ b/private/unimodem/tapisp/mdmutil.c @@ -0,0 +1,1581 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: mdmutil.c +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 6/15/93 Nick Manson Revised OpenModem and CloseModem calls +// 1/6/93 Viroon Touranachun Revised for RNA +// +// +// Description: All Initialization code for rasman component lives here. +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" +#include +#include +#include + +#define STOP_TIMER_EVENT 0 +#define RECALC_TIMER_EVENT 1 +#define TSP_NOTIFICATION_EVENT 2 +#define MAX_TIMER_EVENTS 3 +#define NUM_TIMER_EVENTS(_tlist) (((_tlist).hN)?3:2) + +// Timer list +// +typedef struct tagMdmTimer { + struct tagMdmTimer *pNext; // pointer to next CB + DWORD dwCompletionKey; // for PostQueuedCompletionStatus + LPOVERLAPPED lpOverlapped; // for PostQueuedCompletionStatus + DWORD dwWakeup; // wake-up time +} MDMTIMER, *PMDMTIMER; + +typedef struct tagMdmTimerList { + PMDMTIMER pList; + HANDLE hEvent[MAX_TIMER_EVENTS]; + CRITICAL_SECTION hSem; + HNOTIFICATION hN; + +} TIMERLIST, *PTIMERLIST; + +// LIGHTS application name +// +#define LIGHTSAPP_EXE_NAME TEXT("lights.exe") + +/***************************************************************************** +* Global Parameters +*****************************************************************************/ + +MDMLIST gMdmList; +TIMERLIST gTimerList; +HANDLE ghtdTimer; +DWORD gtidTimerMdm; + +// ******* SOME PRIVATES ************* +void ProcessNotification(HNOTIFICATION hN); +BOOL ValidateFrame(PNOTIFICATION_FRAME pnf, DWORD dwTrueSize); +void ProcessFrame(PNOTIFICATION_FRAME pnf); + +//**************************************************************************** +// BOOL InitCBList() +// +// Function: This function initilaizes the CB list +// +// Returns: TRUE always +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +BOOL InitCBList (HINSTANCE hInstance) +{ + // Initialize the modem list + // + INITCRITICALSECTION(gMdmList.hSem); + gMdmList.pList = NULL; + gMdmList.cModems = 0; + return TRUE; +} + +//**************************************************************************** +// void DeinitCBList() +// +// Function: This function deinitilaizes the CB list +// +// Returns: None +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +void DeinitCBList (HINSTANCE hInstance) +{ + // Do nothing + // + DELETECRITICALSECTION(gMdmList.hSem); + return; +} + +//**************************************************************************** +// BOOL MdmInitTracing() +// +// Function: Performs tracing-related initialization. +// +// Returns: None +// +// 3/29/96 JosephJ Created +//**************************************************************************** +void MdmInitTracing(void) +{ + traceRegisterObject( + &gMdmList, + TSP_MODEM_LIST_GUID, + TSP_MODEM_LIST_VERSION, + 0, + 0 + ); +} + + +//**************************************************************************** +// BOOL MdmDeinitTracing() +// +// Function: Performs tracing-related de-initialization. +// +// Returns: None +// +// 3/29/96 JosephJ Created +//**************************************************************************** +void MdmDeinitTracing(void) +{ + traceUnRegisterObject(&gMdmList, 0, 0); +} + +//**************************************************************************** +// PLINEDEV AllocateCB (UINT cbSize) +// +// Function: Allocates a line device control block +// +// Returns: The pointer to the control block if successful, otherwise NULL. +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV AllocateCB(UINT cbSize) +{ + PLINEDEV pLineDev; + + // Allocate from the process heap + // + pLineDev = (PLINEDEV)LocalAlloc(LPTR, cbSize); + + if (pLineDev == NULL) + return NULL; + + // Ininitialize the initial contents + // + pLineDev->pNext = (PLINEDEV)NULL; + pLineDev->dwVersion = UMDM_VERSION; + INITCRITICALSECTION(pLineDev->hSem); + + return pLineDev; +} + +//**************************************************************************** +// DWORD AddCBToList(PLINEDEV) +// +// Function: Inserts a line control block to the global modem list +// +// Returns: SUCCESS or an error code +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD AddCBToList(PLINEDEV pLineDev) +{ + // Validate the structure + // + if (!ISLINEDEV(pLineDev)) + return ERROR_INVALID_HANDLE; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + + // Insert the new node into the global list + // + pLineDev->pNext = gMdmList.pList; + gMdmList.pList = pLineDev; + gMdmList.cModems++; + + // Release the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD DeleteCB(PLINEDEV pLineDev ) +// +// Function: Removes a line control block to the global modem list and +// deallocate the buffer. +// +// Returns: SUCCESS or an error code +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +DWORD DeleteCB(PLINEDEV pLineDev) +{ + PLINEDEV pCurCB, pPrevCB; + + // Validate the structure + // + if (!ISLINEDEV(pLineDev)) + return ERROR_INVALID_HANDLE; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + + // Start from the head of the CB list + // + pPrevCB = NULL; + pCurCB = gMdmList.pList; + + // traverse the list to find the specified CB + // + while (pCurCB != NULL) + { + if (pCurCB == pLineDev) + { + // Decrement the modem count + // + gMdmList.cModems--; + + // Is there a previous control block? + // + if (pPrevCB == NULL) + { + // head of the list + // + gMdmList.pList = pCurCB->pNext; + } + else + { + pPrevCB->pNext = pCurCB->pNext; + }; + break; + }; + + pPrevCB = pCurCB; + pCurCB = pCurCB->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + + // Wait until no one else is using the line + // + CLAIM_LINEDEV(pLineDev); + DELETECRITICALSECTION(pLineDev->hSem); + LocalFree(pLineDev); + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// PLINEDEV GetFirstCB() +// +// Function: Get the first modem device in the list +// +// Returns: SUCCESS or an error code +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV GetFirstCB() +{ + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + + // Get the next head of the CB list + // + if ((pLineDev = gMdmList.pList) != NULL) + { + CLAIM_LINEDEV(pLineDev); + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + + return pLineDev; +} + +//**************************************************************************** +// PLINEDEV GetCBfromHandle() +// +// Function: This function gets the CB from a handle +// +// Returns: a pointer to PLINEDEV structure if the handle is valid, or +// NULL otherwise +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV GetCBfromHandle (DWORD handle) +{ +#if 0 + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + pLineDev = gMdmList.pList; + + // Walk the modem list to find the line + // + while (pLineDev != NULL) + { + // BUGBUG: Chris Caputo - 1/24/96 + // BUGBUG: pLineDev could be modified as we are scanning. The possibility + // BUGBUG: is that pLineDev->dwVersion gets changed. + if ((pLineDev == (PLINEDEV)handle) && ISLINEDEV(pLineDev)) + { + // Exclusively accessing the line CB + // + CLAIM_LINEDEV(pLineDev); + ASSERT((pLineDev == (PLINEDEV)handle) && ISLINEDEV(pLineDev)); + break; + } + + pLineDev = pLineDev->pNext; + }; + + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + + return pLineDev; + +#endif + + __try { + + PLINEDEV pLineDev; + + pLineDev=(PLINEDEV)handle; + + if (pLineDev->dwVersion == UMDM_VERSION) { + + CLAIM_LINEDEV(pLineDev); + + return pLineDev; + + } + + } __except(EXCEPTION_EXECUTE_HANDLER) { + + + + } + + return NULL; + +} + +//**************************************************************************** +// PLINEDEV GetCBfromID() +// +// Function: This function looks for the CB owning the device +// +// Returns: TRUE (if valid) +// FALSE +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV GetCBfromID (DWORD dwDeviceID) +{ + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + pLineDev = gMdmList.pList; + + // Walk the modem list to find the line + // + while (pLineDev != NULL) + { + // BUGBUG: Chris Caputo - 1/24/96 + // BUGBUG: pLineDev could be modified as we are scanning. The possibility + // BUGBUG: is that pLineDev->dwID gets changed. + if (pLineDev->dwID == dwDeviceID) + { + // Exclusively accessing the line CB + // + CLAIM_LINEDEV(pLineDev); + ASSERT(pLineDev->dwID == dwDeviceID); + break; + } + + pLineDev = pLineDev->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + return pLineDev; +} + +#if 0 + +//**************************************************************************** +// PLINEDEV GetCBfromDeviceHandle() +// +// Function: This function looks for the CB owning the device +// +// Returns: TRUE (if valid) +// FALSE +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV GetCBfromDeviceHandle (DWORD hDevice) +{ + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + pLineDev = gMdmList.pList; + + // Trace the list of modem port control block + // + while (pLineDev != NULL) + { + // BUGBUG: Chris Caputo - 1/24/96 + // BUGBUG: pLineDev could be modified as we are scanning. The possibility + // BUGBUG: is that pLineDev->hDevice gets changed. + if (pLineDev->hDevice == (HANDLE)hDevice) + { + // Exclusively accessing the line CB + // + CLAIM_LINEDEV(pLineDev); + ASSERT(pLineDev->hDevice == (HANDLE)hDevice); + break; + } + + pLineDev = pLineDev->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + return pLineDev; +} + +#endif + +//**************************************************************************** +// PLINEDEV GetCBfromName() +// +// Function: This function looks for the CB owning the device +// +// Returns: TRUE (if valid) +// FALSE +// +// Fri 14-Apr-1995 12:47:57 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +PLINEDEV GetCBfromName (LPTSTR pszName) +{ + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + pLineDev = gMdmList.pList; + + // Trace the list of modem port control block + // + while (pLineDev != NULL) + { + // Exclusively accessing the line CB + // + CLAIM_LINEDEV(pLineDev); + if (!lstrcmp(pLineDev->szDeviceName, pszName)) + break; + + RELEASE_LINEDEV(pLineDev); + pLineDev = pLineDev->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + return pLineDev; +} + +#ifdef DYNA_ADDREMOVE +//**************************************************************************** +// void DisableStaleModems(void) +// +// Function: Disable all modems that do not have the fReinit flag set. +// +// Returns: TRUE (if valid) +// FALSE +// +// 4/24/96 JosephJ Created +//**************************************************************************** +void DisableStaleModems(void) +{ + PLINEDEV pLineDev; + + // Exclusively access the modem list + // + ENTERCRITICALSECTION(gMdmList.hSem); + pLineDev = gMdmList.pList; + + // Trace the list of modem port control block + // + while (pLineDev != NULL) + { + // Exclusively accessing the line CB + // + CLAIM_LINEDEV(pLineDev); + + if (!(pLineDev->fdwResources&LINEDEVFLAGS_REINIT)) + { + DPRINTF1("WARNING: MARKING MODEM OUT-OF-SERVICE: [%s]", + pLineDev->szDeviceName); + pLineDev->fdwResources|= LINEDEVFLAGS_OUTOFSERVICE; + } + else + { + pLineDev->fdwResources&=~LINEDEVFLAGS_REINIT; + pLineDev->fdwResources&=~LINEDEVFLAGS_OUTOFSERVICE; + } + + RELEASE_LINEDEV(pLineDev); + pLineDev = pLineDev->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(gMdmList.hSem); + +} +#endif // DYNA_ADDREMOVE + +//**************************************************************************** +// DWORD NullifyLineDevice(PLINEDEV pLineDev) +// +// Functions: Clean up the contents of the modem CB +// +// Return: ERROR_SUCCESS always +//**************************************************************************** + +DWORD NullifyLineDevice (PLINEDEV pLineDev) +{ + // Turn the line device back to its initiali state + // + pLineDev->fdwResources = 0L; + pLineDev->hDevice = INVALID_DEVICE; + pLineDev->htLine = NULL; + pLineDev->lpfnEvent = NULL; + pLineDev->DevState = DEVST_DISCONNECTED; + pLineDev->szAddress[0] = '\0'; + pLineDev->htCall = NULL; + pLineDev->dwCall = 0L; + pLineDev->dwCallState = LINECALLSTATE_IDLE; + pLineDev->dwCallStateMode = 0L; + pLineDev->dwCurMediaModes = 0L; + pLineDev->dwDetMediaModes = 0L; + pLineDev->fTakeoverMode = FALSE; + pLineDev->dwMediaModes = pLineDev->dwDefaultMediaModes; + pLineDev->dwRingCount = 0L; + pLineDev->dwRingTick = 0L; + pLineDev->dwNegotiatedRate = 0L; + + // Async operation + // + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + pLineDev->dwVxdPendingID = MDM_ID_NULL; + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// BOOL ValidateDevCfgClass(LPCSTR lpszDeviceClass) +// +// Functions: Validate the supported device class +// +// Return: TRUE if the device class is supported +// FALSE otherwise +//**************************************************************************** + +BOOL ValidateDevCfgClass (LPCTSTR lpszDeviceClass) +{ + UINT idClass; + + // Need the device class + // + if (lpszDeviceClass == NULL) + return FALSE; + + // Determine the device class + // + for (idClass = 0; idClass < MAX_SUPPORT_CLASS; idClass++) + { + if (lstrcmpi(lpszDeviceClass, aGetID[idClass].szClassName) == 0) + break; + }; + + // Do we support the requested class? + // + switch (idClass) + { + case TAPILINE: + case COMM: + case COMMMODEM: + case COMMMODEMPORTNAME: + return TRUE; + + default: + return FALSE; + }; +} + +//**************************************************************************** +// ValidateAddress() +// +// Function: This function validates a tapi address and creates a version of +// it to pass to the VxD. In addition, it returns the address in +// ANSI form, rather than Unicode. +// +// Returns: SUCCESS or LINEERR_xxx depending on the failure reason +// +//**************************************************************************** + +LONG ValidateAddress(PLINEDEV pLineDev, +#ifdef UNICODE + LPCTSTR lpszUnicodeInAddress, +#else // UNICODE + LPCSTR lpszInAddress, +#endif // UNICODE + LPSTR lpszOutAddress) +{ + LPCSTR lpszSrc; + int cbOutLen = MAXADDRESSLEN; +#ifdef UNICODE + LPSTR lpszInAddress; // ANSI version of lpszUnicodeInAddress + DWORD dwInAddressLen; // in bytes +#endif // UNICODE + + ASSERT(lpszOutAddress); + +#ifdef UNICODE + // is lpszUnicodeInAddress NULL? + // + if (lpszUnicodeInAddress == NULL || *lpszUnicodeInAddress == 0) + { + *lpszOutAddress = 0; + return ERROR_SUCCESS; + } + + // Convert lpszUnicodeInAddress to lpszInAddress (ANSI) + dwInAddressLen = WideCharToMultiByte(CP_ACP, + 0, + lpszUnicodeInAddress, + -1, + NULL, + 0, + NULL, + NULL); + + if (dwInAddressLen == 0) + { + TSPPRINTF1("ValidateAddress:WideCharToMultiByte returned %d", + GetLastError()); + return LINEERR_INVALADDRESS; + } + + lpszInAddress = (LPSTR)LocalAlloc(LPTR, dwInAddressLen); + + if (lpszInAddress == NULL) + { + TSPPRINTF1("ValidateAddress:WideCharToMultiByte returned %d", + GetLastError()); + return LINEERR_NOMEM; + } + + dwInAddressLen = WideCharToMultiByte(CP_ACP, + 0, + lpszUnicodeInAddress, + -1, + lpszInAddress, + dwInAddressLen, + NULL, + NULL); + + if (dwInAddressLen == 0) + { + TSPPRINTF1("ValidateAddress:WideCharToMultiByte returned %d", + GetLastError()); + LocalFree(lpszInAddress); + return LINEERR_INVALADDRESS; + } +#endif // UNICODE + + // Verify that the first char is a valid single-byte char. + // + if (CharNextA(lpszInAddress) - lpszInAddress != 1) + { +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_INVALADDRESS; + } + + // tone or pulse? set dwDialOptions appropriately + // also, set lpszSrc + // + if (*lpszInAddress == 'T' || *lpszInAddress == 't') // tone + { + lpszSrc = lpszInAddress + 1; + pLineDev->dwDialOptions |= MDM_TONE_DIAL; + } + else + { + if (*lpszInAddress == 'P' || *lpszInAddress == 'p') // pulse + { + lpszSrc = lpszInAddress + 1; + pLineDev->dwDialOptions &= ~MDM_TONE_DIAL; + } + else + { + lpszSrc = lpszInAddress; + } + } + + // copy In to Out scanning for various dialoptions, returning error if we + // don't support something. + // + while (*lpszSrc && cbOutLen) + { + switch (*lpszSrc) + { + case '$': + if (!(pLineDev->dwDevCapFlags & LINEDEVCAPFLAGS_DIALBILLING)) + { + UINT cCommas; + + // Get the wait-for-bong period + // + cCommas = GETWAITBONG(pLineDev->pDevCfg); + + // Calculate the number of commas we need to insert + // + cCommas = (cCommas/INC_WAIT_BONG) + + (cCommas%INC_WAIT_BONG ? 1 : 0); + + // Insert the strings of commas + // + while (cbOutLen && cCommas) + { + *lpszOutAddress++ = ','; + cbOutLen--; + cCommas--; + }; + goto Skip_This_Character; + } + break; + + case '@': + if (!(pLineDev->dwDevCapFlags & LINEDEVCAPFLAGS_DIALQUIET)) + { +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_DIALQUIET; + } + break; + + case 'W': + case 'w': + if (!(pLineDev->dwDevCapFlags & LINEDEVCAPFLAGS_DIALDIALTONE)) + { +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_DIALDIALTONE; + } + break; + + case '?': +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_DIALPROMPT; + + case '|': // subaddress + case '^': // name field + goto Skip_The_Rest; + + case ';': + if (!pLineDev->fPartialDialing) + { +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_INVALADDRESS; + } + + // This signifies the end of a dialable address. + // Use it and skip the rest. + // + *lpszOutAddress++ = *lpszSrc; + goto Skip_The_Rest; + + case ' ': + case '-': + // skip these characters + // + goto Skip_This_Character; + } + + // Copy this character + // + *lpszOutAddress++ = *lpszSrc; + cbOutLen--; + +Skip_This_Character: + // Verify that the next char is a valid single-byte char. + // + if (CharNextA(lpszSrc) - lpszSrc != 1) + { +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_INVALADDRESS; + } + lpszSrc++; + } + + // Did we run out of space in the outgoing buffer? + // + if (*lpszSrc && cbOutLen == 0) + { + // yes + // +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return LINEERR_INVALADDRESS; + } + +Skip_The_Rest: + *lpszOutAddress = 0; +#ifdef UNICODE + LocalFree(lpszInAddress); +#endif // UNICODE + return ERROR_SUCCESS; +} + +//**************************************************************************** +// IsOriginateAddress() +// +// Function: Figures out whether a string is an originate address or not. +// An originate address is one that doesn't have a semi-colon at +// the end. +// +// Note: lpszAddress is not a DBCS string. AnsiNext is not used. +// +// Returns: TRUE if it is an originate address. +// FALSE if it is not. (ie. semi-colon at the end of the address) +// +//**************************************************************************** + +BOOL IsOriginateAddress(LPCSTR lpszAddress) +{ + BOOL fRet = TRUE; // assume this is an originate string + + // try to prove this isn't an originate string by finding a semi-colon + // + while (*lpszAddress) + { + if (';' == *lpszAddress) + { + fRet = FALSE; + break; + } + lpszAddress++; + }; + return fRet; +} + +//**************************************************************************** +// SetMdmTimer(LPOVERLAPPED, DWORD, DWORD) +// +// Function: Set a timer to post to the completion port after the specified +// time elapsed. +// +// Returns: ERROR_SUCCESS if success +// other error code for failure +// +//**************************************************************************** + +DWORD SetMdmTimer (DWORD dwCompletionKey, + LPOVERLAPPED lpOverlapped, + DWORD dwTime) +{ + PMDMTIMER pTimer, pPrev, pNext; + DWORD tcNow = GETTICKCOUNT(); + + ASSERT(dwTimepNext = NULL; + pTimer->dwCompletionKey = dwCompletionKey; + pTimer->lpOverlapped = lpOverlapped; + GTC_AequalsBplusC(pTimer->dwWakeup, tcNow, dwTime); + + // Insert the timer block into the timer list + // +// DPRINTF1("before SetMdmTimer crit sect (%d/%d)", dwCompletionKey, lpOverlapped); + ENTERCRITICALSECTION(gTimerList.hSem); +// DPRINTF1("in SetMdmTimer crit sect (%d/%d)", dwCompletionKey, lpOverlapped); + +#ifdef DEBUG + + pNext = gTimerList.pList; + + while (pNext != NULL) { + + ASSERT(!(pNext->dwCompletionKey == dwCompletionKey && + pNext->lpOverlapped == lpOverlapped)); + + pNext=pNext->pNext; + } + +#endif //DEBUG + + pPrev = NULL; + pNext = gTimerList.pList; + + while(pNext != NULL) + { + if (GTC_AleB(pTimer->dwWakeup, pNext->dwWakeup)) + { + // Found a place to insert + // + pTimer->pNext = pNext; + if (pPrev == NULL) + { + // Head of the list + // + gTimerList.pList = pTimer; + } + else + { + pPrev->pNext = pTimer; + }; + break; + } + else + { + // Next timer block + // + pPrev = pNext; + pNext = pNext->pNext; + }; + }; + + // If we are at the end of the list, append the new timer to the end + // + if (pNext == NULL) + { + if (pPrev == NULL) + { + gTimerList.pList = pTimer; + } + else + { + pPrev->pNext = pTimer; + }; + }; + + // If we insert it in front of the list + // Wake up the timer thread to recalculate the sleep time + // + if (gTimerList.pList == pTimer) + { + SetEvent(gTimerList.hEvent[RECALC_TIMER_EVENT]); + }; + + LEAVECRITICALSECTION(gTimerList.hSem); +// DPRINTF1("after SetMdmTimer crit sect (%d/%d)", dwCompletionKey, lpOverlapped); + + return ERROR_SUCCESS; +} + +//**************************************************************************** +// KillMdmTimer(DWORD, LPOVERLAPPED) +// +// Function: Kill a timer +// +// Returns: TRUE is timeout was found and deleted. +// FLASE if timeout was not found (maybe because it alread fired). +// +//**************************************************************************** + +BOOL KillMdmTimer (DWORD dwCompletionKey, + LPOVERLAPPED lpOverlapped) +{ + PMDMTIMER pCurCB, pPrevCB; + BOOL bRet = FALSE; + +// DPRINTF1("KillMdmTimer entered (%d/%d)", dwCompletionKey, lpOverlapped); + + // Exclusively access the timer list + // + ENTERCRITICALSECTION(gTimerList.hSem); +// DPRINTF1("KillMdmTimer in crit sect (%d/%d)", dwCompletionKey, lpOverlapped); + + // Start from the head of the CB list + // + pPrevCB = NULL; + pCurCB = gTimerList.pList; + + // traverse the list to find the specified CB + // + while (pCurCB != NULL) + { + if (pCurCB->dwCompletionKey == dwCompletionKey && + pCurCB->lpOverlapped == lpOverlapped) + { + bRet = TRUE; + + // Is there a previous control block? + // + if (pPrevCB == NULL) + { + // head of the list + // + gTimerList.pList = pCurCB->pNext; + } + else + { + pPrevCB->pNext = pCurCB->pNext; + }; + LocalFree(pCurCB); + break; + }; + + pPrevCB = pCurCB; + pCurCB = pCurCB->pNext; + }; + +#ifdef DEBUG + if (pCurCB == NULL) + { + D_TRACE(TspDpf(666,TEXT("KillMdmTimer: Did not find event on list.\n"));) +// DPRINTF("KillMdmTimer() did not fine event on its list."); + } +#endif // DEBUG + + // Finish accessing the timer list + // + LEAVECRITICALSECTION(gTimerList.hSem); + +// DPRINTF1("KillMdmTimer exit (%d/%d)", dwCompletionKey/lpOverlapped); + return bRet; +} + +//**************************************************************************** +// DWORD InitializeMdmTimer() +// +// Function: Initialize a timer utility +// +// Returns: ERROR_SUCCESS if success +// other error code for failure +// +//**************************************************************************** + +DWORD InitializeMdmTimer() +{ + // Initialize the timer list critical section + // + INITCRITICALSECTION(gTimerList.hSem); + gTimerList.pList = NULL; + + // Create the recalc event + // + if (gTimerList.hEvent[RECALC_TIMER_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL)) + { + // Create the stop event + // + if (gTimerList.hEvent[STOP_TIMER_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL)) + { + // Create the notification handle and event... + gTimerList.hN = notifCreate(TRUE, SLOTNAME_UNIMODEM_NOTIFY_TSP, + MAX_NOTIFICATION_FRAME_SIZE, 10); + if (!gTimerList.hN) + { + DPRINTF3("WARNING: notifServerCreate(\"%s\", %lu) failed. GetLastError=0x%lx.\n", + (LPCTSTR) SLOTNAME_UNIMODEM_NOTIFY_TSP, + (unsigned long) MAX_NOTIFICATION_FRAME_SIZE, + (unsigned long) GetLastError()); + // Well, we go on, not a fatal error... + } + else + { + gTimerList.hEvent[TSP_NOTIFICATION_EVENT] = + notifGetObj(gTimerList.hN); + ASSERT(gTimerList.hEvent[TSP_NOTIFICATION_EVENT]); + } + // Start the timer thread + // + ghtdTimer = CreateThread( + NULL, // default security + 0, // default stack size + (LPTHREAD_START_ROUTINE)MdmTimerThread, // thread entry point + NULL, // no parameter + 0, // Start immediately + >idTimerMdm); // thread id + + if (ghtdTimer) + { + // We started the timer services + // + + // Register the timer list with the + // tracing system. + traceRegisterObject( + &gTimerList, + TSP_TIMER_LIST_GUID, + TSP_TIMER_LIST_VERSION, + 0, + 0 + ); + return ERROR_SUCCESS; + }; + }; + }; + + // Cannot start the timer, clean up resources + // + + if (gTimerList.hN) + { + // the notification event is owned by the notif object, hN, so we don't + // CloseHandle it here. + gTimerList.hEvent[TSP_NOTIFICATION_EVENT]=NULL; + notifFree(gTimerList.hN); + gTimerList.hN=0; + } + + if (gTimerList.hEvent[STOP_TIMER_EVENT]) + { + CloseHandle(gTimerList.hEvent[STOP_TIMER_EVENT]); + }; + + if (gTimerList.hEvent[RECALC_TIMER_EVENT]) + { + CloseHandle(gTimerList.hEvent[RECALC_TIMER_EVENT]); + }; + + DELETECRITICALSECTION(gTimerList.hSem); + return ERROR_OUTOFMEMORY; +} + +//**************************************************************************** +// DWORD DeinitializeMdmTimer() +// +// Function: Deinitialize a timer utility +// +// Returns: ERROR_SUCCESS if success +// other error code for failure +// +//**************************************************************************** + +DWORD DeinitializeMdmTimer() +{ + // Un-register the timer list with the + // tracing system. + traceUnRegisterObject(&gTimerList, 0, 0); + + // Signal the stop event + // + SetEvent(gTimerList.hEvent[STOP_TIMER_EVENT]); + + // Wait until the the timer thread terminates + // + WaitForSingleObject(ghtdTimer, INFINITE); + + // + // close thread handle + // + CloseHandle(ghtdTimer); + + // Destroy the notification object, if we allocated it... + if (gTimerList.hN) + { + // the notification event is owned by the notif object, hN. + gTimerList.hEvent[TSP_NOTIFICATION_EVENT]=NULL; + notifFree(gTimerList.hN); + gTimerList.hN=0; + } + // Destroy the recalc and the stop events + // + CloseHandle(gTimerList.hEvent[STOP_TIMER_EVENT]); + CloseHandle(gTimerList.hEvent[RECALC_TIMER_EVENT]); + + // Deinitialize the timer list critical section + // + DELETECRITICALSECTION(gTimerList.hSem); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD APIENTRY MdmTimerThread(DWORD) +// +// Function: timer thread +// +// Returns: None +// +//**************************************************************************** + +DWORD APIENTRY MdmTimerThread(DWORD dwParam) +{ + DWORD dwWait; + + // Start waiting for the new timer infinitely + // + dwWait = INFINITE; + + // Wait for the recalc event for the specified time + // + while (TRUE) + { + switch (WaitForMultipleObjects(NUM_TIMER_EVENTS(gTimerList), + gTimerList.hEvent, FALSE, dwWait)) + { + // If the waittime is expired, some timer block needs to wake up + // + case WAIT_TIMEOUT: + { + PMDMTIMER pTimer, pNext; + DWORD dwCurrent; + + ENTERCRITICALSECTION(gTimerList.hSem); + + dwCurrent = GETTICKCOUNT(); + + // Start signalling from the head of the list + // + pNext = gTimerList.pList; + + while(pNext && GTC_AleB(pNext->dwWakeup, dwCurrent)) + { +// DPRINTF1("MdmTimerThread queuing %d/%d", pNext->dwCompletionKey, pNext->lpOverlapped); + PostQueuedCompletionStatus(ghCompletionPort, + 1, + pNext->dwCompletionKey, + pNext->lpOverlapped); + pTimer = pNext; + pNext = pTimer->pNext; + LocalFree(pTimer); + }; + + // Recalculate the wait time + // If nothing is in the list, the wake time is infinite + // + if (pNext) + { + dwWait = GTC_DELTA(dwCurrent, pNext->dwWakeup); + } + else + { + dwWait = INFINITE; + }; + + gTimerList.pList = pNext; + LEAVECRITICALSECTION(gTimerList.hSem); + break; + } + + // If it is the recalc event + // we need to recalc the wait time from the head of the list + // + case WAIT_OBJECT_0+RECALC_TIMER_EVENT: + { + DWORD dwCurrent; + + ENTERCRITICALSECTION(gTimerList.hSem); + + dwCurrent = GETTICKCOUNT(); + + if (gTimerList.pList + && GTC_AleB(dwCurrent, gTimerList.pList->dwWakeup)) + { + dwWait = GTC_DELTA(dwCurrent,gTimerList.pList->dwWakeup); + } + else + { + dwWait = 0; + }; + LEAVECRITICALSECTION(gTimerList.hSem); + break; + } + + case WAIT_OBJECT_0+TSP_NOTIFICATION_EVENT: + { + + ENTERCRITICALSECTION(gTimerList.hSem); + ProcessNotification(gTimerList.hN); + LEAVECRITICALSECTION(gTimerList.hSem); + break; + } + + // Otherwise terminate the timer thread + // + case WAIT_OBJECT_0+STOP_TIMER_EVENT: + { + PMDMTIMER pNextTimer, pTimer; + + // Free all the timer block + // + pNextTimer = gTimerList.pList; + while(pNextTimer) + { + pTimer = pNextTimer; + pNextTimer = pTimer->pNext; + LocalFree(pTimer); + }; + gTimerList.pList = NULL; + + ExitThread(ERROR_SUCCESS); + return ERROR_SUCCESS; + } + + default: + DPRINTF("Got unknown notification!\n"); + break; + }; + }; +} + +//**************************************************************************** +// DWORD LaunchModemLight (LPTSTR szModemName, HANDLE hModem, LPHANDLE lphLight) +// +// Function: Lauch the modem lights applet +// +// Returns: ERROR_SUCCESS if success otherwise ERROR_OPEN_FAILED +// +//****************************************************************************/ + +DWORD LaunchModemLight (LPTSTR szModemName, HANDLE hModem, LPHANDLE lphLight) +{ + HANDLE hEvent; + PROCESS_INFORMATION pi; + STARTUPINFO sti; + TCHAR szCmdline[256]; + SERIALPERF_STATS serialstats; + DWORD dwBytes; + DWORD dwRet; + OVERLAPPED ov; + + // Check to see if any bytes have been transferred or receive. If none + // has, there is no need to launch lights because this is probably a + // port driver that doesn't support this ioctl. + // + ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + if (ov.hEvent == NULL) + { + return ERROR_OPEN_FAILED; + } + + ov.hEvent = (HANDLE)((DWORD)ov.hEvent | 1); + + dwRet = DeviceIoControl(hModem, + IOCTL_SERIAL_GET_STATS, + &serialstats, + sizeof(SERIALPERF_STATS), + &serialstats, + sizeof(SERIALPERF_STATS), + &dwBytes, + &ov); + + if (!dwRet) + { + if (ERROR_IO_PENDING == GetLastError()) + { + dwRet = GetOverlappedResult(hModem, + &ov, + &dwBytes, + TRUE); + } + } + + ov.hEvent = (HANDLE)((DWORD)ov.hEvent & 0xfffffffe); + CloseHandle(ov.hEvent); + + + + if (!dwRet || + (serialstats.ReceivedCount == 0 && + serialstats.TransmittedCount == 0)) + { + return ERROR_OPEN_FAILED; + } + + + // OK, the GET_STATS ioctl seems to work, so let's really launch lights. + + + // Create the lights shutdown event handle. + if ((hEvent = CreateEvent( NULL, FALSE, FALSE, NULL )) != NULL) + { + // Create a global handle for use in other processes and close the + // local handle. + *lphLight = hEvent; + + // Compose a modem lights process command line + // + wsprintf( szCmdline, LIGHTSAPP_EXE_NAME TEXT(" %lu %lu %lu %s"), + GetCurrentProcessId(), hEvent, hModem, szModemName ); + + // Create the modem lights process and store ID for use in CloseModem. + ZeroMemory(&sti, sizeof(sti)); + sti.cb = sizeof(STARTUPINFO); + if ( !CreateProcess(NULL, szCmdline, // Start up command line + NULL, NULL, FALSE, 0, NULL, NULL, &sti, &pi) ) + { + DPRINTF1("LaunchModemLight: CreateProcess failed (%d).", + GetLastError()); + + CloseHandle(hEvent); + *lphLight = (DWORD)NULL; + + return ERROR_OPEN_FAILED; + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + DPRINTF("LaunchModemLight: Succeeded."); + return ERROR_SUCCESS; + } + DPRINTF1("LaunchModemLight: CreateEvent failed (%d).", + GetLastError()); + return ERROR_OPEN_FAILED; +} + +//**************************************************************************** +// DWORD TerminateModemLight (HANDLE hLight) +// +// Function: Terminate the modem lights applet +// +// Returns: ERROR_SUCCESS always +// +//**************************************************************************** + +DWORD TerminateModemLight (HANDLE hLight) +{ + SetEvent(hLight); + CloseHandle(hLight); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// Function: Processes an external TSP notification +// (produced as a result of some process loading unimdm.tsp and +// calling UnimodemNotifyTSP(...)) +// WARNING: This function is called with the timer critical section still +// held -- better return quickly! +//**************************************************************************** +void ProcessNotification(HNOTIFICATION hN) +{ + BOOL fRet; + struct { + DWORD dw0; + BYTE rgb[MAX_NOTIFICATION_FRAME_SIZE]; + } EmptyFr; + PNOTIFICATION_FRAME pnf = (PNOTIFICATION_FRAME) &EmptyFr; + DWORD dwcbMax=sizeof(EmptyFr); + DWORD dwcbRead=0; + + pnf->dwSig=pnf->dwSize=0; + + fRet=notifReadMsg(hN, (LPBYTE) pnf, dwcbMax, &dwcbRead); + if (!fRet) + { + DPRINTF1("notifReadFrame(...) failed. GetLastError=0x%lx.\n", + (unsigned long) GetLastError()); + goto end; + } + + // Verify validity of msg... + if (!ValidateFrame(pnf, dwcbRead)) + { + DPRINTF("Invalid frame\n"); + goto end; + } + ProcessFrame(pnf); + +end: + return; +} + + +//**************************************************************************** +// Function: Validates a frame -- checks signature, etc... +//**************************************************************************** +BOOL ValidateFrame(PNOTIFICATION_FRAME pnf, DWORD dwTrueSize) +{ + return (pnf && pnf->dwSig==dwNFRAME_SIG && pnf->dwSize>=sizeof(*pnf) && + pnf->dwSize==dwTrueSize && + pnf->dwSize<=MAX_NOTIFICATION_FRAME_SIZE); +} + + +//**************************************************************************** +// Function: Processes a received notification frame +// (received as a result of some process loading unimdm.tsp and +// calling UnimodemNotifyTSP(...)) +// WARNING: This function is called with the timer critical section still +// held -- better return quickly! +//**************************************************************************** +void ProcessFrame(PNOTIFICATION_FRAME pnf) +{ + void cplProcessNotification(PNOTIFICATION_FRAME pnf); + + switch(pnf->dwType) + { + + case TSPNOTIF_TYPE_CPL: + DPRINTF("ProcessFrame: Got CPL notification!\n"); + cplProcessNotification(pnf); + break; + case TSPNOTIF_TYPE_DEBUG: + DPRINTF("ProcessFrame: Got DEBUG notifcation.\n"); + traceProcessNotification(pnf); + break; + default: + DPRINTF1("WARNING:Got unknown notif type 0x%lu.\n", pnf->dwType); + break; + } +} diff --git a/private/unimodem/tapisp/modem.c b/private/unimodem/tapisp/modem.c new file mode 100644 index 000000000..2cc5d42db --- /dev/null +++ b/private/unimodem/tapisp/modem.c @@ -0,0 +1,532 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: modem.c +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 6/15/93 Nick Manson Modified OpenModem and CloseModem calls +// 1/6/93 Viroon Touranachun Revised for RNA +// +// +// Description: Intermediate modem SPI layer +// +//**************************************************************************** + + +#include "unimdm.h" +#include "umdmspi.h" + +#ifdef UNDER_CONSTRUCTION + +#include + +#define Not_VxD +#include +#include + +#endif // UNDER_CONSTRUCTION + + + + + +//**************************************************************************** +// LONG DevlineOpen(PLINEDEV) +// +// Function: Opens the modem device. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_ALLOCATED if the modem was already opened +// LINEERR_RESOURCEUNAVAIL if the modem cannot be opened +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineOpen (PLINEDEV pLineDev) +{ + LPCOMMCONFIG lpComConfig; + DWORD dwRet; + + // The line must be closed + // + if (pLineDev->hDevice != INVALID_DEVICE) + return LINEERR_ALLOCATED; + + ASSERT(pLineDev->pDevCfg != NULL); + + // Nullify the terminal window + // + STOP_UI_DLG (pLineDev, UI_DLG_TERMINAL); + + pLineDev->LineClosed=FALSE; + + // Open the modem port + // + lpComConfig = (LPCOMMCONFIG)&(pLineDev->pDevCfg->commconfig); + dwRet = OpenModem(pLineDev, (LPBYTE)lpComConfig, lpComConfig->dwSize); + + // If we successfully opened the modem, reinitialize the rest of the CB + // + if (dwRet == ERROR_SUCCESS) + { + // The modem is just opened, it is not connected + // + pLineDev->DevState = DEVST_DISCONNECTED; + + } + else + { + dwRet = LINEERR_RESOURCEUNAVAIL; + }; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineDetectCall(PLINEDEV) +// +// Function: Starts the modem to monitor a call. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_OPERATIONFAILED if the modem fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineDetectCall(PLINEDEV pLineDev) +{ + DWORD dwRet; + + switch (pLineDev->DevState) + { + // Do nothing if listening in progress + // + case DEVST_PORTLISTENINIT: + case DEVST_PORTLISTENING: + dwRet = ERROR_SUCCESS; + break; + + // If the modem is not started, start listening + // + case DEVST_DISCONNECTED: + // + // If the privilege is to own an inbound call, start listening now + // First Initialize modem + // + pLineDev->DevState = DEVST_PORTLISTENINIT; + + switch (UnimodemInit(pLineDev)) + { + case ERROR_SUCCESS: + ASSERT(0); // We do not expect a success return + + case ERROR_IO_PENDING: + dwRet = ERROR_SUCCESS; + break; + + default: + pLineDev->DevState = DEVST_DISCONNECTED; + dwRet = LINEERR_OPERATIONFAILED; + break; + }; + break; + + default: + dwRet = LINEERR_OPERATIONFAILED; + }; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineMakeCall(PLINEDEV) +// +// Function: Dial M for modem. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_OPERATIONFAILED if the modem fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineMakeCall(PLINEDEV pLineDev) +{ + DWORD dwRet; + + // If we need a UI, start a dialog instance here + // + if ((GETOPTIONS(pLineDev->pDevCfg) & (TERMINAL_PRE | TERMINAL_POST | MANUAL_DIAL)) || + (LINEMEDIAMODE_INTERACTIVEVOICE == pLineDev->dwCurMediaModes)) + { + CreateMdmDlgInstance(pLineDev); + }; + + // If pre-dial terminal mode is set, go to terminal mode + // + if (GETOPTIONS(pLineDev->pDevCfg) & TERMINAL_PRE) + { + switch (pLineDev->DevState) + { + case DEVST_PORTLISTENINIT: + + pLineDev->DevState = DEVST_PORTSTARTPRETERMINAL; + + return pLineDev->dwPendingID; + + case DEVST_PORTLISTENING: + + Sleep(100); + + case DEVST_DISCONNECTED: + + pLineDev->DevState = DEVST_PORTSTARTPRETERMINAL; + + if (MdmAsyncContinue(pLineDev, MDM_SUCCESS) == ERROR_SUCCESS) + { + return pLineDev->dwPendingID; + }; + + default: + DestroyMdmDlgInstance(pLineDev); + return LINEERR_OPERATIONFAILED; + }; + }; + + + + // Start dialing procedure + // + switch (pLineDev->DevState) + { + + case DEVST_PORTLISTENINIT: + // + // Wait until the current modem initialization to finish, + // then start dialing automatically. + // + pLineDev->DevState = DEVST_PORTCONNECTINIT; + dwRet = pLineDev->dwPendingID; + break; + + + case DEVST_PORTLISTENING: + // + // The modem is listening. It was already initialized. + // Stop monitoring immediately. + // When the monitoring stops, it will start dialing automatically. + // + + // + // BUGBUG: To prevent the init or dial strings from stomping the + // monitor command, we will wait briefly here + // + // + Sleep(100); + + if (pLineDev->InitStringsAreValid) { + + pLineDev->DevState = DEVST_PORTCONNECTINIT; + dwRet = pLineDev->dwPendingID; + MdmAsyncContinue (pLineDev, MDM_SUCCESS); + break; + + } + // + // LineSetDevConfig was called and changes the settings, need to rebuild the + // init strings to reflect this + // + // + // Fall on through + // + // + + case DEVST_DISCONNECTED: + + // The modem is disconnected. Initialize it before dialing. + // + pLineDev->DevState = DEVST_PORTCONNECTINIT; + + switch (UnimodemInit(pLineDev)) + { + case ERROR_SUCCESS: + ASSERT(0); // We do not expect a success return + + case ERROR_IO_PENDING: + dwRet = pLineDev->dwPendingID; + break; + + default: + pLineDev->DevState = DEVST_DISCONNECTED; + DestroyMdmDlgInstance(pLineDev); + dwRet = LINEERR_OPERATIONFAILED; + break; + }; + break; + + default: + dwRet = LINEERR_OPERATIONFAILED; + }; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineDial(PLINEDEV) +// +// Function: Dial M for modem. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_OPERATIONFAILED if the modem fails +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineDial(PLINEDEV pLineDev) +{ + DWORD dwRet; + + // Kick start the modem state machine + // + if (MdmAsyncContinue(pLineDev, MDM_SUCCESS) != ERROR_SUCCESS) + { + dwRet = LINEERR_OPERATIONFAILED; + } + else + { + dwRet = ERROR_SUCCESS; + }; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineAnswer (PLINEDEV) +// +// Function: Answer an offered call. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_INVALCALLSTATE if the call was not offerred. +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineAnswer (PLINEDEV pLineDev) +{ + DWORD dwRet; + + if (pLineDev->DevState != DEVST_PORTLISTENOFFER) + return LINEERR_INVALCALLSTATE; + + // Kill RING timer + KillMdmTimer((DWORD)pLineDev, NULL); + + // Advance the call state and return pending + // + pLineDev->DevState = DEVST_PORTLISTENANSWER; + + // Get modem to answer the call + // + switch (UnimodemAnswer(pLineDev)) + { + case ERROR_SUCCESS: + ASSERT(0); // We do not expect a success return + + case ERROR_IO_PENDING: + dwRet = pLineDev->dwPendingID; + break; + + default: + dwRet = LINEERR_OPERATIONFAILED; + break; + }; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineDrop (PLINEDEV, BOOL) +// +// Function: Disconnect the call synchronous or asynchronously. +// +// Returns: ERROR_SUCCESS if success +// LINEERR_INVALCALLSTATE if the call was not offerred. +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineDrop (PLINEDEV pLineDev, BOOL fSync) +{ + DWORD dwRet; + + // Synchronously terminate all the dangling UI windows + // + DestroyTalkDropDialog(pLineDev); + DestroyManualDialog(pLineDev); + DestroyTerminalDialog(pLineDev); + DestroyMdmDlgInstance(pLineDev); + + // Do we need to do a hangup? + // + if (LINECALLSTATE_IDLE == pLineDev->dwCallState && + DEVST_DISCONNECTED == pLineDev->DevState) + { + // The call is idle and the modem is disconnected, + // just notify the completion. + // + (*(gfnCompletionCallback))(pLineDev->dwPendingID, 0L); + pLineDev->dwPendingID = INVALID_PENDINGID; + pLineDev->dwPendingType = INVALID_PENDINGOP; + dwRet = ERROR_SUCCESS; + } + else + { + if (pLineDev->DevState == DEVST_CONNECTED) { + + // Cancel the outstanding remote disconnection detection + // + UnimodemCancelMonitorDisconnect(pLineDev); + } + + if (DEVST_PORTLISTENOFFER == pLineDev->DevState) { + // + // the call was offered and then droped without answering, need to kill timer + // + KillMdmTimer((DWORD)pLineDev, NULL); + } + + + if (DEVST_DISCONNECTING == pLineDev->DevState) { + + TSPPRINTF("DevLineDrop: re-entered, waiting for drop to complete"); + + RELEASE_LINEDEV(pLineDev); + + WaitForSingleObject( + pLineDev->DroppingEvent, + 30*1000 + ); + + CLAIM_LINEDEV(pLineDev); + + TSPPRINTF("DevLineDrop: re-entered, Done waiting"); + + dwRet = ERROR_SUCCESS; + + } else { + + TSPPRINTF1( + "DevLineDrop: Warning. DevState was %lu. Forcing to DISCONNECTING", + pLineDev->DevState + ); + + // + // 7/12/96 JosephJ BUGBUG + // We will simply clobber any existing command being sent out here, + // because we call UnimodemHangup which eventually cancels any pending + // I/O and calls purgecomm. End result is that the command being + // sent out can get truncated and the next command we send out gets + // concatenated to the previously-truncated command. Sometimes this + // results in ATE0V1 (truncated to AT) being combined with ATZ to + // form ATATZ, causing some modems to go off hook. + // + // Fix will to fix the state diagram so that previously executing + // commands are allowed to complete and response to be properly + // read. However this is a hack workaround in the (fSync) case... + // We sleep. + // We specifically exclude those states which are known to be OK + // (no pending I/O.) + if (fSync) + { + switch (pLineDev->DevState) + { + case DEVST_PORTLISTENING: // Fall through + case DEVST_PORTLISTENOFFER: // Fall through + case DEVST_PORTCONNECTWAITFORLINEDIAL: // Fall through + case DEVST_PORTCONNECTING: // Fall through + case DEVST_DISCONNECTED: // Fall through + case DEVST_CONNECTED: // Do Nothing. + break; + + default: + Sleep(150); + break; + } + } + + pLineDev->DevState = DEVST_DISCONNECTING; + + ResetEvent( + pLineDev->DroppingEvent + ); + + // Make a direct call to unimodem to drop the line + // + switch (UnimodemHangup(pLineDev, fSync)) + { + case ERROR_SUCCESS: + pLineDev->DevState = DEVST_DISCONNECTED; + case ERROR_IO_PENDING: + dwRet = ERROR_SUCCESS; + break; + + default: + ASSERT(0); // This should not happen whatsoever!!! + pLineDev->DevState = DEVST_DISCONNECTED; + dwRet = LINEERR_OPERATIONFAILED; + break; + }; + }; + }; + + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineClose (PLINEDEV) +// +// Function: Close the modem. +// +// Returns: ERROR_SUCCESS always +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineClose (PLINEDEV pLineDev) +{ + // If the device is listening, we need to drop the line first + // + if (pLineDev->DevState != DEVST_DISCONNECTED) + { + DevlineDrop(pLineDev, TRUE); + }; + + DestroyMdmDlgInstance(pLineDev); + + // Close the comm port + // + if (pLineDev->hDevice != INVALID_DEVICE) + { + if(pLineDev->hLights != NULL) + { + TerminateModemLight(pLineDev->hLights); + pLineDev->hLights = NULL; + }; + + CloseModem(pLineDev); + pLineDev->hDevice = INVALID_DEVICE; + }; + + return ERROR_SUCCESS ; +} diff --git a/private/unimodem/tapisp/ov_pool.c b/private/unimodem/tapisp/ov_pool.c new file mode 100644 index 000000000..be32d95b3 --- /dev/null +++ b/private/unimodem/tapisp/ov_pool.c @@ -0,0 +1,234 @@ +/****************************************************************************** + + Overlapped Structure Pool + + Functions for managing a pool of overlapped structs + + (C) Copyright MICROSOFT Corp., 1987-1996 + +******************************************************************************/ + +#include "unimdm.h" +#include "umdmspi.h" + +/* + Structure definitions + */ + +typedef struct tagOverList { + LPOVERNODE lpList; + CRITICAL_SECTION hSem; +#ifdef DEBUG + DWORD dwNumInUse; + DWORD dwNumAllocated; +#endif // DEBUG +} OVERLIST, *LPOVERLIST; + + +/* + Global Variables + */ + +OVERLIST gOverList; + + +/* + * BOOL OverPoolInit() + * + * Function: This function initializes the overlapped pool list + * + * Returns: TRUE always + */ +BOOL OverPoolInit() +{ + INITCRITICALSECTION(gOverList.hSem); + + ENTERCRITICALSECTION(gOverList.hSem); + + gOverList.lpList = NULL; + +#ifdef DEBUG + gOverList.dwNumInUse = 0; + gOverList.dwNumAllocated = 0; +#endif // DEBUG + + LEAVECRITICALSECTION(gOverList.hSem); + + return TRUE; +} + + +/* + * BOOL OverPoolDeinit() + * + * Function: This function deinitializes the overlapped pool list + * + * Returns: None + */ +void OverPoolDeinit() +{ + LPOVERNODE lpOverNode, lpOverNodeNext; + + ENTERCRITICALSECTION(gOverList.hSem); + +#ifdef DEBUG + if (gOverList.dwNumInUse != 0) + { + DPRINTF("OverPoolDeinit() called when gOverList.dwNumInUse != 0"); + ASSERT(0); + } + + DPRINTF1("Total number of overlapped nodes allocated = %d", + gOverList.dwNumAllocated); +#endif // DEBUG + + lpOverNode = gOverList.lpList; + + while (lpOverNode) + { + lpOverNodeNext = lpOverNode->lpNext; + + LocalFree(lpOverNode); + + lpOverNode = lpOverNodeNext; + } + + gOverList.lpList = NULL; + + LEAVECRITICALSECTION(gOverList.hSem); + DELETECRITICALSECTION(gOverList.hSem); +} + + +/* + * BOOL OverPoolInitTracing() + * + * Function: Performs tracing-related initialization. + * + * Returns: None + */ +void OverPoolInitTracing(void) +{ + traceRegisterObject( + &gOverList, + TSP_OVER_LIST_GUID, + TSP_OVER_LIST_VERSION, + 0, + 0 + ); +} + + +/* + * BOOL OverPoolDeinitTracing() + * + * Function: Performs tracing-related de-initialization. + * + * Returns: None + */ +void OverPoolDeinitTracing(void) +{ + traceUnRegisterObject(&gOverList, 0, 0); +} + + +/* + * BOOL OverPoolAlloc() + * + * Function: This function returns a pointer to an overlapped structure. + * The structure will be zeroed. The reference count will be + * set to what is passed in. This will indicate how many times + * OverPoolFree will need to be called to actually free the struct. + * + * Returns: pointer to an overlapped struct on success or NULL on failure + */ +LPOVERLAPPED OverPoolAlloc(DWORD dwToken, DWORD dwRefCount) +{ + LPOVERNODE lpOverNode; + + ENTERCRITICALSECTION(gOverList.hSem); + + if (gOverList.lpList != NULL) + { + // Remove from the free list + lpOverNode = gOverList.lpList; + gOverList.lpList = lpOverNode->lpNext; + ZeroMemory(lpOverNode, sizeof(OVERNODE)); + } + else + { + // Allocated zeroed memory. + lpOverNode = LocalAlloc(LPTR, sizeof(OVERNODE)); +#ifdef DEBUG + if (lpOverNode == NULL) + { + DPRINTF1("LocalAlloc() in OverPoolAlloc() failed = %d", + GetLastError()); + } + else + { + gOverList.dwNumAllocated++; + } +#endif // DEBUG + + } + + if (lpOverNode) + { + //DPRINTF2("OverPoolAlloc(refcount=%d) = %0.8x", dwRefCount, lpOverNode); + + lpOverNode->dwToken = dwToken; + lpOverNode->dwRefCount = dwRefCount; + +#ifdef DEBUG + gOverList.dwNumInUse++; +#endif // DEBUG + } + + LEAVECRITICALSECTION(gOverList.hSem); + + return (LPOVERLAPPED)lpOverNode; +} + + +/* + * BOOL OverPoolFree() + * + * Function: This function returns an overlapped structure to the free list. + * + * Returns: TRUE always + */ +void OverPoolFree(LPOVERLAPPED lpOverlapped) +{ + LPOVERNODE lpOverNode = (LPOVERNODE)lpOverlapped; + + ENTERCRITICALSECTION(gOverList.hSem); + + //DPRINTF1("OverPoolFree() = %0.8x", lpOverNode); + + lpOverNode->dwRefCount--; + + if (lpOverNode->dwRefCount == 0) + { + // Add to the free list + lpOverNode->lpNext = gOverList.lpList; + gOverList.lpList = lpOverNode; + +#ifdef DEBUG + + lpOverNode->Type=(DWORD)-1; + + if (gOverList.dwNumInUse == 0) + { + DPRINTF("OverPoolFree() called to free more than allocated!"); + ASSERT(0); + } + else + { + gOverList.dwNumInUse--; + } +#endif // DEBUG + } + + LEAVECRITICALSECTION(gOverList.hSem); +} diff --git a/private/unimodem/tapisp/rcids.h b/private/unimodem/tapisp/rcids.h new file mode 100644 index 000000000..36d72242b --- /dev/null +++ b/private/unimodem/tapisp/rcids.h @@ -0,0 +1,75 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: rcids.h +// Content: This file contain all the declaration for device setting +// resource ID +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// History: +// Wed 15-Jun-1993 10:38:00 -by- Nick Manson [t-nickm] +// Fri 09-Apr-1993 14:41:01 -by- Viroon Touranachun [viroont] +// +//**************************************************************************** + +#ifndef _RCIDS_ +#define _RCIDS_ + +#define MAXTITLE 32 +#define MAXMESSAGE 256 + +//***************************************************************************** +// Icon ID number section +//***************************************************************************** + +#define IDI_ICON 100 +#define IDI_NULL 101 +#define IDI_EXT_MDM 102 +#define IDI_INT_MDM 103 +#define IDI_PCM_MDM 104 + +// Terminal Mode Setting +// +#define IDD_TERMINALSETTING 1000 +#define IDC_TERMINAL_PRE (IDD_TERMINALSETTING) +#define IDC_TERMINAL_POST (IDD_TERMINALSETTING+1) +#define IDC_MANUAL_DIAL (IDD_TERMINALSETTING+2) +#define IDC_LAUNCH_LIGHTS (IDD_TERMINALSETTING+3) +#define IDC_TERMINALGRP (IDD_TERMINALSETTING+4) +#define IDC_MANUAL_DIALGRP (IDD_TERMINALSETTING+5) +#define IDC_LAUNCH_LIGHTSGRP (IDD_TERMINALSETTING+6) +#define IDC_WAIT_TEXT (IDD_TERMINALSETTING+7) +#define IDC_WAIT_SEC (IDD_TERMINALSETTING+8) +#define IDC_WAIT_SEC_ARRW (IDD_TERMINALSETTING+9) +#define IDC_WAIT_UNIT (IDD_TERMINALSETTING+10) +#define IDC_PHONENUMBER (IDD_TERMINALSETTING+11) + +#define IDD_TERMINALDLG 1150 +#define CID_T_EB_SCREEN (IDD_TERMINALDLG) +#define CID_T_PB_ENTER (IDD_TERMINALDLG+1) + +// Talk Drop Dialog +// +#define IDD_TALKDROP 1300 +#define IDTALK (IDD_TALKDROP) +#define IDDROP (IDD_TALKDROP+1) + +// Manual Dial Dialog +// +#define IDD_MANUAL_DIAL 1400 +#define IDCONNECT (IDD_MANUAL_DIAL) + +// Resources +// +#define ID_STRING_BASE 100 +#define ID_PROVIDER_INFO ID_STRING_BASE+0 +#define IDS_PRETERM_TITLE ID_STRING_BASE+1 +#define IDS_POSTTERM_TITLE ID_STRING_BASE+2 + +#define IDS_ERR_TITLE 1000 +#define IDS_ERR_INSTALLED IDS_ERR_TITLE+1 +#define IDS_ERR_INV_WAIT IDS_ERR_TITLE+2 + + +#endif //_RCIDS_ diff --git a/private/unimodem/tapisp/resource.h b/private/unimodem/tapisp/resource.h new file mode 100644 index 000000000..bd8776be1 --- /dev/null +++ b/private/unimodem/tapisp/resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resource.rc +// +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/private/unimodem/tapisp/resource.rc b/private/unimodem/tapisp/resource.rc new file mode 100644 index 000000000..10cee01f9 --- /dev/null +++ b/private/unimodem/tapisp/resource.rc @@ -0,0 +1,324 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "commctrl.h" +#include "winver.h" +#include "ntverp.h" +#include "rcids.h" +#include "logids.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_NULL ICON DISCARDABLE "..\\resource\\nullmdm.ico" +IDI_EXT_MDM ICON DISCARDABLE "..\\resource\\modem.ico" +IDI_INT_MDM ICON DISCARDABLE "..\\resource\\internal.ico" +IDI_PCM_MDM ICON DISCARDABLE "..\\resource\\pcmcia.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_TERMINALSETTING DIALOG DISCARDABLE 0, 0, 212, 188 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU +CAPTION "Options" +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Connection control",IDC_TERMINALGRP,10,10,192,54 + CONTROL "Bring up terminal window &before dialing", + IDC_TERMINAL_PRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 25,25,150,10 + CONTROL "Bring up terminal window a&fter dialing", + IDC_TERMINAL_POST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 25,42,150,10 + GROUPBOX "Dial control",IDC_MANUAL_DIALGRP,10,74,192,57 + CONTROL "Operator assisted or &manual dial",IDC_MANUAL_DIAL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,90,150,10 + LTEXT "&Wait for credit card tone:",IDC_WAIT_TEXT,25,108,79,8 + EDITTEXT IDC_WAIT_SEC,107,107,25,12,ES_RIGHT | WS_GROUP + CONTROL "",IDC_WAIT_SEC_ARRW,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + WS_BORDER | WS_GROUP,120,107,12,12 + LTEXT "seconds",IDC_WAIT_UNIT,136,108,29,8 + GROUPBOX "Status control",IDC_LAUNCH_LIGHTSGRP,10,141,192,37 + CONTROL "Display modem &status",IDC_LAUNCH_LIGHTS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,25,157,115,10 +END + +IDD_TERMINALDLG DIALOG DISCARDABLE 0, 0, 251, 180 +STYLE DS_ABSALIGN | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "Terminal Mode" +FONT 8, "MS Shell Dlg" +BEGIN + EDITTEXT CID_T_EB_SCREEN,8,8,235,140,ES_MULTILINE | WS_VSCROLL | + WS_HSCROLL + DEFPUSHBUTTON "Enter",CID_T_PB_ENTER,8,8,50,14,NOT WS_VISIBLE + PUSHBUTTON "Co&ntinue",IDOK,58,155,54,14 + PUSHBUTTON "&Cancel",IDCANCEL,125,155,54,14 +END + +IDD_TALKDROP DIALOG DISCARDABLE 20, 15, 210, 90 +STYLE DS_ABSALIGN | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Call Status" +FONT 8, "MS Shell Dlg" +BEGIN + ICON IDI_EXT_MDM,-1,10,10,18,20 + LTEXT "Lift the receiver and click Talk.",-1,42,10,158,11 + LTEXT "To disconnect, click Hang Up and replace the receiver.", + -1,42,26,145,16 + DEFPUSHBUTTON "&Talk",IDTALK,94,66,51,14 + PUSHBUTTON "Hang &Up",IDDROP,150,66,50,14 +END + +IDD_MANUAL_DIAL DIALOG DISCARDABLE 20, 15, 210, 90 +STYLE DS_ABSALIGN | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Operator Assisted or Manual Dial" +FONT 8, "MS Shell Dlg" +BEGIN + ICON IDI_EXT_MDM,IDC_STATIC,10,10,18,20 + LTEXT "Pick up the handset and dial (or ask the operator to dial). Press OK immediately after dialing, then replace the handset.\n", + IDC_STATIC,42,9,157,24 + DEFPUSHBUTTON "&OK",IDCONNECT,94,66,51,14 + PUSHBUTTON "Cancel",IDCANCEL,150,66,50,14 + LTEXT "Phone Number:",IDC_STATIC,42,43,50,8 + LTEXT "",IDC_PHONENUMBER,97,43,105,8 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""commctrl.h""\r\n" + "#include ""winver.h""\r\n" + "#include ""ntverp.h""\r\n" + "#include ""rcids.h""\r\n" + "#include ""logids.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGERR_FAILED_VOICE_WAVEOPEN "ERROR: Failed Wave Open.\r\n" + IDS_MSGERR_FAILED_VOICE_WAVECLOSE "ERROR: Failed Wave Close.\r\n" + ID_PROVIDER_INFO "Windows Telephony Service Provider for Universal Modem Driver" + IDS_PRETERM_TITLE "Pre-Dial Terminal Screen" + IDS_POSTTERM_TITLE "Post-Dial Terminal Screen" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_ERR_TITLE "Modem Settings" + IDS_ERR_INSTALLED "Universal Modem Service Provider needs to be installed only once." + IDS_ERR_INV_WAIT "The wait period is invalid or out of range.\nRe-enter a new number." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_OK "OK" + IDS_RESP_INFORMATIVE "Informative" + IDS_RESP_CONNECT "Connect" + IDS_RESP_ERROR "Error" + IDS_RESP_NO_CARRIER "No Carrier" + IDS_RESP_NO_DIALTONE "No Dialtone" + IDS_RESP_BUSY "Busy" + IDS_RESP_NO_ANSWER "No Answer" + IDS_RESP_RING "Ring" + IDS_RESP_SSV "SSV" + IDS_RESP_SMD "SMD" + IDS_RESP_SFA "SFA" + IDS_RESP_SRA "SRA" + IDS_RESP_SRQ "SRQ" + IDS_RESP_SRC "SRC" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_STO "STO" + IDS_RESP_SVM "SVM" + IDS_RESP_DRON "DRON" + IDS_RESP_DROF "DROF" + IDS_RESP_DATE "DATE" + IDS_RESP_TIME "TIME" + IDS_RESP_NMBR "NMBR" + IDS_RESP_NAME "NAME" + IDS_RESP_MESG "MESG" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_RESP_UNKNOWN "Unknown Response\r\n" + IDS_MSGLOG_CONNECTED "Connection established.\r\n" + IDS_MSGLOG_CONNECTEDBPS "Connection established at %dbps.\r\n" + IDS_MSGLOG_UNKNOWNERRORCONTROL "Error-control off or unknown.\r\n" + IDS_MSGLOG_CELLULAR "Cellular error-control on.\r\n" + IDS_MSGLOG_ERRORCONTROL "Error-control on.\r\n" + IDS_MSGLOG_COMPRESSION "Data compression on.\r\n" + IDS_MSGLOG_UNKNOWNCOMPRESSION "Data compression off or unknown.\r\n" + IDS_MSGPERF_WRDESC "Bytes sent to modem per second.\r\n" + IDS_MSGPERF_WRNAME "Bytes sent/sec\r\n" + IDS_MSGPERF_WRREG "SendRate\r\n" + IDS_MSGPERF_RDDESC "Bytes received from modem per second.\r\n" + IDS_MSGPERF_RDNAME "Bytes received/sec\r\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGPERF_RDREG "ReceiveRate\r\n" + IDS_MSGPERF_UNITS "Bytes\r\n" + IDS_MSGLOG_STATISTICS "Session Statistics:\r\n" + IDS_MSGLOG_READSTATS " Reads : %d bytes\r\n" + IDS_MSGLOG_WRITESTATS " Writes: %d bytes\r\n" + IDS_MSGLOG_FRAMEERRORSTATS " Frame Errors: %d\r\n" + IDS_MSGLOG_SERIALOVERRUNERRORSTATS "Serial Overrun Errors: %d\r\n" + IDS_MSGLOG_BUFFEROVERRUNERRORSTATS "Buffer Overrun Errors: %d\r\n" + IDS_MSGLOG_PARITYERRORSTATS " Parity Errors: %d\r\n" + IDS_MSGERR_FAILED_INITSTRINGCONSTRUCTION + "ERROR: Init string construction failed.\r\n" + IDS_MSGERR_FAILED_INIT "ERROR: Init failed.\r\n" + IDS_MSGERR_FAILED_DIALSTRINGCONSTRUCTION + "ERROR: Dial string construction failed for '%s'.\r\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGERR_FAILED_DIAL "ERROR: Dial failed.\r\n" + IDS_MSGERR_FAILED_MONITOR "ERROR: Monitor failed.\r\n" + IDS_MSGERR_FAILED_ANSWER "ERROR: Answer failed.\r\n" + IDS_MSGERR_FAILED_HANGUP "ERROR: Hangup failed.\r\n" + IDS_MSGERR_FAILED_FLUSH "ERROR: Unable to send command to the device.\r\n" + IDS_MSGERR_FAILED_RESPONSE + "ERROR: Unable to recover from unrecognized response.\r\n" + IDS_MSGERR_FAILED_VOICE_ANSWER "ERROR: Voice Answer failed.\r\n" + IDS_MSGERR_FAILED_VOICE_DIALSETUP "ERROR: Voice dial setup failed.\r\n" + IDS_MSGERR_FAILED_VOICE_COMMAND "ERROR: Voice Command failed. %s\r\n" + IDS_MSGERR_FAILED_VOICE_STARTWAVE + "ERROR: Start wave play/record failed.\r\n" + IDS_MSGERR_FAILED_VOICE_STOPWAVE + "ERROR: Stop wave play/record failed.\r\n" + IDS_MSGERR_FAILED_VOICE_SETFORMAT + "ERROR: Failed to set wave foramt.\r\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGERR_FAILED_VOICE_SPEAKERPHONECOMMAND + "ERROR: Speaker Phaone Command Failed.\r\n" + IDS_MSGERR_FAILED_VOICE_GENERATEDTMF "ERROR: Generate DTMF failed.\r\n" + IDS_MSGWARN_UNRECOGNIZEDRESPONSE + "WARNING: Unrecognized response. Retrying...\r\n" + IDS_MSGWARN_FAILEDTOQUERYVALUE + "WARNING: Unable to load the '%s' string.\r\n" + IDS_MSGWARN_FAILEDDTRDROPPAGE + "WARNING: The modem did not respond to lowering DTR. Trying software hangup...\r\n" + IDS_MSGWARN_PREVIOUSCONNECTIONNOTHUNGUP + "WARNING: A previous program left a connection established. Hanging up previous connection...\r\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGLOG_OPENED "%s in use.\r\n" + IDS_MSGLOG_DRIVERDESC "Modem type: %s\r\n" + IDS_MSGLOG_INFPATH "Modem inf path: %s\r\n" + IDS_MSGLOG_INFSECTION "Modem inf section: %s\r\n" + IDS_MSGLOG_CLOSED "Modem closed.\r\n" + IDS_MSGLOG_DIAL "Dialing.\r\n" + IDS_MSGLOG_MONITOR "Waiting for a call.\r\n" + IDS_MSGLOG_ANSWER "Answering the call.\r\n" + IDS_MSGLOG_INIT "Initializing modem.\r\n" + IDS_MSGLOG_HANGUP "Hanging up the modem.\r\n" + IDS_MSGLOG_VOICE_ANSWER "Answering the voice call.\r\n" + IDS_MSGLOG_VOICE_DIALSETUP "Setup to dial voice call.\r\n" + IDS_MSGLOG_VOICE_COMMAND "Issueing voice command.\r\n" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSGLOG_VOICE_STARTWAVE "Starting wave play/record.\r\n" + IDS_MSGLOG_VOICE_STOPWAVE "Ending wave play/record.\r\n" + IDS_MSGLOG_VOICE_SETWAVEFORMAT "Setting wave format.\r\n" + IDS_MSGLOG_VOICE_WAVEOPEN "Voice Modem Wave Open.\r\n" + IDS_MSGLOG_VOICE_WAVECLOSE "Voice Modem Wave Close.\r\n" + IDS_MSGLOG_VOICE_SPEAKERPHONECOMMAND + "Issueing Speakerphone command.\r\n" + IDS_MSGLOG_VOICE_GENTERAEDTMF "Generating DTMF.\r\n" + IDS_MSGLOG_VOICE_DLERECEIVED "Received DLE Raw=%d, Translated=%d.\r\n" + IDS_MSGLOG_HARDWAREHANGUP "Hardware hangup by lowering DTR.\r\n" + IDS_MSGLOG_REMOTEHANGUP "Remote modem hung up.\r\n" + IDS_MSGLOG_COMMAND "Send: %s\r\n" + IDS_MSGLOG_RAWRESPONSE "Recv: %s\r\n" + IDS_MSGLOG_EMPTYRESPONSE "\r\n" + IDS_MSGLOG_RESPONSE "Interpreted response: %s\r\n" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/private/unimodem/tapisp/sources b/private/unimodem/tapisp/sources new file mode 100644 index 000000000..994dbf9cc --- /dev/null +++ b/private/unimodem/tapisp/sources @@ -0,0 +1,82 @@ +!IF 0 + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +Author: + + John Rogers (JohnRo) 25-Oct-1991 + +NOTE: Commented description of this file is in \nt\public\oak\bin\sources.tpl + +Revision History: + +!ENDIF + +ROOT=..\.. +MAJORCOMP=net +MINORCOMP=tapi + +TARGETNAME=unimdm +TARGETPATH=obj +TARGETTYPE=DYNLINK +TARGETEXT=TSP + +TARGETLIBS=$(_NTDRIVE)\nt\public\sdk\lib\*\kernel32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\gdi32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\user32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\advapi32.lib \ + $(_NTDRIVE)\nt\public\sdk\lib\*\setupapi.lib \ + ..\lib\*\rovcomm.lib + +DLLBASE=0x69000000 + +INCLUDES=.;..\inc; + +C_DEFINES=-DWIN32 -DWINNT -D_WIN32 -DWINVER=0x0400 + +USE_MSVCRT=1 + +SOURCES=common.c \ + log.c \ + unimdm.c \ + mdmutil.c \ + modem.c \ + devioctl.c \ + mdmasyn.c \ + mcxstate.c \ + mcxutil.c \ + mcxapi.c \ + mcxrw.c \ + wndthrd.c \ + cfgdlg.c \ + terminal.c \ + talkdrop.c \ + manual.c \ + umdminit.c \ + debug.c \ + ov_pool.c \ + tracing.c \ + unimdm.rc + +UMTYPE=windows + +DLLENTRY=_DllMainCRTStartup + +PRECOMPILED_INCLUDE=unimdm.h +PRECOMPILED_PCH=unimdmp.pch +PRECOMPILED_OBJ=unimdmp.obj + +!IFNDEF 386_WARNING_LEVEL +386_WARNING_LEVEL=/W3 +!ENDIF diff --git a/private/unimodem/tapisp/talkdrop.c b/private/unimodem/tapisp/talkdrop.c new file mode 100644 index 000000000..025598634 --- /dev/null +++ b/private/unimodem/tapisp/talkdrop.c @@ -0,0 +1,137 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: talkdrop.c +// +// Copyright (c) 1992-1994, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 2/28/94 Chris Caputo Created +// +// +// Description: Talk drop dialog, as found in the ATSP +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" +#include "wndthrd.h" +#include "rcids.h" + +//**************************************************************************** +// Function prototypes +//**************************************************************************** + +LRESULT TalkDropDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam); + +//**************************************************************************** +// HWND CreateTalkDropDlg(HWND hwndOwner, DWORD idLine) +// +// Function: creates a modeless talk/drop dialog box +// +// Returns: the modeless window handle +// +//**************************************************************************** + +HWND CreateTalkDropDlg(HWND hwndOwner, DWORD idLine) +{ + HWND hwnd; + + // Create dialog + // + hwnd = CreateDialogParam(ghInstance, + MAKEINTRESOURCE(IDD_TALKDROP), + hwndOwner, + TalkDropDlgProc, + (LPARAM)idLine); + return hwnd; +} + +//**************************************************************************** +// LRESULT TalkDropDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam) +// +// Function: Talk-Drop dialog routine +// +// Returns: varies +// +//**************************************************************************** + +LRESULT TalkDropDlgProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) +{ + DWORD idLine; + + switch(wMsg) + { + case WM_INITDIALOG: + + // remember the hLineDev passed in + // + SetWindowLong(hwnd, DWL_USER, (LONG)lParam); + return 1; + break; + + case WM_COMMAND: + { + UINT idCmd=GET_WM_COMMAND_ID(wParam, lParam); + TUISPIDLLCALLBACK Callback; + // + // One of the buttons (Talk/Drop) is pressed + // + if (idCmd == IDTALK || idCmd == IDDROP || idCmd == IDCANCEL) + { + DLGREQ DlgReq; + PDLGNODE pDlgNode; + + pDlgNode= (PDLGNODE)GetWindowLong(hwnd, DWL_USER); + + idLine = pDlgNode->idLine; + + // Make a direct call to unimodem to drop the line + // + DlgReq.dwCmd = UI_REQ_HANGUP_LINE; + DlgReq.dwParam = 0; + + Callback=GetCallbackProc(pDlgNode->Parent); + + (*Callback)(idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&DlgReq, sizeof(DlgReq)); + + // Return the result + // + EndMdmDialog(pDlgNode->Parent,idLine, TALKDROP_DLG, + (idCmd == IDTALK) ? MDM_SUCCESS : MDM_HANGUP); + return 1; + break; + } + break; + } + + case WM_DESTROY: + { + TUISPIDLLCALLBACK Callback; + DLGREQ DlgReq; + + PDLGNODE pDlgNode; + + pDlgNode= (PDLGNODE)GetWindowLong(hwnd, DWL_USER); + + idLine = pDlgNode->idLine; + + + DlgReq.dwCmd = UI_REQ_END_DLG; + DlgReq.dwParam = TALKDROP_DLG; + + Callback=GetCallbackProc(pDlgNode->Parent); + + (*Callback)(idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&DlgReq, sizeof(DlgReq)); + break; + } + default: + break; + }; + + return 0; +} diff --git a/private/unimodem/tapisp/terminal.c b/private/unimodem/tapisp/terminal.c new file mode 100644 index 000000000..6993434ed --- /dev/null +++ b/private/unimodem/tapisp/terminal.c @@ -0,0 +1,890 @@ +//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright 1993-1996 Microsoft Corporation. All Rights Reserved. +// +// MODULE: terminal.c +// +// PURPOSE: Terminal screen simulation +// +// FUNCTIONS: +// CreateTerminalDlg() +// TerminalDlgWndProc() +// TerminalScreenWndProc() +// OnCommand() +// GetInput() +// SendCharacter() +// AdjustTerminal() +// TerminalThread() +// + +#include "unimdm.h" // includes common header files and global declarations +#include "umdmspi.h" // includes common header files and global declarations +#include "wndthrd.h" // includes UI declarations +#include "rcids.h" // includes the resource definitions + +//**************************************************************************** +// Constants Declaration +//**************************************************************************** + +#define MAXTITLE 32 +#define MAXMESSAGE 256 + +#define WM_MODEMNOTIFY (WM_USER + 998) +#define WM_EOLFROMDEVICE (WM_USER + 999) + +#define SIZE_ReceiveBuf 1024 +#define SIZE_SendBuf 1 + +#define Y_MARGIN 4 +#define X_SPACING 2 +#define MIN_X 170 +#define MIN_Y 80 + +#define TERMINAL_BK_COLOR (RGB( 0, 0, 0 )) +#define TERMINAL_FR_COLOR (RGB( 255, 255, 255 )) +#define MAXTERMLINE 24 + +#define READ_EVENT 0 +#define STOP_EVENT 1 +#define MAX_EVENT 2 + +//**************************************************************************** +// Type Definitions +//**************************************************************************** + +typedef struct tagTERMDLG { + HANDLE hport; + HANDLE hThread; + HANDLE hEvent[MAX_EVENT]; + HWND hwnd; + PBYTE pbyteReceiveBuf; + PBYTE pbyteSendBuf; + HBRUSH hbrushScreenBackground; + HFONT hfontTerminal; + WNDPROC WndprocOldTerminalScreen; + DWORD idLine; + HWND ParenthWnd; +} TERMDLG, *PTERMDLG, FAR* LPTERMDLG; + +//**************************************************************************** +// Function prototypes +//**************************************************************************** + +LRESULT FAR PASCAL TerminalDlgWndProc(HWND hwnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam ); +LRESULT FAR PASCAL TerminalScreenWndProc(HWND hwnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam ); +BOOL NEAR PASCAL OnCommand (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL NEAR PASCAL GetInput (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +VOID NEAR PASCAL SendCharacter( HWND hwnd, BYTE byte ); +VOID NEAR PASCAL AdjustTerminal (HWND hwnd, int wWidth, int wHeight); +void WINAPI TerminalThread (PTERMDLG pTerminaldialog); + +//**************************************************************************** +// HWND CreateTerminalDlg(HWND hwndOwner, DWORD idLine) +// +// Function: creates a modeless terminal dialog box +// +// Returns: the modeless window handle +// +//**************************************************************************** + +HWND CreateTerminalDlg(HWND hwndOwner, DWORD idLine) +{ + HANDLE hComm; + HWND hwnd; + COMMTIMEOUTS commtimeout; + PTERMDLG pTerminaldialog; + DWORD id; + int i; + int iRet; + TERMREQ TermReq; + + TUISPIDLLCALLBACK Callback; + + Callback=GetCallbackProc(hwndOwner); + + // Get the terminal parameters + // + TermReq.DlgReq.dwCmd = UI_REQ_TERMINAL_INFO; + TermReq.DlgReq.dwParam = GetCurrentProcessId(); + + (*Callback)(idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&TermReq, sizeof(TermReq)); + hComm = TermReq.hDevice; + + // Allocate the terminal buffer + // + if ((pTerminaldialog = (PTERMDLG)LocalAlloc(LPTR, sizeof(*pTerminaldialog))) + == NULL) + return NULL; + + if ((pTerminaldialog->pbyteReceiveBuf = (PBYTE)LocalAlloc(LMEM_FIXED, + SIZE_ReceiveBuf + + SIZE_SendBuf)) + == NULL) + { + LocalFree((HLOCAL)pTerminaldialog); + return NULL; + }; + pTerminaldialog->pbyteSendBuf = pTerminaldialog->pbyteReceiveBuf + SIZE_ReceiveBuf; + + // Initialize the terminal buffer + // + pTerminaldialog->ParenthWnd= hwndOwner; + pTerminaldialog->hport = hComm; + pTerminaldialog->idLine = idLine; + pTerminaldialog->hbrushScreenBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); + pTerminaldialog->hfontTerminal = (HFONT)GetStockObject( SYSTEM_FIXED_FONT ); + + // Start receiving from the port + // + commtimeout.ReadIntervalTimeout = MAXDWORD; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = 0; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 1000; + SetCommTimeouts(hComm, &commtimeout); + + SetCommMask(hComm, EV_RXCHAR); + + if (TermReq.dwTermType == TERMINAL_PRE) { + +#define ECHO_OFF "ATE1\r" + + COMMTIMEOUTS commtimeout; + HANDLE hEvent; + + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + + if (hEvent != NULL) { + + DWORD cb; + OVERLAPPED ov; + BOOLEAN bResult; + + ov.Offset = 0; + ov.OffsetHigh = 0; + + // OR with 1 to prevent it from being posted to the completion port. + // + ov.hEvent = (HANDLE)((DWORD)hEvent | 1); + + bResult=WriteFile( + hComm, + ECHO_OFF, + sizeof(ECHO_OFF)-1, + &cb, + &ov + ); + + + if (!bResult) { + + DWORD dwResult = GetLastError(); + + if (ERROR_IO_PENDING == dwResult) { + + GetOverlappedResult( + hComm, + &ov, + &cb, + TRUE + ); + } + } + + CloseHandle(hEvent); + } + } + + + // Create read thread and the synchronization objects + for (i = 0; i < MAX_EVENT; i++) + { + pTerminaldialog->hEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + }; + + pTerminaldialog->hThread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) TerminalThread, + pTerminaldialog, 0, &id); + + // Create the terminal window + hwnd = CreateDialogParam(ghInstance, + MAKEINTRESOURCE(IDD_TERMINALDLG), + hwndOwner, + (DLGPROC)TerminalDlgWndProc, + (LPARAM)pTerminaldialog); + + if (IsWindow(hwnd)) + { + TCHAR szTitle[MAXTITLE]; + + // Set window caption + // + LoadString (ghInstance, + (TermReq.dwTermType == TERMINAL_POST)? + IDS_POSTTERM_TITLE : IDS_PRETERM_TITLE, + szTitle, sizeof(szTitle)); + SetWindowText(hwnd, szTitle); + } + else + { + // The terminal dialog was terminalted, free resources + // + SetEvent(pTerminaldialog->hEvent[STOP_EVENT]); + + SetCommMask(hComm, 0); + WaitForSingleObject(pTerminaldialog->hThread, INFINITE); + CloseHandle(pTerminaldialog->hThread); + + for (i = 0; i < MAX_EVENT; i++) + { + CloseHandle(pTerminaldialog->hEvent[i]); + }; + + LocalFree((HLOCAL)pTerminaldialog->pbyteReceiveBuf); + LocalFree((HLOCAL)pTerminaldialog); + + hwnd = NULL; + }; + + return hwnd; +} + + +/*---------------------------------------------------------------------------- +** Terminal Window Procedure +**---------------------------------------------------------------------------- +*/ + +LRESULT FAR PASCAL TerminalDlgWndProc(HWND hwnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam ) +{ + PTERMDLG pTerminaldialog; + HWND hwndScrn; + RECT rect; + + switch (wMsg) + { + case WM_INITDIALOG: + pTerminaldialog = (PTERMDLG)lParam; + SetWindowLong(hwnd, DWL_USER, (LONG)lParam); + SetForegroundWindow(hwnd); + pTerminaldialog->hwnd = hwnd; + + // Install subclassed WndProcs. + // + hwndScrn = GetDlgItem(hwnd, CID_T_EB_SCREEN); + pTerminaldialog->WndprocOldTerminalScreen = + (WNDPROC)SetWindowLong( hwndScrn, GWL_WNDPROC, + (LONG)TerminalScreenWndProc ); + + // Set the terminal screen font + // + SendMessage(hwndScrn, WM_SETFONT, (WPARAM)pTerminaldialog->hfontTerminal, + 0L); + + // Adjust the dimension + // + GetClientRect(hwnd, &rect); + AdjustTerminal(hwnd, rect.right-rect.left, rect.bottom-rect.top); + + // Start receiving from the port + // + PostMessage(hwnd, WM_MODEMNOTIFY, 0, 0); + + // Set the input focus to the screen + // + SetFocus(hwndScrn); + return 0; + + case WM_CTLCOLOREDIT: + { + pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER); + + /* Set terminal screen colors to TTY-ish green on black. + */ + if (pTerminaldialog->hbrushScreenBackground) + { + SetBkColor( (HDC)wParam, TERMINAL_BK_COLOR ); + SetTextColor((HDC)wParam, TERMINAL_FR_COLOR ); + + return (LRESULT)pTerminaldialog->hbrushScreenBackground; + } + + break; + }; + + case WM_MODEMNOTIFY: + return GetInput(hwnd, wMsg, wParam, lParam); + + case WM_COMMAND: + + // Handle the control activities + // + return OnCommand(hwnd, wMsg, wParam, lParam); + + case WM_DESTROY: + { + DLGREQ DlgReq; + int i; + TUISPIDLLCALLBACK Callback; + + pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER); + SetWindowLong( GetDlgItem(hwnd, CID_T_EB_SCREEN), GWL_WNDPROC, + (LONG)pTerminaldialog->WndprocOldTerminalScreen ); + + // Destroy the dialog + // + DlgReq.dwCmd = UI_REQ_END_DLG; + DlgReq.dwParam = TERMINAL_DLG; + + Callback=GetCallbackProc(pTerminaldialog->ParenthWnd); + + (*Callback)(pTerminaldialog->idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&DlgReq, sizeof(DlgReq)); + + // The terminal dialog was terminated, free resources + // + SetEvent(pTerminaldialog->hEvent[STOP_EVENT]); + + if (pTerminaldialog->hport != NULL) + { + SetCommMask(pTerminaldialog->hport, 0); + }; + + if (pTerminaldialog->hThread != NULL) + { + WaitForSingleObject(pTerminaldialog->hThread, INFINITE); + CloseHandle(pTerminaldialog->hThread); + }; + CloseHandle(pTerminaldialog->hport); + + for (i = 0; i < MAX_EVENT; i++) + { + CloseHandle(pTerminaldialog->hEvent[i]); + }; + + LocalFree((HLOCAL)pTerminaldialog->pbyteReceiveBuf); + LocalFree((HLOCAL)pTerminaldialog); + break; + } + case WM_SIZE: + AdjustTerminal(hwnd, (int)LOWORD(lParam), (int)HIWORD(lParam)); + break; + + case WM_GETMINMAXINFO: + { + MINMAXINFO FAR* lpMinMaxInfo = (MINMAXINFO FAR*)lParam; + DWORD dwUnit = GetDialogBaseUnits(); + + lpMinMaxInfo->ptMinTrackSize.x = (MIN_X*LOWORD(dwUnit))/4; + lpMinMaxInfo->ptMinTrackSize.y = (MIN_Y*LOWORD(dwUnit))/4; + break; + }; + }; + + return 0; +} + +/*---------------------------------------------------------------------------- +** Terminal Screen Subclasses Window Procedure +**---------------------------------------------------------------------------- +*/ + +LRESULT FAR PASCAL TerminalScreenWndProc(HWND hwnd, + UINT wMsg, + WPARAM wParam, + LPARAM lParam ) +{ + HWND hwndParent; + PTERMDLG pTerminaldialog; + + hwndParent = GetParent(hwnd); + pTerminaldialog = (PTERMDLG)GetWindowLong(hwndParent, DWL_USER); + + if (wMsg == WM_EOLFROMDEVICE) + { + /* Remove the first line if the next line exceeds the maximum line + */ + if (SendMessage(hwnd, EM_GETLINECOUNT, 0, 0L) == MAXTERMLINE) + { + SendMessage(hwnd, EM_SETSEL, 0, + SendMessage(hwnd, EM_LINEINDEX, 1, 0L)); + SendMessage(hwnd, EM_REPLACESEL, 0, (LPARAM)(LPTSTR)TEXT("")); + SendMessage(hwnd, EM_SETSEL, 32767, 32767); + SendMessage(hwnd, EM_SCROLLCARET, 0, 0); + }; + + /* An end-of-line in the device input was received. Send a linefeed + ** character to the window. + */ + wParam = '\n'; + wMsg = WM_CHAR; + } + else + { + BOOL fCtrlKeyDown = (GetKeyState( VK_CONTROL ) < 0); + BOOL fShiftKeyDown = (GetKeyState( VK_SHIFT ) < 0); + + if (wMsg == WM_KEYDOWN) + { + /* The key was pressed by the user. + */ + if (wParam == VK_RETURN && !fCtrlKeyDown && !fShiftKeyDown) + { + /* Enter key pressed without Shift or Ctrl is discarded. This + ** prevents Enter from being interpreted as "press default + ** button" when pressed in the edit box. + */ + return 0; + } + + if (fCtrlKeyDown && wParam == VK_TAB) + { + /* Ctrl+Tab pressed. Send a tab character to the device. + ** Pass tab thru to let the edit box handle the visuals. + ** Ctrl+Tab doesn't generate a WM_CHAR. + */ + SendCharacter( hwndParent, (BYTE )VK_TAB ); + } + + if (GetKeyState( VK_MENU ) < 0) + { + return (CallWindowProc(pTerminaldialog->WndprocOldTerminalScreen, hwnd, wMsg, wParam, lParam )); + }; + } + else if (wMsg == WM_CHAR) + { + /* The character was typed by the user. + */ + if (wParam == VK_TAB) + { + /* Ignore tabs...Windows sends this message when Tab (leave + ** field) is pressed but not when Ctrl+Tab (insert a TAB + ** character) is pressed...weird. + */ + return 0; + } + +#ifdef UNICODE + { + CHAR chAnsi; + + if (WideCharToMultiByte(CP_ACP, + 0, + (LPWSTR)&wParam, + 1, + &chAnsi, + 1, + NULL, + NULL)) + { + SendCharacter( hwndParent, (BYTE )chAnsi ); + } + } +#else // UNICODE + SendCharacter( hwndParent, (BYTE )wParam ); +#endif // UNICODE + + return 0; + } + } + + /* Call the previous window procedure for everything else. + */ + return (CallWindowProc(pTerminaldialog->WndprocOldTerminalScreen, hwnd, wMsg, wParam, lParam )); +} + +/*---------------------------------------------------------------------------- +** Terminal Window's Control Handler +**---------------------------------------------------------------------------- +*/ + +BOOL NEAR PASCAL OnCommand (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (GET_WM_COMMAND_ID(wParam, lParam)) + { + case CID_T_EB_SCREEN: + { + switch (HIWORD(wParam)) + { + case EN_SETFOCUS: + { + /* Turn off the default button whenever the terminal + ** window has the focus. Pressing [Return] in the + ** terminal acts like a normal terminal. + */ + SendDlgItemMessage(hwnd, CID_T_PB_ENTER, BM_SETSTYLE, + (WPARAM)BS_DEFPUSHBUTTON, TRUE); + + /* Don't select the entire string on entry. + */ + SendDlgItemMessage(hwnd, CID_T_EB_SCREEN, EM_SETSEL, + 32767, 32767); + SendMessage(hwnd, EM_SCROLLCARET, 0, 0); + break; + }; + }; + + break; + }; + + case IDOK: + case IDCANCEL: + { + PTERMDLG pTerminaldialog; + + pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER); + EndMdmDialog(pTerminaldialog->ParenthWnd,pTerminaldialog->idLine, TERMINAL_DLG, + (GET_WM_COMMAND_ID(wParam, lParam) == IDOK) ? + MDM_SUCCESS : MDM_HANGUP); + break; + } + }; + return 0; +} + + +/*---------------------------------------------------------------------------- +** Terminal Input Handler +**---------------------------------------------------------------------------- +*/ + +BOOL NEAR PASCAL GetInput (HWND hwnd, + UINT usMsg, + WPARAM wParam, + LPARAM lParam ) +{ + PTERMDLG pTerminaldialog; + DWORD cbRead; + OVERLAPPED ov; + HANDLE hEvent; + COMMTIMEOUTS commtimeout; + + pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER); + + if ((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + { + return FALSE; + } + + // Set write timeout to one second + // + commtimeout.ReadIntervalTimeout = MAXDWORD; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = 0; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 1000; + SetCommTimeouts(pTerminaldialog->hport, &commtimeout); + + do + { + /* Make sure we still have the comm port + */ + if (pTerminaldialog->hport == NULL) + break; + + /* A character has been received from the device. + */ + ov.Internal = 0; + ov.InternalHigh = 0; + ov.Offset = 0; + ov.OffsetHigh = 0; + ov.hEvent = (HANDLE)((DWORD)hEvent | 1); + + cbRead = 0; + + if (FALSE == ReadFile(pTerminaldialog->hport, + pTerminaldialog->pbyteReceiveBuf, + SIZE_ReceiveBuf, (LPDWORD)&cbRead, &ov)) + { + DWORD dwResult = GetLastError(); + + if (ERROR_IO_PENDING == dwResult) + { + GetOverlappedResult(pTerminaldialog->hport, + &ov, + &cbRead, + TRUE); + } + else + { + DPRINTF1("ReadFile() in GetInput() failed (0x%8x)!", dwResult); + } + }; + + SetEvent(pTerminaldialog->hEvent[READ_EVENT]); + + /* Send the device talk to the terminal edit box. + */ + if (cbRead != 0) + { + char szBuf[ SIZE_ReceiveBuf + 1 ]; +#ifdef UNICODE + WCHAR szUnicodeBuf[ SIZE_ReceiveBuf + 1 ]; +#endif // UNICODE + LPSTR pch = szBuf; + int i, cb; + HWND hwndScrn = GetDlgItem(hwnd, CID_T_EB_SCREEN); + + cb = cbRead; + for (i = 0; i < cb; ++i) + { + char ch = pTerminaldialog->pbyteReceiveBuf[ i ]; + + /* Formatting: Converts CRs to LFs (there seems to be no VK_ + ** for LF) and throws away LFs. This prevents the user from + ** exiting the dialog when they press Enter (CR) in the + ** terminal screen. LF looks like CRLF in the edit box. Also, + ** throw away TABs because otherwise they change focus to the + ** next control. + */ + if (ch == VK_RETURN) + { + /* Must send whenever end-of-line is encountered because + ** EM_REPLACESEL doesn't handle VK_RETURN characters well + ** (prints garbage). + */ + *pch = '\0'; + + /* Turn off current selection, if any, and replace the null + ** selection with the current buffer. This has the effect + ** of adding the buffer at the caret. Finally, send the + ** EOL to the window which (unlike EM_REPLACESEL) handles + ** it correctly. + */ + SendMessage(hwndScrn, WM_SETREDRAW, (WPARAM )FALSE, 0); + + SendMessage(hwndScrn, EM_SETSEL, 32767, 32767 ); +#ifdef UNICODE + if (MultiByteToWideChar(CP_ACP, + 0, + szBuf, + -1, + szUnicodeBuf, + sizeof(szUnicodeBuf))) + { + SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM )szUnicodeBuf ); + } +#else // UNICODE + SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM )szBuf ); +#endif // UNICODE + SendMessage(hwndScrn, WM_EOLFROMDEVICE, 0, 0 ); + + SendMessage(hwndScrn, WM_SETREDRAW, (WPARAM )TRUE, 0); + SendMessage(hwndScrn, EM_SCROLLCARET, 0, 0); + InvalidateRect(hwndScrn, NULL, FALSE); + + /* Start afresh on the output buffer. + */ + pch = szBuf; + continue; + } + else if (ch == '\n' || ch == VK_TAB) + continue; + + *pch++ = ch; + } + + *pch = '\0'; + + if (pch != szBuf) + { + /* Send the last remnant of the line. + */ + SendMessage(hwndScrn, EM_SETSEL, 32767, 32767); +#ifdef UNICODE + if (MultiByteToWideChar(CP_ACP, + 0, + szBuf, + -1, + szUnicodeBuf, + sizeof(szUnicodeBuf))) + { + SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM)szUnicodeBuf ); + } +#else // UNICODE + SendMessage(hwndScrn, EM_REPLACESEL, 0, (LPARAM)szBuf ); +#endif // UNICODE + SendMessage(hwndScrn, EM_SCROLLCARET, 0, 0); + } + } + }while (cbRead != 0); + + CloseHandle(hEvent); + + return TRUE; +} + +/*---------------------------------------------------------------------------- +** Terminal Output Handler +**---------------------------------------------------------------------------- +*/ + +VOID NEAR PASCAL SendCharacter( HWND hwnd, BYTE byte ) + + /* Send character 'byte' to the device. + */ +{ + PTERMDLG pTerminaldialog; + DWORD cbWrite; + OVERLAPPED ov; + HANDLE hEvent; + COMMTIMEOUTS commtimeout; + + pTerminaldialog = (PTERMDLG)GetWindowLong(hwnd, DWL_USER); + + /* Make sure we still have the comm port + */ + if (pTerminaldialog->hport == NULL) + return; + + /* Send the character to the device. It is not passed thru + ** because the device will echo it. + */ + pTerminaldialog->pbyteSendBuf[ 0 ] = (BYTE )byte; + + // Set write timeout to one second + // + commtimeout.ReadIntervalTimeout = MAXDWORD; + commtimeout.ReadTotalTimeoutMultiplier = 0; + commtimeout.ReadTotalTimeoutConstant = 0; + commtimeout.WriteTotalTimeoutMultiplier= 0; + commtimeout.WriteTotalTimeoutConstant = 1000; + SetCommTimeouts(pTerminaldialog->hport, &commtimeout); + + if ((hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL) + { + ov.Internal = 0; + ov.InternalHigh = 0; + ov.Offset = 0; + ov.OffsetHigh = 0; + ov.hEvent = (HANDLE)((DWORD)hEvent | 1); + + cbWrite = 0; + + if (FALSE == WriteFile(pTerminaldialog->hport, + pTerminaldialog->pbyteSendBuf, + SIZE_SendBuf, &cbWrite, &ov)) + { + DWORD dwResult = GetLastError(); + DWORD dwNumBytesWritten; + + if (ERROR_IO_PENDING == dwResult) + { + GetOverlappedResult(pTerminaldialog->hport, + &ov, + &dwNumBytesWritten, + TRUE); + if (dwNumBytesWritten != SIZE_SendBuf) + { + DPRINTF1("WriteFile() in SendCharacter() only wrote %d bytes!", + dwNumBytesWritten); + } + } + else + { + DPRINTF1("WriteFile() in SendCharacter() failed (0x%8x)!", dwResult); + } + } + + CloseHandle(hEvent); + } + + return; +} + +/*---------------------------------------------------------------------------- +** Terminal Apperance Adjuster +**---------------------------------------------------------------------------- +*/ + +VOID NEAR PASCAL AdjustTerminal (HWND hwnd, int wWidth, int wHeight) +{ + HWND hwndCtrl; + RECT rect; + SIZE sizeButton; + POINT ptPos; + DWORD dwUnit; + + // Get the sizes of the push buttons + // + dwUnit = GetDialogBaseUnits(); + hwndCtrl = GetDlgItem(hwnd, IDOK); + GetWindowRect(hwndCtrl, &rect); + sizeButton.cx = rect.right - rect.left; + sizeButton.cy = rect.bottom - rect.top; + ptPos.x = wWidth/2 - ((X_SPACING*LOWORD(dwUnit))/4)/2 - sizeButton.cx; + ptPos.y = wHeight - (sizeButton.cy+((Y_MARGIN*HIWORD(dwUnit))/4)); + + // Move the push buttons + MoveWindow(hwndCtrl, ptPos.x, ptPos.y, sizeButton.cx, sizeButton.cy, TRUE); + + ptPos.x += ((X_SPACING*LOWORD(dwUnit))/4) + sizeButton.cx; + MoveWindow(GetDlgItem(hwnd, IDCANCEL), ptPos.x, ptPos.y, + sizeButton.cx, sizeButton.cy, TRUE); + + // Get the current position of the terminal screen + hwndCtrl = GetDlgItem(hwnd, CID_T_EB_SCREEN); + GetWindowRect(hwndCtrl, &rect); + ScreenToClient(hwnd, (LPPOINT)&rect); + MoveWindow(hwndCtrl, rect.left, rect.top, + wWidth - 2*rect.left, + ptPos.y - rect.top - ((Y_MARGIN*HIWORD(dwUnit))/4), + TRUE); + + InvalidateRect(hwnd, NULL, TRUE); + return; +} + +/*---------------------------------------------------------------------------- +** Terminal read-notification thread +**---------------------------------------------------------------------------- +*/ + +void WINAPI TerminalThread (PTERMDLG pTerminaldialog) +{ + DWORD dwEvent; + DWORD dwMask; + + while((dwEvent = WaitForMultipleObjects(MAX_EVENT, pTerminaldialog->hEvent, + FALSE, INFINITE)) + < WAIT_OBJECT_0+MAX_EVENT) + { + switch (dwEvent) + { + case READ_EVENT: + + // If we are stopped already, just get out of here + // + if (WaitForSingleObject(pTerminaldialog->hEvent[STOP_EVENT], 0) + == WAIT_TIMEOUT) + { + dwMask = 0; + WaitCommEvent(pTerminaldialog->hport, &dwMask, NULL); + + if ((dwMask & EV_RXCHAR) && (pTerminaldialog->hwnd != NULL)) + { + PostMessage(pTerminaldialog->hwnd, WM_MODEMNOTIFY, 0, 0); + }; + break; + }; + + case STOP_EVENT: + ExitThread(ERROR_SUCCESS); + break; + }; + }; +} diff --git a/private/unimodem/tapisp/timer.c b/private/unimodem/tapisp/timer.c new file mode 100644 index 000000000..cb22775d5 --- /dev/null +++ b/private/unimodem/tapisp/timer.c @@ -0,0 +1,527 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: timer.c +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// +// +// Description: +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" + +#include "timer.h" + +typedef struct _TIMER_CONTROL { + + CRITICAL_SECTION Lock; + + PUNIMODEM_TIMER TimerToBeSet; + + HANDLE Event; + + HANDLE ThreadHandle; + + DWORD ThreadID; + + BOOL TimerEnd; + + HANDLE TimerThreadRunningEvent; + + CRITICAL_SECTION CancelCriticalSection; + +} TIMER_CONTROL, *PTIMER_CONTROL; + +VOID WINAPI +TimerThreadProc( + PTIMER_CONTROL TimerControl + ); + +VOID WINAPI +TimerApcRoutine( + PUNIMODEM_TIMER ThisTimer, + DWORD LowTime, + DWORD HighTime + ); + + +TIMER_CONTROL TimerControlBlock; + +LONG WINAPI +InitializeTimerThread( + VOID + ) + +{ + LONG Result; + PTIMER_CONTROL TimerControl; + + TimerControl=&TimerControlBlock; + + TimerControl->TimerEnd=FALSE; + + TimerControl->TimerToBeSet=NULL; + + InitializeCriticalSection( + &TimerControl->Lock + ); + + + InitializeCriticalSection( + &TimerControl->CancelCriticalSection + ); + + TimerControl->Event=CreateEvent( + NULL, + FALSE, // autoreset + FALSE, // reset + NULL + ); + + + if (TimerControl->Event == NULL) { + + return GetLastError(); + + } + + TimerControl->TimerThreadRunningEvent=CreateEvent( + NULL, + TRUE, // man reset + FALSE, // reset + NULL + ); + + if (TimerControl->TimerThreadRunningEvent == NULL) { + + Result=GetLastError(); + + CloseHandle(TimerControl->Event); + + return Result; + } + + TimerControl->ThreadHandle=CreateThread( + NULL, + 0, + TimerThreadProc, + TimerControl, + 0, + &TimerControl->ThreadID + ); + + if (TimerControl->ThreadHandle == NULL) { + + Result=GetLastError(); + + CloseHandle(TimerControl->TimerThreadRunningEvent); + + CloseHandle(TimerControl->Event); + + return Result; + } + + return ERROR_SUCCESS; + +} + + +VOID WINAPI +TimerThreadProc( + PTIMER_CONTROL TimerControl + ) + +{ + + while (!TimerControl->TimerEnd) { + + // + // if canceling, block here until the cancel code is done + // + EnterCriticalSection( + &TimerControl->CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: Past cancel spinlock");) + + // + // done running for now + // + ResetEvent( + TimerControl->TimerThreadRunningEvent + ); + + // + // release it now, since the cancel routine has done what it needed to + // + LeaveCriticalSection( + &TimerControl->CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: Thread waiting");) + + // + // wait for APC's, or our event to be signaled + // + WaitForSingleObjectEx( + TimerControl->Event, + INFINITE, + TRUE + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: thread running");) + + // + // set this so the cancel code can tell when the thread non alertable + // + SetEvent( + TimerControl->TimerThreadRunningEvent + ); + + + + EnterCriticalSection( + &TimerControl->Lock + ); + + while (TimerControl->TimerToBeSet != NULL) { + + PUNIMODEM_TIMER NewTimer; + + NewTimer=TimerControl->TimerToBeSet; + + TimerControl->TimerToBeSet=NewTimer->Next; + + D_TRACE(McxDpf(888,"TimerThreadProc: Setting new timer");) + + SetWaitableTimer( + NewTimer->TimerHandle, + &NewTimer->DueTime, + 0, + TimerApcRoutine, + NewTimer, + FALSE + ); + + } + + LeaveCriticalSection( + &TimerControl->Lock + ); + + + + + } + + return; + +} + + +VOID WINAPI +TimerApcRoutine( + PUNIMODEM_TIMER TimerObject, + DWORD LowTime, + DWORD HighTime + ) + +{ + + TIMER_CALLBACK *Callback; + HANDLE Context1; + HANDLE Context2; + + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + Callback=TimerObject->CallbackProc; + Context1=TimerObject->Context1; + Context2=TimerObject->Context2; + + + TimerObject->CallbackProc=NULL; + TimerObject->Context1=NULL; + TimerObject->Context2=NULL; + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + + (*Callback)( + Context1, + Context2 + ); + + return; + +} + + +HANDLE WINAPI +CreateUnimodemTimer( + VOID + ) + +{ + + PUNIMODEM_TIMER TimerObject; + + TimerObject=LocalAlloc(LPTR,sizeof(UNIMODEM_TIMER)); + + if (TimerObject == NULL) { + + return NULL; + } + + + TimerObject->Next=NULL; + + TimerObject->CallbackProc=NULL; + TimerObject->Context1=NULL; + TimerObject->Context2=NULL; + + InitializeCriticalSection( + &TimerObject->CriticalSection + ); + + + TimerObject->TimerHandle=CreateWaitableTimer( + NULL, + TRUE, + NULL + ); + + if (TimerObject->TimerHandle == NULL) { + + LocalFree(TimerObject); + + return NULL; + } + + return (HANDLE)TimerObject; + +} + +VOID WINAPI +FreeUnimodemTimer( + HANDLE TimerHandle + ) + +{ + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + CancelUnimodemTimer( + TimerObject + ); + + + CloseHandle( + TimerObject->TimerHandle + ); + + LocalFree(TimerObject); + + return; +} + + + +VOID WINAPI +SetUnimodemTimer( + HANDLE TimerHandle, + DWORD Duration, + TIMER_CALLBACK CallbackFunc, + HANDLE Context1, + HANDLE Context2 + ) + +{ + + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + EnterCriticalSection( + &TimerControlBlock.Lock + ); + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + D_TRACE(McxDpf(888,"SetUnimodemTimer: ");) + + TimerObject->Next=NULL; + + TimerObject->CallbackProc=CallbackFunc; + TimerObject->Context1=Context1; + TimerObject->Context2=Context2; + + + TimerObject->DueTime=Int32x32To64(Duration,-10000); + + + TimerObject->Next=TimerControlBlock.TimerToBeSet; + + TimerControlBlock.TimerToBeSet=TimerObject; + + SetEvent( + TimerControlBlock.Event + ); + + D_TRACE(McxDpf(888,"SetUnimodemTimer: Done");) + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + LeaveCriticalSection( + &TimerControlBlock.Lock + ); + + return; + +} + + +BOOL WINAPI +CancelUnimodemTimer( + HANDLE TimerHandle + ) + +{ + + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + PUNIMODEM_TIMER Current; + PUNIMODEM_TIMER Prev; + BOOL ReturnValue=TRUE; + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: ");) + // + // enter the cancel critical section, so the timer thread will block + // + EnterCriticalSection( + &TimerControlBlock.CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Got cancel lock");) + // + // Signal the event, so the timer thread will run and block on the criical section + // + SetEvent( + TimerControlBlock.Event + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Waiting for thread to run");) + // + // now wait for the thread to actaully run so we know it is not alerted + // + WaitForSingleObject( + TimerControlBlock.TimerThreadRunningEvent, + INFINITE + ); + + + EnterCriticalSection( + &TimerControlBlock.Lock + ); + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + + Prev=NULL; + + Current=TimerControlBlock.TimerToBeSet; + + // + // see if it waiting to be set + // + while (Current != NULL) { + + if (Current == TimerObject) { + // + // found it + // + if (Current == TimerControlBlock.TimerToBeSet) { + + TimerControlBlock.TimerToBeSet=Current->Next; + + } else { + + Prev->Next=Current->Next; + } + + TimerObject->Next=NULL; + TimerObject->CallbackProc=NULL; + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: timer not set yet");) + + goto Done; + + } + + Prev=Current; + Current=Current->Next; + } + + // + // not on list + // + if (TimerObject->CallbackProc != NULL) { + // + // hasn't run yet, so kill it + // + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Canceling pending timer");) + + CancelWaitableTimer( + TimerObject->TimerHandle + ); + + TimerObject->Next=NULL; + TimerObject->CallbackProc=NULL; + + } else { + // + // didn't get the timer, it has run + // + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Missed timer");) + + ReturnValue=FALSE; + } + +Done: + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + + LeaveCriticalSection( + &TimerControlBlock.Lock + ); + + + // + // Done canceling, let the thread go + // + LeaveCriticalSection( + &TimerControlBlock.CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: done canceling");) + + return ReturnValue; + +} diff --git a/private/unimodem/tapisp/timer.h b/private/unimodem/tapisp/timer.h new file mode 100644 index 000000000..f1a8daa82 --- /dev/null +++ b/private/unimodem/tapisp/timer.h @@ -0,0 +1,51 @@ + + + + + + +typedef VOID WINAPI TIMER_CALLBACK(HANDLE,HANDLE); + + +typedef struct _UNIMODEM_TIMER { + + struct _UNIMODEM_TIMER *Next; + + CRITICAL_SECTION CriticalSection; + + TIMER_CALLBACK *CallbackProc; + HANDLE Context1; + HANDLE Context2; + + HANDLE TimerHandle; + + LONGLONG DueTime; + +} UNIMODEM_TIMER, *PUNIMODEM_TIMER; + + + +LONG WINAPI +InitializeTimerThread( + VOID + ); + + +HANDLE WINAPI +CreateUnimodemTimer( + VOID + ); + +VOID WINAPI +SetUnimodemTimer( + HANDLE TimerObject, + DWORD Duration, + TIMER_CALLBACK CallbackFunc, + HANDLE Context1, + HANDLE Context2 + ); + +BOOL WINAPI +CancelUnimodemTimer( + HANDLE TimerObject + ); diff --git a/private/unimodem/tapisp/traceids.h b/private/unimodem/tapisp/traceids.h new file mode 100644 index 000000000..a5f2081d7 --- /dev/null +++ b/private/unimodem/tapisp/traceids.h @@ -0,0 +1,130 @@ +//**************************************************************************** +// +// Module: UNIMDM +// File: TRACEIDS.H +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 3/11/96 JosephJ Created +// +// +// Description: Trace-related IDs. +// +//**************************************************************************** + + +//------------------ IDFROM_* ----------------------------------------------- +// +// THESE INDICATE LOCATIONS IN THE TSP FROM WHICH A TRACING CALL IS MADE +// +// BASE IDs +#define IDFROM_TSPIFN_BASE 10000L +#define IDFROM_LINEDEV_BASE 20000L +#define IDFROM_MDMTIMER_BASE 30000L + +// LineDev related +// +#define IDFROM_LINEDEV_INITLIST (IDFROM_LINEDEV_BASE+ 0L) +#define IDFROM_LINEDEV_ALLOCATE (IDFROM_LINEDEV_BASE+ 1L) +#define IDFROM_LINEDEV_FREE (IDFROM_LINEDEV_BASE+ 2L) +#define IDFROM_LINEDEV_ADD (IDFROM_LINEDEV_BASE+ 3L) + +#define IDFROM_LINEDEV_HANGUP_BEFOREWAIT (IDFROM_LINEDEV_BASE+ 10L) +#define IDFROM_LINEDEV_HANGUP_AFTERWAIT (IDFROM_LINEDEV_BASE+ 11L) + +#define IDFROM_LINEDEV_GETFIRST (IDFROM_LINEDEV_BASE+ 100L) +#define IDFROM_LINEDEV_GETFROMDEVICEHANDLE (IDFROM_LINEDEV_BASE+ 101L) +#define IDFROM_LINEDEV_GETFROMNAME (IDFROM_LINEDEV_BASE+ 102L) +#define IDFROM_LINEDEV_GETFROMHANDLE (IDFROM_LINEDEV_BASE+ 103L) +#define IDFROM_LINEDEV_GETFROMID (IDFROM_LINEDEV_BASE+ 104L) + +#define IDFROM_LINEDEV_ASYNC (IDFROM_LINEDEV_BASE+ 200L) +#define IDFROM_LINEDEV_ASYNC_GOTCOMPLETION (IDFROM_LINEDEV_BASE+ 210L) + +#define IDFROM_DEVLINE_SHUTDOWN (IDFROM_LINEDEV_BASE+ 310L) + +// Timer List related +// +#define IDFROM_MDMTIMER_INIT (IDFROM_MDMTIMER_BASE+ 000L) +#define IDFROM_MDMTIMER_DEINIT (IDFROM_MDMTIMER_BASE+ 010L) +#define IDFROM_MDMTIMER_SET (IDFROM_MDMTIMER_BASE+ 020L) +#define IDFROM_MDMTIMER_KILL (IDFROM_MDMTIMER_BASE+ 030L) +#define IDFROM_MDMTIMER_TIMERTHRD_TIMEOUT (IDFROM_MDMTIMER_BASE+ 040L) +#define IDFROM_MDMTIMER_TIMERTHRD_RECALC (IDFROM_MDMTIMER_BASE+ 050L) + +// TSPI_line* +// +#define IDFROM_TSPI_lineAccept (IDFROM_TSPIFN_BASE+ 10L) +#define IDFROM_TSPI_lineAnswer (IDFROM_TSPIFN_BASE+ 20L) +#define IDFROM_TSPI_lineClose (IDFROM_TSPIFN_BASE+ 30L) +#define IDFROM_TSPI_lineCloseCall (IDFROM_TSPIFN_BASE+ 40L) +#define IDFROM_TSPI_lineConditionalMediaDetection (IDFROM_TSPIFN_BASE+ 50L) +#define IDFROM_TSPI_lineDial (IDFROM_TSPIFN_BASE+ 60L) +#define IDFROM_TSPI_lineDrop (IDFROM_TSPIFN_BASE+ 70L) +#define IDFROM_TSPI_lineDropOnClose (IDFROM_TSPIFN_BASE+ 80L) +#define IDFROM_TSPI_lineGetAddressCaps (IDFROM_TSPIFN_BASE+ 90L) +#define IDFROM_TSPI_lineGetAddressStatus (IDFROM_TSPIFN_BASE+ 100L) +#define IDFROM_TSPI_lineGetCallAddressID (IDFROM_TSPIFN_BASE+ 110L) +#define IDFROM_TSPI_lineGetCallInfo (IDFROM_TSPIFN_BASE+ 120L) +#define IDFROM_TSPI_lineGetCallStatus (IDFROM_TSPIFN_BASE+ 130L) +#define IDFROM_TSPI_lineGetDevCaps (IDFROM_TSPIFN_BASE+ 140L) +#define IDFROM_TSPI_lineGetDevConfig (IDFROM_TSPIFN_BASE+ 150L) +#define IDFROM_TSPI_lineGetIcon (IDFROM_TSPIFN_BASE+ 160L) +#define IDFROM_TSPI_lineGetID (IDFROM_TSPIFN_BASE+ 170L) +#define IDFROM_TSPI_lineGetLineDevStatus (IDFROM_TSPIFN_BASE+ 180L) +#define IDFROM_TSPI_lineGetNumAddressIDs (IDFROM_TSPIFN_BASE+ 190L) +#define IDFROM_TSPI_lineMakeCall (IDFROM_TSPIFN_BASE+ 200L) +#define IDFROM_TSPI_lineNegotiateTSPIVersion (IDFROM_TSPIFN_BASE+ 210L) +#define IDFROM_TSPI_lineOpen (IDFROM_TSPIFN_BASE+ 220L) +#define IDFROM_TSPI_lineSetAppSpecific (IDFROM_TSPIFN_BASE+ 230L) +#define IDFROM_TSPI_lineSetCallParams (IDFROM_TSPIFN_BASE+ 240L) +#define IDFROM_TSPI_lineSetDefaultMediaDetection (IDFROM_TSPIFN_BASE+ 250L) +#define IDFROM_TSPI_lineSetDevConfig (IDFROM_TSPIFN_BASE+ 260L) +#define IDFROM_TSPI_lineSetMediaMode (IDFROM_TSPIFN_BASE+ 270L) +#define IDFROM_TSPI_lineSetStatusMessages (IDFROM_TSPIFN_BASE+ 280L) + +// TSPI_provider* +// +#define IDFROM_TSPI_providerConfig (IDFROM_TSPIFN_BASE+ 500L) +#define IDFROM_TSPI_providerCreateLineDevice (IDFROM_TSPIFN_BASE+ 510L) +#define IDFROM_TSPI_providerEnumDevices (IDFROM_TSPIFN_BASE+ 520L) +#define IDFROM_TSPI_providerFreeDialogInstance (IDFROM_TSPIFN_BASE+ 530L) +#define IDFROM_TSPI_providerGenericDialogData (IDFROM_TSPIFN_BASE+ 540L) +#define IDFROM_TSPI_providerInit (IDFROM_TSPIFN_BASE+ 550L) +#define IDFROM_TSPI_providerInstall (IDFROM_TSPIFN_BASE+ 560L) +#define IDFROM_TSPI_providerRemove (IDFROM_TSPIFN_BASE+ 570L) +#define IDFROM_TSPI_providerShutdown (IDFROM_TSPIFN_BASE+ 580L) +#define IDFROM_TSPI_providerUIIdentify (IDFROM_TSPIFN_BASE+ 590L) + +// ----------------- END IDFROM_* ------------------------------------------- + + + +//------------------ IDEVENT_ ----------------------------------------------- +// +// THESE INDICATE VARIOUS EVENTS IN THE TSP +// +// BASE IDs +// +#define IDEVENT_CP_BASE 10000L // Completion-port +#define IDEVENT_W32C_BASE 20000L // Win32-Comm functions +#define IDEVENT_CS_BASE 30000L // Critical Sections +#define IDEVENT_TSPFN_BASE 40000L // TSP Functions +#define IDEVENT_LOG_BASE 50000L // TSP Functions + + +#define IDEVENT_CP_POST (IDEVENT_CP_BASE+ 10L) +#define IDEVENT_CP_GET (IDEVENT_CP_BASE+ 20L) + + +#define IDEVENT_TSPFN_ENTER (IDEVENT_TSPFN_BASE+ 10L) +#define IDEVENT_TSPFN_EXIT (IDEVENT_TSPFN_BASE+ 20L) +#define IDEVENT_TSPFN_EVENTPROC (IDEVENT_TSPFN_BASE+ 30L) +#define IDEVENT_TSPFN_COMPLETIONPROC (IDEVENT_TSPFN_BASE+ 40L) + + +#define IDEVENT_LOG_PRINTF (IDEVENT_LOG_BASE+ 10L) +#define IDEVENT_LOG_STRING (IDEVENT_LOG_BASE+ 20L) diff --git a/private/unimodem/tapisp/tracing.c b/private/unimodem/tapisp/tracing.c new file mode 100644 index 000000000..5ad7915ad --- /dev/null +++ b/private/unimodem/tapisp/tracing.c @@ -0,0 +1,696 @@ +//**************************************************************************** +// +// Module: UNIMDM +// File: TRACING.C +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 3/29/96 JosephJ Created +// +// +// Description: Tracing (retail-mode diagnostics) functions +// +//**************************************************************************** +#include "unimdm.h" +#include "umdmspi.h" + +// Other modules use this via the TRACINGENABLED macro to determine if +// tracing is enabled in this session. +BOOL gfTracingEnabled; + + +#define fTRACING_INITED (0x1<<0) +#define fTRACING_EXTDLLBOUND (0x1<<1) + +#define TRACINGINITED() (gTracing.dwFlags&fTRACING_INITED) +#define EXTDLLBOUND() (gTracing.dwFlags&fTRACING_EXTDLLBOUND) + +typedef BOOL (WINAPI *PFNINIT) (DWORD, LPDWORD); +typedef void (WINAPI *PFNDEINIT) (void); +typedef void (WINAPI *PFNNOTIFY) (PNOTIFICATION_FRAME); +typedef void (WINAPI *PFNREGISTEROBJECT) (PVOID, PGUID, DWORD, DWORD, DWORD); +typedef void (WINAPI *PFNUNREGISTEROBJECT) (PVOID, DWORD, DWORD); +typedef void (WINAPI *PFNTRACE1) (DWORD); +typedef void (WINAPI *PFNTRACE2) (DWORD, DWORD); +typedef void (WINAPI *PFNTRACE3) (DWORD, DWORD, DWORD); +typedef void (WINAPI *PFNTRACE4) (DWORD, DWORD, DWORD, DWORD); +typedef void (WINAPI *PFNTRACE5) (DWORD, DWORD, DWORD, DWORD, DWORD); +typedef void (WINAPI *PFNTRACE8) (DWORD, DWORD, DWORD, DWORD, DWORD, + DWORD, DWORD, DWORD); + +// Maintains info on the binding to the external MODEMDBG.DLL which contains +// extended tracing and diagnostic information. +// The ext field in gTracing is initialized after a successful call to +// itraceBindToExternalDll. +typedef struct +{ + HANDLE hDll; + PFNINIT pfnInit; + PFNDEINIT pfnDeinit; + PFNREGISTEROBJECT pfnRegisterObject; + PFNUNREGISTEROBJECT pfnUnRegisterObject; + PFNNOTIFY pfnNotify; + PFNTRACE1 pfnTrace1; + PFNTRACE2 pfnTrace2; + PFNTRACE3 pfnTrace3; + PFNTRACE4 pfnTrace4; + PFNTRACE5 pfnTrace5; + PFNTRACE8 pfnTrace8; + +} EXTERNAL_DLL; + +// Global internal tracing state. +struct { + DWORD dwFlags; + CRITICAL_SECTION crit; + EXTERNAL_DLL ext; + LINEEVENT lineEventProc; + ASYNC_COMPLETION TapiCompletionProc; +} gTracing; + + +//---------- PRIVATE FUNCTIONS ------------------------------- +BOOL itraceCheckIfEnabled(DWORD dwPermanentID); +BOOL itraceBindToExternalDll(void); +void itraceUnbindFromExternalDll(void); +void CALLBACK itraceEventProc(HTAPILINE htLine, + HTAPICALL htCall, + DWORD dwMsg, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3 + ); +void CALLBACK itraceTapiCompletionProc( + DRV_REQUESTID dwRequestID, + LONG lResult + ); + + +//**************************************************************************** +// Function: To be called on process attach +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceOnProcessAttach(void) +{ + InitializeCriticalSection(&gTracing.crit); +} + + +//**************************************************************************** +// Function: To be called on process detach +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceOnProcessDetach(void) +{ + DeleteCriticalSection(&gTracing.crit); +} + + +//**************************************************************************** +// Function: To be called on provider initialization +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceInitialize(DWORD dwPermanentID) +{ + TCHAR rgtchExternalDllName[MAX_PATH]; + + EnterCriticalSection(&gTracing.crit); + ASSERT(!gTracing.dwFlags); + + // Determine if tracing is enabled, if so set the gTracingEnabled flag. + gfTracingEnabled = itraceCheckIfEnabled(dwPermanentID); + + // If tracing enabled, try to load the external trace dll and get the + // entry points to that function. + if (TRACINGENABLED()) + { + if (itraceBindToExternalDll()) + { + ASSERT(EXTDLLBOUND()); + } + } + + gTracing.dwFlags |= fTRACING_INITED; + LeaveCriticalSection(&gTracing.crit); +} + + +//**************************************************************************** +// Function: To be called on provider shutdown +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceDeinitialize(void) +{ + EnterCriticalSection(&gTracing.crit); + + if (!TRACINGINITED()) goto end; + + // Deinit external dll.. + if (EXTDLLBOUND()) + { + itraceUnbindFromExternalDll(); + } + + + gTracing.dwFlags = 0; + +end: + ASSERT(!gTracing.dwFlags); + LeaveCriticalSection(&gTracing.crit); +} + + +//**************************************************************************** +// Function: Registers an arbitrary object with the external dll. +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceRegisterObject( + PVOID pv, // Pointer to the object + PGUID pg, // GUID uniquely defining the object + DWORD dwVersion, // Implementation version of the object + DWORD dwFlags, // Unused, currently zero + DWORD dwParam // Unused, currently zero +) +{ + + DPRINTF2("traceRegisterObject: obj 0x%lx, type 0x%lx\n", + (DWORD) pv, (DWORD) pg); + if (!TRACINGENABLED()) goto end; + + if (EXTDLLBOUND()) + { + ASSERT(gTracing.ext.pfnRegisterObject); + gTracing.ext.pfnRegisterObject(pv, pg, dwVersion, dwFlags, dwParam); + } + + +end: + return; +} + +//**************************************************************************** +// Function: UnRegisters an arbitrary object with the external dll. +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceUnRegisterObject( + PVOID pv, // Pointer to a previously-registered object. + DWORD dwFlags, // Unused, currently zero + DWORD dwParam // Unused, currently zero +) +{ + DPRINTF1("traceUnRegiserObject: obj 0x%lx\n", (DWORD) pv); + if (!TRACINGENABLED()) goto end; + + if (EXTDLLBOUND()) + { + ASSERT(gTracing.ext.pfnUnRegisterObject); + gTracing.ext.pfnUnRegisterObject(pv, dwFlags, dwParam); + } + +end: + return; +} + + +//**************************************************************************** +// Function: Processes an external debug notification. +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +void traceProcessNotification( + PNOTIFICATION_FRAME pnf +) +{ + if (!TRACINGENABLED()) goto end; + + ASSERT(TSP_VALID_FRAME(pnf)); + ASSERT(TSP_DEBUG_FRAME(pnf)); + + DPRINTF1("traceProcessNotification: type 0x%lx\n", pnf->dwType); + + if (EXTDLLBOUND()) + { + ASSERT(gTracing.ext.pfnNotify); + gTracing.ext.pfnNotify(pnf); + } + +end: + return; +} + + +void traceTrace1( + DWORD dwWhat +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace1); + gTracing.ext.pfnTrace1(dwWhat); + +end: + return; +} + + + +void traceTrace2( + DWORD dwWhat, + DWORD dw0 +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace2); + gTracing.ext.pfnTrace2(dwWhat, dw0); + +end: + return; +} + + + +void traceTrace3( + DWORD dwWhat, + DWORD dw0, + DWORD dw1 +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace3); + gTracing.ext.pfnTrace3(dwWhat, dw0, dw1); + +end: + return; +} + +void traceTrace4( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2 +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace4); + gTracing.ext.pfnTrace4(dwWhat, dw0, dw1, dw2); + +end: + return; +} + +void traceTrace5( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2, + DWORD dw3 +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace5); + gTracing.ext.pfnTrace5(dwWhat, dw0, dw1, dw2, dw3); + +end: + return; +} + +void traceTrace8( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2, + DWORD dw3, + DWORD dw4, + DWORD dw5, + DWORD dw6 +) +{ + ASSERT(TRACINGENABLED()); + + if (!EXTDLLBOUND()) goto end; + + ASSERT(gTracing.ext.pfnTrace8); + gTracing.ext.pfnTrace8(dwWhat, dw0, dw1, dw2, dw3, dw4, dw5, dw6); + +end: + return; +} + +LINEEVENT traceSetEventProc(LINEEVENT lineEventProc) +{ + ASSERT(TRACINGENABLED()); + gTracing.lineEventProc = lineEventProc; + return itraceEventProc; +} + +ASYNC_COMPLETION traceSetCompletionProc(ASYNC_COMPLETION cbCompletionProc) +{ + ASSERT(TRACINGENABLED()); + gTracing.TapiCompletionProc = cbCompletionProc; + return itraceTapiCompletionProc; +} + +#ifdef ENABLE_TRACE_CRITICAL_SECTION +//**************************************************************************** +// void TRACEInitializeCriticalSection ( +// TRACE_CRITICAL_SECTION * ptspcrit, +// DWORD dwID) +// +// Function: InitializeCriticalSection, with some perf monitoring +//**************************************************************************** + +void TRACEInitializeCriticalSection(TRACE_CRITICAL_SECTION * ptspcrit, DWORD dwID, DWORD dwWTime, DWORD dwCTime) +{ + FillMemory(ptspcrit, sizeof(TRACE_CRITICAL_SECTION), 0); + InitializeCriticalSection(&(ptspcrit->crit)); + ptspcrit->dwID = dwID; + ptspcrit->dwMaxWaitTime=dwWTime; + ptspcrit->dwMaxClaimTime=dwCTime; + +} + +//**************************************************************************** +// void TRACEEnterCriticalSection ( +// TRACE_CRITICAL_SECTION * ptspcrit, +// DWORD dwID) +// +// Function: EnterCriticalSection, with some perf monitoring +//**************************************************************************** +void TRACEEnterCriticalSection(TRACE_CRITICAL_SECTION * ptspcrit, DWORD dwFrom) +{ + DWORD tc0 = GetTickCount(), tc1; + DWORD dwDelta; + + EnterCriticalSection(&(ptspcrit->crit)); + + ptspcrit->dwTotalHits++; + + if (!ptspcrit->dwNested++) + { + tc1 = ptspcrit->tcEntered = GetTickCount(); + ptspcrit->dwFromWhere = dwFrom; + dwDelta = GETTICKCOUNT_DELTA(tc0, tc1); + + if (dwDelta>=CRIT_MIN_WAIT_DELTA) + { + if (dwDelta>=ptspcrit->dwMaxWaitTime) + { + // MONTSPEVENT(_id, _subid, ,,......) + DPRINTF3("WARNING: Took %lums to claim crit %lu from %lu", + dwDelta, ptspcrit->dwID, dwFrom); + } + ptspcrit->dwWaitHits++; + ptspcrit->dwTotalWaitTime+=dwDelta; + } + } +} + +//**************************************************************************** +// void TRACELeaveCriticalSection ( +// TRACE_CRITICAL_SECTION * ptspcrit, +// DWORD dwFrom) +// +// Function: LeaveCriticalSection, with some perf monitoring +void TRACELeaveCriticalSection(TRACE_CRITICAL_SECTION * ptspcrit, DWORD dwFrom) +{ + DWORD tc0 = ptspcrit->tcEntered, tc1=GetTickCount(); + DWORD dwDelta = GETTICKCOUNT_DELTA(tc0, tc1); + + if (!(--(ptspcrit->dwNested))) + { + if (dwDelta>=CRIT_MIN_CLAIM_DELTA) + { + ptspcrit->dwTotalClaimTime+=dwDelta; + ptspcrit->dwClaimHits++; + if (dwDelta>ptspcrit->dwMaxClaimTime) + { + // MONTSPEVENT(_id, _subid, ,,......) + DPRINTF4("WARNING: Took %lums inside crit %lu claimed from %lu;" + "released from %lu", + dwDelta, ptspcrit->dwID, ptspcrit->dwFromWhere, dwFrom); + } + } + } + + LeaveCriticalSection(&(ptspcrit->crit)); +} + +//**************************************************************************** +// void TRACEDeleteCriticalSection ( +// TRACE_CRITICAL_SECTION * ptspcrit, +// DWORD dwID) +// +// Function: DeleteCriticalSection, with some perf monitoring +void TRACEDeleteCriticalSection(TRACE_CRITICAL_SECTION * ptspcrit) +{ + EnterCriticalSection(&(ptspcrit->crit)); + DPRINTF2("Deleteing TRACE crit %lu. TH=%lu", + ptspcrit->dwID, + ptspcrit->dwTotalHits); + DPRINTF4(" ... TWT=%lu TWH=%lu TCT=%lu TCH=%lu\n", + ptspcrit->dwTotalWaitTime, + ptspcrit->dwWaitHits, + ptspcrit->dwTotalClaimTime, + ptspcrit->dwClaimHits); + // +++ MON + + DeleteCriticalSection(&(ptspcrit->crit)); +} + + +//**************************************************************************** +// void TRACESetMaxWaitAndClaimTime( +// TRACE_CRITICAL_SECTION * ptspcrit, +// DWORD dwWTime, +// DWORD dwCTime) +// +// Function: Sets the MaxWaitOrClaimTime of the crit -- if this time is +// exceeded, it results in a mon event being logged. +void TRACESetMaxWaitAndClaimTime(TRACE_CRITICAL_SECTION *ptspcrit, DWORD dwWTime, DWORD dwCTime) +{ + DPRINTF2("TRACECRIT: setting (wait,claim) max time to (%lu,%lu)", + dwWTime, dwCTime); + + EnterCriticalSection(&(ptspcrit->crit)); + ptspcrit->dwMaxWaitTime = dwWTime; + ptspcrit->dwMaxClaimTime = dwCTime; + LeaveCriticalSection(&(ptspcrit->crit)); +} + +#endif // ENABLE_TRACE_CRITICAL_SECTION + + +//**************************************************************************** +// Function: Reads the registry and determines if tracing is enabled in this +// session. Currently tracing is always enabled. +// History: +// 3/25/96 JosephJ Created +//****************************************************************************/ +BOOL itraceCheckIfEnabled(DWORD dwPermanentID) +{ + BOOL fRet=FALSE; + DWORD dwFlags=0; + DWORD dwType=0; + HKEY hKey=0; + LONG l; + DWORD dwSize=sizeof(dwFlags); + TCHAR rgtch[] = szUNIMODEM_REG_PATH TEXT("\\Diagnostics"); + + DPRINTF1("trace:Key=%s", rgtch); + + l=RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + rgtch, // address of name of subkey to open + 0, // reserved + KEY_READ, // desired security access + &hKey // address of buffer for opened handle + ); + if (l!=ERROR_SUCCESS) {hKey=0; goto end;} + + DPRINTF("trace:RegOpen succeeded"); + + l=RegQueryValueEx( + hKey, + TEXT("TraceFlags"), + NULL, + &dwType, + (VOID *)&dwFlags, + &dwSize + ); + if (l != ERROR_SUCCESS || dwType != REG_DWORD || + dwSize != sizeof(dwFlags)) + { + goto end; + } + + DPRINTF1("RegQueryValue succeeds. Value=0x%lx", dwFlags); + + fRet = !!dwFlags; + +end: + if (hKey) RegCloseKey(hKey); + + + DPRINTF1("Tracing %s", (fRet)?TEXT("ENABLED"):TEXT("DISABLED")); + return fRet; +} + + +//**************************************************************************** +// Function: Tries to bind to the external modem diagnostics dll. +// History: +// 3/31/96 JosephJ Created +//****************************************************************************/ +BOOL itraceBindToExternalDll(void) +{ + BOOL fRet=FALSE; + DWORD dwNegVer=0; + + ASSERT(!EXTDLLBOUND()); + + FillMemory(&gTracing.ext, sizeof(gTracing.ext), 0); + + gTracing.ext.hDll = LoadLibrary(TEXT("mdmdbg.dll")); + if (gTracing.ext.hDll) + { + + (FARPROC) gTracing.ext.pfnInit = + GetProcAddress(gTracing.ext.hDll, "MdmDbgInit"); + (FARPROC) gTracing.ext.pfnDeinit = + GetProcAddress(gTracing.ext.hDll, "MdmDbgDeinit"); + (FARPROC) gTracing.ext.pfnNotify = + GetProcAddress(gTracing.ext.hDll, "MdmDbgNotify"); + (FARPROC) gTracing.ext.pfnRegisterObject = + GetProcAddress(gTracing.ext.hDll, "MdmDbgRegisterObject"); + (FARPROC) gTracing.ext.pfnUnRegisterObject = + GetProcAddress(gTracing.ext.hDll, "MdmDbgUnRegisterObject"); + (FARPROC) gTracing.ext.pfnTrace1 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace1"); + (FARPROC) gTracing.ext.pfnTrace2 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace2"); + (FARPROC) gTracing.ext.pfnTrace3 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace3"); + (FARPROC) gTracing.ext.pfnTrace4 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace4"); + (FARPROC) gTracing.ext.pfnTrace5 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace5"); + (FARPROC) gTracing.ext.pfnTrace8 = + GetProcAddress(gTracing.ext.hDll, "MdmDbgTrace8"); + + } + + if ( gTracing.ext.pfnInit + && gTracing.ext.pfnDeinit + && gTracing.ext.pfnRegisterObject + && gTracing.ext.pfnUnRegisterObject + && gTracing.ext.pfnNotify + && gTracing.ext.pfnTrace1 + && gTracing.ext.pfnTrace2 + && gTracing.ext.pfnTrace3 + && gTracing.ext.pfnTrace4 + && gTracing.ext.pfnTrace5 + && gTracing.ext.pfnTrace8) + { + fRet = gTracing.ext.pfnInit(dwMDMDBG_CURRENT_VERSION, &dwNegVer); + + if (fRet && dwNegVer!=dwMDMDBG_CURRENT_VERSION) + { + fRet=FALSE; + gTracing.ext.pfnDeinit(); + } + + } + + if (!fRet) + { + DPRINTF("trace: Did not bind to MDMDBG.DLL.\n"); + if (gTracing.ext.hDll) + { + FreeLibrary(gTracing.ext.hDll); + } + FillMemory(&gTracing.ext, sizeof(gTracing.ext), 0); + } + else + { + DPRINTF("trace: BOUND TO MDMDBG.DLL.\n"); + gTracing.dwFlags|=fTRACING_EXTDLLBOUND; // EXTDLLBOUND now returns TRUE + } + + return fRet; +} + +//**************************************************************************** +// Function: Unbinds from the external modem diagnostics dll. +// History: +// 3/31/96 JosephJ Created +//****************************************************************************/ +void itraceUnbindFromExternalDll(void) +{ + ASSERT(EXTDLLBOUND()); + ASSERT(gTracing.ext.hDll); + ASSERT(gTracing.ext.pfnDeinit); + + gTracing.ext.pfnDeinit(); + + FreeLibrary(gTracing.ext.hDll); + + FillMemory(&gTracing.ext, sizeof(gTracing.ext), 0); + gTracing.dwFlags&=~fTRACING_EXTDLLBOUND; // EXTDLLBOUND now returns FALSE +} + +void CALLBACK itraceEventProc(HTAPILINE htLine, + HTAPICALL htCall, + DWORD dwMsg, + DWORD dwParam1, + DWORD dwParam2, + DWORD dwParam3) +{ + TRACE8(IDEVENT_TSPFN_EVENTPROC, htLine, htCall, dwMsg, + dwParam1, dwParam2, dwParam3, 0); + + if (gTracing.lineEventProc) + { + gTracing.lineEventProc(htLine, htCall, dwMsg, + dwParam1, dwParam2, dwParam3); + } +} + + +void CALLBACK itraceTapiCompletionProc( + DRV_REQUESTID dwRequestID, + LONG lResult +) +{ + TRACE3(IDEVENT_TSPFN_COMPLETIONPROC, dwRequestID, lResult); + //DPRINTF2("TapiCompletionProc: dwReq = 0x%lx, dwResult=0x%lx\n", + // (DWORD) dwRequestID, (DWORD) lResult); + + if (gTracing.TapiCompletionProc) + { + gTracing.TapiCompletionProc(dwRequestID, lResult); + } +} + diff --git a/private/unimodem/tapisp/tracing.h b/private/unimodem/tapisp/tracing.h new file mode 100644 index 000000000..66f18092f --- /dev/null +++ b/private/unimodem/tapisp/tracing.h @@ -0,0 +1,192 @@ +//**************************************************************************** +// +// Module: UNIMDM +// File: TRACING.H +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 3/29/96 JosephJ Created +// +// +// Description: Tracing (retail-mode diagnostics) functions +// +//**************************************************************************** +#include +#include "traceids.h" + +// Trace-related flags, specified in the dwFlags field of TRACEINFO +#define fTI_ERROR (0x1<<0) +#define fTI_WARN (0x1<<1) +#define fTI_LOGTO_MEM (0x1<<31) +#define fTI_LOGTO_FILE (0x1<<31) +#define fTI_LOGTO_TRACE (0x1<<31) + +// These IDs uniquely define the object type passed into traceRegisterObject. +// These will eventually be guids. For now they are simply integer IDs. +#define TSP_TIMER_LIST_GUID 0x1000 +#define TSP_OVER_LIST_GUID 0x1001 +#define TSP_MODEM_LIST_GUID 0x1002 +#define TSP_COMMON_LIST_GUID 0x1003 + +// The corresponding implementation version of the objects above. Bump up +// the version each time there is a change in that objects internal +// structure. +#define TSP_TIMER_LIST_VERSION 0 +#define TSP_OVER_LIST_VERSION 0 +#define TSP_MODEM_LIST_VERSION 0 +#define TSP_COMMON_LIST_VERSION 0 + +// dwMDMDBG_CURRENT_VERSION is passed into the external tracing dll's +// MdmDbgInit function to verify compatible versions. +// 7/13/96 JosephJ INITIALVERSION+2 should be official NT4.0 version. +#define dwMDMDBG_INITIAL_VERSION 0x12345678 +#define dwMDMDBG_CURRENT_VERSION (dwMDMDBG_INITIAL_VERSION+3) + +// This macro determines whether tracing is enabled for this session. +// Tracing is enabled during ProviderInit, based on a registry setting. +// If enabled, it is not disabled until provider shutdown. +#define TRACINGENABLED() (gfTracingEnabled) + +#define TRACE1(_what) \ + (void)(TRACINGENABLED() \ + ? traceTrace1(_what) \ + : 0) + +#define TRACE2(_what, _dw0) \ + (void)(TRACINGENABLED() \ + ? traceTrace2( \ + _what, \ + (DWORD)(_dw0) \ + ) \ + : 0) + +#define TRACE3(_what, _dw0, _dw1) \ + (void)(TRACINGENABLED() \ + ? traceTrace3( \ + _what, \ + (DWORD)(_dw0), (DWORD)(_dw1) \ + ) \ + : 0) + +#define TRACE4(_what, _dw0, _dw1, _dw2) \ + (void)(TRACINGENABLED() \ + ? traceTrace4( \ + _what, \ + (DWORD)(_dw0), (DWORD)(_dw1), (DWORD)(_dw2) \ + ) \ + : 0) + +#define TRACE5(_what, _dw0, _dw1, _dw2, _dw3) \ + (void)(TRACINGENABLED() \ + ? traceTrace5( \ + _what, \ + (DWORD)(_dw0), (DWORD)(_dw1), (DWORD)(_dw2), (DWORD)(_dw3) \ + ) \ + : 0) + +#define TRACE8(_what, _dw0, _dw1, _dw2, _dw3, _dw4, _dw5, _dw6) \ + (void)(TRACINGENABLED() \ + ? traceTrace8( \ + _what, \ + (DWORD)(_dw0), (DWORD)(_dw1), (DWORD)(_dw2), (DWORD)(_dw3), \ + (DWORD)(_dw4), (DWORD)(_dw5), (DWORD)(_dw6) \ + ) \ + : 0) + +// Tracing-related instance data tacked on to the trace-enabled version of +// an object (see for example OVERNODE in unimdm.h). +// +typedef struct { + DWORD dw0; +} TRACEINSTDATA; + + +// This struct is passed in to most tracing output functions (tracePrintf, etc), +// to provide some additional context. +typedef struct +{ + DWORD dwID; // Device ID, if applicable + DWORD dwFlags; // One of the fTI_* flags defined above. + HANDLE hFile; // Handle to a file, if file logging is enabled. +} TRACEINFO, *PTRACEINFO; + +void tracePrintf( + PTRACEINFO pti, + DWORD dwFlags, + LPCTSTR lpctszFormat, + ... +); + +void traceOnProcessAttach(void); +void traceOnProcessDetach(void); +void traceInitialize(DWORD dwPermanentID); +void traceDeinitialize(void); + +typedef DWORD PGUID; + +void traceRegisterObject( + PVOID pv, + PGUID pg, + DWORD dwVersion, + DWORD dwFlags, + DWORD dwParam +); + +void traceUnRegisterObject( + PVOID pv, + DWORD dwFlags, + DWORD dwParam +); + +void traceProcessNotification( + PNOTIFICATION_FRAME pnf +); + +void traceTrace1( + DWORD dwWhat +); + +void traceTrace2( + DWORD dwWhat, + DWORD dw0 +); + +void traceTrace3( + DWORD dwWhat, + DWORD dw0, + DWORD dw1 +); + +void traceTrace4( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2 +); + +void traceTrace5( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2, + DWORD dw3 +); + +void traceTrace8( + DWORD dwWhat, + DWORD dw0, + DWORD dw1, + DWORD dw2, + DWORD dw3, + DWORD dw4, + DWORD dw5, + DWORD dw6 +); + +LINEEVENT traceSetEventProc(LINEEVENT lineEventProc); +ASYNC_COMPLETION traceSetCompletionProc(ASYNC_COMPLETION cbCompletionProc); + +extern BOOL gfTracingEnabled; diff --git a/private/unimodem/tapisp/umdminit.c b/private/unimodem/tapisp/umdminit.c new file mode 100644 index 000000000..aa4ec1ad5 --- /dev/null +++ b/private/unimodem/tapisp/umdminit.c @@ -0,0 +1,2792 @@ +//**************************************************************************** +// +// Module: Unimdm.tsp +// File: umdminit.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 + +#include "common.h" + +#define _INC_OLE +#include + +#define INITGUID +#include +#include + +#include + +#include + +//**************************************************************************** +// Modem enumeration request +//**************************************************************************** + +typedef struct CountInfo{ + UINT cModem; +} COUNTINFO, FAR* LPCOUNTINFO; + +typedef struct InitInfo{ + DWORD dwBaseID; + UINT cModem; +} INITINFO, FAR* LPINITINFO; + +typedef struct FindInfo{ + LPTSTR lpszDeviceName; + BOOL fFound; + HKEY FAR* lphkey; + LPTSTR lpszID; + UINT cbID; +} FINDINFO, FAR* LPFINDINFO; + + +typedef DWORD APIENTRY +PRIVATEGETDEFCOMMCONFIG( + HKEY hKey, + LPCOMMCONFIG pcc, + LPDWORD pdwSize + ); + + +//**************************************************************************** +// GLOBALS +//**************************************************************************** +struct { + + // Cache for hdevinfo, the handle returned by expensive function + // SetupDiGetClassDevsW. + HDEVINFO hdevinfo; + DWORD dwcRefHDevInfo; + + // Cache for MODEMUI DLL and it's "PrivateDefCommConfig" export. + HINSTANCE hModemUIDLL; + DWORD dwcRefModemUI; + PRIVATEGETDEFCOMMCONFIG + *pfnPrivateDefCommConfig; + + // Cache for whether current process has admin priveleges. + BOOL bAdminUser; + + // Handle of thread that processes cpl notifications. + HANDLE hthrdCplNotif; + + CRITICAL_SECTION crit; + + CRITICAL_SECTION critCplNotif; // Critical section used ONLY to + //serialize launching the tepCplNotif thread. +} gUmdm; + + +// This is declared in unimdm.h, and is accessed by the MCX part as well. +DWORD gRegistryFlags; + +#define USER_IS_ADMIN() (gUmdm.bAdminUser) + +//**************************************************************************** +// Constant Parameters +//**************************************************************************** + +LPGUID g_pguidModem = (LPGUID)&GUID_DEVCLASS_MODEM; + +TCHAR cszFriendlyName[] = TEXT("FriendlyName"); +TCHAR cszDeviceType[] = TEXT("DeviceType"); +#ifdef VOICEVIEW +TCHAR cszVoiceView[] = TEXT("VoiceView"); +#endif // VOICEVIEW +TCHAR cszID[] = TEXT("ID"); +TCHAR cszProperties[] = TEXT("Properties"); +TCHAR cszSettings[] = TEXT("Settings"); +TCHAR cszDialSuffix[] = TEXT("DialSuffix"); +TCHAR cszDevicePrefix[] = TEXT("\\\\.\\"); + +#define HAYES_COMMAND_LENGTH 40 // max size for DialSuffix (from VxD) + +TCHAR cszHWNode[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96D-E325-11CE-BFC1-08002BE10318}"); + +TCHAR gszTSPFilename[MAX_PATH]; + + +#ifdef WINNT +extern CRITICAL_SECTION ServiceControlerCriticalSection; +#endif // WINNT + + +// Private function prototypes +// + +LONG DevlineGetDefaultConfig(PLINEDEV pLineDev, HKEY hKey); + +BOOL _ProcessAttach(HINSTANCE hDll); +BOOL _ProcessDetach(HINSTANCE hDll); +LONG DevlineEnum(LPDWORD lpdwNumLines); +LONG DevlineInitialize (DWORD dwBaseID, LPDWORD lpdwNumDevs); +LONG DevlineShutdown (); +void CleanupLineDev(PLINEDEV pLineDev); +PLINEDEV CreateLineDev(HKEY hKeyHardware, DWORD dwID, BOOL fReCreate); +BOOL PUBLIC IsAdminUser(void); // common code from ../rovcomm.lib + + +typedef BOOL (*ENUMMDMCALLBACK)(HKEY, LPVOID); + +BOOL CountModemCallback (HKEY hkey, LPVOID lpData); +BOOL InitModemCallback (HKEY hkey, LPVOID lpData); +void FreeHDevInfo(HDEVINFO hdevinfo); +HDEVINFO GetHDevInfo(DWORD dwDIGCF); +BOOL LoadModemUI(void); +void UnloadModemUI(void); +void CplNotifComplete(BOOL fWait); +LONG EnumerateModems (ENUMMDMCALLBACK pfnCallback, LPVOID lpData, BOOL fAll); + +typedef BOOL (*ENUMMDMKEYCALLBACK)(HKEY, LPTSTR, LPVOID); + +BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData); +LONG EnumerateModemKeys (ENUMMDMKEYCALLBACK pfnCallback, LPVOID lpData); + +LONG PASCAL ProviderInstall(LPTSTR pszProviderName, BOOL bNoMultipleInstance); + +void tspInitGlobals(void); +void tspDeInitGlobals(void); + +VOID WINAPI +UI_ProcessAttach( + VOID + ); + +VOID WINAPI +UI_ProcessDetach( + VOID + ); + +LONG WINAPI +StopModemDriver( + VOID + ); + + + +//**************************************************************************** +// BOOL _Processattach (HINSTANCE) +// +// Function: This function is called when a process is attached to the DLL +// +// History: +// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont] +// Ported from Shell. +//**************************************************************************** + +BOOL _ProcessAttach(HINSTANCE hDll) +{ + BOOL fRet; + +#ifdef DEBUG + // We do this simply to load the debug .ini flags + // + RovComm_ProcessIniFile(); + + DEBUG_BREAK(BF_ONPROCESSATT); + TRACE_MSG(TF_GENERAL, "Process Attach (hDll = %lx)", hDll); +#endif + InitializeCriticalSection(&gUmdm.crit); + InitializeCriticalSection(&gUmdm.critCplNotif); + + traceOnProcessAttach(); + + UI_ProcessAttach(); + + // Initialize line device lists + // + fRet = InitCBList(hDll); + if (fRet) + { + // Remember our instance and module name + // + ghInstance = hDll; + GetModuleFileName(hDll, + gszTSPFilename, + sizeof(gszTSPFilename)/sizeof(TCHAR)); + + fRet = OverPoolInit(); + + if (!fRet) + { + DeinitCBList(hDll); + } + + }; + + if (!fRet) + { + traceOnProcessDetach(); + DeleteCriticalSection(&gUmdm.crit); + DeleteCriticalSection(&gUmdm.critCplNotif); + } + + return fRet; +} + +//**************************************************************************** +// BOOL _ProcessDetach (HINSTANCE) +// +// Function: This function is called when a process is detached from the DLL +// +// History: +// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont] +// Ported from Shell. +//**************************************************************************** + +BOOL _ProcessDetach(HINSTANCE hDll) +{ + DEBUG_CODE( TRACE_MSG(TF_GENERAL, "Process Detach (hDll = %lx)", hDll); ) + DEBUG_CODE( DEBUG_BREAK(BF_ONPROCESSDET); ) + + // Clean up the allocated resources + // + DeinitCBList(hDll); + OverPoolDeinit(); + UI_ProcessDetach(); + ghInstance = NULL; + traceOnProcessDetach(); + DeleteCriticalSection(&gUmdm.crit); + DeleteCriticalSection(&gUmdm.critCplNotif); + return TRUE; +} + +//**************************************************************************** +// BOOL APIENTRY LibMain (HINSTANCE, DWORD, LPVOID) +// +// Function: This function is called when the DLL is loaded +// +// History: +// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont] +// Ported from Shell. +//**************************************************************************** + +BOOL APIENTRY DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) +{ + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + _ProcessAttach(hDll); + break; + case DLL_PROCESS_DETACH: + _ProcessDetach(hDll); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + default: + break; + } // end switch() + + return TRUE; + +} + +//**************************************************************************** +//************************** The Initialization Calls************************* +//**************************************************************************** + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerInstall( +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: Let's telephony CPL know the Remove function is supported. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +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 ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerRemove( +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: Let's telephony CPL know the Install function is supported. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +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 ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerConfig( +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: Let's telephony CPL know the Config function is supported. +// +// History: +// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo] +// Ported from Win95. +//**************************************************************************** + +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 ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TUISPI_providerInstall( +// TUISPIDLLCALLBACK lpfnUIDLLCallback, +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: TSPI installation +// +// History: +// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo] +// Ported from TAPI's atsp +//**************************************************************************** + +LONG +TSPIAPI +TUISPI_providerInstall( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + return ProviderInstall (TEXT("unimdm.tsp"), TRUE); +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TUISPI_providerRemove( +// TUISPIDLLCALLBACK lpfnUIDLLCallback, +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: TSPI removal +// +// History: +// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo] +// Ported from Win95. +//**************************************************************************** + +LONG +TSPIAPI +TUISPI_providerRemove( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TUISPI_providerConfig( +// TUISPIDLLCALLBACK lpfnUIDLLCallback, +// HWND hwndOwner, +// DWORD dwPermanentProviderID +// ) +// +// Function: TUISPI configuration +// +// History: +// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo] +// Ported from Win95. +//**************************************************************************** + +LONG +TSPIAPI +TUISPI_providerConfig( + TUISPIDLLCALLBACK lpfnUIDLLCallback, + HWND hwndOwner, + DWORD dwPermanentProviderID + ) +{ + WinExec("control.exe modem.cpl", SW_SHOW); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG TSPIAPI TSPI_providerEnumDevices() +// +// Function: TSPI device enumeration entry +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG TSPIAPI TSPI_providerEnumDevices(DWORD dwPermanentProviderID, + LPDWORD lpdwNumLines, + LPDWORD lpdwNumPhones, + HPROVIDER hProvider, + LINEEVENT lpfnLineCreateProc, + PHONEEVENT lpfnPhoneCreateProc) + +{ + DBG_ENTER_UL("TSPI_providerEnumDevices", dwPermanentProviderID); + + TRACE3( + IDEVENT_TSPFN_ENTER, + IDFROM_TSPI_providerEnumDevices, + &dwPermanentProviderID + ); + + // Enumerate the number of device + // + DevlineEnum(lpdwNumLines); + *lpdwNumPhones = 0; + + // Initialize the global parameters + // + gfnLineCreateProc = lpfnLineCreateProc; + gdwProviderID = dwPermanentProviderID; + ghProvider = hProvider; + + TRACE4(IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_providerEnumDevices, + &dwPermanentProviderID, + ERROR_SUCCESS); + + DBG_EXIT_UL("TSPI_providerEnumDevices", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG TSPIAPI TSPI_providerInit(DWORD dwTSPIVersion, DWORD ppid) +// +// Function: Initializes the global data strucutres. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG TSPIAPI TSPI_providerInit(DWORD dwTSPIVersion, + DWORD dwPermanentProviderID, + DWORD dwLineDeviceIDBase, + DWORD dwPhoneDeviceIDBase, + DWORD dwNumLines, + DWORD dwNumPhones, + ASYNC_COMPLETION cbCompletionProc, + LPDWORD lpdwTSPIOptions) +{ + DWORD dwDevicePorts = 0; // Number of modem devices + DWORD retcode ; + BOOL fModemUILoaded=FALSE; + HDEVINFO hdevinfo=NULL; + + DBG_ENTER_UL("TSPI_providerInit", dwPermanentProviderID); + + // Initialize tracing facilities + // + traceInitialize(dwPermanentProviderID); + + TRACE3( + IDEVENT_TSPFN_ENTER, + IDFROM_TSPI_providerInit, + &dwTSPIVersion + ); + + ASSERT(gdwProviderID == dwPermanentProviderID); + + + + // Initialize the global parameters + // + tspInitGlobals(); + + // Load MODEMUI.DLL (for private entry points) + fModemUILoaded=TRUE; + if (!LoadModemUI()) + { + fModemUILoaded=FALSE; + goto CleanUp; + } + + + // For the modem device, get the device information + hdevinfo = GetHDevInfo(DIGCF_PRESENT); + if (!hdevinfo) + { + goto CleanUp; + } + + + if (TRACINGENABLED()) + { + cbCompletionProc = traceSetCompletionProc(cbCompletionProc); + } + + gfnCompletionCallback = cbCompletionProc; + + // + // init common modem info list + // + InitializeModemCommonList( + &gCommonList + ); + + InitializeCriticalSection( + &ServiceControlerCriticalSection + ); + + + + // Initialize the line structures + // + retcode = DevlineInitialize(dwLineDeviceIDBase, &dwDevicePorts); + + if (retcode != ERROR_SUCCESS) { + + // + // cleanup common modem info + // + RemoveCommonList( + &gCommonList + ); + + DeleteCriticalSection( + &ServiceControlerCriticalSection + ); + + } + +CleanUp: + + if (hdevinfo != NULL) { + + FreeHDevInfo(hdevinfo); + } + + if(fModemUILoaded) + { + UnloadModemUI(); + } + + TRACE4( + IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_providerInit, + &dwTSPIVersion, + retcode + ); + + if (retcode != ERROR_SUCCESS) + { + // Deinit tracing + // + traceDeinitialize(); + } + + DBG_EXIT_UL("TSPI_providerInit", retcode); + return retcode; +} + +//**************************************************************************** +// LONG TSPIAPI TSPI_providerShutdown(DWORD dwTSPIVersion) +// +// Function: Cleans up all the global data structures. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG TSPIAPI TSPI_providerShutdown(DWORD dwTSPIVersion, + DWORD dwPermanentProviderID) +{ + DBG_ENTER_UL("TSPI_providerShutdown", dwTSPIVersion); + + TRACE3( + IDEVENT_TSPFN_ENTER, + IDFROM_TSPI_providerShutdown, + &dwTSPIVersion + ); + +#ifdef DYNA_ADDREMOVE + // Complete any re-enumeration that may be in progress.. + // + CplNotifComplete(TRUE); +#endif // DYNA_ADDREMOVE + + // Clean up modem lines + // + DevlineShutdown(); + + + // + // cleanup common modem info + // + RemoveCommonList( + &gCommonList + ); + + // Clean up the global parameters + // + gfnCompletionCallback = NULL; // The async completion callback + gfnLineCreateProc = NULL; + + StopModemDriver(); + + DeleteCriticalSection( + &ServiceControlerCriticalSection + ); + + TRACE4( + IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_providerShutdown, + &dwTSPIVersion, + ERROR_SUCCESS + ); + + // DeInit TSP Globals + tspDeInitGlobals(); + + // Deinit tracing + // + traceDeinitialize(); + + DBG_EXIT_UL("TSPI_providerShutdown", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG TSPIAPI TSPI_lineNegotiateTSPIVersion() +// +// Function: Negotiates the service provider version. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG TSPIAPI TSPI_lineNegotiateTSPIVersion(DWORD dwDeviceID, + DWORD dwLowVersion, + DWORD dwHighVersion, + LPDWORD lpdwTSPIVersion) +{ + PLINEDEV pLineDev = NULL; + LONG lRet = LINEERR_OPERATIONFAILED; // assume failure + + DBG_DDI_ENTER("TSPI_lineNegotiateTSPIVersion"); + + TRACE3( + IDEVENT_TSPFN_ENTER, + IDFROM_TSPI_lineNegotiateTSPIVersion, + &dwDeviceID + ); + // Check the range of the device ID + // + if((dwDeviceID == INITIALIZE_NEGOTIATION) || + ((pLineDev = GetCBfromID(dwDeviceID)) != NULL)) + { + // Do not use the line device + // + if (pLineDev) + { + RELEASE_LINEDEV(pLineDev); + } + + // Check the version range + // + if((dwLowVersion > MDMSPI_VERSION) || (dwHighVersion < MDMSPI_VERSION)) + { + *lpdwTSPIVersion = 0; + lRet= LINEERR_INCOMPATIBLEAPIVERSION; + goto end; + } + else + { + *lpdwTSPIVersion = MDMSPI_VERSION; + lRet= ERROR_SUCCESS; + goto end; + }; + }; + + // The requested device doesn't exist. + lRet = LINEERR_NODEVICE; + +end: + + TRACE4( + IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_lineNegotiateTSPIVersion, + &dwDeviceID, + lRet + ); + DBG_DDI_EXIT("TSPI_lineNegotiateTSPIVersion", lRet); + + return lRet; + +} + +//**************************************************************************** +// LONG DevlineEnum() +// +// Function: enumerates the current number of modems +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG DevlineEnum(LPDWORD lpdwNumLines) +{ + COUNTINFO ci; + DWORD dwRet; + + ci.cModem = 0; + + if ((dwRet = EnumerateModems(CountModemCallback, (LPVOID)&ci, FALSE)) == ERROR_SUCCESS) + *lpdwNumLines = ci.cModem; + else + *lpdwNumLines = 0; + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineInitialize() +// +// Function: initializes the modem device list +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG DevlineInitialize (DWORD dwBaseID, + LPDWORD lpdwNumDevs) +{ + INITINFO initi; + DWORD dwRet; + + initi.dwBaseID = dwBaseID; + initi.cModem = 0; + + + MdmInitTracing(); + + dwRet = EnumerateModems(InitModemCallback, (LPVOID)&initi, FALSE); + if (dwRet == ERROR_SUCCESS) + { + *lpdwNumDevs = initi.cModem; + // Initialize Timer services + // + if ((dwRet = InitializeMdmTimer()) == ERROR_SUCCESS) + { + // Initialize the asynchronous thread + // + if ((dwRet = InitializeMdmThreads()) != ERROR_SUCCESS) + { + DeinitializeMdmTimer(); + }; + }; + } + else + *lpdwNumDevs = 0; + + if (dwRet!=ERROR_SUCCESS) + { + MdmDeinitTracing(); + } + + return dwRet; +} + +//**************************************************************************** +// LONG DevlineShutdown() +// +// Function: destroys the modem device list and resources +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +//**************************************************************************** + +LONG DevlineShutdown () +{ + PLINEDEV pLineDev; + + // Deinitialize the modem thread + // + DeinitializeMdmThreads(); + DeinitializeMdmTimer(); + + // Destroy the modem line device one at a time. + // + do + { + // If there is another modem to clean up + // + if ((pLineDev = GetFirstCB()) != NULL) + { + // Clean up the allocated resources + // + CleanupLineDev(pLineDev); + RELEASE_LINEDEV(pLineDev); + + // Now delete the modem device + // + DeleteCB(pLineDev); + }; + } + while (pLineDev != NULL); + + MdmDeinitTracing(); + + return ERROR_SUCCESS ; +} + +//**************************************************************************** +// void CleanupLineDev(PLINEDEV) +// +// Function: Frees the resources owned by the modem line device. +// +// Returns: None. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +// +//**************************************************************************** + +void CleanupLineDev(PLINEDEV pLineDev) +{ + int i; + + if (pLineDev->DroppingEvent != NULL) { + + CloseHandle(pLineDev->DroppingEvent); + + pLineDev->DroppingEvent=NULL; + } + + // Clean up the allocated resources + // + if (pLineDev->hIcon != NULL) + { + DestroyIcon(pLineDev->hIcon); + }; + + if (pLineDev->pDevCfg != NULL) { + + LocalFree((HLOCAL)pLineDev->pDevCfg); + + pLineDev->pDevCfg=NULL; + } + +} + +//**************************************************************************** +// PLINEDEV CreateLineDev(HKEY hKey, DWORD dwID, BOOL fReCreate) +// +// Function: Create a new LINEDEV structure and initilaizes it. +// If fReCreate is TRUE, the following happens: +// -- if it exists, it will return NULL, but will set the +// LINEDEVFLAGS_REINIT flag of pLineDev->fdwResources of +// the existing device. +// -- if it does not exist, it will create it, and also set +// the above flag. +// If fReCreate is FALSE, it will not check if the device exists +// and will NOT set the LINEDEVFAGS_REINIT bit. +// +// Returns: a pointer to the new line device CB on success or +// NULL on failure. +// +// History: +// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont] +// Ported from Win95. +// +//**************************************************************************** + +PLINEDEV CreateLineDev(HKEY hKey, DWORD dwID, BOOL fReCreate) +{ + PLINEDEV pLineDev=NULL; + TCHAR rgtchDeviceName[sizeof(pLineDev->szDeviceName)/sizeof(TCHAR)]; + DWORD dwRegSize = sizeof(rgtchDeviceName); + DWORD dwRegType; + DWORD dwRet; + BYTE bDeviceType; + REGDEVCAPS regdevcaps; + HKEY hKeySettings; + int i; + FINDINFO fi; + TCHAR pszTemp[HAYES_COMMAND_LENGTH+1]; + + + // Get the Friendly Name + ASSERT(dwRegSize == sizeof(pLineDev->szDeviceName)); + dwRet = RegQueryValueEx( + hKey, + cszFriendlyName, + NULL, + &dwRegType, + (VOID *) rgtchDeviceName, + &dwRegSize + ); + + if (dwRet != ERROR_SUCCESS || dwRegType != REG_SZ) + { + goto end; + } + +#ifdef DYNA_ADDREMOVE + if (fReCreate) + { + // determine if we've already got this device in our list... + pLineDev = GetCBfromName (rgtchDeviceName); + if (pLineDev) + { + DPRINTF1("ReCreate: Modem exists: %s", rgtchDeviceName); + pLineDev->fdwResources |= LINEDEVFLAGS_REINIT; + pLineDev->fdwResources &= ~LINEDEVFLAGS_OUTOFSERVICE; + RELEASE_LINEDEV(pLineDev); + pLineDev=NULL; + goto end; + } + } +#endif //DYNA_ADDREMOVE + + // New modem! + + if ((pLineDev = AllocateCB(sizeof(LINEDEV))) == NULL) + { + goto end; + } + + pLineDev->DroppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (pLineDev->DroppingEvent == NULL) { + + goto FailedExit; + } + + // Initialize its control block + // + // pLineDev->hIcon = NULL; + // pLineDev->pDevCfg = NULL; + // + pLineDev->dwVersion = UMDM_VERSION; + pLineDev->dwID = dwID; + lstrcpy(pLineDev->szDeviceName, rgtchDeviceName); + + // Get the Driver Key + fi.lpszDeviceName = pLineDev->szDeviceName; + fi.fFound = FALSE; + fi.lphkey = NULL; + fi.lpszID = pszTemp; + fi.cbID = sizeof(pszTemp); + EnumerateModemKeys(SearchModemCallback, (LPVOID)&fi); + if (!fi.fFound) + { + goto FailedExit; + } + + lstrcpyn(pLineDev->szDriverKey, cszHWNode, sizeof(pLineDev->szDriverKey)); + lstrcat(pLineDev->szDriverKey, TEXT("\\")); + lstrcat(pLineDev->szDriverKey, pszTemp); + + // Read in the permanent ID + dwRegSize = sizeof(pLineDev->dwPermanentLineID); + if (RegQueryValueEx(hKey, cszID, NULL, &dwRegType, + (VOID *)&pLineDev->dwPermanentLineID, + &dwRegSize) != ERROR_SUCCESS || + dwRegType != REG_BINARY) + { + goto FailedExit; + } + + // Read in the REGDEVCAPS + dwRegSize = sizeof(regdevcaps); + if (RegQueryValueEx(hKey, cszProperties, NULL, &dwRegType, + (VOID *)®devcaps, + &dwRegSize) != ERROR_SUCCESS || + dwRegType != REG_BINARY) + { + goto FailedExit; + } + else + { + // + // We want to make sure the following flags are identical + // + #if (LINEDEVCAPFLAGS_DIALBILLING != DIALOPTION_BILLING) + #error LINEDEVCAPFLAGS_DIALBILLING != DIALOPTION_BILLING (check tapi.h vs. mcx16.h) + #endif + #if (LINEDEVCAPFLAGS_DIALQUIET != DIALOPTION_QUIET) + #error LINEDEVCAPFLAGS_DIALQUIET != DIALOPTION_QUIET (check tapi.h vs. mcx16.h) + #endif + #if (LINEDEVCAPFLAGS_DIALDIALTONE != DIALOPTION_DIALTONE) + #error LINEDEVCAPFLAGS_DIALDIALTONE != DIALOPTION_DIALTONE (check tapi.h vs. mcx16.h) + #endif + // + + // Make sure this is the dwDialOptions DWORD we want. + ASSERT(!(regdevcaps.dwDialOptions & ~(LINEDEVCAPFLAGS_DIALBILLING | + LINEDEVCAPFLAGS_DIALQUIET | + LINEDEVCAPFLAGS_DIALDIALTONE))); + pLineDev->dwDevCapFlags = regdevcaps.dwDialOptions; + + pLineDev->dwMaxDCERate = regdevcaps.dwMaxDCERate; + + pLineDev->dwModemOptions = regdevcaps.dwModemOptions; + } + + // Analyze device type and set mediamodes appropriately + dwRegSize = sizeof(BYTE); + if (RegQueryValueEx(hKey, cszDeviceType, NULL, &dwRegType, + &bDeviceType, &dwRegSize) != ERROR_SUCCESS || + dwRegType != REG_BINARY || + dwRegSize != sizeof(BYTE)) + { + goto FailedExit; + } + else + { + // Remember the type + // + pLineDev->bDeviceType = bDeviceType; + + switch (bDeviceType) + { + case DT_PARALLEL_PORT: + pLineDev->bDeviceType = DT_NULL_MODEM; // Map back to null modem + // FALLTHROUGH + + case DT_NULL_MODEM: + pLineDev->dwDefaultMediaModes = LINEMEDIAMODE_DATAMODEM; + pLineDev->dwBearerModes = LINEBEARERMODE_DATA | LINEBEARERMODE_PASSTHROUGH; + pLineDev->fPartialDialing = FALSE; + break; + + case DT_PARALLEL_MODEM: + pLineDev->bDeviceType = DT_EXTERNAL_MODEM; // Map back to external modem + // FALLTHROUGH + + case DT_EXTERNAL_MODEM: + case DT_INTERNAL_MODEM: + case DT_PCMCIA_MODEM: + pLineDev->dwDefaultMediaModes = LINEMEDIAMODE_DATAMODEM | + LINEMEDIAMODE_INTERACTIVEVOICE; +#ifdef VOICEVIEW + { + BYTE bVoiceView; + + dwRegSize = 1; + if ((RegQueryValueEx(hKeySoftware, cszVoiceView, 0, &dwRegType, &bVoiceView, &dwRegSize) == ERROR_SUCCESS) && + (bVoiceView == 1)) + { + pLineDev->dwDefaultMediaModes |= LINEMEDIAMODE_VOICEVIEW; + } + } +#endif // VOICEVIEW + pLineDev->dwBearerModes = LINEBEARERMODE_VOICE | LINEBEARERMODE_PASSTHROUGH; + + // read in Settings\DialSuffix to check whether we can partial dial + pLineDev->fPartialDialing = FALSE; // assume false + if (RegOpenKey(hKey, cszSettings, &hKeySettings) == ERROR_SUCCESS) + { + dwRegSize = HAYES_COMMAND_LENGTH; + if (RegQueryValueEx(hKeySettings, cszDialSuffix, NULL, &dwRegType, (VOID *)pszTemp, &dwRegSize) == ERROR_SUCCESS && + dwRegSize > sizeof(TCHAR)) + { + pLineDev->fPartialDialing = TRUE; + } + RegCloseKey(hKeySettings); + } + break; + + default: + goto FailedExit; + } + } + + // Init line. + NullifyLineDevice(pLineDev); + + // + // get the default commconfig + // + dwRet = DevlineGetDefaultConfig(pLineDev,hKey); + + if (dwRet != ERROR_SUCCESS) { + + goto FailedExit; + } + + + +#ifdef UNDER_CONSTRUCTION + + // Check the devnode status + // If it does not exist or has a problem, mark it as out of service + // + if (!IsDeviceInService(szID)) + { + pLineDev->fdwResources |= LINEDEVFLAGS_OUTOFSERVICE; + }; + +#endif // UNDER_CONSTRUCTION + + if (fReCreate) + { + pLineDev->fdwResources |= LINEDEVFLAGS_REINIT; + } + + // We made it this far, we're GOLDEN! + goto end; + +FailedExit: + DPRINTF("Modem unusable because of corrupt registry entry."); + + // Cleanup the allocated resource + // + CleanupLineDev(pLineDev); + + // Free the modem CB and its resources + // + DeleteCB(pLineDev); + pLineDev = NULL; + // Fall through... + +end: + + return pLineDev; +} + + +//**************************************************************************** +// LONG DevlineGetDefaultConfig(PLINEDEV) +// +// Function: Get modem default configuratio +// +// Returns: ERROR_SUCCESS if success +// LINEERR_NOMEM if out of memory +// +// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont] +// created +//**************************************************************************** + +LONG DevlineGetDefaultConfig(PLINEDEV pLineDev, HKEY hKey) +{ + PDEVCFG pDevCfg; + COMMCONFIG * pcommconfig; + DWORD dwCCSize; + LONG lResult; + + dwCCSize = sizeof(MODEMSETTINGS)+FIELDOFFSET(COMMCONFIG, wcProviderData); + + pDevCfg = (PDEVCFG)LocalAlloc(LPTR, sizeof(DEVCFGHDR)+(UINT)dwCCSize); + + if (pDevCfg == NULL) { + + return LINEERR_NOMEM; + } + + pcommconfig = (COMMCONFIG *)&(pDevCfg->commconfig); + + // Default setting + // + pDevCfg->dfgHdr.dwSize = sizeof(DEVCFGHDR) + dwCCSize; + pDevCfg->dfgHdr.dwVersion = MDMCFG_VERSION; + SETWAITBONG(pDevCfg, DEF_WAIT_BONG); + SETOPTIONS(pDevCfg, (IS_NULL_MODEM(pLineDev) ? + TERMINAL_NONE : TERMINAL_NONE | LAUNCH_LIGHTS)); + pcommconfig->dwProviderSubType = PST_MODEM; + + ASSERT(gUmdm.pfnPrivateDefCommConfig != NULL); + + lResult=(*gUmdm.pfnPrivateDefCommConfig)(hKey, pcommconfig, &dwCCSize); + + if (ERROR_SUCCESS == lResult) { + + pLineDev->pDevCfg = pDevCfg; + + } else { + + LocalFree( + pDevCfg + ); + } + + + return lResult; + + +} + + + + + + + + + + + +//**************************************************************************** +// BOOL CountModemCallback (HKEY hkey, LPVOID lpData) +// +// Function: Count the enumerated modems. +// +// Returns: TRUE always to continue +// +//**************************************************************************** + +BOOL CountModemCallback (HKEY hkey, LPVOID lpData) +{ + LPCOUNTINFO lpCntInfo = (LPCOUNTINFO)lpData; + + (lpCntInfo->cModem)++; + return TRUE; +} + +//**************************************************************************** +// BOOL InitModemCallback (HKEY hkey, LPVOID lpData) +// +// Function: Initialize the enumerated modems. +// +// Returns: TRUE always to continue +// +//**************************************************************************** + +BOOL InitModemCallback (HKEY hkey, LPVOID lpData) +{ + PLINEDEV pMdmDev; + LPINITINFO lpInitInfo = (LPINITINFO)lpData; + + if ((pMdmDev = CreateLineDev(hkey, + lpInitInfo->dwBaseID + + lpInitInfo->cModem, + FALSE)) != NULL) + { + // Insert into the LINEDEV list + // + AddCBToList(pMdmDev); + (lpInitInfo->cModem)++; + }; + return TRUE; +} + +//**************************************************************************** +// EnumerateModems() +// +// Function: Enumerate the modem. +// +//**************************************************************************** + +LONG NEAR PASCAL EnumerateModems (ENUMMDMCALLBACK pfnCallback, + LPVOID lpData, + BOOL fAll) +{ + HDEVINFO hdevinfo; + SP_DEVINFO_DATA diData; + DWORD iEnum; + BOOL fContinue; + HKEY hkey; + DWORD dwRW = KEY_READ; + // DWORD dwDIGCF = (fAll) ? DIGCF_PROFILE : DIGCF_PRESENT; + BOOL fFreeDevInfo=FALSE; + DWORD dwDIGCF = DIGCF_PRESENT; + if (USER_IS_ADMIN()) dwRW |= KEY_WRITE; + + // Get the device info set + // + hdevinfo = GetHDevInfo(dwDIGCF); + + if (hdevinfo != NULL) + { + // Enumerate each modem + // + fFreeDevInfo=TRUE; + fContinue = TRUE; + iEnum = 0; + diData.cbSize = sizeof(diData); + while(fContinue && SetupDiEnumDeviceInfo(hdevinfo, iEnum, &diData)) + { + // Get the driver key + // + hkey = SetupDiOpenDevRegKey(hdevinfo, &diData, DICS_FLAG_GLOBAL, 0, + DIREG_DRV, dwRW); + if (hkey == INVALID_HANDLE_VALUE) + { + DPRINTF1( + "SetupDiOpenDevRegKeyfailed, err=0x%lx", + GetLastError() + ); + } + else + { + fContinue = (*pfnCallback)(hkey, lpData); + + RegCloseKey(hkey); + }; + + // Find next modem + // + iEnum++; + }; + FreeHDevInfo(hdevinfo); + }; + + + return ERROR_SUCCESS; + +} + +//**************************************************************************** +// BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData) +// +// Function: Search the enumerated modems for a matching modem. +// +// Returns: TRUE if not match and continue searching +// +//**************************************************************************** + +BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData) +{ + LPFINDINFO lpFindInfo = (LPFINDINFO)lpData; + TCHAR szDevice[MAXDEVICENAME+1]; + DWORD dwRegType, dwRegSize; + BOOL fContinue = TRUE; + + // Get the Friendly Name + // + dwRegSize = sizeof(szDevice); + if ((RegQueryValueEx(hkey, cszFriendlyName, NULL, + &dwRegType, (VOID *)szDevice, &dwRegSize) + == ERROR_SUCCESS) && (dwRegType == REG_SZ)) + { + // Is this the device? + // + if (!lstrcmpi(lpFindInfo->lpszDeviceName, szDevice)) + { + // BUG! BUG! the key will be closed + // + if (lpFindInfo->lphkey != NULL) + { + *lpFindInfo->lphkey = hkey; + }; + + // Do we need the Instance ID? + // + if ((lpFindInfo->lpszID != NULL) && + (lpFindInfo->cbID > 0)) + { + // Return the instance ID + // + lstrcpyn(lpFindInfo->lpszID, szKey, + lpFindInfo->cbID); + }; + + // Mark that we found it + lpFindInfo->fFound = TRUE; + fContinue = FALSE; + }; + }; + return fContinue; +} + +//**************************************************************************** +// EnumerateModemKeys() +// +// Function: Enumerate the modem driver key. +// +//**************************************************************************** + +LONG NEAR PASCAL EnumerateModemKeys (ENUMMDMKEYCALLBACK pfnCallback, + LPVOID lpData) +{ + HKEY hkey, hkeyEnumNode; + UINT iEnum; + TCHAR szEnumNode[REGSTR_MAX_VALUE_LENGTH+1]; + BOOL fTerminate; + DWORD dwRegType, dwRegSize; + + // Initialize the global enumeration parameters + // + fTerminate = FALSE; + + // Get the key to the modem hardware node + if (RegOpenKey(HKEY_LOCAL_MACHINE, cszHWNode, &hkey) == ERROR_SUCCESS) + { + // Enumerate the enumerator + iEnum = 0; + while ((!fTerminate) && + (RegEnumKey(hkey, iEnum, szEnumNode, + sizeof(szEnumNode)) == ERROR_SUCCESS )) + { + // Open the modem node for this enumerator + if (RegOpenKey(hkey, szEnumNode, &hkeyEnumNode) == ERROR_SUCCESS) + { + // Allow the callback function to do their stuff + fTerminate = !(*pfnCallback)(hkeyEnumNode, szEnumNode, lpData); + + RegCloseKey(hkeyEnumNode); + }; + iEnum++; + }; + RegCloseKey(hkey); + }; + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG +// PASCAL +// ProviderInstall( +// LPTSTR pszProviderName, +// BOOL bNoMultipleInstance +// ) +// +// Function: Check to see if a service provider is already installed. Returns +// appropriate TSPI error code to be passed back from +// TUISPI_providerInstall. +// +// History: +// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo] +// Ported from TAPI's atsp32. Periodically, make sure it is in sync to catch +// any bugs fixed in that code. +//**************************************************************************** + +LONG +PASCAL +ProviderInstall( + LPTSTR 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; + + + lResult = LINEERR_OPERATIONFAILED; // assume failure + + + // + // Load Tapi32.dll & get a pointer to the lineGetProviderList + // func. We could just statically link with Tapi32.lib and + // avoid the hassle (and this wouldn't have any adverse + // performance effects because of the fact that this + // implementation has a separate ui dll that runs only on the + // client context), but a provider who implemented these funcs + // in it's TSP module would want to do an explicit load like + // we do here to prevent the perf hit of Tapi32.dll always + // getting loaded in Tapisrv.exe's context. + // + + if (!(hTapi32 = LoadLibrary (TEXT("tapi32.dll")))) + { + DPRINTF1( + "LoadLibrary(tapi32.dll) failed, err=%d", + GetLastError() + ); + + goto ProviderInstall_return; + } + + if (!((FARPROC) pfnGetProviderList = GetProcAddress( + hTapi32, +#ifdef UNICODE + (LPCSTR) "lineGetProviderListW" +#else // UNICODE + (LPCSTR) "lineGetProviderList" +#endif // UNICODE + ))) + { + DPRINTF1( + "GetProcAddr(lineGetProviderList) failed, err=%d", + GetLastError() + ); + + goto ProviderInstall_unloadTapi32; + } + + + // + // Loop until we get the full provider list + // + + dwTotalSize = sizeof (LINEPROVIDERLIST); + + goto ProviderInstall_allocProviderList; + +ProviderInstall_getProviderList: + + if ((*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++) + { + LPTSTR pszInstalledProviderName = + (LPTSTR) ((LPBYTE) pProviderList + + pProviderEntry->dwProviderFilenameOffset); + LPTSTR psz; + + +#ifdef DONT_WANT_C_RUNTIME + if ((psz = strrchr (pszInstalledProviderName, '\\'))) + { + pszInstalledProviderName = psz + 1; + } +#else // DONT_WANT_C_RUNTIME + // The above code was trying to handle the case where a directory + // path gets returned. We need to do this in a way that doesn't + // load the C runtime code. Ie. search for the last '\\'. + { + LPTSTR pchLastWack; + + pchLastWack = NULL; + psz = pszInstalledProviderName; + + // Find the last '\\'. + while (*psz) + { + if (*psz == TEXT('\\')) + { + pchLastWack = psz; + } + psz++; + } + + if (pchLastWack) + { + pszInstalledProviderName = pchLastWack + 1; + } + } +#endif // DONT_WANT_C_RUNTIME + + if (lstrcmpi (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; +} + + + +#ifdef UNDER_CONSTRUCT + +TCHAR gszModem[]="Modem"; + +LONG WINAPI +AddModemDependency( + VOID + ) + +{ + + schSCManager=OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager != NULL) { + // + // now on service + // + schModemSys=OpenService( + schSCManager, + TEXT("tapisrv"), + SERVICE_ALL_ACCESS + ); + + if (schModemSys != NULL) { + + + ServiceConfig=LocalAlloc(lptr, 4096); + + if (ServiceConfig == NULL) { + + goto Fail; + } + + lResult=QueryServiceConfig( + schModemSys, + ServiceConfig, + 4096, + &BytesNeeded + ); + + if (ERROR_SUCCESS != lResult) { + + got Fail; + } + + Length=RemoveModemSys( + ServiceConfig.lpDependencies + ); + + + NewDependList=LocalAlloc(LPTR,Length+sizeof(gszModem)+2); + + if (NewDependList == NULL) { + + goto Fail;; + } + + + AddModemToDepend( + ServiceConfig.lpDependencies, + NewDependList + ); + + ServiceConfig.lpDependencies=NewDependList; + + lResult=ChangeServiceConfig( + schModemSys, + ServiceConfig.dwServiceType, + ServiceConfig.dwStartType, + ServiceConfig.dwErrorControl, + ServiceConfig.lpBinaryPathName, + &TagValue, + ServiceConfig.dwTagId, + NewDependList, + ServiceConfig.lpServiceStartName, + NULL, + ServiceConfig.lpDisplayName + ); + + + + +//**************************************************************************** +// LONG TSPIAPI TSPI_providerCreateLineDevice() +// +// Dynamically creates a new device. +// +//**************************************************************************** + +LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID, + DWORD dwDeviceID) +{ + + LONG lResult = LINEERR_OPERATIONFAILED; // assume failure + DBG_DDI_ENTER("TSPI_providerCreateLineDevice"); + + + TRACE3( + IDEVENT_TSPFN_ENTER, + IDFROM_TSPI_providerCreateLineDevice, + &dwTempID + ); + + // Let the device level handle it + // + lResult = DevlineNewDevice(dwTempID, dwDeviceID); + + TRACE4( + IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_providerCreateLineDevice, + &dwTempID, + lResult + ); + + DBG_DDI_EXIT("TSPI_providerCreateLineDevice", lResult); + return lResult; +} + +//**************************************************************************** +// IsDeviceInService() +// +// Function: Finds the specified modem in the current modem list +// +//**************************************************************************** + +BOOL NEAR PASCAL IsDeviceInService(LPSTR szID) +{ + DEVNODE dn; + DWORD dwStatus, dwProblem; + BOOL fRet = FALSE; + + // Locate the devnode + // + if (CM_Locate_DevNode(&dn, szID, 0) == ERROR_SUCCESS) + { + // The devnode exists, check the devnode status + // + if (CM_Get_DevNode_Status(&dwStatus, &dwProblem, dn, 0) == ERROR_SUCCESS) + { + // If the device is in service only when it has no problem + // + fRet = ((dwStatus & DN_STARTED) != 0); + }; + }; + + return fRet; +} + +//**************************************************************************** +// FindModemHWKey() +// +// Function: Finds the specified modem's hardware registry key +// +//**************************************************************************** + +DWORD NEAR PASCAL FindModemHWKey (LPSTR pszDeviceName, HKEY FAR* lphkey, + LPSTR pszID, UINT cbID) +{ + FINDINFO fi; + + // Package the enumeration data + // + fi.lpszDeviceName = (LPSTR)pszDeviceName; + fi.fFound = FALSE; + fi.lphkey = lphkey; + fi.lpszID = (LPSTR)pszID; + fi.cbID = cbID; + + // Find the modem + // + return ((EnumerateModemKeys(SearchModemCallback, (LPVOID)&fi) == ERROR_SUCCESS) && + (fi.fFound)) ? ERROR_SUCCESS : ERROR_BAD_DEVICE; +} + +//**************************************************************************** +// lineNewDevice() +// +// Function: Emulate the TAPI lineInitialize call. +// +//**************************************************************************** + +LONG NEAR PASCAL DevlineNewDevice (DWORD dwTempID, + DWORD dwPermID) +{ + HLOCAL hDeviceName; + PSTR pDeviceName; + HKEY hkeyModem; + DWORD dwRet; + char szID[MAXDEVICENAME+1]; + + // Get the name of the device + // + hDeviceName = (HLOCAL)LOWORD(dwTempID); + if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) == NULL) + return LINEERR_BADDEVICEID; + + // Assume failure + // + dwRet = LINEERR_OPERATIONFAILED; + + // if we found the device, create the LINEDEV struct for it + // + if (FindModemHWKey(pDeviceName, &hkeyModem, szID, sizeof(szID)) + == ERROR_SUCCESS) + { + PLINEDEV pLineDev; + + if ((pLineDev = CreateLineDev(hkeyModem, dwPermID, szID)) != NULL) + { + // Insert into the LINEDEV list + // + pLineDev->pNext = gMdmDev; + gMdmDev = pLineDev; + dwRet = SUCCESS; + }; + + RegCloseKey(hkeyModem); + }; + + LocalUnlock(hDeviceName); + LocalFree(hDeviceName); + + return dwRet; +} + +//**************************************************************************** +// lineDisabled() +// +// Function: Remove the LineDev structure. +// +//**************************************************************************** + +LONG NEAR PASCAL DevlineDisabled (PLINEDEV pLineDev) +{ + PLINEDEV pCur, pPrevious; + + // Notify TAPI for device out of service + // + if (pLineDev->lpfnEvent != NULL) + { + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_LINEDEVSTATE, + (pLineDev->fdwResources & LINEDEVFLAGS_REMOVING ? + LINEDEVSTATE_REMOVED : LINEDEVSTATE_OUTOFSERVICE), + 0L, 0L); + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE, + 0L, 0L, 0L); + }; + + // If removal, free the resources for this modem + // + if (pLineDev->fdwResources & LINEDEVFLAGS_REMOVING) + { + // Walk the modem list + // + pPrevious = NULL; + pCur = gMdmDev; + while (pCur) + { + if (pCur == pLineDev) + break; + + pPrevious = pCur; + pCur = pCur->pNext; + }; + + // Remove it from the list + // + if (pPrevious != NULL) + pPrevious->pNext = pLineDev->pNext; + else + gMdmDev = pLineDev->pNext; + + // Free linedev's resources + // + CleanupLineDev(pLineDev); + + if (pLineDev->pDevCfg != NULL) + LocalFree((HLOCAL)pLineDev->pDevCfg); + + // Deallocate the port + // + LocalFree((HLOCAL)pLineDev); + }; + + return SUCCESS; +} + +//**************************************************************************** +// MdmDeviceChangeNotify() +// +// Function: Notify a change in modem list. +// +// Returns: SUCCESS +// +//**************************************************************************** + +DWORD NEAR PASCAL MdmDeviceChangeNotify (UINT uEvent, LPSTR szDevice) +{ + HLOCAL hDeviceName; + PSTR pDeviceName; + + // Allocate a local buffer for the device name + // + if ((hDeviceName = LocalAlloc(LMEM_MOVEABLE, + sizeof(TCHAR) * (MAXDEVICENAME+1))) != NULL) + { + if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) != NULL) + { + // Remember the new device name + // + lstrcpyn((LPSTR)pDeviceName, szDevice, MAXDEVICENAME+1); + LocalUnlock(hDeviceName); + + // Signal ourselves to start adding at a better time + // + PostMessage(ghwndMdm, WM_MDMCHANGE, (WPARAM)uEvent, + (LPARAM)MAKELONG(hDeviceName, 0)); + } + else + { + LocalFree(hDeviceName); + }; + }; + return SUCCESS; +} + +//**************************************************************************** +// MdmDeviceChanged() +// +// Function: Handle a device change notification. +// +// Returns: SUCCESS +// +//**************************************************************************** + +DWORD NEAR PASCAL MdmDeviceChanged (UINT uEvent, LPARAM lParam) +{ + HLOCAL hDeviceName; + PSTR pDeviceName; + PLINEDEV pLineDev; + + // Get the name of the modem that is changed + // + hDeviceName = (HLOCAL)LOWORD(lParam); + if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) == NULL) + { + // Excuse me! something is terribly wrong here. + // + ASSERT(0); + return ERROR_INVALID_HANDLE; + }; + + // Search for an existing device + // + pLineDev = GetCBfromName(pDeviceName); + LocalUnlock(hDeviceName); + + // Determine the type of change + // + switch (uEvent) + { + //************************************************************************ + // Notify TAPI of the new device + //************************************************************************ + + case UMDM_ADD: + { + // If not found, it is a new device + // + if (pLineDev == NULL) + { + (*gfnLineCreateProc)(NULL, NULL, LINE_CREATE, (DWORD)ghProvider, + (DWORD)lParam, 0L); + + // Return here so that the device name token is not freed. + // + return ERROR_SUCCESS; + }; + break; + } + + //************************************************************************ + // Enable modem device, i.e. the modem devnode becomes enabled + //************************************************************************ + + case UMDM_ENABLE: + + // If the device exists and is out of service, make it in service. + // + if (pLineDev != NULL) + { + if (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE) + { + pLineDev->fdwResources &= ~LINEDEVFLAGS_OUTOFSERVICE; + if (pLineDev->lpfnEvent != NULL) + { + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_LINEDEVSTATE, + LINEDEVSTATE_INSERVICE, 0L, 0L); + }; + }; + }; + break; + + //************************************************************************ + // Disable modem device, i.e. the modem devnode becomes disabled, and + // probably remove the modem from the list + //************************************************************************ + + case UMDM_DISABLE: + + // If we found the disabled device + // + if ((pLineDev != NULL) && + (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)) + { + break; + } + + //************************************************************************ + // Fall through + //************************************************************************ + + case UMDM_REMOVE: + + // If we found the disabled device + // + if (pLineDev != NULL) + { + pLineDev->fdwResources |= LINEDEVFLAGS_OUTOFSERVICE; + if (uEvent == UMDM_REMOVE) + { + pLineDev->fdwResources |= LINEDEVFLAGS_REMOVING; + }; + + // Is the modem active? + // + if ((pLineDev->dwCall & CALL_ALLOCATED) && + (pLineDev->dwCallState != LINECALLSTATE_DISCONNECTED)) + { + // We need to clean up the active connection first + // + MdmCompleteAsync (pLineDev, MDM_HANGUP, MDM_ID_NULL); + } + else + { + // The modem might be listening, just close the modem + // + if ((pLineDev->DevState == DEVST_PORTLISTENINIT) || + (pLineDev->DevState == DEVST_PORTLISTENING)) + { + // Notify the monitoring application + // + (*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE, + 0L, 0L, 0L); + DevlineClose(pLineDev); + }; + + // disable or remove it immediately + // + DevlineDisabled(pLineDev); + }; + }; + break; + + default: + break; + }; + + // We no longer need the device name token + // + LocalFree(hDeviceName); + return ERROR_SUCCESS; +} + +#endif //UNDER_CONSTRUCT + + +#ifndef DYNA_ADDREMOVE + +LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID, + DWORD dwDeviceID) +{ + ASSERT(FALSE); + return LINEERR_OPERATIONFAILED; +} + +#else // DYNA_ADDREMOVE + +BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData); +LONG DevlineNewDevice (DWORD dwTempID, DWORD dwPermID); + + +//**************************************************************************** +// LONG DevlineReInitialize() +// +// Function: Re-initializes the modem device list +// +// History: +// 4/15/96 JosephJ Created +//**************************************************************************** + +LONG DevlineReInitialize (DWORD dwBaseID, + LPDWORD lpdwNumDevs) +{ + INITINFO initi; + DWORD dwRet = LINEERR_OPERATIONFAILED; + BOOL fModemUILoaded; + HDEVINFO hdevinfo=NULL; + + // Load MODEMUI.DLL (for private entry points) + fModemUILoaded=TRUE; + if (!LoadModemUI()) + { + fModemUILoaded=FALSE; + goto end; + } + + // For the modem device, get the device information + hdevinfo = GetHDevInfo(DIGCF_PRESENT); + if (!hdevinfo) + { + goto end; + } + + initi.dwBaseID = dwBaseID; + initi.cModem = 0; + + // We do this enumeration inside the global critical section, because there + // Potentially could be more than one tepCplNotif threads active. + // It's almost impossible to do this manually -- one would have to add/remove + // modems real fast in succession so that the 2nd notification comes in when + // the 1st is still proceeding, but it's possible, and we definitely want to + // serialize the marking of all the modems with the REINIT flag and + // subsequently declaring all the unmarked ones out-of-service. Also there + // is the possibility of both threads deciding that a modem needs to be + // created and creating two instances of them. + EnterCriticalSection(&gUmdm.crit); + dwRet = EnumerateModems(ReInitModemCallback, (LPVOID)&initi, TRUE); + if (dwRet == ERROR_SUCCESS) + { + DisableStaleModems(); + *lpdwNumDevs = initi.cModem; + } + else + *lpdwNumDevs = 0; + LeaveCriticalSection(&gUmdm.crit); + +end: + + if (fModemUILoaded) + { + UnloadModemUI(); + } + if (hdevinfo) + { + FreeHDevInfo(hdevinfo); + } + + return dwRet; +} + +//**************************************************************************** +// BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData) +// +// Function: ReInitializes the enumerated modems. +// +// Returns: TRUE always to continue +// +//**************************************************************************** + +BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData) +{ + PLINEDEV pMdmDev; + LPINITINFO lpInitInfo = (LPINITINFO)lpData; + + pMdmDev = CreateLineDev(hkey, MAXDWORD, TRUE); + if (pMdmDev) + { + // Insert into the LINEDEV list + // + AddCBToList(pMdmDev); + (lpInitInfo->cModem)++; + + // Let's callback the LINE_CREATE function here, passing in pMdmDev + // as the handle. + // Note: we haven't claimed any crit-sections at this time. + if (gfnLineCreateProc) + { + (*gfnLineCreateProc)(NULL, NULL, LINE_CREATE, (DWORD)ghProvider, + (DWORD)pMdmDev, 0L); + } + }; + + return TRUE; +} + + +//**************************************************************************** +// LONG TSPIAPI TSPI_providerCreateLineDevice() +// +// Dynamically creates a new device. +// +//**************************************************************************** + +LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID, + DWORD dwDeviceID) +{ + LONG lResult; + + DBG_DDI_ENTER("TSPI_providerCreateLineDevice"); + TRACE3(IDEVENT_TSPFN_ENTER, IDFROM_TSPI_providerCreateLineDevice, &dwTempID); + + // Let the device level handle it + // + lResult = DevlineNewDevice(dwTempID, dwDeviceID); + + TRACE4( + IDEVENT_TSPFN_EXIT, + IDFROM_TSPI_providerCreateLineDevice, + &dwTempID, + lResult + ); + DBG_DDI_EXIT("TSPI_providerCreateLineDevice", lResult); + return lResult; +} + + + +//**************************************************************************** +// lineNewDevice() +// +// Function: Emulate the TAPI lineInitialize call. +// +//**************************************************************************** + +LONG DevlineNewDevice (DWORD dwTempID, + DWORD dwPermID) +{ + LPSTR lpDeviceName; + HKEY hkeyModem; + DWORD dwRet; + char szID[MAXDEVICENAME+1]; + PLINEDEV pLineDev; + + DPRINTF2("DevlineNewDevice(%lu,%lu)", dwTempID, dwPermID); + + // Retrieve the device + // + pLineDev = GetCBfromHandle (dwTempID); + if (!pLineDev) + { + dwRet=LINEERR_BADDEVICEID; + goto end; + } + + // Assume failure + // + dwRet = LINEERR_OPERATIONFAILED; + + // if we found the device, we finish initializing it -- specify + // the proper dwPermID, etc... + // + ASSERT(pLineDev->dwID == MAXDWORD); + pLineDev->dwID=dwPermID; + RELEASE_LINEDEV(pLineDev); + dwRet = ERROR_SUCCESS; + +end: + return dwRet; +} +#endif // DYNA_ADDREMOVE + +// +// Thread Entry Point for the thread that processes cpl notifications. +// +DWORD APIENTRY tepCplNotif(DWORD dwParam) +{ + DWORD dwcbNew; + PNOTIFICATION_FRAME pnf = (PNOTIFICATION_FRAME) dwParam; + + ASSERT(pnf && TSP_CPL_FRAME(pnf)); + + if (pnf->dwFlags&fTSPNOTIF_FLAG_CPL_REENUM) + { + DevlineReInitialize (0, &dwcbNew); + } + else if (pnf->dwFlags&fTSPNOTIF_FLAG_CPL_DEFAULT_COMMCONFIG_CHANGE) + { + if (!(pnf->dwFlags&fTSPNOTIF_FLAG_UNICODE)) + { + ASSERT(FALSE); + } + else + { + // Get friendly name and refresh comm config. + LPCTSTR lpctszFriendlyName = (LPCTSTR) pnf->rgb; + UINT uMaxSize = pnf->dwSize - sizeof(NOTIFICATION_FRAME); + UINT u; + + ASSERT(pnf->dwSize > sizeof(NOTIFICATION_FRAME)); + + // verify string is null-terminated. + for(u=0;ufUpdateDefaultCommConfig=TRUE; + RELEASE_LINEDEV(pLineDev); pLineDev=NULL; + } + } + } + } + + // Our job to free this. + LocalFree(pnf); + + CplNotifComplete(FALSE); + + return ERROR_SUCCESS; +} + + +void cplProcessNotification(PNOTIFICATION_FRAME pnf) +{ + + ASSERT(TSP_CPL_FRAME(pnf)); + { + HANDLE hThread; + DWORD dwTID; + DPRINTF("Processing CPL Notification"); + +#ifdef DYNA_ADDREMOVE + EnterCriticalSection(&gUmdm.critCplNotif); + if (gUmdm.hthrdCplNotif) + { + DPRINTF("cplProcessNotification: Previous CplNotif thread exists. Skipping."); + } + else + { + PNOTIFICATION_FRAME pnfAlloc = + (PNOTIFICATION_FRAME) LocalAlloc + ( + LPTR, + pnf->dwSize + ); + if (pnfAlloc) + { + + CopyMemory(pnfAlloc, pnf, pnf->dwSize); + + // Start the thread to process the notification + // + gUmdm.hthrdCplNotif = CreateThread( + NULL, // default security + 0, // default stack size + (LPTHREAD_START_ROUTINE)tepCplNotif, // thread entry point + pnfAlloc, // parameter + 0, // Start immediately + &dwTID); // thread id + + if (gUmdm.hthrdCplNotif) + { + + DPRINTF2("cplNotification: Created Thread @%lu; TID=0x%lx\n", + GetTickCount(), + dwTID); + } + else + { + DPRINTF1("cplNotification: Created Thread FAILED. Err=%lu\n", + GetLastError()); + LocalFree(pnfAlloc); + pnfAlloc=NULL; + } + } + } + LeaveCriticalSection(&gUmdm.critCplNotif); +#endif // DYNA_ADDREMOVE + } +} + + +#ifdef DYNA_ADDREMOVE +HDEVINFO GetHDevInfo(DWORD dwDIGCF) +{ + HDEVINFO hdevinfo=NULL; + + EnterCriticalSection(&gUmdm.crit); + + if (!gUmdm.dwcRefHDevInfo) + { + gUmdm.hdevinfo = SetupDiGetClassDevsW( + g_pguidModem, + NULL, + NULL, + dwDIGCF); + } + + hdevinfo=gUmdm.hdevinfo; + + if (hdevinfo) + { + gUmdm.dwcRefHDevInfo++; + } + + ASSERT( ( hdevinfo && gUmdm.dwcRefHDevInfo) + ||(!hdevinfo && !gUmdm.dwcRefHDevInfo) ); + + LeaveCriticalSection(&gUmdm.crit); + + return hdevinfo; +} +#endif // DYNA_ADDREMOVE + + + +#ifdef DYNA_ADDREMOVE +void FreeHDevInfo(HDEVINFO hdevinfo) +{ + + EnterCriticalSection(&gUmdm.crit); + + ASSERT(hdevinfo==gUmdm.hdevinfo); + + if (!gUmdm.dwcRefHDevInfo) + { + ASSERT(FALSE); + goto end; + } + if (!--gUmdm.dwcRefHDevInfo) + { + SetupDiDestroyDeviceInfoList(gUmdm.hdevinfo); + gUmdm.hdevinfo=NULL; + } + +end: + + LeaveCriticalSection(&gUmdm.crit); + +} +#endif // DYNA_ADDREMOVE + + +#ifdef DYNA_ADDREMOVE +BOOL LoadModemUI(void) +{ + BOOL fRet=FALSE; + + EnterCriticalSection(&gUmdm.crit); + + if (!gUmdm.dwcRefModemUI) + { + HINSTANCE hlib = LoadLibrary(TEXT("modemui.dll")); + + ASSERT(!gUmdm.hModemUIDLL); + ASSERT(!gUmdm.pfnPrivateDefCommConfig); + + if (hlib) + { + + gUmdm.pfnPrivateDefCommConfig= + (PVOID)GetProcAddress(hlib,"UnimodemGetDefaultCommConfig"); + + if (!gUmdm.pfnPrivateDefCommConfig) + { + FreeLibrary(hlib); + hlib=NULL; + } + } + + gUmdm.hModemUIDLL = hlib; + } + + if (gUmdm.hModemUIDLL) + { + gUmdm.dwcRefModemUI++; + fRet=TRUE; + } + + ASSERT( ( gUmdm.hModemUIDLL && gUmdm.dwcRefModemUI) + ||(!gUmdm.hModemUIDLL && !gUmdm.dwcRefModemUI) ); + + LeaveCriticalSection(&gUmdm.crit); + + return fRet; +} +#endif // DYNA_ADDREMOVE + + +#ifdef DYNA_ADDREMOVE +void UnloadModemUI(void) +{ + + EnterCriticalSection(&gUmdm.crit); + + if (!gUmdm.dwcRefModemUI) + { + ASSERT(FALSE); + goto end; + } + + if (!--gUmdm.dwcRefModemUI) + { + ASSERT(gUmdm.hModemUIDLL && gUmdm.pfnPrivateDefCommConfig); + FreeLibrary(gUmdm.hModemUIDLL); + gUmdm.hModemUIDLL=NULL; + gUmdm.pfnPrivateDefCommConfig=NULL; + } + +end: + + LeaveCriticalSection(&gUmdm.crit); + +} +#endif // DYNA_ADDREMOVE + + +#ifdef DYNA_ADDREMOVE +void CplNotifComplete(BOOL fWait) +{ + HANDLE hthrd; + + EnterCriticalSection(&gUmdm.critCplNotif); + hthrd=gUmdm.hthrdCplNotif; + gUmdm.hthrdCplNotif=0; + LeaveCriticalSection(&gUmdm.critCplNotif); + + if (hthrd) + { + if (fWait) + { + DPRINTF("CplNotifComplete: WARNING -- waiting for re-enum thread to complete"); + WaitForSingleObject(hthrd, INFINITE); + } + CloseHandle(hthrd); + } +} +#endif // DYNA_ADDREMOVE + +// +// Reset the cached CommConfig structure by calling GetDefaultCommConfig. +// +void RefreshDefaultCommConfig(PLINEDEV pLineDev) +{ + + COMMCONFIG * pccCurrent = NULL, * pccNew = NULL; + LPCTSTR lpctszDeviceName = NULL; + + if (pLineDev && pLineDev->pDevCfg) + { + pccCurrent = (COMMCONFIG *)&(pLineDev->pDevCfg->commconfig); + lpctszDeviceName = pLineDev->szDeviceName; + } + + if (!pccCurrent || !lpctszDeviceName) goto end; + + + // Get default comm config. + { + DWORD dwSize = pccCurrent->dwSize; + + DPRINTF1("RefreshDefaultCommConfig: [%s]", lpctszDeviceName); + + pccNew = (COMMCONFIG *)LocalAlloc(LPTR, (UINT)dwSize); + if (pccNew) + { + pccNew->dwProviderSubType = PST_MODEM; + if (!GetDefaultCommConfig(lpctszDeviceName, pccNew, &dwSize)) + { + DPRINTF2 + ( + "RefreshCommComfig: GetDefaultCommConfig(\"%s\"): ERR %08lu", + lpctszDeviceName, + GetLastError() + ); + LocalFree(pccNew); pccNew = NULL; + } + } + } + + if (pccNew) + { + // Similar to what is done by TSPI_lineSetDevConfig. + + ASSERT(pccCurrent->dwSize == pccNew->dwSize); + ASSERT(pccCurrent->wVersion == pccNew->wVersion); + ASSERT(pccCurrent->dwProviderSubType == pccNew->dwProviderSubType); + ASSERT(pccCurrent->dwProviderSize == pccNew->dwProviderSize); + if + ( (pccCurrent->dwSize == pccNew->dwSize) + && (pccCurrent->wVersion == pccNew->wVersion) + && (pccCurrent->dwProviderSubType == pccNew->dwProviderSubType) + && (pccCurrent->dwProviderSize == pccNew->dwProviderSize) + ) + { + + pccCurrent->dcb = pccNew->dcb; + CopyMemory(((LPBYTE)pccCurrent)+pccCurrent->dwProviderOffset, + ((LPBYTE)pccNew)+pccNew->dwProviderOffset, + pccCurrent->dwProviderSize); + + pLineDev->InitStringsAreValid=FALSE; + } + else + { + DPRINTF("RefreshDefaultCommSettings:size/version/prov. mismatch"); + ASSERT(FALSE); + } + } + + +end: + + if (pccNew) {LocalFree(pccNew); pccNew = NULL;} + +} + +// Initialize the global parameters +// +void tspInitGlobals(void) +{ + // Determine if User is Admin + gUmdm.bAdminUser = IsAdminUser(); + + // Determine global registry state flags. + { + TCHAR rgtch[] = szUNIMODEM_REG_PATH TEXT("\\PortSpecific"); + HKEY hKey=NULL; + LONG l; + + gRegistryFlags = 0; + + l=RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // handle of open key + rgtch, // address of name of subkey to open + 0, // reserved + KEY_READ, // desired security access + &hKey // address of buffer for opened handle + ); + + if (l==ERROR_SUCCESS) + { + gRegistryFlags = fGRF_PORTLATENCY; + RegCloseKey(hKey); + } + } +} + +// DeInitialize the global parameters +// +void tspDeInitGlobals(void) +{ + gRegistryFlags = 0; + gUmdm.bAdminUser = FALSE; +} diff --git a/private/unimodem/tapisp/umdmspi.h b/private/unimodem/tapisp/umdmspi.h new file mode 100644 index 000000000..8014a1af8 --- /dev/null +++ b/private/unimodem/tapisp/umdmspi.h @@ -0,0 +1,425 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: umdmspi.h +// Content: This file contains the declaration for Unimodem TSP +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// History: +// Mon 27-Jun-1994 10:10:00 -by- Nick Manson [t-nickm] +// Wed 15-Jun-1994 10:41:00 -by- Nick Manson [t-nickm] +// Fri 30-Jul-1993 10:30:39 -by- Viroon Touranachun [viroont] +// +//**************************************************************************** + +#ifndef _MDMSPI_H_ +#define _MDMSPI_H_ + +//**************************************************************************** +// Constant Definitions +//**************************************************************************** + +#define MDMSPI_VERSION 0x00020000 + +#define MAX_CLASS_NAME_LEN 128 +#define UNIMODEM_WNDCLASS TEXT("MdmWndClass") + +#define MAXDEVICENAME 128 // BUGBUG: should match cpl\modem.h MAX_REG_KEY_LEN +#define MAXADDRESSLEN TAPIMAXDESTADDRESSSIZE + +#define MAX_CLASS_REGISTRY_PATH 100 // BUGBUG: sizeof(REGSTR_PATH_CLASS) + MAX_CLASS_NAME_LEN + 10 + breathing room + +#define INVALID_DEVICE ((HANDLE)0xFFFFFFFF) +#define INVALID_PENDINGID 0xFFFFFFFF + +// 7/12/96 JosephJ. This was 8 seconds in Win95, OSR1, OSR2 and NT4.0 beta 1&2 +// Changed to 12 seconds because problems in Denmark where inter-ring delay +// can be upto 9 seconds. NT bug +#define TO_MS_RING_SEPARATION 12000 // 12 seconds space in between rings indicates a different call + +//**************************************************************************** +// Macros +//**************************************************************************** + +// Check for an error code +// +#define IS_TAPI_ERROR(err) (BOOL)(HIWORD(err) & 0x8000) + +// Validate Modem Service Provider's version +// +#define VALIDATE_VERSION(version) {if (version != MDMSPI_VERSION) \ + return LINEERR_OPERATIONFAILED;} + +// Check the device type +#define IS_NULL_MODEM(pLineDev) (pLineDev->bDeviceType == DT_NULL_MODEM) + +// Notify new call state, pass in pLineDev, dwCallState, and dwCallStateMode +// Can only do when an htCall is valid!!! +#define NEW_CALLSTATE(pLineDev,S,M) {pLineDev->dwCallState = S; \ + pLineDev->dwCallStateMode = M; \ + (*pLineDev->lpfnEvent)(pLineDev->htLine, \ + pLineDev->htCall, \ + LINE_CALLSTATE, \ + S, M, \ + pLineDev->dwCurMediaModes);} + +#define INITCRITICALSECTION(x) InitializeCriticalSection(&x) +#define ENTERCRITICALSECTION(x) EnterCriticalSection(&x) +#define LEAVECRITICALSECTION(x) LeaveCriticalSection(&x) +#define DELETECRITICALSECTION(x) DeleteCriticalSection(&x) + +//**************************************************************************** +// Private type definitions +//**************************************************************************** + +// Enumerated States of the line device +// +typedef enum DevStates { + DEVST_DISCONNECTED = 0, + + DEVST_PORTLISTENINIT, + DEVST_PORTLISTENING, + DEVST_PORTLISTENOFFER, + DEVST_PORTLISTENANSWER, + + DEVST_PORTSTARTPRETERMINAL, + DEVST_PORTPRETERMINAL, + DEVST_PORTCONNECTINIT, + DEVST_PORTCONNECTWAITFORLINEDIAL, // this is a resting state. ie. we sit here waiting for a lineDial. + DEVST_PORTCONNECTDIALTONEDETECT, + DEVST_PORTCONNECTDIAL, + DEVST_PORTCONNECTING, + DEVST_PORTPOSTTERMINAL, + + DEVST_TALKDROPDIALING, + DEVST_MANUALDIALING, + + DEVST_CONNECTED, + DEVST_DISCONNECTING +} DEVSTATES; + +// Flags for the call attributes +// +#define CALL_ALLOCATED 0x00000001 +#define CALL_ACTIVE 0x00000002 +#define CALL_INBOUND 0x00000004 + +// Unimodem Service provider settings +// +#define TERMINAL_NONE 0x00000000 +#define TERMINAL_PRE 0x00000001 +#define TERMINAL_POST 0x00000002 +#define MANUAL_DIAL 0x00000004 +#define LAUNCH_LIGHTS 0x00000008 + +#define MIN_WAIT_BONG 0 +#define MAX_WAIT_BONG 60 +#define DEF_WAIT_BONG 8 +#define INC_WAIT_BONG 2 + +// Device Setting Information +// +typedef struct tagDEVCFGHDR { + DWORD dwSize; + DWORD dwVersion; + DWORD fdwSettings; +} DEVCFGHDR; + +#define GETOPTIONS(pDevCfg) (pDevCfg->dfgHdr.fdwSettings & 0x0000FFFF) +#define GETWAITBONG(pDevCfg) ((pDevCfg->dfgHdr.fdwSettings >> 16) & 0x0000FFFF) +#define SETOPTIONS(pDevCfg, options) {pDevCfg->dfgHdr.fdwSettings = \ + (pDevCfg->dfgHdr.fdwSettings&0xFFFF0000) | \ + (options & 0x0000FFFF);} +#define SETWAITBONG(pDevCfg, wait) {pDevCfg->dfgHdr.fdwSettings = \ + (pDevCfg->dfgHdr.fdwSettings&0x0000FFFF) | \ + ((wait << 16) & 0xFFFF0000);} + +#define MDMCFG_VERSION 0x00010003 + +typedef struct tagDEVCFG { + DEVCFGHDR dfgHdr; + COMMCONFIG commconfig; +} DEVCFG, *PDEVCFG, FAR* LPDEVCFG; + +// Device Class and Information +// +#define TAPILINE 0 +#define COMM 1 +#define COMMMODEM 2 +#define COMMMODEMPORTNAME 3 +#define NDIS 4 +#define MAX_SUPPORT_CLASS 5 + +typedef struct tagGETIDINFO { + LPTSTR szClassName; + DWORD dwFormat; +} GETIDINFO; + +extern GETIDINFO aGetID[MAX_SUPPORT_CLASS]; + +// Pending operation type +// +typedef enum PendingOp { + INVALID_PENDINGOP = 0, + + PENDING_LINEMAKECALL, + PENDING_LINEANSWER, + PENDING_LINEDROP, + PENDING_LINEDIAL +} PENDINGOP; + +// Flags for resources +// +#define LINEDEVFLAGS_OUTOFSERVICE 0x00000001 +#define LINEDEVFLAGS_REMOVING 0x00000002 +#define LINEDEVFLAGS_REINIT 0x00000004 + +// Line device data structure +// +typedef struct tagLineDev { + DWORD dwVersion; // Version stamp + struct tagLineDev *pNext; // pointer to next CB + CRITICAL_SECTION hSem; // critical section for this line + + DWORD dwID; // Local device ID + DWORD dwPermanentLineID; // Permanent ID for this device + TCHAR szDeviceName[MAXDEVICENAME+1]; // device name + BYTE bDeviceType; // the modem type + HICON hIcon; // Device icon + + PDEVCFG pDevCfg; // Device configuration + DWORD fdwResources; // Flags for various resources + DWORD dwDevCapFlags; // LINEDEVCAPSFLAGS (ie. DIALBILLING, DIALQUIET, DIALDIALTONE) + DWORD dwMaxDCERate; // Max DCE as stored in the Properties line of the registry + DWORD dwModemOptions; // dwModemOptions as stored in the Properties line of the registry + BOOL fPartialDialing; // TRUE if partial dialing using ";" is supported + + BOOL InitStringsAreValid; // if LineSetDevConfig called, need to build new init string + + + + DWORD dwBearerModes; // supported bearer modes + DWORD dwCurBearerModes; // The current media bearer modes. Plural because + // we keep track of PASSTHROUGH _and_ the real b-mode + // at the same time. + + DWORD dwDefaultMediaModes; // Default supported media modes + DWORD dwMediaModes; // Current supported media modes + DWORD dwCurMediaModes; // The current media modes + DWORD dwDetMediaModes; // The current detection media modes + + HANDLE hDevice; // Device handle + HTAPILINE htLine; // Tapi line handle + LINEEVENT lpfnEvent; // Line event callback function + DEVSTATES DevState; // intermediate TAPI device state + DWORD dwPendingID; // async pending ID + PENDINGOP dwPendingType; // pending operation + CHAR szAddress[MAXADDRESSLEN+1]; + BOOL fTakeoverMode; // True if unimodem is in takover mode + DWORD dwDialOptions; // Options set in a lineMakeCall + + DWORD dwCall; // Call attributes + HTAPICALL htCall; // TAPI call handle + DWORD dwCallState; // Current call state + DWORD dwCallStateMode; // Current call state mode + DWORD dwRingCount; // Count of the number of rings for an incoming call + DWORD dwRingTick; // TickCount for when the last ring occured on an incoming call + + DWORD dwNegotiatedRate; // Negotiated BPS speed returned from VxD + DWORD dwAppSpecific; // Application specific + + HANDLE hLights; // Lights thread handle + + HTAPIDIALOGINSTANCE hDlgInst; // Dialog thread instance + DWORD fUIDlg; // current dialogs + + TCHAR szDriverKey[MAX_CLASS_NAME_LEN+10]; // ex. "Modem\0000" + + DWORD dwVxdPendingID; // async pending ID for VxD operations + + // + // Mcx operations + // + HANDLE hModem; // Mcx modem handle + MCX_OUT McxOut; // Mcx operation request output info + + HANDLE hSynchronizeEvent; // Event for synchronization between + // MdmAsyncThread and something else. + HANDLE DroppingEvent; + + BOOL fUpdateDefaultCommConfig; // If set, update the default comm + // config the next time + // this line is opened, and + // clear this flag. + + BOOL LineClosed; + +} LINEDEV, *PLINEDEV, FAR* LPLINEDEV; + +#define UMDM_VERSION 0x4D444D55 +#define ISLINEDEV(pLineDev) (pLineDev->dwVersion == UMDM_VERSION) + +#define UI_DLG_TALKDROP 0x00000001 +#define UI_DLG_MANUAL 0x00000002 +#define UI_DLG_TERMINAL 0x00000004 +#define START_UI_DLG(pLineDev, type) (pLineDev->fUIDlg |= type) +#define STOP_UI_DLG(pLineDev, type) (pLineDev->fUIDlg &= (~type)) +#define IS_UI_DLG_UP(pLineDev, type) (pLineDev->fUIDlg & type) + +// Line device list +// +typedef struct tagMdmList { + PLINEDEV pList; + DWORD cModems; + CRITICAL_SECTION hSem; +} MDMLIST, *PMDMLIST; + +// Default mask to MDM_ options +// +#define MDM_MASK (MDM_TONE_DIAL | MDM_BLIND_DIAL) + +typedef struct tagDevCfgDlgInfo { + DWORD dwType; + DWORD dwDevCaps; + DWORD dwOptions; + LPDEVCFG lpDevCfg; +} DCDI, *PDCDI, FAR* LPDCDI; + +//**************************************************************************** +// General Utilities +//**************************************************************************** + +BOOL InitCBList (HINSTANCE hInstance); +void DeinitCBList (HINSTANCE hInstance); +PLINEDEV AllocateCB (UINT cbSize); +DWORD AddCBToList (PLINEDEV pLineDev); +DWORD DeleteCB (PLINEDEV pLineDev); +PLINEDEV GetFirstCB (); +PLINEDEV GetCBfromHandle (DWORD handle); +PLINEDEV GetCBfromID (DWORD dwDeviceID); +PLINEDEV GetCBfromDeviceHandle(DWORD hDevice); +PLINEDEV GetCBfromName (LPTSTR pszName); +void MdmInitTracing (void); +void MdmDeinitTracing (void); +void DisableStaleModems (void); + +#define CLAIM_LINEDEV(p) (ENTERCRITICALSECTION(p->hSem)) +#define RELEASE_LINEDEV(p) (LEAVECRITICALSECTION(p->hSem)) + +DWORD NullifyLineDevice (PLINEDEV pLineDev); +BOOL ValidateDevCfgClass (LPCTSTR lpszDeviceClass); +LONG ValidateAddress (PLINEDEV pLineDev, + LPCTSTR lpszInAddress, + LPSTR lpszOutAddress); + +BOOL IsOriginateAddress (LPCSTR lpszAddress); + +DWORD APIENTRY MdmAsyncThread (HANDLE hStopEvent); +DWORD MdmAsyncContinue(PLINEDEV pLineDev, DWORD dwStatus); + +DWORD InitializeMdmThreads(); +DWORD DeinitializeMdmThreads(); + +DWORD InitializeMdmTimer(); +DWORD DeinitializeMdmTimer(); +DWORD APIENTRY MdmTimerThread(DWORD dwParam); + +DWORD LaunchModemLight (LPTSTR szModemName, HANDLE hModem, + LPHANDLE lphLight); +DWORD TerminateModemLight (HANDLE hLight); +void RefreshDefaultCommConfig (PLINEDEV pLineDev); + +//**************************************************************************** +// Modem SPI prototypes +//**************************************************************************** + +DWORD OpenModem(PLINEDEV pLineDev, LPBYTE lpComConfig, DWORD dwSize); +DWORD CloseModem (PLINEDEV pLineDev); + + +LONG DevlineOpen (PLINEDEV pLineDev); + +LONG DevlineDetectCall(PLINEDEV pLineDev); +LONG DevlineMakeCall (PLINEDEV pLineDev); +LONG DevlineDial (PLINEDEV pLineDev); +LONG DevlineAnswer (PLINEDEV pLineDev); +LONG DevlineDrop (PLINEDEV pLineDev, BOOL fWait); + +LONG DevlineClose (PLINEDEV pLineDev); + + + + +#ifdef UNDER_CONSTRUCTION + +LONG NEAR PASCAL DevlineDisabled (PLINEDEV pLineDev); + +DWORD NEAR PASCAL MdmDeviceServiceChanged (UINT uEvent, LPARAM lParam); +DWORD NEAR PASCAL MdmDeviceChangeNotify (UINT uEvent, LPSTR szDevice); +DWORD NEAR PASCAL MdmDeviceChanged (UINT uEvent, LPARAM lParam); + +#endif // UNDER_CONSTRUCTION + +//**************************************************************************** +// User Interface thread +//**************************************************************************** + +DWORD CreateMdmDlgInstance (PLINEDEV pLineDev); +DWORD DestroyMdmDlgInstance (PLINEDEV pLineDev); + +DWORD TalkDropDialog(PLINEDEV pLineDev); +DWORD DestroyTalkDropDialog(PLINEDEV pLineDev); +DWORD ManualDialog(PLINEDEV pLineDev); +DWORD DestroyManualDialog(PLINEDEV pLineDev); +DWORD TerminalDialog(PLINEDEV pLineDev); +DWORD DestroyTerminalDialog(PLINEDEV pLineDev); + +//**************************************************************************** +// Interface to Unimodem VxD +//**************************************************************************** + +DWORD UnimodemInit(PLINEDEV); +DWORD UnimodemMonitor(PLINEDEV, DWORD); +DWORD UnimodemCancelMonitor (PLINEDEV, BOOL); +DWORD UnimodemAnswer(PLINEDEV); +DWORD UnimodemMonitorDisconnect (PLINEDEV); +DWORD UnimodemCancelMonitorDisconnect (PLINEDEV); +DWORD UnimodemHangup(PLINEDEV, BOOL); +DWORD UnimodemGetCommConfig (PLINEDEV, LPCOMMCONFIG, LPDWORD); +DWORD UnimodemSetCommConfig (PLINEDEV, LPCOMMCONFIG, DWORD); +DWORD UnimodemSetPassthrough(PLINEDEV, DWORD); +DWORD UnimodemGetNegotiatedRate(PLINEDEV, LPDWORD); + +DWORD +UnimodemDial( + PLINEDEV pLineDev, + LPSTR szAddress, + DWORD DialOptions + ); + + +DWORD WINAPI +UnimodemSetModemSettings( + PLINEDEV pLineDev, + LPMODEMSETTINGS lpModemSettings + ); + + + +//**************************************************************************** +// Global Parameters +//**************************************************************************** + +extern DWORD gdwProviderID; +extern HPROVIDER ghProvider; + +extern ASYNC_COMPLETION gfnCompletionCallback; +extern LINEEVENT gfnLineCreateProc; + +extern TCHAR szNull[]; +extern CHAR szSemicolon[]; +extern TCHAR gszTSPFilename[]; +extern TCHAR cszDevicePrefix[]; + +#endif //_MDMSPI_H_ diff --git a/private/unimodem/tapisp/unimdm.c b/private/unimodem/tapisp/unimdm.c new file mode 100644 index 000000000..64a22fa08 --- /dev/null +++ b/private/unimodem/tapisp/unimdm.c @@ -0,0 +1,3399 @@ +//**************************************************************************** +// +// 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; +} diff --git a/private/unimodem/tapisp/unimdm.def b/private/unimodem/tapisp/unimdm.def new file mode 100644 index 000000000..90893cdce --- /dev/null +++ b/private/unimodem/tapisp/unimdm.def @@ -0,0 +1,147 @@ +;****************************************************************************** +; module-definition file for generic -- used by LINK.EXE +;****************************************************************************** + +LIBRARY UNIMDM ; application's module name +PROTMODE + +;****************************************************************************** +;CODE can be moved in memory and discarded/reloaded +;****************************************************************************** + +CODE PRELOAD FIXED + +;****************************************************************************** +;DATA must be MULTIPLE if program can be invoked more than once +;****************************************************************************** + +DATA PRELOAD FIXED + +;****************************************************************************** +; All functions that will be called by any Windows routine +; MUST be exported. +;****************************************************************************** + +EXPORTS + TSPI_lineAccept @500 +; TSPI_lineAddToConference @501 + TSPI_lineAnswer @502 +; TSPI_lineBlindTransfer @503 + TSPI_lineClose @504 + TSPI_lineCloseCall @505 +; TSPI_lineCompleteCall @506 +; TSPI_lineCompleteTransfer @507 + TSPI_lineConditionalMediaDetection @508 +; TSPI_lineConfigDialog @509 +; TSPI_lineDevSpecific @510 +; TSPI_lineDevSpecificFeature @511 + TSPI_lineDial @512 + TSPI_lineDrop @513 +; TSPI_lineForward @514 +; TSPI_lineGatherDigits @515 +; TSPI_lineGenerateDigits @516 +; TSPI_lineGenerateTone @517 + TSPI_lineGetAddressCaps @518 +; TSPI_lineGetAddressID @519 + TSPI_lineGetAddressStatus @520 + TSPI_lineGetCallAddressID @521 + TSPI_lineGetCallInfo @522 + TSPI_lineGetCallStatus @523 + TSPI_lineGetDevCaps @524 + TSPI_lineGetDevConfig @525 +; TSPI_lineGetExtensionID @526 + TSPI_lineGetIcon @527 + TSPI_lineGetID @528 + TSPI_lineGetLineDevStatus @529 + TSPI_lineGetNumAddressIDs @530 +; TSPI_lineHold @531 + TSPI_lineMakeCall @532 +; TSPI_lineMonitorDigits @533 +; TSPI_lineMonitorMedia @534 +; TSPI_lineMonitorTones @535 +; TSPI_lineNegotiateExtVersion @536 + TSPI_lineNegotiateTSPIVersion @537 + TSPI_lineOpen @538 +; TSPI_linePark @539 +; TSPI_linePickup @540 +; TSPI_linePrepareAddToConference @541 +; TSPI_lineRedirect @542 +; TSPI_lineRemoveFromConference @543 +; TSPI_lineSecureCall @544 +; TSPI_lineSelectExtVersion @545 +; TSPI_lineSendUserUserInfo @546 + TSPI_lineSetAppSpecific @547 + TSPI_lineSetCallParams @548 + TSPI_lineSetDefaultMediaDetection @549 + TSPI_lineSetDevConfig @550 +; TSPI_lineSetMediaControl @551 + TSPI_lineSetMediaMode @552 + TSPI_lineSetStatusMessages @553 +; TSPI_lineSetTerminal @554 +; TSPI_lineSetupConference @555 +; TSPI_lineSetupTransfer @556 +; TSPI_lineSwapHold @557 +; TSPI_lineUncompleteCall @558 +; TSPI_lineUnhold @559 +; TSPI_lineUnpark @560 + +; TSPI_phoneClose @561 +; TSPI_phoneConfigDialog @562 +; TSPI_phoneDevSpecific @563 +; TSPI_phoneGetButtonInfo @564 +; TSPI_phoneGetData @565 +; TSPI_phoneGetDevCaps @566 +; TSPI_phoneGetDisplay @567 +; TSPI_phoneGetExtensionID @568 +; TSPI_phoneGetGain @569 +; TSPI_phoneGetHookSwitch @570 +; TSPI_phoneGetIcon @571 +; TSPI_phoneGetID @572 +; TSPI_phoneGetLamp @573 +; TSPI_phoneGetRing @574 +; TSPI_phoneGetStatus @575 +; TSPI_phoneGetVolume @576 +; TSPI_phoneNegotiateExtVersion @577 +; TSPI_phoneNegotiateTSPIVersion @578 +; TSPI_phoneOpen @579 +; TSPI_phoneSelectExtVersion @580 +; TSPI_phoneSetButtonInfo @581 +; TSPI_phoneSetData @582 +; TSPI_phoneSetDisplay @583 +; TSPI_phoneSetGain @584 +; TSPI_phoneSetHookSwitch @585 +; TSPI_phoneSetLamp @586 +; TSPI_phoneSetRing @587 +; TSPI_phoneSetStatusMessages @588 +; TSPI_phoneSetVolume @589 + + TSPI_providerConfig @590 + TSPI_providerInit @591 + TSPI_providerInstall @592 + TSPI_providerRemove @593 + TSPI_providerShutdown @594 + TSPI_providerEnumDevices @595 +; TSPI_lineDropOnClose @596 +; TSPI_lineDropNoOwner @597 + TSPI_providerCreateLineDevice @598 +; TSPI_providerCreatePhoneDevice @599 +; TSPI_lineSetCurrentLocation @600 +; TSPI_lineConfigDialogEdit @601 +; TSPI_lineReleaseUserUserInfo @602 + +; TSPI_lineSetCallData @603 +; TSPI_lineSetCallQualityOfService @604 +; TSPI_lineSetCallTreatment @605 +; TSPI_lineSetLineDevStatus @606 + TSPI_providerFreeDialogInstance @607 + TSPI_providerGenericDialogData @608 + TSPI_providerUIIdentify @609 + + TUISPI_lineConfigDialog @610 + TUISPI_lineConfigDialogEdit @611 +; TUISPI_phoneConfigDialog @612 + TUISPI_providerConfig @613 + TUISPI_providerGenericDialog @614 + TUISPI_providerGenericDialogData @615 + TUISPI_providerInstall @616 + TUISPI_providerRemove @617 diff --git a/private/unimodem/tapisp/unimdm.h b/private/unimodem/tapisp/unimdm.h new file mode 100644 index 000000000..8255dd56e --- /dev/null +++ b/private/unimodem/tapisp/unimdm.h @@ -0,0 +1,182 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: unimdm.h +// Content: This file contains the declaration for RnaDLL +// +// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +// +// History: +// Mon 27-Jun-1994 10:10:00 -by- Nick Manson [t-nickm] +// Wed 15-Jun-1994 10:41:00 -by- Nick Manson [t-nickm] +// Fri 30-Jul-1993 10:30:39 -by- Viroon Touranachun [viroont] +// +//**************************************************************************** + +#ifndef _UNIMDM_H_ +#define _UNIMDM_H_ + +#if DBG > 0 +#define DEBUG +#endif // DBG + +#define UNICODE + +//**************************************************************************** +// Global Include File +//**************************************************************************** + +// #define USE_SERVICECONTROLLER + +#ifndef USE_SERVICECONTROLLER +# include +# include +# include +# ifdef ASSERT +# undef ASSERT +# endif // ASSERT +#endif // USE_SERVICECONTROLLER + +#include // also includes windowsx.h +#include +#ifndef MAXDWORD +#define MAXDWORD MAXULONG +#if (MAXDWORD!=0xffffffff) +# error "MAXDWORD!=0xffffffff" +#endif +#endif // MAXDWORD + +// Public registry defines, in particular REGSTR_PATH_SETUP +#include + +// Dynamic add/remove of devices. +// BUG BUG -- this needs to be consolodated with the code currently +// #ifdef UNDER_CONSTRUCTION +#define DYNA_ADDREMOVE + +#include +#include + +//**************************************************************************** +// NT Build patched +//**************************************************************************** + +#include +#include +#include "mcxioctl.h" + +#include "debug.h" +#include "tracing.h" + +/* Utility Macros */ + +// GTC_* macros -- these handle GetTickCount rollover +// AleB(A,B) == "A<=B" +// DELTA(Start, End) == "End-Start" +// AequalsBplusC(A,B,C) == "A=B+C" +// MAX_DELTA -- all real time differences are expected to be smaller than +// this. + +#define GTC_MASK 0xFFFFFFFFL // Make it smaller to simulate faster rollover +#define GTC_MAXDELTA (GTC_MASK>>1) + +#ifndef TEST_GTC + +// The real stuff... + +# if (GTC_MASK!=0xFFFFFFFF) +# error "GTC_MASK must be 0xFFFFFFFF in the real GTC_MACROS!" +# endif +# define GETTICKCOUNT() GetTickCount() + +# define GTC_AleB(_A,_B) \ + ((DWORD)(((_A)<=(_B)) \ + ? (((_B)-(_A))<=GTC_MAXDELTA) \ + : (((_A)-(_B))>GTC_MAXDELTA))) +# define GTC_DELTA(_Start, _End) \ + ((DWORD) (((_End)>=(_Start)) \ + ? ((_End)-(_Start)) \ + : (1L+(_End)+(GTC_MASK-(_Start))))) +# define GTC_AequalsBplusC(_A,_B,_C) \ + (((_A)=((_B)+(_C))),(_A)?(_A):((_A)=1)) + +#else // TEST_GTC + +// This version calls functions in debug.c which spew debug on rollover + +# define GETTICKCOUNT() (GetTickCount()>C_MASK) +BOOL GTC_AleB(DWORD dwA, DWORD dwB); +DWORD GTC_DELTA(DWORD dwStart, DWORD dwEnd); +# define GTC_AequalsBplusC(_A,_B,_C) \ + fnGTC_AequalsBplusC(&(_A),_B,_C) +void fnGTC_AequalsBplusC(LPDWORD lpdwA, DWORD dwB, DWORD dwC); + +#endif // TEST_GTC + +#define szUNIMODEM_REG_PATH REGSTR_PATH_SETUP TEXT("\\Unimodem") + +/* Timer Functions */ +DWORD SetMdmTimer (DWORD dwCompletionKey, + LPOVERLAPPED lpOverlapped, + DWORD dwTime); +BOOL KillMdmTimer (DWORD dwCompletionKey, + LPOVERLAPPED lpOverlapped); + +/* Overlapped Pool Structure and Functions */ + +typedef struct tagOverNode { + OVERLAPPED overlapped; + DWORD Type; + DWORD dwToken; + DWORD dwRefCount; + DWORD CommEvent; + TRACEINSTDATA Tracedata; + struct tagOverNode *lpNext; +} OVERNODE, *LPOVERNODE; + +#define OVERNODE_TYPE_READWRITE 1 +#define OVERNODE_TYPE_COMMEVENT 2 +#define OVERNODE_TYPE_TIMEOUT 3 +#define OVERNODE_TYPE_WORKITEM 4 + +#define SET_OVERNODE_TYPE(_x, _type) { ((LPOVERNODE)(_x))->Type=(_type); } + +// When Calling PostQueuedCompletionStatus with a NULL lpOverlapped structure, +// we use the dwBytesWritten field to encode the notification type, and, +// if tracing is enabled, to encode the GetTickCount() at the time of calling +// the function. Since both values have to share a DWORD, we right-shift +// GetTickCount and or-in the type. +// +#define CP_BYTES_WRITTEN(_type) \ + (TRACINGENABLED()?((GetTickCount()<<4)|(_type)):(_type)) + +#define CP_TYPE(_cbTransferred) \ + ((_cbTransferred)&0xf) + +#define CP_TICKCOUNT(_cbTransferred) \ + ((_cbTransferred)>>4) + +// Type CP_TYPE_* must be < 16, because of the 4-bit mask above. +// +#define CP_TYPE_TIMEOUT 1 // Timeout notification +#define CP_TYPE_RING 2 // Ring notification + + +BOOL OverPoolInit(); +void OverPoolDeinit(); +LPOVERLAPPED OverPoolAlloc(DWORD dwToken, DWORD dwRefCount); +void OverPoolFree(LPOVERLAPPED lpOverlapped); +void OverPoolInitTracing(void); +void OverPoolDeinitTracing(void); +//**************************************************************************** +// Global Parameters +//**************************************************************************** + +extern HINSTANCE ghInstance; + +extern HANDLE ghCompletionPort; + +extern DWORD gRegistryFlags; // one of the FGRF_* flags below: +#define fGRF_PORTLATENCY 0x1 + +#endif //_UNIMDM_H_ diff --git a/private/unimodem/tapisp/unimdm.rc b/private/unimodem/tapisp/unimdm.rc new file mode 100644 index 000000000..dfc7985b5 --- /dev/null +++ b/private/unimodem/tapisp/unimdm.rc @@ -0,0 +1,18 @@ +//**************************************************************************** +// +// Module: UNIMDM +// File: unimdm.rc +// Content: This file contains all the resources for Modem SPI +// History: +// Wed 15-Jun-1994 10:46:00 -by- Nick Manson [t-nickm] +// Fri 30-Jul-1993 11:40:12 -by- Viroon Touranachun [viroont] +// +//**************************************************************************** + +#include +#include +#include "unimdm.rcv" + +#include "rcids.h" + +#include "resource.rc" diff --git a/private/unimodem/tapisp/unimdm.rcv b/private/unimodem/tapisp/unimdm.rcv new file mode 100644 index 000000000..1f53637c9 --- /dev/null +++ b/private/unimodem/tapisp/unimdm.rcv @@ -0,0 +1,31 @@ +/****************************************************************************** +** +** Module: unimdm +** File: unimdm.rcv +** Descriptions: Modem Service Provider Interface +** Contains: Definitions of version control data +** +** Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved +** +** History: Fri 30-Jul-1993 -by- Viroon Touranachun [viroont] +** +******************************************************************************/ + +#ifdef WINNT +#include +#include +#else +#include +#endif + + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Unimodem Service Provider" +#define VER_INTERNALNAME_STR "UNIMDM" +#define VER_LEGALCOPYRIGHT_YEARS "1992-1995" +#define VER_ORIGINALFILENAME_STR "UNIMDM.TSP" + + + +#include diff --git a/private/unimodem/tapisp/wndthrd.c b/private/unimodem/tapisp/wndthrd.c new file mode 100644 index 000000000..db1d06c82 --- /dev/null +++ b/private/unimodem/tapisp/wndthrd.c @@ -0,0 +1,1538 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: wndthrd.c +// +// Copyright (c) 1992-1995, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// 5/4/95 Viroon Touranachun Moved from modem.c +// +// +// Description: Asynchronous thread to handle the UI window +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" +#include "wndthrd.h" +#include "rcids.h" + + +#define DLG_CMD_FREE_INSTANCE 0 +#define DLG_CMD_CREATE 1 +#define DLG_CMD_DESTROY 2 + +// Dialog Information +// +typedef struct tagDlgInfo { + DWORD dwCmd; + DWORD idLine; + DWORD dwType; +} DLGINFO, *PDLGINFO; + + +// Remote handle +// +typedef struct tagRemHandle { + HANDLE handle; + DWORD pid; +} REMHANDLE, *PREMHANDLE; + + + +typedef struct _UI_THREAD_NODE { + + struct _UI_THREAD_NODE *Next; + + CRITICAL_SECTION CriticalSection; + + HWND hWnd; + HTAPIDIALOGINSTANCE htDlgInst; + TUISPIDLLCALLBACK pfnUIDLLCallback; + + PDLGNODE DlgList; + + UINT RefCount; + +} UI_THREAD_NODE, *PUI_THREAD_NODE; + + +typedef struct UI_THREAD_LIST { + + CRITICAL_SECTION CriticalSection; + + PUI_THREAD_NODE ListHead; + +} UI_THREAD_LIST, *PUI_THREAD_LIST; + + +#define WM_MDM_TERMINATE WM_USER+0x0100 +#define WM_MDM_TERMINATE_WND WM_USER+0x0101 +#define WM_MDM_TERMINATE_WND_NOTIFY WM_USER+0x0102 +#define WM_MDM_DLG WM_USER+0x0113 + +//**************************************************************************** +// Function Prototypes +//**************************************************************************** + +PDLGNODE NewDlgNode (HWND Parent,DWORD idLine, DWORD dwType); +BOOL DeleteDlgNode (HWND Parent,PDLGNODE pDlgNode); +PDLGNODE FindDlgNode (HWND Parent, DWORD idLine, DWORD dwType); +BOOL IsDlgListMessage(HWND Parent,MSG* pmsg); +void CleanupDlgList (HWND Parent); +DWORD StartMdmDialog(HWND hwnd, DWORD idLine, DWORD dwType); +DWORD DestroyMdmDialog(HWND hwnd,DWORD idLine, DWORD dwType); +LRESULT MdmWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +HWND CreateTalkDropDlg(HWND hwndOwner, DWORD idLine); +HWND CreateManualDlg(HWND hwndOwner, DWORD idLine); +HWND CreateTerminalDlg(HWND hwndOwner, DWORD idLine); + +TCHAR gszMdmWndClass[] = UNIMODEM_WNDCLASS; + +UI_THREAD_LIST UI_ThreadList; + + +VOID WINAPI +UI_ProcessAttach( + VOID + ) + +{ + + UI_ThreadList.ListHead=NULL; + + InitializeCriticalSection(&UI_ThreadList.CriticalSection); + + + return; + +} + +VOID WINAPI +UI_ProcessDetach( + VOID + ) + +{ + + UI_ThreadList.ListHead=NULL; + + DeleteCriticalSection(&UI_ThreadList.CriticalSection); + + return; + +} + + + +VOID WINAPI +AddThreadNode( + PUI_THREAD_LIST List, + PUI_THREAD_NODE Node + ) + +{ + EnterCriticalSection(&List->CriticalSection); + + Node->Next=List->ListHead; + + List->ListHead=Node; + + LeaveCriticalSection(&List->CriticalSection); + + return; + +} + +VOID WINAPI +RemoveNode( + PUI_THREAD_LIST List, + PUI_THREAD_NODE Node + ) + +{ + PUI_THREAD_NODE Current; + PUI_THREAD_NODE Prev; + + EnterCriticalSection(&List->CriticalSection); + + Prev=NULL; + Current=List->ListHead; + + while (Current != NULL) { + + if (Current == Node) { + + if (Current == List->ListHead) { + + List->ListHead=Current->Next; + + } else { + + Prev->Next=Current->Next; + } + + break; + } + Prev=Current; + Current=Current->Next; + } + + EnterCriticalSection(&Node->CriticalSection); + + Node->RefCount--; + + LeaveCriticalSection(&Node->CriticalSection); + + LeaveCriticalSection(&List->CriticalSection); + + return; + +} + + +UINT WINAPI +RemoveReference( + PUI_THREAD_NODE Node + ) + +{ + UINT TempCount; + + EnterCriticalSection(&Node->CriticalSection); + + TempCount=--Node->RefCount; + + LeaveCriticalSection(&Node->CriticalSection); + + return TempCount; + +} + + + +HWND WINAPI +FindThreadWindow( + PUI_THREAD_LIST List, + HTAPIDIALOGINSTANCE htDlgInst + ) + +{ + + PUI_THREAD_NODE Node; + HWND Window=NULL; + + EnterCriticalSection(&List->CriticalSection); + + Node=List->ListHead; + + while (Node != NULL && Window == NULL) { + + EnterCriticalSection(&Node->CriticalSection); + + if (Node->htDlgInst == htDlgInst) { + // + // found it + // + Window=Node->hWnd; + + Node->RefCount++; + } + + LeaveCriticalSection(&Node->CriticalSection); + + + Node=Node->Next; + } + + + LeaveCriticalSection(&List->CriticalSection); + + return Window; + +} + + +TUISPIDLLCALLBACK WINAPI +GetCallbackProc( + HWND hdlg + ) + +{ + + PUI_THREAD_NODE Node; + + Node=(PUI_THREAD_NODE)GetWindowLong(hdlg,GWL_USERDATA); + + return Node->pfnUIDLLCallback; + +} + + + +//**************************************************************************** +// LONG TSPIAPI TUISPI_providerGenericDialog( +// TUISPIDLLCALLBACK pfnUIDLLCallback, +// HTAPIDIALOGINSTANCE htDlgInst, +// LPVOID lpParams, +// DWORD dwSize) +// +// Functions: Create modem instance +// +// Return: ERROR_SUCCESS if successful +//**************************************************************************** + +LONG TSPIAPI TUISPI_providerGenericDialog( + TUISPIDLLCALLBACK pfnUIDLLCallback, + HTAPIDIALOGINSTANCE htDlgInst, + LPVOID lpParams, + DWORD dwSize, + HANDLE hEvent) +{ + MSG msg; + WNDCLASS wc; + DWORD dwRet; + + PUI_THREAD_NODE Node; + + DBG_ENTER_UL("TUISPI_providerGenericDialog", htDlgInst); + + Node=LocalAlloc(LPTR, sizeof(UI_THREAD_NODE)); + + if (Node == NULL) { + + return ERROR_NOT_ENOUGH_MEMORY; + } + + InitializeCriticalSection(&Node->CriticalSection); + + Node->pfnUIDLLCallback=pfnUIDLLCallback; + Node->htDlgInst=htDlgInst; + Node->RefCount=1; + + + Node->DlgList=NULL; + + wc.style = CS_NOCLOSE; // Do not allow end-user to close + wc.cbClsExtra = 0; // No per-class extra data. + wc.cbWndExtra = 0; // No per-window extra data. + wc.hInstance = ghInstance; // Application that owns the class. + wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpfnWndProc = MdmWndProc; // Function to retrieve messages. + wc.lpszClassName = gszMdmWndClass; // Name used in call to CreateWindow. + + + + RegisterClass(&wc); + + + // Create the main invisible window + // + Node->hWnd = CreateWindow( + gszMdmWndClass, // The window class + szNull, // Text for window title bar. + WS_OVERLAPPEDWINDOW, // Window style. + CW_USEDEFAULT, // Default horizontal position. + CW_USEDEFAULT, // Default vertical position. + CW_USEDEFAULT, // Default width. + CW_USEDEFAULT, // Default height. + NULL, // Overlapped windows have no parent. + NULL, // Use the window class menu. + ghInstance, // This instance owns this window. + Node // Pointer not needed. + ); + + SetEvent(hEvent); + + // Cannot create a window, bail out + // + if (Node->hWnd == NULL) + { + dwRet = LINEERR_OPERATIONFAILED; + goto Cleanup_Exit; + }; + + + AddThreadNode( + &UI_ThreadList, + Node + ); + + // Get message loop + // + while (GetMessage(&msg, NULL, 0, 0)) + { + if (msg.hwnd != NULL) + { + // The message is for a specific UI window, dispatch the message + // + if (!IsDlgListMessage(Node->hWnd,&msg)) + { + TranslateMessage(&msg); // Translate virtual key code + DispatchMessage(&msg); // Dispatches message to the window + } + } + } + DestroyWindow(Node->hWnd); + + + ASSERT(Node->RefCount == 0); + + dwRet = ERROR_SUCCESS; + +Cleanup_Exit: + + // Free the allocated resources + // + + LocalFree(Node); + + DBG_EXIT_UL("TUISPI_providerGenericDialog", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LONG TSPIAPI TUISPI_providerGenericDialogData( +// HTAPIDIALOGINSTANCE htDlgInst, +// LPVOID lpParams, +// DWORD dwSize) +// +// Functions: Request an action from the modem instance +// +// Return: ERROR_SUCCESS if successful +//**************************************************************************** + +LONG TSPIAPI TUISPI_providerGenericDialogData( + HTAPIDIALOGINSTANCE htDlgInst, + LPVOID lpParams, + DWORD dwSize + ) +{ + PDLGINFO pDlgInfo = (PDLGINFO)lpParams; + HWND ParentWindow; + UINT RefCount; + PUI_THREAD_NODE Node; + + + + + DBG_ENTER_UL("TUISPI_providerGenericDialogData", htDlgInst); + + ParentWindow=FindThreadWindow( + &UI_ThreadList, + htDlgInst + ); + + if (ParentWindow == NULL) { + + return ERROR_SUCCESS; + } + + Node=(PUI_THREAD_NODE)GetWindowLong(ParentWindow, GWL_USERDATA); + + + if (NULL == lpParams) { + // + // tapi want thread to exit, remove from list and dec ref count + // + RemoveNode( + &UI_ThreadList, + Node + ); + + + } + else + { + ASSERT(dwSize == sizeof(*pDlgInfo)); + + switch(pDlgInfo->dwCmd) + { + case DLG_CMD_CREATE: + StartMdmDialog(ParentWindow,pDlgInfo->idLine, pDlgInfo->dwType); + break; + + case DLG_CMD_DESTROY: + DestroyMdmDialog(ParentWindow,pDlgInfo->idLine, pDlgInfo->dwType); + break; + + case DLG_CMD_FREE_INSTANCE: + // + // server wants thread to exit, remove from list and dec refcount + // + RemoveNode( + &UI_ThreadList, + Node + ); + + break; + + default: + break; + } + } + + if (0 == RemoveReference(Node)) { + // + // it's gone, count dec'ed when remove from list + // + PostMessage(ParentWindow, WM_MDM_TERMINATE, 0, 0); + } + + DBG_EXIT_UL("TUISPI_providerGenericDialogData", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// PDLGNODE NewDlgNode(DWORD, DWORD) +// +// Function: Add a new dialog box to the list +// +// Returns: a pointer to the dialog node if the dialog can be added +// +//**************************************************************************** + +PDLGNODE NewDlgNode (HWND Parent, DWORD idLine, DWORD dwType) +{ + PDLGNODE pDlgNode; + + PUI_THREAD_NODE UI_Node=(PUI_THREAD_NODE)GetWindowLong(Parent, GWL_USERDATA); + + // Allocate a new dialog node + // + if ((pDlgNode = (PDLGNODE)LocalAlloc(LPTR, sizeof(*pDlgNode))) + == NULL) + return NULL; + + // Insert the new node into the dialog list + // + pDlgNode->idLine = idLine; + pDlgNode->dwType = dwType; + pDlgNode->Parent = Parent; + INITCRITICALSECTION(pDlgNode->hSem); + + // Insert the new node to the list + // + ENTERCRITICALSECTION(UI_Node->CriticalSection); + pDlgNode->pNext = UI_Node->DlgList; + UI_Node->DlgList = pDlgNode; + LEAVECRITICALSECTION(UI_Node->CriticalSection); + + return pDlgNode; +} + +//**************************************************************************** +// BOOL DeleteDlgNode(PDLGNODE) +// +// Function: Remove a dialog box to the list +// +// Returns: TRUE if the dialog exist and removed +// +//**************************************************************************** + +BOOL DeleteDlgNode (HWND Parent, PDLGNODE pDlgNode) +{ + PDLGNODE pCurDlg, pPrevDlg; + PUI_THREAD_NODE UI_Node=(PUI_THREAD_NODE)GetWindowLong(Parent, GWL_USERDATA); + // Exclusively access the modem list + // + ENTERCRITICALSECTION(UI_Node->CriticalSection); + + // Start from the head of the CB list + // + pPrevDlg = NULL; + pCurDlg = UI_Node->DlgList; + + // traverse the list to find the specified CB + // + while (pCurDlg != NULL) + { + if (pCurDlg == pDlgNode) + { + // Is there a previous control block? + // + if (pPrevDlg == NULL) + { + // head of the list + // + UI_Node->DlgList = pCurDlg->pNext; + } + else + { + pPrevDlg->pNext = pCurDlg->pNext; + }; + break; + }; + + pPrevDlg = pCurDlg; + pCurDlg = pCurDlg->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(UI_Node->CriticalSection); + + // Have we found the dialog box in the list? + // + if (pCurDlg != NULL) + { + // Wait until no one else is using the line + // + ENTERCRITICALSECTION(pCurDlg->hSem); + DELETECRITICALSECTION(pCurDlg->hSem); + LocalFree(pCurDlg); + return TRUE; + } + else + { + return FALSE; + }; +} + +//**************************************************************************** +// PDLGNODE FindDlgNode(DWORD, DWORD) +// +// Function: Find the dialog node for the line dev +// +// Returns: a pointer to the dialog node if the dialog exist and removed. +// The dialog node's semaphore is claimed. +// +//**************************************************************************** + +PDLGNODE FindDlgNode (HWND Parent, DWORD idLine, DWORD dwType) +{ + PDLGNODE pCurDlg; + PUI_THREAD_NODE UI_Node=(PUI_THREAD_NODE)GetWindowLong(Parent, GWL_USERDATA); + // Exclusively access the modem list + // + ENTERCRITICALSECTION(UI_Node->CriticalSection); + + // Start from the head of the CB list + // + pCurDlg = UI_Node->DlgList; + + // traverse the list to find the specified CB + // + while (pCurDlg != NULL) + { + ENTERCRITICALSECTION(pCurDlg->hSem); + + if ((pCurDlg->idLine == idLine) && + (pCurDlg->dwType == dwType) && + (pCurDlg->Parent == Parent) ) + { + break; + }; + + LEAVECRITICALSECTION(pCurDlg->hSem); + + pCurDlg = pCurDlg->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(UI_Node->CriticalSection); + + return pCurDlg; +} + + +//**************************************************************************** +// BOOL IsDlgListMessage(MSG* pmsg) +// +// Function: Run the message throught the dialogbox list +// +// Returns: TRUE if the message is one of the dialog box's and FALSE otherwise +// +//**************************************************************************** + +BOOL IsDlgListMessage(HWND Parent, MSG* pmsg) +{ + PDLGNODE pDlgNode, pNext; + BOOL fRet = FALSE; + PUI_THREAD_NODE UI_Node=(PUI_THREAD_NODE)GetWindowLong(Parent, GWL_USERDATA); + // Exclusively access the modem list + // + ENTERCRITICALSECTION(UI_Node->CriticalSection); + + // Walk the dialog box list + // + pDlgNode = UI_Node->DlgList; + while(pDlgNode != NULL && !fRet) + { + ENTERCRITICALSECTION(pDlgNode->hSem); + + // Check whether the message belongs to this dialog + // + if (IsWindow(pDlgNode->hDlg) && IsDialogMessage(pDlgNode->hDlg, pmsg)) + { + // Yes, we are done! + // + fRet = TRUE; + }; + + LEAVECRITICALSECTION(pDlgNode->hSem); + + // Check the next dialog + // + pDlgNode = pDlgNode->pNext; + }; + + // Finish accessing the modem list + // + LEAVECRITICALSECTION(UI_Node->CriticalSection); + + return fRet; +} +//**************************************************************************** +// void CleanupDlgList() +// +// Function: Clean up the dialogbox list +// +// Returns: None +// +//**************************************************************************** + +void CleanupDlgList (HWND Parent) +{ + PDLGNODE pDlgNode, pNext; + PUI_THREAD_NODE UI_Node=(PUI_THREAD_NODE)GetWindowLong(Parent, GWL_USERDATA); + // Exclusively access the modem list + // + ENTERCRITICALSECTION(UI_Node->CriticalSection); + + // Walk the dialog box list + // + pDlgNode = UI_Node->DlgList; + while(pDlgNode != NULL) + { + ENTERCRITICALSECTION(pDlgNode->hSem); + + // Destroy the dialog box first + // + DestroyWindow(pDlgNode->hDlg); + + // Free the CB and move onto the next dialog + // + pNext = pDlgNode->pNext; + DELETECRITICALSECTION(pDlgNode->hSem); + LocalFree(pDlgNode); + pDlgNode = pNext; + } + + // Finish accessing the modem list + // + UI_Node->DlgList=NULL; + + LEAVECRITICALSECTION(UI_Node->CriticalSection); + + return; +} + +//**************************************************************************** +// DWORD StartMdmDialog(DWORD, DWORD) +// +// Function: Start modem dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD StartMdmDialog(HWND Parent, DWORD idLine, DWORD dwType) +{ + PDLGNODE pDlgNode; + DWORD dwRet; + + // Create the talk/drop dialog node + // + pDlgNode = NewDlgNode(Parent, idLine, dwType); + + if (pDlgNode != NULL) + { + PostMessage(Parent, WM_MDM_DLG, (WPARAM)idLine, (LPARAM)dwType); + dwRet = ERROR_SUCCESS; + } + else + { + dwRet = ERROR_OUTOFMEMORY; + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD DestroyMdmDialog(DWORD, DWORD) +// +// Function: destroy talk/drop dialog +// +// Notes: This function is called from the state machine thread +// +// Returns: none +// +//**************************************************************************** + +DWORD DestroyMdmDialog(HWND Parent,DWORD idLine, DWORD dwType) +{ +#ifdef DEBUG + PDLGNODE pDlgNode; + + // Search for the dialog + // + pDlgNode = FindDlgNode(Parent, idLine, dwType); + + // Check if the talkdrop dialog is available + // + if (pDlgNode != NULL) + { + LEAVECRITICALSECTION(pDlgNode->hSem); + } + else + { + DPRINTF("Could not find the associated dialog node"); + ASSERT(0); + }; +#endif // DEBUG + + PostMessage(Parent, WM_MDM_TERMINATE_WND, (WPARAM)idLine, + (LPARAM)dwType); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// LRESULT MdmWndProc(HWND, UINT, WPARAM, LPARAM) +// +// Function: Main window for the modem window thread. +// +// Returns: 0 or 1 +// +//**************************************************************************** + +LRESULT MdmWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + // Determine the command + // + switch(message) + { + + case WM_CREATE: + { + LPCREATESTRUCT lpcs=(LPCREATESTRUCT) lParam; + + SetWindowLong(hwnd, GWL_USERDATA, (LONG)lpcs->lpCreateParams); + + break; + } + case WM_MDM_TERMINATE: + // + // The thread is being terminated + // Destroy all the windows + // + CleanupDlgList(hwnd); + PostQuitMessage(ERROR_SUCCESS); + break; + + case WM_MDM_TERMINATE_WND: + case WM_MDM_TERMINATE_WND_NOTIFY: + { + PDLGNODE pDlgNode; + + // Search for the dialog node + // + if ((pDlgNode = FindDlgNode(hwnd,(DWORD)wParam, (DWORD)lParam)) == NULL) + { + break; + }; + + // The window is requested to be destroyed + // + DestroyWindow(pDlgNode->hDlg); + + // If the modem dialog structure is available + // notify the state machine thread + // + if (message == WM_MDM_TERMINATE_WND_NOTIFY) + { + DLGREQ DlgReq; + + TUISPIDLLCALLBACK Callback; + + DlgReq.dwCmd = UI_REQ_COMPLETE_ASYNC; + DlgReq.dwParam = pDlgNode->dwStatus; + + Callback=GetCallbackProc(hwnd); + + (*Callback)(pDlgNode->idLine, TUISPIDLL_OBJECT_LINEID, + (LPVOID)&DlgReq, sizeof(DlgReq)); + + }; + + // Remove it from the dialog list + // + LEAVECRITICALSECTION(pDlgNode->hSem); + DeleteDlgNode(hwnd,pDlgNode); + + break; + } + case WM_MDM_DLG: + { + PDLGNODE pDlgNode; + + // + // Find the dialog node + // + pDlgNode = FindDlgNode(hwnd,(DWORD)wParam, (DWORD)lParam); + + if (pDlgNode != NULL) + { + if (pDlgNode->hDlg == NULL) + { + switch(lParam) + { + case TALKDROP_DLG: + // + // Create a talk-drop dialog box + // + pDlgNode->hDlg = CreateTalkDropDlg(hwnd, (DWORD)pDlgNode); + break; + + case MANUAL_DIAL_DLG: + // + // Create a talk-drop dialog box + // + pDlgNode->hDlg = CreateManualDlg(hwnd, (DWORD)pDlgNode); + break; + + case TERMINAL_DLG: + // + // Create a talk-drop dialog box + // + pDlgNode->hDlg = CreateTerminalDlg(hwnd, (DWORD)wParam); + break; + + default: + break; + }; + } + else + { + DPRINTF("Another dialog of the same type exists."); + ASSERT(0); + }; + + LEAVECRITICALSECTION(pDlgNode->hSem); + }; + break; + } + + default: + return(DefWindowProc(hwnd, message, wParam, lParam)); + }; + return 0; +} + + + +//**************************************************************************** +// void EndMdmDialog(DWORD, DWORD, DWORD) +// +// Function: Request to end dialog from the dialog itself. +// +// Returns: None +// +//**************************************************************************** + +void EndMdmDialog(HWND Parent, DWORD idLine, DWORD dwType, DWORD dwStatus) +{ + PDLGNODE pDlgNode; + + // Look for the dialog node + // + if ((pDlgNode = FindDlgNode(Parent, idLine, dwType)) != NULL) + { + pDlgNode->dwStatus = dwStatus; + + // Notify the dialog box result + // + PostMessage(Parent, WM_MDM_TERMINATE_WND_NOTIFY, (WPARAM)idLine, + (LPARAM)dwType); + + LEAVECRITICALSECTION(pDlgNode->hSem); + }; + return; +} + + + +//**************************************************************************** +//**************************************************************************** +//************ The following calls are in the context of TAPISRV************** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// DWORD CreateMdmDlgInstance (PLINEDEV pLineDev) +// +// Function: Start dialog instance +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// +//**************************************************************************** + +DWORD CreateMdmDlgInstance (PLINEDEV pLineDev) +{ + HANDLE hEvent; + TUISPICREATEDIALOGINSTANCEPARAMS cdip; + + DBG_PLD_ENTER("CreateMdmDlgInstance"); + + ASSERT(pLineDev->dwPendingID != INVALID_PENDINGID); + + // Package the params + // + cdip.dwRequestID = pLineDev->dwPendingID; + cdip.hdDlgInst = (HDRVDIALOGINSTANCE)pLineDev; + cdip.htDlgInst = NULL; + cdip.lpszUIDLLName = gszTSPFilename; + cdip.lpParams = NULL; + cdip.dwSize = 0; + + // Notify TAPI to start a dialog instance + // + (*(pLineDev->lpfnEvent))((HTAPILINE)ghProvider, NULL, + LINE_CREATEDIALOGINSTANCE, + (DWORD)(&cdip), + 0, 0); + + pLineDev->hDlgInst = cdip.htDlgInst; + DBG_PLD_EXIT("CreateMdmDlgInstance", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD DestroyMdmDlgInstance (PLINEDEV pLineDev) +// +// Function: Destroy dialog instance +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// +//**************************************************************************** + +DWORD DestroyMdmDlgInstance (PLINEDEV pLineDev) +{ + DLGINFO DlgInfo; + + DBG_PLD_ENTER("DestroyMdmDlgInstance"); + + if (pLineDev->hDlgInst == NULL) + { + DBG_PLD_EXIT("DestroyMdmDlgInstance", ERROR_SUCCESS); + return ERROR_SUCCESS; + } + + // Package the parameters + // + DlgInfo.idLine = 0; + DlgInfo.dwType = 0; + DlgInfo.dwCmd = DLG_CMD_FREE_INSTANCE; + + // Notify TAPI to stop a dialog instance + // + (*(pLineDev->lpfnEvent))((HTAPILINE)pLineDev->hDlgInst, NULL, + LINE_SENDDIALOGINSTANCEDATA, + (DWORD)(&DlgInfo), + sizeof(DlgInfo), + 0); + + pLineDev->hDlgInst = NULL; + + DBG_PLD_EXIT("DestroyMdmDlgInstance", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD SPStartMdmDialog (PLINEDEV pLineDev, DWORD dwType) +// +// Function: Create a dialog in the dialog instance +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// +//**************************************************************************** + +DWORD SPStartMdmDialog (PLINEDEV pLineDev, DWORD dwType) +{ + DLGINFO DlgInfo; + + // Package the parameters + // + DlgInfo.idLine = pLineDev->dwID; + DlgInfo.dwType = dwType; + DlgInfo.dwCmd = DLG_CMD_CREATE; + + // Notify TAPI to start a dialog + // + (*(pLineDev->lpfnEvent))((HTAPILINE)pLineDev->hDlgInst, NULL, + LINE_SENDDIALOGINSTANCEDATA, + (DWORD)(&DlgInfo), + sizeof(DlgInfo), + 0); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD SPDestroyMdmDialog (PLINEDEV pLineDev, DWORD dwType) +// +// Function: Destroy a dialog in the dialog instance +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// +//**************************************************************************** + +DWORD SPDestroyMdmDialog (PLINEDEV pLineDev, DWORD dwType) +{ + DLGINFO DlgInfo; + + // Package the parameters + // + DlgInfo.idLine = pLineDev->dwID; + DlgInfo.dwType = dwType; + DlgInfo.dwCmd = DLG_CMD_DESTROY; + + // Notify TAPI to start a dialog + // + (*(pLineDev->lpfnEvent))((HTAPILINE)pLineDev->hDlgInst, NULL, + LINE_SENDDIALOGINSTANCEDATA, + (DWORD)(&DlgInfo), + sizeof(DlgInfo), + 0); + return ERROR_SUCCESS; +} + +//**************************************************************************** +// DWORD TalkDropDialog(PLINEDEV) +// +// Function: Start talkdrop dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// LINEERR_NOMEM if fails +// +//**************************************************************************** + +DWORD TalkDropDialog(PLINEDEV pLineDev) +{ + DWORD dwRet; + + if(IS_UI_DLG_UP(pLineDev, UI_DLG_TALKDROP)) + { + DPRINTF("Attempting to display another TalkDrop dialog."); + ASSERT(0); + return ERROR_SUCCESS; + }; + + if ((dwRet = SPStartMdmDialog(pLineDev, TALKDROP_DLG)) + == ERROR_SUCCESS) + { + START_UI_DLG(pLineDev, UI_DLG_TALKDROP); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD DestroyTalkDropDialog(PLINEDEV) +// +// Function: Start talkdrop dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD DestroyTalkDropDialog(PLINEDEV pLineDev) +{ + if (!IS_UI_DLG_UP(pLineDev, UI_DLG_TALKDROP)) + return ERROR_SUCCESS; + + return SPDestroyMdmDialog(pLineDev, TALKDROP_DLG); +} + +//**************************************************************************** +// DWORD ManualDialog(PLINEDEV) +// +// Function: Start manual-dial dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD ManualDialog(PLINEDEV pLineDev) +{ + DWORD dwRet; + + if(IS_UI_DLG_UP(pLineDev, UI_DLG_MANUAL)) + { + DPRINTF("Attempting to display another Manual-dial dialog."); + ASSERT(0); + return ERROR_SUCCESS; + }; + + if ((dwRet = SPStartMdmDialog(pLineDev, MANUAL_DIAL_DLG)) + == ERROR_SUCCESS) + { + START_UI_DLG(pLineDev, UI_DLG_MANUAL); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD DestroyManualDialog(PLINEDEV) +// +// Function: Start talkdrop dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD DestroyManualDialog(PLINEDEV pLineDev) +{ + if (!IS_UI_DLG_UP(pLineDev, UI_DLG_MANUAL)) + return ERROR_SUCCESS; + + return SPDestroyMdmDialog(pLineDev, MANUAL_DIAL_DLG); +} + +//**************************************************************************** +// DWORD TerminalDialog(PLINEDEV) +// +// Function: Start terminal dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD TerminalDialog(PLINEDEV pLineDev) +{ + DWORD dwRet; + + if(IS_UI_DLG_UP(pLineDev, UI_DLG_TERMINAL)) + { + DPRINTF("Attempting to display another Terminal dialog."); + ASSERT(0); + return ERROR_SUCCESS; + }; + + if ((dwRet = SPStartMdmDialog(pLineDev, TERMINAL_DLG)) + == ERROR_SUCCESS) + { + START_UI_DLG(pLineDev, UI_DLG_TERMINAL); + }; + + return dwRet; +} + +//**************************************************************************** +// DWORD DestroyTerminalDialog(PLINEDEV) +// +// Function: Start talkdrop dialog +// +// Notes: This function is called from the state machine thread +// +// Return: ERROR_SUCCESS if dialog box is successfully created +// ERROR_OUTOFMEMORY if fails +// +//**************************************************************************** + +DWORD DestroyTerminalDialog(PLINEDEV pLineDev) +{ + if (!IS_UI_DLG_UP(pLineDev, UI_DLG_TERMINAL)) + return ERROR_SUCCESS; + + return SPDestroyMdmDialog(pLineDev, TERMINAL_DLG); +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerGenericDialogData( +// DWORD dwObjectID, +// DWORD dwObjectType, +// LPVOID lpParams, +// DWORD dwSize) +// +// Functions: Callback from UI DLL to TSP +// +// Return: ERROR_SUCCESS if successful +//**************************************************************************** + +LONG +TSPIAPI +TSPI_providerGenericDialogData( + DWORD dwObjectID, + DWORD dwObjectType, + LPVOID lpParams, + DWORD dwSize + ) +{ + PLINEDEV pLineDev; + PDLGREQ pDlgReq = (PDLGREQ)lpParams; + DWORD dwRet = ERROR_SUCCESS; + + DBG_ENTER_UL("TSPI_providerGenericDialogData", dwObjectID); + + ASSERT (dwObjectType == TUISPIDLL_OBJECT_LINEID); + + // Find the corresponding modem device + // + if ((pLineDev = GetCBfromID(dwObjectID)) == NULL) + { + DBG_EXIT_UL("TSPI_providerGenericDialogData", LINEERR_NODEVICE); + return LINEERR_NODEVICE; + } + + // Determine the request + // + switch(pDlgReq->dwCmd) + { + case UI_REQ_COMPLETE_ASYNC: + MdmAsyncContinue(pLineDev, + pDlgReq->dwParam); + break; + + case UI_REQ_END_DLG: + switch(pDlgReq->dwParam) + { + case TALKDROP_DLG: + STOP_UI_DLG(pLineDev, UI_DLG_TALKDROP); + break; + + case MANUAL_DIAL_DLG: + STOP_UI_DLG(pLineDev, UI_DLG_MANUAL); + break; + + case TERMINAL_DLG: + STOP_UI_DLG(pLineDev, UI_DLG_TERMINAL); + break; + }; + break; + + case UI_REQ_HANGUP_LINE: + + // Make a direct call to unimodem to drop the line + // + if ((pLineDev->DevState != DEVST_DISCONNECTED) + && + (pLineDev->DevState != DEVST_DISCONNECTING)) { + + UnimodemHangup(pLineDev, TRUE); + } + + break; + + case UI_REQ_TERMINAL_INFO: + { + PTERMREQ pTermReq = (PTERMREQ)pDlgReq; + HANDLE hTargetProcess; + + // Duplicate sync event handle + // + if ((hTargetProcess = OpenProcess(PROCESS_DUP_HANDLE, TRUE, + pTermReq->DlgReq.dwParam)) != NULL) + { + if (!DuplicateHandle(GetCurrentProcess(), pLineDev->hDevice, + hTargetProcess, &pTermReq->hDevice, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + pTermReq->hDevice = NULL; + }; + CloseHandle(hTargetProcess); + }; + + // Get the terminal type + // + pTermReq->dwTermType = (pLineDev->DevState == DEVST_PORTPOSTTERMINAL)? + TERMINAL_POST : TERMINAL_PRE; + break; + } + + case UI_REQ_GET_PROP: + { + PPROPREQ pPropReq = (PPROPREQ)pDlgReq; + + ASSERT(pLineDev->pDevCfg != NULL); + + // If the line is active, we need to get the current modem setting. + // + if (pLineDev->hDevice != INVALID_DEVICE) + { + DWORD cb = pLineDev->pDevCfg->commconfig.dwSize; + + // Get the modem configuration + // + UnimodemGetCommConfig(pLineDev, + &(pLineDev->pDevCfg->commconfig), + &cb); + }; + + pPropReq->dwCfgSize = pLineDev->pDevCfg->dfgHdr.dwSize; + pPropReq->dwMdmType = (DWORD)pLineDev->bDeviceType; + pPropReq->dwMdmCaps = pLineDev->dwDevCapFlags; + pPropReq->dwMdmOptions = pLineDev->dwModemOptions; + lstrcpyn(pPropReq->szDeviceName, pLineDev->szDeviceName, + sizeof(pPropReq->szDeviceName)); + break; + } + + case UI_REQ_GET_DEVCFG: + { + ASSERT (pLineDev->pDevCfg != NULL); + + // If the line is active, we need to get the current modem setting. + // + if (pLineDev->hDevice != INVALID_DEVICE) + { + DWORD cb = pLineDev->pDevCfg->commconfig.dwSize; + + // Get the modem configuration + // + UnimodemGetCommConfig(pLineDev, + &(pLineDev->pDevCfg->commconfig), + &cb); + }; + + CopyMemory((LPBYTE)(pDlgReq+1), (LPBYTE)pLineDev->pDevCfg, pDlgReq->dwParam); + break; + } + + case UI_REQ_SET_DEVCFG: + { + ASSERT (pLineDev->pDevCfg != NULL); + + // Save the changes back + // + CopyMemory((LPBYTE)pLineDev->pDevCfg, (LPBYTE)(pDlgReq+1), pDlgReq->dwParam); + + // If the line is active, we need to propagate the current modem setting. + // + if (pLineDev->hDevice != INVALID_DEVICE) + { + // Set the modem configuration + // + UnimodemSetCommConfig(pLineDev, + &(pLineDev->pDevCfg->commconfig), + pLineDev->pDevCfg->commconfig.dwSize); + }; + break; + } + + case UI_REQ_GET_PHONENUMBER: + { + PNUMBERREQ pNumberReq = (PNUMBERREQ)pDlgReq; + +// ASSERT(sizeof(pNumberReq->szPhoneNumber) == sizeof(pLineDev->szAddress)); + + if ((DEVST_PORTCONNECTING == pLineDev->DevState) + || + (DEVST_MANUALDIALING == pLineDev->DevState)) { + + lstrcpyA(pNumberReq->szPhoneNumber,pLineDev->szAddress); + + } else { + + lstrcpyA(pNumberReq->szPhoneNumber,""); + } + + break; + } + + + + default: + break; + } + + RELEASE_LINEDEV(pLineDev); + + DBG_EXIT_UL("TSPI_providerGenericDialogData", dwRet); + return dwRet; +} + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerFreeDialogInstance( +// HDRVDIALOGINSTANCE hdDlgInstance) +// +// Functions: Indicates the dialog instance was freed +// +// Return: ERROR_SUCCESS if successful +//**************************************************************************** + +LONG +TSPIAPI +TSPI_providerFreeDialogInstance( + HDRVDIALOGINSTANCE hdDlgInstance + ) +{ + DBG_ENTER_UL("TSPI_providerFreeDialogInstance", hdDlgInstance); + + + DBG_EXIT_UL("TSPI_providerFreeDialogInstance", ERROR_SUCCESS); + return ERROR_SUCCESS; +} + + +//**************************************************************************** +// LONG +// TSPIAPI +// TSPI_providerUIIdentify( +// LPTSTR lpszUIDllName) +// +// Functions: Retreives the UI Dll Name +// +// Return: ERROR_SUCCESS if successful +//**************************************************************************** + +LONG +TSPIAPI +TSPI_providerUIIdentify( + LPTSTR lpszUIDllName + ) +{ + DBG_ENTER("TSPI_providerUIIdentify"); + + lstrcpy(lpszUIDllName, gszTSPFilename); + + DBG_EXIT_UL("TSPI_providerUIIdentify", ERROR_SUCCESS); + return ERROR_SUCCESS; +} diff --git a/private/unimodem/tapisp/wndthrd.h b/private/unimodem/tapisp/wndthrd.h new file mode 100644 index 000000000..cf7083123 --- /dev/null +++ b/private/unimodem/tapisp/wndthrd.h @@ -0,0 +1,83 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: wndthrd.h +// Content: This file contains the declaration for UI parts +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +//**************************************************************************** + +// Dialog Types +// +#define TALKDROP_DLG 0 +#define MANUAL_DIAL_DLG 1 +#define TERMINAL_DLG 2 + +// Dialog Request +// +typedef struct tagDlgReq { + DWORD dwCmd; + DWORD dwParam; +} DLGREQ, *PDLGREQ; + +typedef struct tagTermReq { + DLGREQ DlgReq; + HANDLE hDevice; + DWORD dwTermType; +} TERMREQ, *PTERMREQ; + +typedef struct tagPropReq { + DLGREQ DlgReq; + DWORD dwCfgSize; + DWORD dwMdmType; + DWORD dwMdmCaps; + DWORD dwMdmOptions; + TCHAR szDeviceName[MAXDEVICENAME+1]; +} PROPREQ, *PPROPREQ; + +typedef struct tagNumberReq { + DLGREQ DlgReq; + DWORD dwSize; + CHAR szPhoneNumber[MAXDEVICENAME+1]; +} NUMBERREQ, *PNUMBERREQ; + + +#define UI_REQ_COMPLETE_ASYNC 0 +#define UI_REQ_END_DLG 1 +#define UI_REQ_HANGUP_LINE 2 +#define UI_REQ_TERMINAL_INFO 3 +#define UI_REQ_GET_PROP 4 +#define UI_REQ_GET_DEVCFG 5 +#define UI_REQ_SET_DEVCFG 6 +#define UI_REQ_GET_PHONENUMBER 7 + + +// Dialog node +// +typedef struct tagDlgNode { + struct tagDlgNode *pNext; + CRITICAL_SECTION hSem; + HWND hDlg; + DWORD idLine; + DWORD dwType; + DWORD dwStatus; + HWND Parent; +} DLGNODE, *PDLGNODE; + + + +//extern TUISPIDLLCALLBACK gpfnUICallback; + + +TUISPIDLLCALLBACK WINAPI +GetCallbackProc( + HWND hdlg + ); + +TUISPIDLLCALLBACK WINAPI +GetCallbackProcFromParent( + HWND hdlg + ); + +void EndMdmDialog(HWND Parent, DWORD idLine, DWORD dwType, DWORD dwStatus); -- cgit v1.2.3