xref: /plan9/sys/src/cmd/con/con.c (revision e40528ac90dd64788e1efb1e02a0e0a15ac54a49)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier #include "rustream.h"
53e12c5d1SDavid du Colombier #include "ruttyio.h"
63e12c5d1SDavid du Colombier #include "rusignal.h"
73e12c5d1SDavid du Colombier #include "rufilio.h"
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier int debug;		/* true if debugging */
103e12c5d1SDavid du Colombier int ctl = -1;		/* control fd (for break's) */
113e12c5d1SDavid du Colombier int raw;		/* true if raw is on */
123e12c5d1SDavid du Colombier int consctl = -1;	/* control fd for cons */
133e12c5d1SDavid du Colombier int ttypid;		/* pid's if the 2 processes (used to kill them) */
143e12c5d1SDavid du Colombier int msgfd = -1;		/* mesgld file descriptor (for signals to be written to) */
153e12c5d1SDavid du Colombier int outfd = 1;		/* local output file descriptor */
163e12c5d1SDavid du Colombier int cooked;		/* non-zero forces cooked mode */
173e12c5d1SDavid du Colombier int returns;		/* non-zero forces carriage returns not to be filtered out */
185d459b5aSDavid du Colombier int crtonl;			/* non-zero forces carriage returns to be converted to nls coming from net */
19219b2ee8SDavid du Colombier int	strip;		/* strip off parity bits */
209a747e4fSDavid du Colombier char firsterr[2*ERRMAX];
219a747e4fSDavid du Colombier char transerr[2*ERRMAX];
223e12c5d1SDavid du Colombier int limited;
233e12c5d1SDavid du Colombier char *remuser;
243e12c5d1SDavid du Colombier int verbose;
25219b2ee8SDavid du Colombier int baud;
267dd7cddfSDavid du Colombier int notkbd;
277dd7cddfSDavid du Colombier int nltocr;		/* translate kbd nl to cr  and vice versa */
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier typedef struct Msg Msg;
30219b2ee8SDavid du Colombier #define MAXMSG (2*8192)
313e12c5d1SDavid du Colombier 
323e12c5d1SDavid du Colombier int	dodial(char*, char*, char*);
333e12c5d1SDavid du Colombier void	fromkbd(int);
343e12c5d1SDavid du Colombier void	fromnet(int);
353e12c5d1SDavid du Colombier long	iread(int, void*, int);
363e12c5d1SDavid du Colombier long	iwrite(int, void*, int);
373e12c5d1SDavid du Colombier int	menu(int);
383e12c5d1SDavid du Colombier void	msgfromkbd(int);
393e12c5d1SDavid du Colombier void	msgfromnet(int);
403e12c5d1SDavid du Colombier int	msgwrite(int, void*, int);
413e12c5d1SDavid du Colombier void	notifyf(void*, char*);
423e12c5d1SDavid du Colombier void	pass(int, int, int);
433e12c5d1SDavid du Colombier void	rawoff(void);
443e12c5d1SDavid du Colombier void	rawon(void);
453e12c5d1SDavid du Colombier int	readupto(int, char*, int);
463e12c5d1SDavid du Colombier int	sendctl(int, int);
473e12c5d1SDavid du Colombier int	sendctl1(int, int, int);
483e12c5d1SDavid du Colombier void	stdcon(int);
493e12c5d1SDavid du Colombier char*	system(int, char*);
503e12c5d1SDavid du Colombier void	dosystem(int, char*);
513e12c5d1SDavid du Colombier int	wasintr(void);
523e12c5d1SDavid du Colombier void	punt(char*);
533e12c5d1SDavid du Colombier char*	syserr(void);
54219b2ee8SDavid du Colombier void	seterr(char*);
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier /* protocols */
573e12c5d1SDavid du Colombier void	device(char*, char*);
583e12c5d1SDavid du Colombier void	rlogin(char*, char*);
593e12c5d1SDavid du Colombier void	simple(char*, char*);
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier void
623e12c5d1SDavid du Colombier usage(void)
633e12c5d1SDavid du Colombier {
64*e40528acSDavid du Colombier 	punt("usage: con [-drCvsn] [-b baud] [-l [user]] [-c cmd] net!host[!service]");
653e12c5d1SDavid du Colombier }
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier void
683e12c5d1SDavid du Colombier main(int argc, char *argv[])
693e12c5d1SDavid du Colombier {
703e12c5d1SDavid du Colombier 	char *dest;
713e12c5d1SDavid du Colombier 	char *cmd = 0;
723e12c5d1SDavid du Colombier 
733e12c5d1SDavid du Colombier 	returns = 1;
743e12c5d1SDavid du Colombier 	ARGBEGIN{
75219b2ee8SDavid du Colombier 	case 'b':
76*e40528acSDavid du Colombier 		baud = atoi(EARGF(usage()));
77219b2ee8SDavid du Colombier 		break;
783e12c5d1SDavid du Colombier 	case 'd':
793e12c5d1SDavid du Colombier 		debug = 1;
803e12c5d1SDavid du Colombier 		break;
813e12c5d1SDavid du Colombier 	case 'l':
823e12c5d1SDavid du Colombier 		limited = 1;
839a747e4fSDavid du Colombier 		if(argv[1] != nil && argv[1][0] != '-')
843e12c5d1SDavid du Colombier 			remuser = ARGF();
853e12c5d1SDavid du Colombier 		break;
867dd7cddfSDavid du Colombier 	case 'n':
877dd7cddfSDavid du Colombier 		notkbd = 1;
887dd7cddfSDavid du Colombier 		break;
893e12c5d1SDavid du Colombier 	case 'r':
903e12c5d1SDavid du Colombier 		returns = 0;
913e12c5d1SDavid du Colombier 		break;
927dd7cddfSDavid du Colombier 	case 'R':
937dd7cddfSDavid du Colombier 		nltocr = 1;
947dd7cddfSDavid du Colombier 		break;
955d459b5aSDavid du Colombier 	case 'T':
965d459b5aSDavid du Colombier 		crtonl = 1;
975d459b5aSDavid du Colombier 		break;
983e12c5d1SDavid du Colombier 	case 'C':
993e12c5d1SDavid du Colombier 		cooked = 1;
1003e12c5d1SDavid du Colombier 		break;
1013e12c5d1SDavid du Colombier 	case 'c':
1023e12c5d1SDavid du Colombier 		cmd = ARGF();
1033e12c5d1SDavid du Colombier 		break;
1043e12c5d1SDavid du Colombier 	case 'v':
1053e12c5d1SDavid du Colombier 		verbose = 1;
1063e12c5d1SDavid du Colombier 		break;
107219b2ee8SDavid du Colombier 	case 's':
108219b2ee8SDavid du Colombier 		strip = 1;
109219b2ee8SDavid du Colombier 		break;
1103e12c5d1SDavid du Colombier 	default:
1113e12c5d1SDavid du Colombier 		usage();
1123e12c5d1SDavid du Colombier 	}ARGEND
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier 	if(argc != 1){
1153e12c5d1SDavid du Colombier 		if(remuser == 0)
1163e12c5d1SDavid du Colombier 			usage();
1173e12c5d1SDavid du Colombier 		dest = remuser;
1183e12c5d1SDavid du Colombier 		remuser = 0;
1193e12c5d1SDavid du Colombier 	} else
1203e12c5d1SDavid du Colombier 		dest = argv[0];
1217dd7cddfSDavid du Colombier 	if(*dest == '/' && strchr(dest, '!') == 0)
1223e12c5d1SDavid du Colombier 		device(dest, cmd);
1233e12c5d1SDavid du Colombier 	else if(limited){
1243e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1253e12c5d1SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1263e12c5d1SDavid du Colombier 	} else {
127219b2ee8SDavid du Colombier 		rlogin(dest, cmd);	/* doesn't return if dialout succeeds */
1283e12c5d1SDavid du Colombier 		simple(dest, cmd);	/* doesn't return if dialout succeeds */
1293e12c5d1SDavid du Colombier 	}
1303e12c5d1SDavid du Colombier 	punt(firsterr);
1313e12c5d1SDavid du Colombier }
1323e12c5d1SDavid du Colombier 
1333e12c5d1SDavid du Colombier /*
1343e12c5d1SDavid du Colombier  *  just dial and use as a byte stream with remote echo
1353e12c5d1SDavid du Colombier  */
1363e12c5d1SDavid du Colombier void
1373e12c5d1SDavid du Colombier simple(char *dest, char *cmd)
1383e12c5d1SDavid du Colombier {
1393e12c5d1SDavid du Colombier 	int net;
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	net = dodial(dest, 0, 0);
1423e12c5d1SDavid du Colombier 	if(net < 0)
1433e12c5d1SDavid du Colombier 		return;
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	if(cmd)
1463e12c5d1SDavid du Colombier 		dosystem(net, cmd);
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier 	if(!cooked)
1493e12c5d1SDavid du Colombier 		rawon();
1503e12c5d1SDavid du Colombier 	stdcon(net);
1513e12c5d1SDavid du Colombier 	exits(0);
1523e12c5d1SDavid du Colombier }
1533e12c5d1SDavid du Colombier 
1543e12c5d1SDavid du Colombier /*
1553e12c5d1SDavid du Colombier  *  dial, do UCB authentication, use as a byte stream with local echo
1563e12c5d1SDavid du Colombier  *
1573e12c5d1SDavid du Colombier  *  return if dial failed
1583e12c5d1SDavid du Colombier  */
1593e12c5d1SDavid du Colombier void
1603e12c5d1SDavid du Colombier rlogin(char *dest, char *cmd)
1613e12c5d1SDavid du Colombier {
1627dd7cddfSDavid du Colombier 	int net;
1639a747e4fSDavid du Colombier 	char buf[128];
1643e12c5d1SDavid du Colombier 	char *p;
1653e12c5d1SDavid du Colombier 	char *localuser;
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier 	/* only useful on TCP */
168bd389b36SDavid du Colombier 	if(strchr(dest, '!')
169bd389b36SDavid du Colombier 	&& (strncmp(dest, "tcp!", 4)!=0 && strncmp(dest, "net!", 4)!=0))
1703e12c5d1SDavid du Colombier 		return;
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier 	net = dodial(dest, "tcp", "login");
1733e12c5d1SDavid du Colombier 	if(net < 0)
1743e12c5d1SDavid du Colombier 		return;
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 	/*
1773e12c5d1SDavid du Colombier 	 *  do UCB rlogin authentication
1783e12c5d1SDavid du Colombier 	 */
1797dd7cddfSDavid du Colombier 	localuser = getuser();
1803e12c5d1SDavid du Colombier 	if(remuser == 0){
1813e12c5d1SDavid du Colombier 		if(limited)
1823e12c5d1SDavid du Colombier 			remuser = ":";
1833e12c5d1SDavid du Colombier 		else
1843e12c5d1SDavid du Colombier 			remuser = localuser;
1853e12c5d1SDavid du Colombier 	}
1863e12c5d1SDavid du Colombier 	p = getenv("TERM");
1873e12c5d1SDavid du Colombier 	if(p == 0)
1883e12c5d1SDavid du Colombier 		p = "p9";
1893e12c5d1SDavid du Colombier 	if(write(net, "", 1)<0
1903e12c5d1SDavid du Colombier 	|| write(net, localuser, strlen(localuser)+1)<0
1913e12c5d1SDavid du Colombier 	|| write(net, remuser, strlen(remuser)+1)<0
1923e12c5d1SDavid du Colombier 	|| write(net, p, strlen(p)+1)<0){
1933e12c5d1SDavid du Colombier 		close(net);
1943e12c5d1SDavid du Colombier 		punt("BSD authentication failed");
1953e12c5d1SDavid du Colombier 	}
1963e12c5d1SDavid du Colombier 	if(read(net, buf, 1) != 1)
1973e12c5d1SDavid du Colombier 		punt("BSD authentication failed1");
1983e12c5d1SDavid du Colombier 	if(buf[0] != 0){
1993e12c5d1SDavid du Colombier 		fprint(2, "con: remote error: ");
2003e12c5d1SDavid du Colombier 		while(read(net, buf, 1) == 1){
2013e12c5d1SDavid du Colombier 			write(2, buf, 1);
2023e12c5d1SDavid du Colombier 			if(buf[0] == '\n')
2033e12c5d1SDavid du Colombier 				break;
2043e12c5d1SDavid du Colombier 		}
2053e12c5d1SDavid du Colombier 		exits("read");
2063e12c5d1SDavid du Colombier 	}
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	if(cmd)
2093e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier 	if(!cooked)
2123e12c5d1SDavid du Colombier 		rawon();
2137dd7cddfSDavid du Colombier 	nltocr = 1;
2143e12c5d1SDavid du Colombier 	stdcon(net);
2153e12c5d1SDavid du Colombier 	exits(0);
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier /*
2193e12c5d1SDavid du Colombier  *  just open a device and use it as a connection
2203e12c5d1SDavid du Colombier  */
2213e12c5d1SDavid du Colombier void
2223e12c5d1SDavid du Colombier device(char *dest, char *cmd)
2233e12c5d1SDavid du Colombier {
2243e12c5d1SDavid du Colombier 	int net;
2259a747e4fSDavid du Colombier 	char cname[128];
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier 	net = open(dest, ORDWR);
2287dd7cddfSDavid du Colombier 	if(net < 0) {
2297dd7cddfSDavid du Colombier 		fprint(2, "con: cannot open %s: %r\n", dest);
2307dd7cddfSDavid du Colombier 		exits("open");
2317dd7cddfSDavid du Colombier 	}
2329a747e4fSDavid du Colombier 	snprint(cname, sizeof cname, "%sctl", dest);
2333e12c5d1SDavid du Colombier 	ctl = open(cname, ORDWR);
2349a747e4fSDavid du Colombier 	if (baud > 0) {
2359a747e4fSDavid du Colombier 		if(ctl >= 0)
236219b2ee8SDavid du Colombier 			fprint(ctl, "b%d", baud);
2379a747e4fSDavid du Colombier 		else
2389a747e4fSDavid du Colombier 			fprint(2, "con: cannot open %s: %r\n", cname);
2399a747e4fSDavid du Colombier 	}
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	if(cmd)
2423e12c5d1SDavid du Colombier 		dosystem(net, cmd);
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier 	if(!cooked)
2453e12c5d1SDavid du Colombier 		rawon();
2463e12c5d1SDavid du Colombier 	stdcon(net);
2473e12c5d1SDavid du Colombier 	exits(0);
2483e12c5d1SDavid du Colombier }
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier /*
2513e12c5d1SDavid du Colombier  *  ignore interrupts
2523e12c5d1SDavid du Colombier  */
2533e12c5d1SDavid du Colombier void
2543e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier 	USED(a);
2573e12c5d1SDavid du Colombier 
258d3c05884SDavid du Colombier 	if(strstr(msg, "yankee"))
259d3c05884SDavid du Colombier 		noted(NDFLT);
2603e12c5d1SDavid du Colombier 	if(strstr(msg, "closed pipe")
2613e12c5d1SDavid du Colombier 	|| strcmp(msg, "interrupt") == 0
2623e12c5d1SDavid du Colombier 	|| strcmp(msg, "hangup") == 0)
2633e12c5d1SDavid du Colombier 		noted(NCONT);
2643e12c5d1SDavid du Colombier 	noted(NDFLT);
2653e12c5d1SDavid du Colombier }
2663e12c5d1SDavid du Colombier 
2673e12c5d1SDavid du Colombier /*
2683e12c5d1SDavid du Colombier  *  turn keyboard raw mode on
2693e12c5d1SDavid du Colombier  */
2703e12c5d1SDavid du Colombier void
2713e12c5d1SDavid du Colombier rawon(void)
2723e12c5d1SDavid du Colombier {
2733e12c5d1SDavid du Colombier 	if(debug)
2743e12c5d1SDavid du Colombier 		fprint(2, "rawon\n");
2753e12c5d1SDavid du Colombier 	if(raw)
2763e12c5d1SDavid du Colombier 		return;
2773e12c5d1SDavid du Colombier 	if(consctl < 0)
2783e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
2793e12c5d1SDavid du Colombier 	if(consctl < 0){
2809a747e4fSDavid du Colombier //		fprint(2, "can't open consctl\n");
2813e12c5d1SDavid du Colombier 		return;
2823e12c5d1SDavid du Colombier 	}
2833e12c5d1SDavid du Colombier 	write(consctl, "rawon", 5);
2843e12c5d1SDavid du Colombier 	raw = 1;
2853e12c5d1SDavid du Colombier }
2863e12c5d1SDavid du Colombier 
2873e12c5d1SDavid du Colombier /*
2883e12c5d1SDavid du Colombier  *  turn keyboard raw mode off
2893e12c5d1SDavid du Colombier  */
2903e12c5d1SDavid du Colombier void
2913e12c5d1SDavid du Colombier rawoff(void)
2923e12c5d1SDavid du Colombier {
2933e12c5d1SDavid du Colombier 	if(debug)
2943e12c5d1SDavid du Colombier 		fprint(2, "rawoff\n");
2953e12c5d1SDavid du Colombier 	if(raw == 0)
2963e12c5d1SDavid du Colombier 		return;
2973e12c5d1SDavid du Colombier 	if(consctl < 0)
2983e12c5d1SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
2993e12c5d1SDavid du Colombier 	if(consctl < 0){
3009a747e4fSDavid du Colombier //		fprint(2, "can't open consctl\n");
3013e12c5d1SDavid du Colombier 		return;
3023e12c5d1SDavid du Colombier 	}
3033e12c5d1SDavid du Colombier 	write(consctl, "rawoff", 6);
3043e12c5d1SDavid du Colombier 	raw = 0;
3053e12c5d1SDavid du Colombier }
3063e12c5d1SDavid du Colombier 
3073e12c5d1SDavid du Colombier /*
3083e12c5d1SDavid du Colombier  *  control menu
3093e12c5d1SDavid du Colombier  */
3107dd7cddfSDavid du Colombier #define STDHELP	"\t(b)reak, (q)uit, (i)nterrupt, toggle printing (r)eturns, (.)continue, (!cmd)\n"
3113e12c5d1SDavid du Colombier 
3123e12c5d1SDavid du Colombier int
3133e12c5d1SDavid du Colombier menu(int net)
3143e12c5d1SDavid du Colombier {
3153e12c5d1SDavid du Colombier 	char buf[MAXMSG];
3163e12c5d1SDavid du Colombier 	long n;
3173e12c5d1SDavid du Colombier 	int done;
3183e12c5d1SDavid du Colombier 	int wasraw = raw;
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	if(wasraw)
3213e12c5d1SDavid du Colombier 		rawoff();
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier 	fprint(2, ">>> ");
3243e12c5d1SDavid du Colombier 	for(done = 0; !done; ){
3253e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf)-1);
3263e12c5d1SDavid du Colombier 		if(n <= 0)
3273e12c5d1SDavid du Colombier 			return -1;
3283e12c5d1SDavid du Colombier 		buf[n] = 0;
3293e12c5d1SDavid du Colombier 		switch(buf[0]){
3303e12c5d1SDavid du Colombier 		case '!':
3313e12c5d1SDavid du Colombier 			print(buf);
3323e12c5d1SDavid du Colombier 			system(net, buf+1);
3333e12c5d1SDavid du Colombier 			print("!\n");
3343e12c5d1SDavid du Colombier 			done = 1;
3353e12c5d1SDavid du Colombier 			break;
3363e12c5d1SDavid du Colombier 		case '.':
3373e12c5d1SDavid du Colombier 			done = 1;
3383e12c5d1SDavid du Colombier 			break;
3393e12c5d1SDavid du Colombier 		case 'q':
3403e12c5d1SDavid du Colombier 			return -1;
3413e12c5d1SDavid du Colombier 			break;
3423e12c5d1SDavid du Colombier 		case 'i':
3433e12c5d1SDavid du Colombier 			buf[0] = 0x1c;
3443e12c5d1SDavid du Colombier 			if(msgfd <= 0)
3453e12c5d1SDavid du Colombier 				write(net, buf, 1);
3463e12c5d1SDavid du Colombier 			else
3473e12c5d1SDavid du Colombier 				sendctl1(msgfd, M_SIGNAL, SIGQUIT);
3483e12c5d1SDavid du Colombier 			done = 1;
3493e12c5d1SDavid du Colombier 			break;
3503e12c5d1SDavid du Colombier 		case 'b':
3513e12c5d1SDavid du Colombier 			if(msgfd >= 0)
3523e12c5d1SDavid du Colombier 				sendctl(msgfd, M_BREAK);
3533e12c5d1SDavid du Colombier 			else if(ctl >= 0)
354219b2ee8SDavid du Colombier 				write(ctl, "k", 1);
355219b2ee8SDavid du Colombier 			done = 1;
356219b2ee8SDavid du Colombier 			break;
357219b2ee8SDavid du Colombier 		case 'r':
358219b2ee8SDavid du Colombier 			returns = 1-returns;
3593e12c5d1SDavid du Colombier 			done = 1;
3603e12c5d1SDavid du Colombier 			break;
3613e12c5d1SDavid du Colombier 		default:
3623e12c5d1SDavid du Colombier 			fprint(2, STDHELP);
3633e12c5d1SDavid du Colombier 			break;
3643e12c5d1SDavid du Colombier 		}
3653e12c5d1SDavid du Colombier 		if(!done)
3663e12c5d1SDavid du Colombier 			fprint(2, ">>> ");
3673e12c5d1SDavid du Colombier 	}
3683e12c5d1SDavid du Colombier 
3693e12c5d1SDavid du Colombier 	if(wasraw)
3703e12c5d1SDavid du Colombier 		rawon();
3713e12c5d1SDavid du Colombier 	else
3723e12c5d1SDavid du Colombier 		rawoff();
3733e12c5d1SDavid du Colombier 	return 0;
3743e12c5d1SDavid du Colombier }
3753e12c5d1SDavid du Colombier 
3763e12c5d1SDavid du Colombier /*
3773e12c5d1SDavid du Colombier  *  the real work.  two processes pass bytes back and forth between the
3783e12c5d1SDavid du Colombier  *  terminal and the network.
3793e12c5d1SDavid du Colombier  */
3803e12c5d1SDavid du Colombier void
3813e12c5d1SDavid du Colombier stdcon(int net)
3823e12c5d1SDavid du Colombier {
3833e12c5d1SDavid du Colombier 	int netpid;
3843e12c5d1SDavid du Colombier 
3853e12c5d1SDavid du Colombier 	ttypid = getpid();
3863e12c5d1SDavid du Colombier 	switch(netpid = rfork(RFMEM|RFPROC)){
3873e12c5d1SDavid du Colombier 	case -1:
3883e12c5d1SDavid du Colombier 		perror("con");
3893e12c5d1SDavid du Colombier 		exits("fork");
3903e12c5d1SDavid du Colombier 	case 0:
3913e12c5d1SDavid du Colombier 		notify(notifyf);
3923e12c5d1SDavid du Colombier 		fromnet(net);
393d3c05884SDavid du Colombier 		postnote(PNPROC, ttypid, "die yankee dog");
3943e12c5d1SDavid du Colombier 		exits(0);
3953e12c5d1SDavid du Colombier 	default:
3963e12c5d1SDavid du Colombier 		notify(notifyf);
3973e12c5d1SDavid du Colombier 		fromkbd(net);
3987dd7cddfSDavid du Colombier 		if(notkbd)
3997dd7cddfSDavid du Colombier 			for(;;)sleep(0);
400d3c05884SDavid du Colombier 		postnote(PNPROC, netpid, "die yankee dog");
4013e12c5d1SDavid du Colombier 		exits(0);
4023e12c5d1SDavid du Colombier 	}
4033e12c5d1SDavid du Colombier }
4043e12c5d1SDavid du Colombier 
4053e12c5d1SDavid du Colombier /*
4063e12c5d1SDavid du Colombier  *  Read the keyboard and write it to the network.  '^\' gets us into
4073e12c5d1SDavid du Colombier  *  the menu.
4083e12c5d1SDavid du Colombier  */
4093e12c5d1SDavid du Colombier void
4103e12c5d1SDavid du Colombier fromkbd(int net)
4113e12c5d1SDavid du Colombier {
4123e12c5d1SDavid du Colombier 	long n;
4133e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4147dd7cddfSDavid du Colombier 	char *p, *ep;
4157dd7cddfSDavid du Colombier 	int eofs;
4163e12c5d1SDavid du Colombier 
4177dd7cddfSDavid du Colombier 	eofs = 0;
4183e12c5d1SDavid du Colombier 	for(;;){
4193e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
4203e12c5d1SDavid du Colombier 		if(n < 0){
4213e12c5d1SDavid du Colombier 			if(wasintr()){
422d3c05884SDavid du Colombier 				if(!raw){
4233e12c5d1SDavid du Colombier 					buf[0] = 0x7f;
4243e12c5d1SDavid du Colombier 					n = 1;
4253e12c5d1SDavid du Colombier 				} else
4263e12c5d1SDavid du Colombier 					continue;
4273e12c5d1SDavid du Colombier 			} else
4283e12c5d1SDavid du Colombier 				return;
4293e12c5d1SDavid du Colombier 		}
4307dd7cddfSDavid du Colombier 		if(n == 0){
4317dd7cddfSDavid du Colombier 			if(++eofs > 32)
4327dd7cddfSDavid du Colombier 				return;
4337dd7cddfSDavid du Colombier 		} else
4347dd7cddfSDavid du Colombier 			eofs = 0;
4353e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0x1c, n)){
4363e12c5d1SDavid du Colombier 			if(menu(net) < 0)
4373e12c5d1SDavid du Colombier 				return;
4383e12c5d1SDavid du Colombier 		}else{
439d3c05884SDavid du Colombier 			if(!raw && n==0){
4403e12c5d1SDavid du Colombier 				buf[0] = 0x4;
4413e12c5d1SDavid du Colombier 				n = 1;
4423e12c5d1SDavid du Colombier 			}
4437dd7cddfSDavid du Colombier 			if(nltocr){
4447dd7cddfSDavid du Colombier 				ep = buf+n;
4457dd7cddfSDavid du Colombier 				for(p = buf; p < ep; p++)
4467dd7cddfSDavid du Colombier 					switch(*p){
4477dd7cddfSDavid du Colombier 					case '\r':
4487dd7cddfSDavid du Colombier 						*p = '\n';
4497dd7cddfSDavid du Colombier 						break;
4507dd7cddfSDavid du Colombier 					case '\n':
4517dd7cddfSDavid du Colombier 						*p = '\r';
4527dd7cddfSDavid du Colombier 						break;
4537dd7cddfSDavid du Colombier 					}
4547dd7cddfSDavid du Colombier 			}
4553e12c5d1SDavid du Colombier 			if(iwrite(net, buf, n) != n)
4563e12c5d1SDavid du Colombier 				return;
4573e12c5d1SDavid du Colombier 		}
4583e12c5d1SDavid du Colombier 	}
4593e12c5d1SDavid du Colombier }
4603e12c5d1SDavid du Colombier 
4613e12c5d1SDavid du Colombier /*
4623e12c5d1SDavid du Colombier  *  Read from the network and write to the screen.
4633e12c5d1SDavid du Colombier  *  Filter out spurious carriage returns.
4643e12c5d1SDavid du Colombier  */
4653e12c5d1SDavid du Colombier void
4663e12c5d1SDavid du Colombier fromnet(int net)
4673e12c5d1SDavid du Colombier {
4683e12c5d1SDavid du Colombier 	long n;
4693e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4703e12c5d1SDavid du Colombier 	char *cp, *ep;
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier 	for(;;){
4733e12c5d1SDavid du Colombier 		n = iread(net, buf, sizeof(buf));
4743e12c5d1SDavid du Colombier 		if(n < 0)
4753e12c5d1SDavid du Colombier 			return;
4763e12c5d1SDavid du Colombier 		if(n == 0)
4773e12c5d1SDavid du Colombier 			continue;
4783e12c5d1SDavid du Colombier 
479219b2ee8SDavid du Colombier 		if (strip)
480219b2ee8SDavid du Colombier 			for (cp=buf; cp<buf+n; cp++)
481219b2ee8SDavid du Colombier 				*cp &= 0177;
482219b2ee8SDavid du Colombier 
4835d459b5aSDavid du Colombier 		if(crtonl) {
4845d459b5aSDavid du Colombier 			/* convert cr's to nl's */
4855d459b5aSDavid du Colombier 			for (cp = buf; cp < buf + n; cp++)
4865d459b5aSDavid du Colombier 				if (*cp == '\r')
4875d459b5aSDavid du Colombier 					*cp = '\n';
4885d459b5aSDavid du Colombier 		}
4895d459b5aSDavid du Colombier 		else if(!returns){
4903e12c5d1SDavid du Colombier 			/* convert cr's to null's */
4913e12c5d1SDavid du Colombier 			cp = buf;
4923e12c5d1SDavid du Colombier 			ep = buf + n;
4933e12c5d1SDavid du Colombier 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
4943e12c5d1SDavid du Colombier 				memmove(cp, cp+1, ep-cp-1);
4953e12c5d1SDavid du Colombier 				ep--;
4963e12c5d1SDavid du Colombier 				n--;
4973e12c5d1SDavid du Colombier 			}
4983e12c5d1SDavid du Colombier 		}
4993e12c5d1SDavid du Colombier 
5003e12c5d1SDavid du Colombier 		if(n > 0 && iwrite(outfd, buf, n) != n){
5013e12c5d1SDavid du Colombier 			if(outfd == 1)
5023e12c5d1SDavid du Colombier 				return;
5033e12c5d1SDavid du Colombier 			outfd = 1;
5043e12c5d1SDavid du Colombier 			if(iwrite(1, buf, n) != n)
5053e12c5d1SDavid du Colombier 				return;
5063e12c5d1SDavid du Colombier 		}
5073e12c5d1SDavid du Colombier 	}
5083e12c5d1SDavid du Colombier }
5093e12c5d1SDavid du Colombier 
5103e12c5d1SDavid du Colombier /*
5113e12c5d1SDavid du Colombier  *  dial and return a data connection
5123e12c5d1SDavid du Colombier  */
5133e12c5d1SDavid du Colombier int
5143e12c5d1SDavid du Colombier dodial(char *dest, char *net, char *service)
5153e12c5d1SDavid du Colombier {
5169a747e4fSDavid du Colombier 	char name[128];
5179a747e4fSDavid du Colombier 	char devdir[128];
5183e12c5d1SDavid du Colombier 	int data;
5193e12c5d1SDavid du Colombier 
5203e12c5d1SDavid du Colombier 	devdir[0] = 0;
5213e12c5d1SDavid du Colombier 	strcpy(name, netmkaddr(dest, net, service));
522bd389b36SDavid du Colombier 	data = dial(name, 0, devdir, &ctl);
5233e12c5d1SDavid du Colombier 	if(data < 0){
524219b2ee8SDavid du Colombier 		seterr(name);
5253e12c5d1SDavid du Colombier 		return -1;
5263e12c5d1SDavid du Colombier 	}
5273e12c5d1SDavid du Colombier 	fprint(2, "connected to %s on %s\n", name, devdir);
5283e12c5d1SDavid du Colombier 	return data;
5293e12c5d1SDavid du Colombier }
5303e12c5d1SDavid du Colombier 
5313e12c5d1SDavid du Colombier void
5323e12c5d1SDavid du Colombier dosystem(int fd, char *cmd)
5333e12c5d1SDavid du Colombier {
5343e12c5d1SDavid du Colombier 	char *p;
5353e12c5d1SDavid du Colombier 
5363e12c5d1SDavid du Colombier 	p = system(fd, cmd);
537fbdb243dSDavid du Colombier 	if(p){
5387dd7cddfSDavid du Colombier 		print("con: %s terminated with %s\n", cmd, p);
5393e12c5d1SDavid du Colombier 		exits(p);
5403e12c5d1SDavid du Colombier 	}
5413e12c5d1SDavid du Colombier }
5423e12c5d1SDavid du Colombier 
5433e12c5d1SDavid du Colombier /*
5443e12c5d1SDavid du Colombier  *  run a command with the network connection as standard IO
5453e12c5d1SDavid du Colombier  */
5463e12c5d1SDavid du Colombier char *
5473e12c5d1SDavid du Colombier system(int fd, char *cmd)
5483e12c5d1SDavid du Colombier {
5493e12c5d1SDavid du Colombier 	int pid;
5503e12c5d1SDavid du Colombier 	int p;
5513e12c5d1SDavid du Colombier 	static Waitmsg msg;
5523e12c5d1SDavid du Colombier 	int pfd[2];
5533e12c5d1SDavid du Colombier 	int n;
5543e12c5d1SDavid du Colombier 	char buf[4096];
5553e12c5d1SDavid du Colombier 
5563e12c5d1SDavid du Colombier 	if(pipe(pfd) < 0){
5573e12c5d1SDavid du Colombier 		perror("pipe");
5583e12c5d1SDavid du Colombier 		return "pipe failed";
5593e12c5d1SDavid du Colombier 	}
5603e12c5d1SDavid du Colombier 	outfd = pfd[1];
5613e12c5d1SDavid du Colombier 
562219b2ee8SDavid du Colombier 	close(consctl);
563219b2ee8SDavid du Colombier 	consctl = -1;
5643e12c5d1SDavid du Colombier 	switch(pid = fork()){
5653e12c5d1SDavid du Colombier 	case -1:
5663e12c5d1SDavid du Colombier 		perror("con");
5673e12c5d1SDavid du Colombier 		return "fork failed";
5683e12c5d1SDavid du Colombier 	case 0:
5693e12c5d1SDavid du Colombier 		close(pfd[1]);
5703e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
5713ff48bf5SDavid du Colombier 		dup(fd, 1);
5723e12c5d1SDavid du Colombier 		close(ctl);
5733e12c5d1SDavid du Colombier 		close(fd);
5743e12c5d1SDavid du Colombier 		close(pfd[0]);
5753e12c5d1SDavid du Colombier 		if(*cmd)
5763e12c5d1SDavid du Colombier 			execl("/bin/rc", "rc", "-c", cmd, 0);
5773e12c5d1SDavid du Colombier 		else
5783e12c5d1SDavid du Colombier 			execl("/bin/rc", "rc", 0);
5793e12c5d1SDavid du Colombier 		perror("con");
5803e12c5d1SDavid du Colombier 		exits("exec");
5813e12c5d1SDavid du Colombier 		break;
5823e12c5d1SDavid du Colombier 	default:
5833e12c5d1SDavid du Colombier 		close(pfd[0]);
5843e12c5d1SDavid du Colombier 		while((n = read(pfd[1], buf, sizeof(buf))) > 0){
5853e12c5d1SDavid du Colombier 			if(msgfd >= 0){
5863e12c5d1SDavid du Colombier 				if(msgwrite(fd, buf, n) != n)
5873e12c5d1SDavid du Colombier 					break;
5883e12c5d1SDavid du Colombier 			} else {
5893e12c5d1SDavid du Colombier 				if(write(fd, buf, n) != n)
5903e12c5d1SDavid du Colombier 					break;
5913e12c5d1SDavid du Colombier 			}
5923e12c5d1SDavid du Colombier 		}
5939a747e4fSDavid du Colombier 		p = waitpid();
5943e12c5d1SDavid du Colombier 		outfd = 1;
5953e12c5d1SDavid du Colombier 		close(pfd[1]);
596219b2ee8SDavid du Colombier 		if(p < 0 || p != pid)
597219b2ee8SDavid du Colombier 			return "lost child";
5983e12c5d1SDavid du Colombier 		break;
5993e12c5d1SDavid du Colombier 	}
600219b2ee8SDavid du Colombier 	return msg.msg;
6013e12c5d1SDavid du Colombier }
6023e12c5d1SDavid du Colombier 
6033e12c5d1SDavid du Colombier int
6043e12c5d1SDavid du Colombier wasintr(void)
6053e12c5d1SDavid du Colombier {
6063e12c5d1SDavid du Colombier 	return strcmp(syserr(), "interrupted") == 0;
6073e12c5d1SDavid du Colombier }
6083e12c5d1SDavid du Colombier 
6093e12c5d1SDavid du Colombier void
6103e12c5d1SDavid du Colombier punt(char *msg)
6113e12c5d1SDavid du Colombier {
6123e12c5d1SDavid du Colombier 	if(*msg == 0)
6133e12c5d1SDavid du Colombier 		msg = transerr;
6143e12c5d1SDavid du Colombier 	fprint(2, "con: %s\n", msg);
6153e12c5d1SDavid du Colombier 	exits(msg);
6163e12c5d1SDavid du Colombier }
6173e12c5d1SDavid du Colombier 
6183e12c5d1SDavid du Colombier char*
6193e12c5d1SDavid du Colombier syserr(void)
6203e12c5d1SDavid du Colombier {
6219a747e4fSDavid du Colombier 	static char err[ERRMAX];
6229a747e4fSDavid du Colombier 	errstr(err, sizeof err);
6233e12c5d1SDavid du Colombier 	return err;
6243e12c5d1SDavid du Colombier }
6253e12c5d1SDavid du Colombier 
6263e12c5d1SDavid du Colombier void
627219b2ee8SDavid du Colombier seterr(char *addr)
6283e12c5d1SDavid du Colombier {
6293e12c5d1SDavid du Colombier 	char *se = syserr();
6303e12c5d1SDavid du Colombier 
6313e12c5d1SDavid du Colombier 	if(verbose)
632219b2ee8SDavid du Colombier 		fprint(2, "'%s' calling %s\n", se, addr);
6333e12c5d1SDavid du Colombier 	if(firsterr[0] && (strstr(se, "translate") ||
6343e12c5d1SDavid du Colombier 	 strstr(se, "file does not exist") ||
6353e12c5d1SDavid du Colombier 	 strstr(se, "unknown address") ||
6363e12c5d1SDavid du Colombier 	 strstr(se, "directory entry not found")))
6373e12c5d1SDavid du Colombier 		return;
6383e12c5d1SDavid du Colombier 	strcpy(firsterr, se);
6393e12c5d1SDavid du Colombier }
6403e12c5d1SDavid du Colombier 
6413e12c5d1SDavid du Colombier 
6423e12c5d1SDavid du Colombier long
6433e12c5d1SDavid du Colombier iread(int f, void *a, int n)
6443e12c5d1SDavid du Colombier {
6453e12c5d1SDavid du Colombier 	long m;
6463e12c5d1SDavid du Colombier 
6473e12c5d1SDavid du Colombier 	for(;;){
6483e12c5d1SDavid du Colombier 		m = read(f, a, n);
6493e12c5d1SDavid du Colombier 		if(m >= 0 || !wasintr())
6503e12c5d1SDavid du Colombier 			break;
6513e12c5d1SDavid du Colombier 	}
6523e12c5d1SDavid du Colombier 	return m;
6533e12c5d1SDavid du Colombier }
6543e12c5d1SDavid du Colombier 
6553e12c5d1SDavid du Colombier long
6563e12c5d1SDavid du Colombier iwrite(int f, void *a, int n)
6573e12c5d1SDavid du Colombier {
6583e12c5d1SDavid du Colombier 	long m;
6593e12c5d1SDavid du Colombier 
6603e12c5d1SDavid du Colombier 	m = write(f, a, n);
6613e12c5d1SDavid du Colombier 	if(m < 0 && wasintr())
6623e12c5d1SDavid du Colombier 		return n;
6633e12c5d1SDavid du Colombier 	return m;
6643e12c5d1SDavid du Colombier }
6653e12c5d1SDavid du Colombier 
6663e12c5d1SDavid du Colombier /*
6673e12c5d1SDavid du Colombier  *  The rest is to support the V10 mesgld protocol.
6683e12c5d1SDavid du Colombier  */
6693e12c5d1SDavid du Colombier 
6703e12c5d1SDavid du Colombier /*
6713e12c5d1SDavid du Colombier  *  network orderings
6723e12c5d1SDavid du Colombier  */
6733e12c5d1SDavid du Colombier #define get2byte(p) ((p)[0] + ((p)[1]<<8))
6743e12c5d1SDavid du Colombier #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
6753e12c5d1SDavid du Colombier #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
6763e12c5d1SDavid du Colombier #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
6773e12c5d1SDavid du Colombier 
6783e12c5d1SDavid du Colombier /*
6793e12c5d1SDavid du Colombier  *  tty parameters
6803e12c5d1SDavid du Colombier  */
6813e12c5d1SDavid du Colombier int sgflags = ECHO;
6823e12c5d1SDavid du Colombier 
6833e12c5d1SDavid du Colombier /*
6843e12c5d1SDavid du Colombier  *  a mesgld message
6853e12c5d1SDavid du Colombier  */
6863e12c5d1SDavid du Colombier struct Msg {
6873e12c5d1SDavid du Colombier 	struct mesg h;
6883e12c5d1SDavid du Colombier 	char b[MAXMSG];
6893e12c5d1SDavid du Colombier };
6903e12c5d1SDavid du Colombier 
6913e12c5d1SDavid du Colombier 
6923e12c5d1SDavid du Colombier /*
6933e12c5d1SDavid du Colombier  *  send an empty mesgld message
6943e12c5d1SDavid du Colombier  */
6953e12c5d1SDavid du Colombier int
6963e12c5d1SDavid du Colombier sendctl(int net, int type)
6973e12c5d1SDavid du Colombier {
6983e12c5d1SDavid du Colombier 	Msg m;
6993e12c5d1SDavid du Colombier 
7003e12c5d1SDavid du Colombier 	m.h.type = type;
7013e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
7023e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
7033e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
7043e12c5d1SDavid du Colombier 		return -1;
7053e12c5d1SDavid du Colombier 	return 0;
7063e12c5d1SDavid du Colombier }
7073e12c5d1SDavid du Colombier 
7083e12c5d1SDavid du Colombier /*
7093e12c5d1SDavid du Colombier  *  send a one byte mesgld message
7103e12c5d1SDavid du Colombier  */
7113e12c5d1SDavid du Colombier int
7123e12c5d1SDavid du Colombier sendctl1(int net, int type, int parm)
7133e12c5d1SDavid du Colombier {
7143e12c5d1SDavid du Colombier 	Msg m;
7153e12c5d1SDavid du Colombier 
7163e12c5d1SDavid du Colombier 	m.h.type = type;
7173e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
7183e12c5d1SDavid du Colombier 	m.b[0] = parm;
7193e12c5d1SDavid du Colombier 	put2byte(m.h.size, 1);
7203e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
7213e12c5d1SDavid du Colombier 		return -1;
7223e12c5d1SDavid du Colombier 	return 0;
7233e12c5d1SDavid du Colombier }
7243e12c5d1SDavid du Colombier 
7253e12c5d1SDavid du Colombier /*
7263e12c5d1SDavid du Colombier  *  read n bytes.  return -1 if it fails, 0 otherwise.
7273e12c5d1SDavid du Colombier  */
7283e12c5d1SDavid du Colombier int
7293e12c5d1SDavid du Colombier readupto(int from, char *a, int len)
7303e12c5d1SDavid du Colombier {
7313e12c5d1SDavid du Colombier 	int n;
7323e12c5d1SDavid du Colombier 
7333e12c5d1SDavid du Colombier 	while(len > 0){
7343e12c5d1SDavid du Colombier 		n = iread(from, a, len);
7353e12c5d1SDavid du Colombier 		if(n < 0)
7363e12c5d1SDavid du Colombier 			return -1;
7373e12c5d1SDavid du Colombier 		a += n;
7383e12c5d1SDavid du Colombier 		len -= n;
7393e12c5d1SDavid du Colombier 	}
7403e12c5d1SDavid du Colombier 	return 0;
7413e12c5d1SDavid du Colombier }
7423e12c5d1SDavid du Colombier 
7433e12c5d1SDavid du Colombier /*
7443e12c5d1SDavid du Colombier  *  Decode a mesgld message from the network
7453e12c5d1SDavid du Colombier  */
7463e12c5d1SDavid du Colombier void
7473e12c5d1SDavid du Colombier msgfromnet(int net)
7483e12c5d1SDavid du Colombier {
7493e12c5d1SDavid du Colombier 	ulong com;
7503e12c5d1SDavid du Colombier 	struct stioctl *io;
7513e12c5d1SDavid du Colombier 	struct sgttyb *sg;
7523e12c5d1SDavid du Colombier 	struct ttydevb *td;
7533e12c5d1SDavid du Colombier 	struct tchars *tc;
7543e12c5d1SDavid du Colombier 	int len;
7553e12c5d1SDavid du Colombier 	Msg m;
7563e12c5d1SDavid du Colombier 
7573e12c5d1SDavid du Colombier 	for(;;){
7583e12c5d1SDavid du Colombier 		/* get a complete mesgld message */
7593e12c5d1SDavid du Colombier 		if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
7603e12c5d1SDavid du Colombier 			break;
7613e12c5d1SDavid du Colombier 		if(m.h.magic != MSGMAGIC){
7623e12c5d1SDavid du Colombier 			fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
7633e12c5d1SDavid du Colombier 			break;
7643e12c5d1SDavid du Colombier 		}
7653e12c5d1SDavid du Colombier 		len = get2byte(m.h.size);
766219b2ee8SDavid du Colombier 		if(len > sizeof(m.b)){
767219b2ee8SDavid du Colombier 			len = sizeof(m.b);
768219b2ee8SDavid du Colombier 			fprint(2, "con: mesgld message too long\n");
769219b2ee8SDavid du Colombier 		}
7703e12c5d1SDavid du Colombier 		if(len && readupto(net, m.b, len) < 0)
7713e12c5d1SDavid du Colombier 			break;
7723e12c5d1SDavid du Colombier 
7733e12c5d1SDavid du Colombier 		/* decode */
7743e12c5d1SDavid du Colombier 		switch(m.h.type){
7753e12c5d1SDavid du Colombier 		case M_HANGUP:
7763e12c5d1SDavid du Colombier 			if(debug)
7773e12c5d1SDavid du Colombier 				fprint(2, "M_HANGUP\n");
7783e12c5d1SDavid du Colombier 			return;
7793e12c5d1SDavid du Colombier 		case M_DATA:
7803e12c5d1SDavid du Colombier 			if(debug)
7813e12c5d1SDavid du Colombier 				fprint(2, "M_DATA %d bytes\n", len);
7823e12c5d1SDavid du Colombier 			if(iwrite(outfd, m.b, len) != len){
7833e12c5d1SDavid du Colombier 				if(outfd == 1)
7843e12c5d1SDavid du Colombier 					return;
7853e12c5d1SDavid du Colombier 				outfd = 1;
7863e12c5d1SDavid du Colombier 				if(iwrite(outfd, m.b, len) != len)
7873e12c5d1SDavid du Colombier 					return;
7883e12c5d1SDavid du Colombier 			}
7893e12c5d1SDavid du Colombier 			continue;
7903e12c5d1SDavid du Colombier 		case M_IOCTL:
7913e12c5d1SDavid du Colombier 			break;
7923e12c5d1SDavid du Colombier 		default:
7933e12c5d1SDavid du Colombier 			/* ignore */
7943e12c5d1SDavid du Colombier 			if(debug)
795219b2ee8SDavid du Colombier 				fprint(2, "con: unknown message\n");
7963e12c5d1SDavid du Colombier 			continue;
7973e12c5d1SDavid du Colombier 		}
7983e12c5d1SDavid du Colombier 
7993e12c5d1SDavid du Colombier 		/*
8003e12c5d1SDavid du Colombier 		 *  answer an ioctl
8013e12c5d1SDavid du Colombier 		 */
8023e12c5d1SDavid du Colombier 		io = (struct stioctl *)m.b;
8033e12c5d1SDavid du Colombier 		com = get4byte(io->com);
8043e12c5d1SDavid du Colombier 		if(debug)
8057dd7cddfSDavid du Colombier 			fprint(2, "M_IOCTL %lud\n", com);
8063e12c5d1SDavid du Colombier 		switch(com){
8073e12c5d1SDavid du Colombier 		case FIOLOOKLD:
8083e12c5d1SDavid du Colombier 			put4byte(io->data, tty_ld);
8093e12c5d1SDavid du Colombier 			len = 0;
8103e12c5d1SDavid du Colombier 			break;
8113e12c5d1SDavid du Colombier 		case TIOCGETP:
8123e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
8133e12c5d1SDavid du Colombier 			sg->sg_ispeed = sg->sg_ospeed = B9600;
8143e12c5d1SDavid du Colombier 			sg->sg_erase = 0010;	/* back space */
8153e12c5d1SDavid du Colombier 			sg->sg_kill = 0025;	/* CNTL U */
8163e12c5d1SDavid du Colombier 			put2byte(sg->sg_flags, sgflags);
8173e12c5d1SDavid du Colombier 			len = sizeof(struct sgttyb);
8183e12c5d1SDavid du Colombier 			break;
8193e12c5d1SDavid du Colombier 		case TIOCSETN:
8203e12c5d1SDavid du Colombier 		case TIOCSETP:
8213e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
8223e12c5d1SDavid du Colombier 			sgflags = get2byte(sg->sg_flags);
8233e12c5d1SDavid du Colombier 			if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
8243e12c5d1SDavid du Colombier 				rawon();
8253e12c5d1SDavid du Colombier 			else
8263e12c5d1SDavid du Colombier 				rawoff();
8273e12c5d1SDavid du Colombier 			len = 0;
8283e12c5d1SDavid du Colombier 			break;
8293e12c5d1SDavid du Colombier 		case TIOCGETC:
8303e12c5d1SDavid du Colombier 			tc = (struct tchars *)io->data;
8313e12c5d1SDavid du Colombier 			tc->t_intrc = 0177;
8323e12c5d1SDavid du Colombier 			tc->t_quitc = 0034;
8333e12c5d1SDavid du Colombier 			tc->t_startc = 0;
8343e12c5d1SDavid du Colombier 			tc->t_stopc = 0;
8353e12c5d1SDavid du Colombier 			tc->t_eofc = 0004;
8363e12c5d1SDavid du Colombier 			tc->t_brkc = 0;
8373e12c5d1SDavid du Colombier 			len = sizeof(struct tchars);
8383e12c5d1SDavid du Colombier 			break;
8393e12c5d1SDavid du Colombier 		case TIOCSETC:
8403e12c5d1SDavid du Colombier 			len = 0;
8413e12c5d1SDavid du Colombier 			break;
8423e12c5d1SDavid du Colombier 		case TIOCGDEV:
8433e12c5d1SDavid du Colombier 			td = (struct ttydevb *)io->data;
8443e12c5d1SDavid du Colombier 			td->ispeed = td->ospeed = B9600;
8453e12c5d1SDavid du Colombier 			put2byte(td->flags, 0);
8463e12c5d1SDavid du Colombier 			len = sizeof(struct ttydevb);
8473e12c5d1SDavid du Colombier 			break;
8483e12c5d1SDavid du Colombier 		case TIOCSDEV:
8493e12c5d1SDavid du Colombier 			len = 0;
8503e12c5d1SDavid du Colombier 			break;
8513e12c5d1SDavid du Colombier 		default:
8523e12c5d1SDavid du Colombier 			/*
8533e12c5d1SDavid du Colombier 			 *  unimplemented
8543e12c5d1SDavid du Colombier 			 */
8553e12c5d1SDavid du Colombier 			m.b[len] = 0;
8563e12c5d1SDavid du Colombier 			if(sendctl(net, M_IOCNAK) < 0)
8573e12c5d1SDavid du Colombier 				return;
8583e12c5d1SDavid du Colombier 			continue;
8593e12c5d1SDavid du Colombier 		}
8603e12c5d1SDavid du Colombier 
8613e12c5d1SDavid du Colombier 		/*
8623e12c5d1SDavid du Colombier 		 *  acknowledge
8633e12c5d1SDavid du Colombier 		 */
8643e12c5d1SDavid du Colombier 		m.h.type = M_IOCACK;
8653e12c5d1SDavid du Colombier 		m.h.magic = MSGMAGIC;
8663e12c5d1SDavid du Colombier 		len += 4;
8673e12c5d1SDavid du Colombier 		put2byte(m.h.size, len);
8683e12c5d1SDavid du Colombier 		len += sizeof(struct mesg);
8693e12c5d1SDavid du Colombier 		if(iwrite(net, &m, len) != len)
8703e12c5d1SDavid du Colombier 			return;
8713e12c5d1SDavid du Colombier 	}
8723e12c5d1SDavid du Colombier }
8733e12c5d1SDavid du Colombier 
8743e12c5d1SDavid du Colombier /*
8753e12c5d1SDavid du Colombier  *  Read the keyboard, convert to mesgld messages, and write it to the network.
8763e12c5d1SDavid du Colombier  *  '^\' gets us into the menu.
8773e12c5d1SDavid du Colombier  */
8783e12c5d1SDavid du Colombier void
8793e12c5d1SDavid du Colombier msgfromkbd(int net)
8803e12c5d1SDavid du Colombier {
8813e12c5d1SDavid du Colombier 	long n;
8823e12c5d1SDavid du Colombier 	char buf[MAXMSG];
8833e12c5d1SDavid du Colombier 
8843e12c5d1SDavid du Colombier 	for(;;){
8853e12c5d1SDavid du Colombier 		n = iread(0, buf, sizeof(buf));
8863e12c5d1SDavid du Colombier 		if(n < 0)
8873e12c5d1SDavid du Colombier 			return;
8883e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0034, n)){
8893e12c5d1SDavid du Colombier 			if(menu(net) < 0)
8903e12c5d1SDavid du Colombier 				return;
8913e12c5d1SDavid du Colombier 		} else {
8923e12c5d1SDavid du Colombier 			if(msgwrite(net, buf, n) != n)
8933e12c5d1SDavid du Colombier 				return;
8943e12c5d1SDavid du Colombier 		}
8953e12c5d1SDavid du Colombier 	}
8963e12c5d1SDavid du Colombier }
8973e12c5d1SDavid du Colombier 
8983e12c5d1SDavid du Colombier int
8993e12c5d1SDavid du Colombier msgwrite(int fd, void *buf, int len)
9003e12c5d1SDavid du Colombier {
9013e12c5d1SDavid du Colombier 	Msg m;
9023e12c5d1SDavid du Colombier 	int n;
9033e12c5d1SDavid du Colombier 
9043e12c5d1SDavid du Colombier 	n = len;
9053e12c5d1SDavid du Colombier 	memmove(m.b, buf, n);
9063e12c5d1SDavid du Colombier 	put2byte(m.h.size, n);
9073e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
9083e12c5d1SDavid du Colombier 	m.h.type = M_DATA;
9093e12c5d1SDavid du Colombier 	n += sizeof(struct mesg);
9103e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
9113e12c5d1SDavid du Colombier 		return -1;
9123e12c5d1SDavid du Colombier 
9133e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
9143e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
9153e12c5d1SDavid du Colombier 	m.h.type = M_DELIM;
9163e12c5d1SDavid du Colombier 	n = sizeof(struct mesg);
9173e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
9183e12c5d1SDavid du Colombier 		return -1;
9193e12c5d1SDavid du Colombier 
9203e12c5d1SDavid du Colombier 	return len;
9213e12c5d1SDavid du Colombier }
9223e12c5d1SDavid du Colombier 
923