summaryrefslogtreecommitdiffstats
path: root/private/unimodem/tapisp
diff options
context:
space:
mode:
Diffstat (limited to 'private/unimodem/tapisp')
-rw-r--r--private/unimodem/tapisp/cfgdlg.c578
-rw-r--r--private/unimodem/tapisp/client.c47
-rw-r--r--private/unimodem/tapisp/common.c572
-rw-r--r--private/unimodem/tapisp/common.h88
-rw-r--r--private/unimodem/tapisp/debug.c214
-rw-r--r--private/unimodem/tapisp/debug.h182
-rw-r--r--private/unimodem/tapisp/devioctl.c1160
-rw-r--r--private/unimodem/tapisp/log.c425
-rw-r--r--private/unimodem/tapisp/log.rc153
-rw-r--r--private/unimodem/tapisp/logids.h134
-rw-r--r--private/unimodem/tapisp/makefile6
-rw-r--r--private/unimodem/tapisp/manual.c170
-rw-r--r--private/unimodem/tapisp/mcxapi.c591
-rw-r--r--private/unimodem/tapisp/mcxioctl.h107
-rw-r--r--private/unimodem/tapisp/mcxp.h530
-rw-r--r--private/unimodem/tapisp/mcxrw.c649
-rw-r--r--private/unimodem/tapisp/mcxstate.c4675
-rw-r--r--private/unimodem/tapisp/mcxutil.c781
-rw-r--r--private/unimodem/tapisp/mdmasyn.c1325
-rw-r--r--private/unimodem/tapisp/mdmutil.c1581
-rw-r--r--private/unimodem/tapisp/modem.c532
-rw-r--r--private/unimodem/tapisp/ov_pool.c234
-rw-r--r--private/unimodem/tapisp/rcids.h75
-rw-r--r--private/unimodem/tapisp/resource.h17
-rw-r--r--private/unimodem/tapisp/resource.rc324
-rw-r--r--private/unimodem/tapisp/sources82
-rw-r--r--private/unimodem/tapisp/talkdrop.c137
-rw-r--r--private/unimodem/tapisp/terminal.c890
-rw-r--r--private/unimodem/tapisp/timer.c527
-rw-r--r--private/unimodem/tapisp/timer.h51
-rw-r--r--private/unimodem/tapisp/traceids.h130
-rw-r--r--private/unimodem/tapisp/tracing.c696
-rw-r--r--private/unimodem/tapisp/tracing.h192
-rw-r--r--private/unimodem/tapisp/umdminit.c2792
-rw-r--r--private/unimodem/tapisp/umdmspi.h425
-rw-r--r--private/unimodem/tapisp/unimdm.c3399
-rw-r--r--private/unimodem/tapisp/unimdm.def147
-rw-r--r--private/unimodem/tapisp/unimdm.h182
-rw-r--r--private/unimodem/tapisp/unimdm.rc18
-rw-r--r--private/unimodem/tapisp/unimdm.rcv31
-rw-r--r--private/unimodem/tapisp/wndthrd.c1538
-rw-r--r--private/unimodem/tapisp/wndthrd.h83
42 files changed, 26470 insertions, 0 deletions
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 <regstr.h>
+#include <commctrl.h>
+#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 <windows.h>
+#include "slot.h"
+#include "tspnotif.h"
+
+
+BOOL WINAPI UnimodemNotifyTSP(PNOTIFICATION_FRAME pnf)
+{
+ BOOL fRet=FALSE;
+ HNOTIFICATION hN=0;
+
+ if (pnf->dwSig!=dwNFRAME_SIG || pnf->dwSize<sizeof(*pnf) ||
+ pnf->dwSize>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; i<COMMON_DIAL_MAX_INDEX+1; i++) {
+
+ pCommon->DialComponents[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; i<COMMON_DIAL_MAX_INDEX+1; i++) {
+
+ if (pCommon->DialComponents[i] != NULL) {
+
+ LocalFree(pCommon->DialComponents[i]);
+ }
+ }
+
+ //
+ // free and modem commands that we loaded
+ //
+ for (i=0; i<COMMON_MAX_COMMANDS; i++) {
+
+ if (pCommon->ModemCommands[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; i<COMMON_DIAL_MAX_INDEX+1; i++) {
+
+ if (pCommon->DialComponents[i] != NULL) {
+
+ LocalFree(pCommon->DialComponents[i]);
+ }
+ }
+
+ //
+ // free and modem commands that we loaded
+ //
+ for (i=0; i<COMMON_MAX_COMMANDS; i++) {
+
+ if (pCommon->ModemCommands[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))&GTC_MASK),(_A)?(_A):((_A)=1))
+ DWORD dwA = dwB+dwC;
+ *lpdwA = dwA&GTC_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 <rovcomm.h>
+
+// 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 <ntddmodm.h>
+
+#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 "<no response>\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 ... <cr>"
+// Settings\Init\1 = "AT ... <cr>"
+// ...
+//
+// 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 "<cr>"
+#define CR_MACRO_LENGTH 4
+#define LF_MACRO "<lf>"
+#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<cr>
+ // - set state to STATE_HANGING_UP_CMD
+#define STATE_HANGING_UP_CMD 13 // Wait for a response to ATH<cr>
+ // 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 <devioctl.h>
+#include <ntddmodm.h>
+
+
+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(dwTimeOut<GTC_MAXDELTA);
+
+ ASSERT(pModemInfo->mi_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 <ntddmodm.h>
+
+#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<cr>"
+ //
+ 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<cr>"
+ 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<cr>"
+ 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<cr> / 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 )
+ {
+ // <cr>
+ //
+ if (!strncmpi(pszRegResponse,CR_MACRO,CR_MACRO_LENGTH))
+ {
+ *pszValue++ = CR;
+ pszRegResponse += CR_MACRO_LENGTH;
+ continue;
+ }
+
+ // <lf>
+ //
+ if (!strncmpi(pszRegResponse,LF_MACRO,LF_MACRO_LENGTH))
+ {
+ *pszValue++ = LF;
+ pszRegResponse += LF_MACRO_LENGTH;
+ continue;
+ }
+
+ // <hxx>
+ //
+ 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;
+ }
+
+ // <macro>
+ //
+ 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;
+ }
+ } // <macro>
+ } // 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:
+// "<prefix> <blind_on/off> <dial prefix> <phonenumber> <dial suffix> <terminator>"
+// ... 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<cr> fOriginate = TRUE
+// ";" -> dialtone detection -> ATX_DT;<cr> fOriginate = FALSE
+// "5551212" -> dial and originate -> ATX_DT5551212<cr> fOriginate = TRUE
+// "5551212;" -> dial -> ATX_DT5551212;<cr> fOriginate = FALSE
+// "123456789012345678901234567890123456789012345678901234567890"
+// -> dial and originate -> ATX_DT12345678901234567890123456789012;<cr>
+// ATX_DT3456789012345678901234567890<cr>
+// fOriginate = TRUE
+// "123456789012345678901234567890123456789012345678901234567890;"
+// -> dial -> ATX_DT12345678901234567890123456789012;<cr>
+// ATX_DT3456789012345678901234567890;<cr>
+// 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. ";<cr>"
+ LPSTR pszOrigSuffix; // ex. "<cr>"
+ 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 <devioctl.h>
+#include <ntddser.h>
+
+#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 <cr>, <lf>, <hxx>, 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 <cr>, <lf>, <hxx>, 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 <devioctl.h>
+#include <ntddser.h>
+#include <slot.h>
+
+#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(dwTime<GTC_MAXDELTA);
+
+ // Allocate a timer block
+ //
+ if ((pTimer = (PMDMTIMER)LocalAlloc(LMEM_FIXED, sizeof(*pTimer))) == NULL)
+ {
+ return ERROR_OUTOFMEMORY;
+ };
+
+ // Calculate the wake-up time
+ //
+ pTimer->pNext = 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
+ &gtidTimerMdm); // 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 <regstr.h>
+
+#define Not_VxD
+#include <vmm.h>
+#include <configmg.h>
+
+#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 "<no response>\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 <tspnotif.h>
+#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 <regstr.h>
+
+#include "common.h"
+
+#define _INC_OLE
+#include <ole2.h>
+
+#define INITGUID
+#include <initguid.h>
+#include <devguid.h>
+
+#include <setupapi.h>
+
+#include <rovdbg.h>
+
+//****************************************************************************
+// 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 *)&regdevcaps,
+ &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;u<uMaxSize;u++)
+ {
+ if (!lpctszFriendlyName[u]) break;
+ }
+
+ ASSERT(u<uMaxSize);
+
+ if (u<uMaxSize)
+ {
+ PLINEDEV pLineDev = GetCBfromName (
+ (LPTSTR) lpctszFriendlyName
+ );
+
+ if (pLineDev)
+ {
+ DPRINTF1(
+ "CPLNOTIF: Marking device [%s] for refresh",
+ lpctszFriendlyName
+ );
+ pLineDev->fUpdateDefaultCommConfig=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 <nt.h>
+# include <ntrtl.h>
+# include <nturtl.h>
+# ifdef ASSERT
+# undef ASSERT
+# endif // ASSERT
+#endif // USE_SERVICECONTROLLER
+
+#include <windows.h> // also includes windowsx.h
+#include <windowsx.h>
+#ifndef MAXDWORD
+#define MAXDWORD MAXULONG
+#if (MAXDWORD!=0xffffffff)
+# error "MAXDWORD!=0xffffffff"
+#endif
+#endif // MAXDWORD
+
+// Public registry defines, in particular REGSTR_PATH_SETUP
+#include <regstr.h>
+
+// Dynamic add/remove of devices.
+// BUG BUG -- this needs to be consolodated with the code currently
+// #ifdef UNDER_CONSTRUCTION
+#define DYNA_ADDREMOVE
+
+#include <tapi.h>
+#include <tspi.h>
+
+//****************************************************************************
+// NT Build patched
+//****************************************************************************
+
+#include <modem.h>
+#include <mcx16.h>
+#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()&GTC_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 <windows.h>
+#include <commctrl.h>
+#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 <winver.h>
+#include <ntverp.h>
+#else
+#include <version.h>
+#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 <common.ver>
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);