xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 25705)
113642Ssam #ifndef lint
2*25705Sbloom static char sccsid[] = "@(#)conn.c	5.9 (Berkeley) 01/06/86";
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 */
43*25705Sbloom 
44*25705Sbloom char *PCP = "PCP";	/* PC Pursuit device type */
4525127Sbloom /*
4625127Sbloom  *	catch alarm routine for "expect".
4713642Ssam  */
4813642Ssam alarmtr()
4913642Ssam {
5013642Ssam 	signal(SIGALRM, alarmtr);
5113642Ssam 	if (next_fd >= 0) {
5213642Ssam 		if (close(next_fd))
5313642Ssam 			logent("FAIL", "ACU LINE CLOSE");
5413642Ssam 		next_fd = -1;
5513642Ssam 	}
5613642Ssam 	longjmp(Sjbuf, 1);
5713642Ssam }
5813642Ssam 
59*25705Sbloom /* This template is for seismo to call ihnp4
60*25705Sbloom  * the 3 lines marked ---> will be overwritten for the appropriate city
61*25705Sbloom  */
62*25705Sbloom #define PCP_BAUD	3
63*25705Sbloom #define PCP_PHONE	4
64*25705Sbloom #define PCP_CALLBACK	8
65*25705Sbloom #define PCP_CITY	10
66*25705Sbloom #define PCP_RPHONE	12
67*25705Sbloom #define NPCFIELDS	15
68*25705Sbloom 
69*25705Sbloom static char *PCFlds[] = {
70*25705Sbloom 	"PC-PURSUIT",
71*25705Sbloom 	"Any",
72*25705Sbloom 	"ACU",
73*25705Sbloom 	"1200",
74*25705Sbloom 	CNULL,	/* <--- **** Welcome to Telenet PC Pursuit ***** */
75*25705Sbloom 	"ABORT",
76*25705Sbloom 	"Good",	/* Abort of Good bye! */
77*25705Sbloom 	")", 	/* <--- Enter your 7-digit phone number (xxx-xxxx) */
78*25705Sbloom 	CNULL,	/* ---> 528-1234 */
79*25705Sbloom 	"call?", 	/* <--- Which city do you wish to call? */
80*25705Sbloom 	CNULL,	/* ---> CHICAGO */
81*25705Sbloom 	")", 	/* <--- Enter the phone number you wish to call (xxx-xxxx) */
82*25705Sbloom 	CNULL,	/* ---> 690-7171 */
83*25705Sbloom 	"R)?", 	/* <--- You are #1 in the queue. Do you want to wait, or Restart (Y/N/R)? */
84*25705Sbloom 	"Y",
85*25705Sbloom 	CNULL 	/* <--- .....Good Bye! */
86*25705Sbloom };
87*25705Sbloom 
88*25705Sbloom static char PCP_brand[20];
89*25705Sbloom 
9018619Sralph /*
9118619Sralph  *	place a telephone call to system and login, etc.
9213642Ssam  *
9313642Ssam  *	return codes:
9413642Ssam  *		CF_SYSTEM: don't know system
9513642Ssam  *		CF_TIME: wrong time to call
9613642Ssam  *		CF_DIAL: call failed
9713642Ssam  *		CF_NODEV: no devices available to place call
9813642Ssam  *		CF_LOGIN: login/password dialog failed
9913642Ssam  *
10013642Ssam  *		>0  - file no.  -  connect ok
10113642Ssam  */
10213642Ssam 
10313642Ssam int Dcf = -1;
10417834Sralph char *Flds[MAXC/10];
10517834Sralph extern int LocalOnly;
10613642Ssam 
10713642Ssam conn(system)
10813642Ssam char *system;
10913642Ssam {
110*25705Sbloom 	int nf;
11118619Sralph 	char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE];
11213642Ssam 	register FILE *fsys;
11313642Ssam 	int fcode = 0;
11413642Ssam 
11513642Ssam 	nf = 0;
11613642Ssam 
11713642Ssam 	fsys = fopen(SYSFILE, "r");
11813642Ssam 	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
11913642Ssam 
12017834Sralph 	DEBUG(4, "finds (%s) called\n", system);
12125127Sbloom keeplooking:
12217834Sralph 	while((nf = finds(fsys, system, info, Flds)) > 0) {
12317834Sralph 		if (LocalOnly) {
12417834Sralph 			if (strcmp("TCP", Flds[F_LINE])
12517834Sralph 				&& strcmp("DIR", Flds[F_LINE])
126*25705Sbloom 				&& strcmp("LOCAL", Flds[F_LINE]) ) {
127*25705Sbloom 					fcode = CF_TIME;
128*25705Sbloom 					continue;
129*25705Sbloom 			}
13017834Sralph 		}
13123596Sbloom 		sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
13218619Sralph 		if (!onesys && MaxGrade != DefMaxGrade &&
133*25705Sbloom 			!iswrk(file, "chk", Spool, wkpre))  {
134*25705Sbloom 				fcode = CF_TIME;
135*25705Sbloom 				continue;
136*25705Sbloom 		}
137*25705Sbloom 		/* For GTE's PC Pursuit */
138*25705Sbloom 		if (snccmp(Flds[F_LINE], PCP) == SAME) {
139*25705Sbloom 			FILE *dfp;
140*25705Sbloom 			int status;
141*25705Sbloom 			static struct Devices dev;
142*25705Sbloom 			dfp = fopen(DEVFILE, "r");
143*25705Sbloom 			ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
144*25705Sbloom 			while ((status=rddev(dfp, &dev)) != FAIL
145*25705Sbloom 				&& strcmp(PCP, dev.D_type) != SAME)
146*25705Sbloom 					;
147*25705Sbloom 			fclose(dfp);
148*25705Sbloom 			if (status == FAIL)
149*25705Sbloom 				continue;
150*25705Sbloom 			if (mlock(PCP) == FAIL) {
151*25705Sbloom 				fcode = CF_NODEV;
152*25705Sbloom 				logent("DEVICE", "NO");
153*25705Sbloom 				continue;
154*25705Sbloom 			}
155*25705Sbloom 			PCFlds[PCP_BAUD] = dev.D_class;
156*25705Sbloom 			PCFlds[PCP_PHONE] = dev.D_calldev;
157*25705Sbloom 			PCFlds[PCP_CALLBACK] = dev.D_arg[D_CHAT];
158*25705Sbloom 			PCFlds[PCP_CITY] = Flds[F_CLASS];
159*25705Sbloom 			PCFlds[PCP_RPHONE] = Flds[F_PHONE];
160*25705Sbloom 			strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand));
161*25705Sbloom 			if ((fcode = getto(PCFlds)) < 0)
162*25705Sbloom 				continue;
163*25705Sbloom 			Dcf = fcode;
164*25705Sbloom 			fcode = login(NPCFIELDS, PCFlds, Dcf);
165*25705Sbloom 			clsacu(); /* Hang up, they'll call back */
166*25705Sbloom 			if (fcode != SUCCESS) {
167*25705Sbloom 				fcode = CF_DIAL;
168*25705Sbloom 				continue;
169*25705Sbloom 			}
170*25705Sbloom 			Flds[F_CLASS] = dev.D_class;
171*25705Sbloom 			Flds[F_PHONE] = dev.D_line;
172*25705Sbloom 
173*25705Sbloom 		} /* end PC Pursuit */
174*25705Sbloom 		if ((fcode = getto(Flds)) > 0)
17513642Ssam 			break;
17613642Ssam 	}
17713642Ssam 
17825127Sbloom 	if (nf <= 0) {
17925127Sbloom 		fclose(fsys);
18017834Sralph 		return fcode ? fcode : nf;
18125127Sbloom 	}
18213642Ssam 
183*25705Sbloom 	Dcf = fcode;
184*25705Sbloom 
185*25705Sbloom 	if (fcode >= 0 && snccmp(Flds[F_LINE], PCP) == SAME) {
186*25705Sbloom 		AbortOn = "Good";	/* .... Good Bye */
187*25705Sbloom 		fcode = expect("****~300", Dcf);
188*25705Sbloom 		if (fcode != SUCCESS) {
189*25705Sbloom 			DEBUG(4, "\nexpect timed out\n", CNULL);
190*25705Sbloom 			fcode = CF_DIAL;
191*25705Sbloom 		}
192*25705Sbloom 	}
193*25705Sbloom 	if (fcode >= 0) {
194*25705Sbloom 		DEBUG(4, "login %s\n", "called");
195*25705Sbloom 		fcode = login(nf, Flds, Dcf);
196*25705Sbloom 	}
197*25705Sbloom 	if (fcode < 0) {
19813642Ssam 		clsacu();
199*25705Sbloom 		if (fcode == ABORT) {
20025127Sbloom 			fcode = CF_DIAL;
20125127Sbloom 			goto  keeplooking;
20225127Sbloom 		} else {
20325127Sbloom 			fclose(fsys);
20423596Sbloom 			return CF_LOGIN;
20525127Sbloom 		}
20613642Ssam 	}
20725127Sbloom 	fclose(fsys);
208*25705Sbloom 	fioclex(Dcf);
209*25705Sbloom 	return Dcf;
21013642Ssam }
21113642Ssam 
21225127Sbloom /*
21325127Sbloom  *	connect to remote machine
21413642Ssam  *
21513642Ssam  *	return codes:
21613642Ssam  *		>0  -  file number - ok
21713642Ssam  *		FAIL  -  failed
21813642Ssam  */
21913642Ssam 
22013642Ssam getto(flds)
22113642Ssam register char *flds[];
22213642Ssam {
22313642Ssam 	register struct condev *cd;
22413642Ssam 	int nulldev(), diropn();
22525127Sbloom 	char *line;
22613642Ssam 
22717834Sralph 	DEBUG(4, "getto: call no. %s ", flds[F_PHONE]);
22813642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
22913642Ssam 
23025127Sbloom 	if (snccmp(flds[F_LINE], "LOCAL") == SAME)
23125127Sbloom 		line = "ACU";
23225127Sbloom 	else
23325127Sbloom 		line = flds[F_LINE];
23425127Sbloom #ifdef DIALINOUT
23525127Sbloom 	if (snccmp(line, "ACU") != SAME)
23625127Sbloom 		reenable();
23725127Sbloom #endif DIALINOUT
23813642Ssam 	CU_end = nulldev;
239*25705Sbloom 	if (snccmp(line, PCP) == SAME) {
240*25705Sbloom 		for(cd = condevs; cd->CU_meth != NULL; cd++) {
241*25705Sbloom 			if (snccmp(PCP_brand, cd->CU_brand) == SAME) {
242*25705Sbloom 				CU_end = cd->CU_clos;
243*25705Sbloom 				return diropn(flds);
244*25705Sbloom 			}
24513642Ssam 		}
246*25705Sbloom 		logent(PCP_brand, "UNSUPPORTED ACU TYPE");
247*25705Sbloom 	} else {
248*25705Sbloom 		for (cd = condevs; cd->CU_meth != NULL; cd++) {
249*25705Sbloom 			if (snccmp(cd->CU_meth, line) == SAME) {
250*25705Sbloom 				DEBUG(4, "Using %s to call\n", cd->CU_meth);
251*25705Sbloom 				return (*(cd->CU_gen))(flds);
252*25705Sbloom 			}
253*25705Sbloom 		}
254*25705Sbloom 		DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]);
25513642Ssam 	}
25617834Sralph 	return diropn(flds);	/* search failed, so use direct */
25717834Sralph }
25813642Ssam 
25925127Sbloom /*
26025127Sbloom  *	close call unit
26113642Ssam  *
26213642Ssam  *	return codes:  none
26313642Ssam  */
26413642Ssam 
26513642Ssam int (*CU_end)() = nulldev;
26613642Ssam clsacu()
26713642Ssam {
26817834Sralph 	/* make *sure* Dcf is no longer exclusive.
26917834Sralph 	 * Otherwise dual call-in/call-out modems could get stuck.
27017834Sralph 	 * Unfortunately, doing this here is not ideal, but it is the
27117834Sralph 	 * easiest place to put the call.
27217834Sralph 	 * Hopefully everyone honors the LCK protocol, of course
27317834Sralph 	 */
274*25705Sbloom #ifdef	TIOCNXCL
27523596Sbloom 	if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0)
27623596Sbloom 		DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]);
27717834Sralph #endif
27817834Sralph 	if  (setjmp(Sjbuf))
27917834Sralph 		logent(Rmtname, "CLOSE TIMEOUT");
28017834Sralph 	else {
28117834Sralph 		signal(SIGALRM, alarmtr);
28217834Sralph 		alarm(20);
28317834Sralph 		(*(CU_end))(Dcf);
28417834Sralph 		alarm(0);
28517834Sralph 	}
28613642Ssam 	if (close(Dcf) == 0) {
28713642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
28813642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
28913642Ssam 	}
29013642Ssam 	Dcf = -1;
29113642Ssam 	CU_end = nulldev;
29213642Ssam }
29313642Ssam 
29425127Sbloom /*
29525127Sbloom  *	expand phone number for given prefix and number
29613642Ssam  */
29713642Ssam 
29813642Ssam exphone(in, out)
29913642Ssam register char *in, *out;
30013642Ssam {
30113642Ssam 	FILE *fn;
30213642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
30313642Ssam 	char buf[BUFSIZ];
30413642Ssam 	register char *s1;
30513642Ssam 
30617834Sralph 	if (!isascii(*in) || !isalpha(*in)) {
30713642Ssam 		strcpy(out, in);
30813642Ssam 		return;
30913642Ssam 	}
31013642Ssam 
31113642Ssam 	s1=pre;
31217834Sralph 	while (isascii(*in) && isalpha(*in))
31313642Ssam 		*s1++ = *in++;
31413642Ssam 	*s1 = '\0';
31513642Ssam 	s1 = npart;
31613642Ssam 	while (*in != '\0')
31713642Ssam 		*s1++ = *in++;
31813642Ssam 	*s1 = '\0';
31913642Ssam 
32013642Ssam 	tpre[0] = '\0';
32113642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
32213642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
32313642Ssam 	else {
32413642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
32517834Sralph 			if (sscanf(buf, "%s%s", p, tpre) != 2)
32617834Sralph 				continue;
32713642Ssam 			if (strcmp(p, pre) == SAME)
32813642Ssam 				goto found;
32913642Ssam 			tpre[0] = '\0';
33013642Ssam 		}
33113642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
33213642Ssam 	found:;
33313642Ssam 		fclose(fn);
33413642Ssam 	}
33513642Ssam 
33613642Ssam 	strcpy(out, tpre);
33713642Ssam 	strcat(out, npart);
33813642Ssam }
33913642Ssam 
34018619Sralph /*
34118619Sralph  *	read and decode a line from device file
34213642Ssam  *
34313642Ssam  *	return code - FAIL at end-of file; 0 otherwise
34413642Ssam  */
34513642Ssam 
34613642Ssam rddev(fp, dev)
34713642Ssam register struct Devices *dev;
34813642Ssam FILE *fp;
34913642Ssam {
35017834Sralph 	register int na;
35113642Ssam 
35217834Sralph 	if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp))
35317834Sralph 		return FAIL;
35417834Sralph 	na = getargs(dev->D_argbfr, dev->D_arg, 20);
35517834Sralph 	ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0);
35617834Sralph 	if (na == 4) {
35717834Sralph 		dev->D_brand = "";
35817834Sralph 		na++;
35917834Sralph 	}
36013642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
36117834Sralph 	dev->D_numargs = na;
36217834Sralph 	return 0;
36313642Ssam }
36413642Ssam 
36518619Sralph /*
36618619Sralph  *	set system attribute vector
36713642Ssam  *
36813642Ssam  *	return codes:
36913642Ssam  *		>0  -  number of arguments in vector - succeeded
37013642Ssam  *		CF_SYSTEM  -  system name not found
37113642Ssam  *		CF_TIME  -  wrong time to call
37213642Ssam  */
37313642Ssam 
37413642Ssam finds(fsys, sysnam, info, flds)
37513642Ssam char *sysnam, info[], *flds[];
37613642Ssam FILE *fsys;
37713642Ssam {
37813642Ssam 	int na;
37913642Ssam 	int fcode = 0;
38013642Ssam 
38113642Ssam 	/* format of fields
38213642Ssam 	 *	0 name;
38313642Ssam 	 *	1 time
38413642Ssam 	 *	2 acu/hardwired
38513642Ssam 	 *	3 speed
38613642Ssam 	 *	etc
38713642Ssam 	 */
38813642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
38917834Sralph 		na = getargs(info, flds, MAXC/10);
39023596Sbloom 		if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME)
39113642Ssam 			continue;
39218619Sralph 		if (ifdate(flds[F_TIME]) != FAIL)
39313642Ssam 			/*  found a good entry  */
39417834Sralph 			return na;
39513642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
39613642Ssam 		fcode = CF_TIME;
39713642Ssam 	}
39817834Sralph 	return fcode ? fcode : CF_SYSTEM;
39913642Ssam }
40013642Ssam 
40118619Sralph /*
40218619Sralph  *	do login conversation
40313642Ssam  *
40423596Sbloom  *	return codes:  SUCCESS  |  FAIL
40513642Ssam  */
40613642Ssam 
40713642Ssam login(nf, flds, fn)
40813642Ssam register char *flds[];
40913642Ssam int nf, fn;
41013642Ssam {
41113642Ssam 	register char *want, *altern;
41213642Ssam 	int k, ok;
41313642Ssam 
41417834Sralph 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf);
41517834Sralph 	if (setjmp(Cjbuf))
41617834Sralph 		return FAIL;
41717834Sralph 	AbortOn = NULL;
41813642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
41913642Ssam 		want = flds[k];
42013642Ssam 		ok = FAIL;
42117834Sralph 		while (ok != SUCCESS) {
42213642Ssam 			altern = index(want, '-');
42313642Ssam 			if (altern != NULL)
42413642Ssam 				*altern++ = '\0';
42517834Sralph 			if (strcmp(want, "ABORT") == 0) {
42617834Sralph 				AbortOn = flds[k+1];
42717834Sralph 				DEBUG(4, "ABORT ON: %s\n", AbortOn);
42817834Sralph 				goto nextfield;
42917834Sralph 			}
430*25705Sbloom 			DEBUG(4, "wanted \"%s\"\n", want);
43113642Ssam 			ok = expect(want, fn);
43217834Sralph 			DEBUG(4, "got: %s\n", ok ? "?" : "that");
43317834Sralph 			if (ok == FAIL) {
43417834Sralph 				if (altern == NULL) {
43517834Sralph 					logent("LOGIN", _FAILED);
43617834Sralph 					return FAIL;
43717834Sralph 				}
43817834Sralph 				want = index(altern, '-');
43917834Sralph 				if (want != NULL)
44017834Sralph 					*want++ = '\0';
44117834Sralph 				sendthem(altern, fn);
44217834Sralph 			} else
44317834Sralph 				if (ok == ABORT) {
44417834Sralph 					logent("LOGIN ABORTED", _FAILED);
44523596Sbloom 					return ABORT;
44617834Sralph 				}
44713642Ssam 		}
44817834Sralph 		sleep(1);
44913642Ssam 		if (k+1 < nf)
45013642Ssam 			sendthem(flds[k+1], fn);
45117834Sralph nextfield: ;
45213642Ssam 	}
45317834Sralph 	return SUCCESS;
45413642Ssam }
45513642Ssam 
45613642Ssam 
45717834Sralph /* conditional table generation to support odd speeds */
45813642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
45913642Ssam #ifdef B50
46013642Ssam 	{  50,	 B50},
46113642Ssam #endif
46213642Ssam #ifdef B75
46313642Ssam 	{  75,	 B75},
46413642Ssam #endif
46513642Ssam #ifdef B110
46613642Ssam 	{ 110,	B110},
46713642Ssam #endif
46813642Ssam #ifdef B150
46913642Ssam 	{ 150,	B150},
47013642Ssam #endif
47113642Ssam #ifdef B200
47213642Ssam 	{ 200,	B200},
47313642Ssam #endif
47413642Ssam #ifdef B300
47513642Ssam 	{ 300,  B300},
47613642Ssam #endif
47713642Ssam #ifdef B600
47813642Ssam 	{600,	B600},
47913642Ssam #endif
48013642Ssam #ifdef B1200
48113642Ssam 	{1200, B1200},
48213642Ssam #endif
48313642Ssam #ifdef B1800
48413642Ssam 	{1800, B1800},
48513642Ssam #endif
48613642Ssam #ifdef B2000
48713642Ssam 	{2000, B2000},
48813642Ssam #endif
48913642Ssam #ifdef B2400
49013642Ssam 	{2400, B2400},
49113642Ssam #endif
49213642Ssam #ifdef B3600
49313642Ssam 	{3600, B3600},
49413642Ssam #endif
49513642Ssam #ifdef B4800
49613642Ssam 	{4800, B4800},
49713642Ssam #endif
49813642Ssam #ifdef B7200
49913642Ssam 	{7200, B7200},
50013642Ssam #endif
50113642Ssam #ifdef B9600
50213642Ssam 	{9600, B9600},
50313642Ssam #endif
50413642Ssam #ifdef B19200
50517834Sralph 	{19200, B19200},
50613642Ssam #endif
50717834Sralph #ifdef EXTA
50817834Sralph 	{19200, EXTA},
50917834Sralph #endif
51013642Ssam 	{0, 0}
51113642Ssam };
51213642Ssam 
51318619Sralph /*
51418619Sralph  *	set speed/echo/mode...
51513642Ssam  *
51613642Ssam  *	return codes:  none
51713642Ssam  */
51813642Ssam 
51913642Ssam fixline(tty, spwant)
52013642Ssam int tty, spwant;
52113642Ssam {
52217834Sralph #ifdef	USG
52313642Ssam 	struct termio ttbuf;
52417834Sralph #else	!USG
52513642Ssam 	struct sgttyb ttbuf;
52617834Sralph #endif !USG
52713642Ssam 	register struct sg_spds *ps;
52813642Ssam 	int speed = -1;
52913642Ssam 
53013642Ssam 	for (ps = spds; ps->sp_val; ps++)
53113642Ssam 		if (ps->sp_val == spwant)
53213642Ssam 			speed = ps->sp_name;
53317834Sralph 	ASSERT(speed >= 0, "BAD SPEED", CNULL, speed);
53417834Sralph #ifdef	USG
53523596Sbloom 	if (ioctl(tty, TCGETA, &ttbuf) < 0)
53623596Sbloom 		return FAIL;
53713642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
53813642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
53913642Ssam 	ttbuf.c_iflag = (ushort)0;
54013642Ssam 	ttbuf.c_oflag = (ushort)0;
54113642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
54213642Ssam 	ttbuf.c_lflag = (ushort)0;
54313642Ssam 	ttbuf.c_cc[VMIN] = 6;
54413642Ssam 	ttbuf.c_cc[VTIME] = 1;
54523596Sbloom 	if (ioctl(tty, TCSETA, &ttbuf) < 0)
54623596Sbloom 		return FAIL;
54717834Sralph #else	!USG
54823596Sbloom 	if (ioctl(tty, TIOCGETP, &ttbuf) < 0)
54923596Sbloom 		return FAIL;
55013642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
55113642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
55223596Sbloom 	if (ioctl(tty, TIOCSETP, &ttbuf) < 0)
55323596Sbloom 		return FAIL;
55413642Ssam #endif
55517834Sralph #ifndef	USG
55623596Sbloom 	if (ioctl(tty, TIOCHPCL, STBNULL) < 0)
55723596Sbloom 		return FAIL;
55823596Sbloom 	if (ioctl(tty, TIOCEXCL, STBNULL) < 0)
55923596Sbloom 		return FAIL;
56013642Ssam #endif
56117834Sralph 	linebaudrate = spwant;
56223596Sbloom 	return SUCCESS;
56313642Ssam }
56413642Ssam 
565*25705Sbloom /*
56625518Stef  *	getbaud(tty)	set linebaudrate variable
56725518Stef  *
56825518Stef  *	return codes:  none
56925518Stef  */
57025518Stef 
57125518Stef getbaud(tty)
57225518Stef int tty;
57325518Stef {
57425518Stef #ifdef	USG
57525518Stef 	struct termio ttbuf;
57625518Stef #else
57725518Stef 	struct sgttyb ttbuf;
57825518Stef #endif
57925518Stef 	register struct sg_spds *ps;
58025518Stef 	register int name;
58125518Stef 
58225518Stef 	if (IsTcpIp)
58325518Stef 		return;
58425518Stef #ifdef	USG
58525518Stef 	ioctl(tty, TCGETA, &ttbuf);
58625518Stef 	name = ttbuf.c_cflag & CBAUD;
58725518Stef #else
58825518Stef 	ioctl(tty, TIOCGETP, &ttbuf);
58925518Stef 	name = ttbuf.sg_ispeed;
59025518Stef #endif
59125518Stef 	for (ps = spds; ps->sp_val; ps++)
59225518Stef 		if (ps->sp_name == name) {
59325518Stef 			linebaudrate = ps->sp_val;
59425518Stef 			break;
59525518Stef 		}
59625518Stef }
59725518Stef 
59817834Sralph #define MR 100
59913642Ssam 
60018619Sralph /*
60118619Sralph  *	look for expected string
60213642Ssam  *
60313642Ssam  *	return codes:
60413642Ssam  *		0  -  found
60513642Ssam  *		FAIL  -  lost line or too many characters read
60613642Ssam  *		some character  -  timed out
60713642Ssam  */
60813642Ssam 
60913642Ssam expect(str, fn)
61013642Ssam register char *str;
61113642Ssam int fn;
61213642Ssam {
61314592Skarels 	char rdvec[MR];
61417834Sralph 	register char *rp = rdvec, *strptr;
61517834Sralph 	int kr, cnt_char;
61613642Ssam 	char nextch;
61725127Sbloom 	int timo = MAXMSGTIME;
61813642Ssam 
61917834Sralph 	if (*str == '\0' || strcmp(str, "\"\"") == SAME)
62017834Sralph 		return SUCCESS;
62117834Sralph 	/* Cleanup str, convert \0xx strings to one char  */
62217834Sralph 	for (strptr = str; *strptr; strptr++) {
62317834Sralph 		if (*strptr == '\\')
62417834Sralph 			switch(*++strptr) {
62517834Sralph 			case 's':
62617834Sralph 				DEBUG(5, "BLANK\n", CNULL);
62717834Sralph 				*strptr = ' ';
62817834Sralph 				break;
62917834Sralph 			default:
63017834Sralph 				strptr--;  /* back up to backslash */
63117834Sralph 				sscanf(strptr + 1,"%o", &cnt_char);
63217834Sralph 				DEBUG(6, "BACKSLASHED %02xH\n", cnt_char);
63317834Sralph 				*strptr = (char) (cnt_char);
63417834Sralph 				strcpy(&strptr[1], &strptr[4]);
63517834Sralph 			}
63617834Sralph 	}
63717834Sralph 
63825127Sbloom 	strptr = index(str, '~');
63925127Sbloom 	if (strptr != NULL) {
64025127Sbloom 		*strptr++ = '\0';
64125127Sbloom 		timo = atoi(strptr);
64225127Sbloom 		if (timo <= 0)
64325127Sbloom 			timo = MAXMSGTIME;
64425127Sbloom 	}
64525127Sbloom 
64617834Sralph 	if (setjmp(Sjbuf))
64717834Sralph 		return FAIL;
64813642Ssam 	signal(SIGALRM, alarmtr);
64925127Sbloom 	alarm(timo);
65025127Sbloom 	*rp = 0;
65113642Ssam 	while (notin(str, rdvec)) {
652*25705Sbloom 		int c;
65317834Sralph 		if(AbortOn != NULL && !notin(AbortOn, rdvec)) {
65417834Sralph 			DEBUG(1, "Call aborted on '%s'\n", AbortOn);
65517834Sralph 			alarm(0);
65617834Sralph 			return ABORT;
65717834Sralph 		}
65813642Ssam 		kr = read(fn, &nextch, 1);
65913642Ssam 		if (kr <= 0) {
66013642Ssam 			alarm(0);
66113642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
66213642Ssam 			logent("LOGIN", "LOST LINE");
66317834Sralph 			return FAIL;
66413642Ssam 		}
66513642Ssam 		c = nextch & 0177;
666*25705Sbloom 		if (c == '\0')
667*25705Sbloom 			continue;
668*25705Sbloom 		DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c);
669*25705Sbloom 		*rp++ = c;
67013642Ssam 		if (rp >= rdvec + MR) {
67117834Sralph 			register char *p;
67217834Sralph 			for (p = rdvec+MR/2; p < rp; p++)
67317834Sralph 				*(p-MR/2) = *p;
67417834Sralph 			rp -= MR/2;
67513642Ssam 		}
67613642Ssam 		*rp = '\0';
67713642Ssam 	}
67813642Ssam 	alarm(0);
67917834Sralph 	return SUCCESS;
68013642Ssam }
68113642Ssam 
68213642Ssam 
68313642Ssam /*
68413642Ssam  * Determine next file descriptor that would be allocated.
68513642Ssam  * This permits later closing of a file whose open was interrupted.
68613642Ssam  * It is a UNIX kernel problem, but it has to be handled.
68713642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
68813642Ssam  */
68913642Ssam getnextfd()
69013642Ssam {
69113642Ssam 	close(next_fd = open("/", 0));
69213642Ssam }
69313642Ssam 
69417834Sralph /*
69517834Sralph  *	send line of login sequence
69613642Ssam  *
69713642Ssam  *	return codes:  none
69813642Ssam  */
69913642Ssam sendthem(str, fn)
70013642Ssam register char *str;
70113642Ssam int fn;
70213642Ssam {
70313642Ssam 	register char *strptr;
70413642Ssam 	int i, n, cr = 1;
70517834Sralph 	register char c;
70613642Ssam 	static int p_init = 0;
70713642Ssam 
708*25705Sbloom 	DEBUG(5, "send \"%s\"\n", str);
70913642Ssam 
71013642Ssam 	if (!p_init) {
71113642Ssam 		p_init++;
71213642Ssam 		bld_partab(P_EVEN);
71313642Ssam 	}
71413642Ssam 
71513642Ssam 	if (prefix("BREAK", str)) {
71613642Ssam 		sscanf(&str[5], "%1d", &i);
71713642Ssam 		if (i <= 0 || i > 10)
71813642Ssam 			i = 3;
71913642Ssam 		/* send break */
72013642Ssam 		genbrk(fn, i);
72113642Ssam 		return;
72213642Ssam 	}
72313642Ssam 
72413642Ssam 	if (prefix("PAUSE", str)) {
72513642Ssam 		sscanf(&str[5], "%1d", &i);
72613642Ssam 		if (i <= 0 || i > 10)
72713642Ssam 			i = 3;
72813642Ssam 		/* pause for a while */
72913642Ssam 		sleep((unsigned)i);
73013642Ssam 		return;
73113642Ssam 	}
73213642Ssam 
73313642Ssam 	if (strcmp(str, "EOT") == SAME) {
73413642Ssam 		p_chwrite(fn, '\04');
73513642Ssam 		return;
73613642Ssam 	}
73713642Ssam 
73813642Ssam 	/* Send a '\n' */
739*25705Sbloom 	if (strcmp(str, "LF") == SAME) {
740*25705Sbloom 		p_chwrite(fn, '\n');
741*25705Sbloom 		return;
742*25705Sbloom 	}
74313642Ssam 
74413642Ssam 	/* Send a '\r' */
745*25705Sbloom 	if (strcmp(str, "CR") == SAME) {
746*25705Sbloom 		p_chwrite(fn, '\r');
747*25705Sbloom 		return;
748*25705Sbloom 	}
74913642Ssam 
75013642Ssam 	/* Set parity as needed */
75113642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
75213642Ssam 		bld_partab(P_ZERO);
75313642Ssam 		return;
75413642Ssam 	}
75513642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
75613642Ssam 		bld_partab(P_ONE);
75713642Ssam 		return;
75813642Ssam 	}
75913642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
76013642Ssam 		bld_partab(P_EVEN);
76113642Ssam 		return;
76213642Ssam 	}
76313642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
76413642Ssam 		bld_partab(P_ODD);
76513642Ssam 		return;
76613642Ssam 	}
76713642Ssam 
76813642Ssam 	/* If "", just send '\r' */
76917834Sralph 	if (strcmp(str, "\"\"") == SAME) {
77017834Sralph 		p_chwrite(fn, '\r');
77117834Sralph 		return;
77217834Sralph 	}
77317834Sralph 
774*25705Sbloom 	strptr = str;
775*25705Sbloom 	while ((c = *strptr++) != '\0') {
77617834Sralph 		if (c == '\\') {
77717834Sralph 			switch(*strptr++) {
778*25705Sbloom 			case '\0':
779*25705Sbloom 				DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL);
780*25705Sbloom 				--strptr;
781*25705Sbloom 				continue;
78217834Sralph 			case 's':
78317834Sralph 				DEBUG(5, "BLANK\n", CNULL);
784*25705Sbloom 				c = ' ';
78517834Sralph 				break;
78617834Sralph 			case 'd':
78717834Sralph 				DEBUG(5, "DELAY\n", CNULL);
78817834Sralph 				sleep(1);
78917834Sralph 				continue;
790*25705Sbloom 			case 'n':
791*25705Sbloom 				DEBUG(5, "NEW LINE\n", CNULL);
792*25705Sbloom 				c = '\n';
793*25705Sbloom 				break;
79417834Sralph 			case 'r':
79517834Sralph 				DEBUG(5, "RETURN\n", CNULL);
796*25705Sbloom 				c = '\r';
79717834Sralph 				break;
79817834Sralph 			case 'b':
79917834Sralph 				if (isdigit(*strptr)) {
80017834Sralph 					i = (*strptr++ - '0');
80117834Sralph 					if (i <= 0 || i > 10)
80217834Sralph 						i = 3;
80317834Sralph 				} else
80413642Ssam 					i = 3;
80517834Sralph 				/* send break */
80617834Sralph 				genbrk(fn, i);
80717834Sralph 				if (*strptr == '\0')
80817834Sralph 					cr = 0;
80913642Ssam 				continue;
81017834Sralph 			case 'c':
81117834Sralph 				if (*strptr == '\0') {
81217834Sralph 					DEBUG(5, "NO CR\n", CNULL);
81317834Sralph 					cr = 0;
814*25705Sbloom 				} else
815*25705Sbloom 					DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL);
81613642Ssam 				continue;
817*25705Sbloom #define isoctal(x)	((x >= '0') && (x <= '7'))
81817834Sralph 			default:
819*25705Sbloom 				if (isoctal(strptr[-1])) {
82017834Sralph 					i = 0;
82117834Sralph 					n = 0;
822*25705Sbloom 					--strptr;
823*25705Sbloom 					while (isoctal(*strptr) && ++n <= 3)
824*25705Sbloom 						i = i * 8 + (*strptr++ - '0');
825*25705Sbloom 					DEBUG(5, "\\%o\n", i);
82617834Sralph 					p_chwrite(fn, (char)i);
82717834Sralph 					continue;
82817834Sralph 				}
82913642Ssam 			}
830*25705Sbloom 		}
831*25705Sbloom 		p_chwrite(fn, c);
83213642Ssam 	}
83313642Ssam 
83413642Ssam 	if (cr)
83513642Ssam 		p_chwrite(fn, '\r');
83613642Ssam 	return;
83713642Ssam }
83813642Ssam 
83913642Ssam p_chwrite(fd, c)
84013642Ssam int fd;
84117834Sralph char c;
84213642Ssam {
84317834Sralph 	c = par_tab[c&0177];
84417834Sralph 	if (write(fd, &c, 1) != 1) {
84517834Sralph 		logent(sys_errlist[errno], "BAD WRITE");
84617834Sralph 		longjmp(Cjbuf, 2);
84717834Sralph 	}
84813642Ssam }
84913642Ssam 
85013642Ssam /*
85113642Ssam  * generate parity table for use by p_chwrite.
85213642Ssam  */
85313642Ssam bld_partab(type)
85413642Ssam int type;
85513642Ssam {
85613642Ssam 	register int i, j, n;
85713642Ssam 
85813642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
85913642Ssam 		n = 0;
86013642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
86113642Ssam 			n++;
86213642Ssam 		par_tab[i] = i;
86313642Ssam 		if (type == P_ONE
86413642Ssam 		 || (type == P_EVEN && (n&01) != 0)
86513642Ssam 		 || (type == P_ODD && (n&01) == 0))
86613642Ssam 			par_tab[i] |= sizeof(par_tab);
86713642Ssam 	}
86813642Ssam }
86913642Ssam 
87018619Sralph /*
87118619Sralph  *	check for occurrence of substring "sh"
87213642Ssam  *
87313642Ssam  *	return codes:
87413642Ssam  *		0  -  found the string
87513642Ssam  *		1  -  not in the string
87613642Ssam  */
87713642Ssam notin(sh, lg)
87813642Ssam register char *sh, *lg;
87913642Ssam {
88013642Ssam 	while (*lg != '\0') {
88113642Ssam 		if (wprefix(sh, lg))
88218619Sralph 			return 0;
88313642Ssam 		else
88413642Ssam 			lg++;
88513642Ssam 	}
88618619Sralph 	return 1;
88713642Ssam }
88813642Ssam 
88918619Sralph /*
89023596Sbloom  *	Allow multiple date specifications separated by ','.
89113642Ssam  */
89218619Sralph ifdate(p)
89318619Sralph register char *p;
89413642Ssam {
895*25705Sbloom 	register char *np;
89618619Sralph 	register int ret, g;
89723596Sbloom 	int rtime, i;
89813642Ssam 
89923596Sbloom 	/*  pick up retry time for failures  */
90023596Sbloom 	/*  global variable Retrytime is set here  */
90123596Sbloom 	if ((np = index(p, ';')) == NULL) {
90223596Sbloom 		Retrytime = RETRYTIME;
90323596Sbloom 	} else {
90423596Sbloom 		i = sscanf(np+1, "%d", &rtime);
90523596Sbloom 		if (i < 1 || rtime < 0)
90623596Sbloom 			rtime = 5;
90723596Sbloom 		Retrytime  = rtime * 60;
90823596Sbloom 	}
90923596Sbloom 
91018619Sralph 	ret = FAIL;
91118619Sralph 	MaxGrade = '\0';
91218619Sralph 	do {
91323596Sbloom 		np = strpbrk(p, ",|");	/* prefer , but allow | for compat */
91423596Sbloom 		if (np)
91523596Sbloom 			*np = '\0';
91618619Sralph 		g = ifadate(p);
91718619Sralph 		DEBUG(11,"ifadate returns %o\n", g);
91818619Sralph 		if (g != FAIL) {
91918619Sralph 			ret = SUCCESS;
92018619Sralph 			if (g > MaxGrade)
92118619Sralph 				MaxGrade = g;
92218619Sralph 		}
92323596Sbloom 		if (np)
92423596Sbloom 			*np = ',';
92523596Sbloom 		p = np + 1;
92623596Sbloom 	} while (np);
92723596Sbloom 	if (MaxGrade == '\0')
92823596Sbloom 		MaxGrade = DefMaxGrade;
92918619Sralph 	return ret;
93013642Ssam }
93113642Ssam 
93218619Sralph /*
93318619Sralph  *	this routine will check a string (string)
93413642Ssam  *	like "MoTu0800-1730" to see if the present
93513642Ssam  *	time is within the given limits.
93613642Ssam  *	SIDE EFFECT - Retrytime is set
93713642Ssam  *
93813642Ssam  *	return codes:
93913642Ssam  *		0  -  not within limits
94013642Ssam  *		1  -  within limits
94113642Ssam  */
94213642Ssam 
94318619Sralph ifadate(string)
94418619Sralph char *string;
94513642Ssam {
94613642Ssam 	static char *days[]={
94713642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
94813642Ssam 	};
94913642Ssam 	time_t clock;
95018619Sralph 	register char *s = string;
95117834Sralph 	int i, tl, th, tn, dayok=0;
95213642Ssam 	struct tm *localtime();
95313642Ssam 	struct tm *tp;
95418619Sralph 	char *p, MGrade;
95513642Ssam 
95623596Sbloom 	if ((p = index(s, '/')) == NULL)
95718619Sralph 		MGrade = DefMaxGrade;
95818619Sralph 	else
95918619Sralph 		MGrade = p[1];
96018619Sralph 
96113642Ssam 	time(&clock);
96213642Ssam 	tp = localtime(&clock);
96317834Sralph 	while (isascii(*s) && isalpha(*s)) {
96413642Ssam 		for (i = 0; days[i]; i++) {
96513642Ssam 			if (prefix(days[i], s))
96613642Ssam 				if (tp->tm_wday == i)
96713642Ssam 					dayok = 1;
96813642Ssam 		}
96913642Ssam 
97013642Ssam 		if (prefix("Wk", s))
97113642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
97213642Ssam 				dayok = 1;
97313642Ssam 		if (prefix("Any", s))
97413642Ssam 			dayok = 1;
97517834Sralph 		if (prefix("Evening", s)) {
97617834Sralph 			/* Sat or Sun */
97717834Sralph 			if (tp->tm_wday == 6 || tp->tm_wday == 0
97817834Sralph 				|| tp->tm_hour >= 17 || tp->tm_hour < 8)
97917834Sralph 					dayok = 1;
98017834Sralph 		}
98117834Sralph 		if (prefix("Night", s)) {
98217834Sralph 			if (tp->tm_wday == 6  /* Sat */
98318619Sralph 				|| tp->tm_hour >= 23 || tp->tm_hour < 8
98418619Sralph 					/* Sunday before 5pm */
98518619Sralph 				|| (tp->tm_wday == 0 && tp->tm_hour < 17))
98617834Sralph 					dayok = 1;
98717834Sralph 		}
988*25705Sbloom 		if (prefix("NonPeak", s)) { /* For Tymnet and PC Pursuit */
989*25705Sbloom 			/* Sat or Sun */
990*25705Sbloom 			if (tp->tm_wday == 6 || tp->tm_wday == 0
991*25705Sbloom 				|| tp->tm_hour >= 18 || tp->tm_hour < 7)
992*25705Sbloom 					dayok = 1;
993*25705Sbloom 		}
99413642Ssam 		s++;
99513642Ssam 	}
99613642Ssam 
99718619Sralph 	if (dayok == 0 && s != string)
99818619Sralph 		return FAIL;
99913642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
100018619Sralph   	if (i < 2)
100118619Sralph   		return MGrade;
100218619Sralph 	tn = tp->tm_hour * 100 + tp->tm_min;
100318619Sralph   	if (th < tl) { 		/* crosses midnight */
100418619Sralph   		if (tl <= tn || tn < th)
100518619Sralph   			return MGrade;
100618619Sralph   	} else
100718619Sralph 
100813642Ssam 	if (i < 2)
100918619Sralph 		return MGrade;
101018619Sralph 	if (th < tl) { 	/* crosses midnight */
101117834Sralph 		if (tl <= tn || tn < th)
101218619Sralph 			return MGrade;
101317834Sralph 	} else
101417834Sralph 		if (tl <= tn && tn < th)
101518619Sralph 			return MGrade;
101618619Sralph 	return FAIL;
101713642Ssam }
101813642Ssam 
101918619Sralph /*
102018619Sralph  *	find first digit in string
102113642Ssam  *
102213642Ssam  *	return - pointer to first digit in string or end of string
102313642Ssam  */
102413642Ssam char *
102513642Ssam fdig(cp)
102613642Ssam register char *cp;
102713642Ssam {
102813642Ssam 	register char *c;
102913642Ssam 
103013642Ssam 	for (c = cp; *c; c++)
103113642Ssam 		if (*c >= '0' && *c <= '9')
103213642Ssam 			break;
103317834Sralph 	return c;
103413642Ssam }
103513642Ssam 
103613642Ssam /*
103713642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
103813642Ssam  * Strings are compared as if they contain all capital letters.
103913642Ssam  */
104013642Ssam snccmp(s1, s2)
104113642Ssam register char *s1, *s2;
104213642Ssam {
104313642Ssam 	char c1, c2;
104413642Ssam 
104525127Sbloom 	if (islower(*s1))
104625127Sbloom 		c1 = toupper(*s1);
104725127Sbloom 	else
104825127Sbloom 		c1 = *s1;
104925127Sbloom 	if (islower(*s2))
105025127Sbloom 		c2 = toupper(*s2);
105125127Sbloom 	else
105225127Sbloom 		c2 = *s2;
105313642Ssam 
105413642Ssam 	while (c1 == c2) {
105525127Sbloom 		if (*s1++ == '\0')
105617834Sralph 			return 0;
105713642Ssam 		s2++;
105825127Sbloom 		if (islower(*s1))
105925127Sbloom 			c1 = toupper(*s1);
106025127Sbloom 		else
106125127Sbloom 			c1 = *s1;
106225127Sbloom 		if (islower(*s2))
106325127Sbloom 			c2 = toupper(*s2);
106425127Sbloom 		else
106525127Sbloom 			c2 = *s2;
106613642Ssam 	}
106717834Sralph 	return c1 - c2;
106813642Ssam }
106925127Sbloom 
107017834Sralph /*
107125127Sbloom  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
107225127Sbloom  * Strings are compared as if they contain all capital letters.
107325127Sbloom  */
107425127Sbloom sncncmp(s1, s2, n)
107525127Sbloom register char *s1, *s2;
107625127Sbloom register int n;
107725127Sbloom {
107825127Sbloom 	char c1, c2;
107925127Sbloom 
108025127Sbloom 	if (islower(*s1))
108125127Sbloom 		c1 = toupper(*s1);
108225127Sbloom 	else
108325127Sbloom 		c1 = *s1;
108425127Sbloom 	if (islower(*s2))
108525127Sbloom 		c2 = toupper(*s2);
108625127Sbloom 	else
108725127Sbloom 		c2 = *s2;
108825127Sbloom 
108925127Sbloom 	while ( --n >= 0 && c1 == c2) {
109025127Sbloom 		if (*s1++ == '\0')
109125127Sbloom 			return 0;
109225127Sbloom 		s2++;
109325127Sbloom 		if (islower(*s1))
109425127Sbloom 			c1 = toupper(*s1);
109525127Sbloom 		else
109625127Sbloom 			c1 = *s1;
109725127Sbloom 		if (islower(*s2))
109825127Sbloom 			c2 = toupper(*s2);
109925127Sbloom 		else
110025127Sbloom 			c2 = *s2;
110125127Sbloom 	}
110225127Sbloom 	return n<0 ? 0 : (c1 - c2);
110325127Sbloom }
110425127Sbloom /*
110517834Sralph  * do chat script
110617834Sralph  * occurs after local port is opened,
110717834Sralph  * before 'dialing' the other machine.
110817834Sralph  */
110917834Sralph dochat(dev, flds, fd)
111017834Sralph register struct Devices *dev;
111117834Sralph char *flds[];
111217834Sralph int fd;
111317834Sralph {
111417834Sralph 	register int i;
111517834Sralph 	register char *p;
111617834Sralph 	char bfr[sizeof(dev->D_argbfr)];
111717834Sralph 
111817834Sralph 	if (dev->D_numargs <= 5)
111917834Sralph 		return(0);
112017834Sralph 	DEBUG(4, "dochat called %d\n", dev->D_numargs);
112117834Sralph 	for (i = 0; i < dev->D_numargs-5; i++) {
112217834Sralph 		sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]);
112317834Sralph 		if (strcmp(bfr, dev->D_arg[D_CHAT+i])) {
112417834Sralph 			p = malloc((unsigned)strlen(bfr)+1);
112517834Sralph 			if (p != NULL) {
112617834Sralph 				strcpy(p, bfr);
112717834Sralph 				dev->D_arg[D_CHAT+i] = p;
112817834Sralph 			}
112917834Sralph 		}
113017834Sralph 	}
113117834Sralph 	/* following is a kludge because login() arglist is a kludge */
113217834Sralph 	i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd);
113317834Sralph 	/*
113417834Sralph 	 * If login() last did a sendthem(), must pause so things can settle.
113517834Sralph 	 * But don't bother if chat failed.
113617834Sralph 	 */
113717834Sralph 	if (i == 0 && (dev->D_numargs&01))
113817834Sralph 		sleep(2);
113917834Sralph 	return(i);
114017834Sralph }
1141*25705Sbloom 
1142*25705Sbloom /*
1143*25705Sbloom  *	fix kill/echo/raw on line
1144*25705Sbloom  *
1145*25705Sbloom  *	return codes:  none
1146*25705Sbloom  */
1147*25705Sbloom fixmode(tty)
1148*25705Sbloom register int tty;
1149*25705Sbloom {
1150*25705Sbloom #ifdef	USG
1151*25705Sbloom 	struct termio ttbuf;
1152*25705Sbloom #else	!USG
1153*25705Sbloom 	struct sgttyb ttbuf;
1154*25705Sbloom #endif	!USG
1155*25705Sbloom 	register struct sg_spds *ps;
1156*25705Sbloom 	int speed;
1157*25705Sbloom 
1158*25705Sbloom 	if (IsTcpIp)
1159*25705Sbloom 		return;
1160*25705Sbloom #ifdef	USG
1161*25705Sbloom 	ioctl(tty, TCGETA, &ttbuf);
1162*25705Sbloom 	ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0;
1163*25705Sbloom 	speed = ttbuf.c_cflag &= (CBAUD);
1164*25705Sbloom 	ttbuf.c_cflag |= (CS8|CREAD);
1165*25705Sbloom 	ttbuf.c_cc[VMIN] = 6;
1166*25705Sbloom 	ttbuf.c_cc[VTIME] = 1;
1167*25705Sbloom 	ioctl(tty, TCSETA, &ttbuf);
1168*25705Sbloom #else	!USG
1169*25705Sbloom 	ioctl(tty, TIOCGETP, &ttbuf);
1170*25705Sbloom 	ttbuf.sg_flags = (ANYP | RAW);
1171*25705Sbloom 	ioctl(tty, TIOCSETP, &ttbuf);
1172*25705Sbloom 	speed = ttbuf.sg_ispeed;
1173*25705Sbloom 	ioctl(tty, TIOCEXCL, STBNULL);
1174*25705Sbloom #endif	!USG
1175*25705Sbloom 
1176*25705Sbloom 	for (ps = spds; ps->sp_val; ps++)
1177*25705Sbloom 		if (ps->sp_name == speed) {
1178*25705Sbloom 			linebaudrate = ps->sp_val;
1179*25705Sbloom 			DEBUG(9,"Incoming baudrate is %d\n", linebaudrate);
1180*25705Sbloom 			return;
1181*25705Sbloom 		}
1182*25705Sbloom 	ASSERT(linebaudrate >= 0, "BAD SPEED", CNULL, speed);
1183*25705Sbloom }
1184*25705Sbloom 
1185