| ..back |
// ******************************************************************
// **Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
// **
// ******************************************************************
//
// dial.c The dialing state machine for Unimodem
//
// @doc EX_TSPI
//
// @topic TSPI |
//
// Tspi Stuff
//
//
#include "windows.h"
#include "types.h"
#include "memory.h"
#include "mcx.h"
#include "tspi.h"
#include "linklist.h"
#include "tspip.h"
#include "tapicomn.h"
#include "dial.h"
#include "termctrl.h"
#include "resource.h"
// Functions from modem.c
extern LONG ToggleCommMask(PTLINEDEV pLineDev);
extern void SetDCBfromDevMiniCfg(DCB * pDCB,PDEVMINICFG lpDevMiniCfg);
extern void WriteModemLog(PTLINEDEV pLineDev, UCHAR * szCommand, DWORD dwOp);
// Unimodem thread priority
extern DWORD g_dwUnimodemThreadPriority;
// Some keys we read to get modem related info from registry
const WCHAR szSettings[] = TEXT("Settings");
const WCHAR szDialSuffix[] = TEXT("DialSuffix");
static const WCHAR szInit[] = TEXT("Init");
#define MAXINITKEYS 5
static const PWCHAR szInitNum[MAXINITKEYS] = {
TEXT("1"),
TEXT("2"),
TEXT("3"),
TEXT("4"),
TEXT("5")
};
int strncmpi(char *dst, const char *src, long count)
{
while (count) {
if (toupper(*dst) != toupper(*src))
return 1;
if (*src == 0)
return 0;
dst++;
src++;
count--;
}
return 0;
}
/******************************************************************************
@doc INTERNAL
@api BOOL | ExpandMacros | Takes the string pszLine, and copies it to
lpszVal after expanding macros
@parm char * | pszRegResponse | ptr to response string from registry.
@parm char * | pszExpanded | ptr to buffer to copy string to w/ macros expanded
@parm DWORD * | 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.
*****************************************************************************/
BOOL
ExpandMacros(
PWCHAR pszRegResponse,
PWCHAR pszExpanded,
DWORD * pdwValLen,
MODEMMACRO * pMdmMacro,
DWORD cbMacros
)
{
PWCHAR pszValue;
DWORD cbTmp;
BOOL bFound;
PWCHAR ptchTmp;
DWORD i;
DEBUGMSG(ZONE_DIAL, (TEXT("UNIMODEM:+ExpandMacros : Original \"%s\"\r\n"), pszRegResponse ));
pszValue = pszExpanded;
for ( ; *pszRegResponse; )
{
// check for a macro
if ( *pszRegResponse == LMSCH )
{
// <cr>
if (!wcsnicmp(pszRegResponse,CR_MACRO,CR_MACRO_LENGTH))
{
*pszValue++ = CR;
pszRegResponse += CR_MACRO_LENGTH;
continue;
}
// <lf>
if (!wcsnicmp(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 = wcslen(pMdmMacro[i].MacroName);
if (!wcsnicmp(pszRegResponse, pMdmMacro[i].MacroName, cbTmp))
{
ptchTmp = pMdmMacro[i].MacroValue;
while (*ptchTmp)
{
*pszValue++ = *ptchTmp++;
}
pszRegResponse += cbTmp;
bFound = TRUE;
break;
}
}
if (bFound) // Did we get a match?
{
continue;
}
} // <macro>
} // LMSCH
// No matches, copy the character verbatim.
*pszValue++ = *pszRegResponse++;
} // for
*pszValue = 0;
if (pdwValLen)
{
*pdwValLen = pszValue - pszExpanded;
}
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:-ExpandMacros : Expanded \"%s\"\r\n"), pszExpanded ));
return TRUE;
}
PWCHAR
CreateDialCommands(
PTLINEDEV pLineDev,
BOOL *fOriginate
)
{
DWORD dwSize;
PWCHAR pszTemp;
PWCHAR pszDialPrefix; // ex. "ATX4DT" or "ATX3DT"
PWCHAR pszDialSuffix; // ex. ";<cr>"
PWCHAR pszOrigSuffix; // ex. "<cr>"
PWCHAR pszzDialCommands = NULL;
PWCHAR ptchSrc, ptchDest;
WCHAR pszShortTemp[2];
static const WCHAR szPrefix[] = TEXT("Prefix");
static const WCHAR szTerminator[] = TEXT("Terminator");
static const WCHAR szDialPrefix[] = TEXT("DialPrefix");
static const WCHAR szPulse[] = TEXT("Pulse");
static const WCHAR szTone[] = TEXT("Tone");
static const WCHAR *szDialType; // szTone or szPulse
static const WCHAR szBlindOff[] = TEXT("Blind_Off");
static const WCHAR szBlindOn[] = TEXT("Blind_On");
static const WCHAR *szBlindType; // szBlindOn or szBlindOff
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:+CreateDialCommands - number %s\r\n"),
pLineDev->szAddress ? pLineDev->szAddress : TEXT("") ));
// Figure out fOriginate
ptchSrc = pLineDev->szAddress;
*fOriginate = TRUE;
while (*ptchSrc)
{
if (pLineDev->chContinuation == *ptchSrc) // usually a semicolon
{
*fOriginate = FALSE;
#ifdef DEBUG
// make sure the string is correctly formed.
if (ptchSrc[1])
{
DEBUGMSG(ZONE_DIAL, (TEXT("UNIMODEM: CreateDialCommands szPhoneNumber had a line continuation character not at the end.\r\n")));
}
#endif // DEBUG
}
ptchSrc++;
}
// Trim the command continuation character off the end, now that we know this is not an origination string.
if (!(*fOriginate))
{
DEBUGMSG(ZONE_DIAL, (TEXT("UNIMODEM:CreateDialCommands Non-originate string, trim trailing \"%c\"\r\n"),pLineDev->chContinuation));
#ifdef DEBUG
if (ptchSrc[-1] != pLineDev->chContinuation) // usually a semicolon
{
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:CreateDialCommands made a bad assumption.\r\n")));
}
#endif // DEBUG
ptchSrc[-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
dwSize = ((pLineDev->dwMaxCmd + 1 + // pszTemp
pLineDev->dwMaxCmd + 1 + // pszDialPrefix
pLineDev->dwMaxCmd + 1 + // pszDialSuffix
pLineDev->dwMaxCmd + 1) // pszOrigSuffix
* SZWCHAR);
pszTemp = (PWCHAR)TSPIAlloc( dwSize );
if (!pszTemp)
{
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:-CreateDialCommands : out of memory.\r\n")));
return NULL;
}
DEBUGMSG(ZONE_DIAL, (TEXT("UNIMODEM:CreateDialCommands Allocated %d bytes at x%X for tmp dial strings\r\n"),
dwSize, pszTemp));
pszDialPrefix = pszTemp + pLineDev->dwMaxCmd + 1;
pszDialSuffix = pszDialPrefix + pLineDev->dwMaxCmd + 1;
pszOrigSuffix = pszDialSuffix + pLineDev->dwMaxCmd + 1;
// read in prefix
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szPrefix,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, pszDialPrefix, NULL, NULL, 0);
if ( (MDM_BLIND_DIAL & pLineDev->DevMiniCfg.dwModemOptions) ||
(MDM_BLIND_DIAL & pLineDev->dwDialOptions) )
{ // Turn on blind dialing
szBlindType = szBlindOn;
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands BLIND DIALING - ModemOptions 0x%X, DialOptions 0x%X\r\n"),
pLineDev->DevMiniCfg.dwModemOptions, pLineDev->dwDialOptions ));
}
else
{ // Turn off blind dialing
szBlindType = szBlindOff;
}
#ifdef BLIND_OPTION_IN_PREFIX
// read in appropriate blind options
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szBlindType,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, pszDialPrefix + wcslen(pszDialPrefix), NULL, NULL, 0);
#endif
// read in dial prefix
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS != MdmRegGetValue( pLineDev,
szSettings,
szDialPrefix,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, pszDialPrefix + wcslen(pszDialPrefix), NULL, NULL, 0);
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (MDM_TONE_DIAL & pLineDev->dwDialOptions)
{ // We want to do tone dialing
szDialType = szTone;
}
else
{ // We want to do pulse dialing
szDialType = szPulse;
}
if (ERROR_SUCCESS != MdmRegGetValue( pLineDev,
szSettings,
szDialType,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, pszDialPrefix + wcslen(pszDialPrefix), NULL, NULL, 0);
// read in dial suffix
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS != MdmRegGetValue( pLineDev,
szSettings,
szDialSuffix,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
wcscpy(pszDialSuffix, TEXT(""));
#ifdef TODO
hPort->mi_fHaveDialSuffix = FALSE;
#endif
}
else
{
#ifdef TODO
hPort->mi_fHaveDialSuffix = TRUE;
#endif
ExpandMacros(pszTemp, pszDialSuffix, NULL, NULL, 0);
}
// read in prefix terminator
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS == MdmRegGetValue( pLineDev,
szSettings,
szTerminator,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
ExpandMacros(pszTemp, pszOrigSuffix, NULL, NULL, 0);
wcscat(pszDialSuffix, pszOrigSuffix);
#ifdef DEBUG
if (wcslen(pszOrigSuffix) > wcslen(pszDialSuffix))
{
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands OrigSuffix longer than DialSuffix!!! (contact developer)\r\n")));
}
#endif // DEBUG
}
#ifdef DEBUG
if ((wcslen(pszDialPrefix) + wcslen(pszDialSuffix)) > pLineDev->dwMaxCmd)
{
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Prefix, Terminator, BlindOn/Off, Dial Prefix, and Dial Suffix are too long!\r\n")));
}
#endif // DEBUG
// allocate space for the phone number lines
{
DWORD dwCharsAlreadyTaken = wcslen(pszDialPrefix) + wcslen(pszDialSuffix);
DWORD dwAvailCharsPerLine = (pLineDev->dwMaxCmd - dwCharsAlreadyTaken);
DWORD dwPhoneNumLen = wcslen(pLineDev->szAddress);
DWORD dwNumLines = dwPhoneNumLen ? (dwPhoneNumLen / dwAvailCharsPerLine +
(dwPhoneNumLen % dwAvailCharsPerLine ? 1 : 0))
: 1; // handle null string
dwSize = (dwPhoneNumLen + dwNumLines * (dwCharsAlreadyTaken + 1) + 1) * SZWCHAR;
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Allocation sizes - prefix/suffix %d, Phone num %d, numLines %d\r\n"),
dwCharsAlreadyTaken, dwPhoneNumLen, dwNumLines));
}
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Allocate %d bytes for Dial Commands.\r\n"), dwSize));
dwSize *= 4;
if (!(pszzDialCommands = (PWCHAR)TSPIAlloc(dwSize)))
{
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands ran out of memory and failed a TSPIAlloc!\r\n")));
goto Failure;
}
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Allocated %d bytes at x%X for dial string\r\n"),
dwSize, pszzDialCommands));
ptchDest = pszzDialCommands; // point to the beginning of the commands
// build dial line(s):
#ifndef BLIND_OPTION_IN_PREFIX
// See above : we now split the blind dial out from the dial prefix.
// read in prefix
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szPrefix,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, ptchDest, NULL, NULL, 0);
// read in appropriate blind options
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szBlindType,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto Failure;
}
ExpandMacros(pszTemp, ptchDest + wcslen(ptchDest), NULL, NULL, 0);
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands prepended Blind dial sequence = %s, len %d\r\n"),
ptchDest, wcslen(ptchDest)));
//OK, be sure to add a CR to this
ExpandMacros(CR_MACRO, ptchDest + wcslen(ptchDest), NULL, NULL, 0);
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands prepended Blind dial sequence = %s, len %d\r\n"),
ptchDest, wcslen(ptchDest)));
// begin a new dial string
ptchDest += wcslen(ptchDest) + 1;
#endif
// prime the pump
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Copying Dial prefix %s to x%X\r\n"),
pszDialPrefix, ptchDest));
wcscpy(ptchDest, pszDialPrefix);
// do we have a dial suffix
if ( /*!hPort->mi_fHaveDialSuffix*/ FALSE )
{
#ifdef DEBUG
// but, can we fit the dial string?
if (wcslen(pszDialPrefix) + wcslen(pLineDev->szAddress) +
wcslen(pszDialSuffix) + 1 > pLineDev->dwMaxCmd)
{
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands dial string is too long and we don't have dial suffix capability\r\n")));
}
// did we not want to originate?
if (!(*fOriginate))
{
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands was told not to originate, but it has to because it doesn't have a dial suffix! (tsp screwed up!)\r\n")));
}
#endif // DEBUG
// build it
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Appending phone number %s\r\n"), pLineDev->szAddress));
wcscat(ptchDest, pLineDev->szAddress);
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Appending Dial Suffix %s\r\n"), pszDialSuffix));
wcscat(ptchDest, pszDialSuffix);
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Final Dial String %s\n"), ptchDest));
}
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 pLineDev->dwMaxCmd
ptchSrc = pLineDev->szAddress; // moves a character at a time.
pszShortTemp[1] = 0; // null terminate the 1 character temp string
// step through the source
while (*ptchSrc)
{
if (wcslen(ptchDest) + wcslen(pszDialSuffix) + 1 > pLineDev->dwMaxCmd)
{
// finish up this string
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Appending Dial suffix %s\r\n"), pszDialSuffix));
wcscat(ptchDest, pszDialSuffix);
// begin a new string
ptchDest += wcslen(ptchDest) + 1;
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Copying Dial prefix %s for a new line at 0x%X\r\n"),
pszDialPrefix, ptchDest));
wcscpy(ptchDest, pszDialPrefix);
}
else
{
// copy char
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Appending character %c to dial string %s\r\n"),
*ptchSrc, ptchDest));
pszShortTemp[0] = *ptchSrc;
wcscat(ptchDest, pszShortTemp);
ptchSrc++;
}
}
// conclude with the approprate Suffix.
DEBUGMSG( ZONE_DIAL,
(TEXT("UNIMODEM:CreateDialCommands Appending Final Dial Suffix %s\r\n"), (*fOriginate ? pszOrigSuffix : pszDialSuffix)));
wcscat(ptchDest, (*fOriginate ? pszOrigSuffix : pszDialSuffix));
}
// close keys
Exit:
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:CreateDialCommands Trying to free pszTemp x%X\r\n"), pszTemp));
TSPIFree(pszTemp);
DEBUGMSG( ZONE_DIAL, (TEXT("UNIMODEM:-CreateDialCommands\r\n")));
return pszzDialCommands;
Failure:
if (pszzDialCommands)
{
DEBUGMSG( ZONE_DIAL|ZONE_ERROR, (TEXT("UNIMODEM:CreateDialCommands - Error, freeing dial string\r\n")));
TSPIFree(pszzDialCommands);
pszzDialCommands = NULL;
}
goto Exit;
}
BOOL
IsDigit(
UCHAR ch
)
{
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return TRUE;
}
return FALSE;
}
//
// Extract the connection speed from an extended CONNECT or CARRIER modem response
// and store it in pLineDev->dwCurrentBaudRate
//
void
ParseConnectSpeed(
PTLINEDEV pLineDev,
PUCHAR pszResponse
)
{
DWORD dwSpeed = 0;
PUCHAR psz;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:+ParseConnectSpeed %a\n"), pszResponse));
//
// CONNECT and CARRIER typically follow the form:
// CONNECT <speed></protocol>< protocol> <compressed>
// CARRIER <speed></protocol> < protocol> <compressed>
// Sometimes there is a colon and/or a space before the speed.
// Sometimes a K follows the speed indicating * 1000
// Sometimes there are commas in the speed
//
//
// Skip to the first digit
//
psz = pszResponse;
while (*psz) {
if (IsDigit(*psz)) {
break;
}
psz++;
}
while (*psz) {
if (IsDigit(*psz)) {
dwSpeed = dwSpeed * 10 + (DWORD)(*psz - '0');
} else if (*psz == 'K') {
dwSpeed *= 1000;
} else if (*psz != ',') {
break;
}
psz++;
}
if (dwSpeed) {
pLineDev->dwCurrentBaudRate = dwSpeed;
if (pLineDev->htCall) {
CallLineEventProc(
pLineDev,
pLineDev->htCall,
LINE_CALLINFO,
LINECALLINFOSTATE_RATE,
0,
0
);
}
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-ParseConnectSpeed %d\n"), dwSpeed));
}
const
MODEM_RESPONSE ResponseTable[] =
{
{ "OK", MODEM_SUCCESS },
{ "RING", MODEM_RING },
{ "RINGING", MODEM_RING },
{ "NO CARRIER", MODEM_HANGUP },
{ "ERROR", MODEM_FAILURE },
{ "NO DIALTONE", MODEM_NODIALTONE },
{ "NO DIAL TONE", MODEM_NODIALTONE },
{ "BUSY", MODEM_BUSY},
{ "NO ANSWER", MODEM_NOANSWER },
{ "CONNECT", MODEM_CONNECT },
{ "FCERROR", MODEM_FAILURE },
{ "FCON", MODEM_FAILURE },
{ "BLACKLIST", MODEM_NOANSWER },
{ "CARRIER", MODEM_CARRIER },
{ "DATA", MODEM_FAILURE },
{ "DATE", MODEM_PROGRESS },
{ "DELAYED", MODEM_FAILURE },
{ "DIALING", MODEM_PROGRESS },
{ "FAX", MODEM_FAILURE },
{ "VCON", MODEM_SUCCESS },
{ "VOICE", MODEM_FAILURE },
{ "PROTOCOL", MODEM_PROTOCOL },
{ "RRING", MODEM_RING},
};
#ifdef DEBUG
LPWSTR
ResponseName(
MODEMRESPCODES MdmRsp
)
{
switch (MdmRsp) {
case MODEM_SUCCESS: return TEXT("MODEM_SUCCESS");
case MODEM_PENDING: return TEXT("MODEM_PENDING");
case MODEM_CONNECT: return TEXT("MODEM_CONNECT");
case MODEM_FAILURE: return TEXT("MODEM_FAILURE");
case MODEM_HANGUP: return TEXT("MODEM_HANGUP");
case MODEM_NODIALTONE: return TEXT("MODEM_NODIALTONE");
case MODEM_BUSY: return TEXT("MODEM_BUSY");
case MODEM_NOANSWER: return TEXT("MODEM_NOANSWER");
case MODEM_RING: return TEXT("MODEM_RING");
case MODEM_CARRIER: return TEXT("MODEM_CARRIER");
case MODEM_PROTOCOL: return TEXT("MODEM_PROTOCOL");
case MODEM_PROGRESS: return TEXT("MODEM_PROGRESS");
case MODEM_UNKNOWN: return TEXT("MODEM_UNKNOWN");
case MODEM_IGNORE: return TEXT("MODEM_IGNORE");
case MODEM_EXIT: return TEXT("MODEM_EXIT");
default: return TEXT("UNKNOWN Modem Response Code!!!");
}
}
#endif // DEBUG
// The only valid NULL_MODEM response is "CLIENTSERVER"
const UCHAR pchDCCResp[] = "CLIENTSERVER";
const UCHAR pchDCCCmd[] = "CLIENT";
#define SZ_RESPONSE_TABLE (sizeof(ResponseTable)/sizeof(MODEM_RESPONSE))
MODEMRESPCODES
ModemResponseHandler(
PTLINEDEV pLineDev,
PUCHAR pszResponse,
PUCHAR pszOrigCommand
)
{
UINT16 wRespCode = MODEM_UNKNOWN;
int i;
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:+ModemResponseHandler x%X, x%X, x%X\r\n"),
pLineDev, pszResponse, pszOrigCommand));
// Lets remove any leading CR/LF from response.
while( (CR == *pszResponse) || (LF == *pszResponse) )
pszResponse++;
if( 0 == *pszResponse )
{
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-ModemResponseHandler, Empty response\r\n")));
return MODEM_IGNORE;
}
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:ModemResponseHandler Modem Response '%a'\r\n"), pszResponse));
// Lets remove any leading CR/LF from orig command.
while( (CR == *pszOrigCommand) || (LF == *pszOrigCommand) )
pszOrigCommand++;
// First, check to see if this is just an echo of the command
if( NULL != pszOrigCommand )
{
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:ModemResponseHandler Checking for echo of CMD %a\r\n"), pszOrigCommand));
if( ! strncmpi( pszResponse, pszOrigCommand, strlen(pszResponse) ) )
{
// Ignore this, it was just a duplicate
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:-ModemResponseHandler, Command Echo\r\n")));
return MODEM_IGNORE;
}
}
DEBUGMSG(ZONE_FUNC,
(TEXT("UNIMODEM:ModemResponseHandler response was not an echo\r\n")));
// Regular Modems have a lookup table for responses
// Lets convert the ASCII response to a numeric code
for( i=0; i<SZ_RESPONSE_TABLE; i++ )
{
if( !strncmpi( pszResponse, ResponseTable[i].pszResponse,
(strlen(ResponseTable[i].pszResponse) - 1) ) )
{
wRespCode = ResponseTable[i].ModemRespCode;
break;
}
}
DEBUGMSG(ZONE_CALLS|ZONE_FUNC,
(TEXT("UNIMODEM:-ModemResponseHandler, %s\n"), ResponseName(wRespCode) ));
return wRespCode;
}
//
// Expand macros and convert command to chars
//
LPSTR
MdmConvertCommand(
WCHAR const *pszWCommand,
LPSTR pchCmd,
LPDWORD lpdwSize
)
{
LPSTR lpstr;
WCHAR szExpand[256];
DWORD dwCmdLen;
if (pchCmd) {
lpstr = pchCmd;
} else {
lpstr = NULL;
}
if (!ExpandMacros((PWCHAR)pszWCommand, (PWCHAR)szExpand, 0, NULL, 0)) {
return NULL;
}
dwCmdLen = wcslen(szExpand) + 1;
if (lpstr == NULL) {
lpstr = TSPIAlloc(dwCmdLen);
if (lpstr == NULL) {
return NULL;
}
}
dwCmdLen = wcstombs( lpstr, szExpand, dwCmdLen );
if (lpdwSize) {
*lpdwSize = dwCmdLen;
}
return lpstr;
}
BOOL
MdmSendCommand(
PTLINEDEV pLineDev,
UCHAR const *pszCommand
)
{
DWORD dwLen;
BOOL bRet = FALSE;
//
// This routine sends a Modem command, and then waits for
// a valid response from the modem (or timeout).
//
try
{
if( (HANDLE)INVALID_DEVICE != pLineDev->hDevice )
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmSendCommand '%a'\r\n"), pszCommand));
// Purge any old responses sitting in serial buffer
if (PurgeComm( pLineDev->hDevice, PURGE_RXCLEAR|PURGE_TXCLEAR )) {
// Set the Comm Mask for waitcommevent
if (SetCommMask(pLineDev->hDevice, EV_DEFAULT)) {
// Now, lets send this nice new string to the modem
bRet = WriteFile(pLineDev->hDevice, (LPVOID)pszCommand, strlen((LPVOID)pszCommand), &dwLen, 0 );
if ((FALSE == bRet) || (dwLen != strlen((LPVOID)pszCommand))) {
bRet = FALSE;
RETAILMSG (1,
(TEXT("UNIMODEM:!!!MdmSendCommand wrote %d of %d byte dial string\r\n"),
dwLen, strlen((LPVOID)pszCommand)) );
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:MdmSendCommand Wrote %d bytes of %d byte dial string\r\n"),
dwLen, strlen((LPVOID)pszCommand)) );
}
}
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just return of handle is bad
}
WriteModemLog(pLineDev, (PUCHAR)pszCommand, bRet ? MDMLOG_COMMAND_OK : MDMLOG_COMMAND_FAIL);
return bRet;
}
#ifdef DEBUG
void
DisplayModemStatus(
DWORD ModemStat
)
{
WCHAR szModemStat[256];
szModemStat[0] = 0;
if( ModemStat & EV_BREAK)
wcscat(szModemStat, TEXT(" EV_BREAK"));
if( ModemStat & EV_CTS)
wcscat(szModemStat, TEXT(" EV_CTS"));
if( ModemStat & EV_DSR)
wcscat(szModemStat, TEXT(" EV_DSR"));
if( ModemStat & EV_ERR)
wcscat(szModemStat, TEXT(" EV_ERR"));
if( ModemStat & EV_RING)
wcscat(szModemStat, TEXT(" EV_RING"));
if( ModemStat & EV_RLSD)
wcscat(szModemStat, TEXT(" EV_RLSD"));
if( ModemStat & EV_RXCHAR)
wcscat(szModemStat, TEXT(" EV_RXCHAR"));
if( ModemStat & EV_RXFLAG)
wcscat(szModemStat, TEXT(" EV_RXFLAG"));
if( ModemStat & EV_TXEMPTY)
wcscat(szModemStat, TEXT(" EV_TXEMPTY"));
DEBUGMSG (ZONE_MISC, (TEXT("UNIMODEM:DisplayModemStatus ModemStat =%s\n"), szModemStat));
} // DisplayModemStatus
void
DisplayCommError(
DWORD dwCommError
)
{
WCHAR szCommError[256];
szCommError[0] = 0;
if (dwCommError & CE_BREAK) {
wcscat(szCommError, TEXT(" CE_BREAK"));
}
if (dwCommError & CE_FRAME) {
wcscat(szCommError, TEXT(" CE_FRAME"));
}
if (dwCommError & CE_IOE) {
wcscat(szCommError, TEXT(" CE_IOE"));
}
if (dwCommError & CE_MODE) {
wcscat(szCommError, TEXT(" CE_MODE"));
}
if (dwCommError & CE_OOP) {
wcscat(szCommError, TEXT(" CE_OOP"));
}
if (dwCommError & CE_OVERRUN) {
wcscat(szCommError, TEXT(" CE_OVERRUN"));
}
if (dwCommError & CE_RXOVER) {
wcscat(szCommError, TEXT(" CE_RXOVER"));
}
if (dwCommError & CE_RXPARITY) {
wcscat(szCommError, TEXT(" CE_RXPARITY"));
}
if (dwCommError & CE_TXFULL) {
wcscat(szCommError, TEXT(" CE_TXFULL"));
}
if (dwCommError & CE_DNS) {
wcscat(szCommError, TEXT(" CE_DNS"));
}
if (dwCommError & CE_PTO) {
wcscat(szCommError, TEXT(" CE_PTO"));
}
DEBUGMSG (ZONE_MISC, (TEXT("UNIMODEM:DisplayCommError CommError=%s\n"), szCommError));
} // DisplayCommError
#endif
BOOL
LineNotDropped(
PTLINEDEV pLineDev,
DEVSTATES OrigDevState
)
{
if (pLineDev->DevState == OrigDevState) {
return TRUE;
}
return FALSE;
}
MODEMRESPCODES
MdmGetResponse(
PTLINEDEV pLineDev,
PUCHAR pszCommand,
BOOL bLeaveCS
)
{
MODEMRESPCODES ModemResp = MODEM_IGNORE;
DWORD ModemStat;
UCHAR InBuf[MAXSTRINGLENGTH];
int i;
UCHAR ModemResponse[MAXSTRINGLENGTH];
UINT16 ModemResponseIndex = 0;
DWORD dwLen;
DEVSTATES OrigDevState;
PUCHAR pchDCC; // either pchDCCCmd or pchDCCResp
MODEMRESPCODES DCCResp;
DWORD dwDCCLen;
BOOL bInCS;
DWORD OrigPendingOp;
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+MdmGetResponse for %a\r\n"), pszCommand));
OrigDevState = pLineDev->DevState;
OrigPendingOp = pLineDev->dwPendingType;
bInCS = bLeaveCS;
// Wait until we get some type of meaningful response from the modem
while ((MODEM_IGNORE == ModemResp) && LineNotDropped(pLineDev, OrigDevState))
{
try
{
ModemStat = 0;
if (bInCS) {
//
// To help avoid missing signals from SignalControlThread, stay in CS as long
// as possible before calling WaitCommEvent.
//
LeaveCriticalSection(&pLineDev->OpenCS);
bInCS = FALSE;
}
if (!WaitCommEvent( pLineDev->hDevice, &ModemStat, NULL)) {
dwLen = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - WaitCommEvent failed %d\n"), dwLen));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
if (pLineDev->bWatchdogTimedOut) {
pLineDev->bWatchdogTimedOut = FALSE;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Watchdog timed out\n")));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
//
// Look for signals from SignalControlThread
//
if (pLineDev->dwPendingType != OrigPendingOp) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Interrupted\n")));
ModemResp = MODEM_FAILURE;
goto mgr_exit;
}
if (ModemStat) {
#ifdef DEBUG
DisplayModemStatus(ModemStat);
#endif
if (ModemStat & EV_ERR) {
if (ClearCommError(pLineDev->hDevice, &dwLen, NULL)) {
#ifdef DEBUG
if (dwLen) {
DisplayCommError(dwLen);
}
} else {
dwLen = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse ClearCommError failed %d\n"), dwLen));
#endif
}
}
if( ModemStat & EV_RING) {
ModemResp = MODEM_RING;
}
if ((ModemStat & EV_RXCHAR) && LineNotDropped(pLineDev, OrigDevState))
{
if (!ReadFile (pLineDev->hDevice, (LPVOID)InBuf, sizeof(InBuf), &dwLen, 0)) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - ReadFile failed %d\n"), GetLastError()));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
InBuf[dwLen] = 0;
WriteModemLog(pLineDev, (PUCHAR)InBuf, MDMLOG_RESPONSE);
#ifdef DEBUG_RESPONSES
if (dwLen) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse Response = %a\n"), InBuf));
}
#endif
// Now lets process each response as they arrive
for( i=0; i<(int)dwLen; i++ )
{
ModemResponse[ModemResponseIndex] = InBuf[i];
if( IS_NULL_MODEM(pLineDev) )
{
//
// Only allow one response per call to MdmGetResponse for a DCC connection
//
ModemResp = MODEM_FAILURE;
//
// Are we client or server?
//
if (pLineDev->dwPendingType == PENDING_LINEMAKECALL) {
pchDCC = (PUCHAR)pchDCCResp;
DCCResp = MODEM_CONNECT;
} else {
pchDCC = (PUCHAR)pchDCCCmd;
DCCResp = MODEM_RING;
}
dwDCCLen = strlen(pchDCC);
if( ModemResponse[ModemResponseIndex] == pchDCC[ModemResponseIndex] )
{
ModemResponseIndex++;
// characters match so far, see if we have a complete response.
if( ModemResponseIndex >= dwDCCLen )
{
// OK, we got a full response. Zero terminate it and exit
ModemResponse[ModemResponseIndex] = 0;
// No need to call response handler, we already did all the work.
ModemResp = DCCResp;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse Null Response detected\r\n")));
break;
}
}
else // character mismatch - restart scan sequence.
{
// If character is 'C', it might be first character of the actual
// response. Any other case means that all data up to here is useless
// so we should toss it. This is only true because 'C' appears only as
// the first character of a response, and never after that.
ModemResponseIndex = 0;
if (pchDCC[0] == InBuf[i])
{
ModemResponse[ModemResponseIndex] = InBuf[i];
ModemResponseIndex++;
}
}
}
else
{
if( (CR == InBuf[i]) ||
(LF == InBuf[i]) ||
((DWORD)i == dwLen-1) ||
((pLineDev->dwMaxCmd - 1) <= ModemResponseIndex) )
{
// have a complete response (or max length). Now we parse it.
ModemResponse[ModemResponseIndex] = 0; // Lets Zero Terminate the string
ModemResp = ModemResponseHandler( pLineDev, ModemResponse, pszCommand );
switch (ModemResp) {
case MODEM_CARRIER:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through!!!
case MODEM_PROTOCOL:
case MODEM_PROGRESS:
NewCallState(pLineDev, LINECALLSTATE_PROCEEDING, 0L);
if (i < (int)(dwLen - 1)) {
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
}
break;
case MODEM_UNKNOWN:
case MODEM_IGNORE:
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
break;
case MODEM_CONNECT:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through
default:
goto mgr_exit;
}
ModemResponseIndex = 0; // Start a new response
}
else
{
ModemResponseIndex++; //Add another character to the string
}
}
}
}
}
else
{
// A zero ModemStat is an error, and indicates that the
// waitcommevent was stopped by our watchdog or linedrop.
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Timeout\r\n")));
goto mgr_exit;
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse %s\n"), ResponseName(ModemResp)));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Must have been a bad handle. Give up
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:MdmGetResponse - Exception. Handle \r\n"),
pLineDev->hDevice ));
}
}
mgr_exit:
if (bInCS) {
LeaveCriticalSection(&pLineDev->OpenCS);
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-MdmGetResponse %s\r\n"), ResponseName(ModemResp)));
return ModemResp;
}
//
// There were cases where the ModemWatchdog thread would not make it to the WaitForSingleObject
// before the next SetWatchdog happened. This would leave two or more watchdogs runnning at the
// same time which leads to all kinds of problems. Now SetWatchdog passes a UNIMODEM_WATCHDOG_INFO
// structure to the thread and the watchdog checks that it is the current one before aborting
// any pending operations.
//
typedef struct _UNIMODEM_WATCHDOG_INFO {
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
} UNIMODEM_WATCHDOG_INFO, * PUNIMODEM_WATCHDOG_INFO;
// **********************************************************************
//
// This is the dialer/answer watchdog thread. It is created by the dialer thread.
// Its purpose is to wait for a specified interval, or until signalled by
// the dialer. If the wait times out, then the watchdog calls into the
// COM port driver, causing the waitcommevent in the dialer thread to
// return.
//
// **********************************************************************
void
ModemWatchdog(
PUNIMODEM_WATCHDOG_INFO pWDInfo
)
{
DWORD RetCode;
BOOL bAbort;
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
pLineDev = pWDInfo->pLineDev;
dwTimeout = pWDInfo->dwTimeout;
dwThisWatchdog = pWDInfo->dwThisWatchdog;
TSPIFree(pWDInfo);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:+ModemWatchdog(%d) - timeout set to %d seconds\r\n"),
dwThisWatchdog, dwTimeout/1000));
// Wait for the specified interval.
RetCode = WaitForSingleObject( pLineDev->hTimeoutEvent, dwTimeout );
if ((dwThisWatchdog == pLineDev->dwCurWatchdog) && ( WAIT_TIMEOUT == RetCode )) {
pLineDev->bWatchdogTimedOut = TRUE;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) *** %s TIMEOUT!\n"),
dwThisWatchdog, GetPendingName(pLineDev->dwPendingType)));
// We need to stop the waitcommevent. Note that we set the
// mask to 0, which will cause any subsequent waitcommevent
// calls to also return immediately.
ToggleCommMask(pLineDev);
switch (pLineDev->dwPendingType) {
case PENDING_LINEMAKECALL:
//
// Allow an in progress DCC lineMakeCall to retry
//
bAbort = !(IS_NULL_MODEM(pLineDev));
break;
case PENDING_LINEANSWER:
NewCallState(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_UNKNOWN);
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
bAbort = TRUE;
break;
case PENDING_LINEDIAL:
case PENDING_LINEDROP:
bAbort = TRUE;
break;
default:
bAbort = FALSE;
break;
}
// We set an event when we are done so that DevLineDrop can
// continue with his cleanup.
if (bAbort) {
SetEvent(pLineDev->hCallComplete);
SetAsyncStatus(pLineDev, LINEERR_OPERATIONFAILED);
}
}
#ifdef DEBUG
else {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) cancelled\r\n"), dwThisWatchdog));
}
#endif
// This is a one shot timeout. The thread should go away as
// soon as the timer expires or is signalled/cancelled.
}
// **********************************************************************
// Wrapper function to start the watchdog.
// Note that a timeout of 0 cancels the current watchdog.
// **********************************************************************
DWORD
SetWatchdog(
PTLINEDEV pLineDev,
DWORD dwTimeout
)
{
HANDLE hThread;
PUNIMODEM_WATCHDOG_INFO pWDInfo;
pLineDev->dwCurWatchdog++;
pLineDev->bWatchdogTimedOut = FALSE;
// First, lets cancel any current outstanding watchdogs for this line
PulseEvent(pLineDev->hTimeoutEvent); // Stop the watchdog
// And now, start a new watchdog if they want us to
if( dwTimeout ) {
pWDInfo = TSPIAlloc(sizeof(UNIMODEM_WATCHDOG_INFO));
if (NULL == pWDInfo) {
NKDbgPrintfW( TEXT("UNIMODEM:SetWatchDog Unable to alloc Watchdog info\n") );
return (DWORD)-1;
}
pWDInfo->pLineDev = pLineDev;
pWDInfo->dwTimeout = dwTimeout;
pWDInfo->dwThisWatchdog = pLineDev->dwCurWatchdog;
hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ModemWatchdog,
pWDInfo, 0, NULL );
if ( ! hThread ) {
TSPIFree(pWDInfo);
NKDbgPrintfW( TEXT("UNIMODEM:SetWatchDog Unable to Create Watchdog Thread\n") );
return (DWORD)-1;
}
CeSetThreadPriority(hThread, g_dwUnimodemThreadPriority);
CloseHandle( hThread );
}
return STATUS_SUCCESS;
}
BOOL
ModemInit(
PTLINEDEV pLineDev
)
{
MODEMRESPCODES MdmResp = MODEM_FAILURE;
DWORD dwSize, dwCmdLen;
int RetryCount = 0;
PWCHAR pszTemp = NULL;
PWCHAR pszExpand = NULL;
PCHAR pchCmd = NULL;
MODEMMACRO ModemMacro;
DWORD dwCallSetupFailTimer;
DEVSTATES OrigDevState;
static const WCHAR szReset[] = TEXT("Reset");
static const WCHAR szFlowHard[] = TEXT("FlowHard");
static const WCHAR szFlowSoft[] = TEXT("FlowSoft");
static const WCHAR szFlowNone[] = TEXT("FlowOff");
static const WCHAR *szFlowType; // Hard, Soft, None
static const WCHAR szCallFail[] = TEXT("CallSetupFailTimeout");
static const UCHAR szEscapeCmd[] = "+++";
OrigDevState = pLineDev->DevState;
try
{
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:+ModemInit\r\n")));
// Allocate temp buffers for registry results
pszTemp = (PWCHAR)TSPIAlloc( (pLineDev->dwMaxCmd + 1) * SZWCHAR );
pszExpand = (PWCHAR)TSPIAlloc( (pLineDev->dwMaxCmd + 1) * SZWCHAR );
pchCmd = (PCHAR)TSPIAlloc( pLineDev->dwMaxCmd + 1 );
// First, read the reset command from the registry
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if (ERROR_SUCCESS !=
MdmRegGetValue( pLineDev,
szSettings,
szReset,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
goto init_error;
}
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Reset string is \"%s\" (%d)\r\n"),
pszTemp, dwCmdLen));
// ***** reset modem by clearing DTR
if(LineNotDropped(pLineDev, OrigDevState))
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit SetCommState - DTR off\r\n")));
EscapeCommFunction ( pLineDev->hDevice, CLRDTR);
Sleep( 400 );
}
if(LineNotDropped(pLineDev, OrigDevState))
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit SetCommState - DTR on\r\n")));
EscapeCommFunction ( pLineDev->hDevice, SETDTR);
Sleep( 200 );
}
// No matter what the state was, we are now initializing
pLineDev->MdmState = MDMST_INITIALIZING;
while( (LineNotDropped(pLineDev, OrigDevState)) &&
(RetryCount < MAX_COMMAND_TRIES) )
{
// Set short timeout for init strings
if( SetWatchdog( pLineDev, 8000 ) )
{
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
if( LineNotDropped(pLineDev, OrigDevState) )
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Send Init\r\n")));
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
// See if we managed to get initialized
if( MODEM_SUCCESS == MdmResp )
{
pLineDev->MdmState = MDMST_DISCONNECTED; // It worked
break;
}
else
{
if( LineNotDropped(pLineDev, OrigDevState) )
{
// the modem didn't reset
pLineDev->MdmState = MDMST_UNKNOWN;
// If szReset didn't work, we likely need a +++
MdmSendCommand( pLineDev, szEscapeCmd );
Sleep( 200 );
}
}
RetryCount++;
}
if( (MDMST_DISCONNECTED == pLineDev->MdmState) &&
(LineNotDropped(pLineDev, OrigDevState)) )
{
DWORD mdmRegRslt = ERROR_SUCCESS;
WORD wInitKey;
// read a sequence of additional init strings from the
// registry and send them down now. Can't enumerate the
// keys since that wouldn't allow us to have modem specific
// values mixed with default values.
wInitKey = 0;
while( (wInitKey < MAXINITKEYS) &&
(LineNotDropped(pLineDev, OrigDevState)) &&
(ERROR_SUCCESS == mdmRegRslt) )
{
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
mdmRegRslt = MdmRegGetValue( pLineDev,
szInit,
szInitNum[wInitKey],
REG_SZ,
(PUCHAR)pszTemp,
&dwSize);
if (ERROR_SUCCESS == mdmRegRslt)
{
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Init string %d - %s\r\n"),
wInitKey, pszTemp));
// Set short timeout for init strings
if( SetWatchdog( pLineDev, 8000 ) )
{
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
if (LineNotDropped(pLineDev, OrigDevState)) {
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad init string. We can't recover from this so exit
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
else
{
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:ModemInit Error x%X reading Init string %d\r\n"),
mdmRegRslt, wInitKey));
}
wInitKey++;
}
// And now that we have the basic init in place, we still need to
// make sure the flow control settings match what we are doing in
// the UART.
if( MDM_FLOWCONTROL_HARD & pLineDev->DevMiniCfg.dwModemOptions )
{ // Set Modem for hardware flow control
szFlowType = szFlowHard;
}
else if( MDM_FLOWCONTROL_SOFT & pLineDev->DevMiniCfg.dwModemOptions )
{ // Set Modem for software flow control
szFlowType = szFlowSoft;
}
else
{ // Set modem for no flow control
szFlowType = szFlowNone;
}
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if( ERROR_SUCCESS == MdmRegGetValue( pLineDev,
szSettings,
szFlowType,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
// OK, we got the flow control command, send it.
MdmConvertCommand(pszTemp, pchCmd, &dwCmdLen);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Flow Control string %s\r\n"),
pszTemp));
if (LineNotDropped(pLineDev, OrigDevState))
{
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad flow control string. We can't recover from this.
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
// Now we set up the call fail timer if it exists.
dwSize = pLineDev->dwMaxCmd * SZWCHAR;
if( ERROR_SUCCESS == MdmRegGetValue( pLineDev,
szSettings,
szCallFail,
REG_SZ,
(PUCHAR)pszTemp,
&dwSize) )
{
// OK, we got the Call Fail setup command, send it.
// Most modems can't handle a value > 255 for call fail time
// And a time of 0 usually really means wait the maximum
dwCallSetupFailTimer = pLineDev->DevMiniCfg.dwCallSetupFailTimer;
if( (dwCallSetupFailTimer > 255) ||
(dwCallSetupFailTimer == 0) )
dwCallSetupFailTimer = 255;
// Expand macros, including the fail time <#>
wcscpy(ModemMacro.MacroName, INTEGER_MACRO);
wsprintf(ModemMacro.MacroValue, TEXT("%d"), dwCallSetupFailTimer );
ExpandMacros(pszTemp, pszExpand, NULL, &ModemMacro, 1);
// We need to convert the UniCode to ASCII
dwCmdLen = wcslen(pszExpand) + 1;
dwCmdLen = wcstombs( pchCmd, pszExpand, dwCmdLen );
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Call fail timer string %s\r\n"),
pszTemp));
if (LineNotDropped(pLineDev, OrigDevState))
{
// We got a value, write it out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// Hmm, we could probably ignore this failure, but the call might
// never time out. Lets be safe and abort now.
pLineDev->MdmState = MDMST_UNKNOWN;
goto init_error;
}
}
// And finally, see if user requested any special modifier string
if( dwCmdLen = wcslen(pLineDev->DevMiniCfg.szDialModifier) )
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Dial Modifier string %s\r\n"),
pLineDev->DevMiniCfg.szDialModifier));
// Convert the UniCode to ASCII, and insert 'AT' in command
pchCmd[0] = 'A';
pchCmd[1] = 'T';
dwCmdLen += 1;
dwCmdLen = wcstombs( pchCmd+2, pLineDev->DevMiniCfg.szDialModifier, dwCmdLen );
// OK, now don't forget the CR at end.
strcat( pchCmd, "\r" );
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemInit Generated Modifier string %a\r\n"),
pchCmd));
if (LineNotDropped(pLineDev, OrigDevState))
{
// And write this out to modem
MdmResp = MODEM_FAILURE;
if (MdmSendCommand( pLineDev, pchCmd )) {
if (LineNotDropped(pLineDev, OrigDevState)) {
MdmResp = MdmGetResponse( pLineDev, pchCmd, NOCS );
}
}
}
if( MODEM_SUCCESS != MdmResp )
{
// bad modifier string. We can't recover from this.
pLineDev->MdmState = MDMST_UNKNOWN;
DEBUGMSG(ZONE_CALLS | ZONE_ERROR,
(TEXT("UNIMODEM:ModemInit Bad user supplied dial modifier %s\r\n"),
pLineDev->DevMiniCfg.szDialModifier));
goto init_error;
}
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Most likely a bad handle. Just give up
pLineDev->MdmState = MDMST_UNKNOWN;
}
init_error:
// Cancel watchdog if he's still around.
SetWatchdog( pLineDev, 0 );
if( pszTemp )
TSPIFree( pszTemp );
if( pchCmd )
TSPIFree( pchCmd );
if( pszExpand )
TSPIFree( pszExpand );
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM: -ModemInit %s\n"),
(pLineDev->MdmState == MDMST_UNKNOWN) ? TEXT("FAILED"): TEXT("OK")));
return (pLineDev->MdmState == MDMST_UNKNOWN) ? FALSE : TRUE;
} // ModemInit
#define NUM_BAUD_RATES 9
DWORD
NextBaudRate(
DWORD dwBaudRate
)
{
switch (dwBaudRate) {
case CBR_19200: return CBR_57600;
case CBR_57600: return CBR_115200;
case CBR_115200: return CBR_38400;
case CBR_38400: return CBR_56000;
case CBR_56000: return CBR_128000;
case CBR_128000: return CBR_256000;
case CBR_256000: return CBR_9600;
case CBR_9600: return CBR_14400;
case CBR_14400: return CBR_19200;
}
return CBR_19200;
}
//
// Called to set the baud rate for a NULL MODEM device.
//
BOOL
AutoBaudRate(
PTLINEDEV pLineDev,
DWORD dwBaudRate
)
{
DCB commDCB;
DWORD status;
DWORD Retry;
DWORD dwCurBaud;
Sleep(200);
if (!EscapeCommFunction ( pLineDev->hDevice, CLRDTR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate EscapeCommFunction(CLRDTR) failed %d\n"), status));
return FALSE;
}
Sleep(400);
if (!GetCommState(pLineDev->hDevice, &commDCB)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate GetCommState failed %d\n"), status));
return FALSE;
}
Retry = 0;
if (dwBaudRate) {
dwCurBaud = dwBaudRate;
} else {
abr_next:
dwCurBaud = NextBaudRate(pLineDev->dwCurrentBaudRate);
}
pLineDev->dwCurrentBaudRate = commDCB.BaudRate = dwCurBaud;
if (!PurgeComm(pLineDev->hDevice, PURGE_TXCLEAR|PURGE_RXCLEAR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate PurgeComm failed %d\r\n"), status));
}
if (!SetCommState(pLineDev->hDevice, &commDCB)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate SetCommState(baud = %d) failed %d\n"),
commDCB.BaudRate, status));
//
// If SetCommState fails with inval parm, assume the error was an unsupported baud rate
// and try the next one.
//
if (status == ERROR_INVALID_PARAMETER) {
Retry++;
if (Retry < NUM_BAUD_RATES) {
goto abr_next;
}
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate failed.\n")));
return FALSE;
}
if (!EscapeCommFunction ( pLineDev->hDevice, SETDTR)) {
status = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate EscapeCommFunction(SETDTR) failed %d\n"), status));
return FALSE;
}
Sleep(200);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:AutoBaudRate trying %d\n"), commDCB.BaudRate));
return TRUE;
} // AutoBaudRate
BOOL
CallNotDropped(
PTLINEDEV pLineDev
)
{
switch (pLineDev->dwCallState) {
case LINECALLSTATE_CONNECTED:
case LINECALLSTATE_DIALING:
case LINECALLSTATE_DIALTONE:
case LINECALLSTATE_PROCEEDING:
case LINECALLSTATE_UNKNOWN:
return TRUE;
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:CallNotDropped call state = %x\n"), pLineDev->dwCallState));
return FALSE;
}
// **********************************************************************
//
// This is the dialer thread. It is created whenever we decide to
// dial a modem, and exists until the call completes or is terminated.
//
// **********************************************************************
void
Dialer(
PTLINEDEV pLineDev
)
{
DCB commDCB;
MODEMRESPCODES MdmResp;
BOOL fOriginate;
BOOL bFirstResp;
PWCHAR pszzDialCommands = NULL; // strings of dial strings returned from CreateDialCommand
PWCHAR ptchDialCmd;
PCHAR pchDialCmd = NULL;
DWORD dwDialLen;
DWORD LineCallState;
DWORD LineCallStateParm2;
DWORD LineError; // Indicates asynchronous return code for LineMakeCall completion
DWORD dwCallFailTimer;
BOOL bKeepLooping;
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - dial options x%X (x%X), modem options x%X\r\n"),
pLineDev->dwDialOptions, pLineDev->DevMiniCfg.fwOptions, pLineDev->DevMiniCfg.dwModemOptions));
dwCallFailTimer = pLineDev->DevMiniCfg.dwCallSetupFailTimer;
LineCallStateParm2 = LINEDISCONNECTMODE_NORMAL;
LineError = LINEERR_OPERATIONFAILED;
bFirstResp = TRUE;
if( (dwCallFailTimer == 0) ||
(dwCallFailTimer > 512) )
dwCallFailTimer = 512;
// Clear any old CallComplete events before starting a new call
WaitForSingleObject(pLineDev->hCallComplete, 0);
pLineDev->dwCallState = LineCallState = LINECALLSTATE_UNKNOWN;
try
{
// Disable HW flow control while we try to connect.
// Otherwise, our xmit may get stuck in a flowed-off state and
// then we cannot send.
GetCommState( pLineDev->hDevice, &commDCB );
commDCB.fRtsControl = RTS_CONTROL_ENABLE;
commDCB.fOutxCtsFlow = 0;
SetCommState( pLineDev->hDevice, &commDCB );
// Our job is to dial the modem, and then sit here waiting for
// a response. All the helper routines in this file are responsible
// for driving the state machine.
LineCallState = LINECALLSTATE_DIALING;
NewCallState(pLineDev, LineCallState, 0L);
//
// If we are here because of a lineDial call, then skip the NULL modem
// and manual dial stuff
//
if (pLineDev->dwPendingType == PENDING_LINEDIAL) {
goto dial_continue;
}
#define NULL_MODEM_RETRY 3
if( IS_NULL_MODEM(pLineDev) )
{
DWORD Retry;
DWORD BaudRates;
DWORD NumBaudRates;
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - Attempting DCC connection\r\n")));
//
// This is a DCC connection. Dial strings are simple.
// Send 'CLIENT', expect back 'CLIENTSERVER'. Try several
// times, unless we are dropping the line
//
if (pLineDev->DevMiniCfg.dwModemOptions & MDM_SPEED_ADJUST) {
NumBaudRates = NUM_BAUD_RATES;
} else {
//
// Automatic baud rate detection is off, just use the supplied baud rate
//
NumBaudRates = 1;
pLineDev->dwLastBaudRate = 0;
}
if (!AutoBaudRate(
pLineDev,
(pLineDev->dwLastBaudRate) ?
pLineDev->dwLastBaudRate : pLineDev->DevMiniCfg.dwBaudRate)) {
pLineDev->dwLastBaudRate = 0;
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
for (BaudRates=0; BaudRates < NumBaudRates; BaudRates++) {
for( Retry=0;
(Retry <= NULL_MODEM_RETRY) && (CallNotDropped(pLineDev) );
Retry++ )
{
// Start the watchdog thread before we block in a read
if( SetWatchdog( pLineDev, dwCallFailTimer * 1000 ) )
{
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
// Send out CLIENT
if (MdmSendCommand( pLineDev, pchDCCCmd )) {
// Now look for CLIENTSERVER
do
{
MdmResp = MdmGetResponse( pLineDev, (PUCHAR)pchDCCCmd, NOCS);
} while ( (MODEM_FAILURE != MdmResp) &&
(MODEM_EXIT != MdmResp) &&
(MODEM_CONNECT != MdmResp) &&
CallNotDropped(pLineDev) );
} else {
MdmResp = MODEM_FAILURE;
}
if( MODEM_CONNECT == MdmResp )
{
// Cool, we are connected
LineError = 0;
pLineDev->dwLastBaudRate = pLineDev->dwCurrentBaudRate;
pLineDev->dwCallFlags |= CALL_ACTIVE;
goto dial_connected;
}
// We timed out on a connect. Reset the watchdog and try again
SetWatchdog( pLineDev, 0 );
//
// Check if the operation got cancelled.
//
if (pLineDev->dwPendingType != PENDING_LINEMAKECALL) {
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
// Tell the application that we are retrying connect
if (Retry < NULL_MODEM_RETRY) {
NewCallState(pLineDev, LineCallState, 0L);
}
}
if (BaudRates == 0) {
//
// Make sure the baud rate is within autobaud's range
//
pLineDev->dwCurrentBaudRate = NextBaudRate(0);
}
if (!AutoBaudRate(pLineDev, 0)) {
pLineDev->dwLastBaudRate = 0;
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
}
pLineDev->dwLastBaudRate = 0;
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
else if (pLineDev->DevMiniCfg.fwOptions & MANUAL_DIAL)
{
if (DisplayTerminalWindow(pLineDev, IDS_MANUAL_DIAL_TERMINAL)) {
// The user pressed OK, so he must be connected.
LineError = 0;
pLineDev->dwCallFlags |= CALL_ACTIVE;
}
goto dial_done;
}
else
{
// Its not a NULL modem, so send actual dial strings
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:Dialer - Attempting Modem connection\r\n")));
EnterCriticalSection(&pLineDev->OpenCS);
ModemInit(pLineDev);
LeaveCriticalSection(&pLineDev->OpenCS);
// If modeminit failed, we sure won't be able to dial
if( MDMST_UNKNOWN == pLineDev->MdmState )
{
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - Modem Reset failed, aborting call\r\n")));
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
// Are we supposed to do a pre-dial terminal???
if ( (pLineDev->DevMiniCfg.fwOptions & TERMINAL_PRE) &&
CallNotDropped(pLineDev) )
{
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - PreDial - Modem State x%X\r\n"),
pLineDev->MdmState ));
if (!DisplayTerminalWindow(pLineDev, IDS_PRE_DIAL_TERMINAL))
{
// Either the user cancelled or something went wrong.
goto dial_done;
}
}
dial_continue:
// Convert the dial string to a modem format.
DEBUGMSG(ZONE_MISC, (TEXT("UNIMODEM:Dialer - Ready to create Dial Strings\r\n")));
pszzDialCommands = CreateDialCommands( pLineDev, &fOriginate );
if (!pszzDialCommands) {
goto dial_done;
}
ptchDialCmd = pszzDialCommands;
// Dial strings get truncated to pLineDev->dwMaxCmd so
// allocate a buffer large enough to store that.
pchDialCmd = TSPIAlloc( pLineDev->dwMaxCmd + 4 );
if (!pchDialCmd) {
goto dial_done;
}
// Start the watchdog thread before we block in a read
if( SetWatchdog( pLineDev, dwCallFailTimer * 1000 ) )
{
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
goto dial_done;
}
// Remember, this is a string of dial strings. We need to iterate
// through each of them and handle the responses.
while (CallNotDropped(pLineDev) && *ptchDialCmd)
{
// We need to convert the UniCode to ASCII
dwDialLen = wcslen(ptchDialCmd) + 1;
DEBUGMSG(ZONE_MISC,
(TEXT("UNIMODEM:Dialer - Sending Dial string of len %d - %s\r\n"),
dwDialLen, ptchDialCmd));
dwDialLen = wcstombs( pchDialCmd, ptchDialCmd, dwDialLen );
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - Advancing ptchDialCmd to x%X\r\n"),
ptchDialCmd));
ptchDialCmd += wcslen(ptchDialCmd) + 1;
// Send the command and wait for a response
MdmSendCommand( pLineDev, pchDialCmd );
// Loop looking for a failure or success response
bKeepLooping = TRUE;
while ((CallNotDropped(pLineDev)) && (bKeepLooping)) {
MdmResp = MdmGetResponse( pLineDev, pchDialCmd, NOCS );
bKeepLooping = FALSE;
if (bFirstResp) {
bFirstResp = FALSE;
switch (MdmResp) {
case MODEM_CARRIER:
case MODEM_CONNECT:
case MODEM_PROGRESS:
case MODEM_PROTOCOL:
case MODEM_SUCCESS:
NewCallState(pLineDev, LINECALLSTATE_DIALTONE, LINEDIALTONEMODE_UNAVAIL);
break;
}
}
LineError = LINEERR_OPERATIONFAILED;
switch (MdmResp) {
case MODEM_CONNECT:
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:Dialer - Dial succeeded\n")));
pLineDev->dwCallFlags |= CALL_ACTIVE;
LineError = 0;
break;
case MODEM_BUSY:
// If it was busy, let application know about it
NewCallState(pLineDev, LINECALLSTATE_BUSY, 0L);
LineCallStateParm2 = LINEDISCONNECTMODE_BUSY;
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - BUSY\r\n")));
goto dial_done;
case MODEM_NODIALTONE:
LineCallStateParm2 = LINEDISCONNECTMODE_NODIALTONE;
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - No Dial Tone\r\n")));
goto dial_done;
case MODEM_NOANSWER:
LineCallStateParm2 = LINEDISCONNECTMODE_NOANSWER;
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - No Answer\r\n")));
goto dial_done;
case MODEM_HANGUP:
LineCallStateParm2 = LINEDISCONNECTMODE_NORMAL;
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - HANGUP\r\n")));
goto dial_done;
case MODEM_FAILURE:
case MODEM_EXIT:
LineCallStateParm2 = LINEDISCONNECTMODE_UNKNOWN;
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - UNKNOWN Disconnect mode\r\n")));
goto dial_done;
case MODEM_SUCCESS:
case MODEM_PROGRESS:
case MODEM_CARRIER:
DEBUGMSG(ZONE_CALLS,(TEXT("UNIMODEM:Dialer - Continuing Dial Sequence\r\n")));
LineError = 1;
break;
default:
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - Unknown response x%X\r\n"),
MdmResp));
// Don't fail on unknown responses. Just look for a known good, a fail, or a timeout
bKeepLooping = TRUE;
break;
}
}
} // while more dial strings
}
dial_connected:
SetWatchdog( pLineDev, 0 ); // Stop the watchdog
// Are we supposed to do a post-dial terminal???
// LAM - Why isn't this inside of the NOT MANUAL DIAL section
if ( (pLineDev->DevMiniCfg.fwOptions & TERMINAL_POST) &&
CallNotDropped(pLineDev) )
{
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - PostDial - Modem State x%X\r\n"),
pLineDev->MdmState ));
if (!DisplayTerminalWindow(pLineDev, IDS_POST_DIAL_TERMINAL)) {
// Either the user cancelled or something went wrong.
goto dial_done;
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Somebody must have hit a bad handle. Fail this dial sequence
goto dial_done;
}
dial_done:
switch (LineError) {
case 0:
pLineDev->DevState = DEVST_CONNECTED;
LineCallState = LINECALLSTATE_CONNECTED;
LineCallStateParm2 = 0;
break;
case 1:
pLineDev->DevState = DEVST_PORTCONNECTWAITFORLINEDIAL;
LineCallState = LINECALLSTATE_DIALING;
LineCallStateParm2 = 0;
break;
default:
pLineDev->DevState = DEVST_DISCONNECTED;
LineCallState = LINECALLSTATE_DISCONNECTED;
break;
}
SetWatchdog( pLineDev, 0 ); // Stop the watchdog
if ((pLineDev->dwPendingType == PENDING_LINEMAKECALL) ||
(pLineDev->dwPendingType == PENDING_LINEDIAL)) {
DEBUGMSG(ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - tCall Completion for ReqID x%X, Status x%X\r\n"),
pLineDev->dwPendingID, (LineError == 1) ? 0 : LineError));
SetAsyncStatus(pLineDev, (LineError == 1) ? 0 : LineError);
}
NewCallState(pLineDev, LineCallState, LineCallStateParm2);
if (CallNotDropped(pLineDev)) {
if (LINECALLSTATE_CONNECTED == LineCallState) {
try {
// Don't forget to restore the dev state if we connected. The init
// sequence took care of telling the modem what we thought the
// flow control should be.
SetDCBfromDevMiniCfg(&commDCB, &(pLineDev->DevMiniCfg));
if (IS_NULL_MODEM(pLineDev)) {
commDCB.BaudRate = pLineDev->dwLastBaudRate;
}
SetCommState( pLineDev->hDevice, &commDCB );
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS,
(TEXT("UNIMODEM:Dialer - RTS Control %d, CTS Out Flow %d, XON/XOFF out/in %d/%d\r\n\r\n"),
commDCB.fRtsControl, commDCB.fOutxCtsFlow, commDCB.fOutX, commDCB.fInX));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Nothing special needs done if the handle is gone.
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:Dialer **** Call Connected\r\n")));
}
} else {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:Dialer **** Call State x%X, closing port\r\n"), LineCallState));
DevlineClose(pLineDev, FALSE);
}
// Free up anything we may have allocated in here.
if( pchDialCmd )
TSPIFree( pchDialCmd );
if( pszzDialCommands )
TSPIFree( pszzDialCommands );
// We set an event when we are done so that DevLineDrop can
// continue with his cleanup.
SetEvent(pLineDev->hCallComplete);
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-Dialer\r\n")));
}
Legal Declaration: it is for studying wince(MicroSoft Windows CE) only! : http://www.vxworks6.com