[comp.dcom.modems] T2500/SCO Xenix Configuration

bbs@alchemy.UUCP (BBS Administration) (03/29/91)

After trying for several days to get things to work the way I want them, I
am putting my faith in the hands of USENET...

My system is a '386 machine running SCO Xenix v2.3.2GT. I have a "dumb"
serial card installed and have a Telebit T2500 attached using "tty1A".
I have set up the "/etc/ttys" file to use the "gettydefs" entry that
locks the speed between the computer and the modem at 19200 bps (it's
label is "n" in the gettydefs file). I have configured the "Devices"
file to use the "dialTBIT" dialer and have appended "u" to the phone
number of systems I network with that have a Telebit modem.

Here's what I want to be able to do:

1) Connect, via uucico, to other machines running Unix and transfer files.

This seems to work rather well with my current setup. I followed the
instructions on page 14 of the "Fast Start Guide" and this operation
seems to work consistently.

2) Allow users to dial into my BBS at any speed supported by the T2500.

This works sporadically. One problem is that, after I connect at PEP
speed during a UUCP exchange with my feed site, my T2500 will only
connect with modems dialing in at PEP speed. I have configured the
"A" profile with "S50=0" and "S92=1" so that automatic speed detection
is used, and PEP tones come last, but things still do not get reset
properly after my UUCP exchange. I went so far as to use my terminal
program (called XCMALT) to talk directly to the modem after a PEP
connection and issue an "ATZ" in the hopes that this would reset the
modem to the proper state. When I dialed in with another computer,
my modem picked up the phone, then paused for a while, sent no tones
at all, then hung up.

I'm not sure, but I think that if I do an "ATZ" then examine things
with an "AT&N" then write things back with an "AT&W" that >then< the
modem answers correctly (I think). And when it does answer, it will
continue to answer correctly until I dial out again at PEP speed
(or maybe it dies when someone else dials in at PEP speed, I'm not
too sure at what point it decides to go out to lunch).

3) Allow me to dial out using XCMALT to various systems and when I'm
done, reset to the proper mode for users to dial in.

Usually, this works, but not always. I think that sometimes the S50
register gets set to 255 (via the "dialTBIT" dialer which is used
when I connect to my feed site) and is still set when I try to connect
to a 2400 bps modem. If I issue an ATZ then the "S50=0" setting gets
loaded into memory and I can connect.

[End of description of problems]

My questions are:

1) How do the settings in Profile "A" (I have the physical button set to
this profile and the S255 register set to 0 so the T2500 observes this
setting) get loaded back into memory once uucico stops and the getty on
tty1A is respawned so users can dial in at ANY speed?

2) A stupid question? How can one examine the CURRENT settings in memory
of the T2500? All I could find was the &N commands that shows you what
is in NRAM, but nothing about how to display the current settings in RAM?

3) How do I solve all my problems?

I would think there must be many people out there using the exact same
hardware I am, and running it on the exact same software. Can someone
please tell me how they set up their system? Is there something I'm
missing in the "/usr/lib/uucp" directory that is improperly configured
or something? Could someone send a copy of the relevant files? Did
anyone modify the dialTBIT.c program to make it work better (?) with
the T2500 (or I heard of someone who modified it to use a "v" after
the phone number to >require< that the connection be made at v32)?

If it's any help: here's the profile "A" settings:

E0 F1 M0 Q4 P V1 W0 X1 Y0 &P0 &T4     Version GF7.00-T2500SA
S00=001 S01=000 S02=043 S03=013 S04=010 S05=008 S06=002 S07=040 S08=002 S09=006
S10=007 S11=070 S12=050 S18=000 S25=005 S26=000 S38=000 
S41=000 S45=000 S47=004 S48=000 S49=000 
S50=000 S51:005 S52:001 S54:003 S55:003 S56=017 S57=019 S58=003 S59=000 
S61:099 S62=003 S63=001 S64:001 S65=000 S66:001 S67:001 S68:003 S69=000 
S90=000 S91=000 S92:001 S93=008 S94=001 S95:002 S96=001 S97:001 S98=003 
S100=000 S101=000 S102=000 S104=000 S105=001 S106:001 S107=020 
S110=255 S111=255 S112=001 
S121=000 S130:005 S131:001 
S150=000 S151=004 S152=001 S153=001 S154=000 S155=000 S157=000 S158=000 
S160=010 S161=020 S162=002 S163=003 S164=007 S169=000 S255=000 

Oh, and one more interesting thing I found today... I wrote a gateway
program between Unix and a BBS system called "ProLine" (it runs on
Apple II computers). The transport mechanism is simply Xmodem. After
installing the T2500 the Unix system could >receive< files from the
Apple (since the Apple is in control of sending each packet) but
when the Unix side sends a file using Xmodem, the "send" light goes
on and stays on without waiting for the Apple to ACK the packets. If
I simply change modems, this problem goes away, so it must be the
T2500 (or could it be related to flow control, XON/XOFF, something
like that?)

Hoping to hear from all you Telebit experts!

-- John

John Donahue, Senior Partner | UUCP: ucrmath!alchemy!{bbs, gumby} | The Future
  Alchemy Software Designs   | INET: {bbs, gumby}@alchemy.UUCP    | Begins Now
-------------------+---------+------------------------------------+-----------
Communique On-line | +1-714-278-0862 {12, 24, 96v32, 19.2k} T2500 | Next Wave:
Information System |    Alchemy Software Designs Support System   | Communique

gandrews@netcom.COM (Greg Andrews) (03/30/91)

In article <390@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>After trying for several days to get things to work the way I want them, I
>am putting my faith in the hands of USENET...
>
>My system is a '386 machine running SCO Xenix v2.3.2GT. I have a "dumb"
>serial card installed and have a Telebit T2500 attached using "tty1A".
>I have set up the "/etc/ttys" file to use the "gettydefs" entry that
>locks the speed between the computer and the modem at 19200 bps (it's
>label is "n" in the gettydefs file). I have configured the "Devices"
>file to use the "dialTBIT" dialer and have appended "u" to the phone
>number of systems I network with that have a Telebit modem.
>
>Here's what I want to be able to do:
>
>1) Connect, via uucico, to other machines running Unix and transfer files.
>
>This seems to work rather well with my current setup. I followed the
>instructions on page 14 of the "Fast Start Guide" and this operation
>seems to work consistently.
>

The Fast Start Guide simply can't compete with a real, live SCO Xenix
setup guide available from Telebit Tech Support.

Note that the dialTBIT distributed with SCO Xenix (and Unix) was written
for the TrailBlazer Plus modem and not the T2500.  It can't handle the
V.32 result codes that the modem will return, so it chokes on V.32 calls.

There are hacked versions of dialTBIT on the net (dunno where).

>
>2) Allow users to dial into my BBS at any speed supported by the T2500.
>
>This works sporadically. One problem is that, after I connect at PEP
>speed during a UUCP exchange with my feed site, my T2500 will only
>connect with modems dialing in at PEP speed. I have configured the
>"A" profile with "S50=0" and "S92=1" so that automatic speed detection
>is used, and PEP tones come last, but things still do not get reset
>properly after my UUCP exchange. I went so far as to use my terminal
>program (called XCMALT) to talk directly to the modem after a PEP
>connection and issue an "ATZ" in the hopes that this would reset the
>modem to the proper state. When I dialed in with another computer,
>my modem picked up the phone, then paused for a while, sent no tones
>at all, then hung up.
>
>I'm not sure, but I think that if I do an "ATZ" then examine things
>with an "AT&N" then write things back with an "AT&W" that >then< the
>modem answers correctly (I think). And when it does answer, it will
>continue to answer correctly until I dial out again at PEP speed
>(or maybe it dies when someone else dials in at PEP speed, I'm not
>too sure at what point it decides to go out to lunch).
>

Set your S52 register to 2.  That will do the equivalent of "ATZ"
after every call out and in, resetting your S50 back to 0.

>
>3) Allow me to dial out using XCMALT to various systems and when I'm
>done, reset to the proper mode for users to dial in.
>
>Usually, this works, but not always. 
>  [theory about cause of problem deleted - use the S52=2 above]
>
>My questions are:
>
>1) How do the settings in Profile "A" (I have the physical button set to
>this profile and the S255 register set to 0 so the T2500 observes this
>setting) get loaded back into memory once uucico stops and the getty on
>tty1A is respawned so users can dial in at ANY speed?
>

If an "ATZ" command is sent to the modem, or DTR drops when S52=2.

>
>2) A stupid question? How can one examine the CURRENT settings in memory
>of the T2500? All I could find was the &N commands that shows you what
>is in NRAM, but nothing about how to display the current settings in RAM?
>

"ATN?" does that.

>
>3) How do I solve all my problems?
>

The ones you described above?  S52=2.

>
>[bunch of stuff deleted]
>
>E0 F1 M0 Q4 P V1 W0 X1 Y0 &P0 &T4     Version GF7.00-T2500SA
>S00=001 S01=000 S02=043 S03=013 S04=010 S05=008 S06=002 S07=040 S08=002 S09=006
>S10=007 S11=070 S12=050 S18=000 S25=005 S26=000 S38=000 
>S41=000 S45=000 S47=004 S48=000 S49=000 
>S50=000 S51:005 S52:001 S54:003 S55:003 S56=017 S57=019 S58=003 S59=000 
>S61:099 S62=003 S63=001 S64:001 S65=000 S66:001 S67:001 S68:003 S69=000 
>S90=000 S91=000 S92:001 S93=008 S94=001 S95:002 S96=001 S97:001 S98=003 
>S100=000 S101=000 S102=000 S104=000 S105=001 S106:001 S107=020 
>S110=255 S111=255 S112=001 
>S121=000 S130:005 S131:001 
>S150=000 S151=004 S152=001 S153=001 S154=000 S155=000 S157=000 S158=000 
>S160=010 S161=020 S162=002 S163=003 S164=007 S169=000 S255=000 
>

The S58=3 setting will hose your XMODEM, YMODEM, and uucp file transfers
unless they are spoofed by the modem (available only in PEP and V.32/MNP
connections).  S58=0 might be a better setting, or S58=2 S68=255 if your 
system can support RTS/CTS flow control.

>
>Oh, and one more interesting thing I found today... I wrote a gateway
>program between Unix and a BBS system called "ProLine" (it runs on
>Apple II computers). The transport mechanism is simply Xmodem. After
>installing the T2500 the Unix system could >receive< files from the
>Apple (since the Apple is in control of sending each packet) but
>when the Unix side sends a file using Xmodem, the "send" light goes
>on and stays on without waiting for the Apple to ACK the packets. If
>I simply change modems, this problem goes away, so it must be the
>T2500 (or could it be related to flow control, XON/XOFF, something
>like that?)
>

Sounds like you have the spoofing turned on for XMODEM/YMODEM.  You
don't seem to have S111=20, so you must be setting it in a dialer
script or including an 'x' in the phone number for dialTBIT.

Or the other system is calling you and they have S111=20 in their
modem when they call.

Why do you call this a 'problem'?

