1161754Sru/*	$OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $	*/
288276Smarkm/*	$NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $	*/
388276Smarkm
47527Sjkh/*
57527Sjkh * Copyright (c) 1983, 1993
67527Sjkh *	The Regents of the University of California.  All rights reserved.
77527Sjkh *
87527Sjkh * Redistribution and use in source and binary forms, with or without
97527Sjkh * modification, are permitted provided that the following conditions
107527Sjkh * are met:
117527Sjkh * 1. Redistributions of source code must retain the above copyright
127527Sjkh *    notice, this list of conditions and the following disclaimer.
137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright
147527Sjkh *    notice, this list of conditions and the following disclaimer in the
157527Sjkh *    documentation and/or other materials provided with the distribution.
16161754Sru * 3. Neither the name of the University nor the names of its contributors
177527Sjkh *    may be used to endorse or promote products derived from this software
187527Sjkh *    without specific prior written permission.
197527Sjkh *
207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237527Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307527Sjkh * SUCH DAMAGE.
317527Sjkh */
327527Sjkh
3388276Smarkm#include <sys/cdefs.h>
3488276Smarkm__FBSDID("$FreeBSD: stable/10/usr.bin/tip/tip/tip.c 357518 2020-02-04 19:24:10Z dim $");
3588276Smarkm
367527Sjkh#ifndef lint
37161754Srustatic const char copyright[] =
387527Sjkh"@(#) Copyright (c) 1983, 1993\n\
397527Sjkh	The Regents of the University of California.  All rights reserved.\n";
407527Sjkh#endif /* not lint */
417527Sjkh
427527Sjkh#ifndef lint
4328365Scharnier#if 0
447527Sjkhstatic char sccsid[] = "@(#)tip.c	8.1 (Berkeley) 6/6/93";
45161754Srustatic const char rcsid[] = "$OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $";
4628365Scharnier#endif
477527Sjkh#endif /* not lint */
487527Sjkh
497527Sjkh/*
507527Sjkh * tip - UNIX link to other systems
517527Sjkh *  tip [-v] [-speed] system-name
527527Sjkh * or
537527Sjkh *  cu phone-number [-s speed] [-l line] [-a acu]
547527Sjkh */
557527Sjkh#include "tip.h"
567527Sjkh#include "pathnames.h"
577527Sjkh
5888276Smarkmint	disc = TTYDISC;		/* tip normally runs this way */
597527Sjkhchar	PNbuf[256];			/* This limits the size of a number */
607527Sjkh
61161754Srustatic void	intprompt(int);
62161754Srustatic void	tipin(void);
63161754Srustatic int	escape(void);
64161754Sru
6551287Speterint
66161754Srumain(int argc, char *argv[])
677527Sjkh{
68161754Sru	char *sys = NOSTR, sbuf[12], *p;
6988276Smarkm	int i;
707527Sjkh
71161754Sru	/* XXX preserve previous braindamaged behavior */
72161754Sru	setboolean(value(DC), TRUE);
73161754Sru
747527Sjkh	gid = getgid();
757527Sjkh	egid = getegid();
767527Sjkh	uid = getuid();
777527Sjkh	euid = geteuid();
7888276Smarkm	if (equal(__progname, "cu")) {
797527Sjkh		cumode = 1;
807527Sjkh		cumain(argc, argv);
817527Sjkh		goto cucommon;
827527Sjkh	}
837527Sjkh
8488276Smarkm	if (argc > 4) {
8588276Smarkm		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
8688276Smarkm		exit(1);
8788276Smarkm	}
8888276Smarkm	if (!isatty(0)) {
8988276Smarkm		fprintf(stderr, "%s: must be interactive\n", __progname);
9088276Smarkm		exit(1);
9188276Smarkm	}
927527Sjkh
937527Sjkh	for (; argc > 1; argv++, argc--) {
947527Sjkh		if (argv[1][0] != '-')
95161754Sru			sys = argv[1];
967527Sjkh		else switch (argv[1][1]) {
977527Sjkh
987527Sjkh		case 'v':
997527Sjkh			vflag++;
1007527Sjkh			break;
1017527Sjkh
10288276Smarkm		case 'n':
10388276Smarkm			noesc++;
10488276Smarkm			break;
10588276Smarkm
1067527Sjkh		case '0': case '1': case '2': case '3': case '4':
1077527Sjkh		case '5': case '6': case '7': case '8': case '9':
1087527Sjkh			BR = atoi(&argv[1][1]);
1097527Sjkh			break;
1107527Sjkh
1117527Sjkh		default:
11288276Smarkm			fprintf(stderr, "%s: %s, unknown option\n", __progname,
11388276Smarkm			    argv[1]);
1147527Sjkh			break;
1157527Sjkh		}
1167527Sjkh	}
1177527Sjkh
118161754Sru	if (sys == NOSTR)
1197527Sjkh		goto notnumber;
120161754Sru	if (isalpha(*sys))
1217527Sjkh		goto notnumber;
1227527Sjkh	/*
1237527Sjkh	 * System name is really a phone number...
1247527Sjkh	 * Copy the number then stomp on the original (in case the number
1257527Sjkh	 *	is private, we don't want 'ps' or 'w' to find it).
1267527Sjkh	 */
127161754Sru	if (strlen(sys) > sizeof PNbuf - 1) {
12888276Smarkm		fprintf(stderr, "%s: phone number too long (max = %d bytes)\n",
12988276Smarkm			__progname, (int)sizeof(PNbuf) - 1);
13088276Smarkm		exit(1);
13188276Smarkm	}
132161754Sru	strlcpy(PNbuf, sys, sizeof PNbuf - 1);
133161754Sru	for (p = sys; *p; p++)
1347527Sjkh		*p = '\0';
1357527Sjkh	PN = PNbuf;
13636791Simp	(void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
137161754Sru	sys = sbuf;
1387527Sjkh
1397527Sjkhnotnumber:
1407527Sjkh	(void)signal(SIGINT, cleanup);
1417527Sjkh	(void)signal(SIGQUIT, cleanup);
1427527Sjkh	(void)signal(SIGHUP, cleanup);
1437527Sjkh	(void)signal(SIGTERM, cleanup);
144161754Sru	(void)signal(SIGCHLD, SIG_DFL);
1457527Sjkh
146161754Sru	if ((i = hunt(sys)) == 0) {
1477527Sjkh		printf("all ports busy\n");
1487527Sjkh		exit(3);
1497527Sjkh	}
1507527Sjkh	if (i == -1) {
1517527Sjkh		printf("link down\n");
1527527Sjkh		(void)uu_unlock(uucplock);
1537527Sjkh		exit(3);
1547527Sjkh	}
1557527Sjkh	setbuf(stdout, NULL);
1567527Sjkh	loginit();
1577527Sjkh
1587527Sjkh	/*
15988276Smarkm	 * Now that we have the logfile and the ACU open
16088276Smarkm	 *  return to the real uid and gid.  These things will
16188276Smarkm	 *  be closed on exit.  Swap real and effective uid's
16288276Smarkm	 *  so we can get the original permissions back
16388276Smarkm	 *  for removing the uucp lock.
16488276Smarkm	 */
16588276Smarkm	user_uid();
16688276Smarkm
16788276Smarkm	/*
1687527Sjkh	 * Kludge, their's no easy way to get the initialization
1697527Sjkh	 *   in the right order, so force it here
1707527Sjkh	 */
1717527Sjkh	if ((PH = getenv("PHONES")) == NOSTR)
1727527Sjkh		PH = _PATH_PHONES;
1737527Sjkh	vinit();				/* init variables */
17488276Smarkm	setparity("none");			/* set the parity table */
1757527Sjkh
1767527Sjkh	/*
1777527Sjkh	 * Hardwired connections require the
1787527Sjkh	 *  line speed set before they make any transmissions
1797527Sjkh	 *  (this is particularly true of things like a DF03-AC)
1807527Sjkh	 */
181161754Sru	if (HW && ttysetup(number(value(BAUDRATE)))) {
182161754Sru		fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
183161754Sru		    number(value(BAUDRATE)));
1847527Sjkh		daemon_uid();
1857527Sjkh		(void)uu_unlock(uucplock);
186161754Sru		exit(3);
187161754Sru	}
188161754Sru	if ((p = con())) {
189161754Sru		printf("\07%s\n[EOT]\n", p);
190161754Sru		daemon_uid();
191161754Sru		(void)uu_unlock(uucplock);
1927527Sjkh		exit(1);
1937527Sjkh	}
194161754Sru	if (!HW && ttysetup(number(value(BAUDRATE)))) {
195161754Sru		fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
196161754Sru		    number(value(BAUDRATE)));
197161754Sru		daemon_uid();
198161754Sru		(void)uu_unlock(uucplock);
199161754Sru		exit(3);
200161754Sru	}
20188276Smarkmcucommon:
2027527Sjkh	/*
2037527Sjkh	 * From here down the code is shared with
2047527Sjkh	 * the "cu" version of tip.
2057527Sjkh	 */
2067527Sjkh
20788276Smarkm	i = fcntl(FD, F_GETFL);
20888276Smarkm	if (i == -1) {
20988276Smarkm		perror("fcntl");
210161754Sru		cleanup(0);
21188276Smarkm	}
21288276Smarkm	i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK);
21388276Smarkm	if (i == -1) {
21488276Smarkm		perror("fcntl");
215161754Sru		cleanup(0);
21688276Smarkm	}
21788276Smarkm
21888276Smarkm	tcgetattr(0, &defterm);
219161754Sru	gotdefterm = 1;
22088276Smarkm	term = defterm;
22188276Smarkm	term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
22288276Smarkm	term.c_iflag &= ~(INPCK|ICRNL);
22388276Smarkm	term.c_oflag &= ~OPOST;
22488276Smarkm	term.c_cc[VMIN] = 1;
22588276Smarkm	term.c_cc[VTIME] = 0;
22688276Smarkm	defchars = term;
22788276Smarkm	term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
228161754Sru	    term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
229161754Sru	    term.c_cc[VLNEXT] = _POSIX_VDISABLE;
2307527Sjkh	raw();
2317527Sjkh
2327527Sjkh	pipe(fildes); pipe(repdes);
2337527Sjkh	(void)signal(SIGALRM, timeout);
2347527Sjkh
235161754Sru	if (value(LINEDISC) != TTYDISC) {
236161781Sru		int ld = (int)(intptr_t)value(LINEDISC);
237161754Sru		ioctl(FD, TIOCSETD, &ld);
238161754Sru	}
239161754Sru
2407527Sjkh	/*
2417527Sjkh	 * Everything's set up now:
2427527Sjkh	 *	connection established (hardwired or dialup)
2437527Sjkh	 *	line conditioned (baud rate, mode, etc.)
2447527Sjkh	 *	internal data structures (variables)
2457527Sjkh	 * so, fork one process for local side and one for remote.
2467527Sjkh	 */
2477527Sjkh	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
248161754Sru	tipin_pid = getpid();
249161754Sru	if ((tipout_pid = fork()))
2507527Sjkh		tipin();
2517527Sjkh	else
2527527Sjkh		tipout();
2537527Sjkh	/*NOTREACHED*/
25488276Smarkm	exit(0);
2557527Sjkh}
2567527Sjkh
2577527Sjkhvoid
258161754Srucleanup(int signo)
2597527Sjkh{
2607527Sjkh	daemon_uid();
2617527Sjkh	(void)uu_unlock(uucplock);
2627527Sjkh	if (odisc)
263161754Sru		ioctl(0, TIOCSETD, &odisc);
264161754Sru	unraw();
265161754Sru	if (signo && tipout_pid) {
266161754Sru		kill(tipout_pid, signo);
267161754Sru		wait(NULL);
268161754Sru	}
2697527Sjkh	exit(0);
2707527Sjkh}
2717527Sjkh
2727527Sjkh/*
2737527Sjkh * Muck with user ID's.  We are setuid to the owner of the lock
2747527Sjkh * directory when we start.  user_uid() reverses real and effective
2757527Sjkh * ID's after startup, to run with the user's permissions.
2767527Sjkh * daemon_uid() switches back to the privileged uid for unlocking.
2777527Sjkh * Finally, to avoid running a shell with the wrong real uid,
2787527Sjkh * shell_uid() sets real and effective uid's to the user's real ID.
2797527Sjkh */
2807527Sjkhstatic int uidswapped;
2817527Sjkh
28228365Scharniervoid
283161754Sruuser_uid(void)
2847527Sjkh{
2857527Sjkh	if (uidswapped == 0) {
2867527Sjkh		seteuid(uid);
2877527Sjkh		uidswapped = 1;
2887527Sjkh	}
2897527Sjkh}
2907527Sjkh
29128365Scharniervoid
292161754Srudaemon_uid(void)
2937527Sjkh{
29488276Smarkm
2957527Sjkh	if (uidswapped) {
2967527Sjkh		seteuid(euid);
2977527Sjkh		uidswapped = 0;
2987527Sjkh	}
2997527Sjkh}
3007527Sjkh
30128365Scharniervoid
302161754Srushell_uid(void)
3037527Sjkh{
30436791Simp	setegid(gid);
3057527Sjkh	seteuid(uid);
3067527Sjkh}
3077527Sjkh
3087527Sjkh/*
3097527Sjkh * put the controlling keyboard into raw mode
3107527Sjkh */
3117527Sjkhvoid
312161754Sruraw(void)
3137527Sjkh{
31488276Smarkm	tcsetattr(0, TCSADRAIN, &term);
3157527Sjkh}
3167527Sjkh
3177527Sjkh
3187527Sjkh/*
3197527Sjkh * return keyboard to normal mode
3207527Sjkh */
32128365Scharniervoid
322161754Sruunraw(void)
3237527Sjkh{
324161754Sru	if (gotdefterm)
325161754Sru		tcsetattr(0, TCSADRAIN, &defterm);
3267527Sjkh}
3277527Sjkh
328178736Sbms/*
329178736Sbms * give up exclusive tty access
330178736Sbms */
331178736Sbmsvoid
332178736Sbmsunexcl()
333178736Sbms{
334178736Sbms	ioctl(FD, TIOCNXCL, 0);
335178736Sbms}
336178736Sbms
3377527Sjkhstatic	jmp_buf promptbuf;
3387527Sjkh
3397527Sjkh/*
3407527Sjkh * Print string ``s'', then read a string
3417527Sjkh *  in from the terminal.  Handles signals & allows use of
3427527Sjkh *  normal erase and kill characters.
3437527Sjkh */
34428365Scharnierint
345161754Sruprompt(char *s, char *p, size_t sz)
3467527Sjkh{
34788276Smarkm	int c;
34888276Smarkm	char *b = p;
3497527Sjkh	sig_t oint, oquit;
3507527Sjkh
3517527Sjkh	stoprompt = 0;
3527527Sjkh	oint = signal(SIGINT, intprompt);
3537527Sjkh	oquit = signal(SIGQUIT, SIG_IGN);
3547527Sjkh	unraw();
3557527Sjkh	printf("%s", s);
3567527Sjkh	if (setjmp(promptbuf) == 0)
35788276Smarkm		while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
3587527Sjkh			p++;
3597527Sjkh	*p = '\0';
3607527Sjkh
3617527Sjkh	raw();
3627527Sjkh	(void)signal(SIGINT, oint);
3637527Sjkh	(void)signal(SIGQUIT, oquit);
3647527Sjkh	return (stoprompt || p == b);
3657527Sjkh}
3667527Sjkh
3677527Sjkh/*
3687527Sjkh * Interrupt service routine during prompting
3697527Sjkh */
370161754Sru/*ARGSUSED*/
371161754Srustatic void
372161754Sruintprompt(int signo)
3737527Sjkh{
3747527Sjkh	(void)signal(SIGINT, SIG_IGN);
3757527Sjkh	stoprompt = 1;
3767527Sjkh	printf("\r\n");
3777527Sjkh	longjmp(promptbuf, 1);
3787527Sjkh}
3797527Sjkh
3807527Sjkh/*
3817527Sjkh * ****TIPIN   TIPIN****
3827527Sjkh */
383161754Srustatic void
384161754Srutipin(void)
3857527Sjkh{
386161754Sru	int bol = 1;
387161754Sru	int gch;
388161754Sru	char ch;
3897527Sjkh
3907527Sjkh	/*
3917527Sjkh	 * Kinda klugey here...
3927527Sjkh	 *   check for scripting being turned on from the .tiprc file,
3937527Sjkh	 *   but be careful about just using setscript(), as we may
3947527Sjkh	 *   send a SIGEMT before tipout has a chance to set up catching
3957527Sjkh	 *   it; so wait a second, then setscript()
3967527Sjkh	 */
3977527Sjkh	if (boolean(value(SCRIPT))) {
3987527Sjkh		sleep(1);
3997527Sjkh		setscript();
4007527Sjkh	}
4017527Sjkh
4027527Sjkh	while (1) {
40388276Smarkm		gch = getchar()&STRIP_PAR;
404161754Sru		/* XXX does not check for EOF */
4057527Sjkh		if ((gch == character(value(ESCAPE))) && bol) {
40688276Smarkm			if (!noesc) {
40788276Smarkm				if (!(gch = escape()))
40888276Smarkm					continue;
40988276Smarkm			}
4107527Sjkh		} else if (!cumode && gch == character(value(RAISECHAR))) {
41188276Smarkm			setboolean(value(RAISE), !boolean(value(RAISE)));
4127527Sjkh			continue;
4137527Sjkh		} else if (gch == '\r') {
4147527Sjkh			bol = 1;
415161754Sru			ch = gch;
416161754Sru			parwrite(FD, &ch, 1);
4177527Sjkh			if (boolean(value(HALFDUPLEX)))
4187527Sjkh				printf("\r\n");
4197527Sjkh			continue;
420357518Sdim		} else if (!cumode && gch == character(value(FORCE))) {
42188276Smarkm			gch = getchar()&STRIP_PAR;
422357518Sdim		}
4237527Sjkh		bol = any(gch, value(EOL));
4247527Sjkh		if (boolean(value(RAISE)) && islower(gch))
4257527Sjkh			gch = toupper(gch);
426161754Sru		ch = gch;
427161754Sru		parwrite(FD, &ch, 1);
4287527Sjkh		if (boolean(value(HALFDUPLEX)))
429161754Sru			printf("%c", ch);
4307527Sjkh	}
4317527Sjkh}
4327527Sjkh
4337527Sjkhextern esctable_t etable[];
4347527Sjkh
4357527Sjkh/*
4367527Sjkh * Escape handler --
4377527Sjkh *  called on recognition of ``escapec'' at the beginning of a line
4387527Sjkh */
439161754Srustatic int
440161754Sruescape(void)
4417527Sjkh{
442161754Sru	int gch;
44388276Smarkm	esctable_t *p;
4447527Sjkh	char c = character(value(ESCAPE));
4457527Sjkh
44688276Smarkm	gch = (getchar()&STRIP_PAR);
447161754Sru	/* XXX does not check for EOF */
4487527Sjkh	for (p = etable; p->e_char; p++)
4497527Sjkh		if (p->e_char == gch) {
4507527Sjkh			if ((p->e_flags&PRIV) && uid)
4517527Sjkh				continue;
4527527Sjkh			printf("%s", ctrl(c));
4537527Sjkh			(*p->e_func)(gch);
4547527Sjkh			return (0);
4557527Sjkh		}
4567527Sjkh	/* ESCAPE ESCAPE forces ESCAPE */
4577527Sjkh	if (c != gch)
45888276Smarkm		parwrite(FD, &c, 1);
4597527Sjkh	return (gch);
4607527Sjkh}
4617527Sjkh
46228365Scharnierint
463161754Sruany(int cc, char *p)
4647527Sjkh{
46588276Smarkm	char c = cc;
4667527Sjkh	while (p && *p)
4677527Sjkh		if (*p++ == c)
4687527Sjkh			return (1);
4697527Sjkh	return (0);
4707527Sjkh}
4717527Sjkh
472161754Srusize_t
473161754Srusize(char *s)
4747527Sjkh{
475161754Sru	size_t i = 0;
4767527Sjkh
4777527Sjkh	while (s && *s++)
4787527Sjkh		i++;
4797527Sjkh	return (i);
4807527Sjkh}
4817527Sjkh
4827527Sjkhchar *
483161754Sruinterp(char *s)
4847527Sjkh{
4857527Sjkh	static char buf[256];
48688276Smarkm	char *p = buf, c, *q;
4877527Sjkh
48828365Scharnier	while ((c = *s++)) {
4897527Sjkh		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
4907527Sjkh			if (*q++ == c) {
4917527Sjkh				*p++ = '\\'; *p++ = *q;
4927527Sjkh				goto next;
4937527Sjkh			}
4947527Sjkh		if (c < 040) {
4957527Sjkh			*p++ = '^'; *p++ = c + 'A'-1;
4967527Sjkh		} else if (c == 0177) {
4977527Sjkh			*p++ = '^'; *p++ = '?';
4987527Sjkh		} else
4997527Sjkh			*p++ = c;
5007527Sjkh	next:
5017527Sjkh		;
5027527Sjkh	}
5037527Sjkh	*p = '\0';
5047527Sjkh	return (buf);
5057527Sjkh}
5067527Sjkh
5077527Sjkhchar *
508161754Sructrl(char c)
5097527Sjkh{
5107527Sjkh	static char s[3];
5117527Sjkh
5127527Sjkh	if (c < 040 || c == 0177) {
5137527Sjkh		s[0] = '^';
5147527Sjkh		s[1] = c == 0177 ? '?' : c+'A'-1;
5157527Sjkh		s[2] = '\0';
5167527Sjkh	} else {
5177527Sjkh		s[0] = c;
5187527Sjkh		s[1] = '\0';
5197527Sjkh	}
5207527Sjkh	return (s);
5217527Sjkh}
5227527Sjkh
5237527Sjkh/*
5247527Sjkh * Help command
5257527Sjkh */
52628365Scharniervoid
527161754Sruhelp(int c)
5287527Sjkh{
52988276Smarkm	esctable_t *p;
5307527Sjkh
5317527Sjkh	printf("%c\r\n", c);
5327527Sjkh	for (p = etable; p->e_char; p++) {
5337527Sjkh		if ((p->e_flags&PRIV) && uid)
5347527Sjkh			continue;
5357527Sjkh		printf("%2s", ctrl(character(value(ESCAPE))));
5367527Sjkh		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
5377527Sjkh			p->e_flags&EXP ? '*': ' ', p->e_help);
5387527Sjkh	}
5397527Sjkh}
5407527Sjkh
5417527Sjkh/*
5427527Sjkh * Set up the "remote" tty's state
5437527Sjkh */
544161754Sruint
545161754Sruttysetup(int speed)
5467527Sjkh{
54788276Smarkm	struct termios	cntrl;
5487527Sjkh
549161754Sru	if (tcgetattr(FD, &cntrl))
550161754Sru		return (-1);
551161754Sru	cfsetspeed(&cntrl, speed);
55288276Smarkm	cntrl.c_cflag &= ~(CSIZE|PARENB);
55388276Smarkm	cntrl.c_cflag |= CS8;
55488276Smarkm	if (boolean(value(DC)))
55588276Smarkm		cntrl.c_cflag |= CLOCAL;
556161754Sru	if (boolean(value(HARDWAREFLOW)))
557161754Sru		cntrl.c_cflag |= CRTSCTS;
55888276Smarkm	cntrl.c_iflag &= ~(ISTRIP|ICRNL);
55988276Smarkm	cntrl.c_oflag &= ~OPOST;
56088276Smarkm	cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
56188276Smarkm	cntrl.c_cc[VMIN] = 1;
56288276Smarkm	cntrl.c_cc[VTIME] = 0;
5637527Sjkh	if (boolean(value(TAND)))
56488276Smarkm		cntrl.c_iflag |= IXOFF;
565161754Sru	return (tcsetattr(FD, TCSAFLUSH, &cntrl));
5667527Sjkh}
5677527Sjkh
5687527Sjkhstatic char partab[0200];
5697527Sjkh
5707527Sjkh/*
5717527Sjkh * Do a write to the remote machine with the correct parity.
5727527Sjkh * We are doing 8 bit wide output, so we just generate a character
5737527Sjkh * with the right parity and output it.
5747527Sjkh */
57528365Scharniervoid
576161754Sruparwrite(int fd, char *buf, size_t n)
5777527Sjkh{
578161781Sru	size_t i;
57988276Smarkm	char *bp;
5807527Sjkh
5817527Sjkh	bp = buf;
5827527Sjkh	if (bits8 == 0)
5837527Sjkh		for (i = 0; i < n; i++) {
5847527Sjkh			*bp = partab[(*bp) & 0177];
5857527Sjkh			bp++;
5867527Sjkh		}
5877527Sjkh	if (write(fd, buf, n) < 0) {
588230654Sphk		if (errno == EIO || errno == ENXIO)
5897527Sjkh			tipabort("Lost carrier.");
59088276Smarkm		/* this is questionable */
59188276Smarkm		perror("write");
5927527Sjkh	}
5937527Sjkh}
5947527Sjkh
5957527Sjkh/*
5967527Sjkh * Build a parity table with appropriate high-order bit.
5977527Sjkh */
59828365Scharniervoid
599161754Srusetparity(char *defparity)
6007527Sjkh{
60188276Smarkm	int i, flip, clr, set;
6027527Sjkh	char *parity;
60388276Smarkm	extern const unsigned char evenpartab[];
6047527Sjkh
6057527Sjkh	if (value(PARITY) == NOSTR)
6067527Sjkh		value(PARITY) = defparity;
6077527Sjkh	parity = value(PARITY);
6087527Sjkh	if (equal(parity, "none")) {
6097527Sjkh		bits8 = 1;
6107527Sjkh		return;
6117527Sjkh	}
6127527Sjkh	bits8 = 0;
6137527Sjkh	flip = 0;
6147527Sjkh	clr = 0377;
6157527Sjkh	set = 0;
6167527Sjkh	if (equal(parity, "odd"))
6177527Sjkh		flip = 0200;			/* reverse bit 7 */
6187527Sjkh	else if (equal(parity, "zero"))
6197527Sjkh		clr = 0177;			/* turn off bit 7 */
6207527Sjkh	else if (equal(parity, "one"))
6217527Sjkh		set = 0200;			/* turn on bit 7 */
6227527Sjkh	else if (!equal(parity, "even")) {
6237527Sjkh		(void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
6247527Sjkh		(void) fflush(stderr);
6257527Sjkh	}
6267527Sjkh	for (i = 0; i < 0200; i++)
627161754Sru		partab[i] = ((evenpartab[i] ^ flip) | set) & clr;
6287527Sjkh}
629