PWB1/sys/source/s8/cu.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	cu telno [-t] [-s speed] [-l line] [-a acu]
 *
 *	-t is for dial-out to terminal.
 *	speeds are: 110, 134, 150, 300, 1200. 300 is default.
 *
 *	Escape with `~' at beginning of line.
 *	Ordinary diversions are ~<, ~> and ~>>.
 *	Silent output diversions are ~>: and ~>>:.
 *	Terminate output diversion with ~> alone.
 *	Quit is ~. and ~! gives local command or shell.
 *	Also ~$ for canned procedure pumping remote.
 *	~%put from [to]  and  ~%take from [to] invoke builtins
 */

#include "stat.h"
#define EVEN  0200
#define ODD   0100
#define RAW   0040
#define CRMOD 0020
#define ECHO  0010
#define HUPCL 0001

#define CRLF "\r\0\0\0\n\0\0\0",8

#define wrc(ds) write(ds,&c,1)
#define spd(n)	(n<<8)|n


char	*devcul	"/dev/cul0";
char	*devcua	"/dev/cua0";
char	*lspeed	"300";

int	ln;	/* fd for comm line */
char	tkill, terase;	/* current input kill & erase */
char	c;

char	*connmsg[] {
	"",
	"line busy",
	"call dropped",
	"no carrier",
	"can't fork",
	"acu access",
	"tty access",
	"tty hung",
	"usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
};

rdc(ds) {
	ds=read(ds,&c,1); 
	c=& 0177; 
	return (ds);
}

int intr;

sig2()
{
	signal(2,1); 
	intr=1;
}

int set14;

xsleep(n)
{
	xalarm(n);
	pause();
	xalarm(0);
}

xalarm(n)
{
	set14=n; 
	alarm(n);
}

sig14()
{
	signal(14,sig14); 
	if (set14) alarm(1);
}

int nhup,dout;

/*
 *	main: get connection, set speed for line.
 *	spawn child to invoke rd to read from line, output to fd 1
 *	main line invokes wr to read tty, write to line
 */
main(ac,av)
char *av[];
{
	int fk,v[3];
	int speed;
	char *telno;
	signal(14,sig14);
	if (ac < 2) {
		prf(connmsg[8]);
		exit(8);
	}
	telno = av[1];
	av =+ 2;
	ac =- 2;
	for (; ac > 0; av++) {
		if (equal(*av, "-t")) {
			dout = 1;
			--ac;
			continue;
		}
		if (ac < 2)
			break;
		if (equal(*av, "-s"))
			lspeed = *++av;
		else if (equal(*av, "-l"))
			devcul = *++av;
		else if (equal(*av, "-a"))
			devcua = *++av;
		else
			break;
		ac =- 2;
	}
	if (!exists(devcua) || !exists(devcul))
		exit(9);
	ln = conn(devcul, devcua, telno);
	if (ln < 0) {
		prf("Connect failed: %s",connmsg[-ln]);
		exit(-ln);
	}
	switch(atoi(lspeed)) {
	case 110:
		speed = spd(3);break;
	case 134:
		speed = spd(4);break;
	case 150:
		speed = spd(5);break;
	default:
	case 300:
		speed = spd(7);break;
	case 1200:
		speed = spd(9);break;
	}
	v[0] = speed;
	v[2]=EVEN|ODD|HUPCL;
	if (!dout) v[2]=| RAW;
	stty(ln, v);
	prf("Connected");
	if (dout) fk=(-1); 
	else
		fk = dofork();
	nhup=signal(2,1);
	if (fk == 0) {
		rd();
		prf("\007Lost carrier");
		exit(3);
	}
	mode(1);
	wr();
	mode(0);
	kill(fk,9);
	wait(v);
	v[0]=0;
	v[2]=HUPCL;
	stty(ln, v);
	prf("Disconnected");
	exit(0);
}

/*
 *	conn: establish dial-out connection.
 *	Example:  fd = conn("/dev/ttyh","/dev/dn1","4500");
 *	Returns descriptor open to tty for reading and writing.
 *	Negative values (-1...-7) denote errors in connmsg.
 *	Uses alarm and fork/wait; requires sig14 handler.
 *	Be sure to disconnect tty when done, via HUPCL or stty 0.
 */

conn(dev,acu,telno)
char *dev,*acu,*telno;
{
	extern errno;
	char *p,*q,b[30];
	int er,fk,dn,dh,t,v[3];
	er=0; 
	fk=(-1);
	if ((dn=open(acu,1))<0) {
		er=(errno == 6? 1:5); 
		goto X;
	}
	if ((fk=fork()) == (-1)) {
		er=4; 
		goto X;
	}
	if (fk == 0) {
		open(dev,2); 
		for (;;) pause();
	}
	xsleep(2);
	/*
	 *	copy phone #, assure -= at end
	 */
	p=b; 
	q=telno;
	while (*p++=(*q++));
	p--;
	if (*(p-1)!='=') {
		if (*(p-1)!='-') *p++='-';
		*p++='=';
	}
	t=p-b;
	xalarm(5*t);
	t=write(dn,b,t);
	xalarm(0);
	if (t<0) {
		er=2; 
		goto X;
	}
	close(dn);
	xalarm(10);		/* was 5; sometimes missed carrier */
	dh = open(dev,2);
	xalarm(0);
	if (dh<0) {
		er=(errno == 4? 3:6); 
		goto X;
	}
	gtty(dh,v);
	v[2] = (v[2]|HUPCL) & ~ECHO;
	xalarm(10);
	t=stty(dh,v);
	xalarm(0);
	if (t<0) er=(errno == 4? 7:6);
X: 
	if (er) close(dn);
	if (fk!=(-1)) {
		kill(fk,9);
		xalarm(10);
		while ((t=wait(v))!=(-1) && t!=fk);
		xalarm(0);
	}
	return (er? -er:dh);
}

/*
 *	wr: write to remote: 0 -> line.
 *	~.	terminate
 *	~<file	send file
 *	~!	local login-style shell
 *	~!cmd	execute cmd locally
 *	~$proc	execute proc locally, send output to line
 *	~%cmd	execute builtin cmd (put and take)
 */

wr()
{
	int ds,fk,lcl,x;
	char *p,b[600];
	for (;;) {
		p=b;
		while (rdc(0) == 1) {
			if (p == b) lcl=(c == '~');
			if (p == b+1 && b[0] == '~') lcl=(c!='~');
			if (c == 0) c=0177;
			if (!lcl) {
				if (wrc(ln) == 0) {
					prf("line gone"); return;
				}
			}
			if (lcl) {
				if (c == 0177) c=tkill;
				if (c == '\r' || c == '\n') goto A;
				if (!dout) wrc(0);
			}
			*p++=c;
			if (c == terase) {
				p=p-2; 
				if (p<b) p=b;
			}
			if (c == tkill || c == 0177 || c == '\r' || c == '\n') p=b;
		}
		return;
A: 
		if (!dout) echo("");
		*p=0;
		switch (b[1]) {
		case '.':
		case '\004':
			return;
		case '!':
		case '$':
			fk = dofork();
			if (fk == 0) {
				close(1);
				dup(b[1] == '$'? ln:2);
				close(ln);
				mode(0);
				if (!nhup) signal(2,0);
				if (b[2] == 0) execl("/bin/sh","-",0);
				else execl("/bin/sh","sh","-c",b+2,0);
				prf("Can't execute shell");
				exit(~0);
			}
			if (fk!=(-1)) {
				while (wait(&x)!=fk);
			}
			mode(1);
			if (b[1] == '!') echo("!");
			else {
				if (dout) echo("$");
			}
			break;
		case '<':
			if (b[2] == 0) break;
			if ((ds=open(b+2,0))<0) {
				prf("Can't divert %s",b+1); 
				break;
			}
			intr=x=0;
			mode(2);
			if (!nhup) signal(2,sig2);
			while (!intr && rdc(ds) == 1) {
				if (wrc(ln) == 0) {
					x=1; 
					break;
				}
			}
			signal(2,1);
			close(ds);
			mode(1);
			if (x) return;
			if (dout) echo("<");
			break;
		case '%':
			dopercen(&b[2]);
			break;
		default:
			prf("Use `~~' to start line with `~'");
		}
		continue;
	}
}

