v13i059: Hardware-independant modem routines

Rich Salz rsalz at bbn.com
Tue Feb 23 10:09:27 AEST 1988


Submitted-by: The Beach Bum <ulysses!ihnp4!killer!jfh at seismo.CSS.GOV>
Posting-number: Volume 13, Issue 59
Archive-name: modemcap

This is a modem-independant dial(3) package, with a termcap-style
description file.  No manual page -- refer to the relevant (SystemV)
manuals.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	makefile
#	modemcap
#	modemtype
#	modemcap.h
#	mgetent.c
#	mgetstr.c
#	mgetflag.c
#	mgetnum.c
#	mdial.c
#	merror.c
#	initmodem.c
#	hangup.c
#	dial.c
#	call.c
# This archive created: Mon Nov  2 13:32:08 1987
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
This package is a modem independent dial(3) package.  It provides a device
independent method for dialing and manipulating modems.  The format of the
description file is the ever present ;-) termcaps format.  You may want to
read the modemcap file to see just what capabilities are present.

This is Release 1.1 of this software.  Please bear in mind that I haven't
released this to the public before this release.

--< Start of the legal conditions of this software >--

This software is copyright 1987 John F. Haugh II, all rights reserved.
Use, duplication and disclosure subject to the terms and conditions of
the license agreement below.  This notice is intended to have legal
significance, and not to be taken lightly.  If you have any questions,
please contact the author at the address below.  This copyright covers
the entire software distribution it is enclosed with.  Removing this
copyright is a violation of federal copyright law.  Please consult an
attorney if you have any questions regarding the legal ramifications of
this agreement.

This software is licensed subject to the following terms and conditions.
In order that this product may expand into the universe to fill the current
(void) in this area, it is my intention that this software be widely
distributed, and maintained in a consistent fashion.  To this end, you
are authorized to redistribute this software in either source or binary
format, provided that, this agreement is retained as part of the release,
no direct profit is realized from the sale or transfer of this software,
and that credit is given the author for this work.  To facilitate this
package coming into acceptance, you must provide library versions of this
software and any documentation included with this package when distributing
binary versions embedded in your products.  Paying royalties would be
nice and you won't do it anyway, so don't even pretend to be nice people
unless you really want me to stay on top of this thing.  Author retains
all rights to derived works, and as a condition to your making modifications
to the source code, you are required by this agreement to provide detailed
notes concerning the actual modifications and the motivation behind the
modification itself.  Making the documentation look better is a nice idea
also.  And since I'm very lazy, please send me your documentation.  You
don't have to, but standardized documentation is a Good Thing.

The author provides this software without warrantee.  The user accepts by
use all responsibility for the performance (or lack thereof ;-) of this
software, including loss of profits, reputation, or job.

--< End of the legal stuff, now for the documentation. >--

call.c - a test program.  do a `make all' to create the library and compile
the call program.  read all the documentation before trying it out.

dial(3L) - a version of the standard dial(3) command which should be fairly
compatible with the one in your manual ...  has both dial() and undial()
routines.  see your manpage for more details.

hangup.c/hangup(3L) - a routine that attempts to absolutely hangup a modem.
it uses the modem capabilities database to figure out the best way to
hangup a modem.  it supports both hangup on DTR and hangup on command.

initmodem.c/initmodem(3L) - this routine takes a character pointer to a
modem name as it appears in the database and a file descriptor from a
open() call, and loads the database information.  after the database is
loaded, the modem is placed in the command mode.  beware, initmodem()
may make an alarm(2) call if the InitializationDelay requirement is present.

mdial.c/mdial(3L) - this routine builds a dial command string to give
to the dialer.  this is the weakest routine in the package, because i don't
have that many different modems around here, and hayes is pretty damned
common, so i don't see many others.  the first argument is a character string
telephone number, digits only, or if you understand your modem (boo on me)
you can put in pause commands.  the second argument is a file descriptor
from an open() call. this routine _will_ be the first to get fixed.

merror.c/merror(3L) - this routine is a modemcap replacement for perror.
an `int merrno' variable is maintained by the routines.  after an error
return, you can call merror with a character pointer just like perror(3)
and have a message printed on your standard error output.

mgetent.c/mgetent(3L) - this is a low level routine you shouldn't be
calling anyway.  it works like tgetent(3), only different.  mostly, it
doesn't have the neat things.  the first argument is a pointer to a
character buffer where the entry will be placed.  the second argument
is a pointer to the modem name.

mgetflag.c/mgetflag(3L) - just like tgetflag.  this is a low level
routine you might just want to use.  in particular, `if (mgetflag ("hc"))'
tests for modem hanging up on DTR being negated.  `if (HC)' does the
same thing after mgetent() ...

