Category : UNIX Files
Archive   : UUPC11QS.ZIP
Filename : MODEM.C

 
Output of file : MODEM.C contained in archive : UUPC11QS.ZIP
/*--------------------------------------------------------------------*/
/* m o d e m . c */
/* */
/* High level modem control routines for UUPC/extended */
/* */
/* Copyright (c) 1991 by Andrew H. Derbyshire */
/* */
/* Change history: */
/* 21 Apr 91 Create from dcpsys.c */
/*--------------------------------------------------------------------*/

#include
#include
#include
#include
#include
#include

#include "lib.h"
#include "arpadate.h"
#include "checktim.h"
#include "dcp.h"
#include "dcpsys.h"
#include "hlib.h"
#include "hostable.h"
#include "modem.h"
#include "script.h"
#include "security.h"
#include "ssleep.h"
#include "ulib.h"

#define MAX_MODEM 8 /* Max length of a modem name */

char *device = NULL; /*Public to show in login banner */

static char **answer, **initialize, **dropline, **ring, **connect;
static char *dialPrefix, *dialSuffix;

static INTEGER chardelay, dialTimeout, modemTimeout, scriptTimeout;
static INTEGER answerTimeout, inspeed;
static INTEGER gWindow, gPacket;

typedef enum {
MODEM_FIXEDSPEED,
MODEM_DIRECT,
MODEM_LAST
} MODEM_FLAGS;

static FLAGTABLE modemFlags[] = {
"direct", MODEM_DIRECT, B_UUIO,
"fixedspeed", MODEM_FIXEDSPEED, B_UUIO,
nil(char)
} ;

static boolean bmodemflag[MODEM_LAST];

static CONFIGTABLE modemtable[] = {
"answer", (char **) &answer, B_LIST | B_UUIO,
"answertimeout", (char **) &answerTimeout,B_INTEGER| B_UUIO,
"chardelay", (char **) &chardelay, B_INTEGER| B_UUIO,
"connect", (char **) &connect, B_LIST | B_UUIO,
"device", &device, B_TOKEN | B_UUIO | B_REQUIRED,
"dialprefix", &dialPrefix, B_STRING | B_UUIO | B_REQUIRED,
"dialsuffix", &dialSuffix, B_STRING | B_UUIO,
"dialtimeout", (char **) &dialTimeout, B_INTEGER| B_UUIO,
"gwindowsize", (char **) &gWindow, B_INTEGER| B_UUIO,
"gpacketsize", (char **) &gPacket, B_INTEGER| B_UUIO,
"initialize", (char **) &initialize, B_LIST | B_UUIO,
"hangup", (char **) &dropline, B_LIST | B_UUIO,
"modemtimeout", (char **) &modemTimeout, B_INTEGER| B_UUIO,
"options", (char **) bmodemflag, B_ALL | B_BOOLEAN,
"ring", (char **) &ring, B_LIST | B_UUIO,
"scripttimeout", (char **) &scriptTimeout,B_INTEGER| B_UUIO,
"inspeed", (char **) &inspeed, B_INTEGER| B_UUIO,
nil(char)
}; /* modemtable */

/*--------------------------------------------------------------------*/
/* Internal function prototypes */
/*--------------------------------------------------------------------*/

static boolean getmodem( const char *brand);

static boolean dial(char *number, const size_t speed);

static boolean sendlist( char **list, int timeout, int lasttimeout);

static boolean sendalt( char *string, int timeout);

static void autobaud( const size_t speed);

/*--------------------------------------------------------------------*/
/* Define current file name for references */
/*--------------------------------------------------------------------*/

currentfile();

/*--------------------------------------------------------------------*/
/* c a l l u p */
/* */
/* script processor - nothing fancy! */
/*--------------------------------------------------------------------*/