dopercen(line)
register char *line;
{
	char *args[10];
	register narg, f;
	int fk, v;
	int rcount, wcount, wrcret;
	for (narg = 0; narg < 10;) {
		while(*line == ' ' || *line == '\t')
			line++;
		if (*line == '\0')
			break;
		args[narg++] = line;
		while(*line != '\0' && *line != ' ' && *line != '\t')
			line++;
		if (*line == '\0')
			break;
		*line++ = '\0';
	}
	if (equal(args[0], "take")) {
		if (narg < 2) {
			prf("usage: ~%%take from [to]");
			return;
		}
		if (narg < 3)
			args[2] = args[1];
		wrln("echo '~>:'");
		wrln(args[2]);
		wrln(";tee /dev/null <");
		wrln(args[1]);
		wrln(";echo '~>'\n");
		return;
	} else if (equal(args[0], "put")) {
		if (narg < 2) {
			prf("usage: ~%%put from [to]");
			return;
		}
		if (narg < 3)
			args[2] = args[1];
		if ((f = open(args[1], 0)) < 0) {
			prf("cannot open: %s", args[1]);
			return;
		}
		wrln("stty -echo;cat >");
		wrln(args[2]);
		wrln(";stty echo\n");
		xsleep(5);
		intr = 0;
		if (!nhup)
			signal(2, sig2);
		mode(2);
		wcount = rcount = 0;
		while(!intr && rdc(f) == 1) {
			rcount++;
			if (c == tkill || c == terase)
				wrln("\\");
			if ((wrcret = wrc(ln)) == 1)
				wcount++;
			else {
				xsleep(2);
				if (wrc(ln) == 1)
					wcount++;
				else {
					prf("character missed");
					intr = 1;
					break;
				}
			}
		}
		signal(2, 1);
		close(f);
		if (intr) {
			wrln("\n");
			prf("stopped after %d bytes", rcount);
		}
		wrln("\004");
		xsleep(5);
		mode(1);
		return;
	}
	prf("~%%%s unknown\n",args[0]);
}

