171333Sitojun/*	$OpenBSD: tip.c,v 1.30 2006/08/18 03:06:18 jason Exp $	*/
2118968Sume/*	$NetBSD: tip.c,v 1.13 1997/04/20 00:03:05 mellon Exp $	*/
362656Skris
455505Sshin/*-
555505Sshin * SPDX-License-Identifier: BSD-3-Clause
6224144Shrs *
755505Sshin * Copyright (c) 1983, 1993
8222732Shrs *	The Regents of the University of California.  All rights reserved.
955505Sshin *
1055505Sshin * Redistribution and use in source and binary forms, with or without
1155505Sshin * modification, are permitted provided that the following conditions
1255505Sshin * are met:
1355505Sshin * 1. Redistributions of source code must retain the above copyright
1455505Sshin *    notice, this list of conditions and the following disclaimer.
1555505Sshin * 2. Redistributions in binary form must reproduce the above copyright
1655505Sshin *    notice, this list of conditions and the following disclaimer in the
1755505Sshin *    documentation and/or other materials provided with the distribution.
1855505Sshin * 3. Neither the name of the University nor the names of its contributors
1955505Sshin *    may be used to endorse or promote products derived from this software
20222732Shrs *    without specific prior written permission.
2155505Sshin *
2255505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2355505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2455505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2555505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2655505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2755505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2855505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2955505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3055505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3155505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3255505Sshin * SUCH DAMAGE.
3355505Sshin */
3455505Sshin
3555505Sshin/*
3655505Sshin * tip - UNIX link to other systems
3755505Sshin *  tip [-v] [-speed] system-name
3855505Sshin * or
3955505Sshin *  cu phone-number [-s speed] [-l line] [-a acu]
4055505Sshin */
4155505Sshin#define	EXTERN
4255505Sshin#include "tip.h"
4355505Sshin#include "pathnames.h"
4455505Sshin
4557120Sshinint	disc = TTYDISC;		/* tip normally runs this way */
4655505Sshinchar	PNbuf[256];			/* This limits the size of a number */
4757120Sshin
48151468Ssuzstatic void	intprompt(int);
4955505Sshinstatic void	tipin(void);
5055505Sshinstatic int	escape(void);
5155505Sshin
5255505Sshinint
5355505Sshinmain(int argc, char *argv[])
5455505Sshin{
55224144Shrs	char *sys = NOSTR, sbuf[12], *p;
56222732Shrs	int i;
5755505Sshin
58136764Ssuz	/* XXX preserve previous braindamaged behavior */
5955505Sshin	setboolean(value(DC), TRUE);
60253970Shrs
6155505Sshin	gid = getgid();
6278064Sume	egid = getegid();
6355505Sshin	uid = getuid();
6455505Sshin	euid = geteuid();
6555505Sshin	if (equal(__progname, "cu")) {
6655505Sshin		cumode = 1;
6755505Sshin		cumain(argc, argv);
6855505Sshin		goto cucommon;
6955505Sshin	}
70222732Shrs
71222732Shrs	if (argc > 4) {
72222732Shrs		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
73222732Shrs		exit(1);
74222732Shrs	}
7598172Sume	if (!isatty(0)) {
7698172Sume		fprintf(stderr, "%s: must be interactive\n", __progname);
7798172Sume		exit(1);
78173412Skevlo	}
79222732Shrs
80222732Shrs	for (; argc > 1; argv++, argc--) {
8155505Sshin		if (argv[1][0] != '-')
82222732Shrs			sys = argv[1];
83222732Shrs		else switch (argv[1][1]) {
84222732Shrs
8555505Sshin		case 'v':
86222732Shrs			vflag++;
87222732Shrs			break;
88222732Shrs
8955505Sshin		case 'n':
90222732Shrs			noesc++;
91222732Shrs			break;
92222732Shrs
93222732Shrs		case '0': case '1': case '2': case '3': case '4':
94222732Shrs		case '5': case '6': case '7': case '8': case '9':
95222732Shrs			BR = atoi(&argv[1][1]);
96222732Shrs			break;
97222732Shrs
98222732Shrs		default:
99222732Shrs			fprintf(stderr, "%s: %s, unknown option\n", __progname,
100222732Shrs			    argv[1]);
101222732Shrs			break;
102222732Shrs		}
103222732Shrs	}
104222732Shrs
105222732Shrs	if (sys == NOSTR)
106222732Shrs		goto notnumber;
107222732Shrs	if (isalpha(*sys))
108222732Shrs		goto notnumber;
109222732Shrs	/*
110222732Shrs	 * System name is really a phone number...
111222732Shrs	 * Copy the number then stomp on the original (in case the number
112222732Shrs	 *	is private, we don't want 'ps' or 'w' to find it).
113222732Shrs	 */
114222743Shrs	if (strlen(sys) > sizeof PNbuf - 1) {
115222732Shrs		fprintf(stderr, "%s: phone number too long (max = %d bytes)\n",
116222732Shrs			__progname, (int)sizeof(PNbuf) - 1);
117222732Shrs		exit(1);
118222732Shrs	}
11962656Skris	strlcpy(PNbuf, sys, sizeof PNbuf - 1);
120118784Sume	for (p = sys; *p; p++)
12155505Sshin		*p = '\0';
12255505Sshin	PN = PNbuf;
12355505Sshin	(void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
12455505Sshin	sys = sbuf;
12555505Sshin
12655505Sshinnotnumber:
12762656Skris	(void)signal(SIGINT, cleanup);
128222732Shrs	(void)signal(SIGQUIT, cleanup);
129222732Shrs	(void)signal(SIGHUP, cleanup);
13062656Skris	(void)signal(SIGTERM, cleanup);
13155505Sshin	(void)signal(SIGCHLD, SIG_DFL);
13255505Sshin
13362656Skris	if ((i = hunt(sys)) == 0) {
13455505Sshin		printf("all ports busy\n");
135224144Shrs		exit(3);
136224144Shrs	}
137224144Shrs	if (i == -1) {
138224144Shrs		printf("link down\n");
139222732Shrs		(void)uu_unlock(uucplock);
140224144Shrs		exit(3);
141224144Shrs	}
142224144Shrs	setbuf(stdout, NULL);
143224144Shrs	loginit();
144224144Shrs
145224144Shrs	/*
146224144Shrs	 * Now that we have the logfile and the ACU open
147224144Shrs	 *  return to the real uid and gid.  These things will
148222732Shrs	 *  be closed on exit.  Swap real and effective uid's
149224144Shrs	 *  so we can get the original permissions back
150222972Shrs	 *  for removing the uucp lock.
151224144Shrs	 */
152222972Shrs	user_uid();
153224144Shrs
154224144Shrs	/*
155224144Shrs	 * Kludge, their's no easy way to get the initialization
156224144Shrs	 *   in the right order, so force it here
157224144Shrs	 */
158224144Shrs	if ((PH = getenv("PHONES")) == NOSTR)
159224144Shrs		PH = _PATH_PHONES;
160224144Shrs	vinit();				/* init variables */
161224144Shrs	setparity("none");			/* set the parity table */
162224144Shrs
163224144Shrs	/*
164224144Shrs	 * Hardwired connections require the
165224144Shrs	 *  line speed set before they make any transmissions
166224144Shrs	 *  (this is particularly true of things like a DF03-AC)
167224144Shrs	 */
168224144Shrs	if (HW && ttysetup(number(value(BAUDRATE)))) {
169224144Shrs		fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
170224144Shrs		    number(value(BAUDRATE)));
171222972Shrs		daemon_uid();
172224144Shrs		(void)uu_unlock(uucplock);
173224144Shrs		exit(3);
174224144Shrs	}
175222972Shrs	if ((p = con())) {
176222972Shrs		printf("\07%s\n[EOT]\n", p);
177224144Shrs		daemon_uid();
178222972Shrs		(void)uu_unlock(uucplock);
179222972Shrs		exit(1);
180224144Shrs	}
181224144Shrs	if (!HW && ttysetup(number(value(BAUDRATE)))) {
182224144Shrs		fprintf(stderr, "%s: bad baud rate %ld\n", __progname,
183224144Shrs		    number(value(BAUDRATE)));
184222972Shrs		daemon_uid();
185224144Shrs		(void)uu_unlock(uucplock);
186224144Shrs		exit(3);
187222972Shrs	}
188224144Shrscucommon:
189224144Shrs	/*
190224144Shrs	 * From here down the code is shared with
191224144Shrs	 * the "cu" version of tip.
192224144Shrs	 */
193224144Shrs
194224144Shrs	i = fcntl(FD, F_GETFL);
195224144Shrs	if (i == -1) {
196224144Shrs		perror("fcntl");
197224144Shrs		cleanup(0);
198224144Shrs	}
199224144Shrs	i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK);
200224144Shrs	if (i == -1) {
201224144Shrs		perror("fcntl");
202224144Shrs		cleanup(0);
203224144Shrs	}
204224144Shrs
205224144Shrs	tcgetattr(0, &defterm);
206224144Shrs	gotdefterm = 1;
207224144Shrs	term = defterm;
208224144Shrs	term.c_lflag &= ~(ICANON|IEXTEN|ECHO);
209224144Shrs	term.c_iflag &= ~(INPCK|ICRNL);
210224144Shrs	term.c_oflag &= ~OPOST;
211224144Shrs	term.c_cc[VMIN] = 1;
212224144Shrs	term.c_cc[VTIME] = 0;
213224144Shrs	defchars = term;
214224144Shrs	term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] =
215224144Shrs	    term.c_cc[VDSUSP] = term.c_cc[VDISCARD] =
216224144Shrs	    term.c_cc[VLNEXT] = _POSIX_VDISABLE;
217224144Shrs	raw();
218224144Shrs
219228990Suqs	pipe(fildes); pipe(repdes);
220224144Shrs	(void)signal(SIGALRM, timeout);
221224144Shrs
222224144Shrs	if (value(LINEDISC) != TTYDISC) {
223224144Shrs		int ld = (int)(intptr_t)value(LINEDISC);
224224144Shrs		ioctl(FD, TIOCSETD, &ld);
225224144Shrs	}
226224144Shrs
227224144Shrs	/*
228224144Shrs	 * Everything's set up now:
229224144Shrs	 *	connection established (hardwired or dialup)
230224144Shrs	 *	line conditioned (baud rate, mode, etc.)
231224144Shrs	 *	internal data structures (variables)
232224144Shrs	 * so, fork one process for local side and one for remote.
233224144Shrs	 */
234224144Shrs	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
235224144Shrs	tipin_pid = getpid();
236224144Shrs	if ((tipout_pid = fork()))
237224144Shrs		tipin();
238224144Shrs	else
239224144Shrs		tipout();
240224144Shrs	exit(0);
241224144Shrs}
242224144Shrs
243224144Shrsvoid
244224144Shrscleanup(int signo)
245224144Shrs{
246224144Shrs	daemon_uid();
247224144Shrs	(void)uu_unlock(uucplock);
248224144Shrs	if (odisc)
249224144Shrs		ioctl(0, TIOCSETD, &odisc);
250224144Shrs	unraw();
251224144Shrs	if (signo && tipout_pid) {
252224144Shrs		kill(tipout_pid, signo);
253224144Shrs		wait(NULL);
254224144Shrs	}
255224144Shrs	exit(0);
256224144Shrs}
257224144Shrs
258224144Shrs/*
259224144Shrs * Muck with user ID's.  We are setuid to the owner of the lock
260224144Shrs * directory when we start.  user_uid() reverses real and effective
261224144Shrs * ID's after startup, to run with the user's permissions.
262224144Shrs * daemon_uid() switches back to the privileged uid for unlocking.
263224144Shrs * Finally, to avoid running a shell with the wrong real uid,
264224144Shrs * shell_uid() sets real and effective uid's to the user's real ID.
265224144Shrs */
266224144Shrsstatic int uidswapped;
267224144Shrs
268224144Shrsvoid
269224144Shrsuser_uid(void)
270224144Shrs{
271224144Shrs	if (uidswapped == 0) {
272224144Shrs		seteuid(uid);
273224144Shrs		uidswapped = 1;
274224144Shrs	}
275224144Shrs}
276222972Shrs
277222972Shrsvoid
278222972Shrsdaemon_uid(void)
279222972Shrs{
280224144Shrs
281222732Shrs	if (uidswapped) {
282222732Shrs		seteuid(euid);
283222732Shrs		uidswapped = 0;
284222732Shrs	}
285222732Shrs}
286222732Shrs
287222732Shrsvoid
288222732Shrsshell_uid(void)
289224144Shrs{
290222732Shrs	setegid(gid);
291222732Shrs	seteuid(uid);
292224144Shrs}
293224144Shrs
294224144Shrs/*
295222732Shrs * put the controlling keyboard into raw mode
296222732Shrs */
297222732Shrsvoid
298222732Shrsraw(void)
299254955Shrs{
300254955Shrs	tcsetattr(0, TCSADRAIN, &term);
301222732Shrs}
302222732Shrs
303222732Shrs
304222732Shrs/*
305222732Shrs * return keyboard to normal mode
306222732Shrs */
307222732Shrsvoid
308222732Shrsunraw(void)
309222732Shrs{
310222732Shrs	if (gotdefterm)
311222732Shrs		tcsetattr(0, TCSADRAIN, &defterm);
312222732Shrs}
313222732Shrs
314222732Shrs/*
315222732Shrs * give up exclusive tty access
316222732Shrs */
317222732Shrsvoid
318222732Shrsunexcl()
319222732Shrs{
320222732Shrs	ioctl(FD, TIOCNXCL, 0);
321222732Shrs}
322224144Shrs
323224144Shrsstatic	jmp_buf promptbuf;
324222732Shrs
325222732Shrs/*
326222732Shrs * Print string ``s'', then read a string
327224144Shrs *  in from the terminal.  Handles signals & allows use of
328224144Shrs *  normal erase and kill characters.
329222732Shrs */
330222732Shrsint
331224144Shrsprompt(char *s, char *p, size_t sz)
332222732Shrs{
333222732Shrs	int c;
334222972Shrs	char *b = p;
335224144Shrs	sig_t oint, oquit;
336222732Shrs
337222732Shrs	stoprompt = 0;
338222732Shrs	oint = signal(SIGINT, intprompt);
339222732Shrs	oquit = signal(SIGQUIT, SIG_IGN);
340222732Shrs	unraw();
341224144Shrs	printf("%s", s);
342224144Shrs	if (setjmp(promptbuf) == 0)
343224144Shrs		while ((c = getchar()) != EOF && (*p = c) != '\n' && --sz > 0)
344224144Shrs			p++;
345224144Shrs	*p = '\0';
346224144Shrs
347224144Shrs	raw();
348224144Shrs	(void)signal(SIGINT, oint);
349222732Shrs	(void)signal(SIGQUIT, oquit);
350222732Shrs	return (stoprompt || p == b);
351224144Shrs}
35255505Sshin
35355505Sshin/*
354222732Shrs * Interrupt service routine during prompting
355222732Shrs */
356222732Shrs/*ARGSUSED*/
357224144Shrsstatic void
35855505Sshinintprompt(int signo)
35955505Sshin{
360222820Shrs	(void)signal(SIGINT, SIG_IGN);
361222732Shrs	stoprompt = 1;
362222732Shrs	printf("\r\n");
363222732Shrs	longjmp(promptbuf, 1);
364222732Shrs}
365222732Shrs
366224144Shrs/*
36755505Sshin * ****TIPIN   TIPIN****
368222732Shrs */
369222732Shrsstatic void
370222732Shrstipin(void)
371222732Shrs{
372222732Shrs	int bol = 1;
37378064Sume	int gch;
37455505Sshin	char ch;
37555505Sshin
376222732Shrs	/*
37755505Sshin	 * Kinda klugey here...
378222732Shrs	 *   check for scripting being turned on from the .tiprc file,
379222732Shrs	 *   but be careful about just using setscript(), as we may
380224144Shrs	 *   send a SIGEMT before tipout has a chance to set up catching
38155505Sshin	 *   it; so wait a second, then setscript()
382222732Shrs	 */
383224144Shrs	if (boolean(value(SCRIPT))) {
384222972Shrs		sleep(1);
38555505Sshin		setscript();
38655505Sshin	}
38755505Sshin
38855505Sshin	while (1) {
38955505Sshin		gch = getchar();
39055505Sshin		if (gch == EOF)
39155505Sshin			return;
39255505Sshin		gch = gch & STRIP_PAR;
39355505Sshin		if ((gch == character(value(ESCAPE))) && bol) {
394224144Shrs			if (!noesc) {
395222732Shrs				gch = escape();
396224144Shrs				if (gch == EOF)
397222972Shrs					return;
39855505Sshin				if (gch == 0)
399224144Shrs					continue;
400222732Shrs			}
401222732Shrs		} else if (!cumode && gch == character(value(RAISECHAR))) {
402224144Shrs			setboolean(value(RAISE), !boolean(value(RAISE)));
403224144Shrs			continue;
40455505Sshin		} else if (gch == '\r') {
405224144Shrs			bol = 1;
406222732Shrs			ch = gch;
407224144Shrs			parwrite(FD, &ch, 1);
408222732Shrs			if (boolean(value(HALFDUPLEX)))
409222972Shrs				printf("\r\n");
41055505Sshin			continue;
411224144Shrs		} else if (!cumode && gch == character(value(FORCE))) {
41255505Sshin			gch = getchar();
41355505Sshin			if (gch == EOF)
414222732Shrs				return;
41555505Sshin			gch = gch & STRIP_PAR;
416118968Sume		}
417118968Sume		bol = any(gch, value(EOL));
418118968Sume		if (boolean(value(RAISE)) && islower(gch))
419118968Sume			gch = toupper(gch);
420118968Sume		ch = gch;
421118968Sume		parwrite(FD, &ch, 1);
422118968Sume		if (boolean(value(HALFDUPLEX)))
423118968Sume			printf("%c", ch);
424118968Sume	}
425118968Sume}
426118968Sume
427118968Sumeextern esctable_t etable[];
428222972Shrs
429118968Sume/*
430118968Sume * Escape handler --
431118968Sume *  called on recognition of ``escapec'' at the beginning of a line
432222732Shrs */
433118968Sumestatic int
434222732Shrsescape(void)
435222732Shrs{
436222732Shrs	int gch;
43778064Sume	esctable_t *p;
43878064Sume	char c = character(value(ESCAPE));
43978064Sume
44078064Sume	gch = getchar();
441222732Shrs	if (gch == EOF)
442222732Shrs		return (EOF);
443118968Sume	gch = gch & STRIP_PAR;
444224144Shrs	for (p = etable; p->e_char; p++)
445222972Shrs		if (p->e_char == gch) {
44678064Sume			if ((p->e_flags&PRIV) && uid)
44755505Sshin				continue;
448222732Shrs			printf("%s", ctrl(c));
449224144Shrs			(*p->e_func)(gch);
450224144Shrs			return (0);
45155505Sshin		}
452224144Shrs	/* ESCAPE ESCAPE forces ESCAPE */
453222732Shrs	if (c != gch)
454224144Shrs		parwrite(FD, &c, 1);
455222732Shrs	return (gch);
456222972Shrs}
45755505Sshin
458222732Shrsint
45955505Sshinany(int cc, char *p)
46055505Sshin{
461118968Sume	char c = cc;
46255505Sshin	while (p && *p)
463224144Shrs		if (*p++ == c)
464222732Shrs			return (1);
465224144Shrs	return (0);
466222972Shrs}
46755505Sshin
468224144Shrssize_t
46955505Sshinsize(char *s)
47078064Sume{
47178064Sume	size_t i = 0;
472224144Shrs
473224144Shrs	while (s && *s++)
474222972Shrs		i++;
47555505Sshin	return (i);
476224144Shrs}
47755505Sshin
478118968Sumechar *
47978064Sumeinterp(char *s)
480222732Shrs{
481222732Shrs	static char buf[256];
482222972Shrs	char *p = buf, c, *q;
48378064Sume
48455505Sshin	while ((c = *s++)) {
48578064Sume		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
48678064Sume			if (*q++ == c) {
487118664Sume				*p++ = '\\'; *p++ = *q;
48878064Sume				goto next;
48978064Sume			}
49078064Sume		if (c < 040) {
49178064Sume			*p++ = '^'; *p++ = c + 'A'-1;
492222732Shrs		} else if (c == 0177) {
49378064Sume			*p++ = '^'; *p++ = '?';
494222732Shrs		} else
495118968Sume			*p++ = c;
496118968Sume	next:
497118968Sume		;
498118968Sume	}
499118968Sume	*p = '\0';
500118968Sume	return (buf);
501118968Sume}
502118968Sume
503118968Sumechar *
504222732Shrsctrl(char c)
505222820Shrs{
506222732Shrs	static char s[3];
50771437Sume
508222732Shrs	if (c < 040 || c == 0177) {
509118968Sume		s[0] = '^';
510222732Shrs		s[1] = c == 0177 ? '?' : c+'A'-1;
511222732Shrs		s[2] = '\0';
512222972Shrs	} else {
513118968Sume		s[0] = c;
514222732Shrs		s[1] = '\0';
515118968Sume	}
516222732Shrs	return (s);
517222732Shrs}
518224144Shrs
519222972Shrs/*
520118968Sume * Help command
521222732Shrs */
522118968Sumevoid
523222732Shrshelp(int c)
524222732Shrs{
525224144Shrs	esctable_t *p;
52662656Skris
527118968Sume	printf("%c\r\n", c);
528118968Sume	for (p = etable; p->e_char; p++) {
529118968Sume		if ((p->e_flags&PRIV) && uid)
530224144Shrs			continue;
531222732Shrs		printf("%2s", ctrl(character(value(ESCAPE))));
532224144Shrs		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
533222972Shrs			p->e_flags&EXP ? '*': ' ', p->e_help);
534118968Sume	}
535222732Shrs}
53655505Sshin
537118968Sume/*
538118968Sume * Set up the "remote" tty's state
539118968Sume */
540118968Sumeint
541118968Sumettysetup(int speed)
542118968Sume{
543118968Sume	struct termios	cntrl;
544118968Sume
545118968Sume	if (tcgetattr(FD, &cntrl))
546118968Sume		return (-1);
547118968Sume	cfsetspeed(&cntrl, speed);
548222732Shrs	cntrl.c_cflag &= ~(CSIZE|PARENB);
549222732Shrs	cntrl.c_cflag |= CS8;
55055505Sshin	if (boolean(value(DC)))
551118968Sume		cntrl.c_cflag |= CLOCAL;
552118968Sume	if (boolean(value(HARDWAREFLOW)))
553118968Sume		cntrl.c_cflag |= CRTSCTS;
554224144Shrs	cntrl.c_iflag &= ~(ISTRIP|ICRNL);
555118968Sume	cntrl.c_oflag &= ~OPOST;
556224144Shrs	cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
557224144Shrs	cntrl.c_cc[VMIN] = 1;
558222972Shrs	cntrl.c_cc[VTIME] = 0;
559118968Sume	if (boolean(value(TAND)))
560224144Shrs		cntrl.c_iflag |= IXOFF;
56155505Sshin	return (tcsetattr(FD, TCSAFLUSH, &cntrl));
562118968Sume}
563118968Sume
564253970Shrsstatic char partab[0200];
565253970Shrs
566253970Shrs/*
567222732Shrs * Do a write to the remote machine with the correct parity.
568222732Shrs * We are doing 8 bit wide output, so we just generate a character
569118968Sume * with the right parity and output it.
57078064Sume */
571118968Sumevoid
572118968Sumeparwrite(int fd, char *buf, size_t n)
573118968Sume{
574118968Sume	size_t i;
575224144Shrs	char *bp;
576118968Sume
577224144Shrs	bp = buf;
578224144Shrs	if (bits8 == 0)
579222972Shrs		for (i = 0; i < n; i++) {
580118968Sume			*bp = partab[(*bp) & 0177];
581224144Shrs			bp++;
58255505Sshin		}
583118968Sume	if (write(fd, buf, n) < 0) {
584118968Sume		if (errno == EIO || errno == ENXIO)
585253970Shrs			tipabort("Lost carrier.");
586253970Shrs		/* this is questionable */
587253970Shrs		perror("write");
588222732Shrs	}
589222732Shrs}
59055505Sshin
591222820Shrs/*
592222820Shrs * Build a parity table with appropriate high-order bit.
593222820Shrs */
594222972Shrsvoid
595222972Shrssetparity(char *defparity)
596222972Shrs{
59755505Sshin	int i, flip, clr, set;
598222732Shrs	char *parity;
599222732Shrs	extern const unsigned char evenpartab[];
60055505Sshin
601224144Shrs	if (value(PARITY) == NOSTR)
602224144Shrs		value(PARITY) = defparity;
60355505Sshin	parity = value(PARITY);
604224144Shrs	if (equal(parity, "none")) {
605224144Shrs		bits8 = 1;
606222972Shrs		return;
60755505Sshin	}
608224144Shrs	bits8 = 0;
609222732Shrs	flip = 0;
61055505Sshin	clr = 0377;
61155505Sshin	set = 0;
61255505Sshin	if (equal(parity, "odd"))
61355505Sshin		flip = 0200;			/* reverse bit 7 */
614224144Shrs	else if (equal(parity, "zero"))
61555505Sshin		clr = 0177;			/* turn off bit 7 */
616222732Shrs	else if (equal(parity, "one"))
617224144Shrs		set = 0200;			/* turn on bit 7 */
61855505Sshin	else if (!equal(parity, "even")) {
619224144Shrs		(void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
620222732Shrs		(void) fflush(stderr);
621224144Shrs	}
622224144Shrs	for (i = 0; i < 0200; i++)
623222972Shrs		partab[i] = ((evenpartab[i] ^ flip) | set) & clr;
62455505Sshin}
62555505Sshin