CONN_STATE callup()
{
char *exp;
int i;
size_t speed;

/*--------------------------------------------------------------------*/
/* Determine if the window for calling this system is open */
/*--------------------------------------------------------------------*/

if ( !callnow && equal(flds[FLD_CCTIME],"Never" ))
/* Don't update if we */
return CONN_INITIALIZE; /* never try calling */

time(&hostp->hstats->ltime); /* Save time of last attempt to call */

/*--------------------------------------------------------------------*/
/* Check the time of day and whether or not we should call now. */
/* */
/* If calling a system to set the clock and we determine the */
/* system clock is bad (we fail the sanity check of the last */
/* connected a host to being in the future), then we ignore the */
/* time check field. */
/*--------------------------------------------------------------------*/

if (!(callnow || checktime(flds[FLD_CCTIME],(time_t) 0)))
{

if ((*flds[FLD_PROTO] != '*') || /* Not setting clock? */
((hostp->hstats->ltime > hostp->hstats->lconnect) &&
(hostp->hstats->ltime > 630720000L )))
/* Clock okay? */
{ /* Yes--> Return */
hostp->hstatus = wrong_time;
return CONN_INITIALIZE;
}
} /* if */

/*--------------------------------------------------------------------*/
/* Announce we are trying to call the system */
/*--------------------------------------------------------------------*/

printmsg(1, "callup: calling \"%s\" via %s at %s on %s",
rmtname, flds[FLD_TYPE], flds[FLD_SPEED], arpadate());

hostp->hstatus = dial_failed; /* Assume failure in the dial */

speed = (size_t) atoi( flds[FLD_SPEED] );
if (speed < 300)
{
printmsg(0,"callup: Modem speed \"%s\" is invalid.",
flds[FLD_SPEED]);
return CONN_INITIALIZE;
}

/*--------------------------------------------------------------------*/
/* Get the modem information */
/*--------------------------------------------------------------------*/

if (!getmodem(flds[FLD_TYPE]))
return CONN_INITIALIZE;

/*--------------------------------------------------------------------*/
/* Dial the telephone */
/*--------------------------------------------------------------------*/

if (! dial(flds[FLD_PHONE],speed))
return CONN_DROPLINE;

/*--------------------------------------------------------------------*/
/* The modem is connected; now login the host */
/*--------------------------------------------------------------------*/

hostp->hstatus = script_failed; /* Assume failure */
for (i = FLD_EXPECT; i < kflds; i += 2) {

exp = flds[i];
printmsg(2, "expecting %d of %d \"%s\"", i, kflds, exp);
if (!sendalt( exp, scriptTimeout ))
{
printmsg(0, "SCRIPT FAILED");
return CONN_DROPLINE;
} /* if */

printmsg(2, "callup: sending %d of %d \"%s\"",
i + 1, kflds, flds[i + 1]);
sendstr(flds[i + 1]);

} /*for*/

return CONN_PROTOCOL;

} /*callup*/

/*--------------------------------------------------------------------*/
/* c a l l h o t */
/* */
/* Initialize processing when phone is already off the hook */
/*--------------------------------------------------------------------*/

CONN_STATE callhot( const BPS xspeed )
{
BPS speed;

if ( xspeed == 0)
speed = inspeed;
else
speed = xspeed;

/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/

if (E_inmodem == NULL)
{
printmsg(0,"callin: No modem name supplied for incoming calls!");
panic();
} /* if */

if (!getmodem(E_inmodem)) /* Initialize modem configuration */
panic(); /* Avoid loop if bad modem name */

/*--------------------------------------------------------------------*/
/* Open the communications port */
/*--------------------------------------------------------------------*/

if (openline(device, speed, bmodemflag[MODEM_DIRECT] ))
panic();

/*--------------------------------------------------------------------*/
/* Initialize stats */
/*--------------------------------------------------------------------*/

memset( &remote_stats, 0, sizeof remote_stats);
/* Clear remote stats for login */
time(&remote_stats.ltime); /* Remember time of last attempt conn */
remote_stats.calls ++ ;
return CONN_HOTLOGIN;

} /* callhot */

/*--------------------------------------------------------------------*/
/* c a l l i n */
/* */
/* Answer the modem in passive mode */
/*--------------------------------------------------------------------*/