mgetnum.c/mgetnum(3L) - just like tgetnum.  don't see much use for using
it.

mgetstr.c/mgetstr(3L) - just like tgetstr, except it has a few quirks.
octal escapes are all three digits.  the format '^c' where 'c' is some
character, only works with upper case letters.  correctly at least.
ain't no way to get a null into the string, no how.

/etc/modemcap - a modem capabilities database.  read the file for more
details.

/etc/modemtype - a modem/port mapping table.  look at the example file.

you will need to make entries for your devices in the L-devices file.
the speed listed must be a legal speed according to the modemcap file.
any compilation errors or warnings should be brought to my attention. i
didn't get any the last time i compiled all this stuff.

the source is well enough (i'm lieing) documented for anyone to fix.
please don't add your local improvement.  if you insist, make the mods
and send me context diffs.  i'll tell you what i think about the change.
remember, according to the license you must let me in on what you are
doing.  this is in everyones best interest.

--< End of the documentation, now for my personal philosophical b.s. >--

It is not my intention to limit the use of this software or your profits,
except where such use is inconsistent with the spirit of humanity, whatever
the hell that means.  I don't care how much money you make selling your
new terminal program, just don't go jacking the price up because you
have added this thing.  I will only work on this package if I get feedback
and I have some motivation, other than being a nice guy.  I think I've been
nice enough by putting this thing out there.  If what you want makes sense
in a real way, I will probably include your suggestions, and if you are
polite, I might just give you credit ;-)  So don't be a jerk and pretend
that anyone actually works for free.  I have a car note just like you.

By way of this license and the legal mumbo-jumbo, I hope to keep people
from ripping me off, and totally trashing and perverting the integrity
of the code.  Please, don't construe this agreement to be limiting in
a negative way.  I hope to provide just enough limits to keep the code
consistent and portable across all machine environments, and hopefully,
you will use this thing enough that it becomes better and more useful
and fills the need for such a thing.  Who knows, we both might just make
some money off of this thing.

--
John F. Haugh II		QUOTE: "The important thing is to not stop
7825 McCallum Blvd.			questioning" -- Albert Einstein
Apt. 510			TELCO: (214) 250-3311
Dallas, TX 75252		UUCP:  { backbone } !ihnp4!killer!jfh
SHAR_EOF
fi
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
cat << \SHAR_EOF > 'makefile'
# Your library directory.
LIBDIR=/usr/lib
# Your local command directory.
LBIN=/usr/local/bin
OSFLAG=-DUNIX_S5	# For System V machines.
# OSFLAG=-DUNIX_V7	# For Version 7 machines.
# For those poor people who need ranlib
# RANLIB=ranlib $(LIBDIR)/libmodemcap.a
# Standard Bourne shell.
SHELL=/bin/sh

CFLAGS=-O
LDFLAGS=-s

OFILES=mgetent.o mgetstr.o mgetflag.o mgetnum.o mdial.o merror.o \
	initmodem.o hangup.o dial.o

CFILES=mgetent.c mgetstr.c mgetflag.c mgetnum.c mdial.c merror.c \
	initmodem.c hangup.c dial.c

LFILES=libmodemcap.a(mgetent.o)\
	libmodemcap.a(mgetstr.o)\
	libmodemcap.a(mgetflag.o)\
	libmodemcap.a(mgetnum.o)\
	libmodemcap.a(mdial.o)\
	libmodemcap.a(merror.o)\
	libmodemcap.a(initmodem.o)\
	libmodemcap.a(hangup.o)\
	libmodemcap.a(dial.o)

all:	$(LFILES)

install:	all call
	cp modemcap.h /usr/include
	cp modemcap /etc/modemcap
	cp modemtype /etc/modemtype
	cp libmodemcap.a $(LIBDIR)
	chmod 644 /usr/include/modemcap.h /etc/modemcap /etc/modemtype $(LIBDIR)/libmodemcap.a
	cp call $(LBIN)/call
	chmod 711 $(LBIN)/call

call:	call.c libmodemcap.a
	cc $(LDFLAGS) $(CFLAGS) call.c libmodemcap.a -o call

initmodem.o:	initmodem.c /usr/include/modemcap.h

mdial.o:	mdial.c /usr/include/modemcap.h

hangup.o:	hangup.c /usr/include/modemcap.h

dial.o:	dial.c	/usr/include/modemcap.h

shar:	README $(CFILES) makefile modemcap modemtype modemcap.h call.c
	shar README makefile modemcap modemtype modemcap.h $(CFILES) call.c > modem.shar
SHAR_EOF
fi
if test -f 'modemcap'
then
	echo shar: "will not over-write existing file 'modemcap'"
