home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
TELECOM
/
UUCP_Blars.lzh
/
dial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-03-09
|
15KB
|
680 lines
/*
* @(#) dialHA12.c 1.5 86/12/18
*
* Copyright (C) The Santa Cruz Operation, Inc. 1986
*
* Function: dialer program for the Hayes Smartmodem 1200/1200b
*
* Usage: dial ttyname telnumber speed
* dial -h ttyname speed
*
* Returns: 0x80 bit = 1 if connection failed
* 0x10 bit = 1 if line is also used for dialin
* 0x0f if msb=1: error code
* if msb=0: connected baud rate (0=same as dialed baud)
*
* Note: cu and uucp only call the dialer with -h when they are
* done if the return code from the first dialer call has the
* 0x10 bit set.
*
* Error codes are split into two catagories: 1) (codes 0-11)
* Local problems are defined as tty port, or modem problems:
* problems that can be worked around by using a different device.
* 2) (codes 12-15) Remote problems are phone busy, no answer, etc.
* : attempts to connect to this remote system should be stopped.
*
* Documents: Smartmodem 1200/1200b manual
*
* Recommended switch settings for the Hayes Smartmodem 1200
*
* 1 2 3 4 5 6 7 8
* up up down up up up up down
*/
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termio.h>
#include <pwd.h>
#include <errno.h>
static char Sccsid[] = "@(#) dialHA12.c 1.5 86/12/18 ";
/* return codes: these are set up so that an abort signal at any time can */
/* set the fail bit and return to the caller with the correct status */
#define RC_BAUD 0x0f /* CBAUD connected at (0=same as dialed speed)*/
#define RC_ENABLED 0x10 /* enabled flag: 1 = ungetty -r required to */
/* restore the line */
#define RC_FAIL 0x80 /* 1 = failed to connect */
/* return code error codes */
#define RCE_NULL 0 /* general purpose or unknown error code */
#define RCE_INUSE 1 /* line in use */
#define RCE_SIG 2 /* signal aborted dialer */
#define RCE_ARGS 3 /* invalid arguments */
#define RCE_PHNO 4 /* invalid phone number */
#define RCE_SPEED 5 /* invalid baud rate -or- bad connect baud */
#define RCE_OPEN 6 /* can't open line */
#define RCE_IOCTL 7 /* ioctl error */
#define RCE_TIMOUT 8 /* timeout */
#define RCE_NOTONE 9 /* no dial tone */
#define RCE_BUSY 13 /* phone is busy */
#define RCE_NOCARR 14 /* no carrier */
#define RCE_ANSWER 15 /* no answer */
#define SUCCESS 0
/* ungetty return codes */
#define UG_NOTENAB 0
#define UG_ENAB 1
#define UG_RESTART 1
#define UG_FAIL 2
#define SAME 0
#define MAXLINE 80
#define UNGETTY "/usr/lib/uucp/ungetty"
#define DEBUG(l, f, s) if (Debug >= l) fprintf(stderr, f, s)
#ifndef DBG
#define DBG 0
#endif
/*
* MDSETUP - No echo, enable result codes, tone dial, set escape to +++.
*/
#define MDSETUP "ATX3E0V1S2=043\r"
/*
* MDVALID - Allow only these characters to reach the modem.
*/
#define MDVALID "0123456789TPW/,*#()-"
/*
* MDESCAPE - Takes modem out of online state to accept commands.
*/
#define MDESCAPE "+++"
/*
* MDHANGUP - Force modem to drop carrier.
*/
#define MDHANGUP "ATH\r"
/*
* MDRESET - Reset modem to default power-up state.
*/
#define MDRESET "ATQ0Z\r"
/*
* MDDIALIN - Setup modem for dial in
*/
#define MDDIALIN "ATS0=1Q1\r"
/*
* MDDSBLESC - Disable escape sequence
*/
#define MDDSBLESC "ATS2=128\r"
/*
* These defines are used to determine how long the dialer timeout
* should be. MDPULSDLY can be changed, but MDPAUSDLY requires
* reprogramming modem register S8 to be effective.
*/
#define MDPULSCHR 'P'
#define MDPULSDLY 15
#define MDPAUSCHR ','
#define MDPAUSDLY 2
#define DIAL_RETRY 4
/*
* Possible messages produced by modem.
* We ignore RING since the HAYES only produces it when answering.
*/
#define OK 0
#define NOCARRIER 1
#define ERROR 2
#define BUSY 3
#define NOANSWER 4
#define NODIALTONE 5
#define CONNECT1200 6
#define CONNECT 7
char *mdmsgs[] = {
/* 0 */ "OK",
/* 1 */ "NO CARRIER",
/* 2 */ "ERROR",
/* 3 */ "BUSY",
/* 4 */ "NO ANSWER",
/* 5 */ "NO DIALTONE",
/* 6 */ "CONNECT 1200",
/* 7 */ "CONNECT",
0
};
char *strchr();
int alrmint();
struct termio term;
int Debug = DBG; /* set when debug flag is given */
int dialing; /* set while modem is dialing */
int fd = -1; /* file descriptor for acu */
int retcode = RC_FAIL; /* return code */
char User[10] = "unknown"; /* user id for logfile entries */
char Rmtname[] = "unknown"; /* remote system for logfile */
abort(sig)
int sig;
{
signal(SIGINT, SIG_IGN);
if (fd != -1) {
ioctl(fd, TCGETA, &term);
term.c_cflag |= HUPCL; /* make sure modem hangs up */
ioctl(fd, TCSETA, &term);
close(fd);
}
if (sig) retcode |= (RC_FAIL | RCE_SIG);
exit(retcode);
}
main(argc,argv)
int argc;
char *argv[];
{
char *acu; /* device to dial through */
char *phone; /* phone number to dial */
char command[MAXLINE]; /* modem command buffer */
int errflag = 0; /* set on errors */
int hflag = 0; /* set to hangup modem */
int timeout; /* how long to wait for alarm */
int dial_retry = DIAL_RETRY; /* dial retry count */
int highbaud, lowbaud; /* baud rate limits */
extern int optind;
extern char *optarg;
int c, pid;
char *p;
struct passwd *pwd, *getpwuid();
/*
* Reenable all those signals we want to know about
*/
signal(SIGILL, SIG_DFL);
signal(SIGIOT, SIG_DFL);
signal(SIGEMT, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGSYS, SIG_DFL);
signal(SIGTERM, SIG_DFL);
while ((c = getopt(argc, argv, "hx:")) != EOF)
switch(c) {
case 'h':
hflag++;
break;
case 'x':
Debug = atoi(optarg);
break;
case '?':
errflag++;
break;
}
if (Debug) {
fprintf(stderr, "dialer args ");
for (c=0; c<argc; c++) fprintf(stderr, ":%s", argv[c]);
fprintf(stderr, "\n");
}
if (hflag) {
if (argc - optind != 2) errflag++ ;
} else {
if (argc - optind != 3) errflag++ ;
}
if (errflag) {
if (hflag)
fprintf(stderr,"Usage: %s -h devicename speed\n",
argv[0]);
else
fprintf(stderr,"Usage: %s devicename number speed\n",
argv[0]);
exit(RC_FAIL | RCE_ARGS);
}
acu = argv[optind++];
if (!hflag) {
phone = argv[optind++];
if (strlen(phone) != strspn(phone, MDVALID)) {
fprintf(stderr, "dial: Bad phone number %s\n", phone);
exit(RC_FAIL | RCE_PHNO);
}
}
lowbaud = highbaud = checkbaud(atoi(argv[optind]));
/* test for a range of baudrates */
if ((p = strchr(argv[optind], '-')) != NULL) {
*p++ = '\0';
highbaud = checkbaud(atoi(p));
}
if (!hflag) {
if ((pid = fork()) == 0) {
DEBUG(6, "dialer: %s called\n", UNGETTY);
execl(UNGETTY, "ungetty", acu, NULL);
fprintf(stderr, "ungetty exec error\n");
exit(-1);
}
while (((c = wait(&errflag)) != pid) && c != -1);
switch ((errflag>>8) & 0xff) {
case UG_NOTENAB: /* line acquired: not enabled */
retcode = SUCCESS;
break;
case UG_ENAB: /* line acquired: need ungetty -r when done */
retcode = RC_ENABLED;
break;
case UG_FAIL: /* could not acquire line */
exit(RC_FAIL | RCE_INUSE);
case 255:
exit(RC_FAIL);
}
}
/*
* Must open with O_NDELAY set or the open may hang.
*/
if ((fd = open(acu, O_RDWR | O_NDELAY)) < 0) {
fprintf(stderr, "dial: Can't open device: %s\n", acu);
exit(RC_FAIL | RCE_OPEN | retcode);
}
/*
* set line for no echo and correct speed.
* We will issue commands to the Hayes 1200 at the highest possible
* baud rate to encourage connection at the highest baud rate.
* If hanging up, issue commands at 1200 to enable auto answer
* at 1200.
*/
signal(SIGINT, abort);
errflag = ioctl(fd, TCGETA, &term);
term.c_cflag &= ~(CBAUD | HUPCL);
term.c_cflag |= CLOCAL | (hflag ? (B1200|HUPCL) : highbaud);
term.c_lflag &= ~ECHO;
term.c_cc[VMIN] = '\1';
term.c_cc[VTIME] = '\0';
errflag = ioctl(fd, TCSETA, &term);
if (errflag) {
char buf[16];
DEBUG(1, "dial: ioctl error on %s", acu);
DEBUG(1, " errno=%d\n", errno);
cleanup(RC_FAIL | RCE_IOCTL | retcode);
}
/*
* Reopen line with clocal so we can talk without carrier present
*/
c = fd;
if ((fd = open(acu, O_RDWR)) < 0) {
fprintf(stderr, "dial: Can't open device local: %s\n", acu);
exit(RC_FAIL | RCE_OPEN | retcode);
}
close(c);
/*
* Timeout after 10 seconds if no response
*/
timeout = 10;
signal(SIGALRM, alrmint);
/*
* Hangup and exit if requested
*/
if (hflag) {
hangup(timeout);
mdwrite(MDDSBLESC); /* disable escape */
/* call ungetty to see if we need to switch to dialin */
if ((pid = fork()) == 0) {
execl(UNGETTY, "ungetty", "-t", acu, NULL);
exit(-1);
}
while (((c = wait(&errflag)) != pid) && c != -1) ;
if (((errflag>>8) & 0xff) != UG_RESTART) cleanup(SUCCESS);
/* setup modem for dialin */
/* note: mdwrite(MDDIALIN) will never work because */
/* the last modem command disables "OK" */
mdwrite(MDDIALIN); /* return to dial in mode */
if ((pid = fork()) == 0) {
execl(UNGETTY, "ungetty", "-r", acu, NULL);
exit(-1);
}
while (((c = wait(&errflag)) != pid) && c != -1) ;
cleanup( ((errflag>>8) & 0xff) ? RC_FAIL : SUCCESS ) ;
}
/*
* Reset and put modem into command mode
*/
reset:
if (mdwrite(MDRESET) == -1)
cleanup(RC_FAIL | retcode);
if (mdread(timeout) != OK) {
if (hangup(timeout) == -1)
cleanup(RC_FAIL | retcode);
goto reset;
}
/*
* Must wait at least 0.5 seconds after reset
* for HAYES to recover and receive commands.
*/
sleep(1);
/*
* Initialize the modem
*/
if (mdwrite(MDSETUP) == -1)
cleanup(RC_FAIL | retcode);
if (mdread(timeout) != OK) {
if (hangup(timeout) == -1)
cleanup(RC_FAIL | retcode);
goto reset;
}
/*
* Build up the phone number
*/
sprintf(command, "ATD%s\r", phone);
/*
* Set up a timeout for the connect.
* Add in MDPAUSDLY seconds more for each pause character
* Pulse dialing takes MDPULSDLY seconds longer too
*/
timeout = 6 * strlen(phone) + 15;
for (p = phone; (p = strchr(p, MDPAUSCHR)) != NULL; p++)
timeout += MDPAUSDLY;
if (strchr(phone, MDPULSCHR) != NULL)
timeout += MDPULSDLY;
if (timeout < 30)
timeout = 30;
/* command string can only be 40 characters excluding "AT" */
if (strlen(command) > 42)
cleanup(RC_FAIL | RCE_PHNO | retcode);
redial:
if (mdwrite(command) == -1)
cleanup(RC_FAIL | retcode);
dialing = 1;
DEBUG(6, "wait for connect - timeout %d\n", timeout);
switch (mdread(timeout)) {
case OK:
case ERROR:
if (dial_retry--) goto redial;
cleanup(RC_FAIL | RCE_NULL | retcode);
case CONNECT:
cleanup(retcode);
case CONNECT1200:
c = matchbaud(B1200, lowbaud, highbaud);
cleanup(retcode | c);
case NOANSWER:
cleanup(RC_FAIL | RCE_ANSWER | retcode);
case NODIALTONE:
cleanup(RC_FAIL | RCE_NOTONE | retcode);
case NOCARRIER:
cleanup(RC_FAIL | RCE_NOCARR | retcode);
case BUSY:
cleanup(RC_FAIL | RCE_BUSY | retcode);
default:
cleanup(RC_FAIL | retcode);
}
}
/*
* hangup(htime)
*
* Function: Forces the modem to drop carrier and hang up the phone.
* Reads are allowed htime seconds before timeout.
*
* Returns: 0 if disconnect completed.
* -1 on failure, phone may still be connected.
*
*/
nil() {}
hangup(htime)
int htime;
{
int retry = 4, rcode;
int (*s)();
DEBUG(4, "hangup - timeout %d\n", htime);
sleep(1);
rcode = -1;
s = signal(SIGALRM, nil); /* alarms are non-fatal here */
while (retry-- && rcode == -1) {
if (mdwrite(MDESCAPE) == -1)
return(-1);
sleep(1);
/*
* MDESCAPE will return OK only if online, so ignore error return
*/
mdflush() ; /* waste "OK" if we were on line */
if (mdwrite(MDHANGUP) == -1)
return(-1);
if (mdread(htime) == OK)
rcode = 0;
}
signal(SIGALRM, s);
return(-1);
}
/*
* mdread(rtime)
*
* Function: Reads from the ACU until it finds a valid response (found
* in mdmsgs) or times out after rtime seconds.
*
* Returns: The index in mdmsgs of the modem response found.
* -1 on timeout.
*
*/
mdread(rtime)
int rtime;
{
char c, **mp;
register char *bp;
char buf[MAXLINE];
bp = buf;
alarm(rtime);
DEBUG(6, "MODEM returned %s", "<<");
while (read(fd, &c, 1) == 1) {
if ((*bp = c) != '\0')
*++bp = '\0';
DEBUG(6, (c >= 040 ? "%c" : "^%c"), (c >= 040 ? c : c+0100));
if (bp >= buf + MAXLINE) {
alarm(0);
DEBUG(4,">>-%s\n","FAIL");
return(-1);
}
if (c == '\r')
for (mp = mdmsgs; *mp; ++mp)
if (substr(*mp, buf) == 0) {
alarm(0);
DEBUG(6,">>-%s\n", "OK");
DEBUG(4,"got %s\n",mdmsgs[mp - mdmsgs]);
return(mp - mdmsgs);
}
}
alarm(0);
DEBUG(6,">>-%s","FAIL");
DEBUG(4, " no responce\n", 0);
return(-1);
}
/* mdflush()
*
* Function: Flushes input clists for modem
*/
mdflush()
{
ioctl(fd, TCFLSH, 0) ;
}
/*
* mdwrite(c)
*
* Function: Outputs the string pointed to by c to the ACU device.
*
* Returns: 0 on completion.
* -1 on write errors.
*
*/
mdwrite(c)
register char *c;
{
int err;
/*
* Give modem a chance to recover before writing.
*/
sleep(1);
DEBUG(6, "Sent MODEM %s", "<<");
while (*c) {
if ((err = write(fd, c, 1)) != 1) {
char buf[16];
DEBUG(6, ">>-%s\n", "FAIL");
DEBUG(1, "ACU write error (errno=%d)\n", errno);
return(-1);
}
DEBUG(6, (*c >= 040 ? "%c" : "^%c"),(*c >= 040 ? *c : *c+0100));
c++;
}
DEBUG(6, ">>-%s\n", "OK");
return(0);
}
/*
* substr(s, l)
*
* Function: Checks for the presence of the string pointed to by s
* somewhere within the string pointed to by l.
*
* Returns: 0 if found.
* -1 if not found.
*/
substr(s, l)
char *s;
register char *l;
{
int len;
len = strlen(s);
while ((l = strchr(l, *s)) != NULL) {
if (strncmp(s, l, len) == SAME)
return(0);
l++;
}
return(-1);
}
/*
* alrmint()
*
* Function: Catches alarm calls (signal 14) and exits.
*
* Returns: No return. Exits with status RC_FAIL.
*/
alrmint()
{
DEBUG(4, "\nTimeout waiting for %s\n", dialing ? "carrier" : "acu");
cleanup(RC_FAIL | RCE_TIMOUT | retcode);
}
/*
* cleanup(stat)
*
* Function: Closes device file and exits.
*
* Returns: No return. Exits with status stat.
*/
cleanup(stat)
int stat;
{
if (stat & RC_FAIL) { /* if we failed, drop DTR (in abort) */
retcode = stat;
abort(0);
} else { /* else, return */
exit(stat);
}
}
/*
* checkbaud(n)
*
* Function: Check for valid baud rates
*
* Returns: The baud rate in struct termio c_cflag fashion
*
*/
checkbaud(n)
int n;
{
int baudrate;
switch(n) {
case 300:
baudrate = B300;
break;
case 1200:
baudrate = B1200;
break;
default:
fprintf(stderr, "dial: Bad speed: %d\n", n);
exit(RC_FAIL | RCE_SPEED);
}
return(baudrate);
}
/*
* matchbaud(connect, high, low)
*
* Function: determine dialer return code based on connect, high, and low
* baud rates
*
* Returns: 0 if connected baud == high baud
* Bxxxx if low baud <= connected baud <= high baud
* RCE_NOCARR if connected baud rate is out of range
* (actually, bad carrier not 'no carrier'
* but its a remote problem so RCE_SPEED
* is clearly wrong)
*/
matchbaud(cbaud, low, high)
int cbaud, low, high;
{
if (cbaud == high) return(0); /* uucp/cu assume highest baud */
if (low <= cbaud && cbaud <= high) return(cbaud);
return(RC_FAIL | RCE_SPEED);
}