-- 
.------------------------------------------------------------------------.
|  Greg Andrews   |       UUCP: {apple,amdahl,claris}!netcom!gandrews    |
|                 |   Internet: gandrews@netcom.COM                      |
`------------------------------------------------------------------------'

jpr@jpradley.jpr.com (Jean-Pierre Radley) (03/31/91)

In article <390@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>This works sporadically. One problem is that, after I connect at PEP
>speed during a UUCP exchange with my feed site, my T2500 will only
>connect with modems dialing in at PEP speed. I have configured the
>"A" profile with "S50=0" and "S92=1" so that automatic speed detection
>is used, and PEP tones come last, but things still do not get reset
>properly after my UUCP exchange. I went so far as to use my terminal
>program (called XCMALT) to talk directly to the modem after a PEP
>connection and issue an "ATZ" in the hopes that this would reset the
>modem to the proper state. When I dialed in with another computer,
>my modem picked up the phone, then paused for a while, sent no tones
>at all, then hung up.

That shouldn't be necessary. On completion, uucico would be calling dialTBIT
again to hang up the modem and reset it.

>3) Allow me to dial out using XCMALT to various systems and when I'm
>done, reset to the proper mode for users to dial in.

XCMALT, like dialTBIT, drops DTR for a moment or so, which is designed to have
the modem reset. Works if S52=2.

>2) A stupid question? How can one examine the CURRENT settings in memory
>of the T2500? All I could find was the &N commands that shows you what
>is in NRAM, but nothing about how to display the current settings in RAM?

It's ATN?, which is in the manual...

>3) How do I solve all my problems?

There's a dialTBALL.c that was propagated, which encompasses the TB2500; the
Xenix 2.3 dialTBIT was written before that modem was sold. Do you need that?
Email me back.

-- 

 Jean-Pierre Radley   NYC Public Unix   jpr@jpradley.jpr.com   CIS: 72160,1341

bbs@alchemy.UUCP (BBS Administration) (03/31/91)

In article <1991Mar29.233228.17548@netcom.COM> gandrews@netcom.COM (Greg Andrews) writes:
>In article <390@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>>This seems to work rather well with my current setup. I followed the
>>instructions on page 14 of the "Fast Start Guide" and this operation
>>seems to work consistently.

>The Fast Start Guide simply can't compete with a real, live SCO Xenix
>setup guide available from Telebit Tech Support.

So, just dial 1-800-TELEBIT and ask for one? I guess maybe I should send
in my registration card first (do they check?)

>Note that the dialTBIT distributed with SCO Xenix (and Unix) was written
>for the TrailBlazer Plus modem and not the T2500.  It can't handle the
>V.32 result codes that the modem will return, so it chokes on V.32 calls.
>There are hacked versions of dialTBIT on the net (dunno where).

If anyone knows of such a thing, I'd love to hear about it as it would
be nice to have it understand V.32 connections, etc.

>>2) Allow users to dial into my BBS at any speed supported by the T2500.

>Set your S52 register to 2.  That will do the equivalent of "ATZ"
>after every call out and in, resetting your S50 back to 0.

The problem >was< the dialTBIT program. I modified it to do an ATZ just
before it closed the modem port and this fixed things up. I also changed
S52 to 2 though and it didn't adversly affect anything, so I'm going to
leave it set to 2 -- thanks!

>>2) A stupid question? How can one examine the CURRENT settings in memory
>>of the T2500?

>"ATN?" does that.

Once again, thanks. I guess I should have looked harder, but I also thought
it might be discussed someplace during installation.

[My register settings]

>The S58=3 setting will hose your XMODEM, YMODEM, and uucp file transfers
>unless they are spoofed by the modem (available only in PEP and V.32/MNP
>connections).  S58=0 might be a better setting, or S58=2 S68=255 if your 
>system can support RTS/CTS flow control.

Here's the deal:

You are correct. That was the problem. Once I changed S58 to 0, the other
site connecting at 2400 bps (thus >not< spoofing the UUCP "g" protocol)
was able to transfer files. Thanks!

Still, there are problems. Once this was changed, I called another system
at V.32 speed and issued the "uulog" command which sent an enormous
amount of data to my system. At the same time, I was reading the man
page on my machine for "uulog" (which happens to be on the same page as
UUCP and is quite lengthy, plus nroff is a CPU pig, etc.) and the data
being transmitted to my machine was stopped and could not be started
again until I manually pressed ^Q. Obviously, if this were to happen
during a UUCICO exchange, I doubt the ^Q would be sent.

This occurred when I used the S58=2 and S68=255 method you also mentioned.
It would appear that >no< flow control is bad, and that makes sense. But
I'm wondering how to overcome the fact that my system does not properly
interpret the RST/CTS signals.

Is the solution installing the FAS serial driver (I have version 2.08
dated February 3, 1991 -- is this the latest?) or installing the 
NS16550AFN UART chip on my "dumb" serial card or both? Or is it something
else altogether?

>.------------------------------------------------------------------------.
>|  Greg Andrews   |       UUCP: {apple,amdahl,claris}!netcom!gandrews    |
>|                 |   Internet: gandrews@netcom.COM                      |
>`------------------------------------------------------------------------'

Once again, THANK YOU for answering this article! I was at the end of my
rope and am really happy to have access to USENET. Now, my rope has been
lengthened, but I'm at your mercy once again...

Hope to get more great answers soon,

-- John

John Donahue, Senior Partner | UUCP: ucrmath!alchemy!{bbs, gumby} | The Future
  Alchemy Software Designs   | INET: {bbs, gumby}@alchemy.UUCP    | Begins Now
-------------------+---------+------------------------------------+-----------
Communique On-line | +1-714-278-0862 {12, 24, 96v32, 19.2k} T2500 | Next Wave:
Information System |    Alchemy Software Designs Support System   | Communique

jpr@jpradley.jpr.com (Jean-Pierre Radley) (04/02/91)

In article <398@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>In article <1991Mar29.233228.17548@netcom.COM> gandrews@netcom.COM (Greg Andrews) writes:
>>In article <390@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:

>>Note that the dialTBIT distributed with SCO Xenix (and Unix) was written
>>for the TrailBlazer Plus modem and not the T2500.  It can't handle the
>>V.32 result codes that the modem will return, so it chokes on V.32 calls.
>>There are hacked versions of dialTBIT on the net (dunno where).
>
>If anyone knows of such a thing, I'd love to hear about it as it would
>be nice to have it understand V.32 connections, etc.

OK, I captured dialTBALL.c once.

---------------------------------------------
/*
 *  Function:	dialer program for the Telebit Trailblazer
 *
 *  Usage:	dial ttyname telnumber speed 
 *		dial -h ttyname speed
 *		dial -z ttyname speed
 *
 *  Returns:	0x80	bit = 1 if connection failed
 *		0x10	bit = 1 if line is also used for dialin #ifndef HDUU
 *		0x0f	if msb=1: error code
 *			if msb=0: connected baud rate (0=same as dialed baud)
 *
 *		Note: getty calls the dialer with -h whenever it starts up
 *		on a line enabled in /etc/ttys and listed in Devices with
 *		this dialer.
 *
 *		The user should call the dialer with -z to initialize
 *		the modem when it is first installed: the -z option writes
 *		default settings into the non-volatile memory of the modem.
 *
 *		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 such as phone busy, no
 *		answer, etc.  Attempts to connect to this remote system
 *		should be stopped.
 *
 *  Documents:	Telebit Trailblazer manual
 *		Telebit T2500 manual
 *		Telebit Trailblazer Plus PC manual (T18PC)
 *
 *  Note:	This source file can be used both for the old UUCP and
 *		for the new HoneyDanBer UUCP.  For the latter, HDUU may
 *		be defined to avoid calls to the HD ungetty program - which
 *		assumes that uugetty is used, and so simply returns SUCCESS.
 *		However, dialer binaries for the old UUCP are equally valid
 *		for the new HoneyDanBer UUCP (but make an unnecessary call
 *		to the null ungetty, supplied for backward compatibility).
 *
 *  Note:	Changes for Telebit T2500 and TrailblazerPlus PC modems made
 *		by Scott O'Connell & Bill Blue (ipars!scotto, crash!bblue)
 */
static char sccsid[] = "@(#)dialTBALL.c	 89/11/23 ";

#define SLIP 

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

/* 
 * define T2500 for the T2500, TPC for the T18PC, or V3 for the older
 * rev 3 ROMS on a standard Trailblazer, either here or in the makefile.
 * If all are undefined, default becomes standard newer Trailblazer.
 *
 * also, define WAITFORDT to always wait for dialtone before continuing.
 *
 * define SLOWRITE if a one second delay seems necessary prior to each
 * modem *string* write.  It was a default in the original dialer.
 */

#define T2500		/**/
* #define TPC		/**/
/* #define V3		/**/
#define WAITFORDT	/**/
/* define SLOWRITE	/**/

#ifndef B19200
#define B19200 EXTA
#endif

#ifndef B38400
#define B38400 EXTB
#endif

/* 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 */

/* error return 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_HANGUP	10	/* hangup failed */
#define RCE_NORESP	11	/* Modem didn't respond. */
#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		256
#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 - set up for DIDO - don't assume anything about modem state
 *	or defaults.
 *
 *  NOTE: 82 characters is the maximum for a Telebit command line.
 *
 * &F		- Reload factory defaults
 * E0		- Don't echo commands
 * F1		- Turn off echoplex (no local echo)
 * M0		- Speaker disabled at all times
 * Note: M0 does not apply to the PC card version.  It has no speaker!
 * Q4		- Don't be quiet, but don't tell us about RINGs
 * V1		- Verbose on; return english result codes
 * X3		- Use extended codes including MNP and PEP codes
 * S0=1		- Answer on first ring
 * S2=043	- Set escape sequence to be +++
 * S6=12	- Set # seconds to wait for dialtone (default is 2) used TPC only
 * S7=40	- Set connect timeout to default value
 * S10=4	- Set for T2500 only, loss of carrier to disconnect delay
 * S25=2	- Set for T2500 only, DTR down time for action
 * S45=0	- Disable remote modem access
 * S48=1	- All 8 bits are significant
 * S50=0	- Use automatic connect speed determination
 * S51=254	- Set serial port baud rate automatically, using 19200 for PEP.
 * S52=2	- Go on hook when dtr drops and reset to NV-RAM
 * S53=1	- DCD signal tracks remote carrier, DSR on when modem ready
 * S54=3	- Pass BREAK signal to remote modem
 * S55=0	- Respond sanely to command escape sequence
 * S58=2	- DTE uses CTS/RTS flow control.
 * S59=052	- Set prompt to "*" (?)
 * S60=0	- Use 8 data, 1 stop, no parity
 * S66=0	- Don't lock interface speed, just go with the flow.
 * S68=255	- DCE uses whatever flow control DTE uses
 * S92=0	- Issue PEP tones at the beginning of answer sequence
 * S95=2	- Set MNP Auto-Reliable mode
 * S110=255	- Use data compression when the remote modem requests it.
 * Note: S110 doesn't seem to work in Trailblazer Rev-3 ROMS
 * S111=255	- Accept any protocol
 * &W		- Write all of this into Non-Volatile RAM
 * Note: &W does not apply to the PC card version.  It has no NVRAM!
 *
 * Note that we have to break the setup string into two command lines.
 */


#ifdef T2500
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S10=4S25=2S45=0S48=1S50=0S51=254S52=2S53=1S54=3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0S95=2S110=255S111=255&W\r"
#endif
#ifdef TPC
#define	MDSETUP1 "AT&FE0F1Q4V1X3S6=12S2=043S45=0S48=1S50=0S51=254S52=2S53=1S54=3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0s110=255S111=255\r"
#endif
#ifdef V3
/* this is currently specific to crash wrt s51, s66 and s95 */
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S45=0S48=1S50=0S51=254S52=2S53=1S54=3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0S95=2S111=255&W\r"
#endif
#if !defined(T2500) && !defined(TPC) && !defined(V3)
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S45=0S48=1S50=0S51=254S52=2\r"
#define MDSETUP2 "ATS53=1S54=3S55=0S58=2S60=0S66=0S68=255S92=1S110=255S111=255&W\r"
#endif

/*
 * MDXONXOFF - Use XON/XOFF flow control
 *
 *  S58=3	DTE Uses XON/XOFF flow control (DCE will follow DTE)
 */
#define MDXONXOFF "ATS58=3\r"

/*
 *  MDDIALKERM - Dial an answering TBIT modem using kermit protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=10	- Use kermit (no parity) protocol.
 */
#define	MDDIALKERM "ATS7=60S50=255S111=10\r"

/*
 *  MDDIALUUCP - Dial an answering TBIT modem using uucp G protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=30	- Use uucp G protocol.
 */
#define	MDDIALUUCP "ATS7=60S50=255S111=30\r"

/*
 *  MDDIALXMDM - Dial an answering TBIT modem using [xy]modem protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=20	- Use [xy]modem protocol.
 */
#define	MDDIALXMDM "ATS7=60S50=255S111=20\r"

/*
 *  MDCOMPRESS - Set compression mode on
 *
 *  S110=1	- Data compression is enabled provided the connect is PEP
 *		- and the remote end is allows compression.
 */
#define MDCOMPRESS "ATS110=1\r"

/*
 *	MDFORCEPEP	- Force a PEP mode connection
 *
 *	S7=60	- Give it a full minute to get a PEP recognition code
 *	S50=255	- Force PEP mode operation
 */
#define MDFORCEPEP	"ATS7=60S50=255\r"

/*
 *	MDFORCEV32	- Force a V32 mode connection
 *
 *	S50=6	- Force V.32 operation
 */
#define MDFORCEV32	"ATS50=6\r"	/* T2500 */

/*
 *	MDMNPMODE	- Set up MNP mode for slow connections
 *
 *	S95=2	- Enable Auto-reliable mode
 */
#define MDMNPMODE	"ATS95=2\r"

/*
 *	MDECHOSUP	- Enable Echo Supressor Compensation
 *
 *	S121=1	- Enable Echo Suppressor Compensation
 */
#define MDECHOSUP	"ATS121=1\r"

/*
 *  MDUNLOCK	- Unlock interface speed.
 */
#define MDUNLOCK "ATS66=0\r"

/*
 *  MDVALID - Allow only these characters to reach the modem.
 */
#define MDVALID		"0123456789CcEeFfKkMmNnPpRrTtUuVvWwXx*#,!/()-"
/* T2500 (added "Vv" to valid list) */

/*
 *  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		"ATZ\r" 

/*
 *  MDDIALOUT - Minor changes to set when dialing out.
 *
 *  S66=1	- Lock the interface speed.
 *  S95=0	- Disable MNP mode unless requested otherwise
 *  S110=0	- Disable data compression unless requested otherwise
 */

#ifdef T2500
#define	MDDIALOUT "ATS66=1S95=0S110=255\r"
#endif
#ifdef V3
#define	MDDIALOUT "ATS66=1S95=0\r"
#endif
#if !defined(T2500) && !defined(V3)
#define MDDIALOUT "ATS66=1S110=255\r"
#endif

/*
 *  MDATTN - Get modems attention
 */
#define	MDATTN		"AT\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.
 */