else
cat << \SHAR_EOF > 'modemcap'
#
#       @(#)modemcap    1.0
#
#       First attempt at a modem capabilities database.
#
#       Capabilities are:
#
#       Name    Type    Meaning
#
#       as      flag    Numbers are in ASCII, not binary
#       at      string  Attention string, forces model into command mode from online mode
#       ad      number  Delay after AS
#       bd      number  Highest online baud rate
#       bl      number  Alternate lower baud rate
#       cs      string  Command start string
#       ce      string  Command end string (required if CS is present)
#       co      string  String from modem on remote connection at BD baud rate
#       cl      string  String from modem on remote connection at BL baud rate
#       di      flag    Modem has a dialer
#       ds      string  Start dial command string
#       de      string  End dial command string (required if DS is present)
#       is      string  Initialization string, resets modem to offline, ready to dial
#       id      number  Delay after IS
#       hc      flag    Modem hangs up when DTR drops
#       hu      string  Hangup command
#       tt      flag    Modem dials touchtone by default (or DS is set that way)
#
#       All commands, such as DS (dial command) and HU (hang up) will be prefixed by
#       CS and ended with CE.  If there is a common prefix and suffix, use this feature.
#       Otherwise, each command will have to have the entire string built in.
#
hy|hayes|Hayes Smartmodem 1200:\
	:as:at=+++:ad#6:bd#1200:bl#300:cs=AT:ce=\r:co=CONNECT:\
	:cl=CONNECT:di:ds=DT :de=:is=ATQ0 V1 E1\r:id#2:\
	:hc:hu=H0 V0 E0 Q1:tt:
si|mk12|Signalman Mark XII:\
        :as:at=+++:ad#6:bd#1200:bl#300:cs=AT:ce=\r:co=CONNECT 1200:\
        :cl=CONNECT:di:ds=DT :de=:is=ATQ0 V1 E1\r:id#2:\
        :hu=H0 V0 E0 Q1:tt:
ds|dc300|Radio Shack Direct-Connect 300 Modem:\
        :bd#300:bl#110:
SHAR_EOF
fi
if test -f 'modemtype'
then
	echo shar: "will not over-write existing file 'modemtype'"
else
cat << \SHAR_EOF > 'modemtype'
hayes1200 tty38
hayes1200 tty39
ch1770 modem
SHAR_EOF
fi
if test -f 'modemcap.h'
then
	echo shar: "will not over-write existing file 'modemcap.h'"
else
cat << \SHAR_EOF > 'modemcap.h'
/* 
 *      @(#)modemcap.h  1.0
 *
 *      names of variables and whatnots for modemcap file
 */

char    AS,             /* True if numbers dialed in ASCII, False for binary digits     */
        DI,             /* True if modem can dial numbers, False otherwise              */
        HC,             /* True if modem hangs up when DTR drops, False otherwise       */
        TT;             /* True if modem uses touchtone by default, False for pulse     */

char    *AT,            /* Enter command state when online                              */
        *CS,            /* Command start string                                         */
        *CE,            /* Command end string - must be present if CS is                */
        *DS,            /* Dial command string                                          */
        *DE,            /* End of dial command string - must be present if DS is        */
        *CO,            /* Connection made at primary baud rate                         */
        *CL,            /* Connection made at secondary (lower) baud rate               */
        *IS,            /* Initialization string - reset modem to onhook and ready      */
        *HU;            /* Hangup command                                               */

int     AD,             /* Delay after AT string before next command                    */
        BD,             /* Highest communications baud rate                             */
        BL,             /* Another, lower baud rate                                     */
        ID;             /* Delay time after initialization                              */

/*
 * The dial command is the principle string that must be built.
 * The routines will build a dial command as follows:
 *
 *      <CS><DS><phone-number><DE><CE>
 *
 * Note that the DE and CE strings are present ALWAYS.
 * This procedure will be used to dial phone numbers if the DI flag is true.
 * If this isn't the way to dial numbers,
 * DO NOT SET DI IN THE MODEMCAP FILE!!!
 */

/*
 * The type of modem is determined by reading the file "_MODEMTYPE_".  This
 * is similiar to the way curses works by reading the ttytype file.
 */

#define	_MODEMTYPE_	"/etc/modemtype"

/*
 * a hangup command will be performed as follows:
 *
 *      1). any attention string (AT) will be sent followed by the delay (AD)
 *      2). modem should now be in command state, send hangup (HU) command
 *      3). send initialization string (IS) followed by the delay (ID)
 *
 * It is important that you determine a correct AT and HU string
 *  to perform this function.
 * If the modem hangs up when DTR falls (even if there is a HU string),
 *  declare the flag HC (for Hangup on Close).
 */

