xref: /csrg-svn/old/cu/cu.c (revision 996)
1*996Sbill static char *sccsid = "@(#)cu.c	4.1 (Berkeley) 10/01/80";
2*996Sbill #include <stdio.h>
3*996Sbill #include <signal.h>
4*996Sbill #include <sgtty.h>
5*996Sbill /*
6*996Sbill  *	cu telno [-t] [-s speed] [-l line] [-a acu]
7*996Sbill  *
8*996Sbill  *	-t is for dial-out to terminal.
9*996Sbill  *	speeds are: 110, 134, 150, 300, 1200. 300 is default.
10*996Sbill  *
11*996Sbill  *	Escape with `~' at beginning of line.
12*996Sbill  *	Ordinary diversions are ~<, ~> and ~>>.
13*996Sbill  *	Silent output diversions are ~>: and ~>>:.
14*996Sbill  *	Terminate output diversion with ~> alone.
15*996Sbill  *	Quit is ~. and ~! gives local command or shell.
16*996Sbill  *	Also ~$ for canned procedure pumping remote.
17*996Sbill  *	~%put from [to]  and  ~%take from [to] invoke builtins
18*996Sbill  */
19*996Sbill 
20*996Sbill #define CRLF "\r\n"
21*996Sbill #define wrc(ds) write(ds,&c,1)
22*996Sbill 
23*996Sbill 
24*996Sbill char	*devcul	= "/dev/cul0";
25*996Sbill char	*devcua	= "/dev/cua0";
26*996Sbill char	*lspeed	= "300";
27*996Sbill 
28*996Sbill int	ln;	/* fd for comm line */
29*996Sbill char	tkill, terase;	/* current input kill & erase */
30*996Sbill int	efk;		/* process of id of listener  */
31*996Sbill char	c;
32*996Sbill char	oc;
33*996Sbill 
34*996Sbill char	*connmsg[] = {
35*996Sbill 	"",
36*996Sbill 	"line busy",
37*996Sbill 	"call dropped",
38*996Sbill 	"no carrier",
39*996Sbill 	"can't fork",
40*996Sbill 	"acu access",
41*996Sbill 	"tty access",
42*996Sbill 	"tty hung",
43*996Sbill 	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
44*996Sbill };
45*996Sbill 
46*996Sbill rdc(ds) {
47*996Sbill 
48*996Sbill 	ds=read(ds,&c,1);
49*996Sbill 	oc = c;
50*996Sbill 	c &= 0177;
51*996Sbill 	return (ds);
52*996Sbill }
53*996Sbill 
54*996Sbill int intr;
55*996Sbill 
56*996Sbill sig2()
57*996Sbill {
58*996Sbill 	signal(SIGINT, SIG_IGN);
59*996Sbill 	intr = 1;
60*996Sbill }
61*996Sbill 
62*996Sbill int set14;
63*996Sbill 
64*996Sbill xsleep(n)
65*996Sbill {
66*996Sbill 	xalarm(n);
67*996Sbill 	pause();
68*996Sbill 	xalarm(0);
69*996Sbill }
70*996Sbill 
71*996Sbill xalarm(n)
72*996Sbill {
73*996Sbill 	set14=n;
74*996Sbill 	alarm(n);
75*996Sbill }
76*996Sbill 
77*996Sbill sig14()
78*996Sbill {
79*996Sbill 	signal(SIGALRM, sig14);
80*996Sbill 	if (set14) alarm(1);
81*996Sbill }
82*996Sbill 
83*996Sbill int	dout;
84*996Sbill int	nhup;
85*996Sbill int	dbflag;
86*996Sbill 
87*996Sbill /*
88*996Sbill  *	main: get connection, set speed for line.
89*996Sbill  *	spawn child to invoke rd to read from line, output to fd 1
90*996Sbill  *	main line invokes wr to read tty, write to line
91*996Sbill  */
92*996Sbill main(ac,av)
93*996Sbill char *av[];
94*996Sbill {
95*996Sbill 	int fk;
96*996Sbill 	int speed;
97*996Sbill 	char *telno;
98*996Sbill 	struct sgttyb stbuf;
99*996Sbill 
100*996Sbill 	signal(SIGALRM, sig14);
101*996Sbill 	if (ac < 2) {
102*996Sbill 		prf(connmsg[8]);
103*996Sbill 		exit(8);
104*996Sbill 	}
105*996Sbill 	for (; ac > 1; av++,ac--) {
106*996Sbill 		if (av[1][0] != '-')
107*996Sbill 			telno = av[1];
108*996Sbill 		else switch(av[1][1]) {
109*996Sbill 		case 't':
110*996Sbill 			dout = 1;
111*996Sbill 			--ac;
112*996Sbill 			continue;
113*996Sbill 		case 'd':
114*996Sbill 			dbflag++;
115*996Sbill 			continue;
116*996Sbill 		case 's':
117*996Sbill 			lspeed = av[2]; ++av; --ac;
118*996Sbill 			break;
119*996Sbill 		case 'l':
120*996Sbill 			devcul = av[2]; ++av; --ac;
121*996Sbill 			break;
122*996Sbill 		case 'a':
123*996Sbill 			devcua = av[2]; ++av; --ac;
124*996Sbill 			break;
125*996Sbill 		case '0': case '1': case '2': case '3': case '4':
126*996Sbill 		case '5': case '6': case '7': case '8': case '9':
127*996Sbill 			devcua[strlen(devcua)-1] = av[1][1];
128*996Sbill 			devcul[strlen(devcul)-1] = av[1][1];
129*996Sbill 			break;
130*996Sbill 		default:
131*996Sbill 			prf("Bad flag %s", av[1]);
132*996Sbill 			break;
133*996Sbill 		}
134*996Sbill 	}
135*996Sbill 	if (!exists(devcua) || !exists(devcul))
136*996Sbill 		exit(9);
137*996Sbill 	ln = conn(devcul, devcua, telno);
138*996Sbill 	if (ln < 0) {
139*996Sbill 		prf("Connect failed: %s",connmsg[-ln]);
140*996Sbill 		exit(-ln);
141*996Sbill 	}
142*996Sbill 	switch(atoi(lspeed)) {
143*996Sbill 	case 110:
144*996Sbill 		speed = B110;break;
145*996Sbill 	case 150:
146*996Sbill 		speed = B150;break;
147*996Sbill 	default:
148*996Sbill 	case 300:
149*996Sbill 		speed = B300;break;
150*996Sbill 	case 1200:
151*996Sbill 		speed = B1200;break;
152*996Sbill 	}
153*996Sbill 	stbuf.sg_ispeed = speed;
154*996Sbill 	stbuf.sg_ospeed = speed;
155*996Sbill 	stbuf.sg_flags = EVENP|ODDP;
156*996Sbill 	if (!dout) {
157*996Sbill 		stbuf.sg_flags |= RAW;
158*996Sbill 		stbuf.sg_flags &= ~ECHO;
159*996Sbill 	}
160*996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
161*996Sbill 	ioctl(ln, TIOCEXCL, (struct sgttyb *)NULL);
162*996Sbill 	ioctl(ln, TIOCHPCL, (struct sgttyb *)NULL);
163*996Sbill 	prf("Connected");
164*996Sbill 	if (dout)
165*996Sbill 		fk = -1;
166*996Sbill 	else
167*996Sbill 		fk = fork();
168*996Sbill 	nhup = (int)signal(SIGINT, SIG_IGN);
169*996Sbill 	if (fk == 0) {
170*996Sbill 		chwrsig();
171*996Sbill 		rd();
172*996Sbill 		prf("\007Lost carrier");
173*996Sbill 		exit(3);
174*996Sbill 	}
175*996Sbill 	mode(1);
176*996Sbill 	efk = fk;
177*996Sbill 	wr();
178*996Sbill 	mode(0);
179*996Sbill 	kill(fk, SIGKILL);
180*996Sbill 	wait((int *)NULL);
181*996Sbill 	stbuf.sg_ispeed = 0;
182*996Sbill 	stbuf.sg_ospeed = 0;
183*996Sbill 	ioctl(ln, TIOCSETP, &stbuf);
184*996Sbill 	prf("Disconnected");
185*996Sbill 	exit(0);
186*996Sbill }
187*996Sbill 
188*996Sbill /*
189*996Sbill  *	conn: establish dial-out connection.
190*996Sbill  *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
191*996Sbill  *	Returns descriptor open to tty for reading and writing.
192*996Sbill  *	Negative values (-1...-7) denote errors in connmsg.
193*996Sbill  *	Uses alarm and fork/wait; requires sig14 handler.
194*996Sbill  *	Be sure to disconnect tty when done, via HUPCL or stty 0.
195*996Sbill  */
196*996Sbill 
197*996Sbill conn(dev,acu,telno)
198*996Sbill char *dev, *acu, *telno;
199*996Sbill {
200*996Sbill 	struct sgttyb stbuf;
201*996Sbill 	extern errno;
202*996Sbill 	char *p, *q, b[30];
203*996Sbill 	int er, fk, dn, dh, t;
204*996Sbill 	er=0;
205*996Sbill 	fk=(-1);
206*996Sbill 	if ((dn=open(acu,1))<0) {
207*996Sbill 		er=(errno == 6? 1:5);
208*996Sbill 		goto X;
209*996Sbill 	}
210*996Sbill 	if ((fk=fork()) == (-1)) {
211*996Sbill 		er=4;
212*996Sbill 		goto X;
213*996Sbill 	}
214*996Sbill 	if (fk == 0) {
215*996Sbill 		open(dev,2);
216*996Sbill 		for (;;) pause();
217*996Sbill 	}
218*996Sbill 	xsleep(2);
219*996Sbill 	/*
220*996Sbill 	 *	copy phone #, assure EON
221*996Sbill 	 */
222*996Sbill 	p=b;
223*996Sbill 	q=telno;
224*996Sbill 	while (*p++=(*q++))
225*996Sbill 		;
226*996Sbill 	p--;
227*996Sbill 	if (*(p-1)!='<') {
228*996Sbill 		/*if (*(p-1)!='-') *p++='-';*/
229*996Sbill 		*p++='<';
230*996Sbill 	}
231*996Sbill 	t=p-b;
232*996Sbill 	xalarm(5*t);
233*996Sbill 	t=write(dn,b,t);
234*996Sbill 	xalarm(0);
235*996Sbill 	if (t<0) {
236*996Sbill 		er=2;
237*996Sbill 		goto X;
238*996Sbill 	}
239*996Sbill 	/* close(dn) */
240*996Sbill 	xalarm(40);		/* was 5; sometimes missed carrier */
241*996Sbill 	dh = open(dev,2);
242*996Sbill 	xalarm(0);
243*996Sbill 	if (dh<0) {
244*996Sbill 		er=(errno == 4? 3:6);
245*996Sbill 		goto X;
246*996Sbill 	}
247*996Sbill 	ioctl(ln, TIOCGETP, &stbuf);
248*996Sbill 	stbuf.sg_flags &= ~ECHO;
249*996Sbill 	xalarm(10);
250*996Sbill 	ioctl(dh, TIOCSETP, &stbuf);
251*996Sbill 	ioctl(dh, TIOCHPCL, (struct sgttyb *)NULL);
252*996Sbill 	xalarm(0);
253*996Sbill X:
254*996Sbill 	if (er) close(dn);
255*996Sbill 	if (fk!=(-1)) {
256*996Sbill 		kill(fk, SIGKILL);
257*996Sbill 		xalarm(10);
258*996Sbill 		while ((t=wait((int *)NULL))!=(-1) && t!=fk);
259*996Sbill 		xalarm(0);
260*996Sbill 	}
261*996Sbill 	return (er? -er:dh);
262*996Sbill }
263*996Sbill 
264*996Sbill /*
265*996Sbill  *	wr: write to remote: 0 -> line.
266*996Sbill  *	~.	terminate
267*996Sbill  *	~<file	send file
268*996Sbill  *	~!	local login-style shell
269*996Sbill  *	~!cmd	execute cmd locally
270*996Sbill  *	~$proc	execute proc locally, send output to line
271*996Sbill  *	~%cmd	execute builtin cmd (put and take)
272*996Sbill  *	~#	send 1-sec break
273*996Sbill  */
274*996Sbill 
275*996Sbill wr()
276*996Sbill {
277*996Sbill 	int ds,fk,lcl,x;
278*996Sbill 	char *p,b[600];
279*996Sbill 	for (;;) {
280*996Sbill 		p=b;
281*996Sbill 		while (rdc(0) == 1) {
282*996Sbill 			if (p == b) lcl=(c == '~');
283*996Sbill 			if (p == b+1 && b[0] == '~') lcl=(c!='~');
284*996Sbill 			/* if (c == 0) oc=c=0177; fake break kludge */
285*996Sbill 			if (!lcl) {
286*996Sbill 				c = oc;
287*996Sbill 				if (wrc(ln) == 0) {
288*996Sbill 					prf("line gone"); return;
289*996Sbill 				}
290*996Sbill 				c &= 0177;
291*996Sbill 			}
292*996Sbill 			if (lcl) {
293*996Sbill 				if (c == 0177) c=tkill;
294*996Sbill 				if (c == '\r' || c == '\n') goto A;
295*996Sbill 				if (!dout) wrc(0);
296*996Sbill 			}
297*996Sbill 			*p++=c;
298*996Sbill 			if (c == terase) {
299*996Sbill 				p=p-2;
300*996Sbill 				if (p<b) p=b;
301*996Sbill 			}
302*996Sbill 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
303*996Sbill 		}
304*996Sbill 		return;
305*996Sbill A:
306*996Sbill 		if (!dout) echo("");
307*996Sbill 		*p=0;
308*996Sbill 		switch (b[1]) {
309*996Sbill 		case '.':
310*996Sbill 		case '\004':
311*996Sbill 			return;
312*996Sbill 		case '#':
313*996Sbill 			ioctl(ln, TIOCSBRK, 0);
314*996Sbill 			sleep(1);
315*996Sbill 			ioctl(ln, TIOCCBRK, 0);
316*996Sbill 			continue;
317*996Sbill 		case '!':
318*996Sbill 		case '$':
319*996Sbill 			fk = fork();
320*996Sbill 			if (fk == 0) {
321*996Sbill 				char *getenv();
322*996Sbill 				char *shell = getenv("SHELL");
323*996Sbill 				if (shell == 0) shell = "/bin/sh";
324*996Sbill 				close(1);
325*996Sbill 				dup(b[1] == '$'? ln:2);
326*996Sbill 				close(ln);
327*996Sbill 				mode(0);
328*996Sbill 				if (!nhup) signal(SIGINT, SIG_DFL);
329*996Sbill 				if (b[2] == 0) execl(shell,shell,0);
330*996Sbill 				/* if (b[2] == 0) execl(shell,"-",0); */
331*996Sbill 				else execl(shell,"sh","-c",b+2,0);
332*996Sbill 				prf("Can't execute shell");
333*996Sbill 				exit(~0);
334*996Sbill 			}
335*996Sbill 			if (fk!=(-1)) {
336*996Sbill 				while (wait(&x)!=fk);
337*996Sbill 			}
338*996Sbill 			mode(1);
339*996Sbill 			if (b[1] == '!') echo("!");
340*996Sbill 			else {
341*996Sbill 				if (dout) echo("$");
342*996Sbill 			}
343*996Sbill 			break;
344*996Sbill 		case '<':
345*996Sbill 			if (b[2] == 0) break;
346*996Sbill 			if ((ds=open(b+2,0))<0) {
347*996Sbill 				prf("Can't divert %s",b+1);
348*996Sbill 				break;
349*996Sbill 			}
350*996Sbill 			intr=x=0;
351*996Sbill 			mode(2);
352*996Sbill 			if (!nhup) signal(SIGINT, sig2);
353*996Sbill 			while (!intr && rdc(ds) == 1) {
354*996Sbill 				if (wrc(ln) == 0) {
355*996Sbill 					x=1;
356*996Sbill 					break;
357*996Sbill 				}
358*996Sbill 			}
359*996Sbill 			signal(SIGINT, SIG_IGN);
360*996Sbill 			close(ds);
361*996Sbill 			mode(1);
362*996Sbill 			if (x) return;
363*996Sbill 			if (dout) echo("<");
364*996Sbill 			break;
365*996Sbill 		case '>':
366*996Sbill 		case ':':
367*996Sbill 			{
368*996Sbill 			FILE *fp; char tbuff[128]; register char *q;
369*996Sbill 			sprintf(tbuff,"/tmp/cu%d",efk);
370*996Sbill 			if(NULL==(fp = fopen(tbuff,"w"))) {
371*996Sbill 				prf("Can't tell other demon to divert");
372*996Sbill 				break;
373*996Sbill 			}
374*996Sbill 			fprintf(fp,"%s\n",(b[1]=='>'?&b[2]: &b[1] ));
375*996Sbill 			if(dbflag) prf("name to be written in temporary:"),prf(&b[2]);
376*996Sbill 			fclose(fp);
377*996Sbill 			kill(efk,SIGEMT);
378*996Sbill 			}
379*996Sbill 			break;
380*996Sbill #ifdef SIGTSTP
381*996Sbill #define CTRLZ	26
382*996Sbill 		case CTRLZ:
383*996Sbill 			mode(0);
384*996Sbill 			kill(getpid(), SIGTSTP);
385*996Sbill 			mode(1);
386*996Sbill 			break;
387*996Sbill #endif
388*996Sbill 		case '%':
389*996Sbill 			dopercen(&b[2]);
390*996Sbill 			break;
391*996Sbill 		default:
392*996Sbill 			prf("Use `~~' to start line with `~'");
393*996Sbill 		}
394*996Sbill 		continue;
395*996Sbill 	}
396*996Sbill }
397*996Sbill 
398*996Sbill dopercen(line)
399*996Sbill register char *line;
400*996Sbill {
401*996Sbill 	char *args[10];
402*996Sbill 	register narg, f;
403*996Sbill 	int rcount;
404*996Sbill 	for (narg = 0; narg < 10;) {
405*996Sbill 		while(*line == ' ' || *line == '\t')
406*996Sbill 			line++;
407*996Sbill 		if (*line == '\0')
408*996Sbill 			break;
409*996Sbill 		args[narg++] = line;
410*996Sbill 		while(*line != '\0' && *line != ' ' && *line != '\t')
411*996Sbill 			line++;
412*996Sbill 		if (*line == '\0')
413*996Sbill 			break;
414*996Sbill 		*line++ = '\0';
415*996Sbill 	}
416*996Sbill 	if (equal(args[0], "take")) {
417*996Sbill 		if (narg < 2) {
418*996Sbill 			prf("usage: ~%%take from [to]");
419*996Sbill 			return;
420*996Sbill 		}
421*996Sbill 		if (narg < 3)
422*996Sbill 			args[2] = args[1];
423*996Sbill 		wrln("echo '~>:'");
424*996Sbill 		wrln(args[2]);
425*996Sbill 		wrln(";tee /dev/null <");
426*996Sbill 		wrln(args[1]);
427*996Sbill 		wrln(";echo '~>'\n");
428*996Sbill 		return;
429*996Sbill 	} else if (equal(args[0], "put")) {
430*996Sbill 		if (narg < 2) {
431*996Sbill 			prf("usage: ~%%put from [to]");
432*996Sbill 			return;
433*996Sbill 		}
434*996Sbill 		if (narg < 3)
435*996Sbill 			args[2] = args[1];
436*996Sbill 		if ((f = open(args[1], 0)) < 0) {
437*996Sbill 			prf("cannot open: %s", args[1]);
438*996Sbill 			return;
439*996Sbill 		}
440*996Sbill 		wrln("stty -echo;cat >");
441*996Sbill 		wrln(args[2]);
442*996Sbill 		wrln(";stty echo\n");
443*996Sbill 		xsleep(5);
444*996Sbill 		intr = 0;
445*996Sbill 		if (!nhup)
446*996Sbill 			signal(SIGINT, sig2);
447*996Sbill 		mode(2);
448*996Sbill 		rcount = 0;
449*996Sbill 		while(!intr && rdc(f) == 1) {
450*996Sbill 			rcount++;
451*996Sbill 			if (c == tkill || c == terase)
452*996Sbill 				wrln("\\");
453*996Sbill 			if (wrc(ln) != 1) {
454*996Sbill 				xsleep(2);
455*996Sbill 				if (wrc(ln) != 1) {
456*996Sbill 					prf("character missed");
457*996Sbill 					intr = 1;
458*996Sbill 					break;
459*996Sbill 				}
460*996Sbill 			}
461*996Sbill 		}
462*996Sbill 		signal(SIGINT, SIG_IGN);
463*996Sbill 		close(f);
464*996Sbill 		if (intr) {
465*996Sbill 			wrln("\n");
466*996Sbill 			prf("stopped after %d bytes", rcount);
467*996Sbill 		}
468*996Sbill 		wrln("\004");
469*996Sbill 		xsleep(5);
470*996Sbill 		mode(1);
471*996Sbill 		return;
472*996Sbill 	}
473*996Sbill 	prf("~%%%s unknown\n", args[0]);
474*996Sbill }
475*996Sbill 
476*996Sbill equal(s1, s2)
477*996Sbill register char *s1, *s2;
478*996Sbill {
479*996Sbill 	while (*s1++ == *s2)
480*996Sbill 		if (*s2++ == '\0')
481*996Sbill 			return(1);
482*996Sbill 	return(0);
483*996Sbill }
484*996Sbill 
485*996Sbill wrln(s)
486*996Sbill register char *s;
487*996Sbill {
488*996Sbill 	while (*s)
489*996Sbill 		write(ln, s++, 1);
490*996Sbill }
491*996Sbill /*	chwrsig:  Catch orders from wr process
492*996Sbill  *	to instigate diversion
493*996Sbill  */
494*996Sbill int whoami;
495*996Sbill chwrsig(){
496*996Sbill 	int dodiver();
497*996Sbill 	whoami = getpid();
498*996Sbill 	signal(SIGEMT,dodiver);
499*996Sbill }
500*996Sbill int ds,slnt;
501*996Sbill int justrung;
502*996Sbill dodiver(){
503*996Sbill 	static char dobuff[128], morejunk[256]; register char *cp;
504*996Sbill 	FILE *fp;
505*996Sbill 	justrung = 1;
506*996Sbill 	signal(SIGEMT,dodiver);
507*996Sbill 	sprintf(dobuff,"/tmp/cu%d",whoami);
508*996Sbill 	fp = fopen(dobuff,"r");
509*996Sbill 	if(fp==NULL) prf("Couldn't open temporary");
510*996Sbill 	unlink(dobuff);
511*996Sbill 	if(dbflag) {
512*996Sbill 		prf("Name of temporary:");
513*996Sbill 		prf(dobuff);
514*996Sbill 	}
515*996Sbill 	fgets(dobuff,128,fp); fclose(fp);
516*996Sbill 	if(dbflag) {
517*996Sbill 		prf("Name of target file:");
518*996Sbill 		prf(dobuff);
519*996Sbill 	}
520*996Sbill 	for(cp = dobuff-1; *++cp; ) /* squash newline */
521*996Sbill 		if(*cp=='\n') *cp=0;
522*996Sbill 	cp = dobuff;
523*996Sbill 	if (*cp=='>') cp++;
524*996Sbill 	if (*cp==':') {
525*996Sbill 		cp++;
526*996Sbill 		if(*cp==0) {
527*996Sbill 			slnt ^= 1;
528*996Sbill 			return;
529*996Sbill 		} else  {
530*996Sbill 			slnt = 1;
531*996Sbill 		}
532*996Sbill 	}
533*996Sbill 	if (ds >= 0) close(ds);
534*996Sbill 	if (*cp==0) {
535*996Sbill 		slnt = 0;
536*996Sbill 		ds = -1;
537*996Sbill 		return;
538*996Sbill 	}
539*996Sbill 	if (*dobuff!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
540*996Sbill 	lseek(ds, (long)0, 2);
541*996Sbill 	if(ds < 0) prf("Creat failed:"), prf(cp);
542*996Sbill 	if (ds<0) prf("Can't divert %s",cp+1);
543*996Sbill }
544*996Sbill 
545*996Sbill 
546*996Sbill /*
547*996Sbill  *	rd: read from remote: line -> 1
548*996Sbill  *	catch:
549*996Sbill  *	~>[>][:][file]
550*996Sbill  *	stuff from file...
551*996Sbill  *	~>	(ends diversion)
552*996Sbill  */
553*996Sbill 
554*996Sbill rd()
555*996Sbill {
556*996Sbill 	extern int ds,slnt;
557*996Sbill 	char *p,*q,b[600];
558*996Sbill 	p=b;
559*996Sbill 	ds=(-1);
560*996Sbill agin:
561*996Sbill 	while (rdc(ln) == 1) {
562*996Sbill 		if (!slnt) wrc(1);
563*996Sbill 		*p++=c;
564*996Sbill 		if (c!='\n') continue;
565*996Sbill 		q=p;
566*996Sbill 		p=b;
567*996Sbill 		if (b[0]!='~' || b[1]!='>') {
568*996Sbill 			if (*(q-2) == '\r') {
569*996Sbill 				q--;
570*996Sbill 				*(q-1)=(*q);
571*996Sbill 			}
572*996Sbill 			if (ds>=0) write(ds,b,q-b);
573*996Sbill 			continue;
574*996Sbill 		}
575*996Sbill 		if (ds>=0) close(ds);
576*996Sbill 		if (slnt) {
577*996Sbill 			write(1, b, q - b);
578*996Sbill 			write(1, CRLF, sizeof(CRLF));
579*996Sbill 		}
580*996Sbill 		if (*(q-2) == '\r') q--;
581*996Sbill 		*(q-1)=0;
582*996Sbill 		slnt=0;
583*996Sbill 		q=b+2;
584*996Sbill 		if (*q == '>') q++;
585*996Sbill 		if (*q == ':') {
586*996Sbill 			slnt=1;
587*996Sbill 			q++;
588*996Sbill 		}
589*996Sbill 		if (*q == 0) {
590*996Sbill 			ds=(-1);
591*996Sbill 			continue;
592*996Sbill 		}
593*996Sbill 		if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
594*996Sbill 		lseek(ds, (long)0, 2);
595*996Sbill 		if (ds<0) prf("Can't divert %s",b+1);
596*996Sbill 	}
597*996Sbill 	if(justrung) {
598*996Sbill 		justrung = 0;
599*996Sbill 		goto agin;
600*996Sbill 	}
601*996Sbill }
602*996Sbill 
603*996Sbill struct {char lobyte; char hibyte;};
604*996Sbill mode(f)
605*996Sbill {
606*996Sbill 	struct sgttyb stbuf;
607*996Sbill 	if (dout) return;
608*996Sbill 	ioctl(0, TIOCGETP, &stbuf);
609*996Sbill 	tkill = stbuf.sg_kill;
610*996Sbill 	terase = stbuf.sg_erase;
611*996Sbill 	if (f == 0) {
612*996Sbill 		stbuf.sg_flags &= ~RAW;
613*996Sbill 		stbuf.sg_flags |= ECHO|CRMOD;
614*996Sbill 	}
615*996Sbill 	if (f == 1) {
616*996Sbill 		stbuf.sg_flags |= RAW;
617*996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
618*996Sbill 	}
619*996Sbill 	if (f == 2) {
620*996Sbill 		stbuf.sg_flags &= ~RAW;
621*996Sbill 		stbuf.sg_flags &= ~(ECHO|CRMOD);
622*996Sbill 	}
623*996Sbill 	ioctl(0, TIOCSETP, &stbuf);
624*996Sbill }
625*996Sbill 
626*996Sbill echo(s)
627*996Sbill char *s;
628*996Sbill {
629*996Sbill 	char *p;
630*996Sbill 	for (p=s;*p;p++);
631*996Sbill 	if (p>s) write(0,s,p-s);
632*996Sbill 	write(0,CRLF, sizeof(CRLF));
633*996Sbill }
634*996Sbill 
635*996Sbill prf(f, s)
636*996Sbill char *f;
637*996Sbill char *s;
638*996Sbill {
639*996Sbill 	fprintf(stderr, f, s);
640*996Sbill 	fprintf(stderr, CRLF);
641*996Sbill }
642*996Sbill 
643*996Sbill exists(devname)
644*996Sbill char *devname;
645*996Sbill {
646*996Sbill 	if (access(devname, 0)==0)
647*996Sbill 		return(1);
648*996Sbill 	prf("%s does not exist", devname);
649*996Sbill 	return(0);
650*996Sbill }
651