xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 17834)
113642Ssam #ifndef lint
2*17834Sralph static char sccsid[] = "@(#)conn.c	5.4 (Berkeley) 01/22/85";
313642Ssam #endif
413642Ssam 
513642Ssam #include "uucp.h"
613642Ssam #include <signal.h>
713642Ssam #include <setjmp.h>
813642Ssam #include <ctype.h>
913642Ssam #include <sys/types.h>
1013642Ssam #include <errno.h>
11*17834Sralph #ifdef	USG
1213642Ssam #include <termio.h>
1313642Ssam #include <fcntl.h>
1413642Ssam #endif
15*17834Sralph #ifndef	USG
1613642Ssam #include <sgtty.h>
1713642Ssam #endif
18*17834Sralph #ifdef BSD4_2
19*17834Sralph #include <sys/time.h>
20*17834Sralph #else
21*17834Sralph #include <time.h>
22*17834Sralph #endif
2313642Ssam 
2413642Ssam #define MAXC 1000
2513642Ssam 
2613642Ssam extern jmp_buf Sjbuf;
27*17834Sralph jmp_buf Cjbuf;
2813642Ssam extern int errno;
29*17834Sralph extern char *sys_errlist[];
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
36*17834Sralph 
37*17834Sralph #define ABORT -2
38*17834Sralph 
39*17834Sralph char 	*AbortOn = NULL;
4013642Ssam char	par_tab[128];	/* must be power of two */
41*17834Sralph 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 */
4413642Ssam /***
4513642Ssam  *	alarmtr()  -  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 
5813642Ssam /*******
5913642Ssam  *	conn(system)
6013642Ssam  *	char *system;
6113642Ssam  *
6213642Ssam  *	conn - place a telephone call to system and
6313642Ssam  *	login, etc.
6413642Ssam  *
6513642Ssam  *	return codes:
6613642Ssam  *		CF_SYSTEM: don't know system
6713642Ssam  *		CF_TIME: wrong time to call
6813642Ssam  *		CF_DIAL: call failed
6913642Ssam  *		CF_NODEV: no devices available to place call
7013642Ssam  *		CF_LOGIN: login/password dialog failed
7113642Ssam  *
7213642Ssam  *		>0  - file no.  -  connect ok
7313642Ssam  *
7413642Ssam  */
7513642Ssam 
7613642Ssam int Dcf = -1;
77*17834Sralph char *Flds[MAXC/10];
78*17834Sralph extern int LocalOnly;
7913642Ssam 
8013642Ssam conn(system)
8113642Ssam char *system;
8213642Ssam {
8313642Ssam 	int ret, nf;
84*17834Sralph 	register int fn = 0;
85*17834Sralph 	char info[MAXC];
8613642Ssam 	register FILE *fsys;
8713642Ssam 	int fcode = 0;
8813642Ssam 
8913642Ssam 	nf = 0;
9013642Ssam 
9113642Ssam 	fsys = fopen(SYSFILE, "r");
9213642Ssam 	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
9313642Ssam 
94*17834Sralph 	DEBUG(4, "finds (%s) called\n", system);
95*17834Sralph 	while((nf = finds(fsys, system, info, Flds)) > 0) {
96*17834Sralph 		if (LocalOnly) {
97*17834Sralph 			if (strcmp("TCP", Flds[F_LINE])
98*17834Sralph 				&& strcmp("DIR", Flds[F_LINE])
99*17834Sralph 				&& strcmp("LOCAL", Flds[F_LINE]) )
100*17834Sralph 					fn = CF_TIME;
101*17834Sralph 		}
102*17834Sralph 		if (fn != CF_TIME && (fn = getto(Flds)) > 0) {
10313642Ssam 			Dcf = fn;
10413642Ssam 			break;
10513642Ssam 		}
10613642Ssam 		fcode = (fn == FAIL ? CF_DIAL : fn);
10713642Ssam 	}
10813642Ssam 	fclose(fsys);
10913642Ssam 
11013642Ssam 	if (nf <= 0)
111*17834Sralph 		return fcode ? fcode : nf;
11213642Ssam 
11313642Ssam 	DEBUG(4, "login %s\n", "called");
114*17834Sralph 	ret = login(nf, Flds, fn);
115*17834Sralph 	if (ret == FAIL) {
11613642Ssam 		clsacu();
117*17834Sralph 		return CF_LOGIN;
11813642Ssam 	}
11913642Ssam 	/* rti!trt:  avoid passing file to children */
12013642Ssam 	fioclex(fn);
121*17834Sralph 	return fn;
12213642Ssam }
12313642Ssam 
12413642Ssam /***
12513642Ssam  *	getto(flds)		connect to remote machine
12613642Ssam  *	char *flds[];
12713642Ssam  *
12813642Ssam  *	return codes:
12913642Ssam  *		>0  -  file number - ok
13013642Ssam  *		FAIL  -  failed
13113642Ssam  */
13213642Ssam 
13313642Ssam getto(flds)
13413642Ssam register char *flds[];
13513642Ssam {
13613642Ssam 	register struct condev *cd;
13713642Ssam 	int nulldev(), diropn();
13813642Ssam 
139*17834Sralph 	DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
14013642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
14113642Ssam 
14213642Ssam 	CU_end = nulldev;
14313642Ssam 	for (cd = condevs; cd->CU_meth != NULL; cd++) {
14413642Ssam 		if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) {
14513642Ssam 			DEBUG(4, "Using %s to call\n", cd->CU_meth);
146*17834Sralph 			return (*(cd->CU_gen))(flds);
14713642Ssam 		}
14813642Ssam 	}
149*17834Sralph 	DEBUG(1, "Can't find %s, assuming DIR", flds[F_LINE]);
150*17834Sralph 	return diropn(flds);	/* search failed, so use direct */
151*17834Sralph }
15213642Ssam 
15313642Ssam /***
15413642Ssam  *	clsacu()	close call unit
15513642Ssam  *
15613642Ssam  *	return codes:  none
15713642Ssam  */
15813642Ssam 
15913642Ssam int (*CU_end)() = nulldev;
16013642Ssam clsacu()
16113642Ssam {
162*17834Sralph 	/* make *sure* Dcf is no longer exclusive.
163*17834Sralph 	 * Otherwise dual call-in/call-out modems could get stuck.
164*17834Sralph 	 * Unfortunately, doing this here is not ideal, but it is the
165*17834Sralph 	 * easiest place to put the call.
166*17834Sralph 	 * Hopefully everyone honors the LCK protocol, of course
167*17834Sralph 	 */
168*17834Sralph #ifndef	USG
169*17834Sralph 	ioctl(Dcf, TIOCNXCL, STBNULL);
170*17834Sralph #endif
171*17834Sralph 	if  (setjmp(Sjbuf))
172*17834Sralph 		logent(Rmtname, "CLOSE TIMEOUT");
173*17834Sralph 	else {
174*17834Sralph 		signal(SIGALRM, alarmtr);
175*17834Sralph 		alarm(20);
176*17834Sralph 		(*(CU_end))(Dcf);
177*17834Sralph 		alarm(0);
178*17834Sralph 	}
17913642Ssam 	if (close(Dcf) == 0) {
18013642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
18113642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
18213642Ssam 	}
18313642Ssam 	Dcf = -1;
18413642Ssam 	CU_end = nulldev;
18513642Ssam }
18613642Ssam 
18713642Ssam /***
18813642Ssam  *	exphone - expand phone number for given prefix and number
18913642Ssam  *
19013642Ssam  *	return code - none
19113642Ssam  */
19213642Ssam 
19313642Ssam exphone(in, out)
19413642Ssam register char *in, *out;
19513642Ssam {
19613642Ssam 	FILE *fn;
19713642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
19813642Ssam 	char buf[BUFSIZ];
19913642Ssam 	register char *s1;
20013642Ssam 
201*17834Sralph 	if (!isascii(*in) || !isalpha(*in)) {
20213642Ssam 		strcpy(out, in);
20313642Ssam 		return;
20413642Ssam 	}
20513642Ssam 
20613642Ssam 	s1=pre;
207*17834Sralph 	while (isascii(*in) && isalpha(*in))
20813642Ssam 		*s1++ = *in++;
20913642Ssam 	*s1 = '\0';
21013642Ssam 	s1 = npart;
21113642Ssam 	while (*in != '\0')
21213642Ssam 		*s1++ = *in++;
21313642Ssam 	*s1 = '\0';
21413642Ssam 
21513642Ssam 	tpre[0] = '\0';
21613642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
21713642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
21813642Ssam 	else {
21913642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
220*17834Sralph 			if (sscanf(buf, "%s%s", p, tpre) != 2)
221*17834Sralph 				continue;
22213642Ssam 			if (strcmp(p, pre) == SAME)
22313642Ssam 				goto found;
22413642Ssam 			tpre[0] = '\0';
22513642Ssam 		}
22613642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
22713642Ssam 	found:;
22813642Ssam 		fclose(fn);
22913642Ssam 	}
23013642Ssam 
23113642Ssam 	strcpy(out, tpre);
23213642Ssam 	strcat(out, npart);
23313642Ssam }
23413642Ssam 
23513642Ssam /***
23613642Ssam  *	rddev - read and decode a line from device file
23713642Ssam  *
23813642Ssam  *	return code - FAIL at end-of file; 0 otherwise
23913642Ssam  */
24013642Ssam 
24113642Ssam rddev(fp, dev)
24213642Ssam register struct Devices *dev;
24313642Ssam FILE *fp;
24413642Ssam {
245*17834Sralph 	register int na;
24613642Ssam 
247*17834Sralph 	if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp))
248*17834Sralph 		return FAIL;
249*17834Sralph 	na = getargs(dev->D_argbfr, dev->D_arg, 20);
250*17834Sralph 	ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0);
251*17834Sralph 	if (na == 4) {
252*17834Sralph 		dev->D_brand = "";
253*17834Sralph 		na++;
254*17834Sralph 	}
25513642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
256*17834Sralph 	dev->D_numargs = na;
257*17834Sralph 	return 0;
25813642Ssam }
25913642Ssam 
26013642Ssam /***
26113642Ssam  *	finds(fsys, sysnam, info, flds)	set system attribute vector
26213642Ssam  *
26313642Ssam  *	return codes:
26413642Ssam  *		>0  -  number of arguments in vector - succeeded
26513642Ssam  *		CF_SYSTEM  -  system name not found
26613642Ssam  *		CF_TIME  -  wrong time to call
26713642Ssam  */
26813642Ssam 
26913642Ssam finds(fsys, sysnam, info, flds)
27013642Ssam char *sysnam, info[], *flds[];
27113642Ssam FILE *fsys;
27213642Ssam {
27313642Ssam 	char sysn[8];
27413642Ssam 	int na;
27513642Ssam 	int fcode = 0;
27613642Ssam 
27713642Ssam 	/* format of fields
27813642Ssam 	 *	0 name;
27913642Ssam 	 *	1 time
28013642Ssam 	 *	2 acu/hardwired
28113642Ssam 	 *	3 speed
28213642Ssam 	 *	etc
28313642Ssam 	 */
28413642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
285*17834Sralph 		na = getargs(info, flds, MAXC/10);
28613642Ssam 		sprintf(sysn, "%.7s", flds[F_NAME]);
28713642Ssam 		if (strcmp(sysnam, sysn) != SAME)
28813642Ssam 			continue;
28913642Ssam 		if (ifdate(flds[F_TIME]))
29013642Ssam 			/*  found a good entry  */
291*17834Sralph 			return na;
29213642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
29313642Ssam 		fcode = CF_TIME;
29413642Ssam 	}
295*17834Sralph 	return fcode ? fcode : CF_SYSTEM;
29613642Ssam }
29713642Ssam 
29813642Ssam /***
29913642Ssam  *	login(nf, flds, dcr)		do login conversation
30013642Ssam  *	char *flds[];
30113642Ssam  *	int nf;
30213642Ssam  *
30313642Ssam  *	return codes:  0  |  FAIL
30413642Ssam  */
30513642Ssam 
30613642Ssam login(nf, flds, fn)
30713642Ssam register char *flds[];
30813642Ssam int nf, fn;
30913642Ssam {
31013642Ssam 	register char *want, *altern;
31113642Ssam 	extern char *index();
31213642Ssam 	int k, ok;
31313642Ssam 
314*17834Sralph 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf);
315*17834Sralph 	if (setjmp(Cjbuf))
316*17834Sralph 		return FAIL;
317*17834Sralph 	AbortOn = NULL;
31813642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
31913642Ssam 		want = flds[k];
32013642Ssam 		ok = FAIL;
321*17834Sralph 		while (ok != SUCCESS) {
32213642Ssam 			altern = index(want, '-');
32313642Ssam 			if (altern != NULL)
32413642Ssam 				*altern++ = '\0';
325*17834Sralph 			if (strcmp(want, "ABORT") == 0) {
326*17834Sralph 				AbortOn = flds[k+1];
327*17834Sralph 				DEBUG(4, "ABORT ON: %s\n", AbortOn);
328*17834Sralph 				goto nextfield;
329*17834Sralph 			}
330*17834Sralph 			DEBUG(4, "wanted: %s\n", want);
33113642Ssam 			ok = expect(want, fn);
332*17834Sralph 			DEBUG(4, "got: %s\n", ok ? "?" : "that");
333*17834Sralph 			if (ok == FAIL) {
334*17834Sralph 				if (altern == NULL) {
335*17834Sralph 					logent("LOGIN", _FAILED);
336*17834Sralph 					return FAIL;
337*17834Sralph 				}
338*17834Sralph 				want = index(altern, '-');
339*17834Sralph 				if (want != NULL)
340*17834Sralph 					*want++ = '\0';
341*17834Sralph 				sendthem(altern, fn);
342*17834Sralph 			} else
343*17834Sralph 				if (ok == ABORT) {
344*17834Sralph 					logent("LOGIN ABORTED", _FAILED);
345*17834Sralph 					return FAIL;
346*17834Sralph 				}
34713642Ssam 		}
348*17834Sralph 		sleep(1);
34913642Ssam 		if (k+1 < nf)
35013642Ssam 			sendthem(flds[k+1], fn);
351*17834Sralph nextfield: ;
35213642Ssam 	}
353*17834Sralph 	return SUCCESS;
35413642Ssam }
35513642Ssam 
35613642Ssam 
357*17834Sralph /* conditional table generation to support odd speeds */
35813642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
35913642Ssam #ifdef B50
36013642Ssam 	{  50,	 B50},
36113642Ssam #endif
36213642Ssam #ifdef B75
36313642Ssam 	{  75,	 B75},
36413642Ssam #endif
36513642Ssam #ifdef B110
36613642Ssam 	{ 110,	B110},
36713642Ssam #endif
36813642Ssam #ifdef B150
36913642Ssam 	{ 150,	B150},
37013642Ssam #endif
37113642Ssam #ifdef B200
37213642Ssam 	{ 200,	B200},
37313642Ssam #endif
37413642Ssam #ifdef B300
37513642Ssam 	{ 300,  B300},
37613642Ssam #endif
37713642Ssam #ifdef B600
37813642Ssam 	{600,	B600},
37913642Ssam #endif
38013642Ssam #ifdef B1200
38113642Ssam 	{1200, B1200},
38213642Ssam #endif
38313642Ssam #ifdef B1800
38413642Ssam 	{1800, B1800},
38513642Ssam #endif
38613642Ssam #ifdef B2000
38713642Ssam 	{2000, B2000},
38813642Ssam #endif
38913642Ssam #ifdef B2400
39013642Ssam 	{2400, B2400},
39113642Ssam #endif
39213642Ssam #ifdef B3600
39313642Ssam 	{3600, B3600},
39413642Ssam #endif
39513642Ssam #ifdef B4800
39613642Ssam 	{4800, B4800},
39713642Ssam #endif
39813642Ssam #ifdef B7200
39913642Ssam 	{7200, B7200},
40013642Ssam #endif
40113642Ssam #ifdef B9600
40213642Ssam 	{9600, B9600},
40313642Ssam #endif
40413642Ssam #ifdef B19200
405*17834Sralph 	{19200, B19200},
40613642Ssam #endif
407*17834Sralph #ifdef EXTA
408*17834Sralph 	{19200, EXTA},
409*17834Sralph #endif
41013642Ssam 	{0, 0}
41113642Ssam };
41213642Ssam 
41313642Ssam /***
41413642Ssam  *	fixline(tty, spwant)	set speed/echo/mode...
41513642Ssam  *	int tty, spwant;
41613642Ssam  *
41713642Ssam  *	return codes:  none
41813642Ssam  */
41913642Ssam 
42013642Ssam fixline(tty, spwant)
42113642Ssam int tty, spwant;
42213642Ssam {
423*17834Sralph #ifdef	USG
42413642Ssam 	struct termio ttbuf;
425*17834Sralph #else	!USG
42613642Ssam 	struct sgttyb ttbuf;
427*17834Sralph #endif !USG
42813642Ssam 	register struct sg_spds *ps;
42913642Ssam 	int speed = -1;
43013642Ssam 	int ret;
43113642Ssam 
43213642Ssam 	for (ps = spds; ps->sp_val; ps++)
43313642Ssam 		if (ps->sp_val == spwant)
43413642Ssam 			speed = ps->sp_name;
435*17834Sralph 	ASSERT(speed >= 0, "BAD SPEED", CNULL, speed);
436*17834Sralph #ifdef	USG
43713642Ssam 	ioctl(tty, TCGETA, &ttbuf);
43813642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
43913642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
44013642Ssam 	ttbuf.c_iflag = (ushort)0;
44113642Ssam 	ttbuf.c_oflag = (ushort)0;
44213642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
44313642Ssam 	ttbuf.c_lflag = (ushort)0;
44413642Ssam 	ttbuf.c_cc[VMIN] = 6;
44513642Ssam 	ttbuf.c_cc[VTIME] = 1;
44613642Ssam 	ret = ioctl(tty, TCSETA, &ttbuf);
447*17834Sralph #else	!USG
44813642Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
44913642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
45013642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
45113642Ssam 	ret = ioctl(tty, TIOCSETP, &ttbuf);
45213642Ssam #endif
453*17834Sralph 	ASSERT(ret >= 0, "RETURN FROM STTY", CNULL, ret);
454*17834Sralph #ifndef	USG
45513642Ssam 	ioctl(tty, TIOCHPCL, STBNULL);
45613642Ssam 	ioctl(tty, TIOCEXCL, STBNULL);
45713642Ssam #endif
458*17834Sralph 	linebaudrate = spwant;
45913642Ssam 	return;
46013642Ssam }
46113642Ssam 
462*17834Sralph #define MR 100
46313642Ssam 
46413642Ssam /***
46513642Ssam  *	expect(str, fn)	look for expected string
46613642Ssam  *	char *str;
46713642Ssam  *
46813642Ssam  *	return codes:
46913642Ssam  *		0  -  found
47013642Ssam  *		FAIL  -  lost line or too many characters read
47113642Ssam  *		some character  -  timed out
47213642Ssam  */
47313642Ssam 
47413642Ssam expect(str, fn)
47513642Ssam register char *str;
47613642Ssam int fn;
47713642Ssam {
47814592Skarels 	char rdvec[MR];
479*17834Sralph 	register char *rp = rdvec, *strptr;
480*17834Sralph 	int kr, cnt_char;
48113642Ssam 	char nextch;
48213642Ssam 
483*17834Sralph 	if (*str == '\0' || strcmp(str, "\"\"") == SAME)
484*17834Sralph 		return SUCCESS;
485*17834Sralph 	/* Cleanup str, convert \0xx strings to one char  */
486*17834Sralph 	for (strptr = str; *strptr; strptr++) {
487*17834Sralph 		if (*strptr == '\\')
488*17834Sralph 			switch(*++strptr) {
489*17834Sralph 			case 's':
490*17834Sralph 				DEBUG(5, "BLANK\n", CNULL);
491*17834Sralph 				*strptr = ' ';
492*17834Sralph 				break;
493*17834Sralph 			default:
494*17834Sralph 				strptr--;  /* back up to backslash */
495*17834Sralph 				sscanf(strptr + 1,"%o", &cnt_char);
496*17834Sralph 				DEBUG(6, "BACKSLASHED %02xH\n", cnt_char);
497*17834Sralph 				*strptr = (char) (cnt_char);
498*17834Sralph 				strcpy(&strptr[1], &strptr[4]);
499*17834Sralph 			}
500*17834Sralph 	}
501*17834Sralph 
50213642Ssam 	*rp = 0;
503*17834Sralph 	if (setjmp(Sjbuf))
504*17834Sralph 		return FAIL;
50513642Ssam 	signal(SIGALRM, alarmtr);
50613642Ssam 	alarm(MAXMSGTIME);
50713642Ssam 	while (notin(str, rdvec)) {
508*17834Sralph 		if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
509*17834Sralph 			DEBUG(1, "Call aborted on '%s'\n", AbortOn);
510*17834Sralph 			alarm(0);
511*17834Sralph 			return ABORT;
512*17834Sralph 		}
51313642Ssam 		kr = read(fn, &nextch, 1);
51413642Ssam 		if (kr <= 0) {
51513642Ssam 			alarm(0);
51613642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
51713642Ssam 			logent("LOGIN", "LOST LINE");
518*17834Sralph 			return FAIL;
51913642Ssam 		}
52013642Ssam 		{
52113642Ssam 		int c;
52213642Ssam 		c = nextch & 0177;
52313642Ssam 		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
524*17834Sralph 		if (c == '\n')
525*17834Sralph 			DEBUG(4,"\n", CNULL);
52613642Ssam 		}
52713642Ssam 		if ((*rp = nextch & 0177) != '\0')
52813642Ssam 			rp++;
52913642Ssam 		if (rp >= rdvec + MR) {
530*17834Sralph 			register char *p;
531*17834Sralph 			for (p = rdvec+MR/2; p < rp; p++)
532*17834Sralph 				*(p-MR/2) = *p;
533*17834Sralph 			rp -= MR/2;
53413642Ssam 		}
53513642Ssam 		*rp = '\0';
53613642Ssam 	}
53713642Ssam 	alarm(0);
538*17834Sralph 	return SUCCESS;
53913642Ssam }
54013642Ssam 
54113642Ssam 
54213642Ssam /*
54313642Ssam  * Determine next file descriptor that would be allocated.
54413642Ssam  * This permits later closing of a file whose open was interrupted.
54513642Ssam  * It is a UNIX kernel problem, but it has to be handled.
54613642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
54713642Ssam  */
54813642Ssam getnextfd()
54913642Ssam {
55013642Ssam 	close(next_fd = open("/", 0));
55113642Ssam }
55213642Ssam 
553*17834Sralph /*
554*17834Sralph  *	send line of login sequence
55513642Ssam  *
55613642Ssam  *	return codes:  none
55713642Ssam  */
55813642Ssam sendthem(str, fn)
55913642Ssam register char *str;
56013642Ssam int fn;
56113642Ssam {
56213642Ssam 	register char *strptr;
56313642Ssam 	int i, n, cr = 1;
564*17834Sralph 	register char c;
56513642Ssam 	static int p_init = 0;
56613642Ssam 
56713642Ssam 	DEBUG(5, "send %s\n", str);
56813642Ssam 
56913642Ssam 	if (!p_init) {
57013642Ssam 		p_init++;
57113642Ssam 		bld_partab(P_EVEN);
57213642Ssam 	}
57313642Ssam 
57413642Ssam 	if (prefix("BREAK", str)) {
57513642Ssam 		sscanf(&str[5], "%1d", &i);
57613642Ssam 		if (i <= 0 || i > 10)
57713642Ssam 			i = 3;
57813642Ssam 		/* send break */
57913642Ssam 		genbrk(fn, i);
58013642Ssam 		return;
58113642Ssam 	}
58213642Ssam 
58313642Ssam 	if (prefix("PAUSE", str)) {
58413642Ssam 		sscanf(&str[5], "%1d", &i);
58513642Ssam 		if (i <= 0 || i > 10)
58613642Ssam 			i = 3;
58713642Ssam 		/* pause for a while */
58813642Ssam 		sleep((unsigned)i);
58913642Ssam 		return;
59013642Ssam 	}
59113642Ssam 
59213642Ssam 	if (strcmp(str, "EOT") == SAME) {
59313642Ssam 		p_chwrite(fn, '\04');
59413642Ssam 		return;
59513642Ssam 	}
59613642Ssam 
59713642Ssam 	/* Send a '\n' */
59813642Ssam 	if (strcmp(str, "LF") == SAME)
59913642Ssam 		str = "\\n\\c";
60013642Ssam 
60113642Ssam 	/* Send a '\r' */
60213642Ssam 	if (strcmp(str, "CR") == SAME)
60313642Ssam 		str = "\\r\\c";
60413642Ssam 
60513642Ssam 	/* Set parity as needed */
60613642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
60713642Ssam 		bld_partab(P_ZERO);
60813642Ssam 		return;
60913642Ssam 	}
61013642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
61113642Ssam 		bld_partab(P_ONE);
61213642Ssam 		return;
61313642Ssam 	}
61413642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
61513642Ssam 		bld_partab(P_EVEN);
61613642Ssam 		return;
61713642Ssam 	}
61813642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
61913642Ssam 		bld_partab(P_ODD);
62013642Ssam 		return;
62113642Ssam 	}
62213642Ssam 
62313642Ssam 	/* If "", just send '\r' */
624*17834Sralph 	if (strcmp(str, "\"\"") == SAME) {
625*17834Sralph 		p_chwrite(fn, '\r');
626*17834Sralph 		return;
627*17834Sralph 	}
628*17834Sralph 
629*17834Sralph 	for (strptr = str; c = *strptr++;) {
630*17834Sralph 		if (c == '\\') {
631*17834Sralph 			switch(*strptr++) {
632*17834Sralph 			case 's':
633*17834Sralph 				DEBUG(5, "BLANK\n", CNULL);
634*17834Sralph 				p_chwrite(fn, ' ');
635*17834Sralph 				break;
636*17834Sralph 			case 'd':
637*17834Sralph 				DEBUG(5, "DELAY\n", CNULL);
638*17834Sralph 				sleep(1);
639*17834Sralph 				continue;
640*17834Sralph 			case 'r':
641*17834Sralph 				DEBUG(5, "RETURN\n", CNULL);
642*17834Sralph 				p_chwrite(fn, '\r');
643*17834Sralph 				break;
644*17834Sralph 			case 'b':
645*17834Sralph 				if (isdigit(*strptr)) {
646*17834Sralph 					i = (*strptr++ - '0');
647*17834Sralph 					if (i <= 0 || i > 10)
648*17834Sralph 						i = 3;
649*17834Sralph 				} else
65013642Ssam 					i = 3;
651*17834Sralph 				/* send break */
652*17834Sralph 				genbrk(fn, i);
653*17834Sralph 				if (*strptr == '\0')
654*17834Sralph 					cr = 0;
65513642Ssam 				continue;
656*17834Sralph 			case 'c':
657*17834Sralph 				if (*strptr == '\0') {
658*17834Sralph 					DEBUG(5, "NO CR\n", CNULL);
659*17834Sralph 					cr = 0;
660*17834Sralph 					continue;
661*17834Sralph 				}
662*17834Sralph 				DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL);
66313642Ssam 				continue;
664*17834Sralph 			default:
665*17834Sralph 				if (isdigit(*strptr)) {
666*17834Sralph 					i = 0;
667*17834Sralph 					n = 0;
668*17834Sralph 					while (isdigit(*strptr) && ++n <= 3)
669*17834Sralph 						i = i*8 + (*strptr++ - '0');
670*17834Sralph 					p_chwrite(fn, (char)i);
671*17834Sralph 					continue;
672*17834Sralph 				}
673*17834Sralph 				DEBUG(5, "BACKSLASH\n", CNULL);
674*17834Sralph 				--strptr;
67513642Ssam 			}
676*17834Sralph 		} else
677*17834Sralph 			p_chwrite(fn, c);
67813642Ssam 	}
67913642Ssam 
68013642Ssam 	if (cr)
68113642Ssam 		p_chwrite(fn, '\r');
68213642Ssam 	return;
68313642Ssam }
68413642Ssam 
68513642Ssam p_chwrite(fd, c)
68613642Ssam int fd;
687*17834Sralph char c;
68813642Ssam {
689*17834Sralph 	c = par_tab[c&0177];
690*17834Sralph 	if (write(fd, &c, 1) != 1) {
691*17834Sralph 		logent(sys_errlist[errno], "BAD WRITE");
692*17834Sralph 		longjmp(Cjbuf, 2);
693*17834Sralph 	}
69413642Ssam }
69513642Ssam 
69613642Ssam /*
69713642Ssam  * generate parity table for use by p_chwrite.
69813642Ssam  */
69913642Ssam bld_partab(type)
70013642Ssam int type;
70113642Ssam {
70213642Ssam 	register int i, j, n;
70313642Ssam 
70413642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
70513642Ssam 		n = 0;
70613642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
70713642Ssam 			n++;
70813642Ssam 		par_tab[i] = i;
70913642Ssam 		if (type == P_ONE
71013642Ssam 		 || (type == P_EVEN && (n&01) != 0)
71113642Ssam 		 || (type == P_ODD && (n&01) == 0))
71213642Ssam 			par_tab[i] |= sizeof(par_tab);
71313642Ssam 	}
71413642Ssam }
71513642Ssam 
71613642Ssam #define BSPEED B150
71713642Ssam 
71813642Ssam /***
71913642Ssam  *	genbrk		send a break
72013642Ssam  *
72113642Ssam  *	return codes;  none
72213642Ssam  */
72313642Ssam 
72413642Ssam genbrk(fn, bnulls)
72513642Ssam register int fn, bnulls;
72613642Ssam {
72713642Ssam 	register int ret;
728*17834Sralph #ifdef	USG
72913642Ssam 	ret = ioctl(fn, TCSBRK, STBNULL);
73013642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
731*17834Sralph #else	!USG
73213642Ssam #ifdef	TIOCSBRK
73313642Ssam 	ret = ioctl(fn, TIOCSBRK, STBNULL);
73413642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
73513642Ssam #ifdef	TIOCCBRK
73613642Ssam 	sleep(1);
73713642Ssam 	ret = ioctl(fn, TIOCCBRK, STBNULL);
73813642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
739*17834Sralph #endif TIOCCBRK
740*17834Sralph 	DEBUG(4, "ioctl %d second break\n", bnulls );
741*17834Sralph #else !TIOCSBRK
74213642Ssam 	struct sgttyb ttbuf;
74313642Ssam 	register int sospeed;
74413642Ssam 
74513642Ssam 	ret = ioctl(fn, TIOCGETP, &ttbuf);
74613642Ssam 	sospeed = ttbuf.sg_ospeed;
74713642Ssam 	ttbuf.sg_ospeed = BSPEED;
74813642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
74913642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
750*17834Sralph 	if (ret != bnulls) {
751*17834Sralph badbreak:
752*17834Sralph 		logent(sys_errlist[errno], "BAD WRITE genbrk");
753*17834Sralph 		alarm(0);
754*17834Sralph 		longjmp(Sjbuf, 3);
755*17834Sralph 	}
75613642Ssam 	ttbuf.sg_ospeed = sospeed;
75713642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
75813642Ssam 	ret = write(fn, "@", 1);
759*17834Sralph 	if (ret != 1)
760*17834Sralph 		goto badbreak;
76113642Ssam 	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
762*17834Sralph #endif !TIOCSBRK
763*17834Sralph #endif !USG
76413642Ssam }
76513642Ssam 
76613642Ssam /***
76713642Ssam  *	notin(sh, lg)	check for occurrence of substring "sh"
76813642Ssam  *	char *sh, *lg;
76913642Ssam  *
77013642Ssam  *	return codes:
77113642Ssam  *		0  -  found the string
77213642Ssam  *		1  -  not in the string
77313642Ssam  */
77413642Ssam notin(sh, lg)
77513642Ssam register char *sh, *lg;
77613642Ssam {
77713642Ssam 	while (*lg != '\0') {
77813642Ssam 		if (wprefix(sh, lg))
77913642Ssam 			return(0);
78013642Ssam 		else
78113642Ssam 			lg++;
78213642Ssam 	}
78313642Ssam 	return(1);
78413642Ssam }
78513642Ssam 
78613642Ssam /*******
78713642Ssam  *	ifdate(s)
78813642Ssam  *	char *s;
78913642Ssam  *
79013642Ssam  *	ittvax!swatt
79113642Ssam  *	Allow multiple date specifications separated by '|'.
79213642Ssam  *	Calls ifadate, formerly "ifdate".
79313642Ssam  *
79413642Ssam  *	return codes:
79513642Ssam  *		see ifadate
79613642Ssam  */
79713642Ssam 
79813642Ssam ifdate(s)
79913642Ssam char *s;
80013642Ssam {
80113642Ssam 	register char *p;
80213642Ssam 	register int ret;
80313642Ssam 
80413642Ssam 	for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|'))
80513642Ssam 		if (ret = ifadate(p))
806*17834Sralph 			return ret;
807*17834Sralph 	return 0;
80813642Ssam }
80913642Ssam 
81013642Ssam /*******
81113642Ssam  *	ifadate(s)
81213642Ssam  *	char *s;
81313642Ssam  *
81413642Ssam  *	ifadate  -  this routine will check a string (s)
81513642Ssam  *	like "MoTu0800-1730" to see if the present
81613642Ssam  *	time is within the given limits.
81713642Ssam  *	SIDE EFFECT - Retrytime is set
81813642Ssam  *
81913642Ssam  *	String alternatives:
82013642Ssam  *		Wk - Mo thru Fr
82113642Ssam  *		zero or one time means all day
82213642Ssam  *		Any - any day
82313642Ssam  *
82413642Ssam  *	return codes:
82513642Ssam  *		0  -  not within limits
82613642Ssam  *		1  -  within limits
82713642Ssam  */
82813642Ssam 
82913642Ssam ifadate(s)
83013642Ssam char *s;
83113642Ssam {
83213642Ssam 	static char *days[]={
83313642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
83413642Ssam 	};
83513642Ssam 	time_t clock;
83613642Ssam 	int rtime;
837*17834Sralph 	int i, tl, th, tn, dayok=0;
83813642Ssam 	struct tm *localtime();
83913642Ssam 	struct tm *tp;
84013642Ssam 	char *index();
84113642Ssam 	char *p;
84213642Ssam 
84313642Ssam 	/*  pick up retry time for failures  */
84413642Ssam 	/*  global variable Retrytime is set here  */
84513642Ssam 	if ((p = index(s, ',')) == NULL) {
84613642Ssam 		Retrytime = RETRYTIME;
847*17834Sralph 	} else {
84813642Ssam 		i = sscanf(p+1, "%d", &rtime);
849*17834Sralph 		if (i < 1 || rtime < 0)
85013642Ssam 			rtime = 5;
85113642Ssam 		Retrytime  = rtime * 60;
85213642Ssam 	}
85313642Ssam 
85413642Ssam 	time(&clock);
85513642Ssam 	tp = localtime(&clock);
856*17834Sralph 	while (isascii(*s) && isalpha(*s)) {
85713642Ssam 		for (i = 0; days[i]; i++) {
85813642Ssam 			if (prefix(days[i], s))
85913642Ssam 				if (tp->tm_wday == i)
86013642Ssam 					dayok = 1;
86113642Ssam 		}
86213642Ssam 
86313642Ssam 		if (prefix("Wk", s))
86413642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
86513642Ssam 				dayok = 1;
86613642Ssam 		if (prefix("Any", s))
86713642Ssam 			dayok = 1;
868*17834Sralph 		if (prefix("Evening", s)) {
869*17834Sralph 			/* Sat or Sun */
870*17834Sralph 			if (tp->tm_wday == 6 || tp->tm_wday == 0
871*17834Sralph 				|| tp->tm_hour >= 17 || tp->tm_hour < 8)
872*17834Sralph 					dayok = 1;
873*17834Sralph 		}
874*17834Sralph 		if (prefix("Night", s)) {
875*17834Sralph 			if (tp->tm_wday == 6  /* Sat */
876*17834Sralph 				|| tp->tm_hour > 23 || tp->tm_hour < 8)
877*17834Sralph 					dayok = 1;
878*17834Sralph 		}
87913642Ssam 		s++;
88013642Ssam 	}
88113642Ssam 
88213642Ssam 	if (dayok == 0)
88313642Ssam 		return(0);
88413642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
88513642Ssam 	if (i < 2)
88613642Ssam 		return(1);
887*17834Sralph 	tn = tp->tm_hour * 100 + tp->tm_min;
888*17834Sralph 	if (th < tl) {		/* crosses midnight */
889*17834Sralph 		if (tl <= tn || tn < th)
890*17834Sralph 			return(1);
891*17834Sralph 	} else
892*17834Sralph 		if (tl <= tn && tn < th)
893*17834Sralph 			return(1);
894*17834Sralph 	return(0);
89513642Ssam }
89613642Ssam 
89713642Ssam 
89813642Ssam /***
89913642Ssam  *	char *
90013642Ssam  *	lastc(s)	return pointer to last character
90113642Ssam  *	char *s;
90213642Ssam  *
90313642Ssam  */
90413642Ssam char *
90513642Ssam lastc(s)
90613642Ssam register char *s;
90713642Ssam {
908*17834Sralph 	while (*s != '\0')
909*17834Sralph 		s++;
910*17834Sralph 	return s;
91113642Ssam }
91213642Ssam 
91313642Ssam /***
91413642Ssam  *	char *
91513642Ssam  *	fdig(cp)	find first digit in string
91613642Ssam  *
91713642Ssam  *	return - pointer to first digit in string or end of string
91813642Ssam  */
91913642Ssam char *
92013642Ssam fdig(cp)
92113642Ssam register char *cp;
92213642Ssam {
92313642Ssam 	register char *c;
92413642Ssam 
92513642Ssam 	for (c = cp; *c; c++)
92613642Ssam 		if (*c >= '0' && *c <= '9')
92713642Ssam 			break;
928*17834Sralph 	return c;
92913642Ssam }
93013642Ssam 
93113642Ssam /*
93213642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
93313642Ssam  * Strings are compared as if they contain all capital letters.
93413642Ssam  */
93513642Ssam snccmp(s1, s2)
93613642Ssam register char *s1, *s2;
93713642Ssam {
93813642Ssam 	char c1, c2;
93913642Ssam 
94013642Ssam 	if (islower(*s1)) c1 = toupper(*s1);
94113642Ssam 	else c1 = *s1;
94213642Ssam 	if (islower(*s2)) c2 = toupper(*s2);
94313642Ssam 	else c2 = *s2;
94413642Ssam 
94513642Ssam 	while (c1 == c2) {
94613642Ssam 		if (*s1++=='\0')
947*17834Sralph 			return 0;
94813642Ssam 		s2++;
94913642Ssam 		if (islower(*s1)) c1 = toupper(*s1);
95013642Ssam 		else c1 = *s1;
95113642Ssam 		if (islower(*s2)) c2 = toupper(*s2);
95213642Ssam 		else c2 = *s2;
95313642Ssam 	}
954*17834Sralph 	return c1 - c2;
95513642Ssam }
956*17834Sralph /*
957*17834Sralph  * do chat script
958*17834Sralph  * occurs after local port is opened,
959*17834Sralph  * before 'dialing' the other machine.
960*17834Sralph  */
961*17834Sralph dochat(dev, flds, fd)
962*17834Sralph register struct Devices *dev;
963*17834Sralph char *flds[];
964*17834Sralph int fd;
965*17834Sralph {
966*17834Sralph 	register int i;
967*17834Sralph 	register char *p;
968*17834Sralph 	char bfr[sizeof(dev->D_argbfr)];
969*17834Sralph 
970*17834Sralph 	if (dev->D_numargs <= 5)
971*17834Sralph 		return(0);
972*17834Sralph 	DEBUG(4, "dochat called %d\n", dev->D_numargs);
973*17834Sralph 	for (i = 0; i < dev->D_numargs-5; i++) {
974*17834Sralph 		sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]);
975*17834Sralph 		if (strcmp(bfr, dev->D_arg[D_CHAT+i])) {
976*17834Sralph 			p = malloc((unsigned)strlen(bfr)+1);
977*17834Sralph 			if (p != NULL) {
978*17834Sralph 				strcpy(p, bfr);
979*17834Sralph 				dev->D_arg[D_CHAT+i] = p;
980*17834Sralph 			}
981*17834Sralph 		}
982*17834Sralph 	}
983*17834Sralph 	/* following is a kludge because login() arglist is a kludge */
984*17834Sralph 	i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd);
985*17834Sralph 	/*
986*17834Sralph 	 * If login() last did a sendthem(), must pause so things can settle.
987*17834Sralph 	 * But don't bother if chat failed.
988*17834Sralph 	 */
989*17834Sralph 	if (i == 0 && (dev->D_numargs&01))
990*17834Sralph 		sleep(2);
991*17834Sralph 	return(i);
992*17834Sralph }
993