SHAR_EOF
fi
if test -f 'mgetent.c'
then
	echo shar: "will not over-write existing file 'mgetent.c'"
else
cat << \SHAR_EOF > 'mgetent.c'
#include <stdio.h>

char	*__modemcap;
char	*MODEMCAP = "/etc/modemcap";

static	isent (ent, name)
char	*ent;
char	*name;
{
	char	buf[16];
	register int	i;

	while (*ent != ':' && *ent != 0) {
		for (i = 0;*ent != ':' && *ent != '|' && *ent != 0 && i < 15;i++)
			buf[i] = *ent++;

		if (*ent == '|')
			ent++;

		buf[i] = 0;
		if (strcmp (buf, name) == 0)
			return (1);
	}
	return (0);
}

mgetent (bp, name)
char	*bp;
char	*name;
{
	char	buf[1024];
	register char	*cp;
	register FILE	*modemcap;
	register int	i;
	char	*getenv ();

	if ((cp = getenv ("MODEMCAP")) != NULL) {
		if (*cp != '/') {
			if (isent (cp, name)) {
				strcpy (buf, cp);
				return (1);
			}
		}
		MODEMCAP = cp;
	}
	if ((modemcap = fopen (MODEMCAP, "r")) == NULL)
		return (-1);

	while (fgets (buf, 512, modemcap) != NULL) {
		if (buf[0] == '#')				/* skip all comment lines		*/
			continue;

		i = strlen (buf) - 1;				/* find last character in line		*/
		buf[i] = 0;					/* remove trailing newline		*/
		if (i == 0)					/* ignore blank lines			*/
			continue;

		while (buf[(i = strlen (buf) - 1)] == '\\') {	/* is last character a \\, still more	*/
			cp = &buf[i];				/* find last character			*/
			cp[0] = 0;				/* nullify, end of this part		*/
			if (fgets (cp, 512, modemcap) == NULL)	/* end of file?	...			*/
				break;				/* ... end of entry			*/

			cp[strlen (cp) - 1] = 0;		/* remove trailing newline		*/
			if (cp[0] == '#') {			/* comment line? ...			*/
				cp[0] = 0;			/* remove that line			*/
				continue;			/* go get another line			*/
			}
		}
		if (isent (buf, name)) {
			__modemcap = bp;
			strcpy (bp, buf);
			fclose (modemcap);
			return (1);
		}
	}
	fclose (modemcap);
	return (0);
}
SHAR_EOF
fi
if test -f 'mgetstr.c'
then
	echo shar: "will not over-write existing file 'mgetstr.c'"
else
cat << \SHAR_EOF > 'mgetstr.c'
extern	char	*__modemcap;

char	*mgetstr (id, area)
register char	*id;
register char	**area;
{
	register char	*cp = __modemcap;
	register char	*str = *area;		/* start of current string		*/

	if (__modemcap == (char *) 0)		/* has mgetent() been called? ...	*/
		return ((char *) 0);			/* ... no, can't find string	*/

	while (*cp != ':' && *cp != 0)		/* find first entry in cap		*/
		cp++;

	if (*cp == 0)				/* empty entry???			*/
		return ((char *) 0);			/* ... yes, bad modemcap entry		*/
	else
		cp++;				/* point to first character in next	*/

	while (*cp != 0) {			/* until entry found or end of entry	*/
		if (cp[0] == id[0] && cp[1] == id[1]) {	/* found entry!!!		*/
			if (cp[2] != '=')	/* is it a string value???		*/
				return ((char *) 0);	/* no, something else			*/
			else
				break;		/* yes, entry was found			*/
		} else {			/* not entry, skip this entire entry	*/
			while (*cp != ':' && *cp != 0)
				cp++;		/* search for end of current entry	*/

			if (*cp != 0)
				cp++;		/* skip terminating character		*/
		}
	}
	if (*cp == 0)				/* end of modem cap entry		*/
		return ((char *) 0);

	cp += 3;				/* point to actual string		*/
	while (*cp != ':' && *cp != 0) {	/* for every character in string ...	*/
		if (*cp == '\\') {		/* translate escaped character		*/
			cp++;
			switch (*cp) {
				case 'n':	/* newline			*/
					**area = '\n';
					(*area)++;
					cp++;
					break;
				case 'r':	/* carriage return		*/
					**area = '\r';
					(*area)++;
					cp++;
					break;
				case 'b':	/* backspace			*/
					**area = '\b';
					(*area)++;
					cp++;
					break;
				case 'f':	/* form feed			*/
					**area = '\f';
					(*area)++;
					cp++;
					break;
				case 't':	/* tab				*/
					**area = '\t';
					(*area)++;
					cp++;
					break;
				case 'E':	/* Escape character		*/
					**area = 033;
					(*area)++;
					cp++;
					break;
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
					**area = ((cp[0] - '0') << 6) +
						 ((cp[1] - '0') << 3) +
						  (cp[2] - '0');
					(*area)++;
					cp += 3;
					break;
				default:
					**area = *cp++;
					(*area)++;
					break;
			}
		} else if (*cp == '^') {	/* some control character		*/
			cp++;
			if (*cp >= '@' && *cp <= '_') {
				**area = *cp - '@';
				(*area)++;
			}
			cp++;
		} else {			/* some normal character		*/
			**area = *cp++;		/* put character in area		*/
			(*area)++;
		}
	}
	*((*area)++) = 0;			/* null terminate area and string	*/
	return (str);				/* return pointer to start of string	*/
}
SHAR_EOF
fi
if test -f 'mgetflag.c'
then
	echo shar: "will not over-write existing file 'mgetflag.c'"
