xref: /csrg-svn/usr.bin/uucp/uucico/conn.c (revision 13642)
1*13642Ssam #ifndef lint
2*13642Ssam static char sccsid[] = "@(#)conn.c	5.1 (Berkeley) 07/02/83";
3*13642Ssam #endif
4*13642Ssam 
5*13642Ssam #include "uucp.h"
6*13642Ssam #include <signal.h>
7*13642Ssam #include <setjmp.h>
8*13642Ssam #include <ctype.h>
9*13642Ssam #include <sys/types.h>
10*13642Ssam #include <time.h>
11*13642Ssam #include <errno.h>
12*13642Ssam #ifdef	SYSIII
13*13642Ssam #include <termio.h>
14*13642Ssam #include <fcntl.h>
15*13642Ssam #endif
16*13642Ssam #ifndef	SYSIII
17*13642Ssam #include <sgtty.h>
18*13642Ssam #endif
19*13642Ssam 
20*13642Ssam #define MAXC 1000
21*13642Ssam 
22*13642Ssam extern jmp_buf Sjbuf;
23*13642Ssam extern int errno;
24*13642Ssam 
25*13642Ssam /* Parity control during login procedure */
26*13642Ssam #define	P_ZERO	0
27*13642Ssam #define	P_ONE	1
28*13642Ssam #define	P_EVEN	2
29*13642Ssam #define	P_ODD	3
30*13642Ssam char	par_tab[128];	/* must be power of two */
31*13642Ssam 
32*13642Ssam int next_fd = -1;	/* predicted fd to close interrupted opens */
33*13642Ssam 				/* rti!trt, courtesy unc!smb */
34*13642Ssam /***
35*13642Ssam  *	alarmtr()  -  catch alarm routine for "expect".
36*13642Ssam  */
37*13642Ssam alarmtr()
38*13642Ssam {
39*13642Ssam 	signal(SIGALRM, alarmtr);
40*13642Ssam 	if (next_fd >= 0) {
41*13642Ssam 		if (close(next_fd))
42*13642Ssam 			logent("FAIL", "ACU LINE CLOSE");
43*13642Ssam 		next_fd = -1;
44*13642Ssam 	}
45*13642Ssam 	longjmp(Sjbuf, 1);
46*13642Ssam }
47*13642Ssam 
48*13642Ssam /*******
49*13642Ssam  *	conn(system)
50*13642Ssam  *	char *system;
51*13642Ssam  *
52*13642Ssam  *	conn - place a telephone call to system and
53*13642Ssam  *	login, etc.
54*13642Ssam  *
55*13642Ssam  *	return codes:
56*13642Ssam  *		CF_SYSTEM: don't know system
57*13642Ssam  *		CF_TIME: wrong time to call
58*13642Ssam  *		CF_DIAL: call failed
59*13642Ssam  *		CF_NODEV: no devices available to place call
60*13642Ssam  *		CF_LOGIN: login/password dialog failed
61*13642Ssam  *
62*13642Ssam  *		>0  - file no.  -  connect ok
63*13642Ssam  *
64*13642Ssam  */
65*13642Ssam 
66*13642Ssam int Dcf = -1;
67*13642Ssam 
68*13642Ssam conn(system)
69*13642Ssam char *system;
70*13642Ssam {
71*13642Ssam 	int ret, nf;
72*13642Ssam 	register int fn, fnd;
73*13642Ssam 	char info[MAXC], *flds[MAXC/10];
74*13642Ssam 	register FILE *fsys;
75*13642Ssam 	int fcode = 0;
76*13642Ssam 
77*13642Ssam 	nf = 0;
78*13642Ssam 	fnd = 0;
79*13642Ssam 
80*13642Ssam 
81*13642Ssam 	fsys = fopen(SYSFILE, "r");
82*13642Ssam 	ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
83*13642Ssam 
84*13642Ssam 	DEBUG(4, "finds %s\n", "called");
85*13642Ssam 	while((nf = finds(fsys, system, info, flds)) > 0) {
86*13642Ssam 		DEBUG(4, "getto %s\n", "called");
87*13642Ssam 		if ((fn = getto(flds)) > 0) {
88*13642Ssam 			fnd = 1;
89*13642Ssam 			Dcf = fn;
90*13642Ssam 			break;
91*13642Ssam 		}
92*13642Ssam 		fcode = (fn == FAIL ? CF_DIAL : fn);
93*13642Ssam 	}
94*13642Ssam 	fclose(fsys);
95*13642Ssam 
96*13642Ssam 	if (nf <= 0)
97*13642Ssam 		return(fcode ? fcode : nf);
98*13642Ssam 
99*13642Ssam 	DEBUG(4, "login %s\n", "called");
100*13642Ssam 	ret = login(nf, flds, fn);
101*13642Ssam 	if (ret < 0) {
102*13642Ssam 		clsacu();
103*13642Ssam 		return(CF_LOGIN);
104*13642Ssam 	}
105*13642Ssam 	/* rti!trt:  avoid passing file to children */
106*13642Ssam 	fioclex(fn);
107*13642Ssam 	return(fn);
108*13642Ssam }
109*13642Ssam 
110*13642Ssam /***
111*13642Ssam  *	getto(flds)		connect to remote machine
112*13642Ssam  *	char *flds[];
113*13642Ssam  *
114*13642Ssam  *	return codes:
115*13642Ssam  *		>0  -  file number - ok
116*13642Ssam  *		FAIL  -  failed
117*13642Ssam  */
118*13642Ssam 
119*13642Ssam getto(flds)
120*13642Ssam register char *flds[];
121*13642Ssam {
122*13642Ssam 	register struct condev *cd;
123*13642Ssam 	int nulldev(), diropn();
124*13642Ssam 
125*13642Ssam 	DEBUG(4, "call: no. %s ", flds[F_PHONE]);
126*13642Ssam 	DEBUG(4, "for sys %s\n", flds[F_NAME]);
127*13642Ssam 
128*13642Ssam 	CU_end = nulldev;
129*13642Ssam 	for (cd = condevs; cd->CU_meth != NULL; cd++) {
130*13642Ssam 		if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) {
131*13642Ssam 			DEBUG(4, "Using %s to call\n", cd->CU_meth);
132*13642Ssam 			return((*(cd->CU_gen))(flds));
133*13642Ssam 			}
134*13642Ssam 		}
135*13642Ssam 	logent(flds[F_LINE], "getto: Can't find, using DIR");
136*13642Ssam 	return(diropn(flds));	/* search failed, so use direct */
137*13642Ssam 	}
138*13642Ssam 
139*13642Ssam /***
140*13642Ssam  *	clsacu()	close call unit
141*13642Ssam  *
142*13642Ssam  *	return codes:  none
143*13642Ssam  */
144*13642Ssam 
145*13642Ssam int (*CU_end)() = nulldev;
146*13642Ssam clsacu()
147*13642Ssam {
148*13642Ssam 	(*(CU_end))(Dcf);
149*13642Ssam 	if (close(Dcf) == 0) {
150*13642Ssam 		DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf);
151*13642Ssam 		logent("clsacu", "NOT CLOSED by CU_clos");
152*13642Ssam 	}
153*13642Ssam 	Dcf = -1;
154*13642Ssam 	CU_end = nulldev;
155*13642Ssam }
156*13642Ssam 
157*13642Ssam /***
158*13642Ssam  *	exphone - expand phone number for given prefix and number
159*13642Ssam  *
160*13642Ssam  *	return code - none
161*13642Ssam  */
162*13642Ssam 
163*13642Ssam exphone(in, out)
164*13642Ssam register char *in, *out;
165*13642Ssam {
166*13642Ssam 	FILE *fn;
167*13642Ssam 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
168*13642Ssam 	char buf[BUFSIZ];
169*13642Ssam 	register char *s1;
170*13642Ssam 
171*13642Ssam 	if (!isalpha(*in)) {
172*13642Ssam 		strcpy(out, in);
173*13642Ssam 		return;
174*13642Ssam 	}
175*13642Ssam 
176*13642Ssam 	s1=pre;
177*13642Ssam 	while (isalpha(*in))
178*13642Ssam 		*s1++ = *in++;
179*13642Ssam 	*s1 = '\0';
180*13642Ssam 	s1 = npart;
181*13642Ssam 	while (*in != '\0')
182*13642Ssam 		*s1++ = *in++;
183*13642Ssam 	*s1 = '\0';
184*13642Ssam 
185*13642Ssam 	tpre[0] = '\0';
186*13642Ssam 	if ((fn = fopen(DIALFILE, "r")) == NULL)
187*13642Ssam 		DEBUG(2, "CAN'T OPEN %s\n", DIALFILE);
188*13642Ssam 	else {
189*13642Ssam 		while (cfgets(buf, BUFSIZ, fn)) {
190*13642Ssam 			sscanf(buf, "%s%s", p, tpre);
191*13642Ssam 			if (strcmp(p, pre) == SAME)
192*13642Ssam 				goto found;
193*13642Ssam 			tpre[0] = '\0';
194*13642Ssam 		}
195*13642Ssam 		DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre);
196*13642Ssam 	found:;
197*13642Ssam 		fclose(fn);
198*13642Ssam 	}
199*13642Ssam 
200*13642Ssam 	strcpy(out, tpre);
201*13642Ssam 	strcat(out, npart);
202*13642Ssam 	return;
203*13642Ssam }
204*13642Ssam 
205*13642Ssam /***
206*13642Ssam  *	rddev - read and decode a line from device file
207*13642Ssam  *
208*13642Ssam  *	return code - FAIL at end-of file; 0 otherwise
209*13642Ssam  */
210*13642Ssam 
211*13642Ssam rddev(fp, dev)
212*13642Ssam register struct Devices *dev;
213*13642Ssam FILE *fp;
214*13642Ssam {
215*13642Ssam 	char *fdig();
216*13642Ssam 	char buf[BUFSIZ];
217*13642Ssam 	int na;
218*13642Ssam 
219*13642Ssam 	if (!cfgets(buf, BUFSIZ, fp))
220*13642Ssam 		return(FAIL);
221*13642Ssam 
222*13642Ssam 	na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line,
223*13642Ssam 	  dev->D_calldev, dev->D_class, dev->D_brand);
224*13642Ssam 	ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0);
225*13642Ssam 	if (na != 5) dev->D_brand[0] = '\0';
226*13642Ssam 	dev->D_speed = atoi(fdig(dev->D_class));
227*13642Ssam 	return(0);
228*13642Ssam }
229*13642Ssam 
230*13642Ssam /***
231*13642Ssam  *	finds(fsys, sysnam, info, flds)	set system attribute vector
232*13642Ssam  *
233*13642Ssam  *	return codes:
234*13642Ssam  *		>0  -  number of arguments in vector - succeeded
235*13642Ssam  *		CF_SYSTEM  -  system name not found
236*13642Ssam  *		CF_TIME  -  wrong time to call
237*13642Ssam  */
238*13642Ssam 
239*13642Ssam finds(fsys, sysnam, info, flds)
240*13642Ssam char *sysnam, info[], *flds[];
241*13642Ssam FILE *fsys;
242*13642Ssam {
243*13642Ssam 	char sysn[8];
244*13642Ssam 	int na;
245*13642Ssam 	int fcode = 0;
246*13642Ssam 
247*13642Ssam 	/* format of fields
248*13642Ssam 	 *	0 name;
249*13642Ssam 	 *	1 time
250*13642Ssam 	 *	2 acu/hardwired
251*13642Ssam 	 *	3 speed
252*13642Ssam 	 *	etc
253*13642Ssam 	 */
254*13642Ssam 	while (cfgets(info, MAXC, fsys) != NULL) {
255*13642Ssam 		na = getargs(info, flds);
256*13642Ssam 		sprintf(sysn, "%.7s", flds[F_NAME]);
257*13642Ssam 		if (strcmp(sysnam, sysn) != SAME)
258*13642Ssam 			continue;
259*13642Ssam 		if (ifdate(flds[F_TIME]))
260*13642Ssam 			/*  found a good entry  */
261*13642Ssam 			return(na);
262*13642Ssam 		DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]);
263*13642Ssam 		fcode = CF_TIME;
264*13642Ssam 	}
265*13642Ssam 	return(fcode ? fcode : CF_SYSTEM);
266*13642Ssam }
267*13642Ssam 
268*13642Ssam /***
269*13642Ssam  *	login(nf, flds, dcr)		do login conversation
270*13642Ssam  *	char *flds[];
271*13642Ssam  *	int nf;
272*13642Ssam  *
273*13642Ssam  *	return codes:  0  |  FAIL
274*13642Ssam  */
275*13642Ssam 
276*13642Ssam login(nf, flds, fn)
277*13642Ssam register char *flds[];
278*13642Ssam int nf, fn;
279*13642Ssam {
280*13642Ssam 	register char *want, *altern;
281*13642Ssam 	extern char *index();
282*13642Ssam 	int k, ok;
283*13642Ssam 
284*13642Ssam 	ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf);
285*13642Ssam 	for (k = F_LOGIN; k < nf; k += 2) {
286*13642Ssam 		want = flds[k];
287*13642Ssam 		ok = FAIL;
288*13642Ssam 		while (ok != 0) {
289*13642Ssam 			altern = index(want, '-');
290*13642Ssam 			if (altern != NULL)
291*13642Ssam 				*altern++ = '\0';
292*13642Ssam 			DEBUG(4, "wanted %s ", want);
293*13642Ssam 			ok = expect(want, fn);
294*13642Ssam 			DEBUG(4, "got %s\n", ok ? "?" : "that");
295*13642Ssam 			if (ok == 0)
296*13642Ssam 				break;
297*13642Ssam 			if (altern == NULL) {
298*13642Ssam 				logent("LOGIN", "FAILED");
299*13642Ssam 				/* close *not* needed here. rti!trt */
300*13642Ssam 				return(FAIL);
301*13642Ssam 			}
302*13642Ssam 			want = index(altern, '-');
303*13642Ssam 			if (want != NULL)
304*13642Ssam 				*want++ = '\0';
305*13642Ssam 			sendthem(altern, fn);
306*13642Ssam 		}
307*13642Ssam 		sleep(2);
308*13642Ssam 		if (k+1 < nf)
309*13642Ssam 			sendthem(flds[k+1], fn);
310*13642Ssam 	}
311*13642Ssam 	return(0);
312*13642Ssam }
313*13642Ssam 
314*13642Ssam 
315*13642Ssam /* rti!trt: conditional table generation to support odd speeds */
316*13642Ssam /* Suggested in n44a.139 by n44!dan (Dan Ts'o) */
317*13642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = {
318*13642Ssam #ifdef B50
319*13642Ssam 	{  50,	 B50},
320*13642Ssam #endif
321*13642Ssam #ifdef B75
322*13642Ssam 	{  75,	 B75},
323*13642Ssam #endif
324*13642Ssam #ifdef B110
325*13642Ssam 	{ 110,	B110},
326*13642Ssam #endif
327*13642Ssam #ifdef B150
328*13642Ssam 	{ 150,	B150},
329*13642Ssam #endif
330*13642Ssam #ifdef B200
331*13642Ssam 	{ 200,	B200},
332*13642Ssam #endif
333*13642Ssam #ifdef B300
334*13642Ssam 	{ 300,  B300},
335*13642Ssam #endif
336*13642Ssam #ifdef B600
337*13642Ssam 	{600,	B600},
338*13642Ssam #endif
339*13642Ssam #ifdef B1200
340*13642Ssam 	{1200, B1200},
341*13642Ssam #endif
342*13642Ssam #ifdef B1800
343*13642Ssam 	{1800, B1800},
344*13642Ssam #endif
345*13642Ssam #ifdef B2000
346*13642Ssam 	{2000, B2000},
347*13642Ssam #endif
348*13642Ssam #ifdef B2400
349*13642Ssam 	{2400, B2400},
350*13642Ssam #endif
351*13642Ssam #ifdef B3600
352*13642Ssam 	{3600, B3600},
353*13642Ssam #endif
354*13642Ssam #ifdef B4800
355*13642Ssam 	{4800, B4800},
356*13642Ssam #endif
357*13642Ssam #ifdef B7200
358*13642Ssam 	{7200, B7200},
359*13642Ssam #endif
360*13642Ssam #ifdef B9600
361*13642Ssam 	{9600, B9600},
362*13642Ssam #endif
363*13642Ssam #ifdef B19200
364*13642Ssam 	{19200,B19200},
365*13642Ssam #endif
366*13642Ssam 	{0, 0}
367*13642Ssam };
368*13642Ssam 
369*13642Ssam /***
370*13642Ssam  *	fixline(tty, spwant)	set speed/echo/mode...
371*13642Ssam  *	int tty, spwant;
372*13642Ssam  *
373*13642Ssam  *	return codes:  none
374*13642Ssam  */
375*13642Ssam 
376*13642Ssam fixline(tty, spwant)
377*13642Ssam int tty, spwant;
378*13642Ssam {
379*13642Ssam #ifdef	SYSIII
380*13642Ssam 	struct termio ttbuf;
381*13642Ssam #endif
382*13642Ssam #ifndef	SYSIII
383*13642Ssam 	struct sgttyb ttbuf;
384*13642Ssam #endif
385*13642Ssam 	register struct sg_spds *ps;
386*13642Ssam 	int speed = -1;
387*13642Ssam 	int ret;
388*13642Ssam 
389*13642Ssam 	for (ps = spds; ps->sp_val; ps++)
390*13642Ssam 		if (ps->sp_val == spwant)
391*13642Ssam 			speed = ps->sp_name;
392*13642Ssam 	ASSERT(speed >= 0, "BAD SPEED", "", speed);
393*13642Ssam #ifdef	SYSIII
394*13642Ssam 	ioctl(tty, TCGETA, &ttbuf);
395*13642Ssam 	/* ttbuf.sg_flags = (ANYP|RAW);
396*13642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
397*13642Ssam 	ttbuf.c_iflag = (ushort)0;
398*13642Ssam 	ttbuf.c_oflag = (ushort)0;
399*13642Ssam 	ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
400*13642Ssam 	ttbuf.c_lflag = (ushort)0;
401*13642Ssam 	ttbuf.c_cc[VMIN] = 6;
402*13642Ssam 	ttbuf.c_cc[VTIME] = 1;
403*13642Ssam 	ret = ioctl(tty, TCSETA, &ttbuf);
404*13642Ssam #endif
405*13642Ssam #ifndef	SYSIII
406*13642Ssam 	ioctl(tty, TIOCGETP, &ttbuf);
407*13642Ssam 	ttbuf.sg_flags = (ANYP|RAW);
408*13642Ssam 	ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
409*13642Ssam 	ret = ioctl(tty, TIOCSETP, &ttbuf);
410*13642Ssam #endif
411*13642Ssam 	ASSERT(ret >= 0, "RETURN FROM STTY", "", ret);
412*13642Ssam #ifndef	SYSIII
413*13642Ssam 	ioctl(tty, TIOCHPCL, STBNULL);
414*13642Ssam 	ioctl(tty, TIOCEXCL, STBNULL);
415*13642Ssam #endif
416*13642Ssam 	return;
417*13642Ssam }
418*13642Ssam 
419*13642Ssam 
420*13642Ssam /* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */
421*13642Ssam /* Actually, the 'expect' algorithm should be rewritten. */
422*13642Ssam #define MR 1000
423*13642Ssam 
424*13642Ssam 
425*13642Ssam /***
426*13642Ssam  *	expect(str, fn)	look for expected string
427*13642Ssam  *	char *str;
428*13642Ssam  *
429*13642Ssam  *	return codes:
430*13642Ssam  *		0  -  found
431*13642Ssam  *		FAIL  -  lost line or too many characters read
432*13642Ssam  *		some character  -  timed out
433*13642Ssam  */
434*13642Ssam 
435*13642Ssam expect(str, fn)
436*13642Ssam register char *str;
437*13642Ssam int fn;
438*13642Ssam {
439*13642Ssam 	static char rdvec[MR];
440*13642Ssam 	register char *rp = rdvec;
441*13642Ssam 	int kr;
442*13642Ssam 	char nextch;
443*13642Ssam 
444*13642Ssam 	if (strcmp(str, "\"\"") == SAME)
445*13642Ssam 		return(0);
446*13642Ssam 	*rp = 0;
447*13642Ssam 	if (setjmp(Sjbuf)) {
448*13642Ssam 		return(FAIL);
449*13642Ssam 	}
450*13642Ssam 	signal(SIGALRM, alarmtr);
451*13642Ssam /* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */
452*13642Ssam 	alarm(MAXMSGTIME);
453*13642Ssam 	while (notin(str, rdvec)) {
454*13642Ssam 		kr = read(fn, &nextch, 1);
455*13642Ssam 		if (kr <= 0) {
456*13642Ssam 			alarm(0);
457*13642Ssam 			DEBUG(4, "lost line kr - %d\n, ", kr);
458*13642Ssam 			logent("LOGIN", "LOST LINE");
459*13642Ssam 			return(FAIL);
460*13642Ssam 		}
461*13642Ssam 		{
462*13642Ssam 		int c;
463*13642Ssam 		c = nextch & 0177;
464*13642Ssam 		DEBUG(4, c >= 040 ? "%c" : "\\%03o", c);
465*13642Ssam 		}
466*13642Ssam 		if ((*rp = nextch & 0177) != '\0')
467*13642Ssam 			rp++;
468*13642Ssam /* Check rdvec before null termination -- cmcl2!salkind */
469*13642Ssam 		if (rp >= rdvec + MR) {
470*13642Ssam 			alarm(0);
471*13642Ssam 			return(FAIL);
472*13642Ssam 		}
473*13642Ssam 		*rp = '\0';
474*13642Ssam 	}
475*13642Ssam 	alarm(0);
476*13642Ssam 	return(0);
477*13642Ssam }
478*13642Ssam 
479*13642Ssam 
480*13642Ssam /*
481*13642Ssam  * Determine next file descriptor that would be allocated.
482*13642Ssam  * This permits later closing of a file whose open was interrupted.
483*13642Ssam  * It is a UNIX kernel problem, but it has to be handled.
484*13642Ssam  * unc!smb (Steve Bellovin) probably first discovered it.
485*13642Ssam  */
486*13642Ssam getnextfd()
487*13642Ssam {
488*13642Ssam 	close(next_fd = open("/", 0));
489*13642Ssam }
490*13642Ssam 
491*13642Ssam /***
492*13642Ssam  *	sendthem(str, fn)	send line of login sequence
493*13642Ssam  *	char *str;
494*13642Ssam  *
495*13642Ssam  *	return codes:  none
496*13642Ssam  */
497*13642Ssam 
498*13642Ssam sendthem(str, fn)
499*13642Ssam register char *str;
500*13642Ssam int fn;
501*13642Ssam {
502*13642Ssam 	register char *strptr;
503*13642Ssam 	int i, n, cr = 1;
504*13642Ssam 	static int p_init = 0;
505*13642Ssam 
506*13642Ssam 	/* Note: debugging authorized only for privileged users */
507*13642Ssam 	DEBUG(5, "send %s\n", str);
508*13642Ssam 
509*13642Ssam 	if (!p_init) {
510*13642Ssam 		p_init++;
511*13642Ssam 		bld_partab(P_EVEN);
512*13642Ssam 	}
513*13642Ssam 
514*13642Ssam 	if (prefix("BREAK", str)) {
515*13642Ssam 		sscanf(&str[5], "%1d", &i);
516*13642Ssam 		if (i <= 0 || i > 10)
517*13642Ssam 			i = 3;
518*13642Ssam 		/* send break */
519*13642Ssam 		genbrk(fn, i);
520*13642Ssam 		return;
521*13642Ssam 	}
522*13642Ssam 
523*13642Ssam 	if (prefix("PAUSE", str)) {
524*13642Ssam 		sscanf(&str[5], "%1d", &i);
525*13642Ssam 		if (i <= 0 || i > 10)
526*13642Ssam 			i = 3;
527*13642Ssam 		/* pause for a while */
528*13642Ssam 		sleep((unsigned)i);
529*13642Ssam 		return;
530*13642Ssam 	}
531*13642Ssam 
532*13642Ssam 	if (strcmp(str, "EOT") == SAME) {
533*13642Ssam 		p_chwrite(fn, '\04');
534*13642Ssam 		return;
535*13642Ssam 	}
536*13642Ssam 
537*13642Ssam 	/* LF, CR, and "" courtesy unc!smb */
538*13642Ssam 	/* Send a '\n' */
539*13642Ssam 	if (strcmp(str, "LF") == SAME)
540*13642Ssam 		str = "\\n\\c";
541*13642Ssam 
542*13642Ssam 	/* Send a '\r' */
543*13642Ssam 	if (strcmp(str, "CR") == SAME)
544*13642Ssam 		str = "\\r\\c";
545*13642Ssam 
546*13642Ssam 	/* Set parity as needed */
547*13642Ssam 	if (strcmp(str, "P_ZERO") == SAME) {
548*13642Ssam 		bld_partab(P_ZERO);
549*13642Ssam 		return;
550*13642Ssam 	}
551*13642Ssam 	if (strcmp(str, "P_ONE") == SAME) {
552*13642Ssam 		bld_partab(P_ONE);
553*13642Ssam 		return;
554*13642Ssam 	}
555*13642Ssam 	if (strcmp(str, "P_EVEN") == SAME) {
556*13642Ssam 		bld_partab(P_EVEN);
557*13642Ssam 		return;
558*13642Ssam 	}
559*13642Ssam 	if (strcmp(str, "P_ODD") == SAME) {
560*13642Ssam 		bld_partab(P_ODD);
561*13642Ssam 		return;
562*13642Ssam 	}
563*13642Ssam 
564*13642Ssam 	/* If "", just send '\r' */
565*13642Ssam 	if (strcmp(str, "\"\"") != SAME)
566*13642Ssam 	for (strptr = str; *strptr; strptr++) {
567*13642Ssam 		if (*strptr == '\\') switch(*++strptr) {
568*13642Ssam 		case 's':
569*13642Ssam 			DEBUG(5, "BLANK\n", "");
570*13642Ssam 			*strptr = ' ';
571*13642Ssam 			break;
572*13642Ssam 		case 'd':
573*13642Ssam 			DEBUG(5, "DELAY\n", "");
574*13642Ssam 			sleep(1);
575*13642Ssam 			continue;
576*13642Ssam 		case 'r':
577*13642Ssam 			DEBUG(5, "RETURN\n", "");
578*13642Ssam 			*strptr = '\r';
579*13642Ssam 			break;
580*13642Ssam 		case 'b':
581*13642Ssam 			if (isdigit(*(strptr+1))) {
582*13642Ssam 				i = (*++strptr - '0');
583*13642Ssam 				if (i <= 0 || i > 10)
584*13642Ssam 					i = 3;
585*13642Ssam 			} else
586*13642Ssam 				i = 3;
587*13642Ssam 			/* send break */
588*13642Ssam 			genbrk(fn, i);
589*13642Ssam 			continue;
590*13642Ssam 		case 'c':
591*13642Ssam 			if (*(strptr+1) == '\0') {
592*13642Ssam 			DEBUG(5, "NO CR\n", "");
593*13642Ssam 				cr = 0;
594*13642Ssam 				continue;
595*13642Ssam 			}
596*13642Ssam 			DEBUG(5, "NO CR - MIDDLE IGNORED\n", "");
597*13642Ssam 			continue;
598*13642Ssam 		default:
599*13642Ssam 			if (isdigit(strptr[1])) {
600*13642Ssam 				i = 0;
601*13642Ssam 				n = 0;
602*13642Ssam 				while (isdigit(strptr[1]) && ++n <= 3)
603*13642Ssam 					i = i*8 + (*++strptr - '0');
604*13642Ssam 				p_chwrite(fn, i);
605*13642Ssam 				continue;
606*13642Ssam 			}
607*13642Ssam 			DEBUG(5, "BACKSLASH\n", "");
608*13642Ssam 			strptr--;
609*13642Ssam 		}
610*13642Ssam 		p_chwrite(fn, *strptr);
611*13642Ssam 	}
612*13642Ssam 
613*13642Ssam 	/* '\n' changed to '\r'--a better default. rti!trt */
614*13642Ssam 	if (cr)
615*13642Ssam 		p_chwrite(fn, '\r');
616*13642Ssam 	return;
617*13642Ssam }
618*13642Ssam 
619*13642Ssam p_chwrite(fd, c)
620*13642Ssam int fd;
621*13642Ssam int c;
622*13642Ssam {
623*13642Ssam 	char t[2];
624*13642Ssam 
625*13642Ssam 	t[0] = par_tab[c&0177];
626*13642Ssam 	t[1] = '\0';
627*13642Ssam 	ASSERT(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]);
628*13642Ssam }
629*13642Ssam 
630*13642Ssam /*
631*13642Ssam  * generate parity table for use by p_chwrite.
632*13642Ssam  */
633*13642Ssam bld_partab(type)
634*13642Ssam int type;
635*13642Ssam {
636*13642Ssam 	register int i, j, n;
637*13642Ssam 
638*13642Ssam 	for (i = 0; i < sizeof(par_tab); i++) {
639*13642Ssam 		n = 0;
640*13642Ssam 		for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j)
641*13642Ssam 			n++;
642*13642Ssam 		par_tab[i] = i;
643*13642Ssam 		if (type == P_ONE
644*13642Ssam 		 || (type == P_EVEN && (n&01) != 0)
645*13642Ssam 		 || (type == P_ODD && (n&01) == 0))
646*13642Ssam 			par_tab[i] |= sizeof(par_tab);
647*13642Ssam 	}
648*13642Ssam }
649*13642Ssam 
650*13642Ssam #define BSPEED B150
651*13642Ssam 
652*13642Ssam /***
653*13642Ssam  *	genbrk		send a break
654*13642Ssam  *
655*13642Ssam  *	return codes;  none
656*13642Ssam  */
657*13642Ssam 
658*13642Ssam genbrk(fn, bnulls)
659*13642Ssam register int fn, bnulls;
660*13642Ssam {
661*13642Ssam 	register int ret;
662*13642Ssam #ifdef	SYSIII
663*13642Ssam 	ret = ioctl(fn, TCSBRK, STBNULL);
664*13642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
665*13642Ssam #endif
666*13642Ssam #ifndef	SYSIII
667*13642Ssam #ifdef	TIOCSBRK
668*13642Ssam 	ret = ioctl(fn, TIOCSBRK, STBNULL);
669*13642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
670*13642Ssam #ifdef	TIOCCBRK
671*13642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
672*13642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
673*13642Ssam 	sleep(1);
674*13642Ssam 	ret = ioctl(fn, TIOCCBRK, STBNULL);
675*13642Ssam 	DEBUG(5, "break ioctl ret %d\n", ret);
676*13642Ssam #endif
677*13642Ssam 	DEBUG(4, "ioctl 1 second break\n", STBNULL);
678*13642Ssam #else
679*13642Ssam 	struct sgttyb ttbuf;
680*13642Ssam 	register int sospeed;
681*13642Ssam 
682*13642Ssam 	ret = ioctl(fn, TIOCGETP, &ttbuf);
683*13642Ssam 	sospeed = ttbuf.sg_ospeed;
684*13642Ssam 	ttbuf.sg_ospeed = BSPEED;
685*13642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
686*13642Ssam 	ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls);
687*13642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
688*13642Ssam 	ttbuf.sg_ospeed = sospeed;
689*13642Ssam 	ret = ioctl(fn, TIOCSETP, &ttbuf);
690*13642Ssam 	ret = write(fn, "@", 1);
691*13642Ssam 	ASSERT(ret > 0, "BAD WRITE genbrk", "", ret);
692*13642Ssam 	DEBUG(4, "sent BREAK nulls - %d\n", bnulls);
693*13642Ssam #endif
694*13642Ssam #endif
695*13642Ssam }
696*13642Ssam 
697*13642Ssam 
698*13642Ssam /***
699*13642Ssam  *	notin(sh, lg)	check for occurrence of substring "sh"
700*13642Ssam  *	char *sh, *lg;
701*13642Ssam  *
702*13642Ssam  *	return codes:
703*13642Ssam  *		0  -  found the string
704*13642Ssam  *		1  -  not in the string
705*13642Ssam  */
706*13642Ssam 
707*13642Ssam notin(sh, lg)
708*13642Ssam register char *sh, *lg;
709*13642Ssam {
710*13642Ssam 	while (*lg != '\0') {
711*13642Ssam 		/* Dave Martingale: permit wild cards in 'expect' */
712*13642Ssam 		if (wprefix(sh, lg))
713*13642Ssam 			return(0);
714*13642Ssam 		else
715*13642Ssam 			lg++;
716*13642Ssam 	}
717*13642Ssam 	return(1);
718*13642Ssam }
719*13642Ssam 
720*13642Ssam 
721*13642Ssam /*******
722*13642Ssam  *	ifdate(s)
723*13642Ssam  *	char *s;
724*13642Ssam  *
725*13642Ssam  *	ittvax!swatt
726*13642Ssam  *	Allow multiple date specifications separated by '|'.
727*13642Ssam  *	Calls ifadate, formerly "ifdate".
728*13642Ssam  *
729*13642Ssam  *	return codes:
730*13642Ssam  *		see ifadate
731*13642Ssam  */
732*13642Ssam 
733*13642Ssam ifdate(s)
734*13642Ssam char *s;
735*13642Ssam {
736*13642Ssam 	register char *p;
737*13642Ssam 	register int ret;
738*13642Ssam 
739*13642Ssam 	for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|'))
740*13642Ssam 		if (ret = ifadate(p))
741*13642Ssam 			return(ret);
742*13642Ssam 	return(0);
743*13642Ssam }
744*13642Ssam 
745*13642Ssam 
746*13642Ssam /*******
747*13642Ssam  *	ifadate(s)
748*13642Ssam  *	char *s;
749*13642Ssam  *
750*13642Ssam  *	ifadate  -  this routine will check a string (s)
751*13642Ssam  *	like "MoTu0800-1730" to see if the present
752*13642Ssam  *	time is within the given limits.
753*13642Ssam  *	SIDE EFFECT - Retrytime is set
754*13642Ssam  *
755*13642Ssam  *	String alternatives:
756*13642Ssam  *		Wk - Mo thru Fr
757*13642Ssam  *		zero or one time means all day
758*13642Ssam  *		Any - any day
759*13642Ssam  *
760*13642Ssam  *	return codes:
761*13642Ssam  *		0  -  not within limits
762*13642Ssam  *		1  -  within limits
763*13642Ssam  */
764*13642Ssam 
765*13642Ssam ifadate(s)
766*13642Ssam char *s;
767*13642Ssam {
768*13642Ssam 	static char *days[]={
769*13642Ssam 		"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
770*13642Ssam 	};
771*13642Ssam 	time_t clock;
772*13642Ssam 	int rtime;
773*13642Ssam 	int i, tl, th, tn, flag, dayok=0;
774*13642Ssam 	struct tm *localtime();
775*13642Ssam 	struct tm *tp;
776*13642Ssam 	char *index();
777*13642Ssam 	char *p;
778*13642Ssam 
779*13642Ssam 	/*  pick up retry time for failures  */
780*13642Ssam 	/*  global variable Retrytime is set here  */
781*13642Ssam 	if ((p = index(s, ',')) == NULL) {
782*13642Ssam 		Retrytime = RETRYTIME;
783*13642Ssam 	}
784*13642Ssam 	else {
785*13642Ssam 		i = sscanf(p+1, "%d", &rtime);
786*13642Ssam 		if (i < 1 || rtime < 5)
787*13642Ssam 			rtime = 5;
788*13642Ssam 		Retrytime  = rtime * 60;
789*13642Ssam 	}
790*13642Ssam 
791*13642Ssam 	time(&clock);
792*13642Ssam 	tp = localtime(&clock);
793*13642Ssam 	while (isalpha(*s)) {
794*13642Ssam 		for (i = 0; days[i]; i++) {
795*13642Ssam 			if (prefix(days[i], s))
796*13642Ssam 				if (tp->tm_wday == i)
797*13642Ssam 					dayok = 1;
798*13642Ssam 		}
799*13642Ssam 
800*13642Ssam 		if (prefix("Wk", s))
801*13642Ssam 			if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
802*13642Ssam 				dayok = 1;
803*13642Ssam 		if (prefix("Any", s))
804*13642Ssam 			dayok = 1;
805*13642Ssam 		s++;
806*13642Ssam 	}
807*13642Ssam 
808*13642Ssam 	if (dayok == 0)
809*13642Ssam 		return(0);
810*13642Ssam 	i = sscanf(s, "%d-%d", &tl, &th);
811*13642Ssam 	tn = tp->tm_hour * 100 + tp->tm_min;
812*13642Ssam 	if (i < 2)
813*13642Ssam 		return(1);
814*13642Ssam 	if (th < tl)
815*13642Ssam 		flag = 0;  /* set up for crossover 2400 test */
816*13642Ssam 	else
817*13642Ssam 		flag = 1;
818*13642Ssam 	if ((tn >= tl && tn <= th)
819*13642Ssam 	  || (tn >= th && tn <= tl)) /* test for crossover 2400 */
820*13642Ssam 		return(flag);
821*13642Ssam 	else
822*13642Ssam 		return(!flag);
823*13642Ssam }
824*13642Ssam 
825*13642Ssam 
826*13642Ssam /***
827*13642Ssam  *	char *
828*13642Ssam  *	lastc(s)	return pointer to last character
829*13642Ssam  *	char *s;
830*13642Ssam  *
831*13642Ssam  */
832*13642Ssam 
833*13642Ssam char *
834*13642Ssam lastc(s)
835*13642Ssam register char *s;
836*13642Ssam {
837*13642Ssam 	while (*s != '\0') s++;
838*13642Ssam 	return(s);
839*13642Ssam }
840*13642Ssam 
841*13642Ssam 
842*13642Ssam /***
843*13642Ssam  *	char *
844*13642Ssam  *	fdig(cp)	find first digit in string
845*13642Ssam  *
846*13642Ssam  *	return - pointer to first digit in string or end of string
847*13642Ssam  */
848*13642Ssam 
849*13642Ssam char *
850*13642Ssam fdig(cp)
851*13642Ssam register char *cp;
852*13642Ssam {
853*13642Ssam 	register char *c;
854*13642Ssam 
855*13642Ssam 	for (c = cp; *c; c++)
856*13642Ssam 		if (*c >= '0' && *c <= '9')
857*13642Ssam 			break;
858*13642Ssam 	return(c);
859*13642Ssam }
860*13642Ssam 
861*13642Ssam 
862*13642Ssam /*
863*13642Ssam  * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
864*13642Ssam  * Strings are compared as if they contain all capital letters.
865*13642Ssam  */
866*13642Ssam 
867*13642Ssam snccmp(s1, s2)
868*13642Ssam register char *s1, *s2;
869*13642Ssam {
870*13642Ssam 	char c1, c2;
871*13642Ssam 
872*13642Ssam 	if (islower(*s1)) c1 = toupper(*s1);
873*13642Ssam 	else c1 = *s1;
874*13642Ssam 	if (islower(*s2)) c2 = toupper(*s2);
875*13642Ssam 	else c2 = *s2;
876*13642Ssam 
877*13642Ssam 	while (c1 == c2) {
878*13642Ssam 		if (*s1++=='\0')
879*13642Ssam 			return(0);
880*13642Ssam 		s2++;
881*13642Ssam 		if (islower(*s1)) c1 = toupper(*s1);
882*13642Ssam 		else c1 = *s1;
883*13642Ssam 		if (islower(*s2)) c2 = toupper(*s2);
884*13642Ssam 		else c2 = *s2;
885*13642Ssam 	}
886*13642Ssam 	return(c1 - c2);
887*13642Ssam }
888