#define	OK		0	/* Command succesful */
#define	NOCARRIER	1	/* Connect timeout has occurred */
#define	ERROR		2	/* Command error encountered */
#define	NODIALTONE	3	/* No dial tone was detected */
#define	BUSY		4	/* Remote telephone is busy */
#define	NOANSWER	5	/* Remote site did not answer */
#define	RRING		6	/* Remote site is ringing */
#define CONNECT300REL	7	/* Connection established @ 300 using MNP */
#define CONNECT1200REL	8	/* Connection established @ 1200 using MNP */
#define CONNECT2400REL	9	/* Connection established @ 2400 using MNP */
#define	CONNECT300	10	/* Connection established @ 300 */
#define	CONNECT1200	11	/* Connection established @ 1200 */
#define CONNECT2400	12	/* Connection established @ 2400 */
#define CONNECTFASTKERM	13	/* Connection established @ 19200/Kermit */
#define CONNECTFASTXMDM	14	/* Connection established @ 19200/Xmodem */
#define CONNECTFASTUUCP	15	/* Connection established @ 19200/UUCP */
#define CONNECTFAST	16	/* Connection established using PEP */
/* T2500 (17-20) */
#define CONNECT4800	17	/* Connection established @ 4800 */
#define CONNECT4800REL	18	/* Connection established @ 4800 using MNP */
#define CONNECT9600	19	/* Connection established @ 9600 */
#define CONNECT9600REL	20	/* Connection established @ 9600 using MNP */
#ifdef SLIP
#define LOGIN		21	/* login prompt */
#define PASS		22	/* password prompt */
#endif

char *mdmsgs[] = {
/* 0 */		"OK",
/* 1 */		"NO CARRIER",
/* 2 */		"ERROR",

/* Note:	The original SCO dialer defined "NO DIALTONE".  In my testing
 *		I have learned that the Trailblazer Plus PC, the Trailblazer
 *		and the T2500 respond with "NO DIAL TONE".  This may need to
 *		be changed for your modem. -- Scott
 */

/* 3 */		"NO DIAL TONE",
/* 4 */		"BUSY",
/* 5 */		"NO ANSWER",
/* 6 */		"RRING",
/* 7 */		"CONNECT 300/REL",
/* 8 */		"CONNECT 1200/REL",
/* 9 */		"CONNECT 2400/REL",
/* 10 */	"CONNECT 300",
/* 11 */	"CONNECT 1200",
/* 12 */	"CONNECT 2400",
/* 13 */	"CONNECT FAST/KERM",
/* 14 */	"CONNECT FAST/XMDM",
/* 15 */	"CONNECT FAST/UUCP",
/* 16 */	"CONNECT FAST",
/* 17 */	"CONNECT 4800",		/* T2500 */
/* 18 */	"CONNECT 4800/REL",	/* T2500 */
/* 19 */	"CONNECT 9600",		/* T2500 */
/* 20 */	"CONNECT 9600/REL",	/* T2500 */
#ifdef SLIP
/* 21 */	"ogin:",
/* 22 */	"ord:",
#endif
		0
};

char *strchr();
int alrmint();
int abort();

struct termio term;			/* for storing tty parameters	*/
int Debug = DBG;			/* set when debug flag is given	*/
int dialing;				/* set while modem is dialing	*/
int fd = -1;				/* file descriptor for acu	*/
int errflag = 0;			/* set on errors		*/
int hflag = 0;				/* set to hangup modem		*/
int zflag = 0;				/* set to setup modem		*/
int highbaud, lowbaud;			/* baud rate limits		*/
int retcode = RC_FAIL;			/* return code			*/
int compress = 0;			/* set if compression requested */
int mnpmode = 0;			/* set if MNP mode requested    */
int forcepep = 0;			/* set if PEP mode requested    */
int forcev32 = 0;			/* set if V32 mode requested (T2500) */
int echosup = 0;			/* echo supressor compensation  */
int xonxoff = 0;			/* XON/XOFF flow control mode   */
int speedlock = 1;			/* set when baud rate is locked */
int kermcall = 0;			/* set if kermit call		*/
int uucall = 0;				/* set if uucico call		*/
int xmdmcall = 0;			/* set if [xy]modem call	*/
int timeout;				/* how long to wait for alarm	*/
int dial_retry = DIAL_RETRY;		/* dial retry count		*/
int pid;				/* stores child's pid		*/
int c;					/* temporary storage		*/
char command[MAXLINE];			/* modem command buffer		*/
char *p;				/* temporary storage		*/
char *acu;				/* device to dial through	*/
char *phone;				/* phone number to dial		*/
extern int optind;			/* for getopt ()		*/
extern char *optarg;			/* for getopt ()		*/

#ifdef SLIP
int slipline = 0;			/* set if SLIP connection	*/
char	lockname[64], *meslip, *themslip;
FILE	*fp1;
#endif /* SLIP */

#define	toprint(x)	((x)<' '?((x)+'@'):'?')

/* vgets - Format one character in "always printable" format (like cat -v)
 */

char *
vgets(c, f)
unsigned char c;
FILE *f;
{
	static char buffer[10];
	char *pnt;

	pnt = buffer;
	if (iscntrl(c) || !isprint(c)) {
		if (!isascii(c)) {			/* Top bit is set */
			*pnt++ = 'M';
			*pnt++ = '-';
			c = toascii(c);			/* Strip it */
		}
		if (iscntrl(c)) {			/* Not printable */
			*pnt++ = '^';
			c = toprint(c);			/* Make it printable */
		}
	}
	*pnt++ = c;
	*pnt = '\0';
	return(buffer);
}


/*
 * translate the pairs of characters present in the first
 * string whenever the first of the pair appears in the second
 * string.
 */
static void
translate(ttab, str)
register char *ttab, *str;
{
	register char *s;

	for(;*ttab && *(ttab+1); ttab += 2)
		for(s=str;*s;s++)
			if(*ttab == *s)
				*s = *(ttab+1);
}