else
cat << \SHAR_EOF > 'mgetflag.c'
extern	char	*__modemcap;

mgetflag (id)
register char	*id;
{
	register char	*cp = __modemcap;

	if (__modemcap == (char *) 0)		/* has mgetent() been called? ...	*/
		return (-1);			/* ... no, can't find number		*/

	while (*cp != ':' && *cp != 0)		/* find first entry in cap		*/
		cp++;

	if (*cp == 0)				/* empty entry???			*/
		return (0);			/* ... yes, bad modemcap entry		*/
	else
		cp++;				/* point to first character in next	*/

	while (*cp != 0) {			/* until entry found or end of entry	*/
		if (cp[0] == id[0] && cp[1] == id[1])	/* found entry!!!		*/
			return (1);		/* return true				*/
		else {			/* not entry, skip this entire entry	*/
			while (*cp != ':' && *cp != 0)
				cp++;		/* search for end of current entry	*/

			if (*cp != 0)
				cp++;		/* skip terminating character		*/
		}
	}
	return (0);
}
SHAR_EOF
fi
if test -f 'mgetnum.c'
then
	echo shar: "will not over-write existing file 'mgetnum.c'"
else
cat << \SHAR_EOF > 'mgetnum.c'
extern	char	*__modemcap;

mgetnum (id)
register char	*id;
{
	register char	*cp = __modemcap;

	if (__modemcap == (char *) 0)		/* has mgetent() been called? ...	*/
		return (-1);			/* ... no, can't find number		*/

	while (*cp != ':' && *cp != 0)		/* find first entry in cap		*/
		cp++;

	if (*cp == 0)				/* empty entry???			*/
		return (-1);			/* ... yes, bad modemcap entry		*/
	else
		cp++;				/* point to first character in next	*/

	while (*cp != 0) {			/* until entry found or end of entry	*/
		if (cp[0] == id[0] && cp[1] == id[1]) {	/* found entry!!!		*/
			if (cp[2] != '#')	/* is it a numeric value???		*/
				return (-1);	/* no, something else			*/

			return (atoi (&cp[3]));	/* return value (just after #)		*/
		} else {			/* not entry, skip this entire entry	*/
			while (*cp != ':' && *cp != 0)
				cp++;		/* search for end of current entry	*/

			if (*cp != 0)
				cp++;		/* skip terminating character		*/
		}
	}
	return (-1);
}
SHAR_EOF
fi
if test -f 'mdial.c'
then
	echo shar: "will not over-write existing file 'mdial.c'"
else
cat << \SHAR_EOF > 'mdial.c'
#include "modemcap.h"
#include <setjmp.h>
#include <signal.h>
#include <dial.h>

static	jmp_buf	env;		/* long jump buffer if timeout in read	*/
extern	int	merrno;

static	timeout ()
{
	longjmp  (env, 1);
}

mdial (telno, fd)
char	*telno;
int	fd;
{
	char	buf[64];	/* telephone buffer if AS is false */
	char	command[80];	/* dial command buffer */
	int	i, j;		/* index and length of telephone number */
	char	c;		/* single character for connection verification */

	if (! DI)
		return (merrno = A_PROB); /* can't dial phone anyhow */

	if (! AS)		/* never used any other kind of modem */
		return (merrno = A_PROB);
	else			/* normal ascii character phone numbers	*/
		strcpy (buf, telno);

	sprintf (command, "%s%s%s%s%s", CS, DS, buf, DE, CE);
	if (setjmp (env) != 0) {	
		signal (SIGALRM, SIG_DFL);
		return (merrno = D_HUNG);
	}
	signal (SIGALRM, timeout);
	alarm (10);
	write (fd, command, strlen (command));

	if (CO) {	/* verify connection */
		if (setjmp (env) != 0) {	
			signal (SIGALRM, SIG_DFL);
			return (merrno = A_PROB);
		}
		signal (SIGALRM, timeout);
		if (TT)
			alarm (30);
		else
			alarm (30 + strlen (telno) / 2);

		for (i = 0;CO[i] != 0;) {
			if (read (fd, &c, 1) != 1)
				continue;
			
			if (CO[i] == c)
				i++;
			else
				i = 0;
		}
		return (0);
	}
	return (0);
}
SHAR_EOF
fi
if test -f 'merror.c'
then
	echo shar: "will not over-write existing file 'merror.c'"