CONN_STATE callin( const char *logintime )
{
char c; /* A character for input buffer */

int offset; /* Time to wait for telephone */

/*--------------------------------------------------------------------*/
/* Determine how long we can wait for the telephone, up to */
/* MAX_INT seconds. Aside from Turbo C limits, this insures we */
/* kick the modem once in a while. */
/*--------------------------------------------------------------------*/

if (logintime == NULL) /* Any time specified? */
offset = INT_MAX; /* No --> Run almost forever */
else { /* Yes --> Determine elapsed time */
int delta = 4096; /* Rate at which we change offset */
boolean split = FALSE;

if (!checktime(logintime,(time_t) 0)) /* Still want system up? */
return CONN_EXIT; /* No --> shutdown */

offset = 0; /* Wait until end of this minute */
while ( ((INT_MAX - delta) > offset ) && (delta > 0))
{
printmsg(4,"Current time is %s, offset is %d, offset is %d",
arpadate(), offset, delta);
if (checktime(logintime,(time_t) offset + delta))
offset += delta;
else
split = TRUE; /* Once we starting splitting, we
never stop */
if ( split )
delta /= 2;
} /* while */
} /* else */

/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/

if (E_inmodem == NULL)
{
printmsg(0,"callin: No modem name supplied for incoming calls!");
panic();
} /* if */

if (!getmodem(E_inmodem)) /* Initialize modem configuration */
panic(); /* Avoid loop if bad modem name */

if ((ring == NULL) || (inspeed == 0))
{
printmsg(0,"callin: Missing inspeed and/or ring values in modem \
configuration file.");
panic();
} /* if */

/*--------------------------------------------------------------------*/
/* Open the communications port */
/*--------------------------------------------------------------------*/

if (openline(device, inspeed, bmodemflag[MODEM_DIRECT]))
panic();

/*--------------------------------------------------------------------*/
/* Flush the input buffer of any characters */
/*--------------------------------------------------------------------*/

while (sread(&c ,1,0)); /* Discard trailing trash from modem
connect message */

/*--------------------------------------------------------------------*/
/* Initialize the modem */
/*--------------------------------------------------------------------*/

if (!sendlist( initialize, modemTimeout, modemTimeout))
{
printmsg(0,"callin: Modem failed to initialize");
panic();
}

/*--------------------------------------------------------------------*/
/* Wait for the telephone to ring */
/*--------------------------------------------------------------------*/

if (!sendlist( ring,modemTimeout, offset))
/* Did it ring? */
{
shutdown();
return CONN_INITIALIZE; /* No --> Return to caller */
}

if(!sendlist(answer, modemTimeout,answerTimeout))
/* Pick up the telephone */
{
printmsg(1,"callin: Modem failed to connect to incoming call");
shutdown();
return CONN_INITIALIZE;
}

/*--------------------------------------------------------------------*/
/* The modem is connected; now try to autobaud it */
/*--------------------------------------------------------------------*/

printmsg(14, "callin: got CONNECT");
autobaud(inspeed); /* autobaud the modem */

/*--------------------------------------------------------------------*/
/* Flush the input buffer of any other input characters */
/*--------------------------------------------------------------------*/

while (sread(&c ,1,0)); /* Discard trailing trash from modem
connect message */

memset( &remote_stats, 0, sizeof remote_stats);
/* Clear remote stats for login */
time(&remote_stats.ltime); /* Remember time of last attempt conn */
remote_stats.calls ++ ;
return CONN_LOGIN;

} /* callin */


/*--------------------------------------------------------------------*/
/* g e t m o d e m */
/* */
/* Read a modem configuration file */
/*--------------------------------------------------------------------*/

