xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 13705)
113642Ssam #ifndef lint
2*13705Ssam static char sccsid[] = "@(#)conn.c	5.2 (Berkeley) 07/02/83";
313642Ssam #endif
413642Ssam 
513642Ssam #include "uucp.h"
613642Ssam #include <signal.h>
713642Ssam #include <setjmp.h>
813642Ssam #include <ctype.h>
913642Ssam #include <sys/types.h>
10*13705Ssam #include <sys/time.h>
1113642Ssam #include <errno.h>
1213642Ssam #ifdef	SYSIII
1313642Ssam #include <termio.h>
1413642Ssam #include <fcntl.h>
1513642Ssam #endif
1613642Ssam #ifndef	SYSIII
1713642Ssam #include <sgtty.h>
1813642Ssam #endif
1913642Ssam 
2013642Ssam #define MAXC 1000
2113642Ssam 
2213642Ssam extern jmp_buf Sjbuf;
2313642Ssam extern int errno;
2413642Ssam 
2513642Ssam /* Parity control during login procedure */
2613642Ssam #define	P_ZERO	0
2713642Ssam #define	P_ONE	1
2813642Ssam #define	P_EVEN	2
2913642Ssam #define	P_ODD	3
3013642Ssam char	par_tab[128];	/* must be power of two */
3113642Ssam 
3213642Ssam int next_fd = -1;	/* predicted fd to close interrupted opens */
3313642Ssam 				/* rti!trt, courtesy unc!smb */
3413642Ssam /***
3513642Ssam  *	alarmtr()  -  catch alarm routine for "expect".
3613642Ssam  */
3713642Ssam alarmtr()
3813642Ssam {
3913642Ssam 	signal(SIGALRM, alarmtr);
4013642Ssam 	if (next_fd >= 0) {
4113642Ssam 		if (close(next_fd))
4213642Ssam 			logent("FAIL", "ACU LINE CLOSE");
4313642Ssam 		next_fd = -1;
4413642Ssam 	}
4513642Ssam 	longjmp(Sjbuf, 1);
4613642Ssam }
4713642Ssam 
4813642Ssam /*******
4913642Ssam  *	conn(system)
5013642Ssam  *	char *system;
5113642Ssam  *
5213642Ssam  *	conn - place a telephone call to system and
5313642Ssam  *	login, etc.
5413642Ssam  *
5513642Ssam  *	return codes:
5613642Ssam  *		CF_SYSTEM: don't know system
5713642Ssam  *		CF_TIME: wrong time to call
5813642Ssam  *		CF_DIAL: call failed
5913642Ssam  *		CF_NODEV: no devices available to place call
6013642Ssam  *		CF_LOGIN: login/password dialog failed
6113642Ssam  *
6213642Ssam  *		>0  - file no.  -  connect ok
6313642Ssam  *
6413642Ssam  */
6513642Ssam 
6613642Ssam int Dcf = -1;
6713642Ssam 
6813642Ssam conn(system)
6913642Ssam char *system;
7013642Ssam {
7113642Ssam 	int ret, nf;
7213642Ssam 	register int fn, fnd;
7313642Ssam 	char info[MAXC], *flds[MAXC/10];
7413642Ssam 	register FILE *fsys;
7513642Ssam 	int fcode = 0;
7613642Ssam 
7713642Ssam 	nf = 0;
7813642Ssam 	fnd = 0;
7913642Ssam 
8013642Ssam 
8113642Ssam 	fsys = fopen(SYSFILE, "r");
8213642Ssam 	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
8313642Ssam 
8413642Ssam 	DEBUG(4, "finds %s\n", "called");
8513642Ssam 	while((nf = finds(fsys, system, info, flds)) > 0) {
8613642Ssam 		DEBUG(4, "getto %s\n", "called");
8713642Ssam 		if ((fn = getto(flds)) > 0) {
8813642Ssam 			fnd = 1;
8913642Ssam 			Dcf = fn;
9013642Ssam 			break;
9113642Ssam 		}
9213642Ssam 		fcode = (fn == FAIL ? CF_DIAL : fn);
9313642Ssam 	}
9413642Ssam 	fclose(fsys);
9513642Ssam 
9613642Ssam 	if (nf <= 0)
9713642Ssam 		return(fcode ? fcode : nf);
9813642Ssam 
9913642Ssam 	DEBUG(4, "login %s\n", "called");
10013642Ssam 	ret = login(nf, flds, fn);
10113642Ssam 	if (ret < 0) {
10213642Ssam 		clsacu();
10313642Ssam 		return(CF_LOGIN);
10413642Ssam 	}
10513642Ssam 	/* rti!trt:  avoid passing file to children */
10613642Ssam 	fioclex(fn);
10713642Ssam 	return(fn);
10813642Ssam }
10913642Ssam 
11013642Ssam /***
11113642Ssam  *	getto(flds)		connect to remote machine
11213642Ssam  *	char *flds[];
11313642Ssam  *
11413642Ssam  *	return codes:
11513642Ssam  *		>0  -  file number - ok
11613642Ssam  *		FAIL  -  failed
11713642Ssam  */
11813642Ssam 
11913642Ssam getto(flds)
12013642Ssam register char *flds[];
12113642Ssam {
12213642Ssam 	register struct condev *cd;
12313642Ssam 	int nulldev(), diropn();
12413642Ssam 
12513642Ssam 	DEBUG(4, "call: no. %s ", flds[F_PHONE]);
12613642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
12713642Ssam 
12813642Ssam 	CU_end = nulldev;
12913642Ssam 	for (cd = condevs; cd->CU_meth != NULL; cd++) {
13013642Ssam 		if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) {
13113642Ssam 			DEBUG(4, "Using %s to call\n", cd->CU_meth);
13213642Ssam 			return((*(cd->CU_gen))(flds));
13313642Ssam 			}
13413642Ssam 		}
13513642Ssam 	logent(flds[F_LINE], "getto: Can't find, using DIR");
13613642Ssam 	return(diropn(flds));	/* search failed, so use direct */
13713642Ssam 	}
13813642Ssam 
13913642Ssam /***
14013642Ssam  *	clsacu()	close call unit
14113642Ssam  *
14213642Ssam  *	return codes:  none
14313642Ssam  */
14413642Ssam 
14513642Ssam int (*CU_end)() = nulldev;
14613642Ssam clsacu()
14713642Ssam {
14813642Ssam 	(*(CU_end))(Dcf);
14913642Ssam 	if (close(Dcf) == 0) {
15013642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
15113642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
15213642Ssam 	}
15313642Ssam 	Dcf = -1;
15413642Ssam 	CU_end = nulldev;
15513642Ssam }
15613642Ssam 
15713642Ssam /***
15813642Ssam  *	exphone - expand phone number for given prefix and number
15913642Ssam  *
16013642Ssam  *	return code - none
16113642Ssam  */
16213642Ssam 
16313642Ssam exphone(in, out)
16413642Ssam register char *in, *out;
16513642Ssam {
16613642Ssam 	FILE *fn;
16713642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
16813642Ssam 	char buf[BUFSIZ];
16913642Ssam 	register char *s1;
17013642Ssam 
17113642Ssam 	if (!isalpha(*in)) {
17213642Ssam 		strcpy(out, in);
17313642Ssam 		return;
17413642Ssam 	}
17513642Ssam 
17613642Ssam 	s1=pre;
17713642Ssam 	while (isalpha(*in))
17813642Ssam 		*s1++ = *in++;
17913642Ssam 	*s1 = '\0';
18013642Ssam 	s1 = npart;
18113642Ssam 	while (*in != '\0')
18213642Ssam 		*s1++ = *in++;
18313642Ssam 	*s1 = '\0';
18413642Ssam 
18513642Ssam 	tpre[0] = '\0';
18613642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
18713642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
18813642Ssam 	else {
18913642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
19013642Ssam 			sscanf(buf, "%s%s", p, tpre);
19113642Ssam 			if (strcmp(p, pre) == SAME)
19213642Ssam 				goto found;
19313642Ssam 			tpre[0] = '\0';
19413642Ssam 		}
19513642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
19613642Ssam 	found:;
19713642Ssam 		fclose(fn);
19813642Ssam 	}
19913642Ssam 
20013642Ssam 	strcpy(out, tpre);
20113642Ssam 	strcat(out, npart);
20213642Ssam 	return;
20313642Ssam }
20413642Ssam 
20513642Ssam /***
20613642Ssam  *	rddev - read and decode a line from device file
20713642Ssam  *
20813642Ssam  *	return code - FAIL at end-of file; 0 otherwise
20913642Ssam  */
21013642Ssam 
21113642Ssam rddev(fp, dev)
21213642Ssam register struct Devices *dev;
21313642Ssam FILE *fp;
21413642Ssam {
21513642Ssam 	char *fdig();
21613642Ssam 	char buf[BUFSIZ];
21713642Ssam 	int na;
21813642Ssam 
21913642Ssam 	if (!cfgets(buf, BUFSIZ, fp))
22013642Ssam 		return(FAIL);
22113642Ssam 
22213642Ssam 	na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line,
22313642Ssam 	  dev->D_calldev, dev->D_class, dev->D_brand);
22413642Ssam 	ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0);
22513642Ssam 	if (na != 5) dev->D_brand[0] = '\0';
22613642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
22713642Ssam 	return(0);
22813642Ssam }
22913642Ssam 
23013642Ssam /***
23113642Ssam  *	finds(fsys, sysnam, info, flds)	set system attribute vector
23213642Ssam  *
23313642Ssam  *	return codes:
23413642Ssam  *		>0  -  number of arguments in vector - succeeded
23513642Ssam  *		CF_SYSTEM  -  system name not found
23613642Ssam  *		CF_TIME  -  wrong time to call
23713642Ssam  */
23813642Ssam 
23913642Ssam finds(fsys, sysnam, info, flds)
24013642Ssam char *sysnam, info[], *flds[];
24113642Ssam FILE *fsys;
24213642Ssam {
24313642Ssam 	char sysn[8];
24413642Ssam 	int na;
24513642Ssam 	int fcode = 0;
24613642Ssam 
24713642Ssam 	/* format of fields
24813642Ssam 	 *	0 name;
24913642Ssam 	 *	1 time
25013642Ssam 	 *	2 acu/hardwired
25113642Ssam 	 *	3 speed
25213642Ssam 	 *	etc
25313642Ssam 	 */
25413642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
25513642Ssam 		na = getargs(info, flds);
25613642Ssam 		sprintf(sysn, "%.7s", flds[F_NAME]);
25713642Ssam 		if (strcmp(sysnam, sysn) != SAME)
25813642Ssam 			continue;
25913642Ssam 		if (ifdate(flds[F_TIME]))
26013642Ssam 			/*  found a good entry  */
26113642Ssam 			return(na);
26213642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
26313642Ssam 		fcode = CF_TIME;
26413642Ssam 	}
26513642Ssam 	return(fcode ? fcode : CF_SYSTEM);
26613642Ssam }
26713642Ssam 
26813642Ssam /***
26913642Ssam  *	login(nf, flds, dcr)		do login conversation
27013642Ssam  *	char *flds[];
27113642Ssam  *	int nf;
27213642Ssam  *
27313642Ssam  *	return codes:  0  |  FAIL
27413642Ssam  */
27513642Ssam 
27613642Ssam login(nf, flds, fn)
27713642Ssam register char *flds[];
27813642Ssam int nf, fn;
27913642Ssam {
28013642Ssam 	register char *want, *altern;
28113642Ssam 	extern char *index();
28213642Ssam 	int k, ok;
28313642Ssam 
28413642Ssam 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf);
28513642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
28613642Ssam 		want = flds[k];
28713642Ssam 		ok = FAIL;
28813642Ssam 		while (ok != 0) {
28913642Ssam 			altern = index(want, '-');
29013642Ssam 			if (altern != NULL)
29113642Ssam 				*altern++ = '\0';
29213642Ssam 			DEBUG(4, "wanted %s ", want);
29313642Ssam 			ok = expect(want, fn);
29413642Ssam 			DEBUG(4, "got %s\n", ok ? "?" : "that");
29513642Ssam 			if (ok == 0)
29613642Ssam 				break;
29713642Ssam 			if (altern == NULL) {
29813642Ssam 				logent("LOGIN", "FAILED");
29913642Ssam 				/* close *not* needed here. rti!trt */
30013642Ssam 				return(FAIL);
30113642Ssam 			}
30213642Ssam 			want = index(altern, '-');
30313642Ssam 			if (want != NULL)
30413642Ssam 				*want++ = '\0';
30513642Ssam 			sendthem(altern, fn);
30613642Ssam 		}
30713642Ssam 		sleep(2);
30813642Ssam 		if (k+1 < nf)
30913642Ssam 			sendthem(flds[k+1], fn);
31013642Ssam 	}
31113642Ssam 	return(0);
31213642Ssam }
31313642Ssam 
31413642Ssam 
31513642Ssam /* rti!trt: conditional table generation to support odd speeds */
31613642Ssam /* Suggested in n44a.139 by n44!dan (Dan Ts'o) */
31713642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
31813642Ssam #ifdef B50
31913642Ssam 	{  50,	 B50},
32013642Ssam #endif
32113642Ssam #ifdef B75
32213642Ssam 	{  75,	 B75},
32313642Ssam #endif
32413642Ssam #ifdef B110
32513642Ssam 	{ 110,	B110},
32613642Ssam #endif
32713642Ssam #ifdef B150
32813642Ssam 	{ 150,	B150},
32913642Ssam #endif
33013642Ssam #ifdef B200
33113642Ssam 	{ 200,	B200},
33213642Ssam #endif
33313642Ssam #ifdef B300
33413642Ssam 	{ 300,  B300},
33513642Ssam #endif
33613642Ssam #ifdef B600
33713642Ssam 	{600,	B600},
33813642Ssam #endif
33913642Ssam #ifdef B1200
34013642Ssam 	{1200, B1200},
34113642Ssam #endif
34213642Ssam #ifdef B1800
34313642Ssam 	{1800, B1800},
34413642Ssam #endif
34513642Ssam #ifdef B2000
34613642Ssam 	{2000, B2000},
34713642Ssam #endif
34813642Ssam #ifdef B2400
34913642Ssam 	{2400, B2400},
35013642Ssam #endif
35113642Ssam #ifdef B3600
35213642Ssam 	{3600, B3600},
35313642Ssam #endif
35413642Ssam #ifdef B4800
35513642Ssam 	{4800, B4800},
35613642Ssam #endif
35713642Ssam #ifdef B7200
35813642Ssam 	{7200, B7200},
35913642Ssam #endif
36013642Ssam #ifdef B9600
36113642Ssam 	{9600, B9600},
36213642Ssam #endif
36313642Ssam #ifdef B19200
36413642Ssam 	{19200,B19200},
36513642Ssam #endif
36613642Ssam 	{0, 0}
36713642Ssam };
36813642Ssam 
36913642Ssam /***
37013642Ssam  *	fixline(tty, spwant)	set speed/echo/mode...
37113642Ssam  *	int tty, spwant;
37213642Ssam  *
37313642Ssam  *	return codes:  none
37413642Ssam  */
37513642Ssam 
37613642Ssam fixline(tty, spwant)
37713642Ssam int tty, spwant;
37813642Ssam {
37913642Ssam #ifdef	SYSIII
38013642Ssam 	struct termio ttbuf;
38113642Ssam #endif
38213642Ssam #ifndef	SYSIII
38313642Ssam 	struct sgttyb ttbuf;
38413642Ssam #endif
38513642Ssam 	register struct sg_spds *ps;
38613642Ssam 	int speed = -1;
38713642Ssam 	int ret;
38813642Ssam 
38913642Ssam 	for (ps = spds; ps->sp_val; ps++)
39013642Ssam 		if (ps->sp_val == spwant)
39113642Ssam 			speed = ps->sp_name;
39213642Ssam 	ASSERT(speed >= 0, "BAD SPEED", "", speed);
39313642Ssam #ifdef	SYSIII
39413642Ssam 	ioctl(tty, TCGETA, &ttbuf);
39513642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
39613642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
39713642Ssam 	ttbuf.c_iflag = (ushort)0;
39813642Ssam 	ttbuf.c_oflag = (ushort)0;
39913642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
40013642Ssam 	ttbuf.c_lflag = (ushort)0;
40113642Ssam 	ttbuf.c_cc[VMIN] = 6;
40213642Ssam 	ttbuf.c_cc[VTIME] = 1;
40313642Ssam 	ret = ioctl(tty, TCSETA, &ttbuf);
40413642Ssam #endif
40513642Ssam #ifndef	SYSIII
40613642Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
40713642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
40813642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
40913642Ssam 	ret = ioctl(tty, TIOCSETP, &ttbuf);
41013642Ssam #endif
41113642Ssam 	ASSERT(ret >= 0, "RETURN FROM STTY", "", ret);
41213642Ssam #ifndef	SYSIII
41313642Ssam 	ioctl(tty, TIOCHPCL, STBNULL);
41413642Ssam 	ioctl(tty, TIOCEXCL, STBNULL);
41513642Ssam #endif
41613642Ssam 	return;
41713642Ssam }
41813642Ssam 
41913642Ssam 
42013642Ssam /* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */
42113642Ssam /* Actually, the 'expect' algorithm should be rewritten. */
42213642Ssam #define MR 1000
42313642Ssam 
42413642Ssam 
42513642Ssam /***
42613642Ssam  *	expect(str, fn)	look for expected string
42713642Ssam  *	char *str;
42813642Ssam  *
42913642Ssam  *	return codes:
43013642Ssam  *		0  -  found
43113642Ssam  *		FAIL  -  lost line or too many characters read
43213642Ssam  *		some character  -  timed out
43313642Ssam  */
43413642Ssam 
43513642Ssam expect(str, fn)
43613642Ssam register char *str;
43713642Ssam int fn;
43813642Ssam {
43913642Ssam 	static char rdvec[MR];
44013642Ssam 	register char *rp = rdvec;
44113642Ssam 	int kr;
44213642Ssam 	char nextch;
44313642Ssam 
44413642Ssam 	if (strcmp(str, "\"\"") == SAME)
44513642Ssam 		return(0);
44613642Ssam 	*rp = 0;
44713642Ssam 	if (setjmp(Sjbuf)) {
44813642Ssam 		return(FAIL);
44913642Ssam 	}
45013642Ssam 	signal(SIGALRM, alarmtr);
45113642Ssam /* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */
45213642Ssam 	alarm(MAXMSGTIME);
45313642Ssam 	while (notin(str, rdvec)) {
45413642Ssam 		kr = read(fn, &nextch, 1);
45513642Ssam 		if (kr <= 0) {
45613642Ssam 			alarm(0);
45713642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
45813642Ssam 			logent("LOGIN", "LOST LINE");
45913642Ssam 			return(FAIL);
46013642Ssam 		}
46113642Ssam 		{
46213642Ssam 		int c;
46313642Ssam 		c = nextch & 0177;
46413642Ssam 		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
46513642Ssam 		}
46613642Ssam 		if ((*rp = nextch & 0177) != '\0')
46713642Ssam 			rp++;
46813642Ssam /* Check rdvec before null termination -- cmcl2!salkind */
46913642Ssam 		if (rp >= rdvec + MR) {
47013642Ssam 			alarm(0);
47113642Ssam 			return(FAIL);
47213642Ssam 		}
47313642Ssam 		*rp = '\0';
47413642Ssam 	}
47513642Ssam 	alarm(0);
47613642Ssam 	return(0);
47713642Ssam }
47813642Ssam 
47913642Ssam 
48013642Ssam /*
48113642Ssam  * Determine next file descriptor that would be allocated.
48213642Ssam  * This permits later closing of a file whose open was interrupted.
48313642Ssam  * It is a UNIX kernel problem, but it has to be handled.
48413642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
48513642Ssam  */
48613642Ssam getnextfd()
48713642Ssam {
48813642Ssam 	close(next_fd = open("/", 0));
48913642Ssam }
49013642Ssam 
49113642Ssam /***
49213642Ssam  *	sendthem(str, fn)	send line of login sequence
49313642Ssam  *	char *str;
49413642Ssam  *
49513642Ssam  *	return codes:  none
49613642Ssam  */
49713642Ssam 
49813642Ssam sendthem(str, fn)
49913642Ssam register char *str;
50013642Ssam int fn;
50113642Ssam {
50213642Ssam 	register char *strptr;
50313642Ssam 	int i, n, cr = 1;
50413642Ssam 	static int p_init = 0;
50513642Ssam 
50613642Ssam 	/* Note: debugging authorized only for privileged users */
50713642Ssam 	DEBUG(5, "send %s\n", str);
50813642Ssam 
50913642Ssam 	if (!p_init) {
51013642Ssam 		p_init++;
51113642Ssam 		bld_partab(P_EVEN);
51213642Ssam 	}
51313642Ssam 
51413642Ssam 	if (prefix("BREAK", str)) {
51513642Ssam 		sscanf(&str[5], "%1d", &i);
51613642Ssam 		if (i <= 0 || i > 10)
51713642Ssam 			i = 3;
51813642Ssam 		/* send break */
51913642Ssam 		genbrk(fn, i);
52013642Ssam 		return;
52113642Ssam 	}
52213642Ssam 
52313642Ssam 	if (prefix("PAUSE", str)) {
52413642Ssam 		sscanf(&str[5], "%1d", &i);
52513642Ssam 		if (i <= 0 || i > 10)
52613642Ssam 			i = 3;
52713642Ssam 		/* pause for a while */
52813642Ssam 		sleep((unsigned)i);
52913642Ssam 		return;
53013642Ssam 	}
53113642Ssam 
53213642Ssam 	if (strcmp(str, "EOT") == SAME) {
53313642Ssam 		p_chwrite(fn, '\04');
53413642Ssam 		return;
53513642Ssam 	}
53613642Ssam 
53713642Ssam 	/* LF, CR, and "" courtesy unc!smb */
53813642Ssam 	/* Send a '\n' */
53913642Ssam 	if (strcmp(str, "LF") == SAME)
54013642Ssam 		str = "\\n\\c";
54113642Ssam 
54213642Ssam 	/* Send a '\r' */
54313642Ssam 	if (strcmp(str, "CR") == SAME)
54413642Ssam 		str = "\\r\\c";
54513642Ssam 
54613642Ssam 	/* Set parity as needed */
54713642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
54813642Ssam 		bld_partab(P_ZERO);
54913642Ssam 		return;
55013642Ssam 	}
55113642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
55213642Ssam 		bld_partab(P_ONE);
55313642Ssam 		return;
55413642Ssam 	}
55513642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
55613642Ssam 		bld_partab(P_EVEN);
55713642Ssam 		return;
55813642Ssam 	}
55913642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
56013642Ssam 		bld_partab(P_ODD);
56113642Ssam 		return;
56213642Ssam 	}
56313642Ssam 
56413642Ssam 	/* If "", just send '\r' */
56513642Ssam 	if (strcmp(str, "\"\"") != SAME)
56613642Ssam 	for (strptr = str; *strptr; strptr++) {
56713642Ssam 		if (*strptr == '\\') switch(*++strptr) {
56813642Ssam 		case 's':
56913642Ssam 			DEBUG(5, "BLANK\n", "");
57013642Ssam 			*strptr = ' ';
57113642Ssam 			break;
57213642Ssam 		case 'd':
57313642Ssam 			DEBUG(5, "DELAY\n", "");
57413642Ssam 			sleep(1);
57513642Ssam 			continue;
57613642Ssam 		case 'r':
57713642Ssam 			DEBUG(5, "RETURN\n", "");
57813642Ssam 			*strptr = '\r';
57913642Ssam 			break;
58013642Ssam 		case 'b':
58113642Ssam 			if (isdigit(*(strptr+1))) {
58213642Ssam 				i = (*++strptr - '0');
58313642Ssam 				if (i <= 0 || i > 10)
58413642Ssam 					i = 3;
58513642Ssam 			} else
58613642Ssam 				i = 3;
58713642Ssam 			/* send break */
58813642Ssam 			genbrk(fn, i);
58913642Ssam 			continue;
59013642Ssam 		case 'c':
59113642Ssam 			if (*(strptr+1) == '\0') {
59213642Ssam 			DEBUG(5, "NO CR\n", "");
59313642Ssam 				cr = 0;
59413642Ssam 				continue;
59513642Ssam 			}
59613642Ssam 			DEBUG(5, "NO CR - MIDDLE IGNORED\n", "");
59713642Ssam 			continue;
59813642Ssam 		default:
59913642Ssam 			if (isdigit(strptr[1])) {
60013642Ssam 				i = 0;
60113642Ssam 				n = 0;
60213642Ssam 				while (isdigit(strptr[1]) && ++n <= 3)
60313642Ssam 					i = i*8 + (*++strptr - '0');
60413642Ssam 				p_chwrite(fn, i);
60513642Ssam 				continue;
60613642Ssam 			}
60713642Ssam 			DEBUG(5, "BACKSLASH\n", "");
60813642Ssam 			strptr--;
60913642Ssam 		}
61013642Ssam 		p_chwrite(fn, *strptr);
61113642Ssam 	}
61213642Ssam 
61313642Ssam 	/* '\n' changed to '\r'--a better default. rti!trt */
61413642Ssam 	if (cr)
61513642Ssam 		p_chwrite(fn, '\r');
61613642Ssam 	return;
61713642Ssam }
61813642Ssam 
61913642Ssam p_chwrite(fd, c)
62013642Ssam int fd;
62113642Ssam int c;
62213642Ssam {
62313642Ssam 	char t[2];
62413642Ssam 
62513642Ssam 	t[0] = par_tab[c&0177];
62613642Ssam 	t[1] = '\0';
62713642Ssam 	ASSERT(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]);
62813642Ssam }
62913642Ssam 
63013642Ssam /*
63113642Ssam  * generate parity table for use by p_chwrite.
63213642Ssam  */
63313642Ssam bld_partab(type)
63413642Ssam int type;
63513642Ssam {
63613642Ssam 	register int i, j, n;
63713642Ssam 
63813642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
63913642Ssam 		n = 0;
64013642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
64113642Ssam 			n++;
64213642Ssam 		par_tab[i] = i;
64313642Ssam 		if (type == P_ONE
64413642Ssam 		 || (type == P_EVEN && (n&01) != 0)
64513642Ssam 		 || (type == P_ODD && (n&01) == 0))
64613642Ssam 			par_tab[i] |= sizeof(par_tab);
64713642Ssam 	}
64813642Ssam }
64913642Ssam 
65013642Ssam #define BSPEED B150
65113642Ssam 
65213642Ssam /***
65313642Ssam  *	genbrk		send a break
65413642Ssam  *
65513642Ssam  *	return codes;  none
65613642Ssam  */
65713642Ssam 
65813642Ssam genbrk(fn, bnulls)
65913642Ssam register int fn, bnulls;
66013642Ssam {
66113642Ssam 	register int ret;
66213642Ssam #ifdef	SYSIII
66313642Ssam 	ret = ioctl(fn, TCSBRK, STBNULL);
66413642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
66513642Ssam #endif
66613642Ssam #ifndef	SYSIII
66713642Ssam #ifdef	TIOCSBRK
66813642Ssam 	ret = ioctl(fn, TIOCSBRK, STBNULL);
66913642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
67013642Ssam #ifdef	TIOCCBRK
67113642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
67213642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
67313642Ssam 	sleep(1);
67413642Ssam 	ret = ioctl(fn, TIOCCBRK, STBNULL);
67513642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
67613642Ssam #endif
67713642Ssam 	DEBUG(4, "ioctl 1 second break\n", STBNULL);
67813642Ssam #else
67913642Ssam 	struct sgttyb ttbuf;
68013642Ssam 	register int sospeed;
68113642Ssam 
68213642Ssam 	ret = ioctl(fn, TIOCGETP, &ttbuf);
68313642Ssam 	sospeed = ttbuf.sg_ospeed;
68413642Ssam 	ttbuf.sg_ospeed = BSPEED;
68513642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
68613642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
68713642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
68813642Ssam 	ttbuf.sg_ospeed = sospeed;
68913642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
69013642Ssam 	ret = write(fn, "@", 1);
69113642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
69213642Ssam 	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
69313642Ssam #endif
69413642Ssam #endif
69513642Ssam }
69613642Ssam 
69713642Ssam 
69813642Ssam /***
69913642Ssam  *	notin(sh, lg)	check for occurrence of substring "sh"
70013642Ssam  *	char *sh, *lg;
70113642Ssam  *
70213642Ssam  *	return codes:
70313642Ssam  *		0  -  found the string
70413642Ssam  *		1  -  not in the string
70513642Ssam  */
70613642Ssam 
70713642Ssam notin(sh, lg)
70813642Ssam register char *sh, *lg;
70913642Ssam {
71013642Ssam 	while (*lg != '\0') {
71113642Ssam 		/* Dave Martingale: permit wild cards in 'expect' */
71213642Ssam 		if (wprefix(sh, lg))
71313642Ssam 			return(0);
71413642Ssam 		else
71513642Ssam 			lg++;
71613642Ssam 	}
71713642Ssam 	return(1);
71813642Ssam }
71913642Ssam 
72013642Ssam 
72113642Ssam /*******
72213642Ssam  *	ifdate(s)
72313642Ssam  *	char *s;
72413642Ssam  *
72513642Ssam  *	ittvax!swatt
72613642Ssam  *	Allow multiple date specifications separated by '|'.
72713642Ssam  *	Calls ifadate, formerly "ifdate".
72813642Ssam  *
72913642Ssam  *	return codes:
73013642Ssam  *		see ifadate
73113642Ssam  */
73213642Ssam 
73313642Ssam ifdate(s)
73413642Ssam char *s;
73513642Ssam {
73613642Ssam 	register char *p;
73713642Ssam 	register int ret;
73813642Ssam 
73913642Ssam 	for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|'))
74013642Ssam 		if (ret = ifadate(p))
74113642Ssam 			return(ret);
74213642Ssam 	return(0);
74313642Ssam }
74413642Ssam 
74513642Ssam 
74613642Ssam /*******
74713642Ssam  *	ifadate(s)
74813642Ssam  *	char *s;
74913642Ssam  *
75013642Ssam  *	ifadate  -  this routine will check a string (s)
75113642Ssam  *	like "MoTu0800-1730" to see if the present
75213642Ssam  *	time is within the given limits.
75313642Ssam  *	SIDE EFFECT - Retrytime is set
75413642Ssam  *
75513642Ssam  *	String alternatives:
75613642Ssam  *		Wk - Mo thru Fr
75713642Ssam  *		zero or one time means all day
75813642Ssam  *		Any - any day
75913642Ssam  *
76013642Ssam  *	return codes:
76113642Ssam  *		0  -  not within limits
76213642Ssam  *		1  -  within limits
76313642Ssam  */
76413642Ssam 
76513642Ssam ifadate(s)
76613642Ssam char *s;
76713642Ssam {
76813642Ssam 	static char *days[]={
76913642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
77013642Ssam 	};
77113642Ssam 	time_t clock;
77213642Ssam 	int rtime;
77313642Ssam 	int i, tl, th, tn, flag, dayok=0;
77413642Ssam 	struct tm *localtime();
77513642Ssam 	struct tm *tp;
77613642Ssam 	char *index();
77713642Ssam 	char *p;
77813642Ssam 
77913642Ssam 	/*  pick up retry time for failures  */
78013642Ssam 	/*  global variable Retrytime is set here  */
78113642Ssam 	if ((p = index(s, ',')) == NULL) {
78213642Ssam 		Retrytime = RETRYTIME;
78313642Ssam 	}
78413642Ssam 	else {
78513642Ssam 		i = sscanf(p+1, "%d", &rtime);
78613642Ssam 		if (i < 1 || rtime < 5)
78713642Ssam 			rtime = 5;
78813642Ssam 		Retrytime  = rtime * 60;
78913642Ssam 	}
79013642Ssam 
79113642Ssam 	time(&clock);
79213642Ssam 	tp = localtime(&clock);
79313642Ssam 	while (isalpha(*s)) {
79413642Ssam 		for (i = 0; days[i]; i++) {
79513642Ssam 			if (prefix(days[i], s))
79613642Ssam 				if (tp->tm_wday == i)
79713642Ssam 					dayok = 1;
79813642Ssam 		}
79913642Ssam 
80013642Ssam 		if (prefix("Wk", s))
80113642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
80213642Ssam 				dayok = 1;
80313642Ssam 		if (prefix("Any", s))
80413642Ssam 			dayok = 1;
80513642Ssam 		s++;
80613642Ssam 	}
80713642Ssam 
80813642Ssam 	if (dayok == 0)
80913642Ssam 		return(0);
81013642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
81113642Ssam 	tn = tp->tm_hour * 100 + tp->tm_min;
81213642Ssam 	if (i < 2)
81313642Ssam 		return(1);
81413642Ssam 	if (th < tl)
81513642Ssam 		flag = 0;  /* set up for crossover 2400 test */
81613642Ssam 	else
81713642Ssam 		flag = 1;
81813642Ssam 	if ((tn >= tl && tn <= th)
81913642Ssam 	  || (tn >= th && tn <= tl)) /* test for crossover 2400 */
82013642Ssam 		return(flag);
82113642Ssam 	else
82213642Ssam 		return(!flag);
82313642Ssam }
82413642Ssam 
82513642Ssam 
82613642Ssam /***
82713642Ssam  *	char *
82813642Ssam  *	lastc(s)	return pointer to last character
82913642Ssam  *	char *s;
83013642Ssam  *
83113642Ssam  */
83213642Ssam 
83313642Ssam char *
83413642Ssam lastc(s)
83513642Ssam register char *s;
83613642Ssam {
83713642Ssam 	while (*s != '\0') s++;
83813642Ssam 	return(s);
83913642Ssam }
84013642Ssam 
84113642Ssam 
84213642Ssam /***
84313642Ssam  *	char *
84413642Ssam  *	fdig(cp)	find first digit in string
84513642Ssam  *
84613642Ssam  *	return - pointer to first digit in string or end of string
84713642Ssam  */
84813642Ssam 
84913642Ssam char *
85013642Ssam fdig(cp)
85113642Ssam register char *cp;
85213642Ssam {
85313642Ssam 	register char *c;
85413642Ssam 
85513642Ssam 	for (c = cp; *c; c++)
85613642Ssam 		if (*c >= '0' && *c <= '9')
85713642Ssam 			break;
85813642Ssam 	return(c);
85913642Ssam }
86013642Ssam 
86113642Ssam 
86213642Ssam /*
86313642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
86413642Ssam  * Strings are compared as if they contain all capital letters.
86513642Ssam  */
86613642Ssam 
86713642Ssam snccmp(s1, s2)
86813642Ssam register char *s1, *s2;
86913642Ssam {
87013642Ssam 	char c1, c2;
87113642Ssam 
87213642Ssam 	if (islower(*s1)) c1 = toupper(*s1);
87313642Ssam 	else c1 = *s1;
87413642Ssam 	if (islower(*s2)) c2 = toupper(*s2);
87513642Ssam 	else c2 = *s2;
87613642Ssam 
87713642Ssam 	while (c1 == c2) {
87813642Ssam 		if (*s1++=='\0')
87913642Ssam 			return(0);
88013642Ssam 		s2++;
88113642Ssam 		if (islower(*s1)) c1 = toupper(*s1);
88213642Ssam 		else c1 = *s1;
88313642Ssam 		if (islower(*s2)) c2 = toupper(*s2);
88413642Ssam 		else c2 = *s2;
88513642Ssam 	}
88613642Ssam 	return(c1 - c2);
88713642Ssam }
888