else
cat << \SHAR_EOF > 'merror.c'
#include <stdio.h>

int	merrno;

char	*_merr_list[] = {
	"No error",
	"Interrupt occurred",
	"Dialer Hung",
	"No answer",
	"Illegal baud rate",
	"ACU Problem",
	"Line Problem",
	"Can't open LDEVS file",
	"Requested device not available",
	"Requested device not known",
	"No device available at requested baud",
	"No device known at requested baud"
};

int	_msys_nerr = (sizeof (_merr_list) / sizeof (char *));

merror (s)
char	*s;
{
	int	i = - merrno;

	if (0 <= i && i < _msys_nerr)
		fprintf (stderr, "%s: %s\n", s, _merr_list[i]);
	else
		fprintf (stderr, "%s: Error %d\n", s, merrno);
}
SHAR_EOF
fi
if test -f 'initmodem.c'
then
	echo shar: "will not over-write existing file 'initmodem.c'"
else
cat << \SHAR_EOF > 'initmodem.c'
#include "modemcap.h"

static	char	f_names[] = "asditthc";
static	char	*f_caps[] = {
	&AS, &DI, &TT, &HC
};

static	char	i_names[] = "bdblidad";
static	int	*i_caps[] = {
	&BD, &BL, &ID, &AD
};

static	char	c_names[] = "cscedsdeiscoclathu";
static	char	**c_caps[] = {
	&CS, &CE, &DS, &DE, &IS, &CO, &CL, &AT, &HU
};

initmodem (modem, fd)
char	*modem;					/* name of modem		*/
int	fd;					/* channel to modem		*/
{
	static	char	mcapbuf[1024];
	static	char	area[1024];
	char	*ap = area;
	register char	*cp;
	register int	i, j;
	register char	*s;
	char	*mgetstr ();

	if (mgetent (mcapbuf, modem) != 1)
		return (0);

	for (i = 0, cp = f_names;*cp;i++, cp += 2)
		*(f_caps[i]) = mgetflag (cp);

	for (i = 0, cp = i_names;*cp;i++, cp += 2) {
		j = mgetnum (cp);
		if (j >= 0)
			*(i_caps[i]) = j;
		else
			*(i_caps[i]) = 0;
	}
	for (i = 0, cp = c_names;*cp;i++, cp += 2)
		*(c_caps[i]) = mgetstr (cp, &ap);

	if (IS != (char *) 0) {
		write (fd, IS, strlen (IS));
		if (ID)
			sleep (ID);
	}
	return (1);
}
SHAR_EOF
fi
if test -f 'hangup.c'
then
	echo shar: "will not over-write existing file 'hangup.c'"
else
cat << \SHAR_EOF > 'hangup.c'
#include "modemcap.h"
#ifdef	UNIX_S5
#include <termio.h>
#endif
#ifdef	UNIX_V7
#include <sgtty.h>
#endif

extern	int	merrno;

hangup (fd)
int	fd;
{
#ifdef	UNIX_S5
	struct	termio	termio;
	struct	termio	hupcl;
#endif
#ifdef	UNIX_V7
	struct	sgttyb	termio;
	struct	sgttyb	hupcl;
#endif
	if (HU == (char *) 0 && HC == 0) {
		undial (fd);
		return (0);
	}
	if (AT != (char *) 0) {
		write (fd, AT, strlen (AT));
		if (AD)
			sleep (AD);
	}
	if (HU) {
		if (CS)
			write (fd, CS, strlen (CS));
		write (fd, HU, strlen (HU));
		if (CE)
			write (fd, CE, strlen (CE));

		if (IS) {
			write (fd, IS, strlen (IS));
			if (ID)
				sleep (ID);
		}
		undial (fd);
		return (1);
	}
#ifdef	UNIX_S5
	ioctl (fd, TCGETA, &termio);
	ioctl (fd, TCGETA, &hupcl);
	
	hupcl.c_cflag &= ~CBAUD;
	hupcl.c_cflag |= HUPCL;

	ioctl (fd, TCSETA, &hupcl);
	sleep (2);
	ioctl (fd, TCSETA, &termio);
#endif
#ifdef	UNIX_V7
	gtty (fd, &termio);
	gtty (fd, &hupcl);

	hupcl.sg_ispeed = B0;
	hupcl.sg_ospeed = B0;
	stty (fd, &hupcl);
	sleep (2);
	stty (fd, &termio);
#endif
	undial (fd);
	return (1);
}
SHAR_EOF
fi
if test -f 'dial.c'
then
	echo shar: "will not over-write existing file 'dial.c'"
