[comp.os.minix] UUPC for Minix, part 3/5

housel@en.ecn.purdue.edu (Peter S. Housel) (07/03/89)

echo 'x - dcpunix.c'
sed 's/^X//' <<'**-dcpunix.c-EOF-**' >dcpunix.c
X/*
X * dcpunix.c - Unix/Minix support for dcp
X * Peter S. Housel
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sgtty.h>
X#include <dial.h>
X#include <signal.h>
X#include "dcp.h"
X
Xextern char *_merr_list[];
Xextern int merrno;
X
Xint timedout;		/* set when alarm goes off */
Xint swritefd;		/* fd for serial write */
Xint sreadfd;		/* fd for serial read */
XCALL call;		/* dial(3) structure */
X
Xint ontime()
X{
X signal(SIGALRM, ontime);
X timedout = 1;
X return 0;
X}
X
Xswrite(data, num)
Xchar *data; int num;
X{
X return write(swritefd, data, num);
X}
X
Xint sread(data, num, timeout)
Xchar *data; int num, timeout;
X{
X int ret;
X
X if(timeout)
X    alarm(timeout);
X else
X    alarm(2);
X signal(SIGALRM, ontime);
X
X ret = read(sreadfd, data, num);
X alarm(0);
X if(ret < 0)
X    return 0;
X return ret;
X}
X
Xint sread2(data, num)
Xchar *data; int num;
X{
X return read(sreadfd, data, num);
X}
X
Xshell(command, inname, outname, errname)
Xchar *command;
Xchar *inname;
Xchar *outname;
Xchar *errname;
X{
X int waitstat;
X int fd;
X
X printmsg(M_INFO, "shell: %s < %s > %s", command, inname, outname);
X
X if(strncmp(command, "rmail", 5) != 0 && strncmp(command, "rnews", 5) != 0)
X   {
X    printmsg(M_ERROR, "illegal command \"%s\"", command);
X    return;
X   }
X
X switch(fork())
X       {
X	case -1:
X		printmsg(M_ERROR, "couldn't fork");
X		return;
X	case 0:
X		if(strlen(inname) != 0)
X		  {
X		   fd = open(inname, 0);
X		   dup2(fd, 0);
X		   if(fd > 0)
X		      close(fd);
X		   printmsg(M_INFO, "Changed infile to %s, fd=%d", inname, fd);
X		  }
X		if(strlen(outname) != 0)
X		  {
X		   fd = creat(outname, 0644);
X		   dup2(fd, 1);
X		   if(fd > 1)
X		      close(fd);
X		  }
X		execl("/bin/sh", "sh", "-c", command, (char *)0);
X		printmsg(M_ERROR, "couldn't exec shell");
X		exit(1);
X	default:
X		wait(&waitstat);
X		if(waitstat != 0)
X		   printmsg(M_ERROR, "xqt status of 0x%x for command \"%s\"",
X			    command);
X       }
X}
X
Xint initline()
X{
X struct sgttyb ttyb;
X
X sreadfd = 0;	/* standard input */
X swritefd = 1;	/* standard output */
X
X gtty(sreadfd, &ttyb);	/* set raw mode */
X ttyb.sg_flags |= RAW;
X ttyb.sg_flags &= ~(XTABS | EVENP | ODDP | CRMOD | ECHO | CBREAK);
X stty(sreadfd, &ttyb);
X
X return 0;
X}
X
X
Xint dcpdial(dev, speed, tel)
Xchar *dev, *speed, *tel;
X{
X call.baud = call.speed = atoi(speed);
X call.line = dev;
X call.telno = tel;
X call.modem = 0;
X
X printmsg(M_CALL, "Dialing at speed %d", call.speed);
X if(tel != NULL)
X    printmsg(M_CALL, "Calling phone# %s", call.telno);
X if((sreadfd = swritefd = dial(&call)) < 0)
X   {
X    printmsg(M_ERROR, "dial failed, merror=%s (%d)",
X	     _merr_list[-merrno], merrno);
X    return FALSE;
X   }
X
X return TRUE;
X}
X
Xdcpundial()
X{
X if(swritefd > 2)
X    hangup(swritefd);
X}
**-dcpunix.c-EOF-**
echo 'x - dcputil.c'
sed 's/^X//' <<'**-dcputil.c-EOF-**' >dcputil.c
X/*
X * dcputil.c 
X *
X * Revised^2 edition of dcp 	Peter Housel Nov '88
X *
X * Revised editition of dcp	Stuart Lynne May/87 
X *
X * Copyright (c) Richard H. Lamb 1985, 1986, 1987
X * Changes Copyright (c) Stuart Lynne 1987 
X *
X * miscellaneous utility functions
X */
X#include "dcp.h"
X#include <ctype.h>
X#include <pwd.h>
X
X/*
X * |uucpname()| returns a pointer to the local host's UUCP nodename.
X * There are several possible means of determining this, depending
X * on the operating system version. For now, this version just reads
X * one line from the |NODENAME| file, which is usually either "/etc/cpu"
X * or "/etc/uucpname".
X */
Xchar *uucpname()
X{
X FILE *uufile;
X static char uuname[SITENAMELEN];
X
X if(NULL == (uufile = fopen(NODENAME, "r")))
X    return "";
X fgets(uuname, sizeof uuname, uufile);
X uuname[strlen(uuname) - 1] = '\0';	/* remove '\n' */
X fclose(uufile);
X
X return uuname;
X}
X
X/*
X * |printmsg(level, format, ...)| prints an error or debugging message
X * into the system error log file.  If not remote, also print to standard
X * error.  All messages at levels less than or equal to the current
X * |debuglevel| are printed.
X */
X/* VARARGS1 */
Xprintmsg(level, fmt, a1, a2, a3, a4, a5)
Xint level;
Xchar *fmt;
Xchar *a1, *a2, *a3, *a4, *a5;
X{
X char msg[512];
X
X if(level <= debuglevel)
X   {
X    sprintf(msg, fmt, a1, a2, a3, a4, a5);
X    strcat(msg, "\n");
X    if(remote == MASTER && debuglevel > 0)
X      fputs(msg, stderr);
X    fputs(msg, logfile);
X   }
X}
X
X/*
X * visib(data, length) prints the buffer of character data in "visible"
X * format. Printable characters (except '\') are printed as themselves,
X * special control characters (CR, LF, BS, HT) are printed in the usual
X * escape format, and others are printed using 3-digit octal escapes.
X * The usual warning about return value pointing to a static buffer which
X * is overwritten on each call applies here.
X */
Xchar *visib(data, len)
Xchar *data; int len;
X{
X static char buf[256];
X char c, *p;
X
X p = buf;
X while(len--)
X    {
X     c = *data++;
X     if(isascii(c) && (isprint(c) || ' ' == c))
X	*p++ = c;
X     else if('\n' == c)
X       {*p++ = '\\';
X	*p++ = 'n';
X       }
X     else if('\t' == c)
X       {*p++ = '\\';
X	*p++ = 't';
X       }
X     else if('\r' == c)
X       {*p++ = '\\';
X	*p++ = 'r';
X       }
X     else if('\b' == c)
X       {*p++ = '\\';
X	*p++ = 'b';
X       }
X     else
X       {sprintf(p, "\\%03o", c);
X	p += 4;
X       }
X    }
X *p = '\0';
X return buf;
X}
X
X/*
X * |getargs(str, argv)| breaks up |str|, which should be a string of
X * whitespace-separated fields, and places a pointer to each field
X * into the array pointed to by |argv|. The number of fields is
X * returned.
X */
Xint getargs(str, argv)
Xchar *str; char *argv[];
X{
X int nflds = 0;
X
X while(*str && isspace(*str))		/* leading space */
X       ++str;
X
X while(*str && '\n' != *str)
X      {
X       ++nflds;				/* field */
X       *argv++ = str;
X
X       while(*str && !isspace(*str))	/* skip to end of field */
X	     ++str;
X       *str++ = '\0';			/* and terminate it with a null */
X
X       while(*str && isspace(*str))	/* trailing space */
X             ++str;
X      }
X
X return nflds;
X}
X
X/*
X * |expandtilde(filename)| expands |filename| using the usual "~" convention.
X * That is, "~user" expands to the home directory of "user". "~" by itself
X * expands to the home directory of the effective userid, which in this
X * case is usually the /usr/spool/uucppublic directory. Care is taken not
X * to overflow the (static) name buffer.
X */
Xchar *expandtilde(filename)
Xchar *filename;
X{
X struct passwd *pw, *getpwnam(), *getpwuid();
X static char namebuf[PATHLEN];
X char *p;
X
X if('~' != *filename)
X    return filename;
X
X ++filename;
X p = namebuf;
X while(*filename && '/' != *filename && (p - namebuf) < PATHLEN)
X       *p++ = *filename++;
X *p = '\0';
X
X if(strlen(namebuf) == 0)
X    pw = getpwuid(geteuid());
X else
X    pw = getpwnam(namebuf);
X
X if(NULL == pw)
X    return NULL;
X
X if(strlen(pw->pw_dir) + strlen(filename) + 1 > PATHLEN)
X    return NULL;
X strcpy(namebuf, pw->pw_dir);
X strcat(namebuf, filename);
X return namebuf;
X}
**-dcputil.c-EOF-**
echo 'x - dcpxfer.c'
sed 's/^X//' <<'**-dcpxfer.c-EOF-**' >dcpxfer.c
X/*
X * dcpxfer.c 
X *
X * Revised edition of dcp 
X *
X * Stuart Lynne May/87 
X *
X * Copyright (c) Richard H. Lamb 1985, 1986, 1987 Changes Copyright (c) Stuart
X * Lynne 1987 
X *
X * "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987
X * file send routines
X */
X#include "dcp.h"
X#include <ctype.h>
X
Xextern int errno;
Xextern char *sys_errlist[];
X
Xstatic unsigned char rpacket[MAXPACK];
Xstatic unsigned char spacket[MAXPACK];
X
X/***************SEND PROTOCOL****************/
X
X/*
X * s d a t a 
X *
X * Send File Data 
X */
Xsdata()
X{
X while(TRUE)
X      {
X       if((size = fread(spacket, 1, pktsize, fp)) <= 0) /* Get data */
X	  return ('Z');		/* If EOF set state to that */
X       if((*sendpkt) (spacket, size, 0))
X	  return (0);		/* send data */
X      }
X
X return ('D');		/* sent data, stay in state D */
X}
X
X
X/*
X * s b r e a k 
X *
X */
Xsbreak()
X{
X int len, i;
X
X if(sendmsg("H") < 0)
X    return (0);
X if(getmsg(spacket) < 0)
X    return 0;
X printmsg(M_CONVERSE, "Switch modes: %s", spacket);
X if(spacket[1] == 'N')
X    return ('G');
X return ('Y');
X}
X
X
X/*
X * s e o f 
X *
X * Send End-Of-File. 
X */
Xseof()
X{
X int len, i;
X
X fclose(fp);
X fp = NULL;
X
X if((*sendpkt) (spacket, 0, 0) < 0)	/* length zero packet indicates EOF */
X    return (0);
X if(getmsg(spacket) < 0)
X    return (0);		/* receive CY or CN */
X if(strncmp(spacket, "CY", 2))
X    return (0);		/* couldn't send file */
X
X unlink(fromfile);
X printmsg(M_TRANSFER, "Transfer of %s completed.", fromfile);
X
X /*
X  * fprintf( syslog, "%s!%s (%d/%d-%d:%d:%d) -> %ld / %ld secs", host, id,
X  * size, secs ); 
X  */
X
X return ('F');		/* go get the next file to send */
X}
X
X/*
X * s f i l e 
X *
X * Send File Header. 
X */
Xsfile()
X{
X int i, len;
X char *cp;
X
X if(fp == NULL)
X   {				/* If not already open, */
X    printmsg(M_SPOOL, "looking for next file...");
X    if(getfile())
X      {				/* get next file from current work */
X       fclose(fw);
X       unlink(cfile);		/* close and delete completed workfile */
X       fw = NULL;
X       return ('B');		/* end sending session */
X      }
X
X
X    printmsg(M_SPOOL, "Opening %s for sending.", fromfile);
X    fp = fopen(fromfile, "r");	/* open the file to be sent */
X    if(fp == NULL)
X      {				/* If bad file pointer, give up */
X       printmsg(M_ERROR, "Cannot open file %s.", fromfile);
X       return ('A');
X      }
X   }
X else
X   return ('A');	/* If something's already open, we're in trouble */
X printmsg(M_SPOOL, "Sending %s as %s", fromfile, tofile);
X if(sendmsg(tofile) < 0)
X    return (0);		/* send 'S fromfile tofile user - tofile 0666'. */
X if(getmsg(spacket) < 0)
X   return (0);
X if (spacket[1] != 'Y')
X    return ('A');		/* If otherside says no-quit */
X return ('D');
X}
X
X/*
X * s i n i t 
X *
X * Send Initiate: send this host's parameters and get other side's back. 
X */
Xsinit()
X{
X if((*openpk) ())
X    return ('A');
X return ('B');
X}
X
X
X/* 
X *
X * getfile 
X *
X * getfile reads the next line from the presently open workfile (cfile) and
X * determines from this the next file to be sent (file). If there are no more
X * TRUE is returned. A fix for "R from to 0666" should be done here to
X * recieve files in addition to sending them. The appropriate "state
X * letter" i.e. "R" should be returned to the send "master" or "slave"
X * state switching table in "dcp.c" I did not implement this since the
X * majority of uucp transactions appear to be "S from to 0666" type.
X * RHLamb 1/87 
X */
Xgetfile()
X{
X int i;
X char line[132], buf[132];
X register char *cp;
X 
X if(fgets(line, BUFSIZ, fw) == (char *) NULL)
X    return (TRUE);
X
X sscanf(line, "%*c %*s %*s %*s %*s %s", buf);
X sprintf(fromfile, "%s/%s", SPOOLDIR, buf);
X
X for(i = 0, cp = line; *cp != '\0'; i++, cp++)
X    {
X     if(strncmp(cp, "0666", 4) == 0)
X        break;
X    }
X cp += 4;
X *cp = '\0';
X strcpy(tofile, line);
X printmsg(M_SPOOL, "getfile: fromfile=%s, tofile=%s.", fromfile, tofile);
X return (FALSE);
X}
X
X
X/*********************** MISC SUB SUB PROTOCOL *************************/
X
X/*
X *
X * schkdir
X * scan the dir 
X */
Xschkdir()
X{
X char c;
X
X c = scandir();
X if(c == 'Q')
X   {
X    return ('Y');
X   }
X if (c == 'S')
X   {
X    sprintf(rpacket, "HN");
X    if((*sendpkt) (rpacket, 0, 1))
X      return (0);
X   }
X return ('B');
X}
X
X/* 
X * endp() end protocol 
X *
X */
Xendp()
X{
X (void) sendmsg("HY");
X (*closepk) ();
X return ('P');
X}
X
X
X
X/***********************RECIEVE PROTOCOL**********************/
X
X/*
X * r d a t a 
X *
X * Receive Data 
X */
Xrdata()
X{
X int len;
X 
X if ((*getpkt) (rpacket, &len))
X    return (0);
X
X if(len == 0)
X   {
X    fclose(fp);
X    /* we ought to do the copy in a temp file, and move it here */
X    if(sendmsg("CY") < 0)
X      return (0);
X    printmsg(M_TRANSFER, "transfer complete");
X    return ('F');
X   }
X
X if(fwrite(rpacket, len, 1, fp) != 1)	/* Write the data to the file */
X    return (0);
X return ('D');			/* Remain in data state */
X}
X
X
X/*
X * r f i l e 
X *
X * Receive File Header 
X */
Xrfile()
X{
X char buf[256];
X char *flds[10];
X int numflds;
X 
X int len, i;
X char tmpfilename[256];	/* Holds the converted file name */
X char *cp;
X 
X printmsg(M_TRANSFER, "rfile entered");
X 
X if(getmsg(buf) < 0)
X    return 0;
X
X if(buf[0] == 'H')
X    return ('C');
X
X printmsg(M_TRANSFER, "rfile: buf %d \"%s\"", len, buf);
X
X /*
X  * Convert upper case to lower
X  * for(cp = buf; *cp != '\0';cp++)
X  *     if(isupper(*cp))
X  *	   tolower(*cp); 
X  */
X
X numflds = getargs(buf, flds);
X
X cp = flds[2];
X printmsg(M_INFO, "rfile: receive file \"%s\"", cp);
X
X /* check for ~/ destination -> /usr/spool/uucppublic */
X if (strncmp(cp, "~/", 2) == SAME)
X   sprintf(tmpfilename, "%s%s", PUBDIR, cp + 1);
X else
X   sprintf(tmpfilename, "%s/%s", SPOOLDIR, cp);
X printmsg(M_INFO, "rfile: receive file \"%s\"", tmpfilename);
X
X /* check for dirname only */
X cp = tmpfilename + strlen(tmpfilename) - 1;
X if (*cp == '\n')
X   *cp-- = '\0';
X 
X if(*cp == '/')
X   {
X    cp = rindex(flds[1], '/');
X    if(cp == (char *) NULL)
X       cp = flds[1];
X    else
X       cp++;
X
X    strcat(tmpfilename, cp);
X   }
X
X strcpy(tofile, tmpfilename);
X printmsg(M_TRANSFER, "rfile: receive file \"%s\"", tofile);
X
X if((fp = fopen(tofile, "w")) == NULL)
X   {				/* Try to open a new file */
X    printmsg(M_ERROR, "cannot create %s err=%s", tofile, sys_errlist[errno]);
X    return ('A');	/* Give up if can't */
X   }
X printmsg(M_TRANSFER, "Receiving %s as %s", flds[1], tofile);
X  if(sendmsg("SY") < 0)
X   return (0);
X return ('D');		/* Switch to data state */
X}
X
X/*
X * r i n i t 
X *
X * Receive Initialization 
X */
Xrinit()
X{
X if ((*openpk) ())
X   return (0);
X return ('F');
X}
X
X
X/*
X * |getmsg()| recieves a null-terminated "conversation-level" message
X * from the communications channel. This may require one or more packets,
X * but all of them will be "long-data" packets containing a full 64 bytes.
X */
Xint getmsg(dest)
Xchar *dest;
X{
X int len;
X
X while(1)
X      {
X       if((*getpkt)(dest, &len) < 0)
X          return -1;
X       *(dest + len) = '\0';		/* make sure it's terminated */
X       if(strlen(dest) != len)
X	  break;			/* we reached the terminator */
X       dest += len;
X      }
X
X return 0;
X}
X
X/*
X * |sendmsg(message)| sends a null-terminated "conversation-level" message.
X */
Xint sendmsg(message)
Xchar *message;
X{
X int len;
X len = strlen(message) + 1;		/* total length including '\0' */
X
X while(1)
X      {
X       if((*sendpkt)(message, 0, 1) < 0) /* send with padding */
X          return -1;
X       if((len -= pktsize) <= 0)
X          break;
X       message += pktsize;
X      }
X return 0;
X}
**-dcpxfer.c-EOF-**
mkdir lib.uucp; cd lib.uucp
echo  'x - lib.uucp/'
echo 'x - L-devices'
sed 's/^X//' <<'**-L-devices-EOF-**' >L-devices
X#type	line	foo	baud	brand
X#-----	------	------	------	------
XACU	tty1	foo	1200	promodem
**-L-devices-EOF-**
echo 'x - L.sys'
sed 's/^X//' <<'**-L.sys-EOF-**' >L.sys
Xnoname Any ACU 1200 867-5309 "" "" ogin:--ogin: uucp ssword: FATCHANCE
**-L.sys-EOF-**
echo 'x - LOGFILE'
sed 's/^X//' <<'**-LOGFILE-EOF-**' >LOGFILE
**-LOGFILE-EOF-**
echo 'x - SPOOLSEQ'
sed 's/^X//' <<'**-SPOOLSEQ-EOF-**' >SPOOLSEQ
X1
**-SPOOLSEQ-EOF-**
cd ..
mkdir modemcap; cd modemcap
echo  'x - modemcap/'
echo 'x - Makefile'
sed 's/^X//' <<'**-Makefile-EOF-**' >Makefile
X# Your library directory.
XLIBDIR=/usr/lib
X# Your local command directory.
XLBIN=/usr/housel/bin
X# OSFLAG=-DUNIX_S5	# For System V machines.
XOSFLAG=-DUNIX_V7	# For Version 7 machines.
X# For those poor people who need ranlib
X# RANLIB=ranlib $(LIBDIR)/libmodemcap.a
X# Standard Bourne shell.
XSHELL=/bin/sh
X
XCFLAGS=$(OSFLAG) -LIB
X# CFLAGS=-O
X# LDFLAGS=-s
X
XOFILES=mgetent.s mgetstr.s mgetflag.s mgetnum.s mdial.s merror.s \
X	initmodem.s hangup.s dial.s dialvars.s
X
XCFILES=mgetent.c mgetstr.c mgetflag.c mgetnum.c mdial.c merror.c \
X	initmodem.c hangup.c dial.c dialvars.c
X
XLFILES=	hangup.s\
X	dial.s\
X	dialvars.s\
X	initmodem.s\
X	mgetent.s\
X	mgetstr.s\
X	mgetflag.s\
X	mgetnum.s\
X	mdial.s\
X	merror.s\
X
Xall:	libmodemcap.a
X
Xlibmodemcap.a: $(LFILES)
X	ar r libmodemcap.a $(LFILES)
X
Xinstall:	all call
X	cp modemcap.h /usr/include
X	cp modemcap /etc/modemcap
X	cp modemtype /etc/modemtype
X	cp libmodemcap.a $(LIBDIR)
X	chmod 644 /usr/include/modemcap.h /etc/modemcap /etc/modemtype $(LIBDIR)/libmodemcap.a
X	cp call $(LBIN)/call
X	chmod 711 $(LBIN)/call
X
Xcall:	call.c libmodemcap.a
X	cc $(LDFLAGS) $(CFLAGS) call.c libmodemcap.a scanf.s -o call
X
Xinitmodem.s:	initmodem.c /usr/include/modemcap.h
X
Xmdial.s:	mdial.c /usr/include/modemcap.h
X
Xhangup.s:	hangup.c /usr/include/modemcap.h
X
Xdial.s:	dial.c	/usr/include/modemcap.h
X
Xshar:	README $(CFILES) makefile modemcap modemtype modemcap.h call.c
X	shar README makefile modemcap modemtype modemcap.h $(CFILES) call.c > modem.shar
**-Makefile-EOF-**
echo 'x - README'
sed 's/^X//' <<'**-README-EOF-**' >README
XThis package is a modem independent dial(3) package.  It provides a device
Xindependent method for dialing and manipulating modems.  The format of the
Xdescription file is the ever present ;-) termcaps format.  You may want to
Xread the modemcap file to see just what capabilities are present.
X
XThis is Release 1.1 of this software.  Please bear in mind that I haven't
Xreleased this to the public before this release.
X
X--< Start of the legal conditions of this software >--
X
XThis software is copyright 1987 John F. Haugh II, all rights reserved.
XUse, duplication and disclosure subject to the terms and conditions of
Xthe license agreement below.  This notice is intended to have legal
Xsignificance, and not to be taken lightly.  If you have any questions,
Xplease contact the author at the address below.  This copyright covers
Xthe entire software distribution it is enclosed with.  Removing this
Xcopyright is a violation of federal copyright law.  Please consult an
Xattorney if you have any questions regarding the legal ramifications of
Xthis agreement.
X
XThis software is licensed subject to the following terms and conditions.
XIn order that this product may expand into the universe to fill the current
X(void) in this area, it is my intention that this software be widely
Xdistributed, and maintained in a consistent fashion.  To this end, you
Xare authorized to redistribute this software in either source or binary
Xformat, provided that, this agreement is retained as part of the release,
Xno direct profit is realized from the sale or transfer of this software,
Xand that credit is given the author for this work.  To facilitate this
Xpackage coming into acceptance, you must provide library versions of this
Xsoftware and any documentation included with this package when distributing
Xbinary versions embedded in your products.  Paying royalties would be
Xnice and you won't do it anyway, so don't even pretend to be nice people
Xunless you really want me to stay on top of this thing.  Author retains
Xall rights to derived works, and as a condition to your making modifications
Xto the source code, you are required by this agreement to provide detailed
Xnotes concerning the actual modifications and the motivation behind the
Xmodification itself.  Making the documentation look better is a nice idea
Xalso.  And since I'm very lazy, please send me your documentation.  You
Xdon't have to, but standardized documentation is a Good Thing.
X
XThe author provides this software without warrantee.  The user accepts by
Xuse all responsibility for the performance (or lack thereof ;-) of this
Xsoftware, including loss of profits, reputation, or job.
X
X--< End of the legal stuff, now for the documentation. >--
X
Xcall.c - a test program.  do a `make all' to create the library and compile
Xthe call program.  read all the documentation before trying it out.
X
Xdial(3L) - a version of the standard dial(3) command which should be fairly
Xcompatible with the one in your manual ...  has both dial() and undial()
Xroutines.  see your manpage for more details.
X
Xhangup.c/hangup(3L) - a routine that attempts to absolutely hangup a modem.
Xit uses the modem capabilities database to figure out the best way to
Xhangup a modem.  it supports both hangup on DTR and hangup on command.
X
Xinitmodem.c/initmodem(3L) - this routine takes a character pointer to a
Xmodem name as it appears in the database and a file descriptor from a
Xopen() call, and loads the database information.  after the database is
Xloaded, the modem is placed in the command mode.  beware, initmodem()
Xmay make an alarm(2) call if the InitializationDelay requirement is present.
X
Xmdial.c/mdial(3L) - this routine builds a dial command string to give
Xto the dialer.  this is the weakest routine in the package, because i don't
Xhave that many different modems around here, and hayes is pretty damned
Xcommon, so i don't see many others.  the first argument is a character string
Xtelephone number, digits only, or if you understand your modem (boo on me)
Xyou can put in pause commands.  the second argument is a file descriptor
Xfrom an open() call. this routine _will_ be the first to get fixed.
X
Xmerror.c/merror(3L) - this routine is a modemcap replacement for perror.
Xan `int merrno' variable is maintained by the routines.  after an error
Xreturn, you can call merror with a character pointer just like perror(3)
Xand have a message printed on your standard error output.
X
Xmgetent.c/mgetent(3L) - this is a low level routine you shouldn't be
Xcalling anyway.  it works like tgetent(3), only different.  mostly, it
Xdoesn't have the neat things.  the first argument is a pointer to a
Xcharacter buffer where the entry will be placed.  the second argument
Xis a pointer to the modem name.
X
Xmgetflag.c/mgetflag(3L) - just like tgetflag.  this is a low level
Xroutine you might just want to use.  in particular, `if (mgetflag ("hc"))'
Xtests for modem hanging up on DTR being negated.  `if (HC)' does the
Xsame thing after mgetent() ...
X
Xmgetnum.c/mgetnum(3L) - just like tgetnum.  don't see much use for using
Xit.
X
Xmgetstr.c/mgetstr(3L) - just like tgetstr, except it has a few quirks.
Xoctal escapes are all three digits.  the format '^c' where 'c' is some
Xcharacter, only works with upper case letters.  correctly at least.
Xain't no way to get a null into the string, no how.
X
X/etc/modemcap - a modem capabilities database.  read the file for more
Xdetails.
X
X/etc/modemtype - a modem/port mapping table.  look at the example file.
X
Xyou will need to make entries for your devices in the L-devices file.
Xthe speed listed must be a legal speed according to the modemcap file.
Xany compilation errors or warnings should be brought to my attention. i
Xdidn't get any the last time i compiled all this stuff.
X
Xthe source is well enough (i'm lieing) documented for anyone to fix.
Xplease don't add your local improvement.  if you insist, make the mods
Xand send me context diffs.  i'll tell you what i think about the change.
Xremember, according to the license you must let me in on what you are
Xdoing.  this is in everyones best interest.
X
X--< End of the documentation, now for my personal philosophical b.s. >--
X
XIt is not my intention to limit the use of this software or your profits,
Xexcept where such use is inconsistent with the spirit of humanity, whatever
Xthe hell that means.  I don't care how much money you make selling your
Xnew terminal program, just don't go jacking the price up because you
Xhave added this thing.  I will only work on this package if I get feedback
Xand I have some motivation, other than being a nice guy.  I think I've been
Xnice enough by putting this thing out there.  If what you want makes sense
Xin a real way, I will probably include your suggestions, and if you are
Xpolite, I might just give you credit ;-)  So don't be a jerk and pretend
Xthat anyone actually works for free.  I have a car note just like you.
X
XBy way of this license and the legal mumbo-jumbo, I hope to keep people
Xfrom ripping me off, and totally trashing and perverting the integrity
Xof the code.  Please, don't construe this agreement to be limiting in
Xa negative way.  I hope to provide just enough limits to keep the code
Xconsistent and portable across all machine environments, and hopefully,
Xyou will use this thing enough that it becomes better and more useful
Xand fills the need for such a thing.  Who knows, we both might just make
Xsome money off of this thing.
X
X--
XJohn F. Haugh II		QUOTE: "The important thing is to not stop
X7825 McCallum Blvd.			questioning" -- Albert Einstein
XApt. 510			TELCO: (214) 250-3311
XDallas, TX 75252		UUCP:  { backbone } !ihnp4!killer!jfh
**-README-EOF-**
echo 'x - README.housel'
sed 's/^X//' <<'**-README.housel-EOF-**' >README.housel
XAll of this stuff is modified from jfh@rpp368.dallas.tx.us's package,
Xso that it more closely follows the dial(3) manual page. Some things
Xwere changed just because I wanted them to be done that way.
**-README.housel-EOF-**
echo 'x - call.c'
sed 's/^X//' <<'**-call.c-EOF-**' >call.c
X#include <dial.h>
X#include <stdio.h>
X
XCALL	call;
X
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	if (strcmp (argv[0], "call") == 0)
X		exit (do_call (argc, argv));
X	else if (strcmp (argv[0], "hangup") == 0)
X		exit (do_hup (argc, argv));
X
X	fprintf (stderr, "usage: call tty baud telno\n");
X	fprintf (stderr, "       hangup tty baud\n");
X	exit (1);
X}
X
Xdo_call (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	fd;
X
X	if (argc < 4) {
X		fprintf (stderr, "usage: call tty baud telno\n");
X		exit (1);
X	}
X	call.line = argv[1];
X	call.baud = atoi (argv[2]);
X	call.telno = argv[3];
X	
X	fd = dial (&call);
X	if (fd < 0) {
X		merror (argv[0]);
X		exit (2);
X	}
X	undial (fd);
X	return (0);
X}
X
Xdo_hup (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	fd;
X
X	if (argc < 3) {
X		fprintf (stderr, "usage: hangup tty baud\n");
X		exit (1);
X	}
X	call.line = argv[1];
X	call.baud = atoi (argv[2]);
X	
X	fd = dial (&call);
X	if (fd < 0) {
X		merror (argv[0]);
X		exit (2);
X	}
X	hangup (fd);
X	undial (fd);
X	return (0);
X}
**-call.c-EOF-**
echo 'x - dial.c'
sed 's/^X//' <<'**-dial.c-EOF-**' >dial.c
X#include <sgtty.h>
X#include <dial.h>
X#include <signal.h>
X#include <stdio.h>
X#include "modemcap.h"
X
Xstatic	char	lockfile[64];
Xstatic	int	modemfd = -1;
Xextern	int	merrno;
X
Xstatic	findline(callp, brand)
XCALL *callp;
Xchar	*brand;
X{
X int	exists = 0;		/* device exists at some baud rate */
X int	tried = 0;		/* found a device but it was locked */
X static	char l_line[DVC_LEN+1];	/* tty device name */
X char	l_type[DVC_LEN+1];	/* ACU, DIR, etc. */
X int	l_baud;			/* tty baud rate */
X char	buf[128];		/* L-devices line buffer */
X FILE	*fp;			/* L-devices file pointer */
X int	fd;			/* device lock file descriptor */
X char	*strcpy (),
X	*strcat ();
X
X if((fp = fopen (LDEVS, "r")) == NULL)
X    return (merrno = NO_Ldv);
X
X while(fgets(buf, sizeof buf, fp) != NULL)
X      {
X       if(buf[0] == '#')		/* ignore comment lines		*/
X	  continue;
X
X       if(sscanf (buf, "%s%s%*s%d%s", l_type, l_line, &l_baud, brand) != 4)
X	  continue;			/* mangled line			*/
X
X       if(callp->telno != NULL)		/* we're going to dial		*/
X	 {
X          if(strcmp (l_type, "ACU") != 0)
X	     continue;			/* not a dialer line		*/
X
X          if(callp->line != NULL)	/* device specified?		*/
X	     if(strcmp (l_line, callp->line) != 0)
X		continue;		/* wrong device			*/
X
X          exists++;		/* say device exists at some baud rate	*/
X
X          if(l_baud != callp->speed)	/* does it use the right speed?	*/
X	     continue;
X         }
X       else if(callp->line != NULL)
X	 {
X          if(strcmp(l_type, "DIR") != 0)
X	     continue;			/* not a dialer line		*/
X
X	  if(strcmp(l_line, callp->line) != 0)
X	     continue;			/* wrong device			*/
X
X	  callp->baud = l_baud;		/* use line's baud rate		*/
X	 }
X
X       ++tried;				/* found device at desired baud rate*/
X       strcat(strcpy(lockfile, LOCK), l_line);
X
X       if(access(lockfile, 0) == 0 || (fd = creat (lockfile, 0)) == -1)
X	  continue;			/* couldn't create lock */
X
X       close (fd);		/* created lock, now close descriptor	*/
X       fclose (fp);
X       callp->line = l_line;
X       return (1);
X      }
X
X if(tried)
X   return (merrno = DV_NT_A);
X else if(exists)
X   return (merrno = ILL_BD);
X else
X   return (merrno = DV_NT_K);
X}
X
X
Xstatic struct speedlist {
X	int	value;
X	int	name;
X} speeds[] = {
X	{    0,     0},
X	{  110,  B110},
X	{  300,  B300},
X/*	{  600,  B600},	*/
X	{ 1200, B1200},
X	{ 2400, B2400},
X	{ 4800, B4800},
X	{ 9600, B9600},
X/*	{19200, EXTA},	*/
X/*	{38400, EXTB},	*/
X	{   -1, -1}
X};
X
Xstatic	findspeed(speed)
Xint	speed;
X{
X	register struct	speedlist *ps;
X
X	for (ps = speeds; ps->value >= 0; ps++)
X		if (ps->value == speed)
X			return (ps->name);
X
X	return (0);
X}
X
X#ifdef CATCH
Xalarmcatch ()
X{
X	long	timebuf[2];
X
X	time (&timebuf[0]);
X	timebuf[1] = timebuf[0];
X
X	utime (lockfile, timebuf);
X	signal (SIGALRM, alarmcatch);
X	alarm (3600);
X}
X
Xhupcatch ()
X{
X	close (modemfd);
X	unlink (lockfile);
X	signal (SIGHUP, SIG_DFL);
X}
X#endif CATCH
X
Xint	dial (call)
XCALL	*call;
X{
X	char	modemline[64];		/* device name */
X	char	modemname[16];		/* modemcap name of modem	*/
X	char	*strcpy (),
X		*strcat ();
X#ifdef	UNIX_S5
X	struct	termio	termio;
X#endif
X#ifdef	UNIX_V7
X	struct	sgttyb	termio;
X#endif
X	int	fd;
X	int	err;
X
X	modemname[0] = '\0';
X
X	fd = -1;		/* channel illegal until line is opened	*/
X
X	if ((err = findline (call, modemname)) <= 0)
X		goto error;
X
X	if (modemname[0] == '\0') { /* can't determine the type of modem */
X		printf("can't determine modem type\n");
X		err = DV_NT_K;
X		goto error;
X	}
X
X	strcat(strcpy(modemline, DEVDIR), call->line);
X	if ((fd = open (modemline, O_RDWR)) < 0) { /* can't open modem line */
X		err = L_PROB;
X		goto error;
X	}
X#ifdef	UNIX_S5
X	if (call->attr != (struct termio *) 0) { /* set attributes */
X		if (ioctl (fd, TCSETA, call->attr) == -1) { /* some ioctl() problem */
X			err = L_PROB;
X			goto error;
X		}
X	} else {
X		ioctl (fd, TCGETA, &termio);
X		if ((termio.c_cflag = findspeed (call->baud)) == 0) {
X			err = ILL_BD;
X			goto error;
X		}
X		termio.c_cflag |= (CS8|CREAD|HUPCL);
X		termio.c_iflag = 0;
X		termio.c_oflag = 0;
X		termio.c_lflag = 0;
X		termio.c_cc[VMIN] = 1;
X		termio.c_cc[VTIME] = 1;
X		if (ioctl (fd, TCSETA, &termio) == -1) {
X			err = L_PROB;
X			goto error;
X		}
X	}
X#endif
X#ifdef	UNIX_V7
X	if (call->attr != (struct sgttyb *) 0) { /* set attributes */
X		if (gtty (fd, call->attr) == -1) { /* some gtty() problem */
X			err = L_PROB;
X			goto error;
X		}
X	} else {
X		gtty (fd, &termio);
X		if ((termio.sg_ispeed = findspeed (call->baud)) == 0) {
X			err = ILL_BD;
X			goto error;
X		}
X		termio.sg_ospeed = termio.sg_ispeed;
X		termio.sg_flags = RAW|ANYP;
X		termio.sg_erase = -1;
X		termio.sg_kill = -1;
X		if (stty (fd, &termio) == -1) {
X			err = L_PROB;
X			goto error;
X		}
X	}
X#endif
X	initmodem (modemname, fd);	/* setup modemcap variables */
X	if (call->telno == NULL)     /* no phone number, connection complete */
X		goto okay;
X
X	if (! DI) {			/* modem has no ACU!!! */
X		err = A_PROB;		/* no ACU to attach to */
X		goto error;
X	}
X	if (BD != call->baud) {	/* is connection desired at high speed? */
X		if (BL != call->baud){/* is connection desired at low speed? */
X			err = ILL_BD;	/* modem can't handle this speed */
X			goto error;
X		}
X		BD = BL;		/* set baud to low baud rate */
X		CO = CL;	/* set connect reply to low baud reply */
X	}
X	if (err = mdial (call->telno, fd)) 	/* some error trying to dial */
X		goto error;
X#ifdef CATCH
X	signal (SIGALRM, alarmcatch);	/* set catcher for ALARM clock */
X	signal (SIGHUP, hupcatch);	/* set catcher for HANG UP */
X	alarm (3600);			/* set clock to touch lock in 1 hour */
X#endif CATCH
X
Xokay:
X	return (modemfd = fd);
X
Xerror:
X	if(lockfile[0])		/* don't unlink '.'! */
X        	unlink (lockfile);
X	if (fd > 2)
X		close (fd);
X	return (merrno = err);
X}
X
Xvoid	undial (fd)
Xint	fd;
X{
X	if (fd > 2)
X		close (fd);
X
X	if(lockfile[0])
X	   unlink (lockfile);
X#ifdef CATCH
X	alarm (0);
X#endif CATCH
X}
**-dial.c-EOF-**