/* File: D:\WACKER\cncttapi\cncttapi.c (Created: 08-Feb-1994) * * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 53 $ * $Date: 7/12/02 9:06a $ */ #define TAPI_CURRENT_VERSION 0x00010004 // cab:11/14/96 - required! #include #include #pragma hdrstop //#define DEBUGSTR #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cncttapi.h" #include "cncttapi.hh" #include // XD_TYPE #include // xfrGetDisplayWindow(), xfrDoTransfer() #include "tdll\XFDSPDLG.H" // XFR_SHUTDOWN static int DoNewModemWizard(HWND hWnd, int iTimeout); static int tapiReinit(const HHDRIVER hhDriver); static int tapiReinitMessage(const HHDRIVER hhDriver); static int DoDelayedCall(const HHDRIVER hhDriver); const TCHAR *g_achApp = TEXT("HyperTerminal"); static HHDRIVER gbl_hhDriver; // see LINEDEVSTATE for explaination. #if 0 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvEntry * * DESCRIPTION: * Currently, just initializes the C-Runtime library but may be used * for other things later. * * ARGUMENTS: * hInstDll - Instance of this DLL * fdwReason - Why this entry point is called * lpReserved - reserved * * RETURNS: * BOOL * */ BOOL WINAPI cnctdrvEntry(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpReserved) { hInstance = hInstDll; return _CRT_INIT(hInstDll, fdwReason, lpReserved); } #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvCreate * * DESCRIPTION: * Initializes the connection driver and returns a handle to the driver * if successful. * * ARGUMENTS: * hCnct - public connection handle * * RETURNS: * Handle to driver if successful, else 0. * */ HDRIVER WINAPI cnctdrvCreate(const HCNCT hCnct, const HSESSION hSession) { HHDRIVER hhDriver; if (hCnct == 0) { assert(FALSE); return 0; } hhDriver = malloc(sizeof(*hhDriver)); if (hhDriver == 0) { assert(FALSE); return 0; } gbl_hhDriver = hhDriver; memset(hhDriver, 0, sizeof(*hhDriver)); InitializeCriticalSection(&hhDriver->cs); hhDriver->hCnct = hCnct; hhDriver->hSession = hSession; hhDriver->iStatus = CNCT_STATUS_FALSE; hhDriver->dwLine = (DWORD)-1; cnctdrvInit(hhDriver); return (HDRIVER)hhDriver; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvDestroy * * DESCRIPTION: * Destroys a connection driver handle. * * ARGUMENTS: * hhDriver - private driver handle. * * RETURNS: * 0 or error code * */ int WINAPI cnctdrvDestroy(const HHDRIVER hhDriver) { if (hhDriver == 0) { assert(FALSE); return CNCT_BAD_HANDLE; } // Disconnect if we're connected or in the process. // Note: cnctdrvDisconnect should terminate the thread. cnctdrvDisconnect(hhDriver, DISCNCT_NOBEEP); if (hhDriver->hLine) { lineClose(hhDriver->hLine); memset(&hhDriver->stCallPar, 0, sizeof(hhDriver->stCallPar)); hhDriver->stCallPar.dwTotalSize = sizeof(hhDriver->stCallPar); hhDriver->stCallPar.dwMediaMode = LINEMEDIAMODE_DATAMODEM; hhDriver->stCallPar.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; hhDriver->stCallPar.dwBearerMode = 0; hhDriver->hLine = 0; } if (hhDriver->hLineApp) { LONG lLineShutdown = lineShutdown(hhDriver->hLineApp); if (lLineShutdown == LINEERR_NOMEM) { // // We are in a low memory state, so wait for a while, // then try to shutdown the line again. REV: 5/1/2002 // Sleep(500); lLineShutdown = lineShutdown(hhDriver->hLineApp); } if (lLineShutdown != 0) { assert(FALSE); } hhDriver->hLineApp = 0; } if (IsWindow(hhDriver->hwndCnctDlg)) EndModelessDialog(hhDriver->hwndCnctDlg); if (IsWindow(hhDriver->hwndTAPIWindow)) { DestroyWindow(hhDriver->hwndTAPIWindow); } /* --- Cleanup --- */ DeleteCriticalSection(&hhDriver->cs); free(hhDriver); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvLock * * DESCRIPTION: * Locks the connection driver's critical section semaphore. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * void * */ void cnctdrvLock(const HHDRIVER hhDriver) { EnterCriticalSection(&hhDriver->cs); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvUnlock * * DESCRIPTION: * Unlocks the connection driver's critical section semaphore. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * void * */ void cnctdrvUnlock(const HHDRIVER hhDriver) { LeaveCriticalSection(&hhDriver->cs); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvInit * * DESCRIPTION: * Initializes the connection handle. Can be called to reinitialize * the handle. Does an implicit disconnect. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0 * */ int WINAPI cnctdrvInit(const HHDRIVER hhDriver) { long lRet; int id = 0; int iReturn = 0; // Make sure we're disconnected. // cnctdrvDisconnect(hhDriver, DISCNCT_NOBEEP); // ---------------------------------------------------------------- // Need to shut down hLineApp and reinitialize everytime we read // new data file so that TAPI starts out in a clean and initialized // state. Otherwise, we might inherit values from the previous // session. // ---------------------------------------------------------------- if (hhDriver->hLineApp) { LONG lLineShutdown = lineShutdown(hhDriver->hLineApp); if (lLineShutdown == LINEERR_NOMEM) { // // We are in a low memory state, so wait for a while, // then try to shutdown the line again. REV: 5/1/2002 // Sleep(500); lLineShutdown = lineShutdown(hhDriver->hLineApp); } if (lLineShutdown != 0) { assert(FALSE); hhDriver->hLineApp = 0; return -2; } } hhDriver->hLineApp = 0; // Try to get a new LineApp handle now. // lRet = lineInitialize(&hhDriver->hLineApp, glblQueryDllHinst(), lineCallbackFunc, g_achApp, &hhDriver->dwLineCnt); if (lRet != 0) { iReturn = -3; switch (lRet) { case LINEERR_INIFILECORRUPT: id = IDS_ER_TAPI_INIFILE; break; case LINEERR_NODRIVER: id = IDS_ER_TAPI_NODRIVER; break; case LINEERR_NOMULTIPLEINSTANCE: id = IDS_ER_TAPI_NOMULTI; break; #if 0 // rev:08/05/99 We are now printing the lineInitialize() error. // rev:08/26/98 We need to make sure there was no error reported. // case LINEERR_INVALAPPNAME: case LINEERR_OPERATIONFAILED: case LINEERR_RESOURCEUNAVAIL: case LINEERR_INVALPOINTER: case LINEERR_REINIT: case LINEERR_NODEVICE: case LINEERR_NOMEM: id = IDS_ER_CNCT_TAPIFAILED; break; #endif case LINEERR_OPERATIONUNAVAIL: //rev: 08-05-99 If TAPI has not been installed, then return a // unique error code (since it will be handled // differently than other TAPI errors). // iReturn = -4; #if ((NT_EDITION && !NDEBUG) || !NT_EDITION) // Run the new Modem wizard if we have not prompted before. // DoNewModemWizard(sessQueryHwnd(hhDriver->hSession), sessQueryTimeout(hhDriver->hSession)); #endif // ((NT_EDITION && !NDEBUG) || !NT_EDITION) break; default: id = IDS_ER_TAPI_UNKNOWN; break; } // // Only display these errors if in Debug mode in NT_EDITION. // #if ((NT_EDITION && !NDEBUG) || !NT_EDITION) if ( id ) { TCHAR ach[256]; TCHAR achMessage[256]; LoadString(glblQueryDllHinst(), id, ach, sizeof(ach) / sizeof(TCHAR)); if (id == IDS_ER_TAPI_UNKNOWN) { wsprintf(achMessage, ach, lRet); } else { lstrcpy(achMessage, ach); } TimedMessageBox(sessQueryHwnd(hhDriver->hSession), achMessage, NULL, MB_OK | MB_ICONSTOP, sessQueryTimeout(hhDriver->hSession)); } #endif //((NT_EDITION && !NDEBUG) || !NT_EDITION) return iReturn; } hhDriver->iStatus = CNCT_STATUS_FALSE; hhDriver->dwLine = (DWORD)-1; hhDriver->dwCountryID = (DWORD)-1; hhDriver->dwPermanentLineId = (DWORD)-1; hhDriver->achDest[0] = TEXT('\0'); hhDriver->achAreaCode[0] = TEXT('\0'); hhDriver->achLineName[0] = TEXT('\0'); hhDriver->fUseCCAC = TRUE; /* --- This guy will set defaults --- */ EnumerateTapiLocations(hhDriver, 0, 0); #if defined(INCL_WINSOCK) hhDriver->iPort = 23; hhDriver->achDestAddr[0] = TEXT('\0'); #endif #ifdef INCL_CALL_ANSWERING hhDriver->fAnswering = FALSE; hhDriver->fRestoreSettings = FALSE; hhDriver->nSendCRLF = 0; hhDriver->nLocalEcho = 0; hhDriver->nAddLF = 0; hhDriver->nEchoplex = 0; hhDriver->pvUnregister = 0; #endif return iReturn; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvLoad * * DESCRIPTION: * Reads the session file to get stuff connection driver needs. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0=OK, else error * */ int WINAPI cnctdrvLoad(const HHDRIVER hhDriver) { LPVARSTRING pvs; unsigned long ul; const SF_HANDLE sfhdl = sessQuerySysFileHdl(hhDriver->hSession); hhDriver->dwCountryID = (DWORD)-1; ul = sizeof(hhDriver->dwCountryID); sfGetSessionItem(sfhdl, SFID_CNCT_CC, &ul, &hhDriver->dwCountryID); hhDriver->achAreaCode[0] = TEXT('\0'); ul = sizeof(hhDriver->achAreaCode); sfGetSessionItem(sfhdl, SFID_CNCT_AREA, &ul, hhDriver->achAreaCode); hhDriver->achDest[0] = TEXT('\0'); ul = sizeof(hhDriver->achDest); sfGetSessionItem(sfhdl, SFID_CNCT_DEST, &ul, hhDriver->achDest); hhDriver->dwPermanentLineId = 0; ul = sizeof(hhDriver->dwPermanentLineId); sfGetSessionItem(sfhdl, SFID_CNCT_LINE, &ul, &hhDriver->dwPermanentLineId); hhDriver->fUseCCAC = 1; ul = sizeof(hhDriver->fUseCCAC); sfGetSessionItem(sfhdl, SFID_CNCT_USECCAC, &ul, &hhDriver->fUseCCAC); hhDriver->fRedialOnBusy = 1; ul = sizeof(hhDriver->fRedialOnBusy); sfGetSessionItem(sfhdl, SFID_CNCT_REDIAL, &ul, &hhDriver->fRedialOnBusy); #if defined (INCL_WINSOCK) hhDriver->iPort = 23; ul = sizeof(hhDriver->iPort); sfGetSessionItem(sfhdl, SFID_CNCT_IPPORT, &ul, &hhDriver->iPort); hhDriver->achDestAddr[0] = TEXT('\0'); ul = sizeof(hhDriver->achDestAddr); sfGetSessionItem(sfhdl, SFID_CNCT_IPDEST, &ul, hhDriver->achDestAddr); #endif hhDriver->fCarrierDetect = FALSE; ul = sizeof(hhDriver->fCarrierDetect); sfGetSessionItem(sfhdl, SFID_CNCT_CARRIERDETECT, &ul, &hhDriver->fCarrierDetect); if ( IsNT() ) { hhDriver->achComDeviceName[0] = TEXT('\0'); ul = sizeof(hhDriver->achComDeviceName); sfGetSessionItem(sfhdl, SFID_CNCT_COMDEVICE, &ul, hhDriver->achComDeviceName); } // ---------------------------------------------------------------- // Need to shut down hLineApp and reinitialize everytime we read // new data file so that TAPI starts out in a clean and initialized // state. Otherwise, we might inherit values from the previous // session. // ---------------------------------------------------------------- if (hhDriver->hLineApp) { LONG lLineShutdown = lineShutdown(hhDriver->hLineApp); if (lLineShutdown == LINEERR_NOMEM) { // // We are in a low memory state, so wait for a while, // then try to shutdown the line again. REV: 5/1/2002 // Sleep(500); lLineShutdown = lineShutdown(hhDriver->hLineApp); } if (lLineShutdown != 0) { assert(FALSE); hhDriver->hLineApp = 0; return -2; } hhDriver->hLineApp = 0; if (lineInitialize(&hhDriver->hLineApp, glblQueryDllHinst(), lineCallbackFunc, g_achApp, &hhDriver->dwLineCnt)) { assert(FALSE); return -3; } } // EnumerateLines() will set the hhDriver->fMatchedPermanentLineID // guy if it finds a match for our saved dwPermanentLineId guy // if ( IsNT() ) { EnumerateLinesNT(hhDriver, 0); } else { EnumerateLines(hhDriver, 0); } /* --- If we saved a tapi configuration, restore it. --- */ if (sfGetSessionItem(sfhdl, SFID_CNCT_TAPICONFIG, &ul, 0) != 0) return 0; // Ok, might not be there. if ((pvs = malloc(ul)) == 0) { assert(FALSE); return -4; } if (sfGetSessionItem(sfhdl, SFID_CNCT_TAPICONFIG, &ul, pvs) == 0) { if (hhDriver->fMatchedPermanentLineID) { LPVOID pv = (BYTE *)pvs + pvs->dwStringOffset; if (lineSetDevConfig(hhDriver->dwLine, pv, pvs->dwStringSize, DEVCLASS) != 0) { // This error prevented a user from even opening a session // file if the file contained TAPI info and the user had // never installed a modem. We modified the error that appears // when you actually try to USE a non-existant modem so that // we could suppress the display of this error jkh 8/3/98 #if 0 TCHAR ach[FNAME_LEN]; LoadString(glblQueryDllHinst(), IDS_OPEN_FAILED, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); free(pvs); pvs = NULL; return -5; #endif } } } free(pvs); pvs = NULL; return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvSave * * DESCRIPTION: * Saves connection settings to the session file * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0=OK, else error * */ int WINAPI cnctdrvSave(const HHDRIVER hhDriver) { DWORD dwSize; unsigned long ul; LPVARSTRING pvs = NULL; const SF_HANDLE sfhdl = sessQuerySysFileHdl(hhDriver->hSession); sfPutSessionItem(sfhdl, SFID_CNCT_CC, sizeof(hhDriver->dwCountryID), &hhDriver->dwCountryID); sfPutSessionItem(sfhdl, SFID_CNCT_AREA, (lstrlen(hhDriver->achAreaCode) + 1) * sizeof(TCHAR), hhDriver->achAreaCode); sfPutSessionItem(sfhdl, SFID_CNCT_DEST, (lstrlen(hhDriver->achDest) + 1) * sizeof(TCHAR), hhDriver->achDest); sfPutSessionItem(sfhdl, SFID_CNCT_LINE, sizeof(hhDriver->dwPermanentLineId), &hhDriver->dwPermanentLineId); sfPutSessionItem(sfhdl, SFID_CNCT_USECCAC, sizeof(hhDriver->fUseCCAC), &hhDriver->fUseCCAC); sfPutSessionItem(sfhdl, SFID_CNCT_REDIAL, sizeof(hhDriver->fRedialOnBusy), &hhDriver->fRedialOnBusy); #if defined (INCL_WINSOCK) sfPutSessionItem(sfhdl, SFID_CNCT_IPPORT, sizeof(hhDriver->iPort), &hhDriver->iPort); sfPutSessionItem(sfhdl, SFID_CNCT_IPDEST, (lstrlen(hhDriver->achDestAddr) + 1) * sizeof(TCHAR), hhDriver->achDestAddr); #endif /* --- Usual lines of code to use TAPI --- */ if (hhDriver->hLineApp && hhDriver->dwLine != (DWORD)-1 && !IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4) && hhDriver->dwPermanentLineId != DIRECT_COM_DEVICE && hhDriver->dwPermanentLineId != DIRECT_COMWINSOCK) { if ((pvs = malloc(sizeof(VARSTRING))) == 0) { assert(FALSE); return 0; } memset( pvs, 0, sizeof(VARSTRING) ); pvs->dwTotalSize = sizeof(VARSTRING); if (lineGetDevConfig(hhDriver->dwLine, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; return 0; } if (pvs->dwNeededSize > pvs->dwTotalSize) { dwSize = pvs->dwNeededSize; free(pvs); pvs = NULL; if ((pvs = malloc(dwSize)) == 0) { assert(FALSE); return 0; } memset( pvs, 0, dwSize ); pvs->dwTotalSize = dwSize; if (lineGetDevConfig(hhDriver->dwLine, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; return 0; } } /* --- Store the whole structure --- */ ul = pvs->dwTotalSize; sfPutSessionItem(sfhdl, SFID_CNCT_TAPICONFIG, ul, pvs); free(pvs); pvs = NULL; } if ( IsNT() && hhDriver->dwPermanentLineId == DIRECT_COM_DEVICE) { ul = sizeof(hhDriver->achComDeviceName); sfPutSessionItem(sfhdl, SFID_CNCT_COMDEVICE, ul, hhDriver->achComDeviceName); } sfPutSessionItem(sfhdl, SFID_CNCT_CARRIERDETECT, sizeof(hhDriver->fCarrierDetect), &hhDriver->fCarrierDetect); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvQueryStatus * * DESCRIPTION: * Returns the current connection status as defined in * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * connection status or error code * */ int WINAPI cnctdrvQueryStatus(const HHDRIVER hhDriver) { int iStatus = CNCT_STATUS_FALSE; if (hhDriver == 0) { assert(FALSE); iStatus = CNCT_BAD_HANDLE; } else { cnctdrvLock(hhDriver); iStatus = hhDriver->iStatus; //* hard-code for now. cnctdrvUnlock(hhDriver); } return iStatus; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * SetStatus * * DESCRIPTION: * There's actually more to setting the connection status than just * setting the status variable as the code below indicates. Dumb * question: Why aren't there any locks in this code. Dumb Answer: * This function is only called from the ConnectLoop thread context * which has already locked things down. * * ARGUMENTS: * hhDriver - private driver handle * iStatus - new status * * RETURNS: * void * */ void SetStatus(const HHDRIVER hhDriver, const int iStatus) { HCLOOP hCLoop; /* --- Don't do things twice --- */ const HWND hwndToolbar = sessQueryHwndToolbar(hhDriver->hSession); cnctdrvLock(hhDriver); if (iStatus == hhDriver->iStatus) { if (iStatus == CNCT_STATUS_TRUE || iStatus == CNCT_STATUS_FALSE) { hCLoop = sessQueryCLoopHdl(hhDriver->hSession); if (hCLoop) CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_CNCTDRV); } cnctdrvUnlock(hhDriver); return; } /* --- Set the status, an exciting new adventure game --- */ switch (iStatus) { case CNCT_STATUS_TRUE: hCLoop = sessQueryCLoopHdl(hhDriver->hSession); #ifdef INCL_CALL_ANSWERING // If we are going from answering to connected, that means // we have answered a call. So tweak the ASCII settings so // that they make chatting possible. - cab:11/20/96 // if (hhDriver->fAnswering) { // Store old ASCII settings, and set the new ones. // hhDriver->nSendCRLF = CLoopGetSendCRLF(hCLoop); hhDriver->nLocalEcho = CLoopGetLocalEcho(hCLoop); hhDriver->nAddLF = CLoopGetAddLF(hCLoop); hhDriver->nEchoplex = CLoopGetEchoplex(hCLoop); CLoopSetSendCRLF(hCLoop, TRUE); CLoopSetLocalEcho(hCLoop, TRUE); CLoopSetAddLF(hCLoop, TRUE); CLoopSetEchoplex(hCLoop, TRUE); hhDriver->fRestoreSettings = TRUE; } #endif hhDriver->iStatus = CNCT_STATUS_TRUE; assert(hCLoop); if (hCLoop) { CLoopRcvControl(hCLoop, CLOOP_RESUME, CLOOP_RB_CNCTDRV); CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_CNCTDRV); } NotifyClient(hhDriver->hSession, EVENT_CONNECTION_OPENED, 0); sessBeeper(hhDriver->hSession); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_DIAL, FALSE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_HANGUP, TRUE); break; case CNCT_STATUS_CONNECTING: hhDriver->iStatus = CNCT_STATUS_CONNECTING; DialingMessage(hhDriver, IDS_DIAL_OFFERING); // temp NotifyClient(hhDriver->hSession, EVENT_CONNECTION_INPROGRESS, 0); EnableDialNow(hhDriver->hwndCnctDlg, FALSE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_DIAL, FALSE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_HANGUP, TRUE); break; case CNCT_STATUS_DISCONNECTING: hhDriver->iStatus = CNCT_STATUS_DISCONNECTING; ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_DIAL, FALSE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_HANGUP, FALSE); break; case CNCT_STATUS_FALSE: hCLoop = sessQueryCLoopHdl(hhDriver->hSession); #ifdef INCL_CALL_ANSWERING // Since this is called when we disconnect we need to restore // any ASCII Settings here. - cab:11/20/96 // if ( hhDriver->fRestoreSettings && hCLoop ) //mpt: so that we don't reference a null pointer { CLoopSetSendCRLF(hCLoop, hhDriver->nSendCRLF); CLoopSetLocalEcho(hCLoop, hhDriver->nLocalEcho); CLoopSetAddLF(hCLoop, hhDriver->nAddLF); CLoopSetEchoplex(hCLoop, hhDriver->nEchoplex); hhDriver->fRestoreSettings = FALSE; } hhDriver->fAnswering = FALSE; #endif hhDriver->iStatus = CNCT_STATUS_FALSE; if (hCLoop) { CLoopRcvControl(hCLoop, CLOOP_RESUME, CLOOP_RB_CNCTDRV); CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_CNCTDRV); } NotifyClient(hhDriver->hSession, EVENT_CONNECTION_CLOSED, 0); EnableDialNow(hhDriver->hwndCnctDlg, TRUE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_DIAL, TRUE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_HANGUP, FALSE); break; case CNCT_STATUS_ANSWERING: #ifdef INCL_CALL_ANSWERING hhDriver->fAnswering = TRUE; hhDriver->iStatus = CNCT_STATUS_ANSWERING; NotifyClient(hhDriver->hSession, EVENT_CONNECTION_INPROGRESS, 0); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_DIAL, FALSE); ToolbarEnableButton(hwndToolbar, IDM_ACTIONS_HANGUP, TRUE); #endif break; default: assert(FALSE); break; } cnctdrvUnlock(hhDriver); /* --- Notify status bar so it can update it's display --- */ PostMessage(sessQueryHwndStatusbar(hhDriver->hSession), SBR_NTFY_REFRESH, (WPARAM)SBR_CNCT_PART_NO, 0); return; } #ifdef INCL_CALL_ANSWERING /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * WaitForCRcallback * * DESCRIPTION: * This function gets registered as a callback with the cloop. Every * character that the cloop gets, is passed back to this function. When * this function finds a CR, it indicates that a connection has been * established. Note that this applies only to an answer mode connection, * in the direct connect driver. * * ARGUMENTS: * ECHAR ech - The character returned from cloop. * void *p - A void pointer passed back from cloop. This is * the enternal connection driver handle. * * RETURNS: * CLOOP_DISCARD unless the character is a CR where is returns CLOOP_KEEP. * * AUTHOR: C. Baumgartner, 11/20/96 (ported from HAWin32) */ int WaitForCRcallback(ECHAR ech, void *p) { int iRet = CLOOP_DISCARD; // Discard all characters except the CR. TCHAR chC = (TCHAR) ech; const HHDRIVER hhDriver = (HHDRIVER)p; if (chC == TEXT('\r')) { CLoopUnregisterRmtInputChain(hhDriver->pvUnregister); hhDriver->pvUnregister = 0; // Okay, we are connected now. // SetStatus(hhDriver, CNCT_STATUS_TRUE); iRet = CLOOP_KEEP; } return iRet; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * WaitForCRinit * * DESCRIPTION: * This function is called to register a new string match function * with the cloop. It unregisters a previously registered function * if necessary. It basically will cause us to wait for a carriage * return. * * ARGUMENTS: * HHDRIVER hhDriver - The internal connection handle. * * RETURNS: * 0 if successful, otherwise -1. * * AUTHOR: C. Baumgartner, 11/20/96 (ported from HAWin32) */ static int WaitForCRinit(const HHDRIVER hhDriver) { const HCLOOP hCLoop = sessQueryCLoopHdl(hhDriver->hSession); if (!hCLoop) { return -1; } // If we are already registered, unregister. // if (hhDriver->pvUnregister != 0) { CLoopUnregisterRmtInputChain(hhDriver->pvUnregister); hhDriver->pvUnregister = 0; } // We need to un-block CLoop so we can look at the // characters as they come in. // CLoopRcvControl(hCLoop, CLOOP_RESUME, CLOOP_RB_CNCTDRV); // Register the match function with the cloop. // hhDriver->pvUnregister = CLoopRegisterRmtInputChain(hCLoop, WaitForCRcallback, hhDriver); if (hhDriver->pvUnregister == 0) { return -1; } return 0; } #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvComEvent * * DESCRIPTION: * Com routines call the this to notify connection routines that some * significant event has happened (ie. carrier lost). The connetion * driver decides what it is interested in knowing however by * querying the com drivers for the specific data. * * ARGUMENTS: * hhDriver - private connection driver handle * event - the com event we are being notified of * * RETURNS: * 0 * */ int WINAPI cnctdrvComEvent(const HHDRIVER hhDriver, const enum COM_EVENTS event) { int iRet; TCHAR ach[MAX_PATH]; #if defined(INCL_WINSOCK) char achMsg[512]; #endif HCOM hCom; if (hhDriver == 0) { assert(FALSE); return CNCT_BAD_HANDLE; } if (event == CONNECT) { #if defined (INCL_WINSOCK) // If we are connected via Winsock, there will be some ComEvents // that we have to handle if (hhDriver->dwPermanentLineId == DIRECT_COMWINSOCK) { hCom = sessQueryComHdl(hhDriver->hSession); iRet = ComDriverSpecial(hCom, "Query ISCONNECTED", ach, MAX_PATH); if (iRet == COM_OK) { int iPortOpen = atoi(ach); // Do we want to initiate a disconnect? Only if we're // connected. if (iPortOpen == COM_PORT_NOT_OPEN) { if (hhDriver->iStatus == CNCT_STATUS_TRUE) { // If we are already connected, then beep when // we disconnect. - cab:12/06/96 // //mpt:10-28-97 added exit upon disconnect feature NotifyClient(hhDriver->hSession, EVENT_LOST_CONNECTION, CNCT_LOSTCARRIER | (sessQueryExit(hhDriver->hSession) ? DISCNCT_EXIT : 0 )); } else if (hhDriver->iStatus == CNCT_STATUS_CONNECTING) { NotifyClient(hhDriver->hSession, EVENT_LOST_CONNECTION, CNCT_LOSTCARRIER | DISCNCT_NOBEEP); LoadString(glblQueryDllHinst(), IDS_ER_TCPIP_BADADDR, ach, MAX_PATH); wsprintf(achMsg, ach, hhDriver->achDestAddr, hhDriver->iPort); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), achMsg, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); } } else if (iPortOpen == COM_PORT_OPEN) { SetStatus(hhDriver, CNCT_STATUS_TRUE); } } } else #endif // defined (INCL_WINSOCK) if (IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4) || hhDriver->dwPermanentLineId == DIRECT_COM_DEVICE) { // Checking the status of DCD before disconnecting // is a good idea, prevents us hanging up whenever we // get any event while connected // - mpt:08-26-97 hCom = sessQueryComHdl(hhDriver->hSession); iRet = ComDriverSpecial(hCom, "Query DCD_STATUS", ach, MAX_PATH); if (iRet == COM_OK) { int iPortOpen = atoi(ach); // Do we want to initiate a disconnect? Only if we're // connected. if (iPortOpen == COM_PORT_NOT_OPEN) { if (hhDriver->iStatus == CNCT_STATUS_TRUE) { // If we are direct cabled, and we're connected, then // the other end just disconnected, so disconnect now. // - cab:11/20/96 // // Note: We must disconnect by posting a message to // thread one. This is because if we get here, we were // called from the context of the com thread, which // will not exit properly if cnctdrvDisconnect is called. // - cab:11/21/96 // // // If we are already connected, then beep when // we disconnect. - cab:12/06/96 // //mpt:10-28-97 added exit upon disconnect feature NotifyClient(hhDriver->hSession, EVENT_LOST_CONNECTION, CNCT_LOSTCARRIER | (sessQueryExit(hhDriver->hSession) ? DISCNCT_EXIT : 0 )); } #if defined(INCL_CALL_ANSWERING) else if (hhDriver->iStatus == CNCT_STATUS_CONNECTING || hhDriver->iStatus == CNCT_STATUS_ANSWERING) #else // defined(INCL_CALL_ANSWERING) else if (hhDriver->iStatus == CNCT_STATUS_CONNECTING) #endif // defined(INCL_CALL_ANSWERING) { NotifyClient(hhDriver->hSession, EVENT_LOST_CONNECTION, CNCT_LOSTCARRIER | DISCNCT_NOBEEP); LoadString(glblQueryDllHinst(), IDS_ER_CNCT_PORTFAILED, ach, MAX_PATH); wsprintf(achMsg, ach, hhDriver->achComDeviceName); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), achMsg, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); } } else if (iPortOpen == COM_PORT_OPEN && hhDriver->iStatus != CNCT_STATUS_ANSWERING) { SetStatus(hhDriver, CNCT_STATUS_TRUE); } } #if defined(INCL_CALL_ANSWERING) if (hhDriver->iStatus == CNCT_STATUS_ANSWERING) { // If we are a direct cabled connection, and we are waiting // for a call, connect when we see a carriage return. // WaitForCRinit(hhDriver); } #endif // defined(INCL_CALL_ANSWERING) } } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * DoAnswerCall * * DESCRIPTION: * Sets up TAPI to answer the next data modem call. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0 or error * * AUTHOR: C. Baumgartner, 11/25/96 (ported from HAWin32) */ int DoAnswerCall(const HHDRIVER hhDriver) { TCHAR ach[256]; // Believe it or not, this is all one has to do to setup and // answer a call. Quite a contrast to placing a call. // if (TRAP(lineOpen(hhDriver->hLineApp, hhDriver->dwLine, &hhDriver->hLine, hhDriver->dwAPIVersion, 0, (DWORD_PTR)hhDriver, LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_DATAMODEM, 0)) != 0) { assert(0); LoadString(glblQueryDllHinst(), IDS_ER_CNCT_TAPIFAILED, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)); return -1; } // The the line app priority for compliance with TAPI specifications. // mrw:9/18/96 // LoadString(glblQueryDllHinst(), IDS_GNRL_APPNAME, ach, sizeof(ach) / sizeof(TCHAR)); TRAP(lineSetAppPriority(ach, LINEMEDIAMODE_DATAMODEM, 0, 0, 0, 1)); // Set line notifications we want to receive // TRAP(lineSetStatusMessages(hhDriver->hLine, LINEDEVSTATE_RINGING, 0)); SetStatus(hhDriver, CNCT_STATUS_ANSWERING); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * DoMakeCall * * DESCRIPTION: * Performs the neccessary TAPI rituals to place an outbound call. * * ARGUMENTS: * hhDriver - private driver handle * uFlags - connection flags * * RETURNS: * 0 or error * * AUTHOR: C. Baumgartner, 11/25/96 (ported from cnctdrvConnect) */ int DoMakeCall(const HHDRIVER hhDriver, const unsigned int uFlags) { unsigned int uidErr = 0; int iRet = 0; LINEDEVSTATUS stLnDevStat; TCHAR ach[256]; BOOL msgFlag = FALSE; tapiReinit(hhDriver); // // Set the line settings. // if (cncttapiSetLineConfig(hhDriver->dwLine, sessQueryComHdl(hhDriver->hSession)) != 0) { assert(0); uidErr = IDS_ER_CNCT_TAPIFAILED; iRet = -1; msgFlag = TRUE; goto ERROR_EXIT; } /* --- Open the line, pass driver handle for data reference --- */ if (TRAP(lineOpen(hhDriver->hLineApp, hhDriver->dwLine, &hhDriver->hLine, hhDriver->dwAPIVersion, 0, (DWORD_PTR)hhDriver, LINECALLPRIVILEGE_NONE, 0, 0)) != 0) { assert(0); uidErr = IDS_ER_CNCT_TAPIFAILED; iRet = -1; msgFlag = TRUE; goto ERROR_EXIT; } /* --- Set line notifications we want to receive, mrw,2/28/95 --- */ TRAP(lineSetStatusMessages(hhDriver->hLine, LINEDEVSTATE_INSERVICE | LINEDEVSTATE_OUTOFSERVICE, 0)); /* --- Check if our device is in service, mrw,2/28/95 --- */ stLnDevStat.dwTotalSize = sizeof(stLnDevStat); TRAP(lineGetLineDevStatus(hhDriver->hLine, &stLnDevStat)); if ((stLnDevStat.dwDevStatusFlags & LINEDEVSTATUSFLAGS_INSERVICE) == 0) { if (DialogBoxParam(glblQueryDllHinst(), MAKEINTRESOURCE(IDD_CNCT_PCMCIA), sessQueryHwnd(hhDriver->hSession), PCMCIADlg, (LPARAM)hhDriver) == FALSE) { iRet = -2; goto ERROR_EXIT; } } /* --- Launch the dialing dialog, or go right into passthrough mode. --- */ if ((uFlags & CNCT_PORTONLY) == 0) { if (!IsWindow(hhDriver->hwndCnctDlg)) { hhDriver->hwndCnctDlg = DoModelessDialog(glblQueryDllHinst(), MAKEINTRESOURCE(IDD_DIALING), sessQueryHwnd(hhDriver->hSession), DialingDlg, (LPARAM)hhDriver); } } /* --- Make the call (oooh, how exciting!) --- */ memset(&hhDriver->stCallPar, 0, sizeof(hhDriver->stCallPar)); hhDriver->stCallPar.dwTotalSize = sizeof(hhDriver->stCallPar); hhDriver->stCallPar.dwMediaMode = LINEMEDIAMODE_DATAMODEM; hhDriver->stCallPar.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; if (uFlags & CNCT_PORTONLY) hhDriver->stCallPar.dwBearerMode = LINEBEARERMODE_PASSTHROUGH; if ((hhDriver->lMakeCallId = lineMakeCall(hhDriver->hLine, &hhDriver->hCall, hhDriver->achDialableDest, hhDriver->dwCountryCode, &hhDriver->stCallPar)) < 0) { #if defined(_DEBUG) char ach[50]; wsprintf(ach, "lineMakeCall returned %x", hhDriver->lMakeCallId); MessageBox (0, ach, "debug", MB_OK); #endif switch (hhDriver->lMakeCallId) { case LINEERR_BEARERMODEUNAVAIL: case LINEERR_INVALBEARERMODE: uidErr = IDS_ER_CNCT_PASSTHROUGH; iRet = -6; msgFlag = TRUE; goto ERROR_EXIT; case LINEERR_RESOURCEUNAVAIL: case LINEERR_CALLUNAVAIL: uidErr = IDS_ER_CNCT_CALLUNAVAIL; iRet = -3; msgFlag = TRUE; goto ERROR_EXIT; case LINEERR_DIALDIALTONE: case LINEERR_DIALPROMPT: if (DoDelayedCall(hhDriver) != 0) { iRet = -4; msgFlag = TRUE; goto ERROR_EXIT; } break; default: iRet = -5; msgFlag = TRUE; goto ERROR_EXIT; } } SetStatus(hhDriver, CNCT_STATUS_CONNECTING); return 0; /* --- Error exit --- */ ERROR_EXIT: // Change this so that the dialog is destroyed before the // error message is displayed. Otherwise, the timer that // handled redials continued to pump a redial message once // every second, causing HT to go into a very nasty loop. mpt 02SEP98 if (IsWindow(hhDriver->hwndCnctDlg)) { EndModelessDialog(hhDriver->hwndCnctDlg); hhDriver->hwndCnctDlg = 0; } if ( msgFlag ) { LoadString(glblQueryDllHinst(), uidErr, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)); } return iRet; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvConnect * * DESCRIPTION: * Attempts to dial the modem. * * ARGUMENTS: * hhDriver - private driver handle * uFlags - connection flags * * RETURNS: * 0 or error * */ int WINAPI cnctdrvConnect(const HHDRIVER hhDriver, const unsigned int uFlags) { TCHAR ach[FNAME_LEN]; #if defined(INCL_WINSOCK) // // MAX_IP_ADDR_LEN+11+1 = buffer size of hhDriver->achDestAddr + // settings string "SET IPADDR=" + 1 for the terminating NULL // character. REV 09/20/2000 // TCHAR szInstruct[MAX_IP_ADDR_LEN+11+1]; // Used only for WinSock TCHAR szResult[MAX_IP_ADDR_LEN+11+1]; // Used only for WinSock int iNumChars; #endif //defined (INCL_WINSOCK) TCHAR achNewCnct[FNAME_LEN]; TCHAR achCom[MAX_PATH]; BOOL fGetNewName = FALSE; HICON hIcon; HCOM hCom; int hIconId; int fFlag; unsigned int uidErr = IDS_ER_CNCT_TAPIFAILED; if (hhDriver == 0) { assert(FALSE); return CNCT_BAD_HANDLE; } /* --- Makes for easier referencing --- */ hCom = sessQueryComHdl(hhDriver->hSession); /* --- Check to see we're not already connected --- */ if (cnctdrvQueryStatus(hhDriver) != CNCT_STATUS_FALSE) return CNCT_ERROR; // JMH 05-29-96 This is needed to prevent CLoop from processing // activity on the terminal window while TAPI is connecting. // CLoopRcvControl(sessQueryCLoopHdl(hhDriver->hSession), CLOOP_SUSPEND, CLOOP_RB_CNCTDRV); CLoopSndControl(sessQueryCLoopHdl(hhDriver->hSession), CLOOP_SUSPEND, CLOOP_SB_CNCTDRV); /* --- Just on the off chance we still have an open line --- */ if (hhDriver->hLineApp && hhDriver->hLine) { lineClose(hhDriver->hLine); memset(&hhDriver->stCallPar, 0, sizeof(hhDriver->stCallPar)); hhDriver->stCallPar.dwTotalSize = sizeof(hhDriver->stCallPar); hhDriver->stCallPar.dwMediaMode = LINEMEDIAMODE_DATAMODEM; hhDriver->stCallPar.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; hhDriver->stCallPar.dwBearerMode = 0; hhDriver->hLine = 0; } if (hhDriver->hLineApp && hhDriver->dwLineCnt == 0 && (uFlags & CNCT_PORTONLY) == 0) { DoNewModemWizard(sessQueryHwnd(hhDriver->hSession), sessQueryTimeout(hhDriver->hSession)); } /* --- Ask for new session name only if needed --- */ sessQueryName(hhDriver->hSession, ach, sizeof(ach)); achNewCnct[0] = TEXT('\0'); LoadString(glblQueryDllHinst(), IDS_GNRL_NEW_CNCT, achNewCnct, sizeof(achNewCnct) / sizeof(TCHAR)); if (ach[0] == TEXT('\0') || lstrcmp(achNewCnct, ach) == 0) { // This can only happen if the user double-clicks on the term.exe or // there is no session name given on the command line. // In this case give the "New Connection" name to the session. // sessSetName(hhDriver->hSession, achNewCnct); if (!(uFlags & CNCT_PORTONLY)) fGetNewName = TRUE; } else if (uFlags & CNCT_NEW) { // This can only happen if the user selects 'File | New Connection' // from the menus. // sessSetName(hhDriver->hSession, achNewCnct); sessSetIsNewSession(hhDriver->hSession, TRUE); } #if defined (INCL_WINSOCK) else if (uFlags & CNCT_WINSOCK) { // // Make sure we don't overwrite the buffer. If the string // is too long, then truncate to the hhDriver->achDestAddr // size of MAX_AP_ADDR_LEN. REV 09/20/2000 // StrCharCopyN(hhDriver->achDestAddr, ach, MAX_IP_ADDR_LEN); hhDriver->achDestAddr[MAX_IP_ADDR_LEN - 1] = TEXT('\0'); hhDriver->dwPermanentLineId = DIRECT_COMWINSOCK; } #endif // defined (INCL_WINSOCK) if (fGetNewName || (uFlags & CNCT_NEW)) { if (DialogBoxParam(glblQueryDllHinst(), MAKEINTRESOURCE(IDD_NEWCONNECTION), sessQueryHwnd(hhDriver->hSession), NewConnectionDlg, (LPARAM)hhDriver->hSession) == FALSE) { if (uFlags & CNCT_NEW) { sessQueryOldName(hhDriver->hSession, ach, sizeof(ach)); sessSetName(hhDriver->hSession, ach); sessSetIsNewSession(hhDriver->hSession, FALSE); } goto ERROR_EXIT; } else { if (uFlags & CNCT_NEW) { sessQueryName(hhDriver->hSession, ach, sizeof(ach)); hIcon = sessQueryIcon(hhDriver->hSession); hIconId = sessQueryIconID(hhDriver->hSession); ReinitializeSessionHandle(hhDriver->hSession, FALSE); CLoopSndControl(sessQueryCLoopHdl(hhDriver->hSession), CLOOP_SUSPEND, CLOOP_SB_CNCTDRV); sessSetName(hhDriver->hSession, ach); sessSetIconID(hhDriver->hSession, hIconId); } } } /* --- Load the Standard Com drivers --- */ ComLoadStdcomDriver(hCom); // There are a bunch of conditions that can trigger the // phone dialog. // fFlag = FALSE; // If no phone number, bring up new phone dialog here // Unless we have a direct to com port selected // // Don't display the dialog if we are answering, because // we don't need a phone number. - cab:11/19/96 // if (!IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4) && hhDriver->dwPermanentLineId != DIRECT_COM_DEVICE && !(uFlags & (CNCT_PORTONLY | CNCT_ANSWER))) { #ifdef INCL_WINSOCK // If the driver is WinSock, then check for a // destination IP address. - cab:11/19/96 // if (hhDriver->dwPermanentLineId == DIRECT_COMWINSOCK && hhDriver->achDestAddr[0] == TEXT('\0')) { fFlag = TRUE; } #endif // defined (INCL_WINSOCK) // If the driver isn't WinSock, then we must be using // TAPI, so check for a destination phone number. - cab:11/19/96 // if (hhDriver->dwPermanentLineId != DIRECT_COMWINSOCK && (hhDriver->achDest[0] == TEXT('\0') || hhDriver->achDialableDest[0] == TEXT('\0') || hhDriver->achCanonicalDest[0] == TEXT('\0'))) { fFlag = TRUE; } } // New connections trigger this dialog // if (uFlags & CNCT_NEW) fFlag = TRUE; // If the modem/port we saved no longer exists // //if (!hhDriver->fMatchedPermanentLineID) // fFlag = TRUE; // Note: Passing the property sheet page here because property // sheets use same code and don't have access directly // to the private driver handle. Upper wacker will have // to address the problem differently - mrw. if (fFlag) { PROPSHEETPAGE psp; // Before you go and critize this goto target come talk to // me. There are enough things going on here that a goto // is warranted in my humble opinion. - mrw NEWPHONEDLG: psp.lParam = (LPARAM)hhDriver->hSession; if (DialogBoxParam(glblQueryDllHinst(), MAKEINTRESOURCE(IDD_CNCT_NEWPHONE), sessQueryHwnd(hhDriver->hSession), NewPhoneDlg, (LPARAM)&psp) == FALSE) { goto ERROR_EXIT; } else if (IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4) || (IsNT() && hhDriver->dwPermanentLineId == DIRECT_COM_DEVICE)) { // // See if the "Configure..." button has already been clicked // and the ComDeviceDialog() function has already been called // for this COM device. // TCHAR szPortName[MAX_PATH]; ComGetPortName(hCom, szPortName, MAX_PATH); if (StrCharCmp(szPortName, hhDriver->achComDeviceName) != 0 ) { /* --- Bring up the port configure dialog --- */ if (hhDriver->dwPermanentLineId == DIRECT_COM_DEVICE) { ComSetPortName(hCom, hhDriver->achComDeviceName); } else { wsprintf(ach, TEXT("COM%d"), hhDriver->dwPermanentLineId - DIRECT_COM1 + 1); ComSetPortName(hCom, ach); } // // Get the current defaults for the serial port. // if (ComDriverSpecial(hCom, "GET Defaults", NULL, 0) != COM_OK) { if (ComDeviceDialog(hCom, sessQueryHwnd(hhDriver->hSession)) != COM_OK) { goto ERROR_EXIT; } } if (ComDeviceDialog(hCom, sessQueryHwnd(hhDriver->hSession)) != COM_OK) { // User canceled // --jcm 3-2-95 //return CNCT_BAD_HANDLE; } } } #if defined(INCL_WINSOCK) // mrw:3/5/96 else if (hhDriver->dwPermanentLineId == DIRECT_COMWINSOCK) { if (hhDriver->achDestAddr[0] == TEXT('\0')) { LoadString(glblQueryDllHinst(), IDS_ER_TCPIP_MISSING_ADDR, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); goto NEWPHONEDLG; } } #endif else { // mrw: Check that we have valid data. // if (hhDriver->achDest[0] == TEXT('\0')) { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_BADADDRESS, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); // goto ERROR_EXIT; // mrw:3/5/96 goto NEWPHONEDLG; // mrw:3/5/96 } } } /* --- Enumerate lines, picks default (set in hhDriver->dwLine) --- */ if ( IsNT() ) { if (EnumerateLinesNT(hhDriver, 0) != 0) { assert(FALSE); goto MSG_EXIT; } } else { if (EnumerateLines(hhDriver, 0) != 0) { assert(FALSE); goto MSG_EXIT; } } /* --- If we don't match any TAPI lines, go back to new phone --- */ if (hhDriver->dwLine == (DWORD)-1) { // // If this is not a modem (it is a COM port), then display the modem // wizard, otherwise just go back to the new phone. REV: 11/1/2001 // if (!IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4) && hhDriver->dwPermanentLineId != DIRECT_COM_DEVICE ) { DoNewModemWizard(sessQueryHwnd(hhDriver->hSession), sessQueryTimeout(hhDriver->hSession)); } goto NEWPHONEDLG; } /* --- Redraw window now so dialogs don't overlap ---- */ UpdateWindow(sessQueryHwnd(hhDriver->hSession)); /* --- Check if we're doing a direct connect or using passthrough mode --- */ if (IsNT() && hhDriver->dwPermanentLineId == DIRECT_COM_DEVICE) { int iActivatePortReturn = IDS_ER_CNCT_PORTFAILED; if (TRAP(ComSetPortName(hCom, hhDriver->achComDeviceName)) != COM_OK || (iActivatePortReturn = TRAP(ComActivatePort(hCom, 0))) != COM_OK) { if (iActivatePortReturn == COM_PORT_IN_USE) { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_CALLUNAVAIL, ach, sizeof(ach) / sizeof(TCHAR)); } else { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_PORTFAILED, achNewCnct, sizeof(achNewCnct) / sizeof(TCHAR)); wsprintf(ach, achNewCnct, hhDriver->achComDeviceName); } TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); return -1; } else { if (uFlags & CNCT_ANSWER) { SetStatus(hhDriver, CNCT_STATUS_ANSWERING); } else { SetStatus(hhDriver, CNCT_STATUS_CONNECTING); } } // // Allow PASSTHROUGH on serial ports as well so that the session // will not be disconnected with loss of carrier. REV: 11/6/2001 // if (uFlags & CNCT_PORTONLY) { hhDriver->stCallPar.dwBearerMode = LINEBEARERMODE_PASSTHROUGH; } cnctdrvComEvent(hhDriver, CONNECT); return COM_OK; } else if (IN_RANGE(hhDriver->dwPermanentLineId, DIRECT_COM1, DIRECT_COM4)) { int iActivatePortReturn = IDS_ER_CNCT_PORTFAILED; wsprintf(achCom, TEXT("COM%d"), hhDriver->dwPermanentLineId - DIRECT_COM1 + 1); if (TRAP(ComSetPortName(hCom, achCom)) != COM_OK || (iActivatePortReturn = TRAP(ComActivatePort(hCom, 0))) != COM_OK) { if (iActivatePortReturn == COM_PORT_IN_USE) { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_CALLUNAVAIL, ach, sizeof(ach) / sizeof(TCHAR)); } else { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_PORTFAILED, achNewCnct, sizeof(achNewCnct) / sizeof(TCHAR)); wsprintf(ach, achNewCnct, achCom); } TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); return -1; } else { if (uFlags & CNCT_ANSWER) { SetStatus(hhDriver, CNCT_STATUS_ANSWERING); } else { SetStatus(hhDriver, CNCT_STATUS_CONNECTING); } } // // Allow PASSTHROUGH on serial ports as well so that the session // will not be disconnected with loss of carrier. REV: 11/6/2001 // if (uFlags & CNCT_PORTONLY) { hhDriver->stCallPar.dwBearerMode = LINEBEARERMODE_PASSTHROUGH; } cnctdrvComEvent(hhDriver, CONNECT); return COM_OK; } #if defined(INCL_WINSOCK) else if (hhDriver->dwPermanentLineId == DIRECT_COMWINSOCK) { int iPort; /* --- Load the Winsock Com drivers --- */ ComLoadWinsockDriver(hCom); // Baud rate, etc. are meaningless for TCP/IP connections // ComSetAutoDetect(hCom, FALSE); iPort = sessQueryTelnetPort(hhDriver->hSession); if (iPort != 0) hhDriver->iPort = iPort; PostMessage(sessQueryHwndStatusbar(hhDriver->hSession), SBR_NTFY_REFRESH, (WPARAM)SBR_COM_PART_NO, 0); #if 0 //DEADWOOD:jmh 3/24/97 Yes, we really want auto-detection, even in telnet! // Auto-detection of emulator type is redundant, since we tell // the telnet host what type we want. Seems like ANSI is the // most likely choice. hEmu = sessQueryEmuHdl(hhDriver->hSession); if (emuQueryEmulatorId(hEmu) == EMU_AUTO) { emuLoad(hEmu, EMU_VT100); #if defined(INCL_USER_DEFINED_BACKSPACE_AND_TELNET_TERMINAL_ID) // Make sure the telnet terminal id is correct. - cab:11/18/96 // emuLoadDefaultTelnetId(hEmu); #endif // defined(INCL_USER_DEFINED_BACKSPACE_AND_TELNET_TERMINAL_ID) PostMessage(sessQueryHwndStatusbar(hhDriver->hSession), SBR_NTFY_REFRESH, (WPARAM)SBR_EMU_PART_NO, 0); } #endif // 0 #if defined(INCL_CALL_ANSWERING) if (uFlags & CNCT_ANSWER) { wsprintf(szInstruct, "SET ANSWER=1"); } else { wsprintf(szInstruct, "SET ANSWER=0"); } ComDriverSpecial(hCom, szInstruct, szResult, sizeof(szResult) / sizeof(TCHAR)); #endif // defined(INCL_CALL_ANSWERING) /* --- Do ComDriverSpecial calls to send the IP address & port number to the comm driver */ // // Make sure we don't overwrite the buffer. If the string // is too long, then truncate to the hhDriver->achDestAddr // size of MAX_AP_ADDR_LEN. REV 09/20/2000 // StrCharCopyN(szInstruct, TEXT("SET IPADDR="), sizeof(szInstruct) / sizeof(TCHAR)); iNumChars = StrCharGetStrLength(szInstruct); StrCharCopyN(&szInstruct[iNumChars], hhDriver->achDestAddr, sizeof(szInstruct)/sizeof(TCHAR) - iNumChars); // // Make sure the string is null terminated. // szInstruct[sizeof(szInstruct)/sizeof(TCHAR) - 1]=TEXT('\0'); ComDriverSpecial(hCom, szInstruct, szResult, sizeof(szResult) / sizeof(TCHAR)); wsprintf(szInstruct, "SET PORTNUM=%ld", hhDriver->iPort); ComDriverSpecial(hCom, szInstruct, szResult, sizeof(szResult) / sizeof(TCHAR)); #if defined(INCL_CALL_ANSWERING) if (uFlags & CNCT_ANSWER) { SetStatus(hhDriver, CNCT_STATUS_ANSWERING); } else { SetStatus(hhDriver, CNCT_STATUS_CONNECTING); } #else // defined(INCL_CALL_ANSWERING) SetStatus(hhDriver, CNCT_STATUS_CONNECTING); #endif // defined(INCL_CALL_ANSWERING) /* --- Activate the port ---*/ if (ComActivatePort(hCom, 0) != COM_OK) { LoadString(glblQueryDllHinst(), IDS_ER_TCPIP_FAILURE, achNewCnct, sizeof(achNewCnct) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION, sessQueryTimeout(hhDriver->hSession)); return -1; } else { return COM_OK; } } #endif // defined(INCL_WINSOCK) /* --- Display confimation dialog if requested --- */ if ((uFlags & (CNCT_PORTONLY | CNCT_DIALNOW | CNCT_ANSWER)) == 0) { if (DialogBoxParam(glblQueryDllHinst(), MAKEINTRESOURCE(IDD_CNCT_CONFIRM), sessQueryHwnd(hhDriver->hSession), ConfirmDlg, (LPARAM)hhDriver) == FALSE) { goto ERROR_EXIT; } } // Either make the call or wait for a call. // if (uFlags & CNCT_ANSWER) { if (DoAnswerCall(hhDriver) != 0) { goto ERROR_EXIT; } } else { if (DoMakeCall(hhDriver, uFlags) != 0) { goto ERROR_EXIT; } } ComSetAutoDetect(hCom, FALSE); PostMessage(sessQueryHwndStatusbar(hhDriver->hSession), SBR_NTFY_REFRESH, (WPARAM)SBR_COM_PART_NO, 0); return 0; /* --- Message exit --- */ MSG_EXIT: LoadString(glblQueryDllHinst(), uidErr, ach, sizeof(ach) / sizeof(TCHAR)); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)); /* --- Error exit --- */ ERROR_EXIT: if (hhDriver->hLineApp && hhDriver->hLine) { lineClose(hhDriver->hLine); memset(&hhDriver->stCallPar, 0, sizeof(hhDriver->stCallPar)); hhDriver->stCallPar.dwTotalSize = sizeof(hhDriver->stCallPar); hhDriver->stCallPar.dwMediaMode = LINEMEDIAMODE_DATAMODEM; hhDriver->stCallPar.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; hhDriver->stCallPar.dwBearerMode = 0; hhDriver->hLine = 0; } SetStatus(hhDriver, CNCT_STATUS_FALSE); return CNCT_ERROR; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * DoDelayedCall * * DESCRIPTION: * Check the section under Delayed Dialing in the programmers guide to * TAPI. Basicly, if the service provider does not provide dialtone * support, then we have to break of the dialable string format into * pieces and prompt the user. * * ARGUMENTS: * hhDriver - private driver handle. * * RETURNS: * 0=OK, else error. * * AUTHOR: Mike Ward, 20-Apr-1995 */ static int DoDelayedCall(const HHDRIVER hhDriver) { TCHAR ach[256]; TCHAR ach2[256]; TCHAR *pach; long lDialRet; #define DIAL_DELIMITERS "Ww@$?" hhDriver->lMakeCallId = -1; lstrcpy(ach, hhDriver->achDialableDest); if ((pach = strtok(ach, DIAL_DELIMITERS)) == 0) return -1; while (pach) { lstrcpy(ach2, pach); // If this is the last segment of the string, don't append the // semicolon. // if ((pach = strtok(NULL, DIAL_DELIMITERS)) != 0) lstrcat(ach2, ";"); if (hhDriver->lMakeCallId < 0) { // By appending a semicolon to the dialable string, we're // telling lineMakeCall that more is on the way. // if ((hhDriver->lMakeCallId = lineMakeCall(hhDriver->hLine, &hhDriver->hCall, ach2, hhDriver->dwCountryCode, &hhDriver->stCallPar)) < 0) { #if defined(_DEBUG) char ach[50]; wsprintf(ach, "DoDelayedCall returned %x", hhDriver->lMakeCallId); MessageBox(GetFocus(), ach, "debug", MB_OK); #endif return -3; } } else { // Once we have a call handle we have to use lineDial to complete // the call. // if ((lDialRet = lineDial(hhDriver->hCall, ach2, hhDriver->dwCountryCode)) < 0) { #if defined(_DEBUG) char ach[50]; wsprintf(ach, "lineDial returned %x", lDialRet); MessageBox(GetFocus(), ach, "debug", MB_OK); #endif return -4; } } // The user has to tell us when the we can continue dialing // if (pach != 0) { LoadString(glblQueryDllHinst(), IDS_CNCT_DELAYEDDIAL, ach2, sizeof(ach2) / sizeof(TCHAR)); if (TimedMessageBox(hhDriver->hwndCnctDlg, ach2, NULL, MB_OKCANCEL | MB_ICONINFORMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)) != IDOK) { return -4; } } } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvDisconnect * * DESCRIPTION: * Signals a disconnect * * ARGUMENTS: * hhDriver - private driver handle * uFlags - disconnect flags * * RETURNS: * 0 or error * */ int WINAPI cnctdrvDisconnect(const HHDRIVER hhDriver, const unsigned int uFlags) { LONG lLineDropId; #if defined(INCL_REDIAL_ON_BUSY) HKEY hKey; DWORD dwSize; BYTE ab[20]; #endif XD_TYPE* pX; int nReturnVal = 0; TCHAR ach[256]; if (hhDriver == 0) { assert(FALSE); return CNCT_BAD_HANDLE; } // // Cancel any active file transfers that are currently executing. // REV: 02/01/2001 // pX = (XD_TYPE*)sessQueryXferHdl(hhDriver->hSession); if (pX != NULL && pX->hwndXfrDisplay != NULL && IsWindow(pX->hwndXfrDisplay) && pX->nDirection != XFER_NONE) { int nCancelTransfer = IDYES; if (uFlags & CNCT_XFERABORTCONFIRM) { // // Prompt to cancel the file transfer. REV: 02/16/2001 // LoadString(glblQueryDllHinst(), IDS_ER_CNCT_ACTIVETRANSFER, ach, sizeof(ach) / sizeof(TCHAR)); nCancelTransfer = TimedMessageBox(pX->hwndXfrDisplay, ach, NULL, MB_YESNO | MB_ICONEXCLAMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)); } if (nCancelTransfer == IDYES || nCancelTransfer == -1) { unsigned int uNewFlags = uFlags; if (uFlags & CNCT_LOSTCARRIER) { // // NOTE: We should only have to tell the XFER to abort here. // It should not be dependent on a message to a dialog. // PostMessage(pX->hwndXfrDisplay, WM_COMMAND, XFER_LOST_CARRIER, 0L); } else if (uFlags & CNCT_XFERABORTCONFIRM) { // // NOTE: We should only have to tell the XFER to abort here. // It should not be dependent on a message to a dialog. // PostMessage(pX->hwndXfrDisplay, WM_COMMAND, XFR_SHUTDOWN, 0L); } // // We can't exit until the file transfer exits, so post a // message to try to disconnect again. Make sure to turn // of the CNCT_XFERABORTCONFIRM flag as we don't want to // prompt the kill the transfer again. // uNewFlags &= ~CNCT_XFERABORTCONFIRM; // // We must post a message to disconnect because we are // waiting for the file transfer to cancel. We have to // post a message otherwise we will get into a deadlock // situation. This is not the best way to accomplish // this as we may be posting a lot of messages to the // session window and there is a potential for the // file transfer to not respond quickly causing the // disconnect to loop. Eventually, the file transfer // will cancel, or will timeout and cancel, so we will // not get into an endless loop. REV: 06/22/2001 // // // Wait half a second before posting this message so we don't // flood ourselves with disconnect messages. REV: 4/25/2002 // Sleep(500); PostDisconnect(hhDriver, uNewFlags); } // // Return an status that the current file transfer must be // canceled (or is in the process of being canceled). We // cannot disconnect until the transfer is complete. // return XFR_SHUTDOWN; } #ifdef INCL_CALL_ANSWERING // Unregister our cloop callback. // if (hhDriver->pvUnregister) { CLoopUnregisterRmtInputChain(hhDriver->pvUnregister); hhDriver->pvUnregister = 0; } #endif ComDeactivatePort(sessQueryComHdl(hhDriver->hSession)); if (hhDriver->hCall) { SetStatus(hhDriver, CNCT_STATUS_DISCONNECTING); if ((lLineDropId = lineDrop(hhDriver->hCall, 0, 0)) < 0) assert(FALSE); hhDriver->hCall = 0; // If the drop is completing asychronously, save the flags and // wait for the call status to go idle. // if (lLineDropId > 0) { hhDriver->uDiscnctFlags = uFlags; return 0; } } SetStatus(hhDriver, CNCT_STATUS_FALSE); if ((uFlags & DISCNCT_NOBEEP) == 0) sessBeeper(hhDriver->hSession); //mpt:10-28-97 added exit upon disconnect feature if ((uFlags & DISCNCT_EXIT)) PostMessage(sessQueryHwnd(hhDriver->hSession), WM_CLOSE, 0, 0); if (hhDriver->hLine) { lineClose(hhDriver->hLine); memset(&hhDriver->stCallPar, 0, sizeof(hhDriver->stCallPar)); hhDriver->stCallPar.dwTotalSize = sizeof(hhDriver->stCallPar); hhDriver->stCallPar.dwMediaMode = LINEMEDIAMODE_DATAMODEM; hhDriver->stCallPar.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE; hhDriver->stCallPar.dwBearerMode = 0; hhDriver->hLine = 0; } if (uFlags & CNCT_DIALNOW) { #if defined(INCL_REDIAL_ON_BUSY) if (hhDriver->fRedialOnBusy && hhDriver->iRedialCnt > 0) { hhDriver->uDiscnctFlags = uFlags; hhDriver->iRedialSecsRemaining = 2; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\HyperTerminal\\TimeToRedial", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(ab); if (RegQueryValueEx(hKey, "", 0, 0, ab, &dwSize) == ERROR_SUCCESS) hhDriver->iRedialSecsRemaining = atoi(ab); RegCloseKey(hKey); } SetTimer(hhDriver->hwndCnctDlg, 1, 1000, 0); } else { PostMessage(sessQueryHwnd(hhDriver->hSession), WM_CNCT_DIALNOW, uFlags, 0); } #else PostMessage(sessQueryHwnd(hhDriver->hSession), WM_CNCT_DIALNOW, uFlags, 0); #endif } else { // If we're not auto redialing, reset the dial count. - mrw:10/10/95 // hhDriver->iRedialCnt = 0; } return nReturnVal; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * lineCallbackFunc * * DESCRIPTION: * Function TAPI calls to handle asynchronous events * * ARGUMENTS: * see TAPI.H * * RETURNS: * void * */ void CALLBACK lineCallbackFunc(DWORD hDevice, DWORD dwMsg, DWORD_PTR dwCallback, DWORD_PTR dwParm1, DWORD_PTR dwParm2, DWORD_PTR dwParm3) { const HHDRIVER hhDriver = (HHDRIVER)dwCallback; int id; unsigned int uFlags; #if 0 { char ach[256]; wsprintf(ach,"%x %x", dwMsg, dwParm1); MessageBox(NULL, ach, "debug", MB_OK); } #endif switch (dwMsg) { case LINE_REPLY: if ((LONG)dwParm1 == hhDriver->lMakeCallId) { hhDriver->lMakeCallId = 0; if ((LONG)dwParm2 != 0) // zero indicates success { switch (dwParm2) { case LINEERR_CALLUNAVAIL: id = IDS_DIAL_NODIALTONE; break; default: id = IDS_DIAL_DISCONNECTED; break; } cnctdrvDisconnect(hhDriver, 0); DialingMessage(hhDriver, id); } } break; case LINE_LINEDEVSTATE: DbgOutStr("LINEDEVSTATE_DISCONNECTED 0x%x\r\n", dwParm1, 0, 0, 0, 0); switch (dwParm1) { case PHONESTATE_CAPSCHANGE: // // If we are currently disconnected, then reset. // if (hhDriver != NULL && hhDriver->iStatus != CNCT_STATUS_FALSE) break; case LINEDEVSTATE_REINIT: case PHONESTATE_REINIT: if (hhDriver == 0) { // Until we open a line, we don't have a driver handle // since we can't pass one during lineInitialize(). // This turns out to be a good time to reinit if we get // notified to do so however, so it has use. // if (tapiReinit(gbl_hhDriver) != 0) tapiReinitMessage(gbl_hhDriver); } else { tapiReinitMessage(hhDriver); } break; case LINEDEVSTATE_INSERVICE: // If we are showing our PCMCIA dialog prompting the user // to insert the card, we post a message to dismiss the // dialog once they insert it. - mrw,2/28/95 // if (IsWindow(hhDriver->hwndPCMCIA)) { PostMessage(hhDriver->hwndPCMCIA, WM_COMMAND, MAKEWPARAM(IDOK, 0), (LPARAM)hhDriver->hwndPCMCIA); } break; case LINEDEVSTATE_OUTOFSERVICE: // Means they yanked the PCMCIA card - mrw,2/28/95 // cnctdrvDisconnect(hhDriver, 0); break; case LINEDEVSTATE_RINGING: // When the current ring count (as told by dwParam3) equals // or exceeds the rings to answer on then we'll do the answer // using the hhdriver->hCall handle we cached during the // LINECALLSTATE_BURNTOFFERING notification. - rjk. 07-31-96 // if ((hhDriver->lMakeCallId = lineAnswer(hhDriver->hCall,0,0)) >= 0) { SetStatus(hhDriver, CNCT_STATUS_CONNECTING); } break; case LINEDEVSTATE_CLOSE: case PHONESTATE_DISCONNECTED: // // Another application has disconnected this device. REV: 04/27/2001 // uFlags = CNCT_DIALNOW | CNCT_NOCONFIRM; id = IDS_DIAL_DISCONNECTED; PostDisconnect(hhDriver, uFlags); DialingMessage(hhDriver, id); break; default: break; } break; // case LINE_LINEDEVSTATE case LINE_CREATE: // Sent when new modem is added assert(0); // So I know it happened // A remote possibilility exists that if two modems were created // back to back, that the LINE_CREATE's would come out of order. // T. Nixon suggests that we bump the line count by the dwParm1 // parameter plus one only when it is greater than or equal to // the current line count. - mrw // if (dwParm1 >= gbl_hhDriver->dwLineCnt) gbl_hhDriver->dwLineCnt = (DWORD)(dwParm1 + 1); break; case LINE_CALLSTATE: DbgOutStr("LINECALLSTATE 0x%x\r\n", dwParm1, 0, 0, 0, 0); switch ((LONG)dwParm1) { case LINECALLSTATE_OFFERING: DialingMessage(hhDriver, IDS_DIAL_OFFERING); // Windows sends us this message only one time while receiving // a call and that is on the very first ring. See the code // that responds to the LINEDEVSTATE_RINGING to see how the call // gets answered. - rjk. 07-31-96 // hhDriver->hCall = (HCALL)hDevice; break; case LINECALLSTATE_DIALTONE: DialingMessage(hhDriver, IDS_DIAL_DIALTONE); break; case LINECALLSTATE_DIALING: DialingMessage(hhDriver, IDS_DIAL_DIALING); break; case LINECALLSTATE_RINGBACK: DialingMessage(hhDriver, IDS_DIAL_RINGBACK); break; case LINECALLSTATE_BUSY: DialingMessage(hhDriver, IDS_DIAL_BUSY); EnableDialNow(hhDriver->hwndCnctDlg, TRUE); uFlags = DISCNCT_NOBEEP; #if defined(INCL_REDIAL_ON_BUSY) if (hhDriver->fRedialOnBusy && hhDriver->iRedialCnt++ < REDIAL_MAX) uFlags = CNCT_DIALNOW | CNCT_NOCONFIRM | DISCNCT_NOBEEP; #endif PostDisconnect(hhDriver, uFlags); break; case LINECALLSTATE_CONNECTED: DialingMessage(hhDriver, IDS_DIAL_CONNECTED); if (Handoff(hhDriver) != 0) { PostDisconnect(hhDriver, 0); } else { if (IsWindow(hhDriver->hwndCnctDlg)) { // Closes the dialing dialog PostMessage(hhDriver->hwndCnctDlg, WM_USER+0x100, 0, 0); } SetStatus(hhDriver, CNCT_STATUS_TRUE); } break; case LINECALLSTATE_DISCONNECTED: DbgOutStr("LINECALLSTATE_DISCONNECTED 0x%x\r\n", dwParm2, 0, 0, 0, 0); uFlags = 0; if (dwParm2 & LINEDISCONNECTMODE_BUSY) { id = IDS_DIAL_BUSY; #if defined(INCL_REDIAL_ON_BUSY) if (hhDriver->fRedialOnBusy && hhDriver->iRedialCnt++ < REDIAL_MAX) { // Wait to let slower phone systems catchup - mrw 2/29/96 // uFlags |= CNCT_DIALNOW|CNCT_NOCONFIRM|DISCNCT_NOBEEP; } #endif } else if (dwParm2 & LINEDISCONNECTMODE_NOANSWER) id = IDS_DIAL_NOANSWER; else if (dwParm2 & LINEDISCONNECTMODE_NODIALTONE) id = IDS_DIAL_NODIALTONE; else { id = IDS_DIAL_DISCONNECTED; //mpt:10-28-97 added exit upon disconnect feature uFlags |= ( sessQueryExit(hhDriver->hSession) ? DISCNCT_EXIT : 0 ); } PostDisconnect(hhDriver, uFlags); DialingMessage(hhDriver, id); break; case LINECALLSTATE_IDLE: cnctdrvDisconnect(hhDriver, hhDriver->uDiscnctFlags); break; default: break; } default: break; } return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * Handoff * * DESCRIPTION: * Hands TAPI's com handle to the Wacker's com routines. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0=OK * */ int Handoff(const HHDRIVER hhDriver) { LPVARSTRING pVarstr; HANDLE hdl; DWORD dwSize; int i; pVarstr = malloc(sizeof(VARSTRING)); if (pVarstr == 0) { assert(FALSE); return 1; } memset( pVarstr, 0, sizeof(VARSTRING) ); pVarstr->dwTotalSize = sizeof(VARSTRING); if (lineGetID(hhDriver->hLine, hhDriver->dwLine, hhDriver->hCall, LINECALLSELECT_CALL, pVarstr, DEVCLASS) != 0) { assert(FALSE); free(pVarstr); pVarstr = NULL; return 2; } if (pVarstr->dwNeededSize > pVarstr->dwTotalSize) { dwSize = pVarstr->dwNeededSize; free(pVarstr); pVarstr = NULL; pVarstr = malloc(dwSize); if (pVarstr == 0) { assert(FALSE); return 3; } memset( pVarstr, 0, dwSize ); pVarstr->dwTotalSize = dwSize; if (TRAP(lineGetID(hhDriver->hLine, hhDriver->dwLine, hhDriver->hCall, LINECALLSELECT_CALL, pVarstr, DEVCLASS)) != 0) { assert(FALSE); free(pVarstr); pVarstr = NULL; return 4; } } if (pVarstr->dwStringSize == 0) { assert(FALSE); free(pVarstr); pVarstr = NULL; return 5; } hdl = *(HANDLE *)((BYTE *)pVarstr + pVarstr->dwStringOffset); // Set comm buffers to 32K // if (SetupComm(hdl, 32768, 32768) == FALSE) { DWORD dwLastError = GetLastError(); assert(0); } if ((i = ComActivatePort(sessQueryComHdl(hhDriver->hSession), (DWORD_PTR)hdl)) != COM_OK) { #if !defined(NDEBUG) char ach[256]; wsprintf(ach, "hdl=%x, i=%d", hdl, i); MessageBox(NULL, ach, "debug", MB_OK); #endif assert(FALSE); free(pVarstr); pVarstr = NULL; return 6; } if(pVarstr) { free(pVarstr); pVarstr = NULL; } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * PostDisconnect * * DESCRIPTION: * Work around to TAPI bug that does not allow us to call lineShutDown() * from with the TAPI callback * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * void * */ void PostDisconnect(const HHDRIVER hhDriver, const unsigned int uFlags) { PostMessage(sessQueryHwnd(hhDriver->hSession), WM_DISCONNECT, uFlags, 0); return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * tapiReinitMessage * * DESCRIPTION: * Displays a messagebox showing TAPI needs to be reinitialized. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0=OK, <0=error * */ static int tapiReinitMessage(const HHDRIVER hhDriver) { TCHAR ach[512], achTitle[256]; if (hhDriver == 0) { assert(FALSE); return -1; } LoadString(glblQueryDllHinst(), IDS_ER_TAPI_REINIT, ach, sizeof(ach) / sizeof(TCHAR)); LoadString(glblQueryDllHinst(), IDS_ER_TAPI_REINIT2, achTitle, sizeof(achTitle) / sizeof(TCHAR)); lstrcat(ach, achTitle); TimedMessageBox(sessQueryHwnd(hhDriver->hSession), ach, NULL, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL, sessQueryTimeout(hhDriver->hSession)); return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * tapiReinit * * DESCRIPTION: * Attempts to reinit tapi. * * ARGUMENTS: * hhDriver - private driver handle * * RETURNS: * 0=OK,else error * */ static int tapiReinit(const HHDRIVER hhDriver) { int i; LPVARSTRING pvs = 0; DWORD dwSize; const SF_HANDLE sfhdl = sessQuerySysFileHdl(hhDriver->hSession); if (hhDriver == 0) { assert(FALSE); return -1; } if (hhDriver->hLineApp) { /* --- Get current config so we can restore it --- */ if (hhDriver->dwLine != (DWORD)-1) { if ((pvs = malloc(sizeof(VARSTRING))) == 0) { assert(FALSE); goto SHUTDOWN; } memset( pvs, 0, sizeof(VARSTRING) ); pvs->dwTotalSize = sizeof(VARSTRING); if (lineGetDevConfig(hhDriver->dwLine, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; hhDriver->dwLine = (DWORD)-1; goto SHUTDOWN; } if (pvs->dwNeededSize > pvs->dwTotalSize) { dwSize = pvs->dwNeededSize; free(pvs); pvs = NULL; if ((pvs = malloc(dwSize)) == 0) { assert(FALSE); hhDriver->dwLine = (DWORD)-1; goto SHUTDOWN; } memset( pvs, 0, dwSize ); pvs->dwTotalSize = dwSize; if (lineGetDevConfig(hhDriver->dwLine, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; hhDriver->dwLine = (DWORD)-1; goto SHUTDOWN; } } } SHUTDOWN: { LONG lLineShutdown = lineShutdown(hhDriver->hLineApp); if (lLineShutdown == LINEERR_NOMEM) { // // We are in a low memory state, so wait for a while, // then try to shutdown the line again. REV: 5/1/2002 // Sleep(500); lLineShutdown = lineShutdown(hhDriver->hLineApp); } if (lLineShutdown != 0) { assert(FALSE); return -6; } } hhDriver->hLineApp = 0; // Wait for 10 seconds, if nothing happens, return an error // for (i=0 ;; ++i) { if (lineInitialize(&hhDriver->hLineApp, glblQueryDllHinst(), lineCallbackFunc, g_achApp, &hhDriver->dwLineCnt) != 0) { if (i > 10) { assert(0); return -7; } Sleep(1000); // sleep 1 second continue; } break; } } /* --- Ok, we've reintialized, put settings back now --- */ if (pvs) { LPVOID pv = (BYTE *)pvs + pvs->dwStringOffset; if (lineSetDevConfig(hhDriver->dwLine, pv, pvs->dwStringSize, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; return -8; } free(pvs); pvs = NULL; } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * cnctdrvSetDestination * * DESCRIPTION: * Sets the destination (in this case phone number). * * ARGUMENTS: * hhDriver - private driver handle * ach - string to set * cb - number of chars in ach * * RETURNS: * 0=OK, <0=error * */ int WINAPI cnctdrvSetDestination(const HHDRIVER hhDriver, TCHAR * const ach, const size_t cb) { int len; if (hhDriver == 0 || ach == 0 || cb == 0) { assert(FALSE); return -1; } len = (int) min(cb, sizeof(hhDriver->achDest)); strncpy(hhDriver->achDest, ach, len); hhDriver->achDest[len-1]; return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * FUNCTION: * DoNewModemWizard * * DESCRIPTION: * Calls up the new modem wizard * * ARGUMENTS: * hhDriver - private driver handle * iTimeout - The timeout length * * RETURNS: * 0=OK,else error * */ static int DoNewModemWizard(HWND hWnd, int iTimeout) { PROCESS_INFORMATION stPI; STARTUPINFO stSI; TCHAR ach[256]; int returnVal = 0; // Initialize the PROCESS_INFORMATION structure for CreateProcess // memset( &stPI, 0, sizeof( PROCESS_INFORMATION ) ); // Initialize the STARTUPINFO structure for CreateProcess // memset(&stSI, 0, sizeof(stSI)); stSI.cb = sizeof(stSI); stSI.dwFlags = STARTF_USESHOWWINDOW; stSI.wShowWindow = SW_SHOW; // See if we should run the New modem wizard. // if(mscAskWizardQuestionAgain()) { LoadString(glblQueryDllHinst(), IDS_ER_CNCT_BADLINE, ach, sizeof(ach) / sizeof(TCHAR)); if (TimedMessageBox(hWnd, ach, NULL, MB_YESNO | MB_ICONEXCLAMATION, iTimeout) == IDYES) { TCHAR systemDir[MAX_PATH]; TCHAR executeString[MAX_PATH * 3]; TCHAR *pParams = TEXT("\\control.exe\" modem.cpl,,Add"); UINT numChars = 0; TCHAR_Fill(systemDir, TEXT('\0'), MAX_PATH); TCHAR_Fill(executeString, TEXT('\0'), MAX_PATH * 3); numChars = GetSystemDirectory(systemDir, MAX_PATH); if (numChars == 0 || StrCharGetStrLength(systemDir) == 0) { returnVal = -3; } else { if (StrCharGetStrLength(systemDir) + StrCharGetStrLength(pParams) + sizeof(TEXT("\"")) / sizeof(TCHAR) > sizeof(executeString) / sizeof(TCHAR)) { returnVal = -2; } else { StrCharCopyN(executeString, TEXT("\""), sizeof(executeString) / sizeof(TCHAR)); StrCharCat(executeString, systemDir); StrCharCat(executeString, pParams); // // Launch the new modem wizard with the command below. // //if (CreateProcess(0, "rundll sysdm.cpl,InstallDevice_Rundll modem,,", // 0, 0, 0, 0, 0, 0, &stSI, &stPI) == FALSE) //if (CreateProcess(0, "control.exe modem.cpl,,Add", // 0, 0, 0, 0, 0, 0, &stSI, &stPI) == FALSE) if (CreateProcess(NULL, executeString, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, systemDir, &stSI, &stPI) == FALSE) { #if defined(_DEBUG) { char ach[100]; DWORD dw = GetLastError(); wsprintf(ach,"CreateProcess (%s, %d) : %x",__FILE__,__LINE__,dw); MessageBox(NULL, ach, "Debug", MB_OK); } #endif returnVal = -1; } else { mscUpdateRegistryValue(); // // Close the handles. // CloseHandle(stPI.hProcess); CloseHandle(stPI.hThread); } } } } } return returnVal; } int cncttapiGetLineConfig( const DWORD dwLineId, VOID ** ppvs ) { DWORD dwSize; LPVARSTRING pvs = (LPVARSTRING)*ppvs; if (pvs != NULL) { assert(FALSE); free(pvs); pvs = NULL; } if ((pvs = malloc(sizeof(VARSTRING))) == 0) { assert(FALSE); return -3; } memset(pvs, 0, sizeof(VARSTRING)); pvs->dwTotalSize = sizeof(VARSTRING); pvs->dwNeededSize = 0; if (lineGetDevConfig(dwLineId, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; return -4; } if (pvs->dwNeededSize > pvs->dwTotalSize) { dwSize = pvs->dwNeededSize; free(pvs); pvs = NULL; if ((pvs = malloc(dwSize)) == 0) { assert(FALSE); return -5; } memset(pvs, 0, dwSize); pvs->dwTotalSize = dwSize; if (lineGetDevConfig(dwLineId, pvs, DEVCLASS) != 0) { assert(FALSE); free(pvs); pvs = NULL; return -6; } } *ppvs = (VOID *)pvs; return 0; } int cncttapiSetLineConfig(const DWORD dwLineId, const HCOM hCom) { int retValue = 0; LPVARSTRING pvs = NULL; PUMDEVCFG pDevCfg = NULL; int iBaudRate; int iDataBits; int iParity; int iStopBits; LONG lLineReturn; retValue = cncttapiGetLineConfig( dwLineId, (VOID **) &pvs); if (retValue != 0) { retValue = retValue; } if (retValue == 0 && pvs == NULL) { retValue = -7; } // The structure of the DevConfig block is as follows // // VARSTRING // UMDEVCFGHDR // COMMCONFIG // MODEMSETTINGS // // The UMDEVCFG structure used below is defined in the // UNIMODEM.H provided in the platform SDK (in the nih // directory for HTPE). REV: 12/01/2000 // if (retValue == 0) { pDevCfg = (UMDEVCFG *)((BYTE *)pvs + pvs->dwStringOffset); if (pDevCfg == NULL) { retValue = -8; } } if (retValue == 0 && (hCom == NULL || ComValidHandle(hCom) == FALSE)) { retValue = -9; } // // commconfig struct has a DCB structure we dereference for the // com settings. // // // The baud rate should be stored with the COM settings for // TAPI devices, but we may want to use the current TAPI device // baud rate instead. We should find a better solution for this. // TODO:REV 05/01/2001 // if (retValue == 0 && ComGetBaud(hCom, &iBaudRate) != COM_OK) { #if defined(TODO) retValue = -10; #endif // TODO } else if (retValue == 0) { ComSetBaud(hCom, pDevCfg->commconfig.dcb.BaudRate); } if (retValue == 0 && ComGetDataBits(hCom, &iDataBits) != COM_OK) { retValue = -11; } if (retValue == 0 && ComGetParity(hCom, &iParity) != COM_OK) { retValue = -12; } if (retValue == 0 && ComGetStopBits(hCom, &iStopBits) != COM_OK) { retValue = -13; } if (retValue != 0) { free(pvs); pvs = NULL; return retValue; } #if defined(TODO) pDevCfg->commconfig.dcb.BaudRate = iBaudRate; #endif // TODO pDevCfg->commconfig.dcb.ByteSize = (BYTE)iDataBits; pDevCfg->commconfig.dcb.Parity = (BYTE)iParity; pDevCfg->commconfig.dcb.StopBits = (BYTE)iStopBits; if (iDataBits != 8 && iParity != NOPARITY && iStopBits != ONESTOPBIT) { ComSetAutoDetect(hCom, FALSE); } // // Actually set the TAPI device's COM settings. // lLineReturn = lineSetDevConfig(dwLineId, pDevCfg, pvs->dwStringSize, DEVCLASS); free(pvs); pvs = NULL; if (lLineReturn < 0) { assert(FALSE); return lLineReturn; } retValue = cncttapiGetLineConfig( dwLineId, (VOID **) &pvs); if (retValue != 0) { retValue = retValue - 100; } // // Make sure the port settings get updated. // retValue = ComConfigurePort(hCom); // // Make sure the status bar contains the correct settings. // PostMessage(sessQueryHwndStatusbar(hCom->hSession), SBR_NTFY_REFRESH, (WPARAM)SBR_COM_PART_NO, 0); if (pvs == NULL) { return -14; } // The structure of the DevConfig block is as follows // // VARSTRING // UMDEVCFGHDR // COMMCONFIG // MODEMSETTINGS // // The UMDEVCFG structure used below is defined in the // UNIMODEM.H provided in the platform SDK (in the nih // directory for HTPE). REV: 12/01/2000 // if (retValue == 0) { pDevCfg = (UMDEVCFG *)((BYTE *)pvs + pvs->dwStringOffset); if (pDevCfg == NULL) { retValue = -15; } } if (retValue == 0 && ( #if defined(TODO) pDevCfg->commconfig.dcb.BaudRate != iBaudRate || #endif // TODO pDevCfg->commconfig.dcb.ByteSize != iDataBits || pDevCfg->commconfig.dcb.Parity != iParity || pDevCfg->commconfig.dcb.StopBits != iStopBits)) { // // If this is NT and we are currently connected with // a modem, we must disconnect and attempt to redial // so that the COM settings are set properly for the // modem since this can not be done once a connection // has been made. REV: 06/05/2001 // if (IsNT()) { HCNCT hCnct = sessQueryCnctHdl(hCom->hSession); if (hCnct) { int iStatus = cnctQueryStatus(hCnct); if (iStatus != CNCT_STATUS_FALSE && iStatus != CNCT_BAD_HANDLE && cnctIsModemConnection(hCnct) == 1) { int nDisconnect = IDYES; // // Don't prompt if this is NT_EDITION, just do the // disconnection quietly and attempt to reconnect. // #if !defined(NT_EDITION) TCHAR ach[256]; TCHAR_Fill(ach, TEXT('\0'), sizeof(ach) / sizeof(TCHAR)); // // Prompt to disconnect current connection due to TAPI // device needing to be reset. REV: 05/31/2001 // LoadString(glblQueryDllHinst(), IDS_ER_TAPI_NEEDS_RESET, ach, sizeof(ach) / sizeof(TCHAR)); nDisconnect = TimedMessageBox(sessQueryHwnd(hCom->hSession), ach, NULL, MB_YESNO | MB_ICONEXCLAMATION | MB_TASKMODAL, sessQueryTimeout(hCom->hSession)); #endif //NT_EDITION if (nDisconnect == IDYES || nDisconnect == -1) { retValue = -16; } } } // hCnct } // IsNT() } free(pvs); pvs = NULL; return retValue; }