main (argc,argv)
	int argc;
	char *argv[];
{
	/*
	 *  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, abort);

	/*
	 * Parse command line options.
	 */
	while ((c = getopt(argc, argv, "hzsx:")) != EOF)
	{
		switch(c)
		{
			case 'h':
				hflag++;
				break;
			case 'z':
				zflag++;
				break;
			case 'x':
				Debug = atoi(optarg);
				break;
#ifdef SLIP
			case 's':
				slipline++;
				break;
#endif /* SLIP */
			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 || zflag)
	{
		if (argc - optind != 2)  errflag++ ;
	}
#ifdef SLIP
	else if (slipline)
	{
		if (argc - optind != 5)  errflag++;
	}
#endif
	else
	{
		if (argc - optind != 3)  errflag++ ;
	}

	if (errflag)
	{
		if (hflag)
		{
			fprintf (stderr,
				"Usage:\t%s -h devicename speed\n", argv[0]);
		}
		else if (zflag)
		{
			fprintf (stderr,
				"Usage:\t%s -z devicename speed\n", argv[0]);
		}
		else
#ifdef SLIP
		if (slipline)
		{
			fprintf(stderr,
				"Usage:\t%s -s devicename number speed ipme ipthem\n", argv[0]);
		}
		else
#endif
		{
			fprintf (stderr,
				"Usage:\t%s devicename number speed\n",
				argv[0]);
		}
		exit(RC_FAIL | RCE_ARGS);
	}

	acu = argv[optind++];

	if (!(hflag || zflag))
	{
		phone = strdup(argv[optind++]);
		translate("=,-,", phone);
		if (strlen(phone) != strspn(phone, MDVALID))
		{
			fprintf(stderr, "dial: Bad phone number %s\n", phone);
			exit(RC_FAIL | RCE_PHNO);
		}
		if (strpbrk(phone, "CcEeFfKkMmNnPpTtUuVvXx"))
/* T2500 added "Vv" */
		{
		    char *phoneno, *ptr;
		    if (strpbrk(phone, "Cc"))
		    {
			compress++;
			DEBUG(4, "COMPRESS MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Ee"))
		    {
			echosup++;
			DEBUG(4, "ECHO SUPRESSOR COMPENSATION REQUESTED%s",
				"\n");
		    }
		    if (strpbrk(phone, "Ff"))
		    {
			xonxoff++;
			DEBUG(4, "XON/XOFF MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Mm"))
		    {
			mnpmode++;
			DEBUG(4, "MNP MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Pp"))
		    {
			forcepep++;
			DEBUG(4, "PEP MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Vv"))
		    {
		    	forcev32++;
			DEBUG(4, "V32 MODE REQUESTED%s", "\n"); /* T2500 */
		    }
		    if (strpbrk(phone, "Uu"))
		    {
			if (strpbrk(phone, "KkXx"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "UUCP phone number, stripping %s\n", phone);
			uucall++;
		    }
		    else if (strpbrk(phone, "Kk"))
		    {
			if (strpbrk(phone, "UuXx"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "KERMIT phone number, stripping %s\n", phone);
			kermcall++;
		    }
		    else if (strpbrk(phone, "Xx"))
		    {
			if (strpbrk(phone, "KkUu"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "[XY]MODEM phone number, stripping %s\n",
				phone);
			xmdmcall++;
		    }
		    phoneno = strdup(phone);
		    *phone = '\0';
		    while ((ptr = strpbrk (phoneno,
		    	"CcEeFfKkMmNnPpTtUuVvXxMm")) != NULL)
 /* T2500 added Vv */
		    {
			*ptr = '\0';
			strcat(phone, phoneno);
			phoneno = ++ptr;
		    }
		    strcat(phone, phoneno);
		    DEBUG(5,"PROTOCOL phone number, got %s\n", phone);
		}
	}

	lowbaud = highbaud = checkbaud (atoi (argv[optind]));
	DEBUG (6, "checkbaud claims low/high baud is 0%o\n", lowbaud);

	/* test for a range of baudrates */

	if ((p = strchr (argv[optind], '-')) != NULL)
	{
		*p++ = '\0';
		highbaud = checkbaud (atoi(p));
		DEBUG (6, "checkbaud claims high baud is 0%o\n", highbaud);
	}

	if (!hflag)
	{
		ungetty ("dialer");
	}

#ifdef SLIP
	if (slipline) {
		meslip = strdup(argv[++optind]);
		themslip = strdup(argv[++optind]);
		DEBUG(4,"SLIP meslip: %s\n", meslip);
		DEBUG(4,"SLIP themslip: %s\n", themslip);
		sliplock();
	}
#endif /* SLIP */

	/*
	 * Open the modem file.
	 */
	mdopen ();

	/*
	 *  Timeout after 10 seconds if no response
	 */
	timeout = 10;
	signal(SIGALRM, alrmint);

	/*
	 * Hangup and exit if requested
	 */
	if (hflag)
	{
		DEBUG(1, "Hangup sequence begun%c", '\n');

		if (hangup (timeout) == -1)
		{
			cleanup (RC_FAIL | RCE_HANGUP);
		}
		cleanup (re_getty ("hangup"));
	}

	/*
	 * Since this is the first connect, the modem needs to
	 * figure out our baud rate.
	 */
	if (mdsync () == RC_FAIL)
	{
		cleanup (RC_FAIL | retcode);
	}

	/*
	 *  Initialize the modem
	 */
	if (zflag)
	{
	    DEBUG(6, "Initializing modem at %s\n", acu);

	    if (mdwrite(MDSETUP1) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    /*
	     * Since MDSETUP1 sets the "autobaud" mode, it forgot our
	     * baud rate...
	     */
		if (mdsync () == RC_FAIL)
		{
			cleanup (RC_FAIL | retcode);
		}

	    if (mdwrite (MDSETUP2) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    cleanup (re_getty ("modem init"));
	}

	/*
	 *  Reset and put modem into command mode
	 */
	reset:

	DEBUG(3, "Resetting modem%c", '\n');

	if (mdwrite(MDRESET) == -1)
	{
		cleanup(RC_FAIL | retcode);
	}

	if (mdread(timeout) != OK)
	{
		if (hangup(timeout) == -1)
		{
			cleanup(RC_FAIL | retcode | RCE_HANGUP);
		}
		goto reset;
	}

	/*
	 *  Must wait at least 0.5 seconds after reset
	 *  for Telebit to recover and receive commands.
	 *	Then, since MDRESET made it forget our baud rate,
	 *	we need to mdsync() again.
	 */
	nap(500L);

	if (mdsync () == RC_FAIL)
	{
		cleanup (RC_FAIL | retcode);
	}

#ifdef TPC
	/*  Initialize the modem since ATZ loses setup... (great modem)
         */
	    DEBUG(6, "Initializing modem (PC) at %s\n", acu);

	    if (mdwrite(MDSETUP1) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    /*
	     * Since MDSETUP1 sets the "autobaud" mode, it forgot our
	     * baud rate...
	     */
		if (mdsync () == RC_FAIL)
		{
			cleanup (RC_FAIL | retcode);
		}

	    if (mdwrite (MDSETUP2) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    cleanup (re_getty ("modem init"));
#endif /* TPC */

	/*
	 * Set up modem for generic dial out settings.
	 */
	DEBUG(3, "Setting DIAL OUT mode%c", '\n');

	if (mdwrite(MDDIALOUT) == -1)
	{
		cleanup(RC_FAIL | retcode);
	}
	if (mdread(timeout) != OK)
	{
		cleanup(RC_FAIL | retcode);
	}

#ifdef LATER
	/*
	 *  If we were given a specific baudrate to use, and that
	 *  baudrate less than or equal to 9600, unlock the modem speed.
	 */
#ifdef T2500
	if ((lowbaud == highbaud) && (highbaud <= B9600))
#else
	if ((lowbaud == highbaud) && (highbaud <= B2400))
#endif
	{
		char speedstr[9], speed[5];
		DEBUG(3, "Unlocking modem speed%c", '\n');

		if (mdwrite(MDUNLOCK) == -1)
		{
			cleanup(RC_FAIL | retcode);
		}
		if (mdread(timeout) != OK)
		{
			cleanup(RC_FAIL | retcode);
		}
		strcpy(speedstr, "ATS50=0\r");

		switch (lowbaud)
		{
		    case B300:
			strcpy(speedstr, "ATS50=1\r");
			strcpy(speed,"300");
			break;
		    case B1200:
			strcpy(speedstr, "ATS50=2\r");
			strcpy(speed,"1200");
			break;
		    case B2400:
			strcpy(speedstr, "ATS50=3\r");
			strcpy(speed,"2400");
			break;
#ifdef T2500
		    case B9600:
		        strcpy(speedstr, "ATS50=6\r");
			strcpy(speed,"9600");
			break;
#endif
		}
		DEBUG(3, "Setting modem connect speed to %s baud\n", speed);

		if (mdwrite(speedstr) == -1)
		{
			cleanup(RC_FAIL | retcode);
		}
		if (mdread(timeout) != OK)
		{
			cleanup(RC_FAIL | retcode);
		}
		speedlock = 0;
	}
#endif /* LATER */

	/*
	 * If kermcall is non-zero, we need to set up the modem for kermit
	 * and tell it not to connect to anything else.
	 */
	if (kermcall)
	{
		DEBUG(3, "Setting KERMIT mode%c", '\n');
		if (mdwrite(MDDIALKERM) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If uucall is non-zero, we need to set the modem up for uucp
	 * G protocol, and tell it not to connect to anything else.
	 */
	else if (uucall)
	{
		DEBUG(3, "Setting UUCP mode%c", '\n');
		if (mdwrite(MDDIALUUCP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If xmdmcall is non-zero, we need to set up the modem for [xy]modem
	 * and tell it not to connect to anything else.
	 */
	else if (xmdmcall)
	{
		DEBUG(3, "Setting XMODEM mode%c", '\n');
		if (mdwrite(MDDIALXMDM) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If compress is non-zero, we need to set up the modem for
	 * in-line data compression.
	 */
	if (compress)
	{
		DEBUG(3, "Setting COMPRESS mode%c", '\n');
		if (mdwrite(MDCOMPRESS) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If mnpmode is non-zero, we enable the modem
	 * to use MNP mode.
	 */
	if (mnpmode)
	{
		DEBUG(3, "Setting MNP mode%c", '\n');
		if (mdwrite(MDMNPMODE) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If forcepep is non-zero, we need to force the modem
	 * to use PEP mode.
	 */
	if (forcepep)
	{
		DEBUG(3, "Setting PEP mode%c", '\n');
		if (mdwrite(MDFORCEPEP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}
	/*
	 * If forcev32 is non-zero, we need to force the modem (T2500)
	 * to use V32 mode.
	 */
	if (forcev32)
	{
		DEBUG(3, "Setting V32 mode%c", '\n');
		if (mdwrite(MDFORCEV32) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If echosup is non-zero, we enable the modem's
	 * echo supressor compensation logic.
	 */
	if (echosup)
	{
		DEBUG(3, "Setting ECHO SUPRESSOR COMPENSATION mode%c", '\n');
		if (mdwrite(MDECHOSUP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If xonxoff is non-zero, we enable the modem's
	 * echo supressor compensation logic.
	 */
	if (xonxoff)
	{
		DEBUG(3, "Setting XON/XOFF mode%c", '\n');
		if (mdwrite(MDXONXOFF) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 *  Build up the phone number
	 */
#ifdef WAITFORDT
	sprintf(command, "ATDTW%s\r", phone);
#else
	sprintf(command, "ATDT%s\r", phone);
#endif
	/*
	 *  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;
	if (uucall) timeout *= 3;
	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 80 characters including "AT" */
	if (strlen(command) > 80)
		cleanup(RC_FAIL | RCE_PHNO | retcode);

redial:
	DEBUG(3, "DIALING %s\n", command);
	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 CONNECT300:
			/* c = matchbaud(B300, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECT1200:
			/* c = matchbaud(B1200, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECT2400:
			/* c = matchbaud(B2400, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECTFAST:
		case CONNECTFASTKERM:
		case CONNECTFASTXMDM:
		case CONNECTFASTUUCP:
		case CONNECT300REL:  	/*  not included in original	*/
		case CONNECT1200REL: 	/*  binary  file		*/
		case CONNECT2400REL: 	/*  -----------			*/
		case CONNECT4800:	/* T2500 */
		case CONNECT4800REL:	/* T2500 */
		case CONNECT9600:	/* T2500 */
		case CONNECT9600REL:	/* T2500 */

#ifdef SLIP
		 	if (slipline)
				sliplog();
#endif /* SLIP */

			cleanup(retcode); 
		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 (sig)
	int sig;
{
	signal (sig, nil);
}

hangup (htime)
	int htime;
{
	int retry = 4, rcode = -1;
	int old_retcode = retcode;
	int (*s)();

	DEBUG(6, "hangup - timeout %d\n", htime);
#ifdef SLOWRITE
	sleep(1);
#endif

	s = signal(SIGALRM, nil);	/* alarms are non-fatal here */

	retcode = (RC_FAIL | RCE_HANGUP); /* In case we are interrupted */

	while (retry--  &&  rcode == -1)
	{
		/*
		 * Send an escape to the modem to take it off-line.
		 */
		if (mdwrite (MDESCAPE) == -1)
		{
			retcode = old_retcode;
			return (rcode);
		}

		/* Give it a minute to think about it */
		sleep (1);

		/*
		 * MDESCAPE will return OK only if online,
		 * so ignore error return
		 */
		mdflush ();		/* waste "OK" if we were on line */

		/*
		 * First sync the baud rate.
		 * Don't bother sending the hangup stuff
		 * if we couldn't even sync baud rates.
		 */
		if (mdsync () != RC_FAIL)
		{
			if (mdwrite (MDHANGUP) == -1)
			{
				retcode = old_retcode;
				return (rcode);
			}

			switch(mdread (htime))
			{
				case OK:
				case NOCARRIER:		/* T2500 */
					rcode = 0;
			}

		}

		if (retry && rcode != 0)
		{
			/*
			 * Try closing the line and re-opening it.  This
			 * should cause a reset due to the DTR transition.
			 * Give the modem a couple of seconds to reset.
			 */
			DEBUG (3, "FAILED, Re-trying hangup%c", '\n');
			mdclose ();
			sleep (2);
			mdopen ();
		}
	}

	if (rcode == -1)
	{
		long now;

		(void) time (&now);
		fprintf (stderr, "dialer: HANGUP FAILED at %s", ctime (&now));
	}
	else
	{
		DEBUG(3, "Disabling escape%c", '\n');
		mdwrite (MDDSBLESC);		/* disable escape */
	}

	signal (SIGALRM, s);
	retcode = old_retcode;
	return (rcode);
}

/*
 *  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 **mp;
	register char *bp;
	char buf[MAXLINE];

	bp = buf;
	alarm(rtime);
	DEBUG(6, "MODEM returned %s", "<<");
	while (read(fd, &c, 1) == 1) {
		c &= 0177;
		if ((*bp = c) != '\0')
			*++bp = '\0';
		DEBUG(6, "%s", vgets(c));
		if (bp >= buf + MAXLINE) {
			alarm(0);
			DEBUG(4,">>-%s\n","FAIL");
			return(-1);
		}
		if (c == '\r') {
			if (substr("RRING", buf) == 0) {
				bp = buf;
				DEBUG(6,">>-%s\n", "OK");
				DEBUG(4,"got %s\n","RRING");
				DEBUG(6, "MODEM returned %s", "<<");
				continue;
			}
			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 response\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, "%s", vgets(*c));
		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);
	}
}

/*
 * Exit, making sure the modem hangs up and we
 * don't leave the tty ungetty'ed.
 */
abort (sig)
int sig;
{
	int error = retcode & ~(RC_FAIL | RC_ENABLED);

	signal(SIGINT, SIG_IGN);
	signal(sig, SIG_IGN);

	if (error != RCE_HANGUP)
	{
		if (hangup (timeout) == -1)
		{
			retcode |= (RC_FAIL);
		}
		else
		{
			/*
		 	* No need to call dial -h again.
		 	*/
			retcode &= ~RC_ENABLED;
		}
	}

	if (re_getty ("abort") == RC_FAIL)
	{
		retcode |= RC_FAIL;
	}

	if (fd != -1)
	{
		ioctl(fd, TCGETA, &term);
		term.c_cflag |= HUPCL;		/* make sure modem hangs up */
		ioctl(fd, TCSETA, &term);
		mdclose ();
	}

	if (sig)  retcode |= (RC_FAIL | RCE_SIG);
	exit (retcode);
}

/*
 *  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;
		case 2400:
			baudrate = B2400;
			break;
		case 4800:
			baudrate = B4800;
			break;
		case 9600:
			baudrate = B9600;
			break;
		case 19200:
			baudrate = B19200;
			break;
		case 38400:
			baudrate = B38400;
			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
 *		Bxxxxx		if low baud <= connected baud <= high baud
 *		RCE_SPEED	if connected baud rate is out of range
 */

matchbaud(cbaud, low, high)
int cbaud, low, high;
{
	/* uucp/cu assume highest baud */
	if ((cbaud == high) || (high > B9600)) return(0);	/* T2500 */
	if (low <= cbaud  &&  cbaud < high)  return(cbaud);
	return(RC_FAIL | RCE_SPEED);
}

/*
 * In order to figure out our baud rate, the modem needs
 * an "a" character.  We send it twice for good measure,
 * and pause 1/4 second after each one.
 */
mdsync()
{
	int (*old_alrm)();
	char buf[MAXLINE];
	int count = 0, n;

/* Note:	While the earlier Telebit modems needed this syncing
 *		routine, the T2500 with Rev-1 ROMS would miss the 
 *		next command sent after the mdsync().  This was because
 *		of a lower case 'a' being sent prior to an upper case
 *		'AT'.  I have been told this is fixed in Rev-2 ROMS,
 *		but since I haven't seen my T2500 miss an 'AT' yet,
 *		I bypass the syncing routine.  -- Scott
 */
#ifdef T2500
	return(0);	/* T2500 */
#endif /* T2500 */

	old_alrm = signal(SIGALRM, nil);	/* alarms are non-fatal here */

	DEBUG (7, "Syncing baud rate...", "");

	while (++count < 6)
	{
		/*
		 * Send 'a'<pause>'a'<pause>... to make the modem sync to our
		 * baud rate.
		 */
		 sendsync ();

		/*
		 * Send ATQ4 to make sure the modem has response codes
		 * enabled.  If the modem is talking our speed, this will
		 * always result in "OK".  First we eat output from
		 * the modem.
		 */
		mdflush ();
		mdwrite ("ATQ4\r");

		/*
		 * If we don't get "OK" in 2 seconds, we ain't gonna.
		 */
		if (mdread(2) == OK ) {
		   break;
		}
	}

	/*
	 * At debug level 9, we print an 'a' every time we send one.
	 * These dots make things look prettier.
	 */
	DEBUG (9, "%s", "...");

	signal (SIGALRM, old_alrm);

	if (count < 10)
	{
		DEBUG (7, "%s\n", "done.");
		return (0);
	}
	else
	{
		DEBUG (7, "%s\n", "FAIL");
		return (RC_FAIL);
	}
}

#define NSYNCS	4		/* Number of a's to send each time */

/*
 * Sendsync: Send a's to make the modem sync to our baud rate.
 */
sendsync ()
{
	int count = 0;
	
	while (count++ < NSYNCS)
	{
		write (fd, "a", 1);
		DEBUG (9, "%c", 'a');
		nap (250L); /* wait between each one */
	}
}

/*
 * Open the modem and set the baud rate.  Sets the global variable
 * "fd".
 */
int
mdopen ()
{
	/*
	 *  Must open with O_NDELAY set or the open may hang.
	 */
	DEBUG (8, "mdopen(): opening %s\n", acu);
	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.
	 * If hanging up, issue commands at high baud to enable auto answer
	 * at all speeds.
	 */
	signal(SIGINT, abort);
	errflag = ioctl(fd, TCGETA, &term);
	term.c_cflag &= ~(CBAUD | HUPCL);
	term.c_cflag |= (CLOCAL /* | CTSFLOW  | RTSFLOW */);
	term.c_cflag |= hflag ? (HUPCL | highbaud) : 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);
	}
	DEBUG(6,"set ioctl on %s, ", acu);
	DEBUG(6,"baudrate = 0%o\n", term.c_cflag & CBAUD);
	/*
	 *  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);
	return (fd);
}

mdclose ()
{
	DEBUG (8, "mdclose(): closing %s\n", acu);
	ioctl(fd, TCGETA, &term);
	term.c_cflag |= HUPCL;		/* make sure modem hangs up */
	ioctl(fd, TCSETA, &term);
	close (fd);
}

/*
 * Call ungetty to send a signal to the getty on a line.
 *
 * returns:
 * RC_FAIL - failure
 * SUCCESS - success
 */

ungetty (string)
	char *string;
{
#ifndef HDUU
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", acu, NULL);
		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 */
			DEBUG (1, "%s: ungetty failed:", string);
			DEBUG (1, " %x", UG_FAIL);
			exit (RC_FAIL | RCE_INUSE);
		case 255:
			exit (RC_FAIL);
	}
#else
	retcode = SUCCESS;	/* uugetty does not require ungetty */
#endif
}

/*
 * Restore the getty on the acu.
 *
 * returns:
 * RC_FAIL - failure
 * SUCCESS - success
 */

re_getty (string)
	char *string;
{
#ifndef HDUU
	/* call ungetty to see if we need to switch to dialin */
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty -t", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", "-t", acu, NULL);
		exit(-1);
	}
	while (((c = wait(&errflag)) != pid) && c != -1) ;

	if (((errflag>>8) & 0xff) != UG_RESTART)
	{
		DEBUG (7, "%s: no ungetty -r needed", string);
		return (SUCCESS);
	}

	DEBUG (7, "%s: ungetty -r needed\n", string);
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty -r", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", "-r", acu, NULL);
		exit (-1);
	}
	while (((c = wait(&errflag)) != pid) && c != -1) ;

	if (((errflag >> 8) & 0xff) == UG_FAIL)
	{
		return (RC_FAIL);
	}
	else
#endif
	{
		return (SUCCESS);
	}
}


#ifdef SLIP
/*
 * Wait on a child process
 */
fwait(pid)
register int	pid;
{
	register int	w;
	int	status;
	int	(*onhup) (), (*onint) ();

	onint = signal(SIGINT, SIG_IGN);
	onhup = signal(SIGHUP, SIG_IGN);
	/* should we add a SIG_IGN for SIGALRM? */
	while ((w = wait(&status)) != pid && w != -1)
		;
	if (w == -1)
		status = -1;
	(void) signal(SIGINT, onint);
	(void) signal(SIGHUP, onhup);
	return(status);

}


sliplock()
{
	char *s;
	int	otherpid,outerr;

	s=strrchr(acu, '/');
	sprintf(lockname,"/usr/spool/uucp/LCK..%s",++s);
	if((fp1 = fopen(lockname, "r")) != (FILE *)0) {
		if(fscanf(fp1,"%10d", &otherpid) == 1)
			outerr=(kill(otherpid,0) == 0 || errno == EPERM);
		(void) fclose(fp1);
		if (outerr)
			exit(RC_FAIL);
		else
			unlink(lockname);
	}
	if((fp1 = fopen(lockname, "w")) != NULL) {	/* create a lockfile */
		(void)chmod(lockname, 0444);
		(void)fprintf(fp1,"%10d\n", getpid());
		fclose(fp1);
	}

}


sliplog()
{
	int     pid, status, outerr, otherpid,pd;
	char	sliplock[64], temp[64], *s;
	char	sbaud[10], sspid[20], unit[20];
	FILE	*fp;

	signal(SIGINT,SIG_IGN);
	alarm(0);	/* off any pending alarm */
        sleep(4);
	sprintf(command,"Scrash\r");
	mdwrite(command);
	sleep(2);
	sprintf(command,"whatnot\r");
	mdwrite(command);
	printf("Login complete.\n");
	sleep(3);
	s=strrchr(acu, '/');
	pd=getpid();
	sprintf(command,"/etc/setslip %s %s > /tmp/ss%d",acu,"19200",pd);
	system(command);
	sleep(8);	/* was 2 */
	sprintf(command,"/tmp/ss%d",pd);
	if((fp=fopen(command,"r")) != (FILE *)0) {
		fscanf(fp,"%s", unit);
		(void) fclose(fp);
	}
	unlink(command);
	if (pid = fork()) 
		status = fwait(pid);
	else {	/* child */
		execl("/etc/ifconfig","ifconfig",unit,"inet",meslip,themslip,0);
		exit(1);
	}
	if (pid = fork()) 
		status = fwait(pid);
	else {	/* child */
		execl("/etc/ifconfig","ifconfig",unit,"inet","up",0);
		exit(1);
	}
	printf("Link activated.\n");
	sleep(10);
	if (pid = fork()) {
		printf("SLIP startup complete.  Use 'sldetach %s' to terminate.\n",unit);
		sleep(1);
	}
	else {	/* child */
		if((fp1 = fopen(lockname, "w")) != NULL) {	/* create a lockfile */
			(void)chmod(lockname, 0444);
			(void)fprintf(fp1,"%10d\n", getpid());
			fclose(fp1);
		}
		sprintf(sliplock,"/usr/spool/locks/slippid.%s",unit);
		if((fp1 = fopen(sliplock, "r")) != (FILE *)0) {
			if(fscanf(fp1,"%10d", &otherpid) == 1)
				outerr=(kill(otherpid,0) == 0 || errno == EPERM);
			(void) fclose(fp1);
			for(;outerr;) {		/* still alive... */
				sleep(5);
				outerr=(kill(otherpid,0) == 0 || errno == EPERM);
			}
		}
		if(fd != -1) {
			mdclose();
			sleep(1);
		}
		unlink(lockname);
		exit(1);
	}

}
#endif /* SLIP */


--- End of forwarded message from MAILER-DAEMON@trout.nosc.mil (Mail Delivery Subsystem)


-- 

 Jean-Pierre Radley   NYC Public Unix   jpr@jpradley.jpr.com   CIS: 72160,1341

Jean-pierre_Radley@f170.n771.z3.fidonet.org (Jean-pierre Radley) (04/03/91)

From: jpr@jpradley.jpr.com (Jean-Pierre Radley)
Lines: 1863
Organization: NYC Public Unix

In article <398@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>In article <1991Mar29.233228.17548@netcom.COM> gandrews@netcom.COM (Greg 
Andrews) writes:
>>In article <390@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:

>>Note that the dialTBIT distributed with SCO Xenix (and Unix) was written
>>for the TrailBlazer Plus modem and not the T2500.  It can't handle the
>>V.32 result codes that the modem will return, so it chokes on V.32 calls.
>>There are hacked versions of dialTBIT on the net (dunno where).
>
>If anyone knows of such a thing, I'd love to hear about it as it would
>be nice to have it understand V.32 connections, etc.

OK, I captured dialTBALL.c once.

---------------------------------------------
/*
 *  Function:	dialer program for the Telebit Trailblazer
 *
 *  Usage:	dial ttyname telnumber speed 
 *		dial -h ttyname speed
 *		dial -z ttyname speed
 *
 *  Returns:	0x80	bit = 1 if connection failed
 *		0x10	bit = 1 if line is also used for dialin #ifndef HDUU
 *		0x0f	if msb=1: error code
 *			if msb=0: connected baud rate (0=same as dialed baud)
 *
 *		Note: getty calls the dialer with -h whenever it starts up
 *		on a line enabled in /etc/ttys and listed in Devices with
 *		this dialer.
 *
 *		The user should call the dialer with -z to initialize
 *		the modem when it is first installed: the -z option writes
 *		default settings into the non-volatile memory of the modem.
 *
 *		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 such as phone busy, no
 *		answer, etc.  Attempts to connect to this remote system
 *		should be stopped.
 *
 *  Documents:	Telebit Trailblazer manual
 *		Telebit T2500 manual
 *		Telebit Trailblazer Plus PC manual (T18PC)
 *
 *  Note:	This source file can be used both for the old UUCP and
 *		for the new HoneyDanBer UUCP.  For the latter, HDUU may
 *		be defined to avoid calls to the HD ungetty program - which
 *		assumes that uugetty is used, and so simply returns SUCCESS.
 *		However, dialer binaries for the old UUCP are equally valid
 *		for the new HoneyDanBer UUCP (but make an unnecessary call
 *		to the null ungetty, supplied for backward compatibility).
 *
 *  Note:	Changes for Telebit T2500 and TrailblazerPlus PC modems made
 *		by Scott O'Connell & Bill Blue (ipars!scotto, crash!bblue)
 */
static char sccsid[] = "@(#)dialTBALL.c	 89/11/23 ";

#define SLIP 

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

/* 
 * define T2500 for the T2500, TPC for the T18PC, or V3 for the older
 * rev 3 ROMS on a standard Trailblazer, either here or in the makefile.
 * If all are undefined, default becomes standard newer Trailblazer.
 *
 * also, define WAITFORDT to always wait for dialtone before continuing.
 *
 * define SLOWRITE if a one second delay seems necessary prior to each
 * modem *string* write.  It was a default in the original dialer.
 */

#define T2500		/**/
* #define TPC		/**/
/* #define V3		/**/
#define WAITFORDT	/**/
/* define SLOWRITE	/**/

#ifndef B19200
#define B19200 EXTA
#endif

#ifndef B38400
#define B38400 EXTB
#endif

/* 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 */

/* error return 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_HANGUP	10	/* hangup failed */
#define RCE_NORESP	11	/* Modem didn't respond. */
#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		256
#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 - set up for DIDO - don't assume anything about modem state
 *	or defaults.
 *
 *  NOTE: 82 characters is the maximum for a Telebit command line.
 *
 * &F		- Reload factory defaults
 * E0		- Don't echo commands
 * F1		- Turn off echoplex (no local echo)
 * M0		- Speaker disabled at all times
 * Note: M0 does not apply to the PC card version.  It has no speaker!
 * Q4		- Don't be quiet, but don't tell us about RINGs
 * V1		- Verbose on; return english result codes
 * X3		- Use extended codes including MNP and PEP codes
 * S0=1		- Answer on first ring
 * S2=043	- Set escape sequence to be +++
 * S6=12	- Set # seconds to wait for dialtone (default is 2) used TPC only
 * S7=40	- Set connect timeout to default value
 * S10=4	- Set for T2500 only, loss of carrier to disconnect delay
 * S25=2	- Set for T2500 only, DTR down time for action
 * S45=0	- Disable remote modem access
 * S48=1	- All 8 bits are significant
 * S50=0	- Use automatic connect speed determination
 * S51=254	- Set serial port baud rate automatically, using 19200 for PEP.
 * S52=2	- Go on hook when dtr drops and reset to NV-RAM
 * S53=1	- DCD signal tracks remote carrier, DSR on when modem ready
 * S54=3	- Pass BREAK signal to remote modem
 * S55=0	- Respond sanely to command escape sequence
 * S58=2	- DTE uses CTS/RTS flow control.
 * S59=052	- Set prompt to "*" (?)
 * S60=0	- Use 8 data, 1 stop, no parity
 * S66=0	- Don't lock interface speed, just go with the flow.
 * S68=255	- DCE uses whatever flow control DTE uses
 * S92=0	- Issue PEP tones at the beginning of answer sequence
 * S95=2	- Set MNP Auto-Reliable mode
 * S110=255	- Use data compression when the remote modem requests it.
 * Note: S110 doesn't seem to work in Trailblazer Rev-3 ROMS
 * S111=255	- Accept any protocol
 * &W		- Write all of this into Non-Volatile RAM
 * Note: &W does not apply to the PC card version.  It has no NVRAM!
 *
 * Note that we have to break the setup string into two command lines.
 */


#ifdef T2500
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S10=4S25=2S45=0S48=1S50=0S51=254S52=
2S53=1S54=3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0S95=2S110=255S111=255&
W\r"
#endif
#ifdef TPC
#define	MDSETUP1 "AT&FE0F1Q4V1X3S6=12S2=043S45=0S48=1S50=0S51=254S52=2S53=
1S54=3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0s110=255S111=255\r"
#endif
#ifdef V3
/* this is currently specific to crash wrt s51, s66 and s95 */
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S45=0S48=1S50=0S51=254S52=2S53=1S54=
3\r"
#define MDSETUP2 "ATS55=0S58=2S60=0S66=0S68=255S92=0S95=2S111=255&W\r"
#endif
#if !defined(T2500) && !defined(TPC) && !defined(V3)
#define	MDSETUP1 "AT&FE0F1M0Q4V1X3S2=043S45=0S48=1S50=0S51=254S52=2\r"
#define MDSETUP2 "ATS53=1S54=3S55=0S58=2S60=0S66=0S68=255S92=1S110=255S111=
255&W\r"
#endif

/*
 * MDXONXOFF - Use XON/XOFF flow control
 *
 *  S58=3	DTE Uses XON/XOFF flow control (DCE will follow DTE)
 */
#define MDXONXOFF "ATS58=3\r"

/*
 *  MDDIALKERM - Dial an answering TBIT modem using kermit protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=10	- Use kermit (no parity) protocol.
 */
#define	MDDIALKERM "ATS7=60S50=255S111=10\r"

/*
 *  MDDIALUUCP - Dial an answering TBIT modem using uucp G protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=30	- Use uucp G protocol.
 */
#define	MDDIALUUCP "ATS7=60S50=255S111=30\r"

/*
 *  MDDIALXMDM - Dial an answering TBIT modem using [xy]modem protocol.
 *
 *  S7=60	- Give it a full minute to get a PEP recognition code
 *  S50=255	- Force PEP mode operation
 *  S111=20	- Use [xy]modem protocol.
 */
#define	MDDIALXMDM "ATS7=60S50=255S111=20\r"

/*
 *  MDCOMPRESS - Set compression mode on
 *
 *  S110=1	- Data compression is enabled provided the connect is PEP
 *		- and the remote end is allows compression.
 */
#define MDCOMPRESS "ATS110=1\r"

/*
 *	MDFORCEPEP	- Force a PEP mode connection
 *
 *	S7=60	- Give it a full minute to get a PEP recognition code
 *	S50=255	- Force PEP mode operation
 */
#define MDFORCEPEP	"ATS7=60S50=255\r"

/*
 *	MDFORCEV32	- Force a V32 mode connection
 *
 *	S50=6	- Force V.32 operation
 */
#define MDFORCEV32	"ATS50=6\r"	/* T2500 */

/*
 *	MDMNPMODE	- Set up MNP mode for slow connections
 *
 *	S95=2	- Enable Auto-reliable mode
 */
#define MDMNPMODE	"ATS95=2\r"

/*
 *	MDECHOSUP	- Enable Echo Supressor Compensation
 *
 *	S121=1	- Enable Echo Suppressor Compensation
 */
#define MDECHOSUP	"ATS121=1\r"

/*
 *  MDUNLOCK	- Unlock interface speed.
 */
#define MDUNLOCK "ATS66=0\r"

/*
 *  MDVALID - Allow only these characters to reach the modem.
 */
#define MDVALID		"0123456789CcEeFfKkMmNnPpRrTtUuVvWwXx*#,!/()-"
/* T2500 (added "Vv" to valid list) */

/*
 *  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		"ATZ\r" 

/*
 *  MDDIALOUT - Minor changes to set when dialing out.
 *
 *  S66=1	- Lock the interface speed.
 *  S95=0	- Disable MNP mode unless requested otherwise
 *  S110=0	- Disable data compression unless requested otherwise
 */

#ifdef T2500
#define	MDDIALOUT "ATS66=1S95=0S110=255\r"
#endif
#ifdef V3
#define	MDDIALOUT "ATS66=1S95=0\r"
#endif
#if !defined(T2500) && !defined(V3)
#define MDDIALOUT "ATS66=1S110=255\r"
#endif

/*
 *  MDATTN - Get modems attention
 */
#define	MDATTN		"AT\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.
 */
#define	OK		0	/* Command succesful */
#define	NOCARRIER	1	/* Connect timeout has occurred */
#define	ERROR		2	/* Command error encountered */
#define	NODIALTONE	3	/* No dial tone was detected */
#define	BUSY		4	/* Remote telephone is busy */
#define	NOANSWER	5	/* Remote site did not answer */
#define	RRING		6	/* Remote site is ringing */
#define CONNECT300REL	7	/* Connection established @ 300 using MNP */
#define CONNECT1200REL	8	/* Connection established @ 1200 using MNP */
#define CONNECT2400REL	9	/* Connection established @ 2400 using MNP */
#define	CONNECT300	10	/* Connection established @ 300 */
#define	CONNECT1200	11	/* Connection established @ 1200 */
#define CONNECT2400	12	/* Connection established @ 2400 */
#define CONNECTFASTKERM	13	/* Connection established @ 19200/Kermit */
#define CONNECTFASTXMDM	14	/* Connection established @ 19200/Xmodem */
#define CONNECTFASTUUCP	15	/* Connection established @ 19200/UUCP */
#define CONNECTFAST	16	/* Connection established using PEP */
/* T2500 (17-20) */
#define CONNECT4800	17	/* Connection established @ 4800 */
#define CONNECT4800REL	18	/* Connection established @ 4800 using MNP */
#define CONNECT9600	19	/* Connection established @ 9600 */
#define CONNECT9600REL	20	/* Connection established @ 9600 using MNP */
#ifdef SLIP
#define LOGIN		21	/* login prompt */
#define PASS		22	/* password prompt */
#endif

char *mdmsgs[] = {
/* 0 */		"OK",
/* 1 */		"NO CARRIER",
/* 2 */		"ERROR",

/* Note:	The original SCO dialer defined "NO DIALTONE".  In my testing
 *		I have learned that the Trailblazer Plus PC, the Trailblazer
 *		and the T2500 respond with "NO DIAL TONE".  This may need to
 *		be changed for your modem. -- Scott
 */

/* 3 */		"NO DIAL TONE",
/* 4 */		"BUSY",
/* 5 */		"NO ANSWER",
/* 6 */		"RRING",
/* 7 */		"CONNECT 300/REL",
/* 8 */		"CONNECT 1200/REL",
/* 9 */		"CONNECT 2400/REL",
/* 10 */	"CONNECT 300",
/* 11 */	"CONNECT 1200",
/* 12 */	"CONNECT 2400",
/* 13 */	"CONNECT FAST/KERM",
/* 14 */	"CONNECT FAST/XMDM",
/* 15 */	"CONNECT FAST/UUCP",
/* 16 */	"CONNECT FAST",
/* 17 */	"CONNECT 4800",		/* T2500 */
/* 18 */	"CONNECT 4800/REL",	/* T2500 */
/* 19 */	"CONNECT 9600",		/* T2500 */
/* 20 */	"CONNECT 9600/REL",	/* T2500 */
#ifdef SLIP
/* 21 */	"ogin:",
/* 22 */	"ord:",
#endif
		0
};

char *strchr();
int alrmint();
int abort();

struct termio term;			/* for storing tty parameters	*/
int Debug = DBG;			/* set when debug flag is given	*/
int dialing;				/* set while modem is dialing	*/
int fd = -1;				/* file descriptor for acu	*/
int errflag = 0;			/* set on errors		*/
int hflag = 0;				/* set to hangup modem		*/
int zflag = 0;				/* set to setup modem		*/
int highbaud, lowbaud;			/* baud rate limits		*/
int retcode = RC_FAIL;			/* return code			*/
int compress = 0;			/* set if compression requested */
int mnpmode = 0;			/* set if MNP mode requested    */
int forcepep = 0;			/* set if PEP mode requested    */
int forcev32 = 0;			/* set if V32 mode requested (T2500) */
int echosup = 0;			/* echo supressor compensation  */
int xonxoff = 0;			/* XON/XOFF flow control mode   */
int speedlock = 1;			/* set when baud rate is locked */
int kermcall = 0;			/* set if kermit call		*/
int uucall = 0;				/* set if uucico call		*/
int xmdmcall = 0;			/* set if [xy]modem call	*/
int timeout;				/* how long to wait for alarm	*/
int dial_retry = DIAL_RETRY;		/* dial retry count		*/
int pid;				/* stores child's pid		*/
int c;					/* temporary storage		*/
char command[MAXLINE];			/* modem command buffer		*/
char *p;				/* temporary storage		*/
char *acu;				/* device to dial through	*/
char *phone;				/* phone number to dial		*/
extern int optind;			/* for getopt ()		*/
extern char *optarg;			/* for getopt ()		*/

#ifdef SLIP
int slipline = 0;			/* set if SLIP connection	*/
char	lockname[64], *meslip, *themslip;
FILE	*fp1;
#endif /* SLIP */

#define	toprint(x)	((x)<' '?((x)+'@'):'?')

/* vgets - Format one character in "always printable" format (like cat -v)
 */

char *
vgets(c, f)
unsigned char c;
FILE *f;
{
	static char buffer[10];
	char *pnt;

	pnt = buffer;
	if (iscntrl(c) || !isprint(c)) {
		if (!isascii(c)) {			/* Top bit is set */
			*pnt++ = 'M';
			*pnt++ = '-';
			c = toascii(c);			/* Strip it */
		}
		if (iscntrl(c)) {			/* Not printable */
			*pnt++ = '^';
			c = toprint(c);			/* Make it printable */
		}
	}
	*pnt++ = c;
	*pnt = '\0';
	return(buffer);
}


/*
 * translate the pairs of characters present in the first
 * string whenever the first of the pair appears in the second
 * string.
 */
static void
translate(ttab, str)
register char *ttab, *str;
{
	register char *s;

	for(;*ttab && *(ttab+1); ttab += 2)
		for(s=str;*s;s++)
			if(*ttab == *s)
				*s = *(ttab+1);
}


main (argc,argv)
	int argc;
	char *argv[];
{
	/*
	 *  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, abort);

	/*
	 * Parse command line options.
	 */
	while ((c = getopt(argc, argv, "hzsx:")) != EOF)
	{
		switch(c)
		{
			case 'h':
				hflag++;
				break;
			case 'z':
				zflag++;
				break;
			case 'x':
				Debug = atoi(optarg);
				break;
#ifdef SLIP
			case 's':
				slipline++;
				break;
#endif /* SLIP */
			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 || zflag)
	{
		if (argc - optind != 2)  errflag++ ;
	}
#ifdef SLIP
	else if (slipline)
	{
		if (argc - optind != 5)  errflag++;
	}
#endif
	else
	{
		if (argc - optind != 3)  errflag++ ;
	}

	if (errflag)
	{
		if (hflag)
		{
			fprintf (stderr,
				"Usage:\t%s -h devicename speed\n", argv[0]);
		}
		else if (zflag)
		{
			fprintf (stderr,
				"Usage:\t%s -z devicename speed\n", argv[0]);
		}
		else
#ifdef SLIP
		if (slipline)
		{
			fprintf(stderr,
				"Usage:\t%s -s devicename number speed ipme ipthem\n", argv[0]);
		}
		else
#endif
		{
			fprintf (stderr,
				"Usage:\t%s devicename number speed\n",
				argv[0]);
		}
		exit(RC_FAIL | RCE_ARGS);
	}

	acu = argv[optind++];

	if (!(hflag || zflag))
	{
		phone = strdup(argv[optind++]);
		translate("=,-,", phone);
		if (strlen(phone) != strspn(phone, MDVALID))
		{
			fprintf(stderr, "dial: Bad phone number %s\n", phone);
			exit(RC_FAIL | RCE_PHNO);
		}
		if (strpbrk(phone, "CcEeFfKkMmNnPpTtUuVvXx"))
/* T2500 added "Vv" */
		{
		    char *phoneno, *ptr;
		    if (strpbrk(phone, "Cc"))
		    {
			compress++;
			DEBUG(4, "COMPRESS MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Ee"))
		    {
			echosup++;
			DEBUG(4, "ECHO SUPRESSOR COMPENSATION REQUESTED%s",
				"\n");
		    }
		    if (strpbrk(phone, "Ff"))
		    {
			xonxoff++;
			DEBUG(4, "XON/XOFF MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Mm"))
		    {
			mnpmode++;
			DEBUG(4, "MNP MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Pp"))
		    {
			forcepep++;
			DEBUG(4, "PEP MODE REQUESTED%s", "\n");
		    }
		    if (strpbrk(phone, "Vv"))
		    {
		    	forcev32++;
			DEBUG(4, "V32 MODE REQUESTED%s", "\n"); /* T2500 */
		    }
		    if (strpbrk(phone, "Uu"))
		    {
			if (strpbrk(phone, "KkXx"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "UUCP phone number, stripping %s\n", phone);
			uucall++;
		    }
		    else if (strpbrk(phone, "Kk"))
		    {
			if (strpbrk(phone, "UuXx"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "KERMIT phone number, stripping %s\n", phone);
			kermcall++;
		    }
		    else if (strpbrk(phone, "Xx"))
		    {
			if (strpbrk(phone, "KkUu"))
			{
				fprintf (stderr,
					"dial: cannot specify two protocols\n");
			 	exit(RC_FAIL | RCE_PHNO);
			}
			DEBUG(4, "[XY]MODEM phone number, stripping %s\n",
				phone);
			xmdmcall++;
		    }
		    phoneno = strdup(phone);
		    *phone = '\0';
		    while ((ptr = strpbrk (phoneno,
		    	"CcEeFfKkMmNnPpTtUuVvXxMm")) != NULL)
 /* T2500 added Vv */
		    {
			*ptr = '\0';
			strcat(phone, phoneno);
			phoneno = ++ptr;
		    }
		    strcat(phone, phoneno);
		    DEBUG(5,"PROTOCOL phone number, got %s\n", phone);
		}
	}

	lowbaud = highbaud = checkbaud (atoi (argv[optind]));
	DEBUG (6, "checkbaud claims low/high baud is 0%o\n", lowbaud);

	/* test for a range of baudrates */

	if ((p = strchr (argv[optind], '-')) != NULL)
	{
		*p++ = '\0';
		highbaud = checkbaud (atoi(p));
		DEBUG (6, "checkbaud claims high baud is 0%o\n", highbaud);
	}

	if (!hflag)
	{
		ungetty ("dialer");
	}

#ifdef SLIP
	if (slipline) {
		meslip = strdup(argv[++optind]);
		themslip = strdup(argv[++optind]);
		DEBUG(4,"SLIP meslip: %s\n", meslip);
		DEBUG(4,"SLIP themslip: %s\n", themslip);
		sliplock();
	}
#endif /* SLIP */

	/*
	 * Open the modem file.
	 */
	mdopen ();

	/*
	 *  Timeout after 10 seconds if no response
	 */
	timeout = 10;
	signal(SIGALRM, alrmint);

	/*
	 * Hangup and exit if requested
	 */
	if (hflag)
	{
		DEBUG(1, "Hangup sequence begun%c", '\n');

		if (hangup (timeout) == -1)
		{
			cleanup (RC_FAIL | RCE_HANGUP);
		}
		cleanup (re_getty ("hangup"));
	}

	/*
	 * Since this is the first connect, the modem needs to
	 * figure out our baud rate.
	 */
	if (mdsync () == RC_FAIL)
	{
		cleanup (RC_FAIL | retcode);
	}

	/*
	 *  Initialize the modem
	 */
	if (zflag)
	{
	    DEBUG(6, "Initializing modem at %s\n", acu);

	    if (mdwrite(MDSETUP1) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    /*
	     * Since MDSETUP1 sets the "autobaud" mode, it forgot our
	     * baud rate...
	     */
		if (mdsync () == RC_FAIL)
		{
			cleanup (RC_FAIL | retcode);
		}

	    if (mdwrite (MDSETUP2) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    cleanup (re_getty ("modem init"));
	}

	/*
	 *  Reset and put modem into command mode
	 */
	reset:

	DEBUG(3, "Resetting modem%c", '\n');

	if (mdwrite(MDRESET) == -1)
	{
		cleanup(RC_FAIL | retcode);
	}

	if (mdread(timeout) != OK)
	{
		if (hangup(timeout) == -1)
		{
			cleanup(RC_FAIL | retcode | RCE_HANGUP);
		}
		goto reset;
	}

	/*
	 *  Must wait at least 0.5 seconds after reset
	 *  for Telebit to recover and receive commands.
	 *	Then, since MDRESET made it forget our baud rate,
	 *	we need to mdsync() again.
	 */
	nap(500L);

	if (mdsync () == RC_FAIL)
	{
		cleanup (RC_FAIL | retcode);
	}

#ifdef TPC
	/*  Initialize the modem since ATZ loses setup... (great modem)
         */
	    DEBUG(6, "Initializing modem (PC) at %s\n", acu);

	    if (mdwrite(MDSETUP1) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    /*
	     * Since MDSETUP1 sets the "autobaud" mode, it forgot our
	     * baud rate...
	     */
		if (mdsync () == RC_FAIL)
		{
			cleanup (RC_FAIL | retcode);
		}

	    if (mdwrite (MDSETUP2) == -1)
		{
			cleanup (RC_FAIL | retcode);
		}
	    if (mdread (timeout) != OK)
		{
			cleanup (RC_FAIL | retcode);
		}

	    cleanup (re_getty ("modem init"));
#endif /* TPC */

	/*
	 * Set up modem for generic dial out settings.
	 */
	DEBUG(3, "Setting DIAL OUT mode%c", '\n');

	if (mdwrite(MDDIALOUT) == -1)
	{
		cleanup(RC_FAIL | retcode);
	}
	if (mdread(timeout) != OK)
	{
		cleanup(RC_FAIL | retcode);
	}

#ifdef LATER
	/*
	 *  If we were given a specific baudrate to use, and that
	 *  baudrate less than or equal to 9600, unlock the modem speed.
	 */
#ifdef T2500
	if ((lowbaud == highbaud) && (highbaud <= B9600))
#else
	if ((lowbaud == highbaud) && (highbaud <= B2400))
#endif
	{
		char speedstr[9], speed[5];
		DEBUG(3, "Unlocking modem speed%c", '\n');

		if (mdwrite(MDUNLOCK) == -1)
		{
			cleanup(RC_FAIL | retcode);
		}
		if (mdread(timeout) != OK)
		{
			cleanup(RC_FAIL | retcode);
		}
		strcpy(speedstr, "ATS50=0\r");

		switch (lowbaud)
		{
		    case B300:
			strcpy(speedstr, "ATS50=1\r");
			strcpy(speed,"300");
			break;
		    case B1200:
			strcpy(speedstr, "ATS50=2\r");
			strcpy(speed,"1200");
			break;
		    case B2400:
			strcpy(speedstr, "ATS50=3\r");
			strcpy(speed,"2400");
			break;
#ifdef T2500
		    case B9600:
		        strcpy(speedstr, "ATS50=6\r");
			strcpy(speed,"9600");
			break;
#endif
		}
		DEBUG(3, "Setting modem connect speed to %s baud\n", speed);

		if (mdwrite(speedstr) == -1)
		{
			cleanup(RC_FAIL | retcode);
		}
		if (mdread(timeout) != OK)
		{
			cleanup(RC_FAIL | retcode);
		}
		speedlock = 0;
	}
#endif /* LATER */

	/*
	 * If kermcall is non-zero, we need to set up the modem for kermit
	 * and tell it not to connect to anything else.
	 */
	if (kermcall)
	{
		DEBUG(3, "Setting KERMIT mode%c", '\n');
		if (mdwrite(MDDIALKERM) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If uucall is non-zero, we need to set the modem up for uucp
	 * G protocol, and tell it not to connect to anything else.
	 */
	else if (uucall)
	{
		DEBUG(3, "Setting UUCP mode%c", '\n');
		if (mdwrite(MDDIALUUCP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If xmdmcall is non-zero, we need to set up the modem for [xy]modem
	 * and tell it not to connect to anything else.
	 */
	else if (xmdmcall)
	{
		DEBUG(3, "Setting XMODEM mode%c", '\n');
		if (mdwrite(MDDIALXMDM) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If compress is non-zero, we need to set up the modem for
	 * in-line data compression.
	 */
	if (compress)
	{
		DEBUG(3, "Setting COMPRESS mode%c", '\n');
		if (mdwrite(MDCOMPRESS) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If mnpmode is non-zero, we enable the modem
	 * to use MNP mode.
	 */
	if (mnpmode)
	{
		DEBUG(3, "Setting MNP mode%c", '\n');
		if (mdwrite(MDMNPMODE) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If forcepep is non-zero, we need to force the modem
	 * to use PEP mode.
	 */
	if (forcepep)
	{
		DEBUG(3, "Setting PEP mode%c", '\n');
		if (mdwrite(MDFORCEPEP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}
	/*
	 * If forcev32 is non-zero, we need to force the modem (T2500)
	 * to use V32 mode.
	 */
	if (forcev32)
	{
		DEBUG(3, "Setting V32 mode%c", '\n');
		if (mdwrite(MDFORCEV32) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If echosup is non-zero, we enable the modem's
	 * echo supressor compensation logic.
	 */
	if (echosup)
	{
		DEBUG(3, "Setting ECHO SUPRESSOR COMPENSATION mode%c", '\n');
		if (mdwrite(MDECHOSUP) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 * If xonxoff is non-zero, we enable the modem's
	 * echo supressor compensation logic.
	 */
	if (xonxoff)
	{
		DEBUG(3, "Setting XON/XOFF mode%c", '\n');
		if (mdwrite(MDXONXOFF) == -1)
			cleanup(RC_FAIL | retcode);
		if (mdread(timeout) != OK)
			cleanup(RC_FAIL | retcode);
	}

	/*
	 *  Build up the phone number
	 */
#ifdef WAITFORDT
	sprintf(command, "ATDTW%s\r", phone);
#else
	sprintf(command, "ATDT%s\r", phone);
#endif
	/*
	 *  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;
	if (uucall) timeout *= 3;
	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 80 characters including "AT" */
	if (strlen(command) > 80)
		cleanup(RC_FAIL | RCE_PHNO | retcode);

redial:
	DEBUG(3, "DIALING %s\n", command);
	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 CONNECT300:
			/* c = matchbaud(B300, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECT1200:
			/* c = matchbaud(B1200, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECT2400:
			/* c = matchbaud(B2400, lowbaud, highbaud); */
			/* cleanup(retcode | c); */
		case CONNECTFAST:
		case CONNECTFASTKERM:
		case CONNECTFASTXMDM:
		case CONNECTFASTUUCP:
		case CONNECT300REL:  	/*  not included in original	*/
		case CONNECT1200REL: 	/*  binary  file		*/
		case CONNECT2400REL: 	/*  -----------			*/
		case CONNECT4800:	/* T2500 */
		case CONNECT4800REL:	/* T2500 */
		case CONNECT9600:	/* T2500 */
		case CONNECT9600REL:	/* T2500 */

#ifdef SLIP
		 	if (slipline)
				sliplog();
#endif /* SLIP */

			cleanup(retcode); 
		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 (sig)
	int sig;
{
	signal (sig, nil);
}

hangup (htime)
	int htime;
{
	int retry = 4, rcode = -1;
	int old_retcode = retcode;
	int (*s)();

	DEBUG(6, "hangup - timeout %d\n", htime);
#ifdef SLOWRITE
	sleep(1);
#endif

	s = signal(SIGALRM, nil);	/* alarms are non-fatal here */

	retcode = (RC_FAIL | RCE_HANGUP); /* In case we are interrupted */

	while (retry--  &&  rcode == -1)
	{
		/*
		 * Send an escape to the modem to take it off-line.
		 */
		if (mdwrite (MDESCAPE) == -1)
		{
			retcode = old_retcode;
			return (rcode);
		}

		/* Give it a minute to think about it */
		sleep (1);

		/*
		 * MDESCAPE will return OK only if online,
		 * so ignore error return
		 */
		mdflush ();		/* waste "OK" if we were on line */

		/*
		 * First sync the baud rate.
		 * Don't bother sending the hangup stuff
		 * if we couldn't even sync baud rates.
		 */
		if (mdsync () != RC_FAIL)
		{
			if (mdwrite (MDHANGUP) == -1)
			{
				retcode = old_retcode;
				return (rcode);
			}

			switch(mdread (htime))
			{
				case OK:
				case NOCARRIER:		/* T2500 */
					rcode = 0;
			}

		}

		if (retry && rcode != 0)
		{
			/*
			 * Try closing the line and re-opening it.  This
			 * should cause a reset due to the DTR transition.
			 * Give the modem a couple of seconds to reset.
			 */
			DEBUG (3, "FAILED, Re-trying hangup%c", '\n');
			mdclose ();
			sleep (2);
			mdopen ();
		}
	}

	if (rcode == -1)
	{
		long now;

		(void) time (&now);
		fprintf (stderr, "dialer: HANGUP FAILED at %s", ctime (&now));
	}
	else
	{
		DEBUG(3, "Disabling escape%c", '\n');
		mdwrite (MDDSBLESC);		/* disable escape */
	}

	signal (SIGALRM, s);
	retcode = old_retcode;
	return (rcode);
}

/*
 *  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 **mp;
	register char *bp;
	char buf[MAXLINE];

	bp = buf;
	alarm(rtime);
	DEBUG(6, "MODEM returned %s", "<<");
	while (read(fd, &c, 1) == 1) {
		c &= 0177;
		if ((*bp = c) != '\0')
			*++bp = '\0';
		DEBUG(6, "%s", vgets(c));
		if (bp >= buf + MAXLINE) {
			alarm(0);
			DEBUG(4,">>-%s\n","FAIL");
			return(-1);
		}
		if (c == '\r') {
			if (substr("RRING", buf) == 0) {
				bp = buf;
				DEBUG(6,">>-%s\n", "OK");
				DEBUG(4,"got %s\n","RRING");
				DEBUG(6, "MODEM returned %s", "<<");
				continue;
			}
			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 response\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, "%s", vgets(*c));
		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);
	}
}

/*
 * Exit, making sure the modem hangs up and we
 * don't leave the tty ungetty'ed.
 */
abort (sig)
int sig;
{
	int error = retcode & ~(RC_FAIL | RC_ENABLED);

	signal(SIGINT, SIG_IGN);
	signal(sig, SIG_IGN);

	if (error != RCE_HANGUP)
	{
		if (hangup (timeout) == -1)
		{
			retcode |= (RC_FAIL);
		}
		else
		{
			/*
		 	* No need to call dial -h again.
		 	*/
			retcode &= ~RC_ENABLED;
		}
	}

	if (re_getty ("abort") == RC_FAIL)
	{
		retcode |= RC_FAIL;
	}

	if (fd != -1)
	{
		ioctl(fd, TCGETA, &term);
		term.c_cflag |= HUPCL;		/* make sure modem hangs up */
		ioctl(fd, TCSETA, &term);
		mdclose ();
	}

	if (sig)  retcode |= (RC_FAIL | RCE_SIG);
	exit (retcode);
}

/*
 *  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;
		case 2400:
			baudrate = B2400;
			break;
		case 4800:
			baudrate = B4800;
			break;
		case 9600:
			baudrate = B9600;
			break;
		case 19200:
			baudrate = B19200;
			break;
		case 38400:
			baudrate = B38400;
			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
 *		Bxxxxx		if low baud <= connected baud <= high baud
 *		RCE_SPEED	if connected baud rate is out of range
 */

matchbaud(cbaud, low, high)
int cbaud, low, high;
{
	/* uucp/cu assume highest baud */
	if ((cbaud == high) || (high > B9600)) return(0);	/* T2500 */
	if (low <= cbaud  &&  cbaud < high)  return(cbaud);
	return(RC_FAIL | RCE_SPEED);
}

/*
 * In order to figure out our baud rate, the modem needs
 * an "a" character.  We send it twice for good measure,
 * and pause 1/4 second after each one.
 */
mdsync()
{
	int (*old_alrm)();
	char buf[MAXLINE];
	int count = 0, n;

/* Note:	While the earlier Telebit modems needed this syncing
 *		routine, the T2500 with Rev-1 ROMS would miss the 
 *		next command sent after the mdsync().  This was because
 *		of a lower case 'a' being sent prior to an upper case
 *		'AT'.  I have been told this is fixed in Rev-2 ROMS,
 *		but since I haven't seen my T2500 miss an 'AT' yet,
 *		I bypass the syncing routine.  -- Scott
 */
#ifdef T2500
	return(0);	/* T2500 */
#endif /* T2500 */

	old_alrm = signal(SIGALRM, nil);	/* alarms are non-fatal here */

	DEBUG (7, "Syncing baud rate...", "");

	while (++count < 6)
	{
		/*
		 * Send 'a'<pause>'a'<pause>... to make the modem sync to our
		 * baud rate.
		 */
		 sendsync ();

		/*
		 * Send ATQ4 to make sure the modem has response codes
		 * enabled.  If the modem is talking our speed, this will
		 * always result in "OK".  First we eat output from
		 * the modem.
		 */
		mdflush ();
		mdwrite ("ATQ4\r");

		/*
		 * If we don't get "OK" in 2 seconds, we ain't gonna.
		 */
		if (mdread(2) == OK ) {
		   break;
		}
	}

	/*
	 * At debug level 9, we print an 'a' every time we send one.
	 * These dots make things look prettier.
	 */
	DEBUG (9, "%s", "...");

	signal (SIGALRM, old_alrm);

	if (count < 10)
	{
		DEBUG (7, "%s\n", "done.");
		return (0);
	}
	else
	{
		DEBUG (7, "%s\n", "FAIL");
		return (RC_FAIL);
	}
}

#define NSYNCS	4		/* Number of a's to send each time */

/*
 * Sendsync: Send a's to make the modem sync to our baud rate.
 */
sendsync ()
{
	int count = 0;
	
	while (count++ < NSYNCS)
	{
		write (fd, "a", 1);
		DEBUG (9, "%c", 'a');
		nap (250L); /* wait between each one */
	}
}

/*
 * Open the modem and set the baud rate.  Sets the global variable
 * "fd".
 */
int
mdopen ()
{
	/*
	 *  Must open with O_NDELAY set or the open may hang.
	 */
	DEBUG (8, "mdopen(): opening %s\n", acu);
	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.
	 * If hanging up, issue commands at high baud to enable auto answer
	 * at all speeds.
	 */
	signal(SIGINT, abort);
	errflag = ioctl(fd, TCGETA, &term);
	term.c_cflag &= ~(CBAUD | HUPCL);
	term.c_cflag |= (CLOCAL /* | CTSFLOW  | RTSFLOW */);
	term.c_cflag |= hflag ? (HUPCL | highbaud) : 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);
	}
	DEBUG(6,"set ioctl on %s, ", acu);
	DEBUG(6,"baudrate = 0%o\n", term.c_cflag & CBAUD);
	/*
	 *  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);
	return (fd);
}

mdclose ()
{
	DEBUG (8, "mdclose(): closing %s\n", acu);
	ioctl(fd, TCGETA, &term);
	term.c_cflag |= HUPCL;		/* make sure modem hangs up */
	ioctl(fd, TCSETA, &term);
	close (fd);
}

/*
 * Call ungetty to send a signal to the getty on a line.
 *
 * returns:
 * RC_FAIL - failure
 * SUCCESS - success
 */

ungetty (string)
	char *string;
{
#ifndef HDUU
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", acu, NULL);
		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 */
			DEBUG (1, "%s: ungetty failed:", string);
			DEBUG (1, " %x", UG_FAIL);
			exit (RC_FAIL | RCE_INUSE);
		case 255:
			exit (RC_FAIL);
	}
#else
	retcode = SUCCESS;	/* uugetty does not require ungetty */
#endif
}

/*
 * Restore the getty on the acu.
 *
 * returns:
 * RC_FAIL - failure
 * SUCCESS - success
 */

re_getty (string)
	char *string;
{
#ifndef HDUU
	/* call ungetty to see if we need to switch to dialin */
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty -t", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", "-t", acu, NULL);
		exit(-1);
	}
	while (((c = wait(&errflag)) != pid) && c != -1) ;

	if (((errflag>>8) & 0xff) != UG_RESTART)
	{
		DEBUG (7, "%s: no ungetty -r needed", string);
		return (SUCCESS);
	}

	DEBUG (7, "%s: ungetty -r needed\n", string);
	if ((pid = fork()) == 0)
	{
		DEBUG (7, "%s: ungetty -r", string);
		DEBUG (7, " %s called\n", acu);
		execl (UNGETTY, "ungetty", "-r", acu, NULL);
		exit (-1);
	}
	while (((c = wait(&errflag)) != pid) && c != -1) ;

	if (((errflag >> 8) & 0xff) == UG_FAIL)
	{
		return (RC_FAIL);
	}
	else
#endif
	{
		return (SUCCESS);
	}
}


#ifdef SLIP
/*
 * Wait on a child process
 */
fwait(pid)
register int	pid;
{
	register int	w;
	int	status;
	int	(*onhup) (), (*onint) ();

	onint = signal(SIGINT, SIG_IGN);
	onhup = signal(SIGHUP, SIG_IGN);
	/* should we add a SIG_IGN for SIGALRM? */
	while ((w = wait(&status)) != pid && w != -1)
		;
	if (w == -1)
		status = -1;
	(void) signal(SIGINT, onint);
	(void) signal(SIGHUP, onhup);
	return(status);

}


sliplock()
{
	char *s;
	int	otherpid,outerr;

	s=strrchr(acu, '/');
	sprintf(lockname,"/usr/spool/uucp/LCK..%s",++s);
	if((fp1 = fopen(lockname, "r")) != (FILE *)0) {
		if(fscanf(fp1,"%10d", &otherpid) == 1)
			outerr=(kill(otherpid,0) == 0 || errno == EPERM);
		(void) fclose(fp1);
		if (outerr)
			exit(RC_FAIL);
		else
			unlink(lockname);
	}
	if((fp1 = fopen(lockname, "w")) != NULL) {	/* create a lockfile */
		(void)chmod(lockname, 0444);
		(void)fprintf(fp1,"%10d\n", getpid());
		fclose(fp1);
	}

}


sliplog()
{
	int     pid, status, outerr, otherpid,pd;
	char	sliplock[64], temp[64], *s;
	char	sbaud[10], sspid[20], unit[20];
	FILE	*fp;

	signal(SIGINT,SIG_IGN);
	alarm(0);	/* off any pending alarm */
        sleep(4);
	sprintf(command,"Scrash\r");
	mdwrite(command);
	sleep(2);
	sprintf(command,"whatnot\r");
	mdwrite(command);
	printf("Login complete.\n");
	sleep(3);
	s=strrchr(acu, '/');
	pd=getpid();
	sprintf(command,"/etc/setslip %s %s > /tmp/ss%d",acu,"19200",pd);
	system(command);
	sleep(8);	/* was 2 */
	sprintf(command,"/tmp/ss%d",pd);
	if((fp=fopen(command,"r")) != (FILE *)0) {
		fscanf(fp,"%s", unit);
		(void) fclose(fp);
	}
	unlink(command);
	if (pid = fork()) 
		status = fwait(pid);
	else {	/* child */
		execl("/etc/ifconfig","ifconfig",unit,"inet",meslip,themslip,0);
		exit(1);
	}
	if (pid = fork()) 
		status = fwait(pid);
	else {	/* child */
		execl("/etc/ifconfig","ifconfig",unit,"inet","up",0);
		exit(1);
	}
	printf("Link activated.\n");
	sleep(10);
	if (pid = fork()) {
		printf("SLIP startup complete.  Use 'sldetach %s' to terminate.\n",unit);
		sleep(1);
	}
	else {	/* child */
		if((fp1 = fopen(lockname, "w")) != NULL) {	/* create a lockfile */
			(void)chmod(lockname, 0444);
			(void)fprintf(fp1,"%10d\n", getpid());
			fclose(fp1);
		}
		sprintf(sliplock,"/usr/spool/locks/slippid.%s",unit);
		if((fp1 = fopen(sliplock, "r")) != (FILE *)0) {
			if(fscanf(fp1,"%10d", &otherpid) == 1)
				outerr=(kill(otherpid,0) == 0 || errno == EPERM);
			(void) fclose(fp1);
			for(;outerr;) {		/* still alive... */
				sleep(5);
				outerr=(kill(otherpid,0) == 0 || errno == EPERM);
			}
		}
		if(fd != -1) {
			mdclose();
			sleep(1);
		}
		unlink(lockname);
		exit(1);
	}

}
#endif /* SLIP */


--- End of forwarded message from MAILER-DAEMON@trout.nosc.mil (Mail 
Delivery Subsystem)


-- 

 Jean-Pierre Radley   NYC Public Unix   jpr@jpradley.jpr.com   CIS: 72160,
1341
--- rfmail 0.3.9
 * Origin: Bonafido  Usenet <====> Fido Gateway.       (3:771/170.0)
SEEN-BY: 771/170 180 220 400 772/20 
FSC-Control: PATH: 771/170 

gandrews@netcom.COM (Greg Andrews) (04/03/91)

In article <398@alchemy.UUCP> bbs@alchemy.UUCP (BBS Administration) writes:
>In article <1991Mar29.233228.17548@netcom.COM> gandrews@netcom.COM (Greg Andrews) writes:
>
>>The Fast Start Guide simply can't compete with a real, live SCO Xenix
>>setup guide available from Telebit Tech Support.
>
>So, just dial 1-800-TELEBIT and ask for one? I guess maybe I should send
>in my registration card first (do they check?)
>

Nope, you don't have to be registered to receive support from Telebit.

>
>>Note that the dialTBIT distributed with SCO Xenix (and Unix) was written
>>for the TrailBlazer Plus modem and not the T2500.  It can't handle the
>>V.32 result codes that the modem will return, so it chokes on V.32 calls.
>>There are hacked versions of dialTBIT on the net (dunno where).
>
>If anyone knows of such a thing, I'd love to hear about it as it would
>be nice to have it understand V.32 connections, etc.
>

I've seen at least one person mention that they have an altered version
of dialTBIT available for you.  They posted a message since my last one,
so you may already have seen it.  (note that they may not want to mail
umpteen copies to everyone in the world!  Netlanders should find the
message and ask nicely...)

>
>>The S58=3 setting will hose your XMODEM, YMODEM, and uucp file transfers
>>unless they are spoofed by the modem (available only in PEP and V.32/MNP
>>connections).  S58=0 might be a better setting, or S58=2 S68=255 if your 
>>system can support RTS/CTS flow control.
>
>Here's the deal:
>
>You are correct. That was the problem. Once I changed S58 to 0, the other
>site connecting at 2400 bps (thus >not< spoofing the UUCP "g" protocol)
>was able to transfer files. Thanks!
>
>Still, there are problems. 
>[description of problems deleted]
>

Most of the trouble you're seeing is related to flow control.  You're
right, running without flow control can make trouble for you.  Uucp
doesn't need flow control so much as interactive sessions would.

If you change the modem to use RTS/CTS flow control, then you need to
also change the computer to use it.  DialTBIT opens the port with RTS/CTS
line disciplines enabled, and I believe cu will retain them.  As someone
else mentioned a couple of weeks ago (and I confirmed on my system), SCO's
uucico will turn all flow control off in the computer.  Even RTS/CTS.

To enable RTS/CTS flow control for logins, you would need to insert the
CTSFLOW keyword into your /etc/gettydefs entries.  My attempts to put in
RTSFLOW were successful for 9600 and slower speeds, but not for the 19200
(EXTA) entry.  I had to leave the RTSFLOW parameter out of the 19200 and
38400 entries (the 38400 entry was for T1600 testing, not for the T2500).
My results were obtained on SCO Unix where the kernel reports a version
of 3.2.0 at boot-up time.  Other versions of SCO Unix, Open Desktop, or
SCO Xenix may behave differently.

Any further efforts to use RTS/CTS flow control on a stock 'COM1' or 'COM2'
port would need a different tty driver from SCO, or replacing the SCO driver
with something like the FAS driver.

>
>Once again, THANK YOU for answering this article! I was at the end of my
>rope and am really happy to have access to USENET. Now, my rope has been
>lengthened, but I'm at your mercy once again...
>

Don't give up until you've at least called tech support!  At the very least,
it would have saved you several days of frustration...


-- 
.------------------------------------------------------------------------.
|  Greg Andrews   |       UUCP: {apple,amdahl,claris}!netcom!gandrews    |
|                 |   Internet: gandrews@netcom.COM                      |
`------------------------------------------------------------------------'