else
cat << \SHAR_EOF > 'dial.c'
#include <fcntl.h>
#include <dial.h>
#include <signal.h>
#include <stdio.h>
#include "modemcap.h"

#ifdef	UNIX_V7
typedef	int	void;
#endif
static	char	lockfile[64];
static	int	modemfd = -1;
extern	int	merrno;

static	findline (line, baud)
char	*line;
int	baud;
{
	int	exists = 0;
	int	l_baud;
	char	l_line[DVC_LEN+1];
	char	l_type[DVC_LEN+1];
	char	buf[64];
	FILE	*fp;

	if ((fp = fopen (LDEVS, "r")) == NULL)
		return (merrno = NO_Ldv);

	while (fgets (buf, 64, fp) != NULL) {
		if (buf[0] == '#')		/* ignore comment lines			*/
			continue;

		if (sscanf (buf, "%s%s%*s%d", l_type, l_line, &l_baud) != 3)
			continue;		/* mangled line				*/

		if (strcmp (l_type, "DIR") != 0)
			continue;		/* not a direct connect line		*/

		if (strcmp (l_line, line) == 0)
			exists++;		/* say device exists at some baud rate	*/
		else
			continue;		/* wrong device				*/

		if (l_baud == baud) {		/* found device at desired baud rate	*/
			fclose (fp);
			return (1);
		}
	}
	if (exists)
		return (merrno = ILL_BD);
	else
		return (merrno = DV_NT_K);
}

static	char	*findmodem (line)
{
	static	char	modemtype[16];
	char	device[DVC_LEN + 1];
	char	buf[82];
	FILE	*fp;

	if ((fp = fopen (_MODEMTYPE_, "r")) == NULL)
		return (NULL);

	while (fgets (buf, 82, fp) != NULL) {
		if (buf[0] == '#')
			continue;

		sscanf (buf, "%s%s\n", modemtype, device);
		if (strcmp (line, device) == 0) {
			fclose (fp);
			return (modemtype);
		}
	}
	fclose (fp);
	return (NULL);
}

struct speedlist {
	int	value;
	int	name;
} speeds[] = {
	{    0,     0},
	{  110,  B110},
	{  300,  B300},
	{  600,  B600},
	{ 1200, B1200},
	{ 2400, B2400},
	{ 4800, B4800},
	{ 9600, B9600},
	{19200, EXTA},
	{38400, EXTB},
	{   -1, -1}
};

static	findspeed (speed)
int	speed;
{
	register struct	speedlist *ps;

	for (ps = speeds; ps->value >= 0; ps++)
		if (ps->value == speed)
			return (ps->name);

	return (0);
}

alarmcatch ()
{
	long	timebuf[2];

	time (&timebuf[0]);
	timebuf[1] = timebuf[0];

	utime (lockfile, timebuf);
	signal (SIGALRM, alarmcatch);
	alarm (3600);
}

hupcatch ()
{
	close (modemfd);
	unlink (lockfile);
	signal (SIGHUP, SIG_DFL);
}