static boolean getmodem( const char *brand)
{
char filename[FILENAME_MAX];
static char modem[MAX_MODEM+1] = "";
FILE *fp;
CONFIGTABLE *tptr;
size_t subscript;
boolean success;

/*--------------------------------------------------------------------*/
/* Validate the modem name */
/*--------------------------------------------------------------------*/

if (strlen(brand) > MAX_MODEM)
{
printmsg(0,"getmodem: Invalid modem %s; must be %d characters or less",
brand, modem);
return FALSE;
}

if (equal(modem, brand)) /* Already initialized? */
return TRUE; /* Yes --> Don't process it again */

/*--------------------------------------------------------------------*/
/* Initialize the table */
/*--------------------------------------------------------------------*/

for (tptr = modemtable; tptr->sym != nil(char); tptr++)
if (tptr->bits & (B_TOKEN | B_STRING | B_LIST | B_CLIST))
*(tptr->loc) = nil(char);

for (subscript = 0; subscript < MODEM_LAST; subscript++)
bmodemflag[subscript] = FALSE;

chardelay = 00; /* Default is no delay between chars */
dialTimeout = 40; /* Default is 40 seconds to dial phone */
scriptTimeout = 30; /* Default is 30 seconds for script data*/
modemTimeout = 3; /* Default is 3 seconds for modem cmds */
gWindow = 0; /* Handle default in dcpgpkt */
gPacket = 0; /* Handle default in dcpgpkt */

/*--------------------------------------------------------------------*/
/* Open the modem configuration file */
/*--------------------------------------------------------------------*/

if (equaln(brand,"COM",3))
{
printmsg(0,"Modem type \"%s\" is invalid; Snuffles suspects \
your %s file is obsolete.", brand, SYSTEMS);
panic();
}

sprintf(filename,"%s/%s.MDM",confdir, brand);
if ((fp = FOPEN(filename, "r", TEXT)) == nil(FILE))
{
printmsg(0,"getmodem: Unable to locate configuration for %s",
brand);
printerr( filename );
return FALSE;
}

/*--------------------------------------------------------------------*/
/* We got the file open, now process it */
/*--------------------------------------------------------------------*/

printmsg(3,"getmodem: loading modem configuration file %s", filename);
success = getconfig(fp, MODEM_CONFIG, B_UUIO, modemtable, modemFlags);
fclose(fp);
if (!success)
return FALSE;

/*--------------------------------------------------------------------*/
/* Verify all required modem parameters were supplied */
/*--------------------------------------------------------------------*/

success = TRUE;
for (tptr = modemtable; tptr->sym != nil(char); tptr++) {
if ((tptr->bits & (B_REQUIRED | B_FOUND)) == B_REQUIRED)
{
printmsg(0, "getmodem: configuration parameter \"%s\" must be set.",
tptr->sym);
success = FALSE;
} /* if */
} /* for */

if ( success ) /* Good modem setup? */
strcpy( modem, brand); /* Yes --> Remember it for next time */
return success;

} /* getmodem */

/*--------------------------------------------------------------------*/
/* d i a l */
/* */
/* Generic modem dialer; only major limitation is that autoabaud */
/* strings are not configurable */
/*--------------------------------------------------------------------*/

static boolean dial(char *number, const size_t speed)
{
char buf[81];

/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/

if (openline(device, speed, bmodemflag[MODEM_DIRECT]))
return FALSE;

/*--------------------------------------------------------------------*/
/* Flush the input buffer of any characters */
/*--------------------------------------------------------------------*/

while (sread(buf,1,0)); /* Discard trailing trash from modem
connect message */

/*--------------------------------------------------------------------*/
/* Initialize the modem */
/*--------------------------------------------------------------------*/

if (!sendlist( initialize, modemTimeout, modemTimeout))
{
printmsg(0,"dial: Modem failed to initialize");
return FALSE;

}

/*--------------------------------------------------------------------*/
/* Setup the dial string and then dial the modem */
/*--------------------------------------------------------------------*/

strcpy(buf, dialPrefix);
strcat(buf, number);
if (dialSuffix != NULL)
strcat(buf, dialSuffix);

sendstr( buf ); /* Send the command to the telephone */

if (!sendlist(connect, modemTimeout, dialTimeout))
return FALSE;
printmsg(3, "dial: Modem reports connected");
time( &remote_stats.lconnect );
remote_stats.calls ++ ;

autobaud(speed); /* Reset modem speed, if desired */

/*--------------------------------------------------------------------*/
/* Report success to caller */
/*--------------------------------------------------------------------*/

return TRUE; /* Dial succeeded */

} /* dial */

/*--------------------------------------------------------------------*/
/* a u t o b a u d */
/* */
/* autobaud a modem which has just connected */
/*--------------------------------------------------------------------*/

