bidirectional getty for SystemV - also does ringback

Paul Traina pst at anise.acc.com
Sun Jul 16 04:35:05 AEST 1989


The following program is a getty that runs under SystemV and is compatible
with any one of the three major "popular" uucp programs (4.3bsd, USG, HDB).
One nice feature about this getty is it has a ringback mode which can allow
you to utilize your modem line for voice and data without causing confusion.

This getty talks to the modem and will automatically determine baudrates
et al.  It has successfully be utilized on:
	MacII w/A/UX running with both trailblazers and 2400 baud modems
	Microport SV/AT			""
	Unix-PC 7300 running with slow modems

Any questions?  Send me mail.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  rb.c
# Wrapped by pst at anise.ac on Sat Jul 15 11:34:01 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'rb.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rb.c'\"
else
echo shar: Extracting \"'rb.c'\" \(12061 characters\)
sed "s/^X//" >'rb.c' <<'END_OF_FILE'
X/******************************************************************************
X
XRingback.c V1.7		13-Jun-1989
X
XThis program implements a ring-back system that allows a phone line 
Xthat is normally used as a voice line and a dial-out data line to be 
Xused as a limited dial-in data and voice line.  It does not interfere 
Xwith the use of the line for an answering machine.  
X
XIf the ringback feature is disabled,  it will act as an intelligent
Xbi-directional getty program with proper locking for the uucp directories.
X
XIt solves a problem for my situation:
X
X1) I am normally in my office.  The phone line is used for dial-out via
X   modem and dial-in/dial-out voice traffic.
X
X2) I sometimes travel, at which time I connect an answering machine to
X   the line.  
X
X3) I'd like to be able to call in to my system via modem when I am 
X   travelling, without interfering with others use of my answering 
X   machine.  
X
X4) I don't want to pay for another phone line.
X
XThis implements a ringback dialin system.  Just call, let the remote line
Xring once, hangup, wait a second, and dial a second time.
X
XIf the program notices that a user (uucp or kermit) is using the line 
Xfor an outgoing call, it will back off until that call is completed.  
X(Note: the first modem response char will be eaten.  Uucp dialing scripts 
Xshould be set up to tolerate this.) 
X
XTwo arguments must be present - tty & speed, one more additional argument
Xif present, will be an output file for debug information.
X
XSample lines from /etc/inittab:
X     rb:1234:respawn:/etc/ringback tty1 2400 [debug-output-file]
X					^^^^
X					speed to talk to modem!
X
XDon't worry about speed being "locked" at 2400 baud, ringback will
Xexec the getty with the proper speed (300, 1200, or 2400, or whatever).
X
XYou will have to make a gettydefs entry for the baud rate if you haven't
Xalready.  For example,  my A/UX system with a Trailblazer and a slower
X2400 baud modem has the following entries:
X
X19200# EXTA # EXTA  HUPCL SANE2 TAB3 # MODEM ~DTR ~FLOW #\r\nlogin: #19200
X9600# B9600 # B9600 HUPCL SANE2 TAB3 # MODEM ~DTR ~FLOW #\r\nlogin: #9600
X2400# B2400 # B2400 HUPCL SANE2 TAB3 # MODEM ~DTR ~FLOW #\r\nlogin: #2400
X1200# B1200 # B1200 HUPCL SANE2 TAB3 # MODEM ~DTR ~FLOW #\r\nlogin: #1200
X300#  B300  # B300  HUPCL SANE2 TAB3 # MODEM ~DTR ~FLOW #\r\nlogin: #3000
X
XTo install:
X
X1) Edit defines below
X2) Compile and install as /etc/ringback
X3) Create an initab line like the above one.
X
X				- Paul Traina (pst at anise.acc.com)
X				adapted from work by:
X 				- Jon Zeeff (umix!b-tech!zeeff)
X
XThis program is in the public domain.  No one is begging for money, however
Xwe would appreciate it if you continue to distribute this program with proper
Xcredit due to Jon & Paul.  If you want to sell the program,  fine;  make a
Xbuck off of our work,  but it would be nice if your stuff our names in the
Xdocumentation and object code somewhere.  If you like the program, great
X(I'd like to hear from you).  If you don't, sorry, but you get what you
Xpay for. If you find any problems (I've done a lot of tuning to get around
XSystemV bugs with the process group stuff) let me know.  If you find yet
Xanother use for it,  I'd be glad to hear about that too.
X
X				- Paul Traina
X
X******************************************************************************/
X
X#define NORB				/* disable ringback feature */
X#define TELEBIT				/* using Telebit Trailblazer modem */
X/* #define HDB_UUCP			/* honey danber uucp & locks */
X/* #define BSD43_UUCP			/* 4.3bsd uucp lock directory
X					   instead of HDB or USG */
X
X/* the id and gid for normal ownership of tty lines (usually uucp) */
X
X#define TTYID		5		/* uucp */
X#define TTYGID		11		/* modem */
X
X/*****************************************************************************/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <fcntl.h>
X#include <termio.h>
X#include <varargs.h>
X#include <time.h>
X#include <utmp.h>
X
Xchar		*strcpy();
Xchar		*strcat();
Xunsigned	sleep();
Xunsigned	alarm();
Xvoid		exit();
X
X#define	TIMEOUT	-1
X
Xchar dbg_name[255];
Xint tty;
Xstruct termio ttymodes;
Xstatic jmp_buf sjbuf;
X
X
X/* print debug message on console */
X
X/*VARARGS0*/
Xvoid debug(va_alist)
Xva_dcl
X{
X	va_list		 args;
X	char		*fmt;
X	struct tm	*t;
X	long		 clock;
X	static FILE	*fp = NULL;
X
X	if (*dbg_name == '\0')
X	    return;
X	else {
X	    if (fp == NULL)
X		if ((fp = fopen(dbg_name, "a")) == NULL)
X		    return;
X	    (void) time(&clock);
X	    t = localtime(&clock);
X
X	    (void) fprintf(fp, "[%02d/%02d %02d:%02d] ", t->tm_mon+1,
X				t->tm_mday, t->tm_hour, t->tm_min);
X	    va_start(args);
X	    fmt = va_arg(args, char *);
X	    (void) vfprintf(fp, fmt, args); 
X	    (void) fprintf(fp, "\n");
X	    fflush(fp);
X	    va_end(args);
X	}
X}
X
X/* send a string to modem, sleep n seconds after doing so */
X
Xvoid sendmodem(string, t)
Xchar *string;
Xint t;
X{
X	debug("sent: %s", string);
X	write(tty, string, strlen(string));		/* send out string */
X	if (t)
X		sleep(t);
X}
X
X/* flush input buffer */
Xvoid eatall() { ioctl(tty, TCFLSH, 0); }
X
X/*	flag timeout as having occured, do longjump into waitfor */
Xvoid expired() { longjmp(sjbuf, 1); }
X
X
X/* waitfor will wait 'timeout' seconds for a character, returning
X   the character immediately if found, otherwise returning TIMEOUT.  */
X
Xchar	waitfor(timeout)
Xint	timeout;
X{
X	char	c;
X
X	signal(SIGALRM, expired);
X	alarm(timeout);
X
X	if (setjmp(sjbuf)) {
X	    signal(SIGALRM, SIG_DFL);
X	    debug("timeout!");
X	    return TIMEOUT;
X	} else {
X	    do {
X		while (read(tty, &c, sizeof(c)) != 1)
X		    ;
X		c &= 0x7f;
X	    } while (c == '\r' || c == '\n'); /* ignore crlfs */
X	    alarm(0);
X	    signal(SIGALRM, SIG_DFL);
X	    return (c & 127);
X	}
X}
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	char	result;
X	struct stat buf;
X	char	tty_lock[100];
X	char	tty_name[100];
X	int	speed, baud, modemspeed;
X	char	aspeed[10];
X	FILE    *lock;
X
X	close(0);	/* close stdin */
X	close(1);	/* close stdout */
X	close(2);	/* close stderr */
X	fclose(stdin);
X	fclose(stdout);
X	fclose(stderr);
X
X	/* name and location of tty locks - change this as needed */
X#ifndef	HDB_UUCP
X# ifdef BSD43_UUCP				/* berkeley 4.3 uucp */
X	strcpy(tty_lock, "/usr/spool/uucp/LCK/LCK..");
X# else						/* System 5.2 uucp */
X	strcpy(tty_lock, "/usr/spool/uucp/LCK..");
X# endif
X#else						/* HDB uucp */
X	strcpy(tty_lock, "/usr/spool/locks/LCK..");
X#endif
X	if (argc == 4) 
X	    strcpy(dbg_name, argv[3]);
X	else
X	    *dbg_name = '\0';
X
X	if (argc < 3 && argc > 4) {
X		debug("invalid number of parameters, exiting");
X		exit(2);
X	}
X
X	strcat(tty_lock, argv[1]);
X	strcpy(tty_name, "/dev/");
X	strcat(tty_name, argv[1]);
X
X	modemspeed = atoi(argv[2]);	/* speed to talk to modem */
X	switch (modemspeed) {
X		case 300:	baud = B300;   break;
X		case 1200:	baud = B1200;  break;
X		case 2400:	baud = B2400;  break;
X		case 4800:	baud = B4800;  break;
X		case 9600:	baud = B9600;  break;
X		case 19200:	baud = EXTA;   break;
X		default:	debug("invalid baud rate"); exit(2);
X	}
X
X	unlink(tty_lock);	/* always existed because user was there */
X	umask(022);
X
X	signal(SIGHUP, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X
X	for (;;) {
X
X	/* Set the permissions, owner, and group for dial-out use */
X
X	    chown(tty_name, TTYID, TTYGID);
X	    chmod(tty_name, 0662);
X
X	    if ((tty  = open(tty_name, O_RDWR, 0662)) == -1) {
X		debug("error opening %s", tty_name);
X		exit(2);
X	    }
X
X	    ttymodes.c_iflag = 0;
X	    ttymodes.c_oflag = NL1 | CR3;
X	    ttymodes.c_cflag = 0;	/* drop dtr */
X	    ttymodes.c_lflag = 0;
X	    ttymodes.c_line  = 0;
X	    ttymodes.c_cc[VMIN]  = 1;	/* min number of characters */
X	    ttymodes.c_cc[VTIME] = 0;  	/* no max time before return */
X	    ioctl(tty, TCSETA, &ttymodes);  /* hang up the line */
X	    sleep(1);
X	    ttymodes.c_cflag = baud | CS8 | CREAD | HUPCL;
X	    ioctl(tty, TCSETA, &ttymodes);
X	    sleep(1);
X
X	    debug("remote line setup");
X
X	    do {
X		sendmodem("\rAT\r", 1);		/* set baudrate */
X		sendmodem("ATE0\r", 2);		/* turn off echo */
X		eatall();			/* flush input buffer */
X
X#ifdef	TELEBIT
X		sendmodem("AT&EE0X1V0S2=128S58=0\r", 0);
X#else
X		sendmodem("ATV0Q0S0=0S2=128M3X1S10=25\r", 0);
X#endif
X
X		do {
X		    result = waitfor(1); /* wait 1s for result */
X		    debug("program modem result=<%c> (%d)", result, result);
X		} while (result != '0' && result != '4' && result != TIMEOUT);
X
X		if (result == '4')
X		    debug("modem program error");
X		if (result == TIMEOUT)
X		    debug("modem timed out");
X		if (result != '0')
X		    sleep(10);	/* wait ten seconds */
X
X	    } while (result != '0');	/* need "OK" from modem */
X
X	    sleep(2);
X	    eatall();
X
X	/* Wait for incoming call ('2') or other usage (uucp or user) */
X
X	    while (read(tty,  &result, sizeof(result)) != 1)
X		;
X
X	/* If we receive a '2' and no lock file is present, we can
X	   be sure that it is not someone calling out. */
X
X	    result &= 127;				/* strip parity */
X
X	    debug("received a character <%c> (%d)", result, result);
X
X	    if (result == '2' && stat(tty_lock, &buf) == -1) {
X		/* create a hdb style lock file */
X		if ((lock = fopen(tty_lock, "w", 0444))) {
X#ifdef HDB_UUCP
X		    fprintf(lock, "%10d\n", getpid());
X#else
X		    putw(getpid(), lock);
X#endif
X		    fclose(lock);
X		}
X
X#ifndef	NORB
X		debug("waiting for second ring...");
X
X		do {
X		    result = waitfor(8);	/* wait 8 seconds */
X		} while (result != '2' && result != TIMEOUT);
X
X		if (result == '2') {
X		    debug("second ring detected, waiting for third ring...");
X		    do {
X			result = waitfor(8);	/* wait 8 seconds */
X		    } while (result != '2' && result != TIMEOUT);
X		}
X
X		if (result == '2') {		/* got third ring */
X		    debug("voice call");
X		    unlink(tty_lock);
X		    sleep(60);	/* wait long enough for human or answering
X				   machine to pick up call */
X
X		} else {	/* must be timeout (no second ring) */
X		    debug("waiting 45 seconds for second call");
X		    sleep(3);
X		    eatall();
X		    result = waitfor(42);
X		    speed  = 0;
X
X		    if (result != '2') {
X			debug("didn't get ring for second call");
X			unlink(tty_lock);
X		    } else {
X#endif
X			debug("answering phone");
X			sendmodem("ATA\r", 1); 
X			eatall();
X			result = waitfor(60);
X			switch (result) {
X			    case TIMEOUT:	
X				debug("answer call timeout"); break;
X			    case '3':
X			    case '8':
X				debug("no carrier"); break;
X			    case '4':	
X				debug("phone answer error"); break;
X			    case '5':	
X				result = waitfor(1);
X				if (result == '0') {
X				    debug("FAST call");
X				    speed = 19200;
X				} else {
X				    debug("1200 baud call");
X				    speed = 1200;
X				}
X				break;
X			    case '1':	
X				result = waitfor(1);
X				if (result == '0') {
X				    debug("2400 baud call");
X				    speed = 2400;
X				} else { 
X				    debug("300 baud call");
X				    speed = 300;
X				}
X				break;
X			    default:	
X				debug("unknown character <%c> (%d)",
X					result, result);
X			} /* end switch */
X
X			eatall();	/* clear out initial crap */
X
X			if (speed == 0) {
X			    debug("invalid answer code from modem");
X			    unlink(tty_lock);
X			} else {
X			    debug("execing getty");
X#ifdef TELEBIT		/* telebit is programmed to always talk fast */
X			    sprintf(aspeed, "%d", modemspeed);
X#else
X			    sprintf(aspeed, "%d", speed);
X#endif
X			/* to circumvent a system5 process group bug,
X			 * we'll turn off hangup-after-last-close, let
X			 * getty close the channel to the tty & reopen it.
X			 * this (hopefully) will make getty be able to always
X			 * fopen /dev/tty
X			 */
X			    ttymodes.c_cflag &= ~HUPCL;
X			    ioctl(tty, TCSETA, &ttymodes);
X			    sleep(1);
X
X			    execl("/etc/getty", "getty", "-h", "-t", "90",
X				argv[1], aspeed, (char *)0);
X
X			    debug("exec of getty failed");
X			}
X#ifndef	NORB
X		    }		/* endif got second call */
X		}
X#endif
X            } else { /* result != 2 -->  Must be someone using line */
X
X		debug("giving up line to uucp or user");
X		close(tty);		/* Release line */
X		sleep(60);
X
X	/* Loop until lock file goes away (uucp or user done) */
X
X		do {
X		    while (stat(tty_lock, &buf) == 0)
X			sleep(40);
X		    sleep(20);
X		}  while (stat(tty_lock, &buf) == 0);
X
X	    } /* endif result != 2 */
X	} /* for(;;) */
X}
END_OF_FILE
if test 12061 -ne `wc -c <'rb.c'`; then
    echo shar: \"'rb.c'\" unpacked with wrong size!
fi
# end of 'rb.c'
fi
echo shar: End of shell archive.
exit 0
-- 
    "Calling people sexist because they are into S/M is like calling
     people capitalist because they like to play Monopoly(TM)."
			    -- `Ask Aunt Sadie' / the Ministry of Truth



More information about the Comp.unix.aux mailing list