home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------*/
- /* 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 <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <sys/types.h>
-
- #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 */
-
-