equal(s1, s2)
register char *s1, *s2;
{
	while (*s1++ == *s2)
		if (*s2++ == '\0')
			return(1);
	return(0);
}

wrln(s)
register char *s;
{
	while (*s)
		write(ln, s++, 1);
}

/*
 *	rd: read from remote: line -> 1
 *	catch:
 *	~>[>][:][file]
 *	stuff from file...
 *	~>	(ends diversion)
 */

rd()
{
	int ds,slnt;
	char *p,*q,b[600];
	p=b;
	ds=(-1);
	while (rdc(ln) == 1) {
		if (ds<0) slnt=0;
		if (!slnt) wrc(1);
		*p++=c;
		if (c!='\n') continue;
		q=p; 
		p=b;
		if (b[0]!='~' || b[1]!='>') {
			if (*(q-2) == '\r') {
				q--; 
				*(q-1)=(*q);
			}
			if (ds>=0) write(ds,b,q-b);
			continue;
		}
		if (ds>=0) close(ds);
		if (slnt) {
			write(1, b, q - b);
			write(1, CRLF);
		}
		if (*(q-2) == '\r') q--;
		*(q-1)=0;
		slnt=0;
		q=b+2;
		if (*q == '>') q++;
		if (*q == ':') {
			slnt=1; 
			q++;
		}
		if (*q == 0) {
			ds=(-1); 
			continue;
		}
		if (b[2]!='>' || (ds=open(q,1))<0) ds=creat(q,0644);
		seek(ds,0,2);
		if (ds<0) prf("Can't divert %s",b+1);
	}
}

struct {char lobyte; char hibyte;};
mode(f)
{
	int v[3];
	if (dout) return;
	gtty(0,v);
	tkill = v[1].hibyte;
	terase = v[1].lobyte;
	if (f == 0) {
		v[2]=& ~RAW;
		v[2]=| (ECHO|CRMOD);
	}
	if (f == 1) {
		v[2]=| RAW;
		v[2]=& ~(ECHO|CRMOD);
	}
	if (f == 2) {
		v[2]=& ~RAW;
		v[2]=& ~(ECHO|CRMOD);
	}
	stty(0,v);
}

echo(s)
char *s;
{
	char *p;
	for (p=s;*p;p++);
	if (p>s) write(0,s,p-s);
	write(0,CRLF);
}

dofork()
{
	register fk, i;
	for (i = 10; i < 60; i =+ 10) {
		if ((fk = fork()) != -1)
			return(fk);
	}
	prf(connmsg[4]);
	return(-1);
}

prf(a0,a1,a2,a3)
{
	extern int fout;
	fout=2;
	printf(a0,a1,a2,a3);
	write(2,CRLF);
}

exists(devname)
char *devname;
{
	struct  statb exstat;
	if (stat(devname, &exstat) == 0)
		return(1);
	prf("%s does not exist",devname);
	return(0);
}