xref: /plan9/sys/src/cmd/con/con.c (revision 6dc4800d6557134cc8e30198a5f4a7fa188deb3b)
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;
23*6dc4800dSDavid du Colombier char *remuser;		/* for BSD rlogin authentication */
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 {
6422a127bbSDavid du Colombier 	punt("usage: con [-CdnrRsTv] [-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':
76e40528acSDavid 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 		case 'i':
3423e12c5d1SDavid du Colombier 			buf[0] = 0x1c;
3433e12c5d1SDavid du Colombier 			if(msgfd <= 0)
3443e12c5d1SDavid du Colombier 				write(net, buf, 1);
3453e12c5d1SDavid du Colombier 			else
3463e12c5d1SDavid du Colombier 				sendctl1(msgfd, M_SIGNAL, SIGQUIT);
3473e12c5d1SDavid du Colombier 			done = 1;
3483e12c5d1SDavid du Colombier 			break;
3493e12c5d1SDavid du Colombier 		case 'b':
3503e12c5d1SDavid du Colombier 			if(msgfd >= 0)
3513e12c5d1SDavid du Colombier 				sendctl(msgfd, M_BREAK);
3523e12c5d1SDavid du Colombier 			else if(ctl >= 0)
353219b2ee8SDavid du Colombier 				write(ctl, "k", 1);
354219b2ee8SDavid du Colombier 			done = 1;
355219b2ee8SDavid du Colombier 			break;
356219b2ee8SDavid du Colombier 		case 'r':
357219b2ee8SDavid du Colombier 			returns = 1-returns;
3583e12c5d1SDavid du Colombier 			done = 1;
3593e12c5d1SDavid du Colombier 			break;
3603e12c5d1SDavid du Colombier 		default:
3613e12c5d1SDavid du Colombier 			fprint(2, STDHELP);
3623e12c5d1SDavid du Colombier 			break;
3633e12c5d1SDavid du Colombier 		}
3643e12c5d1SDavid du Colombier 		if(!done)
3653e12c5d1SDavid du Colombier 			fprint(2, ">>> ");
3663e12c5d1SDavid du Colombier 	}
3673e12c5d1SDavid du Colombier 
3683e12c5d1SDavid du Colombier 	if(wasraw)
3693e12c5d1SDavid du Colombier 		rawon();
3703e12c5d1SDavid du Colombier 	else
3713e12c5d1SDavid du Colombier 		rawoff();
3723e12c5d1SDavid du Colombier 	return 0;
3733e12c5d1SDavid du Colombier }
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier /*
3763e12c5d1SDavid du Colombier  *  the real work.  two processes pass bytes back and forth between the
3773e12c5d1SDavid du Colombier  *  terminal and the network.
3783e12c5d1SDavid du Colombier  */
3793e12c5d1SDavid du Colombier void
3803e12c5d1SDavid du Colombier stdcon(int net)
3813e12c5d1SDavid du Colombier {
3823e12c5d1SDavid du Colombier 	int netpid;
3833e12c5d1SDavid du Colombier 
3843e12c5d1SDavid du Colombier 	ttypid = getpid();
3853e12c5d1SDavid du Colombier 	switch(netpid = rfork(RFMEM|RFPROC)){
3863e12c5d1SDavid du Colombier 	case -1:
3873e12c5d1SDavid du Colombier 		perror("con");
3883e12c5d1SDavid du Colombier 		exits("fork");
3893e12c5d1SDavid du Colombier 	case 0:
3903e12c5d1SDavid du Colombier 		notify(notifyf);
3913e12c5d1SDavid du Colombier 		fromnet(net);
392d3c05884SDavid du Colombier 		postnote(PNPROC, ttypid, "die yankee dog");
3933e12c5d1SDavid du Colombier 		exits(0);
3943e12c5d1SDavid du Colombier 	default:
3953e12c5d1SDavid du Colombier 		notify(notifyf);
3963e12c5d1SDavid du Colombier 		fromkbd(net);
3977dd7cddfSDavid du Colombier 		if(notkbd)
3987dd7cddfSDavid du Colombier 			for(;;)sleep(0);
399d3c05884SDavid du Colombier 		postnote(PNPROC, netpid, "die yankee dog");
4003e12c5d1SDavid du Colombier 		exits(0);
4013e12c5d1SDavid du Colombier 	}
4023e12c5d1SDavid du Colombier }
4033e12c5d1SDavid du Colombier 
4043e12c5d1SDavid du Colombier /*
4053e12c5d1SDavid du Colombier  *  Read the keyboard and write it to the network.  '^\' gets us into
4063e12c5d1SDavid du Colombier  *  the menu.
4073e12c5d1SDavid du Colombier  */
4083e12c5d1SDavid du Colombier void
4093e12c5d1SDavid du Colombier fromkbd(int net)
4103e12c5d1SDavid du Colombier {
4113e12c5d1SDavid du Colombier 	long n;
4123e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4137dd7cddfSDavid du Colombier 	char *p, *ep;
4147dd7cddfSDavid du Colombier 	int eofs;
4153e12c5d1SDavid du Colombier 
4167dd7cddfSDavid du Colombier 	eofs = 0;
4173e12c5d1SDavid du Colombier 	for(;;){
4183e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
4193e12c5d1SDavid du Colombier 		if(n < 0){
4203e12c5d1SDavid du Colombier 			if(wasintr()){
421d3c05884SDavid du Colombier 				if(!raw){
4223e12c5d1SDavid du Colombier 					buf[0] = 0x7f;
4233e12c5d1SDavid du Colombier 					n = 1;
4243e12c5d1SDavid du Colombier 				} else
4253e12c5d1SDavid du Colombier 					continue;
4263e12c5d1SDavid du Colombier 			} else
4273e12c5d1SDavid du Colombier 				return;
4283e12c5d1SDavid du Colombier 		}
4297dd7cddfSDavid du Colombier 		if(n == 0){
4307dd7cddfSDavid du Colombier 			if(++eofs > 32)
4317dd7cddfSDavid du Colombier 				return;
4327dd7cddfSDavid du Colombier 		} else
4337dd7cddfSDavid du Colombier 			eofs = 0;
4343e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0x1c, n)){
4353e12c5d1SDavid du Colombier 			if(menu(net) < 0)
4363e12c5d1SDavid du Colombier 				return;
4373e12c5d1SDavid du Colombier 		}else{
438d3c05884SDavid du Colombier 			if(!raw && n==0){
4393e12c5d1SDavid du Colombier 				buf[0] = 0x4;
4403e12c5d1SDavid du Colombier 				n = 1;
4413e12c5d1SDavid du Colombier 			}
4427dd7cddfSDavid du Colombier 			if(nltocr){
4437dd7cddfSDavid du Colombier 				ep = buf+n;
4447dd7cddfSDavid du Colombier 				for(p = buf; p < ep; p++)
4457dd7cddfSDavid du Colombier 					switch(*p){
4467dd7cddfSDavid du Colombier 					case '\r':
4477dd7cddfSDavid du Colombier 						*p = '\n';
4487dd7cddfSDavid du Colombier 						break;
4497dd7cddfSDavid du Colombier 					case '\n':
4507dd7cddfSDavid du Colombier 						*p = '\r';
4517dd7cddfSDavid du Colombier 						break;
4527dd7cddfSDavid du Colombier 					}
4537dd7cddfSDavid du Colombier 			}
4543e12c5d1SDavid du Colombier 			if(iwrite(net, buf, n) != n)
4553e12c5d1SDavid du Colombier 				return;
4563e12c5d1SDavid du Colombier 		}
4573e12c5d1SDavid du Colombier 	}
4583e12c5d1SDavid du Colombier }
4593e12c5d1SDavid du Colombier 
4603e12c5d1SDavid du Colombier /*
4613e12c5d1SDavid du Colombier  *  Read from the network and write to the screen.
4623e12c5d1SDavid du Colombier  *  Filter out spurious carriage returns.
4633e12c5d1SDavid du Colombier  */
4643e12c5d1SDavid du Colombier void
4653e12c5d1SDavid du Colombier fromnet(int net)
4663e12c5d1SDavid du Colombier {
4673e12c5d1SDavid du Colombier 	long n;
4683e12c5d1SDavid du Colombier 	char buf[MAXMSG];
4693e12c5d1SDavid du Colombier 	char *cp, *ep;
4703e12c5d1SDavid du Colombier 
4713e12c5d1SDavid du Colombier 	for(;;){
4723e12c5d1SDavid du Colombier 		n = iread(net, buf, sizeof(buf));
4733e12c5d1SDavid du Colombier 		if(n < 0)
4743e12c5d1SDavid du Colombier 			return;
4753e12c5d1SDavid du Colombier 		if(n == 0)
4763e12c5d1SDavid du Colombier 			continue;
4773e12c5d1SDavid du Colombier 
478219b2ee8SDavid du Colombier 		if (strip)
479219b2ee8SDavid du Colombier 			for (cp=buf; cp<buf+n; cp++)
480219b2ee8SDavid du Colombier 				*cp &= 0177;
481219b2ee8SDavid du Colombier 
4825d459b5aSDavid du Colombier 		if(crtonl) {
4835d459b5aSDavid du Colombier 			/* convert cr's to nl's */
4845d459b5aSDavid du Colombier 			for (cp = buf; cp < buf + n; cp++)
4855d459b5aSDavid du Colombier 				if (*cp == '\r')
4865d459b5aSDavid du Colombier 					*cp = '\n';
4875d459b5aSDavid du Colombier 		}
4885d459b5aSDavid du Colombier 		else if(!returns){
4893e12c5d1SDavid du Colombier 			/* convert cr's to null's */
4903e12c5d1SDavid du Colombier 			cp = buf;
4913e12c5d1SDavid du Colombier 			ep = buf + n;
4923e12c5d1SDavid du Colombier 			while(cp < ep && (cp = memchr(cp, '\r', ep-cp))){
4933e12c5d1SDavid du Colombier 				memmove(cp, cp+1, ep-cp-1);
4943e12c5d1SDavid du Colombier 				ep--;
4953e12c5d1SDavid du Colombier 				n--;
4963e12c5d1SDavid du Colombier 			}
4973e12c5d1SDavid du Colombier 		}
4983e12c5d1SDavid du Colombier 
4993e12c5d1SDavid du Colombier 		if(n > 0 && iwrite(outfd, buf, n) != n){
5003e12c5d1SDavid du Colombier 			if(outfd == 1)
5013e12c5d1SDavid du Colombier 				return;
5023e12c5d1SDavid du Colombier 			outfd = 1;
5033e12c5d1SDavid du Colombier 			if(iwrite(1, buf, n) != n)
5043e12c5d1SDavid du Colombier 				return;
5053e12c5d1SDavid du Colombier 		}
5063e12c5d1SDavid du Colombier 	}
5073e12c5d1SDavid du Colombier }
5083e12c5d1SDavid du Colombier 
5093e12c5d1SDavid du Colombier /*
5103e12c5d1SDavid du Colombier  *  dial and return a data connection
5113e12c5d1SDavid du Colombier  */
5123e12c5d1SDavid du Colombier int
5133e12c5d1SDavid du Colombier dodial(char *dest, char *net, char *service)
5143e12c5d1SDavid du Colombier {
5159a747e4fSDavid du Colombier 	char name[128];
5169a747e4fSDavid du Colombier 	char devdir[128];
5173e12c5d1SDavid du Colombier 	int data;
5183e12c5d1SDavid du Colombier 
5193e12c5d1SDavid du Colombier 	devdir[0] = 0;
5203e12c5d1SDavid du Colombier 	strcpy(name, netmkaddr(dest, net, service));
521bd389b36SDavid du Colombier 	data = dial(name, 0, devdir, &ctl);
5223e12c5d1SDavid du Colombier 	if(data < 0){
523219b2ee8SDavid du Colombier 		seterr(name);
5243e12c5d1SDavid du Colombier 		return -1;
5253e12c5d1SDavid du Colombier 	}
5263e12c5d1SDavid du Colombier 	fprint(2, "connected to %s on %s\n", name, devdir);
5273e12c5d1SDavid du Colombier 	return data;
5283e12c5d1SDavid du Colombier }
5293e12c5d1SDavid du Colombier 
5303e12c5d1SDavid du Colombier void
5313e12c5d1SDavid du Colombier dosystem(int fd, char *cmd)
5323e12c5d1SDavid du Colombier {
5333e12c5d1SDavid du Colombier 	char *p;
5343e12c5d1SDavid du Colombier 
5353e12c5d1SDavid du Colombier 	p = system(fd, cmd);
536fbdb243dSDavid du Colombier 	if(p){
5377dd7cddfSDavid du Colombier 		print("con: %s terminated with %s\n", cmd, p);
5383e12c5d1SDavid du Colombier 		exits(p);
5393e12c5d1SDavid du Colombier 	}
5403e12c5d1SDavid du Colombier }
5413e12c5d1SDavid du Colombier 
5423e12c5d1SDavid du Colombier /*
5433e12c5d1SDavid du Colombier  *  run a command with the network connection as standard IO
5443e12c5d1SDavid du Colombier  */
5453e12c5d1SDavid du Colombier char *
5463e12c5d1SDavid du Colombier system(int fd, char *cmd)
5473e12c5d1SDavid du Colombier {
5483e12c5d1SDavid du Colombier 	int pid;
5493e12c5d1SDavid du Colombier 	int p;
5503e12c5d1SDavid du Colombier 	static Waitmsg msg;
5513e12c5d1SDavid du Colombier 	int pfd[2];
5523e12c5d1SDavid du Colombier 	int n;
5533e12c5d1SDavid du Colombier 	char buf[4096];
5543e12c5d1SDavid du Colombier 
5553e12c5d1SDavid du Colombier 	if(pipe(pfd) < 0){
5563e12c5d1SDavid du Colombier 		perror("pipe");
5573e12c5d1SDavid du Colombier 		return "pipe failed";
5583e12c5d1SDavid du Colombier 	}
5593e12c5d1SDavid du Colombier 	outfd = pfd[1];
5603e12c5d1SDavid du Colombier 
561219b2ee8SDavid du Colombier 	close(consctl);
562219b2ee8SDavid du Colombier 	consctl = -1;
5633e12c5d1SDavid du Colombier 	switch(pid = fork()){
5643e12c5d1SDavid du Colombier 	case -1:
5653e12c5d1SDavid du Colombier 		perror("con");
5663e12c5d1SDavid du Colombier 		return "fork failed";
5673e12c5d1SDavid du Colombier 	case 0:
5683e12c5d1SDavid du Colombier 		close(pfd[1]);
5693e12c5d1SDavid du Colombier 		dup(pfd[0], 0);
5703ff48bf5SDavid du Colombier 		dup(fd, 1);
5713e12c5d1SDavid du Colombier 		close(ctl);
5723e12c5d1SDavid du Colombier 		close(fd);
5733e12c5d1SDavid du Colombier 		close(pfd[0]);
5743e12c5d1SDavid du Colombier 		if(*cmd)
575f19e7b74SDavid du Colombier 			execl("/bin/rc", "rc", "-c", cmd, nil);
5763e12c5d1SDavid du Colombier 		else
577f19e7b74SDavid du Colombier 			execl("/bin/rc", "rc", nil);
5783e12c5d1SDavid du Colombier 		perror("con");
5793e12c5d1SDavid du Colombier 		exits("exec");
5803e12c5d1SDavid du Colombier 		break;
5813e12c5d1SDavid du Colombier 	default:
5823e12c5d1SDavid du Colombier 		close(pfd[0]);
5833e12c5d1SDavid du Colombier 		while((n = read(pfd[1], buf, sizeof(buf))) > 0){
5843e12c5d1SDavid du Colombier 			if(msgfd >= 0){
5853e12c5d1SDavid du Colombier 				if(msgwrite(fd, buf, n) != n)
5863e12c5d1SDavid du Colombier 					break;
5873e12c5d1SDavid du Colombier 			} else {
5883e12c5d1SDavid du Colombier 				if(write(fd, buf, n) != n)
5893e12c5d1SDavid du Colombier 					break;
5903e12c5d1SDavid du Colombier 			}
5913e12c5d1SDavid du Colombier 		}
5929a747e4fSDavid du Colombier 		p = waitpid();
5933e12c5d1SDavid du Colombier 		outfd = 1;
5943e12c5d1SDavid du Colombier 		close(pfd[1]);
595219b2ee8SDavid du Colombier 		if(p < 0 || p != pid)
596219b2ee8SDavid du Colombier 			return "lost child";
5973e12c5d1SDavid du Colombier 		break;
5983e12c5d1SDavid du Colombier 	}
599219b2ee8SDavid du Colombier 	return msg.msg;
6003e12c5d1SDavid du Colombier }
6013e12c5d1SDavid du Colombier 
6023e12c5d1SDavid du Colombier int
6033e12c5d1SDavid du Colombier wasintr(void)
6043e12c5d1SDavid du Colombier {
6053e12c5d1SDavid du Colombier 	return strcmp(syserr(), "interrupted") == 0;
6063e12c5d1SDavid du Colombier }
6073e12c5d1SDavid du Colombier 
6083e12c5d1SDavid du Colombier void
6093e12c5d1SDavid du Colombier punt(char *msg)
6103e12c5d1SDavid du Colombier {
6113e12c5d1SDavid du Colombier 	if(*msg == 0)
6123e12c5d1SDavid du Colombier 		msg = transerr;
6133e12c5d1SDavid du Colombier 	fprint(2, "con: %s\n", msg);
6143e12c5d1SDavid du Colombier 	exits(msg);
6153e12c5d1SDavid du Colombier }
6163e12c5d1SDavid du Colombier 
6173e12c5d1SDavid du Colombier char*
6183e12c5d1SDavid du Colombier syserr(void)
6193e12c5d1SDavid du Colombier {
6209a747e4fSDavid du Colombier 	static char err[ERRMAX];
6219a747e4fSDavid du Colombier 	errstr(err, sizeof err);
6223e12c5d1SDavid du Colombier 	return err;
6233e12c5d1SDavid du Colombier }
6243e12c5d1SDavid du Colombier 
6253e12c5d1SDavid du Colombier void
626219b2ee8SDavid du Colombier seterr(char *addr)
6273e12c5d1SDavid du Colombier {
6283e12c5d1SDavid du Colombier 	char *se = syserr();
6293e12c5d1SDavid du Colombier 
6303e12c5d1SDavid du Colombier 	if(verbose)
631219b2ee8SDavid du Colombier 		fprint(2, "'%s' calling %s\n", se, addr);
6323e12c5d1SDavid du Colombier 	if(firsterr[0] && (strstr(se, "translate") ||
6333e12c5d1SDavid du Colombier 	 strstr(se, "file does not exist") ||
6343e12c5d1SDavid du Colombier 	 strstr(se, "unknown address") ||
6353e12c5d1SDavid du Colombier 	 strstr(se, "directory entry not found")))
6363e12c5d1SDavid du Colombier 		return;
6373e12c5d1SDavid du Colombier 	strcpy(firsterr, se);
6383e12c5d1SDavid du Colombier }
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier 
6413e12c5d1SDavid du Colombier long
6423e12c5d1SDavid du Colombier iread(int f, void *a, int n)
6433e12c5d1SDavid du Colombier {
6443e12c5d1SDavid du Colombier 	long m;
6453e12c5d1SDavid du Colombier 
6463e12c5d1SDavid du Colombier 	for(;;){
6473e12c5d1SDavid du Colombier 		m = read(f, a, n);
6483e12c5d1SDavid du Colombier 		if(m >= 0 || !wasintr())
6493e12c5d1SDavid du Colombier 			break;
6503e12c5d1SDavid du Colombier 	}
6513e12c5d1SDavid du Colombier 	return m;
6523e12c5d1SDavid du Colombier }
6533e12c5d1SDavid du Colombier 
6543e12c5d1SDavid du Colombier long
6553e12c5d1SDavid du Colombier iwrite(int f, void *a, int n)
6563e12c5d1SDavid du Colombier {
6573e12c5d1SDavid du Colombier 	long m;
6583e12c5d1SDavid du Colombier 
6593e12c5d1SDavid du Colombier 	m = write(f, a, n);
6603e12c5d1SDavid du Colombier 	if(m < 0 && wasintr())
6613e12c5d1SDavid du Colombier 		return n;
6623e12c5d1SDavid du Colombier 	return m;
6633e12c5d1SDavid du Colombier }
6643e12c5d1SDavid du Colombier 
6653e12c5d1SDavid du Colombier /*
6663e12c5d1SDavid du Colombier  *  The rest is to support the V10 mesgld protocol.
6673e12c5d1SDavid du Colombier  */
6683e12c5d1SDavid du Colombier 
6693e12c5d1SDavid du Colombier /*
6703e12c5d1SDavid du Colombier  *  network orderings
6713e12c5d1SDavid du Colombier  */
6723e12c5d1SDavid du Colombier #define get2byte(p) ((p)[0] + ((p)[1]<<8))
6733e12c5d1SDavid du Colombier #define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24))
6743e12c5d1SDavid du Colombier #define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8)
6753e12c5d1SDavid du Colombier #define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24)
6763e12c5d1SDavid du Colombier 
6773e12c5d1SDavid du Colombier /*
6783e12c5d1SDavid du Colombier  *  tty parameters
6793e12c5d1SDavid du Colombier  */
6803e12c5d1SDavid du Colombier int sgflags = ECHO;
6813e12c5d1SDavid du Colombier 
6823e12c5d1SDavid du Colombier /*
6833e12c5d1SDavid du Colombier  *  a mesgld message
6843e12c5d1SDavid du Colombier  */
6853e12c5d1SDavid du Colombier struct Msg {
6863e12c5d1SDavid du Colombier 	struct mesg h;
6873e12c5d1SDavid du Colombier 	char b[MAXMSG];
6883e12c5d1SDavid du Colombier };
6893e12c5d1SDavid du Colombier 
6903e12c5d1SDavid du Colombier 
6913e12c5d1SDavid du Colombier /*
6923e12c5d1SDavid du Colombier  *  send an empty mesgld message
6933e12c5d1SDavid du Colombier  */
6943e12c5d1SDavid du Colombier int
6953e12c5d1SDavid du Colombier sendctl(int net, int type)
6963e12c5d1SDavid du Colombier {
6973e12c5d1SDavid du Colombier 	Msg m;
6983e12c5d1SDavid du Colombier 
6993e12c5d1SDavid du Colombier 	m.h.type = type;
7003e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
7013e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
7023e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg))
7033e12c5d1SDavid du Colombier 		return -1;
7043e12c5d1SDavid du Colombier 	return 0;
7053e12c5d1SDavid du Colombier }
7063e12c5d1SDavid du Colombier 
7073e12c5d1SDavid du Colombier /*
7083e12c5d1SDavid du Colombier  *  send a one byte mesgld message
7093e12c5d1SDavid du Colombier  */
7103e12c5d1SDavid du Colombier int
7113e12c5d1SDavid du Colombier sendctl1(int net, int type, int parm)
7123e12c5d1SDavid du Colombier {
7133e12c5d1SDavid du Colombier 	Msg m;
7143e12c5d1SDavid du Colombier 
7153e12c5d1SDavid du Colombier 	m.h.type = type;
7163e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
7173e12c5d1SDavid du Colombier 	m.b[0] = parm;
7183e12c5d1SDavid du Colombier 	put2byte(m.h.size, 1);
7193e12c5d1SDavid du Colombier 	if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1)
7203e12c5d1SDavid du Colombier 		return -1;
7213e12c5d1SDavid du Colombier 	return 0;
7223e12c5d1SDavid du Colombier }
7233e12c5d1SDavid du Colombier 
7243e12c5d1SDavid du Colombier /*
7253e12c5d1SDavid du Colombier  *  read n bytes.  return -1 if it fails, 0 otherwise.
7263e12c5d1SDavid du Colombier  */
7273e12c5d1SDavid du Colombier int
7283e12c5d1SDavid du Colombier readupto(int from, char *a, int len)
7293e12c5d1SDavid du Colombier {
7303e12c5d1SDavid du Colombier 	int n;
7313e12c5d1SDavid du Colombier 
7323e12c5d1SDavid du Colombier 	while(len > 0){
7333e12c5d1SDavid du Colombier 		n = iread(from, a, len);
7343e12c5d1SDavid du Colombier 		if(n < 0)
7353e12c5d1SDavid du Colombier 			return -1;
7363e12c5d1SDavid du Colombier 		a += n;
7373e12c5d1SDavid du Colombier 		len -= n;
7383e12c5d1SDavid du Colombier 	}
7393e12c5d1SDavid du Colombier 	return 0;
7403e12c5d1SDavid du Colombier }
7413e12c5d1SDavid du Colombier 
7423e12c5d1SDavid du Colombier /*
7433e12c5d1SDavid du Colombier  *  Decode a mesgld message from the network
7443e12c5d1SDavid du Colombier  */
7453e12c5d1SDavid du Colombier void
7463e12c5d1SDavid du Colombier msgfromnet(int net)
7473e12c5d1SDavid du Colombier {
7483e12c5d1SDavid du Colombier 	ulong com;
7493e12c5d1SDavid du Colombier 	struct stioctl *io;
7503e12c5d1SDavid du Colombier 	struct sgttyb *sg;
7513e12c5d1SDavid du Colombier 	struct ttydevb *td;
7523e12c5d1SDavid du Colombier 	struct tchars *tc;
7533e12c5d1SDavid du Colombier 	int len;
7543e12c5d1SDavid du Colombier 	Msg m;
7553e12c5d1SDavid du Colombier 
7563e12c5d1SDavid du Colombier 	for(;;){
7573e12c5d1SDavid du Colombier 		/* get a complete mesgld message */
7583e12c5d1SDavid du Colombier 		if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0)
7593e12c5d1SDavid du Colombier 			break;
7603e12c5d1SDavid du Colombier 		if(m.h.magic != MSGMAGIC){
7613e12c5d1SDavid du Colombier 			fprint(2, "con: bad message magic 0x%ux\n", m.h.magic);
7623e12c5d1SDavid du Colombier 			break;
7633e12c5d1SDavid du Colombier 		}
7643e12c5d1SDavid du Colombier 		len = get2byte(m.h.size);
765219b2ee8SDavid du Colombier 		if(len > sizeof(m.b)){
766219b2ee8SDavid du Colombier 			len = sizeof(m.b);
767219b2ee8SDavid du Colombier 			fprint(2, "con: mesgld message too long\n");
768219b2ee8SDavid du Colombier 		}
7693e12c5d1SDavid du Colombier 		if(len && readupto(net, m.b, len) < 0)
7703e12c5d1SDavid du Colombier 			break;
7713e12c5d1SDavid du Colombier 
7723e12c5d1SDavid du Colombier 		/* decode */
7733e12c5d1SDavid du Colombier 		switch(m.h.type){
7743e12c5d1SDavid du Colombier 		case M_HANGUP:
7753e12c5d1SDavid du Colombier 			if(debug)
7763e12c5d1SDavid du Colombier 				fprint(2, "M_HANGUP\n");
7773e12c5d1SDavid du Colombier 			return;
7783e12c5d1SDavid du Colombier 		case M_DATA:
7793e12c5d1SDavid du Colombier 			if(debug)
7803e12c5d1SDavid du Colombier 				fprint(2, "M_DATA %d bytes\n", len);
7813e12c5d1SDavid du Colombier 			if(iwrite(outfd, m.b, len) != len){
7823e12c5d1SDavid du Colombier 				if(outfd == 1)
7833e12c5d1SDavid du Colombier 					return;
7843e12c5d1SDavid du Colombier 				outfd = 1;
7853e12c5d1SDavid du Colombier 				if(iwrite(outfd, m.b, len) != len)
7863e12c5d1SDavid du Colombier 					return;
7873e12c5d1SDavid du Colombier 			}
7883e12c5d1SDavid du Colombier 			continue;
7893e12c5d1SDavid du Colombier 		case M_IOCTL:
7903e12c5d1SDavid du Colombier 			break;
7913e12c5d1SDavid du Colombier 		default:
7923e12c5d1SDavid du Colombier 			/* ignore */
7933e12c5d1SDavid du Colombier 			if(debug)
794219b2ee8SDavid du Colombier 				fprint(2, "con: unknown message\n");
7953e12c5d1SDavid du Colombier 			continue;
7963e12c5d1SDavid du Colombier 		}
7973e12c5d1SDavid du Colombier 
7983e12c5d1SDavid du Colombier 		/*
7993e12c5d1SDavid du Colombier 		 *  answer an ioctl
8003e12c5d1SDavid du Colombier 		 */
8013e12c5d1SDavid du Colombier 		io = (struct stioctl *)m.b;
8023e12c5d1SDavid du Colombier 		com = get4byte(io->com);
8033e12c5d1SDavid du Colombier 		if(debug)
8047dd7cddfSDavid du Colombier 			fprint(2, "M_IOCTL %lud\n", com);
8053e12c5d1SDavid du Colombier 		switch(com){
8063e12c5d1SDavid du Colombier 		case FIOLOOKLD:
8073e12c5d1SDavid du Colombier 			put4byte(io->data, tty_ld);
8083e12c5d1SDavid du Colombier 			len = 0;
8093e12c5d1SDavid du Colombier 			break;
8103e12c5d1SDavid du Colombier 		case TIOCGETP:
8113e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
8123e12c5d1SDavid du Colombier 			sg->sg_ispeed = sg->sg_ospeed = B9600;
8133e12c5d1SDavid du Colombier 			sg->sg_erase = 0010;	/* back space */
8143e12c5d1SDavid du Colombier 			sg->sg_kill = 0025;	/* CNTL U */
8153e12c5d1SDavid du Colombier 			put2byte(sg->sg_flags, sgflags);
8163e12c5d1SDavid du Colombier 			len = sizeof(struct sgttyb);
8173e12c5d1SDavid du Colombier 			break;
8183e12c5d1SDavid du Colombier 		case TIOCSETN:
8193e12c5d1SDavid du Colombier 		case TIOCSETP:
8203e12c5d1SDavid du Colombier 			sg = (struct sgttyb *)io->data;
8213e12c5d1SDavid du Colombier 			sgflags = get2byte(sg->sg_flags);
8223e12c5d1SDavid du Colombier 			if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO))
8233e12c5d1SDavid du Colombier 				rawon();
8243e12c5d1SDavid du Colombier 			else
8253e12c5d1SDavid du Colombier 				rawoff();
8263e12c5d1SDavid du Colombier 			len = 0;
8273e12c5d1SDavid du Colombier 			break;
8283e12c5d1SDavid du Colombier 		case TIOCGETC:
8293e12c5d1SDavid du Colombier 			tc = (struct tchars *)io->data;
8303e12c5d1SDavid du Colombier 			tc->t_intrc = 0177;
8313e12c5d1SDavid du Colombier 			tc->t_quitc = 0034;
8323e12c5d1SDavid du Colombier 			tc->t_startc = 0;
8333e12c5d1SDavid du Colombier 			tc->t_stopc = 0;
8343e12c5d1SDavid du Colombier 			tc->t_eofc = 0004;
8353e12c5d1SDavid du Colombier 			tc->t_brkc = 0;
8363e12c5d1SDavid du Colombier 			len = sizeof(struct tchars);
8373e12c5d1SDavid du Colombier 			break;
8383e12c5d1SDavid du Colombier 		case TIOCSETC:
8393e12c5d1SDavid du Colombier 			len = 0;
8403e12c5d1SDavid du Colombier 			break;
8413e12c5d1SDavid du Colombier 		case TIOCGDEV:
8423e12c5d1SDavid du Colombier 			td = (struct ttydevb *)io->data;
8433e12c5d1SDavid du Colombier 			td->ispeed = td->ospeed = B9600;
8443e12c5d1SDavid du Colombier 			put2byte(td->flags, 0);
8453e12c5d1SDavid du Colombier 			len = sizeof(struct ttydevb);
8463e12c5d1SDavid du Colombier 			break;
8473e12c5d1SDavid du Colombier 		case TIOCSDEV:
8483e12c5d1SDavid du Colombier 			len = 0;
8493e12c5d1SDavid du Colombier 			break;
8503e12c5d1SDavid du Colombier 		default:
8513e12c5d1SDavid du Colombier 			/*
8523e12c5d1SDavid du Colombier 			 *  unimplemented
8533e12c5d1SDavid du Colombier 			 */
8543e12c5d1SDavid du Colombier 			m.b[len] = 0;
8553e12c5d1SDavid du Colombier 			if(sendctl(net, M_IOCNAK) < 0)
8563e12c5d1SDavid du Colombier 				return;
8573e12c5d1SDavid du Colombier 			continue;
8583e12c5d1SDavid du Colombier 		}
8593e12c5d1SDavid du Colombier 
8603e12c5d1SDavid du Colombier 		/*
8613e12c5d1SDavid du Colombier 		 *  acknowledge
8623e12c5d1SDavid du Colombier 		 */
8633e12c5d1SDavid du Colombier 		m.h.type = M_IOCACK;
8643e12c5d1SDavid du Colombier 		m.h.magic = MSGMAGIC;
8653e12c5d1SDavid du Colombier 		len += 4;
8663e12c5d1SDavid du Colombier 		put2byte(m.h.size, len);
8673e12c5d1SDavid du Colombier 		len += sizeof(struct mesg);
8683e12c5d1SDavid du Colombier 		if(iwrite(net, &m, len) != len)
8693e12c5d1SDavid du Colombier 			return;
8703e12c5d1SDavid du Colombier 	}
8713e12c5d1SDavid du Colombier }
8723e12c5d1SDavid du Colombier 
8733e12c5d1SDavid du Colombier /*
8743e12c5d1SDavid du Colombier  *  Read the keyboard, convert to mesgld messages, and write it to the network.
8753e12c5d1SDavid du Colombier  *  '^\' gets us into the menu.
8763e12c5d1SDavid du Colombier  */
8773e12c5d1SDavid du Colombier void
8783e12c5d1SDavid du Colombier msgfromkbd(int net)
8793e12c5d1SDavid du Colombier {
8803e12c5d1SDavid du Colombier 	long n;
8813e12c5d1SDavid du Colombier 	char buf[MAXMSG];
8823e12c5d1SDavid du Colombier 
8833e12c5d1SDavid du Colombier 	for(;;){
8843e12c5d1SDavid du Colombier 		n = iread(0, buf, sizeof(buf));
8853e12c5d1SDavid du Colombier 		if(n < 0)
8863e12c5d1SDavid du Colombier 			return;
8873e12c5d1SDavid du Colombier 		if(n && memchr(buf, 0034, n)){
8883e12c5d1SDavid du Colombier 			if(menu(net) < 0)
8893e12c5d1SDavid du Colombier 				return;
8903e12c5d1SDavid du Colombier 		} else {
8913e12c5d1SDavid du Colombier 			if(msgwrite(net, buf, n) != n)
8923e12c5d1SDavid du Colombier 				return;
8933e12c5d1SDavid du Colombier 		}
8943e12c5d1SDavid du Colombier 	}
8953e12c5d1SDavid du Colombier }
8963e12c5d1SDavid du Colombier 
8973e12c5d1SDavid du Colombier int
8983e12c5d1SDavid du Colombier msgwrite(int fd, void *buf, int len)
8993e12c5d1SDavid du Colombier {
9003e12c5d1SDavid du Colombier 	Msg m;
9013e12c5d1SDavid du Colombier 	int n;
9023e12c5d1SDavid du Colombier 
9033e12c5d1SDavid du Colombier 	n = len;
9043e12c5d1SDavid du Colombier 	memmove(m.b, buf, n);
9053e12c5d1SDavid du Colombier 	put2byte(m.h.size, n);
9063e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
9073e12c5d1SDavid du Colombier 	m.h.type = M_DATA;
9083e12c5d1SDavid du Colombier 	n += sizeof(struct mesg);
9093e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
9103e12c5d1SDavid du Colombier 		return -1;
9113e12c5d1SDavid du Colombier 
9123e12c5d1SDavid du Colombier 	put2byte(m.h.size, 0);
9133e12c5d1SDavid du Colombier 	m.h.magic = MSGMAGIC;
9143e12c5d1SDavid du Colombier 	m.h.type = M_DELIM;
9153e12c5d1SDavid du Colombier 	n = sizeof(struct mesg);
9163e12c5d1SDavid du Colombier 	if(iwrite(fd, &m, n) != n)
9173e12c5d1SDavid du Colombier 		return -1;
9183e12c5d1SDavid du Colombier 
9193e12c5d1SDavid du Colombier 	return len;
9203e12c5d1SDavid du Colombier }
9213e12c5d1SDavid du Colombier 
922