xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 25518)
113642Ssam #ifndef lint
2*25518Stef static char sccsid[] = "@(#)conn.c	5.8 (Berkeley) 11/22/85";
313642Ssam #endif
413642Ssam 
523596Sbloom #include <signal.h>
613642Ssam #include "uucp.h"
713642Ssam #include <setjmp.h>
813642Ssam #include <ctype.h>
913642Ssam #include <errno.h>
1017834Sralph #ifdef	USG
1113642Ssam #include <termio.h>
1213642Ssam #include <fcntl.h>
1313642Ssam #endif
1417834Sralph #ifndef	USG
1513642Ssam #include <sgtty.h>
1613642Ssam #endif
1717834Sralph #ifdef BSD4_2
1817834Sralph #include <sys/time.h>
1917834Sralph #else
2017834Sralph #include <time.h>
2117834Sralph #endif
2213642Ssam 
2313642Ssam #define MAXC 1000
2413642Ssam 
2513642Ssam extern jmp_buf Sjbuf;
2617834Sralph jmp_buf Cjbuf;
2718619Sralph extern int errno, onesys;
2817834Sralph extern char *sys_errlist[];
2918619Sralph extern char MaxGrade, DefMaxGrade;
3013642Ssam 
3113642Ssam /* Parity control during login procedure */
3213642Ssam #define	P_ZERO	0
3313642Ssam #define	P_ONE	1
3413642Ssam #define	P_EVEN	2
3513642Ssam #define	P_ODD	3
3617834Sralph 
3717834Sralph #define ABORT -2
3817834Sralph 
3917834Sralph char 	*AbortOn = NULL;
4013642Ssam char	par_tab[128];	/* must be power of two */
4117834Sralph int	linebaudrate;	/* used for the sleep test in pk1.c */
4213642Ssam int next_fd = -1;	/* predicted fd to close interrupted opens */
4313642Ssam 				/* rti!trt, courtesy unc!smb */
4425127Sbloom /*
4525127Sbloom  *	catch alarm routine for "expect".
4613642Ssam  */
4713642Ssam alarmtr()
4813642Ssam {
4913642Ssam 	signal(SIGALRM, alarmtr);
5013642Ssam 	if (next_fd >= 0) {
5113642Ssam 		if (close(next_fd))
5213642Ssam 			logent("FAIL", "ACU LINE CLOSE");
5313642Ssam 		next_fd = -1;
5413642Ssam 	}
5513642Ssam 	longjmp(Sjbuf, 1);
5613642Ssam }
5713642Ssam 
5818619Sralph /*
5918619Sralph  *	place a telephone call to system and login, etc.
6013642Ssam  *
6113642Ssam  *	return codes:
6213642Ssam  *		CF_SYSTEM: don't know system
6313642Ssam  *		CF_TIME: wrong time to call
6413642Ssam  *		CF_DIAL: call failed
6513642Ssam  *		CF_NODEV: no devices available to place call
6613642Ssam  *		CF_LOGIN: login/password dialog failed
6713642Ssam  *
6813642Ssam  *		>0  - file no.  -  connect ok
6913642Ssam  */
7013642Ssam 
7113642Ssam int Dcf = -1;
7217834Sralph char *Flds[MAXC/10];
7317834Sralph extern int LocalOnly;
7413642Ssam 
7513642Ssam conn(system)
7613642Ssam char *system;
7713642Ssam {
7813642Ssam 	int ret, nf;
7917834Sralph 	register int fn = 0;
8018619Sralph 	char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE];
8113642Ssam 	register FILE *fsys;
8213642Ssam 	int fcode = 0;
8313642Ssam 
8413642Ssam 	nf = 0;
8513642Ssam 
8613642Ssam 	fsys = fopen(SYSFILE, "r");
8713642Ssam 	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
8813642Ssam 
8917834Sralph 	DEBUG(4, "finds (%s) called\n", system);
9025127Sbloom keeplooking:
9117834Sralph 	while((nf = finds(fsys, system, info, Flds)) > 0) {
9217834Sralph 		if (LocalOnly) {
9317834Sralph 			if (strcmp("TCP", Flds[F_LINE])
9417834Sralph 				&& strcmp("DIR", Flds[F_LINE])
9517834Sralph 				&& strcmp("LOCAL", Flds[F_LINE]) )
9617834Sralph 					fn = CF_TIME;
9717834Sralph 		}
9823596Sbloom 		sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
9918619Sralph 		if (!onesys && MaxGrade != DefMaxGrade &&
10018619Sralph 			!iswrk(file, "chk", Spool, wkpre))
10118619Sralph 				fn = CF_TIME;
10217834Sralph 		if (fn != CF_TIME && (fn = getto(Flds)) > 0) {
10313642Ssam 			Dcf = fn;
10413642Ssam 			break;
10513642Ssam 		}
10613642Ssam 		fcode = (fn == FAIL ? CF_DIAL : fn);
10713642Ssam 	}
10813642Ssam 
10925127Sbloom 	if (nf <= 0) {
11025127Sbloom 		fclose(fsys);
11117834Sralph 		return fcode ? fcode : nf;
11225127Sbloom 	}
11313642Ssam 
11413642Ssam 	DEBUG(4, "login %s\n", "called");
11517834Sralph 	ret = login(nf, Flds, fn);
11623596Sbloom 	if (ret != SUCCESS) {
11713642Ssam 		clsacu();
11825127Sbloom 		if (ret == ABORT) {
11925127Sbloom 			fcode = CF_DIAL;
12025127Sbloom 			goto  keeplooking;
12125127Sbloom 		} else {
12225127Sbloom 			fclose(fsys);
12323596Sbloom 			return CF_LOGIN;
12425127Sbloom 		}
12513642Ssam 	}
12625127Sbloom 	fclose(fsys);
12713642Ssam 	fioclex(fn);
12817834Sralph 	return fn;
12913642Ssam }
13013642Ssam 
13125127Sbloom /*
13225127Sbloom  *	connect to remote machine
13313642Ssam  *
13413642Ssam  *	return codes:
13513642Ssam  *		>0  -  file number - ok
13613642Ssam  *		FAIL  -  failed
13713642Ssam  */
13813642Ssam 
13913642Ssam getto(flds)
14013642Ssam register char *flds[];
14113642Ssam {
14213642Ssam 	register struct condev *cd;
14313642Ssam 	int nulldev(), diropn();
14425127Sbloom 	char *line;
14513642Ssam 
14617834Sralph 	DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
14713642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
14813642Ssam 
14925127Sbloom 	if (snccmp(flds[F_LINE], "LOCAL") == SAME)
15025127Sbloom 		line = "ACU";
15125127Sbloom 	else
15225127Sbloom 		line = flds[F_LINE];
15325127Sbloom #ifdef DIALINOUT
15425127Sbloom 	if (snccmp(line, "ACU") != SAME)
15525127Sbloom 		reenable();
15625127Sbloom #endif DIALINOUT
15713642Ssam 	CU_end = nulldev;
15813642Ssam 	for (cd = condevs; cd->CU_meth != NULL; cd++) {
15925127Sbloom 		if (snccmp(cd->CU_meth, line) == SAME) {
16013642Ssam 			DEBUG(4, "Using %s to call\n", cd->CU_meth);
16117834Sralph 			return (*(cd->CU_gen))(flds);
16213642Ssam 		}
16313642Ssam 	}
16425127Sbloom 	DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]);
16517834Sralph 	return diropn(flds);	/* search failed, so use direct */
16617834Sralph }
16713642Ssam 
16825127Sbloom /*
16925127Sbloom  *	close call unit
17013642Ssam  *
17113642Ssam  *	return codes:  none
17213642Ssam  */
17313642Ssam 
17413642Ssam int (*CU_end)() = nulldev;
17513642Ssam clsacu()
17613642Ssam {
17717834Sralph 	/* make *sure* Dcf is no longer exclusive.
17817834Sralph 	 * Otherwise dual call-in/call-out modems could get stuck.
17917834Sralph 	 * Unfortunately, doing this here is not ideal, but it is the
18017834Sralph 	 * easiest place to put the call.
18117834Sralph 	 * Hopefully everyone honors the LCK protocol, of course
18217834Sralph 	 */
18317834Sralph #ifndef	USG
18423596Sbloom 	if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0)
18523596Sbloom 		DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]);
18617834Sralph #endif
18717834Sralph 	if  (setjmp(Sjbuf))
18817834Sralph 		logent(Rmtname, "CLOSE TIMEOUT");
18917834Sralph 	else {
19017834Sralph 		signal(SIGALRM, alarmtr);
19117834Sralph 		alarm(20);
19217834Sralph 		(*(CU_end))(Dcf);
19317834Sralph 		alarm(0);
19417834Sralph 	}
19513642Ssam 	if (close(Dcf) == 0) {
19613642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
19713642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
19813642Ssam 	}
19913642Ssam 	Dcf = -1;
20013642Ssam 	CU_end = nulldev;
20113642Ssam }
20213642Ssam 
20325127Sbloom /*
20425127Sbloom  *	expand phone number for given prefix and number
20513642Ssam  */
20613642Ssam 
20713642Ssam exphone(in, out)
20813642Ssam register char *in, *out;
20913642Ssam {
21013642Ssam 	FILE *fn;
21113642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
21213642Ssam 	char buf[BUFSIZ];
21313642Ssam 	register char *s1;
21413642Ssam 
21517834Sralph 	if (!isascii(*in) || !isalpha(*in)) {
21613642Ssam 		strcpy(out, in);
21713642Ssam 		return;
21813642Ssam 	}
21913642Ssam 
22013642Ssam 	s1=pre;
22117834Sralph 	while (isascii(*in) && isalpha(*in))
22213642Ssam 		*s1++ = *in++;
22313642Ssam 	*s1 = '\0';
22413642Ssam 	s1 = npart;
22513642Ssam 	while (*in != '\0')
22613642Ssam 		*s1++ = *in++;
22713642Ssam 	*s1 = '\0';
22813642Ssam 
22913642Ssam 	tpre[0] = '\0';
23013642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
23113642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
23213642Ssam 	else {
23313642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
23417834Sralph 			if (sscanf(buf, "%s%s", p, tpre) != 2)
23517834Sralph 				continue;
23613642Ssam 			if (strcmp(p, pre) == SAME)
23713642Ssam 				goto found;
23813642Ssam 			tpre[0] = '\0';
23913642Ssam 		}
24013642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
24113642Ssam 	found:;
24213642Ssam 		fclose(fn);
24313642Ssam 	}
24413642Ssam 
24513642Ssam 	strcpy(out, tpre);
24613642Ssam 	strcat(out, npart);
24713642Ssam }
24813642Ssam 
24918619Sralph /*
25018619Sralph  *	read and decode a line from device file
25113642Ssam  *
25213642Ssam  *	return code - FAIL at end-of file; 0 otherwise
25313642Ssam  */
25413642Ssam 
25513642Ssam rddev(fp, dev)
25613642Ssam register struct Devices *dev;
25713642Ssam FILE *fp;
25813642Ssam {
25917834Sralph 	register int na;
26013642Ssam 
26117834Sralph 	if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp))
26217834Sralph 		return FAIL;
26317834Sralph 	na = getargs(dev->D_argbfr, dev->D_arg, 20);
26417834Sralph 	ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0);
26517834Sralph 	if (na == 4) {
26617834Sralph 		dev->D_brand = "";
26717834Sralph 		na++;
26817834Sralph 	}
26913642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
27017834Sralph 	dev->D_numargs = na;
27117834Sralph 	return 0;
27213642Ssam }
27313642Ssam 
27418619Sralph /*
27518619Sralph  *	set system attribute vector
27613642Ssam  *
27713642Ssam  *	return codes:
27813642Ssam  *		>0  -  number of arguments in vector - succeeded
27913642Ssam  *		CF_SYSTEM  -  system name not found
28013642Ssam  *		CF_TIME  -  wrong time to call
28113642Ssam  */
28213642Ssam 
28313642Ssam finds(fsys, sysnam, info, flds)
28413642Ssam char *sysnam, info[], *flds[];
28513642Ssam FILE *fsys;
28613642Ssam {
28713642Ssam 	int na;
28813642Ssam 	int fcode = 0;
28913642Ssam 
29013642Ssam 	/* format of fields
29113642Ssam 	 *	0 name;
29213642Ssam 	 *	1 time
29313642Ssam 	 *	2 acu/hardwired
29413642Ssam 	 *	3 speed
29513642Ssam 	 *	etc
29613642Ssam 	 */
29713642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
29817834Sralph 		na = getargs(info, flds, MAXC/10);
29923596Sbloom 		if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME)
30013642Ssam 			continue;
30118619Sralph 		if (ifdate(flds[F_TIME]) != FAIL)
30213642Ssam 			/*  found a good entry  */
30317834Sralph 			return na;
30413642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
30513642Ssam 		fcode = CF_TIME;
30613642Ssam 	}
30717834Sralph 	return fcode ? fcode : CF_SYSTEM;
30813642Ssam }
30913642Ssam 
31018619Sralph /*
31118619Sralph  *	do login conversation
31213642Ssam  *
31323596Sbloom  *	return codes:  SUCCESS  |  FAIL
31413642Ssam  */
31513642Ssam 
31613642Ssam login(nf, flds, fn)
31713642Ssam register char *flds[];
31813642Ssam int nf, fn;
31913642Ssam {
32013642Ssam 	register char *want, *altern;
32113642Ssam 	int k, ok;
32213642Ssam 
32317834Sralph 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf);
32417834Sralph 	if (setjmp(Cjbuf))
32517834Sralph 		return FAIL;
32617834Sralph 	AbortOn = NULL;
32713642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
32813642Ssam 		want = flds[k];
32913642Ssam 		ok = FAIL;
33017834Sralph 		while (ok != SUCCESS) {
33113642Ssam 			altern = index(want, '-');
33213642Ssam 			if (altern != NULL)
33313642Ssam 				*altern++ = '\0';
33417834Sralph 			if (strcmp(want, "ABORT") == 0) {
33517834Sralph 				AbortOn = flds[k+1];
33617834Sralph 				DEBUG(4, "ABORT ON: %s\n", AbortOn);
33717834Sralph 				goto nextfield;
33817834Sralph 			}
33917834Sralph 			DEBUG(4, "wanted: %s\n", want);
34013642Ssam 			ok = expect(want, fn);
34117834Sralph 			DEBUG(4, "got: %s\n", ok ? "?" : "that");
34217834Sralph 			if (ok == FAIL) {
34317834Sralph 				if (altern == NULL) {
34417834Sralph 					logent("LOGIN", _FAILED);
34517834Sralph 					return FAIL;
34617834Sralph 				}
34717834Sralph 				want = index(altern, '-');
34817834Sralph 				if (want != NULL)
34917834Sralph 					*want++ = '\0';
35017834Sralph 				sendthem(altern, fn);
35117834Sralph 			} else
35217834Sralph 				if (ok == ABORT) {
35317834Sralph 					logent("LOGIN ABORTED", _FAILED);
35423596Sbloom 					return ABORT;
35517834Sralph 				}
35613642Ssam 		}
35717834Sralph 		sleep(1);
35813642Ssam 		if (k+1 < nf)
35913642Ssam 			sendthem(flds[k+1], fn);
36017834Sralph nextfield: ;
36113642Ssam 	}
36217834Sralph 	return SUCCESS;
36313642Ssam }
36413642Ssam 
36513642Ssam 
36617834Sralph /* conditional table generation to support odd speeds */
36713642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
36813642Ssam #ifdef B50
36913642Ssam 	{  50,	 B50},
37013642Ssam #endif
37113642Ssam #ifdef B75
37213642Ssam 	{  75,	 B75},
37313642Ssam #endif
37413642Ssam #ifdef B110
37513642Ssam 	{ 110,	B110},
37613642Ssam #endif
37713642Ssam #ifdef B150
37813642Ssam 	{ 150,	B150},
37913642Ssam #endif
38013642Ssam #ifdef B200
38113642Ssam 	{ 200,	B200},
38213642Ssam #endif
38313642Ssam #ifdef B300
38413642Ssam 	{ 300,  B300},
38513642Ssam #endif
38613642Ssam #ifdef B600
38713642Ssam 	{600,	B600},
38813642Ssam #endif
38913642Ssam #ifdef B1200
39013642Ssam 	{1200, B1200},
39113642Ssam #endif
39213642Ssam #ifdef B1800
39313642Ssam 	{1800, B1800},
39413642Ssam #endif
39513642Ssam #ifdef B2000
39613642Ssam 	{2000, B2000},
39713642Ssam #endif
39813642Ssam #ifdef B2400
39913642Ssam 	{2400, B2400},
40013642Ssam #endif
40113642Ssam #ifdef B3600
40213642Ssam 	{3600, B3600},
40313642Ssam #endif
40413642Ssam #ifdef B4800
40513642Ssam 	{4800, B4800},
40613642Ssam #endif
40713642Ssam #ifdef B7200
40813642Ssam 	{7200, B7200},
40913642Ssam #endif
41013642Ssam #ifdef B9600
41113642Ssam 	{9600, B9600},
41213642Ssam #endif
41313642Ssam #ifdef B19200
41417834Sralph 	{19200, B19200},
41513642Ssam #endif
41617834Sralph #ifdef EXTA
41717834Sralph 	{19200, EXTA},
41817834Sralph #endif
41913642Ssam 	{0, 0}
42013642Ssam };
42113642Ssam 
42218619Sralph /*
42318619Sralph  *	set speed/echo/mode...
42413642Ssam  *
42513642Ssam  *	return codes:  none
42613642Ssam  */
42713642Ssam 
42813642Ssam fixline(tty, spwant)
42913642Ssam int tty, spwant;
43013642Ssam {
43117834Sralph #ifdef	USG
43213642Ssam 	struct termio ttbuf;
43317834Sralph #else	!USG
43413642Ssam 	struct sgttyb ttbuf;
43517834Sralph #endif !USG
43613642Ssam 	register struct sg_spds *ps;
43713642Ssam 	int speed = -1;
43813642Ssam 
43913642Ssam 	for (ps = spds; ps->sp_val; ps++)
44013642Ssam 		if (ps->sp_val == spwant)
44113642Ssam 			speed = ps->sp_name;
44217834Sralph 	ASSERT(speed >= 0, "BAD SPEED", CNULL, speed);
44317834Sralph #ifdef	USG
44423596Sbloom 	if (ioctl(tty, TCGETA, &ttbuf) < 0)
44523596Sbloom 		return FAIL;
44613642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
44713642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
44813642Ssam 	ttbuf.c_iflag = (ushort)0;
44913642Ssam 	ttbuf.c_oflag = (ushort)0;
45013642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
45113642Ssam 	ttbuf.c_lflag = (ushort)0;
45213642Ssam 	ttbuf.c_cc[VMIN] = 6;
45313642Ssam 	ttbuf.c_cc[VTIME] = 1;
45423596Sbloom 	if (ioctl(tty, TCSETA, &ttbuf) < 0)
45523596Sbloom 		return FAIL;
45617834Sralph #else	!USG
45723596Sbloom 	if (ioctl(tty, TIOCGETP, &ttbuf) < 0)
45823596Sbloom 		return FAIL;
45913642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
46013642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
46123596Sbloom 	if (ioctl(tty, TIOCSETP, &ttbuf) < 0)
46223596Sbloom 		return FAIL;
46313642Ssam #endif
46417834Sralph #ifndef	USG
46523596Sbloom 	if (ioctl(tty, TIOCHPCL, STBNULL) < 0)
46623596Sbloom 		return FAIL;
46723596Sbloom 	if (ioctl(tty, TIOCEXCL, STBNULL) < 0)
46823596Sbloom 		return FAIL;
46913642Ssam #endif
47017834Sralph 	linebaudrate = spwant;
47123596Sbloom 	return SUCCESS;
47213642Ssam }
47313642Ssam 
474*25518Stef /***
475*25518Stef  *	getbaud(tty)	set linebaudrate variable
476*25518Stef  *
477*25518Stef  *	return codes:  none
478*25518Stef  */
479*25518Stef 
480*25518Stef getbaud(tty)
481*25518Stef int tty;
482*25518Stef {
483*25518Stef #ifdef	USG
484*25518Stef 	struct termio ttbuf;
485*25518Stef #else
486*25518Stef 	struct sgttyb ttbuf;
487*25518Stef #endif
488*25518Stef 	register struct sg_spds *ps;
489*25518Stef 	register int name;
490*25518Stef 
491*25518Stef 	if (IsTcpIp)
492*25518Stef 		return;
493*25518Stef #ifdef	USG
494*25518Stef 	ioctl(tty, TCGETA, &ttbuf);
495*25518Stef 	name = ttbuf.c_cflag & CBAUD;
496*25518Stef #else
497*25518Stef 	ioctl(tty, TIOCGETP, &ttbuf);
498*25518Stef 	name = ttbuf.sg_ispeed;
499*25518Stef #endif
500*25518Stef 	for (ps = spds; ps->sp_val; ps++)
501*25518Stef 		if (ps->sp_name == name) {
502*25518Stef 			linebaudrate = ps->sp_val;
503*25518Stef 			break;
504*25518Stef 		}
505*25518Stef }
506*25518Stef 
50717834Sralph #define MR 100
50813642Ssam 
50918619Sralph /*
51018619Sralph  *	look for expected string
51113642Ssam  *
51213642Ssam  *	return codes:
51313642Ssam  *		0  -  found
51413642Ssam  *		FAIL  -  lost line or too many characters read
51513642Ssam  *		some character  -  timed out
51613642Ssam  */
51713642Ssam 
51813642Ssam expect(str, fn)
51913642Ssam register char *str;
52013642Ssam int fn;
52113642Ssam {
52214592Skarels 	char rdvec[MR];
52317834Sralph 	register char *rp = rdvec, *strptr;
52417834Sralph 	int kr, cnt_char;
52513642Ssam 	char nextch;
52625127Sbloom 	int timo = MAXMSGTIME;
52713642Ssam 
52817834Sralph 	if (*str == '\0' || strcmp(str, "\"\"") == SAME)
52917834Sralph 		return SUCCESS;
53017834Sralph 	/* Cleanup str, convert \0xx strings to one char  */
53117834Sralph 	for (strptr = str; *strptr; strptr++) {
53217834Sralph 		if (*strptr == '\\')
53317834Sralph 			switch(*++strptr) {
53417834Sralph 			case 's':
53517834Sralph 				DEBUG(5, "BLANK\n", CNULL);
53617834Sralph 				*strptr = ' ';
53717834Sralph 				break;
53817834Sralph 			default:
53917834Sralph 				strptr--;  /* back up to backslash */
54017834Sralph 				sscanf(strptr + 1,"%o", &cnt_char);
54117834Sralph 				DEBUG(6, "BACKSLASHED %02xH\n", cnt_char);
54217834Sralph 				*strptr = (char) (cnt_char);
54317834Sralph 				strcpy(&strptr[1], &strptr[4]);
54417834Sralph 			}
54517834Sralph 	}
54617834Sralph 
54725127Sbloom 	strptr = index(str, '~');
54825127Sbloom 	if (strptr != NULL) {
54925127Sbloom 		*strptr++ = '\0';
55025127Sbloom 		timo = atoi(strptr);
55125127Sbloom 		if (timo <= 0)
55225127Sbloom 			timo = MAXMSGTIME;
55325127Sbloom 	}
55425127Sbloom 
55517834Sralph 	if (setjmp(Sjbuf))
55617834Sralph 		return FAIL;
55713642Ssam 	signal(SIGALRM, alarmtr);
55825127Sbloom 	alarm(timo);
55925127Sbloom 	*rp = 0;
56013642Ssam 	while (notin(str, rdvec)) {
56117834Sralph 		if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
56217834Sralph 			DEBUG(1, "Call aborted on '%s'\n", AbortOn);
56317834Sralph 			alarm(0);
56417834Sralph 			return ABORT;
56517834Sralph 		}
56613642Ssam 		kr = read(fn, &nextch, 1);
56713642Ssam 		if (kr <= 0) {
56813642Ssam 			alarm(0);
56913642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
57013642Ssam 			logent("LOGIN", "LOST LINE");
57117834Sralph 			return FAIL;
57213642Ssam 		}
57313642Ssam 		{
57413642Ssam 		int c;
57513642Ssam 		c = nextch & 0177;
57613642Ssam 		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
57717834Sralph 		if (c == '\n')
57817834Sralph 			DEBUG(4,"\n", CNULL);
57913642Ssam 		}
58013642Ssam 		if ((*rp = nextch & 0177) != '\0')
58113642Ssam 			rp++;
58213642Ssam 		if (rp >= rdvec + MR) {
58317834Sralph 			register char *p;
58417834Sralph 			for (p = rdvec+MR/2; p < rp; p++)
58517834Sralph 				*(p-MR/2) = *p;
58617834Sralph 			rp -= MR/2;
58713642Ssam 		}
58813642Ssam 		*rp = '\0';
58913642Ssam 	}
59013642Ssam 	alarm(0);
59117834Sralph 	return SUCCESS;
59213642Ssam }
59313642Ssam 
59413642Ssam 
59513642Ssam /*
59613642Ssam  * Determine next file descriptor that would be allocated.
59713642Ssam  * This permits later closing of a file whose open was interrupted.
59813642Ssam  * It is a UNIX kernel problem, but it has to be handled.
59913642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
60013642Ssam  */
60113642Ssam getnextfd()
60213642Ssam {
60313642Ssam 	close(next_fd = open("/", 0));
60413642Ssam }
60513642Ssam 
60617834Sralph /*
60717834Sralph  *	send line of login sequence
60813642Ssam  *
60913642Ssam  *	return codes:  none
61013642Ssam  */
61113642Ssam sendthem(str, fn)
61213642Ssam register char *str;
61313642Ssam int fn;
61413642Ssam {
61513642Ssam 	register char *strptr;
61613642Ssam 	int i, n, cr = 1;
61717834Sralph 	register char c;
61813642Ssam 	static int p_init = 0;
61913642Ssam 
62013642Ssam 	DEBUG(5, "send %s\n", str);
62113642Ssam 
62213642Ssam 	if (!p_init) {
62313642Ssam 		p_init++;
62413642Ssam 		bld_partab(P_EVEN);
62513642Ssam 	}
62613642Ssam 
62713642Ssam 	if (prefix("BREAK", str)) {
62813642Ssam 		sscanf(&str[5], "%1d", &i);
62913642Ssam 		if (i <= 0 || i > 10)
63013642Ssam 			i = 3;
63113642Ssam 		/* send break */
63213642Ssam 		genbrk(fn, i);
63313642Ssam 		return;
63413642Ssam 	}
63513642Ssam 
63613642Ssam 	if (prefix("PAUSE", str)) {
63713642Ssam 		sscanf(&str[5], "%1d", &i);
63813642Ssam 		if (i <= 0 || i > 10)
63913642Ssam 			i = 3;
64013642Ssam 		/* pause for a while */
64113642Ssam 		sleep((unsigned)i);
64213642Ssam 		return;
64313642Ssam 	}
64413642Ssam 
64513642Ssam 	if (strcmp(str, "EOT") == SAME) {
64613642Ssam 		p_chwrite(fn, '\04');
64713642Ssam 		return;
64813642Ssam 	}
64913642Ssam 
65013642Ssam 	/* Send a '\n' */
65113642Ssam 	if (strcmp(str, "LF") == SAME)
65213642Ssam 		str = "\\n\\c";
65313642Ssam 
65413642Ssam 	/* Send a '\r' */
65513642Ssam 	if (strcmp(str, "CR") == SAME)
65613642Ssam 		str = "\\r\\c";
65713642Ssam 
65813642Ssam 	/* Set parity as needed */
65913642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
66013642Ssam 		bld_partab(P_ZERO);
66113642Ssam 		return;
66213642Ssam 	}
66313642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
66413642Ssam 		bld_partab(P_ONE);
66513642Ssam 		return;
66613642Ssam 	}
66713642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
66813642Ssam 		bld_partab(P_EVEN);
66913642Ssam 		return;
67013642Ssam 	}
67113642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
67213642Ssam 		bld_partab(P_ODD);
67313642Ssam 		return;
67413642Ssam 	}
67513642Ssam 
67613642Ssam 	/* If "", just send '\r' */
67717834Sralph 	if (strcmp(str, "\"\"") == SAME) {
67817834Sralph 		p_chwrite(fn, '\r');
67917834Sralph 		return;
68017834Sralph 	}
68117834Sralph 
68217834Sralph 	for (strptr = str; c = *strptr++;) {
68317834Sralph 		if (c == '\\') {
68417834Sralph 			switch(*strptr++) {
68517834Sralph 			case 's':
68617834Sralph 				DEBUG(5, "BLANK\n", CNULL);
68717834Sralph 				p_chwrite(fn, ' ');
68817834Sralph 				break;
68917834Sralph 			case 'd':
69017834Sralph 				DEBUG(5, "DELAY\n", CNULL);
69117834Sralph 				sleep(1);
69217834Sralph 				continue;
69317834Sralph 			case 'r':
69417834Sralph 				DEBUG(5, "RETURN\n", CNULL);
69517834Sralph 				p_chwrite(fn, '\r');
69617834Sralph 				break;
69717834Sralph 			case 'b':
69817834Sralph 				if (isdigit(*strptr)) {
69917834Sralph 					i = (*strptr++ - '0');
70017834Sralph 					if (i <= 0 || i > 10)
70117834Sralph 						i = 3;
70217834Sralph 				} else
70313642Ssam 					i = 3;
70417834Sralph 				/* send break */
70517834Sralph 				genbrk(fn, i);
70617834Sralph 				if (*strptr == '\0')
70717834Sralph 					cr = 0;
70813642Ssam 				continue;
70917834Sralph 			case 'c':
71017834Sralph 				if (*strptr == '\0') {
71117834Sralph 					DEBUG(5, "NO CR\n", CNULL);
71217834Sralph 					cr = 0;
71317834Sralph 					continue;
71417834Sralph 				}
71517834Sralph 				DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL);
71613642Ssam 				continue;
71717834Sralph 			default:
71817834Sralph 				if (isdigit(*strptr)) {
71917834Sralph 					i = 0;
72017834Sralph 					n = 0;
72117834Sralph 					while (isdigit(*strptr) && ++n <= 3)
72217834Sralph 						i = i*8 + (*strptr++ - '0');
72317834Sralph 					p_chwrite(fn, (char)i);
72417834Sralph 					continue;
72517834Sralph 				}
72617834Sralph 				DEBUG(5, "BACKSLASH\n", CNULL);
72717834Sralph 				--strptr;
72813642Ssam 			}
72917834Sralph 		} else
73017834Sralph 			p_chwrite(fn, c);
73113642Ssam 	}
73213642Ssam 
73313642Ssam 	if (cr)
73413642Ssam 		p_chwrite(fn, '\r');
73513642Ssam 	return;
73613642Ssam }
73713642Ssam 
73813642Ssam p_chwrite(fd, c)
73913642Ssam int fd;
74017834Sralph char c;
74113642Ssam {
74217834Sralph 	c = par_tab[c&0177];
74317834Sralph 	if (write(fd, &c, 1) != 1) {
74417834Sralph 		logent(sys_errlist[errno], "BAD WRITE");
74517834Sralph 		longjmp(Cjbuf, 2);
74617834Sralph 	}
74713642Ssam }
74813642Ssam 
74913642Ssam /*
75013642Ssam  * generate parity table for use by p_chwrite.
75113642Ssam  */
75213642Ssam bld_partab(type)
75313642Ssam int type;
75413642Ssam {
75513642Ssam 	register int i, j, n;
75613642Ssam 
75713642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
75813642Ssam 		n = 0;
75913642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
76013642Ssam 			n++;
76113642Ssam 		par_tab[i] = i;
76213642Ssam 		if (type == P_ONE
76313642Ssam 		 || (type == P_EVEN && (n&01) != 0)
76413642Ssam 		 || (type == P_ODD && (n&01) == 0))
76513642Ssam 			par_tab[i] |= sizeof(par_tab);
76613642Ssam 	}
76713642Ssam }
76813642Ssam 
76913642Ssam #define BSPEED B150
77013642Ssam 
77118619Sralph /*
77218619Sralph  *	send a break
77313642Ssam  */
77413642Ssam genbrk(fn, bnulls)
77513642Ssam register int fn, bnulls;
77613642Ssam {
77717834Sralph #ifdef	USG
77823596Sbloom 	if (ioctl(fn, TCSBRK, STBNULL) < 0)
77923596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
78017834Sralph #else	!USG
78123596Sbloom 	struct sgttyb ttbuf;
78223596Sbloom 	register int sospeed;
78323596Sbloom # ifdef	TIOCSBRK
78423596Sbloom 	if (ioctl(fn, TIOCSBRK, STBNULL) < 0)
78523596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
78623596Sbloom # ifdef	TIOCCBRK
78713642Ssam 	sleep(1);
78823596Sbloom 	if (ioctl(fn, TIOCCBRK, STBNULL) < 0)
78923596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
79023596Sbloom # endif TIOCCBRK
79117834Sralph 	DEBUG(4, "ioctl %d second break\n", bnulls );
79223596Sbloom # else !TIOCSBRK
79313642Ssam 
79423596Sbloom 	if (ioctl(fn, TIOCGETP, &ttbuf) < 0)
79523596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
79613642Ssam 	sospeed = ttbuf.sg_ospeed;
79713642Ssam 	ttbuf.sg_ospeed = BSPEED;
79823596Sbloom 	if (ioctl(fn, TIOCSETP, &ttbuf) < 0)
79923596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
80023596Sbloom 	if (write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls) != bnulls) {
80117834Sralph badbreak:
80217834Sralph 		logent(sys_errlist[errno], "BAD WRITE genbrk");
80317834Sralph 		alarm(0);
80417834Sralph 		longjmp(Sjbuf, 3);
80517834Sralph 	}
80613642Ssam 	ttbuf.sg_ospeed = sospeed;
80723596Sbloom 	if (ioctl(fn, TIOCSETP, &ttbuf) < 0)
80823596Sbloom 		DEBUG(5, "break ioctl %s\n", sys_errlist[errno]);
80923596Sbloom 	if (write(fn, "@", 1) != 1)
81017834Sralph 		goto badbreak;
81113642Ssam 	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
81217834Sralph #endif !TIOCSBRK
81317834Sralph #endif !USG
81413642Ssam }
81513642Ssam 
81618619Sralph /*
81718619Sralph  *	check for occurrence of substring "sh"
81813642Ssam  *
81913642Ssam  *	return codes:
82013642Ssam  *		0  -  found the string
82113642Ssam  *		1  -  not in the string
82213642Ssam  */
82313642Ssam notin(sh, lg)
82413642Ssam register char *sh, *lg;
82513642Ssam {
82613642Ssam 	while (*lg != '\0') {
82713642Ssam 		if (wprefix(sh, lg))
82818619Sralph 			return 0;
82913642Ssam 		else
83013642Ssam 			lg++;
83113642Ssam 	}
83218619Sralph 	return 1;
83313642Ssam }
83413642Ssam 
83518619Sralph /*
83623596Sbloom  *	Allow multiple date specifications separated by ','.
83713642Ssam  */
83818619Sralph ifdate(p)
83918619Sralph register char *p;
84013642Ssam {
84123596Sbloom 	register char *np, c;
84218619Sralph 	register int ret, g;
84323596Sbloom 	int rtime, i;
84413642Ssam 
84523596Sbloom 	/*  pick up retry time for failures  */
84623596Sbloom 	/*  global variable Retrytime is set here  */
84723596Sbloom 	if ((np = index(p, ';')) == NULL) {
84823596Sbloom 		Retrytime = RETRYTIME;
84923596Sbloom 	} else {
85023596Sbloom 		i = sscanf(np+1, "%d", &rtime);
85123596Sbloom 		if (i < 1 || rtime < 0)
85223596Sbloom 			rtime = 5;
85323596Sbloom 		Retrytime  = rtime * 60;
85423596Sbloom 	}
85523596Sbloom 
85618619Sralph 	ret = FAIL;
85718619Sralph 	MaxGrade = '\0';
85818619Sralph 	do {
85923596Sbloom 		np = strpbrk(p, ",|");	/* prefer , but allow | for compat */
86023596Sbloom 		if (np)
86123596Sbloom 			*np = '\0';
86218619Sralph 		g = ifadate(p);
86318619Sralph 		DEBUG(11,"ifadate returns %o\n", g);
86418619Sralph 		if (g != FAIL) {
86518619Sralph 			ret = SUCCESS;
86618619Sralph 			if (g > MaxGrade)
86718619Sralph 				MaxGrade = g;
86818619Sralph 		}
86923596Sbloom 		if (np)
87023596Sbloom 			*np = ',';
87123596Sbloom 		p = np + 1;
87223596Sbloom 	} while (np);
87323596Sbloom 	if (MaxGrade == '\0')
87423596Sbloom 		MaxGrade = DefMaxGrade;
87518619Sralph 	return ret;
87613642Ssam }
87713642Ssam 
87818619Sralph /*
87918619Sralph  *	this routine will check a string (string)
88013642Ssam  *	like "MoTu0800-1730" to see if the present
88113642Ssam  *	time is within the given limits.
88213642Ssam  *	SIDE EFFECT - Retrytime is set
88313642Ssam  *
88413642Ssam  *	return codes:
88513642Ssam  *		0  -  not within limits
88613642Ssam  *		1  -  within limits
88713642Ssam  */
88813642Ssam 
88918619Sralph ifadate(string)
89018619Sralph char *string;
89113642Ssam {
89213642Ssam 	static char *days[]={
89313642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
89413642Ssam 	};
89513642Ssam 	time_t clock;
89618619Sralph 	register char *s = string;
89717834Sralph 	int i, tl, th, tn, dayok=0;
89813642Ssam 	struct tm *localtime();
89913642Ssam 	struct tm *tp;
90018619Sralph 	char *p, MGrade;
90113642Ssam 
90223596Sbloom 	if ((p = index(s, '/')) == NULL)
90318619Sralph 		MGrade = DefMaxGrade;
90418619Sralph 	else
90518619Sralph 		MGrade = p[1];
90618619Sralph 
90713642Ssam 	time(&clock);
90813642Ssam 	tp = localtime(&clock);
90917834Sralph 	while (isascii(*s) && isalpha(*s)) {
91013642Ssam 		for (i = 0; days[i]; i++) {
91113642Ssam 			if (prefix(days[i], s))
91213642Ssam 				if (tp->tm_wday == i)
91313642Ssam 					dayok = 1;
91413642Ssam 		}
91513642Ssam 
91613642Ssam 		if (prefix("Wk", s))
91713642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
91813642Ssam 				dayok = 1;
91913642Ssam 		if (prefix("Any", s))
92013642Ssam 			dayok = 1;
92117834Sralph 		if (prefix("Evening", s)) {
92217834Sralph 			/* Sat or Sun */
92317834Sralph 			if (tp->tm_wday == 6 || tp->tm_wday == 0
92417834Sralph 				|| tp->tm_hour >= 17 || tp->tm_hour < 8)
92517834Sralph 					dayok = 1;
92617834Sralph 		}
92717834Sralph 		if (prefix("Night", s)) {
92817834Sralph 			if (tp->tm_wday == 6  /* Sat */
92918619Sralph 				|| tp->tm_hour >= 23 || tp->tm_hour < 8
93018619Sralph 					/* Sunday before 5pm */
93118619Sralph 				|| (tp->tm_wday == 0 && tp->tm_hour < 17))
93217834Sralph 					dayok = 1;
93317834Sralph 		}
93413642Ssam 		s++;
93513642Ssam 	}
93613642Ssam 
93718619Sralph 	if (dayok == 0 && s != string)
93818619Sralph 		return FAIL;
93913642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
94018619Sralph   	if (i < 2)
94118619Sralph   		return MGrade;
94218619Sralph 	tn = tp->tm_hour * 100 + tp->tm_min;
94318619Sralph   	if (th < tl) { 		/* crosses midnight */
94418619Sralph   		if (tl <= tn || tn < th)
94518619Sralph   			return MGrade;
94618619Sralph   	} else
94718619Sralph 
94813642Ssam 	if (i < 2)
94918619Sralph 		return MGrade;
95018619Sralph 	if (th < tl) { 	/* crosses midnight */
95117834Sralph 		if (tl <= tn || tn < th)
95218619Sralph 			return MGrade;
95317834Sralph 	} else
95417834Sralph 		if (tl <= tn && tn < th)
95518619Sralph 			return MGrade;
95618619Sralph 	return FAIL;
95713642Ssam }
95813642Ssam 
95918619Sralph /*
96018619Sralph  *	find first digit in string
96113642Ssam  *
96213642Ssam  *	return - pointer to first digit in string or end of string
96313642Ssam  */
96413642Ssam char *
96513642Ssam fdig(cp)
96613642Ssam register char *cp;
96713642Ssam {
96813642Ssam 	register char *c;
96913642Ssam 
97013642Ssam 	for (c = cp; *c; c++)
97113642Ssam 		if (*c >= '0' && *c <= '9')
97213642Ssam 			break;
97317834Sralph 	return c;
97413642Ssam }
97513642Ssam 
97613642Ssam /*
97713642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
97813642Ssam  * Strings are compared as if they contain all capital letters.
97913642Ssam  */
98013642Ssam snccmp(s1, s2)
98113642Ssam register char *s1, *s2;
98213642Ssam {
98313642Ssam 	char c1, c2;
98413642Ssam 
98525127Sbloom 	if (islower(*s1))
98625127Sbloom 		c1 = toupper(*s1);
98725127Sbloom 	else
98825127Sbloom 		c1 = *s1;
98925127Sbloom 	if (islower(*s2))
99025127Sbloom 		c2 = toupper(*s2);
99125127Sbloom 	else
99225127Sbloom 		c2 = *s2;
99313642Ssam 
99413642Ssam 	while (c1 == c2) {
99525127Sbloom 		if (*s1++ == '\0')
99617834Sralph 			return 0;
99713642Ssam 		s2++;
99825127Sbloom 		if (islower(*s1))
99925127Sbloom 			c1 = toupper(*s1);
100025127Sbloom 		else
100125127Sbloom 			c1 = *s1;
100225127Sbloom 		if (islower(*s2))
100325127Sbloom 			c2 = toupper(*s2);
100425127Sbloom 		else
100525127Sbloom 			c2 = *s2;
100613642Ssam 	}
100717834Sralph 	return c1 - c2;
100813642Ssam }
100925127Sbloom 
101017834Sralph /*
101125127Sbloom  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
101225127Sbloom  * Strings are compared as if they contain all capital letters.
101325127Sbloom  */
101425127Sbloom sncncmp(s1, s2, n)
101525127Sbloom register char *s1, *s2;
101625127Sbloom register int n;
101725127Sbloom {
101825127Sbloom 	char c1, c2;
101925127Sbloom 
102025127Sbloom 	if (islower(*s1))
102125127Sbloom 		c1 = toupper(*s1);
102225127Sbloom 	else
102325127Sbloom 		c1 = *s1;
102425127Sbloom 	if (islower(*s2))
102525127Sbloom 		c2 = toupper(*s2);
102625127Sbloom 	else
102725127Sbloom 		c2 = *s2;
102825127Sbloom 
102925127Sbloom 	while ( --n >= 0 && c1 == c2) {
103025127Sbloom 		if (*s1++ == '\0')
103125127Sbloom 			return 0;
103225127Sbloom 		s2++;
103325127Sbloom 		if (islower(*s1))
103425127Sbloom 			c1 = toupper(*s1);
103525127Sbloom 		else
103625127Sbloom 			c1 = *s1;
103725127Sbloom 		if (islower(*s2))
103825127Sbloom 			c2 = toupper(*s2);
103925127Sbloom 		else
104025127Sbloom 			c2 = *s2;
104125127Sbloom 	}
104225127Sbloom 	return n<0 ? 0 : (c1 - c2);
104325127Sbloom }
104425127Sbloom /*
104517834Sralph  * do chat script
104617834Sralph  * occurs after local port is opened,
104717834Sralph  * before 'dialing' the other machine.
104817834Sralph  */
104917834Sralph dochat(dev, flds, fd)
105017834Sralph register struct Devices *dev;
105117834Sralph char *flds[];
105217834Sralph int fd;
105317834Sralph {
105417834Sralph 	register int i;
105517834Sralph 	register char *p;
105617834Sralph 	char bfr[sizeof(dev->D_argbfr)];
105717834Sralph 
105817834Sralph 	if (dev->D_numargs <= 5)
105917834Sralph 		return(0);
106017834Sralph 	DEBUG(4, "dochat called %d\n", dev->D_numargs);
106117834Sralph 	for (i = 0; i < dev->D_numargs-5; i++) {
106217834Sralph 		sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]);
106317834Sralph 		if (strcmp(bfr, dev->D_arg[D_CHAT+i])) {
106417834Sralph 			p = malloc((unsigned)strlen(bfr)+1);
106517834Sralph 			if (p != NULL) {
106617834Sralph 				strcpy(p, bfr);
106717834Sralph 				dev->D_arg[D_CHAT+i] = p;
106817834Sralph 			}
106917834Sralph 		}
107017834Sralph 	}
107117834Sralph 	/* following is a kludge because login() arglist is a kludge */
107217834Sralph 	i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd);
107317834Sralph 	/*
107417834Sralph 	 * If login() last did a sendthem(), must pause so things can settle.
107517834Sralph 	 * But don't bother if chat failed.
107617834Sralph 	 */
107717834Sralph 	if (i == 0 && (dev->D_numargs&01))
107817834Sralph 		sleep(2);
107917834Sralph 	return(i);
108017834Sralph }
1081