int	dial (call)
CALL	*call;
{
	char	modemline[64];			/* device name				*/
	char	*modemname;			/* modemcap name of modem		*/
	char	*strcpy (),
		*strcat ();
#ifdef	UNIX_S5
	struct	termio	termio;
#endif
#ifdef	UNIX_V7
	struct	sgttyb	termio;
#endif
	int	fd;
	int	err;

	strcat (strcpy (modemline, DEVDIR), call->line);
	strcat (strcpy (lockfile, LOCK), call->line);

	/*
	 * FIX - Version 7 does not have three operand open(), write
	 * conditional compilation for this here ...
	 */

	if (access (lockfile, 0) == 0 || (fd = creat (lockfile, 0)) == -1)
		return (merrno = DV_NT_A);	/* lock existed or couldn't be created	*/
	else
		close (fd);			/* created lock, now close descriptor	*/

	fd = -1;				/* channel illegal until line is opened	*/

	if ((err = findline (call->line, call->baud)) <= 0)
		goto error;

	if ((modemname = findmodem (call->line)) == NULL) { /* can't determine the type of modem	*/
		err = DV_NT_K;
		goto error;
	}
	if ((fd = open (modemline, O_RDWR)) < 0) { /* can't open modem line		*/
		err = L_PROB;
		goto error;
	}
#ifdef	UNIX_S5
	if (call->attr != (struct termio *) 0) { /* set attributes			*/
		if (ioctl (fd, TCSETA, call->attr) == -1) { /* some ioctl() problem	*/
			err = L_PROB;
			goto error;
		}
	} else {
		ioctl (fd, TCGETA, &termio);
		if ((termio.c_cflag = findspeed (call->baud)) == 0) {
			err = ILL_BD;
			goto error;
		}
		termio.c_cflag |= (CS8|CREAD|HUPCL);
		termio.c_iflag = 0;
		termio.c_oflag = 0;
		termio.c_lflag = 0;
		termio.c_cc[VMIN] = 1;
		termio.c_cc[VTIME] = 1;
		if (ioctl (fd, TCSETA, &termio) == -1) {
			err = L_PROB;
			goto error;
		}
	}
#endif
#ifdef	UNIX_V7
	if (call->attr != (struct sgttyb *) 0) { /* set attributes			*/
		if (gtty (fd, call->attr) == -1) { /* some gtty() problem */
			err = L_PROB;
			goto error;
		}
	} else {
		gtty (fd, &termio);
		if ((termio.sg_ispeed = findspeed (call->baud)) == 0) {
			err = ILL_BD;
			goto error;
		}
		termio.sg_ospeed = termio.sg_ispeed;
		termio.sg_flags = RAW|ANYP;
		termio.sg_erase = -1;
		termio.sg_kill = -1;
		if (stty (fd, &termio) == -1) {
			err = L_PROB;
			goto error;
		}
	}
#endif
	initmodem (modemname, fd);		/* setup modemcap variables		*/
	if (call->telno == (char *) 0)		/* no phone number, connection complete	*/
		goto okay;

	if (! DI) {				/* modem has no ACU!!!			*/
		err = A_PROB;			/* no ACU to attach to			*/
		goto error;
	}
	if (BD != call->baud) {			/* is connection desired at high speed?	*/
		if (BL != call->baud)	{	/* is connection desired at low speed?	*/
			err = ILL_BD;		/* modem can't handle this speed	*/
			goto error;
		}
		BD = BL;			/* set baud to low baud rate		*/
		CO = CL;			/* set connect reply to low baud reply	*/
	}
	if (err = mdial (call->telno, fd)) 	/* some error trying to dial		*/
		goto error;

	signal (SIGALRM, alarmcatch);		/* set catcher for ALARM clock		*/
	signal (SIGHUP, hupcatch);		/* set catcher for HANG UP		*/
	alarm (3600);				/* set clock for 1 hour to touch lock	*/

okay:
	return (modemfd = fd);

error:
	unlink (lockfile);
	if (fd > 2)
		close (fd);
	return (merrno = err);
}

void	undial (fd)
int	fd;
{
	if (fd > 2)
		close (fd);

	unlink (lockfile);
	alarm (0);
}
SHAR_EOF
fi
if test -f 'call.c'
then
	echo shar: "will not over-write existing file 'call.c'"
else
cat << \SHAR_EOF > 'call.c'
#include <dial.h>
#include <stdio.h>

CALL	call;

main (argc, argv)
int	argc;
char	**argv;
{
	if (strcmp (argv[0], "call") == 0)
		exit (do_call (argc, argv));
	else if (strcmp (argv[0], "hangup") == 0)
		exit (do_hup (argv, argv));

	fprintf (stderr, "usage: call tty baud telno\n");
	fprintf (stderr, "       hangup tty baud\n");
	exit (1);
}

do_call (argc, argv)
int	argc;
char	**argv;
{
	int	fd;

	if (argc < 4) {
		fprintf (stderr, "usage: call tty baud telno\n");
		exit (1);
	}
	call.line = argv[1];
	call.baud = atoi (argv[2]);
	call.telno = argv[3];
	
	fd = dial (&call);
	if (fd < 0) {
		merror (argv[0]);
		exit (2);
	}
	undial (fd);
	return (0);
}

do_hup (argc, argv)
int	argc;
char	**argv;
{
	int	fd;

	if (argc < 3) {
		fprintf (stderr, "usage: hangup tty baud\n");
		exit (1);
	}
	call.line = argv[1];
	call.baud = atoi (argv[2]);
	
	fd = dial (&call);
	if (fd < 0) {
		merror (argv[0]);
		exit (2);
	}
	hangup (fd);
	undial (fd);
	return (0);
}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II		HECI Exploration Co. Inc.
UUCP:	...!ihnp4!killer!jfh	11910 Greenville Ave, Suite 600
"Don't Have an Oil Well?"	Dallas, TX. 75243
" ... Then Buy One!"		(214) 231-0993
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list