static void autobaud( const size_t speed )
{
char buf[10];

ssleep(1); /* Allow modem port to stablize */

/*--------------------------------------------------------------------*/
/* Autobaud the modem if requested */
/*--------------------------------------------------------------------*/

if (!bmodemflag[MODEM_FIXEDSPEED])
{
size_t len = 0;

memset( buf, '\0', sizeof( buf )); /* Zero buffer */
while ((len < sizeof buf) && sread( &buf[len],1,0))
len = strlen( buf ); /* Get speed into buffer */

if (len > 5)
{
char *token; /* Pointer to buffer value */
token = strtok(buf,WHITESPACE);
if (strlen(token))
{
size_t new_speed = (unsigned) atoi(token);
if ((new_speed != speed) && (new_speed > 300))
{
printmsg(2, "autobaud: speed select %s", token);
SIOSpeed(atoi(token));
} /* if */
} /* if */
} /* if */
else
printmsg(3, "autobaud: unable to speed select, using %d", speed);
} /* if */

} /* autobaud */

/*--------------------------------------------------------------------*/
/* s h u t d o w n */
/* */
/* Terminate modem processing via hangup */
/*--------------------------------------------------------------------*/

void shutdown( void )
{
static boolean recurse = FALSE;

if ( !recurse )
{
recurse = TRUE;
hangup();
sendlist( dropline, modemTimeout, modemTimeout);
recurse = FALSE;
}
closeline();
}

/*--------------------------------------------------------------------*/
/* s e n d l i s t */
/* */
/* Send a NULL terminated list of send/expect strings */
/*--------------------------------------------------------------------*/

static boolean sendlist( char **list, int timeout, int lasttimeout)
{
boolean expect = TRUE;

if (list == NULL) /* Was the field supplied? */
return TRUE; /* No --> Must be optional, return */

/*--------------------------------------------------------------------*/
/* Run through the list, alternating expect and send strings */
/*--------------------------------------------------------------------*/

while( *list != NULL)
{
if (expect)
{
char *exp = strdup( *list );
boolean success;
checkref( exp );
success = sendalt( exp,
(*(++list) == NULL) ? lasttimeout : timeout);
free( exp );
if (!success)
return FALSE;
}
else
sendstr( *list++ );
expect = ! expect;
} /* while */

/*--------------------------------------------------------------------*/
/* If we made it this far, success is at hand; return to caller */
/*--------------------------------------------------------------------*/

return TRUE;
} /* sendlist */

/*--------------------------------------------------------------------*/
/* s e n d a l t */
/* */
/* Expect a string, with alternates */
/*--------------------------------------------------------------------*/

static boolean sendalt( char *exp, int timeout)
{
boolean ok = FALSE;

while (ok != TRUE) {
char *alternate = strchr(exp, '-');

if (alternate != nil(char))
*alternate++ = '\0';

ok = expectstr(exp, timeout);

if (ok) {
printmsg(2, "got that");
break;
}

if (alternate == nil(char)) {
return FALSE;
}

exp = strchr(alternate, '-');
if (exp != nil(char))
*exp++ = '\0';

printmsg(0, "sending alternate");
sendstr(alternate);
} /*while*/
return TRUE;

} /* sendalt */

/*--------------------------------------------------------------------*/
/* s l o w w r i t e */
/* */
/* Write characters to the serial port at a configurable */
/* snail's pace. */
/*--------------------------------------------------------------------*/

void slowwrite( char *s, int len)
{
swrite( s , len );
if (chardelay > 0)
ddelay(chardelay);
} /* slowwrite */

/*--------------------------------------------------------------------*/
/* G e t G W i n d o w */
/* */
/* Report the size of the allowed window for the "g" protocol */
/*--------------------------------------------------------------------*/

INTEGER GetGWindow( INTEGER maxvalue )
{
if ( (gWindow < 1 ) || (gWindow > maxvalue))
return maxvalue;
else
return gWindow;
} /* GetGWindow */

/*--------------------------------------------------------------------*/
/* G e t G P a c k e t */
/* */
/* Return the allowed packet size for the "g" procotol */
/*--------------------------------------------------------------------*/

INTEGER GetGPacket( INTEGER maxvalue )
{
if ( (gPacket < 1 ) || (gPacket > maxvalue))
return maxvalue;
else
return gPacket;
} /* GetGPacket */



  3 Responses to “Category : UNIX Files
Archive   : UUPC11QS.ZIP
Filename : MODEM.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/