xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 18619)
113642Ssam #ifndef lint
2*18619Sralph static char sccsid[] = "@(#)conn.c	5.5 (Berkeley) 04/10/85";
313642Ssam #endif
413642Ssam 
513642Ssam #include "uucp.h"
613642Ssam #include <signal.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;
27*18619Sralph extern int errno, onesys;
2817834Sralph extern char *sys_errlist[];
29*18619Sralph 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 */
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 
58*18619Sralph /*
59*18619Sralph  *	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;
80*18619Sralph 	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);
9017834Sralph 	while((nf = finds(fsys, system, info, Flds)) > 0) {
9117834Sralph 		if (LocalOnly) {
9217834Sralph 			if (strcmp("TCP", Flds[F_LINE])
9317834Sralph 				&& strcmp("DIR", Flds[F_LINE])
9417834Sralph 				&& strcmp("LOCAL", Flds[F_LINE]) )
9517834Sralph 					fn = CF_TIME;
9617834Sralph 		}
97*18619Sralph 		sprintf(wkpre, "%c.%.7s", CMDPRE, Rmtname);
98*18619Sralph 		if (!onesys && MaxGrade != DefMaxGrade &&
99*18619Sralph 			!iswrk(file, "chk", Spool, wkpre))
100*18619Sralph 				fn = CF_TIME;
10117834Sralph 		if (fn != CF_TIME && (fn = getto(Flds)) > 0) {
10213642Ssam 			Dcf = fn;
10313642Ssam 			break;
10413642Ssam 		}
10513642Ssam 		fcode = (fn == FAIL ? CF_DIAL : fn);
10613642Ssam 	}
10713642Ssam 	fclose(fsys);
10813642Ssam 
10913642Ssam 	if (nf <= 0)
11017834Sralph 		return fcode ? fcode : nf;
11113642Ssam 
11213642Ssam 	DEBUG(4, "login %s\n", "called");
11317834Sralph 	ret = login(nf, Flds, fn);
11417834Sralph 	if (ret == FAIL) {
11513642Ssam 		clsacu();
11617834Sralph 		return CF_LOGIN;
11713642Ssam 	}
11813642Ssam 	/* rti!trt:  avoid passing file to children */
11913642Ssam 	fioclex(fn);
12017834Sralph 	return fn;
12113642Ssam }
12213642Ssam 
12313642Ssam /***
12413642Ssam  *	getto(flds)		connect to remote machine
12513642Ssam  *	char *flds[];
12613642Ssam  *
12713642Ssam  *	return codes:
12813642Ssam  *		>0  -  file number - ok
12913642Ssam  *		FAIL  -  failed
13013642Ssam  */
13113642Ssam 
13213642Ssam getto(flds)
13313642Ssam register char *flds[];
13413642Ssam {
13513642Ssam 	register struct condev *cd;
13613642Ssam 	int nulldev(), diropn();
13713642Ssam 
13817834Sralph 	DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
13913642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
14013642Ssam 
14113642Ssam 	CU_end = nulldev;
14213642Ssam 	for (cd = condevs; cd->CU_meth != NULL; cd++) {
14313642Ssam 		if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) {
14413642Ssam 			DEBUG(4, "Using %s to call\n", cd->CU_meth);
14517834Sralph 			return (*(cd->CU_gen))(flds);
14613642Ssam 		}
14713642Ssam 	}
14817834Sralph 	DEBUG(1, "Can't find %s, assuming DIR", flds[F_LINE]);
14917834Sralph 	return diropn(flds);	/* search failed, so use direct */
15017834Sralph }
15113642Ssam 
15213642Ssam /***
15313642Ssam  *	clsacu()	close call unit
15413642Ssam  *
15513642Ssam  *	return codes:  none
15613642Ssam  */
15713642Ssam 
15813642Ssam int (*CU_end)() = nulldev;
15913642Ssam clsacu()
16013642Ssam {
16117834Sralph 	/* make *sure* Dcf is no longer exclusive.
16217834Sralph 	 * Otherwise dual call-in/call-out modems could get stuck.
16317834Sralph 	 * Unfortunately, doing this here is not ideal, but it is the
16417834Sralph 	 * easiest place to put the call.
16517834Sralph 	 * Hopefully everyone honors the LCK protocol, of course
16617834Sralph 	 */
16717834Sralph #ifndef	USG
16817834Sralph 	ioctl(Dcf, TIOCNXCL, STBNULL);
16917834Sralph #endif
17017834Sralph 	if  (setjmp(Sjbuf))
17117834Sralph 		logent(Rmtname, "CLOSE TIMEOUT");
17217834Sralph 	else {
17317834Sralph 		signal(SIGALRM, alarmtr);
17417834Sralph 		alarm(20);
17517834Sralph 		(*(CU_end))(Dcf);
17617834Sralph 		alarm(0);
17717834Sralph 	}
17813642Ssam 	if (close(Dcf) == 0) {
17913642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
18013642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
18113642Ssam 	}
18213642Ssam 	Dcf = -1;
18313642Ssam 	CU_end = nulldev;
18413642Ssam }
18513642Ssam 
18613642Ssam /***
18713642Ssam  *	exphone - expand phone number for given prefix and number
18813642Ssam  *
18913642Ssam  *	return code - none
19013642Ssam  */
19113642Ssam 
19213642Ssam exphone(in, out)
19313642Ssam register char *in, *out;
19413642Ssam {
19513642Ssam 	FILE *fn;
19613642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
19713642Ssam 	char buf[BUFSIZ];
19813642Ssam 	register char *s1;
19913642Ssam 
20017834Sralph 	if (!isascii(*in) || !isalpha(*in)) {
20113642Ssam 		strcpy(out, in);
20213642Ssam 		return;
20313642Ssam 	}
20413642Ssam 
20513642Ssam 	s1=pre;
20617834Sralph 	while (isascii(*in) && isalpha(*in))
20713642Ssam 		*s1++ = *in++;
20813642Ssam 	*s1 = '\0';
20913642Ssam 	s1 = npart;
21013642Ssam 	while (*in != '\0')
21113642Ssam 		*s1++ = *in++;
21213642Ssam 	*s1 = '\0';
21313642Ssam 
21413642Ssam 	tpre[0] = '\0';
21513642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
21613642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
21713642Ssam 	else {
21813642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
21917834Sralph 			if (sscanf(buf, "%s%s", p, tpre) != 2)
22017834Sralph 				continue;
22113642Ssam 			if (strcmp(p, pre) == SAME)
22213642Ssam 				goto found;
22313642Ssam 			tpre[0] = '\0';
22413642Ssam 		}
22513642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
22613642Ssam 	found:;
22713642Ssam 		fclose(fn);
22813642Ssam 	}
22913642Ssam 
23013642Ssam 	strcpy(out, tpre);
23113642Ssam 	strcat(out, npart);
23213642Ssam }
23313642Ssam 
234*18619Sralph /*
235*18619Sralph  *	read and decode a line from device file
23613642Ssam  *
23713642Ssam  *	return code - FAIL at end-of file; 0 otherwise
23813642Ssam  */
23913642Ssam 
24013642Ssam rddev(fp, dev)
24113642Ssam register struct Devices *dev;
24213642Ssam FILE *fp;
24313642Ssam {
24417834Sralph 	register int na;
24513642Ssam 
24617834Sralph 	if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp))
24717834Sralph 		return FAIL;
24817834Sralph 	na = getargs(dev->D_argbfr, dev->D_arg, 20);
24917834Sralph 	ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0);
25017834Sralph 	if (na == 4) {
25117834Sralph 		dev->D_brand = "";
25217834Sralph 		na++;
25317834Sralph 	}
25413642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
25517834Sralph 	dev->D_numargs = na;
25617834Sralph 	return 0;
25713642Ssam }
25813642Ssam 
259*18619Sralph /*
260*18619Sralph  *	set system attribute vector
26113642Ssam  *
26213642Ssam  *	return codes:
26313642Ssam  *		>0  -  number of arguments in vector - succeeded
26413642Ssam  *		CF_SYSTEM  -  system name not found
26513642Ssam  *		CF_TIME  -  wrong time to call
26613642Ssam  */
26713642Ssam 
26813642Ssam finds(fsys, sysnam, info, flds)
26913642Ssam char *sysnam, info[], *flds[];
27013642Ssam FILE *fsys;
27113642Ssam {
27213642Ssam 	int na;
27313642Ssam 	int fcode = 0;
27413642Ssam 
27513642Ssam 	/* format of fields
27613642Ssam 	 *	0 name;
27713642Ssam 	 *	1 time
27813642Ssam 	 *	2 acu/hardwired
27913642Ssam 	 *	3 speed
28013642Ssam 	 *	etc
28113642Ssam 	 */
28213642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
28317834Sralph 		na = getargs(info, flds, MAXC/10);
284*18619Sralph 		if (strncmp(sysnam, flds[F_NAME], 7) != SAME)
28513642Ssam 			continue;
286*18619Sralph 		if (ifdate(flds[F_TIME]) != FAIL)
28713642Ssam 			/*  found a good entry  */
28817834Sralph 			return na;
28913642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
29013642Ssam 		fcode = CF_TIME;
29113642Ssam 	}
29217834Sralph 	return fcode ? fcode : CF_SYSTEM;
29313642Ssam }
29413642Ssam 
295*18619Sralph /*
296*18619Sralph  *	do login conversation
29713642Ssam  *
29813642Ssam  *	return codes:  0  |  FAIL
29913642Ssam  */
30013642Ssam 
30113642Ssam login(nf, flds, fn)
30213642Ssam register char *flds[];
30313642Ssam int nf, fn;
30413642Ssam {
30513642Ssam 	register char *want, *altern;
30613642Ssam 	extern char *index();
30713642Ssam 	int k, ok;
30813642Ssam 
30917834Sralph 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf);
31017834Sralph 	if (setjmp(Cjbuf))
31117834Sralph 		return FAIL;
31217834Sralph 	AbortOn = NULL;
31313642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
31413642Ssam 		want = flds[k];
31513642Ssam 		ok = FAIL;
31617834Sralph 		while (ok != SUCCESS) {
31713642Ssam 			altern = index(want, '-');
31813642Ssam 			if (altern != NULL)
31913642Ssam 				*altern++ = '\0';
32017834Sralph 			if (strcmp(want, "ABORT") == 0) {
32117834Sralph 				AbortOn = flds[k+1];
32217834Sralph 				DEBUG(4, "ABORT ON: %s\n", AbortOn);
32317834Sralph 				goto nextfield;
32417834Sralph 			}
32517834Sralph 			DEBUG(4, "wanted: %s\n", want);
32613642Ssam 			ok = expect(want, fn);
32717834Sralph 			DEBUG(4, "got: %s\n", ok ? "?" : "that");
32817834Sralph 			if (ok == FAIL) {
32917834Sralph 				if (altern == NULL) {
33017834Sralph 					logent("LOGIN", _FAILED);
33117834Sralph 					return FAIL;
33217834Sralph 				}
33317834Sralph 				want = index(altern, '-');
33417834Sralph 				if (want != NULL)
33517834Sralph 					*want++ = '\0';
33617834Sralph 				sendthem(altern, fn);
33717834Sralph 			} else
33817834Sralph 				if (ok == ABORT) {
33917834Sralph 					logent("LOGIN ABORTED", _FAILED);
34017834Sralph 					return FAIL;
34117834Sralph 				}
34213642Ssam 		}
34317834Sralph 		sleep(1);
34413642Ssam 		if (k+1 < nf)
34513642Ssam 			sendthem(flds[k+1], fn);
34617834Sralph nextfield: ;
34713642Ssam 	}
34817834Sralph 	return SUCCESS;
34913642Ssam }
35013642Ssam 
35113642Ssam 
35217834Sralph /* conditional table generation to support odd speeds */
35313642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
35413642Ssam #ifdef B50
35513642Ssam 	{  50,	 B50},
35613642Ssam #endif
35713642Ssam #ifdef B75
35813642Ssam 	{  75,	 B75},
35913642Ssam #endif
36013642Ssam #ifdef B110
36113642Ssam 	{ 110,	B110},
36213642Ssam #endif
36313642Ssam #ifdef B150
36413642Ssam 	{ 150,	B150},
36513642Ssam #endif
36613642Ssam #ifdef B200
36713642Ssam 	{ 200,	B200},
36813642Ssam #endif
36913642Ssam #ifdef B300
37013642Ssam 	{ 300,  B300},
37113642Ssam #endif
37213642Ssam #ifdef B600
37313642Ssam 	{600,	B600},
37413642Ssam #endif
37513642Ssam #ifdef B1200
37613642Ssam 	{1200, B1200},
37713642Ssam #endif
37813642Ssam #ifdef B1800
37913642Ssam 	{1800, B1800},
38013642Ssam #endif
38113642Ssam #ifdef B2000
38213642Ssam 	{2000, B2000},
38313642Ssam #endif
38413642Ssam #ifdef B2400
38513642Ssam 	{2400, B2400},
38613642Ssam #endif
38713642Ssam #ifdef B3600
38813642Ssam 	{3600, B3600},
38913642Ssam #endif
39013642Ssam #ifdef B4800
39113642Ssam 	{4800, B4800},
39213642Ssam #endif
39313642Ssam #ifdef B7200
39413642Ssam 	{7200, B7200},
39513642Ssam #endif
39613642Ssam #ifdef B9600
39713642Ssam 	{9600, B9600},
39813642Ssam #endif
39913642Ssam #ifdef B19200
40017834Sralph 	{19200, B19200},
40113642Ssam #endif
40217834Sralph #ifdef EXTA
40317834Sralph 	{19200, EXTA},
40417834Sralph #endif
40513642Ssam 	{0, 0}
40613642Ssam };
40713642Ssam 
408*18619Sralph /*
409*18619Sralph  *	set speed/echo/mode...
41013642Ssam  *
41113642Ssam  *	return codes:  none
41213642Ssam  */
41313642Ssam 
41413642Ssam fixline(tty, spwant)
41513642Ssam int tty, spwant;
41613642Ssam {
41717834Sralph #ifdef	USG
41813642Ssam 	struct termio ttbuf;
41917834Sralph #else	!USG
42013642Ssam 	struct sgttyb ttbuf;
42117834Sralph #endif !USG
42213642Ssam 	register struct sg_spds *ps;
42313642Ssam 	int speed = -1;
42413642Ssam 	int ret;
42513642Ssam 
42613642Ssam 	for (ps = spds; ps->sp_val; ps++)
42713642Ssam 		if (ps->sp_val == spwant)
42813642Ssam 			speed = ps->sp_name;
42917834Sralph 	ASSERT(speed >= 0, "BAD SPEED", CNULL, speed);
43017834Sralph #ifdef	USG
43113642Ssam 	ioctl(tty, TCGETA, &ttbuf);
43213642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
43313642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
43413642Ssam 	ttbuf.c_iflag = (ushort)0;
43513642Ssam 	ttbuf.c_oflag = (ushort)0;
43613642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
43713642Ssam 	ttbuf.c_lflag = (ushort)0;
43813642Ssam 	ttbuf.c_cc[VMIN] = 6;
43913642Ssam 	ttbuf.c_cc[VTIME] = 1;
44013642Ssam 	ret = ioctl(tty, TCSETA, &ttbuf);
44117834Sralph #else	!USG
44213642Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
44313642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
44413642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
44513642Ssam 	ret = ioctl(tty, TIOCSETP, &ttbuf);
44613642Ssam #endif
44717834Sralph 	ASSERT(ret >= 0, "RETURN FROM STTY", CNULL, ret);
44817834Sralph #ifndef	USG
44913642Ssam 	ioctl(tty, TIOCHPCL, STBNULL);
45013642Ssam 	ioctl(tty, TIOCEXCL, STBNULL);
45113642Ssam #endif
45217834Sralph 	linebaudrate = spwant;
45313642Ssam 	return;
45413642Ssam }
45513642Ssam 
45617834Sralph #define MR 100
45713642Ssam 
458*18619Sralph /*
459*18619Sralph  *	look for expected string
46013642Ssam  *
46113642Ssam  *	return codes:
46213642Ssam  *		0  -  found
46313642Ssam  *		FAIL  -  lost line or too many characters read
46413642Ssam  *		some character  -  timed out
46513642Ssam  */
46613642Ssam 
46713642Ssam expect(str, fn)
46813642Ssam register char *str;
46913642Ssam int fn;
47013642Ssam {
47114592Skarels 	char rdvec[MR];
47217834Sralph 	register char *rp = rdvec, *strptr;
47317834Sralph 	int kr, cnt_char;
47413642Ssam 	char nextch;
47513642Ssam 
47617834Sralph 	if (*str == '\0' || strcmp(str, "\"\"") == SAME)
47717834Sralph 		return SUCCESS;
47817834Sralph 	/* Cleanup str, convert \0xx strings to one char  */
47917834Sralph 	for (strptr = str; *strptr; strptr++) {
48017834Sralph 		if (*strptr == '\\')
48117834Sralph 			switch(*++strptr) {
48217834Sralph 			case 's':
48317834Sralph 				DEBUG(5, "BLANK\n", CNULL);
48417834Sralph 				*strptr = ' ';
48517834Sralph 				break;
48617834Sralph 			default:
48717834Sralph 				strptr--;  /* back up to backslash */
48817834Sralph 				sscanf(strptr + 1,"%o", &cnt_char);
48917834Sralph 				DEBUG(6, "BACKSLASHED %02xH\n", cnt_char);
49017834Sralph 				*strptr = (char) (cnt_char);
49117834Sralph 				strcpy(&strptr[1], &strptr[4]);
49217834Sralph 			}
49317834Sralph 	}
49417834Sralph 
49513642Ssam 	*rp = 0;
49617834Sralph 	if (setjmp(Sjbuf))
49717834Sralph 		return FAIL;
49813642Ssam 	signal(SIGALRM, alarmtr);
49913642Ssam 	alarm(MAXMSGTIME);
50013642Ssam 	while (notin(str, rdvec)) {
50117834Sralph 		if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
50217834Sralph 			DEBUG(1, "Call aborted on '%s'\n", AbortOn);
50317834Sralph 			alarm(0);
50417834Sralph 			return ABORT;
50517834Sralph 		}
50613642Ssam 		kr = read(fn, &nextch, 1);
50713642Ssam 		if (kr <= 0) {
50813642Ssam 			alarm(0);
50913642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
51013642Ssam 			logent("LOGIN", "LOST LINE");
51117834Sralph 			return FAIL;
51213642Ssam 		}
51313642Ssam 		{
51413642Ssam 		int c;
51513642Ssam 		c = nextch & 0177;
51613642Ssam 		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
51717834Sralph 		if (c == '\n')
51817834Sralph 			DEBUG(4,"\n", CNULL);
51913642Ssam 		}
52013642Ssam 		if ((*rp = nextch & 0177) != '\0')
52113642Ssam 			rp++;
52213642Ssam 		if (rp >= rdvec + MR) {
52317834Sralph 			register char *p;
52417834Sralph 			for (p = rdvec+MR/2; p < rp; p++)
52517834Sralph 				*(p-MR/2) = *p;
52617834Sralph 			rp -= MR/2;
52713642Ssam 		}
52813642Ssam 		*rp = '\0';
52913642Ssam 	}
53013642Ssam 	alarm(0);
53117834Sralph 	return SUCCESS;
53213642Ssam }
53313642Ssam 
53413642Ssam 
53513642Ssam /*
53613642Ssam  * Determine next file descriptor that would be allocated.
53713642Ssam  * This permits later closing of a file whose open was interrupted.
53813642Ssam  * It is a UNIX kernel problem, but it has to be handled.
53913642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
54013642Ssam  */
54113642Ssam getnextfd()
54213642Ssam {
54313642Ssam 	close(next_fd = open("/", 0));
54413642Ssam }
54513642Ssam 
54617834Sralph /*
54717834Sralph  *	send line of login sequence
54813642Ssam  *
54913642Ssam  *	return codes:  none
55013642Ssam  */
55113642Ssam sendthem(str, fn)
55213642Ssam register char *str;
55313642Ssam int fn;
55413642Ssam {
55513642Ssam 	register char *strptr;
55613642Ssam 	int i, n, cr = 1;
55717834Sralph 	register char c;
55813642Ssam 	static int p_init = 0;
55913642Ssam 
56013642Ssam 	DEBUG(5, "send %s\n", str);
56113642Ssam 
56213642Ssam 	if (!p_init) {
56313642Ssam 		p_init++;
56413642Ssam 		bld_partab(P_EVEN);
56513642Ssam 	}
56613642Ssam 
56713642Ssam 	if (prefix("BREAK", str)) {
56813642Ssam 		sscanf(&str[5], "%1d", &i);
56913642Ssam 		if (i <= 0 || i > 10)
57013642Ssam 			i = 3;
57113642Ssam 		/* send break */
57213642Ssam 		genbrk(fn, i);
57313642Ssam 		return;
57413642Ssam 	}
57513642Ssam 
57613642Ssam 	if (prefix("PAUSE", str)) {
57713642Ssam 		sscanf(&str[5], "%1d", &i);
57813642Ssam 		if (i <= 0 || i > 10)
57913642Ssam 			i = 3;
58013642Ssam 		/* pause for a while */
58113642Ssam 		sleep((unsigned)i);
58213642Ssam 		return;
58313642Ssam 	}
58413642Ssam 
58513642Ssam 	if (strcmp(str, "EOT") == SAME) {
58613642Ssam 		p_chwrite(fn, '\04');
58713642Ssam 		return;
58813642Ssam 	}
58913642Ssam 
59013642Ssam 	/* Send a '\n' */
59113642Ssam 	if (strcmp(str, "LF") == SAME)
59213642Ssam 		str = "\\n\\c";
59313642Ssam 
59413642Ssam 	/* Send a '\r' */
59513642Ssam 	if (strcmp(str, "CR") == SAME)
59613642Ssam 		str = "\\r\\c";
59713642Ssam 
59813642Ssam 	/* Set parity as needed */
59913642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
60013642Ssam 		bld_partab(P_ZERO);
60113642Ssam 		return;
60213642Ssam 	}
60313642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
60413642Ssam 		bld_partab(P_ONE);
60513642Ssam 		return;
60613642Ssam 	}
60713642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
60813642Ssam 		bld_partab(P_EVEN);
60913642Ssam 		return;
61013642Ssam 	}
61113642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
61213642Ssam 		bld_partab(P_ODD);
61313642Ssam 		return;
61413642Ssam 	}
61513642Ssam 
61613642Ssam 	/* If "", just send '\r' */
61717834Sralph 	if (strcmp(str, "\"\"") == SAME) {
61817834Sralph 		p_chwrite(fn, '\r');
61917834Sralph 		return;
62017834Sralph 	}
62117834Sralph 
62217834Sralph 	for (strptr = str; c = *strptr++;) {
62317834Sralph 		if (c == '\\') {
62417834Sralph 			switch(*strptr++) {
62517834Sralph 			case 's':
62617834Sralph 				DEBUG(5, "BLANK\n", CNULL);
62717834Sralph 				p_chwrite(fn, ' ');
62817834Sralph 				break;
62917834Sralph 			case 'd':
63017834Sralph 				DEBUG(5, "DELAY\n", CNULL);
63117834Sralph 				sleep(1);
63217834Sralph 				continue;
63317834Sralph 			case 'r':
63417834Sralph 				DEBUG(5, "RETURN\n", CNULL);
63517834Sralph 				p_chwrite(fn, '\r');
63617834Sralph 				break;
63717834Sralph 			case 'b':
63817834Sralph 				if (isdigit(*strptr)) {
63917834Sralph 					i = (*strptr++ - '0');
64017834Sralph 					if (i <= 0 || i > 10)
64117834Sralph 						i = 3;
64217834Sralph 				} else
64313642Ssam 					i = 3;
64417834Sralph 				/* send break */
64517834Sralph 				genbrk(fn, i);
64617834Sralph 				if (*strptr == '\0')
64717834Sralph 					cr = 0;
64813642Ssam 				continue;
64917834Sralph 			case 'c':
65017834Sralph 				if (*strptr == '\0') {
65117834Sralph 					DEBUG(5, "NO CR\n", CNULL);
65217834Sralph 					cr = 0;
65317834Sralph 					continue;
65417834Sralph 				}
65517834Sralph 				DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL);
65613642Ssam 				continue;
65717834Sralph 			default:
65817834Sralph 				if (isdigit(*strptr)) {
65917834Sralph 					i = 0;
66017834Sralph 					n = 0;
66117834Sralph 					while (isdigit(*strptr) && ++n <= 3)
66217834Sralph 						i = i*8 + (*strptr++ - '0');
66317834Sralph 					p_chwrite(fn, (char)i);
66417834Sralph 					continue;
66517834Sralph 				}
66617834Sralph 				DEBUG(5, "BACKSLASH\n", CNULL);
66717834Sralph 				--strptr;
66813642Ssam 			}
66917834Sralph 		} else
67017834Sralph 			p_chwrite(fn, c);
67113642Ssam 	}
67213642Ssam 
67313642Ssam 	if (cr)
67413642Ssam 		p_chwrite(fn, '\r');
67513642Ssam 	return;
67613642Ssam }
67713642Ssam 
67813642Ssam p_chwrite(fd, c)
67913642Ssam int fd;
68017834Sralph char c;
68113642Ssam {
68217834Sralph 	c = par_tab[c&0177];
68317834Sralph 	if (write(fd, &c, 1) != 1) {
68417834Sralph 		logent(sys_errlist[errno], "BAD WRITE");
68517834Sralph 		longjmp(Cjbuf, 2);
68617834Sralph 	}
68713642Ssam }
68813642Ssam 
68913642Ssam /*
69013642Ssam  * generate parity table for use by p_chwrite.
69113642Ssam  */
69213642Ssam bld_partab(type)
69313642Ssam int type;
69413642Ssam {
69513642Ssam 	register int i, j, n;
69613642Ssam 
69713642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
69813642Ssam 		n = 0;
69913642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
70013642Ssam 			n++;
70113642Ssam 		par_tab[i] = i;
70213642Ssam 		if (type == P_ONE
70313642Ssam 		 || (type == P_EVEN && (n&01) != 0)
70413642Ssam 		 || (type == P_ODD && (n&01) == 0))
70513642Ssam 			par_tab[i] |= sizeof(par_tab);
70613642Ssam 	}
70713642Ssam }
70813642Ssam 
70913642Ssam #define BSPEED B150
71013642Ssam 
711*18619Sralph /*
712*18619Sralph  *	send a break
71313642Ssam  *
71413642Ssam  *	return codes;  none
71513642Ssam  */
71613642Ssam 
71713642Ssam genbrk(fn, bnulls)
71813642Ssam register int fn, bnulls;
71913642Ssam {
72013642Ssam 	register int ret;
72117834Sralph #ifdef	USG
72213642Ssam 	ret = ioctl(fn, TCSBRK, STBNULL);
72313642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
72417834Sralph #else	!USG
72513642Ssam #ifdef	TIOCSBRK
72613642Ssam 	ret = ioctl(fn, TIOCSBRK, STBNULL);
72713642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
72813642Ssam #ifdef	TIOCCBRK
72913642Ssam 	sleep(1);
73013642Ssam 	ret = ioctl(fn, TIOCCBRK, STBNULL);
73113642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
73217834Sralph #endif TIOCCBRK
73317834Sralph 	DEBUG(4, "ioctl %d second break\n", bnulls );
73417834Sralph #else !TIOCSBRK
73513642Ssam 	struct sgttyb ttbuf;
73613642Ssam 	register int sospeed;
73713642Ssam 
73813642Ssam 	ret = ioctl(fn, TIOCGETP, &ttbuf);
73913642Ssam 	sospeed = ttbuf.sg_ospeed;
74013642Ssam 	ttbuf.sg_ospeed = BSPEED;
74113642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
74213642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
74317834Sralph 	if (ret != bnulls) {
74417834Sralph badbreak:
74517834Sralph 		logent(sys_errlist[errno], "BAD WRITE genbrk");
74617834Sralph 		alarm(0);
74717834Sralph 		longjmp(Sjbuf, 3);
74817834Sralph 	}
74913642Ssam 	ttbuf.sg_ospeed = sospeed;
75013642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
75113642Ssam 	ret = write(fn, "@", 1);
75217834Sralph 	if (ret != 1)
75317834Sralph 		goto badbreak;
75413642Ssam 	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
75517834Sralph #endif !TIOCSBRK
75617834Sralph #endif !USG
75713642Ssam }
75813642Ssam 
759*18619Sralph /*
760*18619Sralph  *	check for occurrence of substring "sh"
76113642Ssam  *
76213642Ssam  *	return codes:
76313642Ssam  *		0  -  found the string
76413642Ssam  *		1  -  not in the string
76513642Ssam  */
76613642Ssam notin(sh, lg)
76713642Ssam register char *sh, *lg;
76813642Ssam {
76913642Ssam 	while (*lg != '\0') {
77013642Ssam 		if (wprefix(sh, lg))
771*18619Sralph 			return 0;
77213642Ssam 		else
77313642Ssam 			lg++;
77413642Ssam 	}
775*18619Sralph 	return 1;
77613642Ssam }
77713642Ssam 
778*18619Sralph /*
77913642Ssam  *	Allow multiple date specifications separated by '|'.
78013642Ssam  */
781*18619Sralph ifdate(p)
782*18619Sralph register char *p;
78313642Ssam {
784*18619Sralph 	register int ret, g;
78513642Ssam 
786*18619Sralph 	ret = FAIL;
787*18619Sralph 	MaxGrade = '\0';
788*18619Sralph 	do {
789*18619Sralph 		g = ifadate(p);
790*18619Sralph 		DEBUG(11,"ifadate returns %o\n", g);
791*18619Sralph 		if (g != FAIL) {
792*18619Sralph 			ret = SUCCESS;
793*18619Sralph 			if (g > MaxGrade)
794*18619Sralph 				MaxGrade = g;
795*18619Sralph 		}
796*18619Sralph 		p = index(p, '|');
797*18619Sralph 	} while (p++ && *p);
798*18619Sralph 	return ret;
79913642Ssam }
80013642Ssam 
801*18619Sralph /*
802*18619Sralph  *	this routine will check a string (string)
80313642Ssam  *	like "MoTu0800-1730" to see if the present
80413642Ssam  *	time is within the given limits.
80513642Ssam  *	SIDE EFFECT - Retrytime is set
80613642Ssam  *
80713642Ssam  *	return codes:
80813642Ssam  *		0  -  not within limits
80913642Ssam  *		1  -  within limits
81013642Ssam  */
81113642Ssam 
812*18619Sralph ifadate(string)
813*18619Sralph char *string;
81413642Ssam {
81513642Ssam 	static char *days[]={
81613642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
81713642Ssam 	};
81813642Ssam 	time_t clock;
819*18619Sralph 	register char *s = string;
82013642Ssam 	int rtime;
82117834Sralph 	int i, tl, th, tn, dayok=0;
82213642Ssam 	struct tm *localtime();
82313642Ssam 	struct tm *tp;
824*18619Sralph 	char *p, MGrade;
82513642Ssam 
82613642Ssam 	/*  pick up retry time for failures  */
82713642Ssam 	/*  global variable Retrytime is set here  */
82813642Ssam 	if ((p = index(s, ',')) == NULL) {
82913642Ssam 		Retrytime = RETRYTIME;
83017834Sralph 	} else {
83113642Ssam 		i = sscanf(p+1, "%d", &rtime);
83217834Sralph 		if (i < 1 || rtime < 0)
83313642Ssam 			rtime = 5;
83413642Ssam 		Retrytime  = rtime * 60;
83513642Ssam 	}
83613642Ssam 
837*18619Sralph 	if ((p = index(s, '@')) == NULL)
838*18619Sralph 		MGrade = DefMaxGrade;
839*18619Sralph 	else
840*18619Sralph 		MGrade = p[1];
841*18619Sralph 
84213642Ssam 	time(&clock);
84313642Ssam 	tp = localtime(&clock);
84417834Sralph 	while (isascii(*s) && isalpha(*s)) {
84513642Ssam 		for (i = 0; days[i]; i++) {
84613642Ssam 			if (prefix(days[i], s))
84713642Ssam 				if (tp->tm_wday == i)
84813642Ssam 					dayok = 1;
84913642Ssam 		}
85013642Ssam 
85113642Ssam 		if (prefix("Wk", s))
85213642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
85313642Ssam 				dayok = 1;
85413642Ssam 		if (prefix("Any", s))
85513642Ssam 			dayok = 1;
85617834Sralph 		if (prefix("Evening", s)) {
85717834Sralph 			/* Sat or Sun */
85817834Sralph 			if (tp->tm_wday == 6 || tp->tm_wday == 0
85917834Sralph 				|| tp->tm_hour >= 17 || tp->tm_hour < 8)
86017834Sralph 					dayok = 1;
86117834Sralph 		}
86217834Sralph 		if (prefix("Night", s)) {
86317834Sralph 			if (tp->tm_wday == 6  /* Sat */
864*18619Sralph 				|| tp->tm_hour >= 23 || tp->tm_hour < 8
865*18619Sralph 					/* Sunday before 5pm */
866*18619Sralph 				|| (tp->tm_wday == 0 && tp->tm_hour < 17))
86717834Sralph 					dayok = 1;
86817834Sralph 		}
86913642Ssam 		s++;
87013642Ssam 	}
87113642Ssam 
872*18619Sralph 	if (dayok == 0 && s != string)
873*18619Sralph 		return FAIL;
87413642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
875*18619Sralph   	if (i < 2)
876*18619Sralph   		return MGrade;
877*18619Sralph 	tn = tp->tm_hour * 100 + tp->tm_min;
878*18619Sralph   	if (th < tl) { 		/* crosses midnight */
879*18619Sralph   		if (tl <= tn || tn < th)
880*18619Sralph   			return MGrade;
881*18619Sralph   	} else
882*18619Sralph 
88313642Ssam 	if (i < 2)
884*18619Sralph 		return MGrade;
885*18619Sralph 	if (th < tl) { 	/* crosses midnight */
88617834Sralph 		if (tl <= tn || tn < th)
887*18619Sralph 			return MGrade;
88817834Sralph 	} else
88917834Sralph 		if (tl <= tn && tn < th)
890*18619Sralph 			return MGrade;
891*18619Sralph 	return FAIL;
89213642Ssam }
89313642Ssam 
894*18619Sralph /*
895*18619Sralph  *	find first digit in string
89613642Ssam  *
89713642Ssam  *	return - pointer to first digit in string or end of string
89813642Ssam  */
89913642Ssam char *
90013642Ssam fdig(cp)
90113642Ssam register char *cp;
90213642Ssam {
90313642Ssam 	register char *c;
90413642Ssam 
90513642Ssam 	for (c = cp; *c; c++)
90613642Ssam 		if (*c >= '0' && *c <= '9')
90713642Ssam 			break;
90817834Sralph 	return c;
90913642Ssam }
91013642Ssam 
91113642Ssam /*
91213642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
91313642Ssam  * Strings are compared as if they contain all capital letters.
91413642Ssam  */
91513642Ssam snccmp(s1, s2)
91613642Ssam register char *s1, *s2;
91713642Ssam {
91813642Ssam 	char c1, c2;
91913642Ssam 
92013642Ssam 	if (islower(*s1)) c1 = toupper(*s1);
92113642Ssam 	else c1 = *s1;
92213642Ssam 	if (islower(*s2)) c2 = toupper(*s2);
92313642Ssam 	else c2 = *s2;
92413642Ssam 
92513642Ssam 	while (c1 == c2) {
92613642Ssam 		if (*s1++=='\0')
92717834Sralph 			return 0;
92813642Ssam 		s2++;
92913642Ssam 		if (islower(*s1)) c1 = toupper(*s1);
93013642Ssam 		else c1 = *s1;
93113642Ssam 		if (islower(*s2)) c2 = toupper(*s2);
93213642Ssam 		else c2 = *s2;
93313642Ssam 	}
93417834Sralph 	return c1 - c2;
93513642Ssam }
93617834Sralph /*
93717834Sralph  * do chat script
93817834Sralph  * occurs after local port is opened,
93917834Sralph  * before 'dialing' the other machine.
94017834Sralph  */
94117834Sralph dochat(dev, flds, fd)
94217834Sralph register struct Devices *dev;
94317834Sralph char *flds[];
94417834Sralph int fd;
94517834Sralph {
94617834Sralph 	register int i;
94717834Sralph 	register char *p;
94817834Sralph 	char bfr[sizeof(dev->D_argbfr)];
94917834Sralph 
95017834Sralph 	if (dev->D_numargs <= 5)
95117834Sralph 		return(0);
95217834Sralph 	DEBUG(4, "dochat called %d\n", dev->D_numargs);
95317834Sralph 	for (i = 0; i < dev->D_numargs-5; i++) {
95417834Sralph 		sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]);
95517834Sralph 		if (strcmp(bfr, dev->D_arg[D_CHAT+i])) {
95617834Sralph 			p = malloc((unsigned)strlen(bfr)+1);
95717834Sralph 			if (p != NULL) {
95817834Sralph 				strcpy(p, bfr);
95917834Sralph 				dev->D_arg[D_CHAT+i] = p;
96017834Sralph 			}
96117834Sralph 		}
96217834Sralph 	}
96317834Sralph 	/* following is a kludge because login() arglist is a kludge */
96417834Sralph 	i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd);
96517834Sralph 	/*
96617834Sralph 	 * If login() last did a sendthem(), must pause so things can settle.
96717834Sralph 	 * But don't bother if chat failed.
96817834Sralph 	 */
96917834Sralph 	if (i == 0 && (dev->D_numargs&01))
97017834Sralph 		sleep(2);
97117834Sralph 	return(i);
97217834Sralph }
973