xref: /csrg-svn/usr.bin/tip/tip.c (revision 40695)
119806Sdist /*
235464Sbostic  * Copyright (c) 1983 The Regents of the University of California.
335464Sbostic  * All rights reserved.
435464Sbostic  *
535464Sbostic  * Redistribution and use in source and binary forms are permitted
635464Sbostic  * provided that the above copyright notice and this paragraph are
735464Sbostic  * duplicated in all such forms and that any documentation,
835464Sbostic  * advertising materials, and other materials related to such
935464Sbostic  * distribution and use acknowledge that the software was developed
1035464Sbostic  * by the University of California, Berkeley.  The name of the
1135464Sbostic  * University may not be used to endorse or promote products derived
1235464Sbostic  * from this software without specific prior written permission.
1335464Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435464Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535464Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1619806Sdist  */
1719806Sdist 
1813279Ssam #ifndef lint
1919806Sdist char copyright[] =
2035464Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
2119806Sdist  All rights reserved.\n";
2235464Sbostic #endif /* not lint */
235136Ssam 
2419806Sdist #ifndef lint
25*40695Sbostic static char sccsid[] = "@(#)tip.c	5.12 (Berkeley) 04/03/90";
2635464Sbostic #endif /* not lint */
2719806Sdist 
283696Sroot /*
295136Ssam  * tip - UNIX link to other systems
303696Sroot  *  tip [-v] [-speed] system-name
315136Ssam  * or
325136Ssam  *  cu phone-number [-s speed] [-l line] [-a acu]
333696Sroot  */
343696Sroot #include "tip.h"
3537857Sbostic #include "pathnames.h"
363696Sroot 
373696Sroot /*
383696Sroot  * Baud rate mapping table
393696Sroot  */
403696Sroot int bauds[] = {
413696Sroot 	0, 50, 75, 110, 134, 150, 200, 300, 600,
423696Sroot 	1200, 1800, 2400, 4800, 9600, 19200, -1
433696Sroot };
443696Sroot 
454004Ssam int	disc = OTTYDISC;		/* tip normally runs this way */
4639254Sbostic void	intprompt();
4739254Sbostic void	timeout();
4839254Sbostic void	cleanup();
495257Sshannon char	*sname();
5025550Sdonn char	PNbuf[256];			/* This limits the size of a number */
513696Sroot 
523696Sroot main(argc, argv)
534962Ssam 	char *argv[];
543696Sroot {
553696Sroot 	char *system = NOSTR;
563696Sroot 	register int i;
575257Sshannon 	register char *p;
585257Sshannon 	char sbuf[12];
593696Sroot 
6030458Skarels 	gid = getgid();
6130458Skarels 	egid = getegid();
6230458Skarels 	uid = getuid();
6330458Skarels 	euid = geteuid();
645257Sshannon 	if (equal(sname(argv[0]), "cu")) {
6525905Skarels 		cumode = 1;
665136Ssam 		cumain(argc, argv);
675136Ssam 		goto cucommon;
685136Ssam 	}
695136Ssam 
703696Sroot 	if (argc > 4) {
713696Sroot 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
723696Sroot 		exit(1);
733696Sroot 	}
743696Sroot 	if (!isatty(0)) {
753696Sroot 		fprintf(stderr, "tip: must be interactive\n");
763696Sroot 		exit(1);
773696Sroot 	}
785257Sshannon 
795257Sshannon 	for (; argc > 1; argv++, argc--) {
805257Sshannon 		if (argv[1][0] != '-')
815257Sshannon 			system = argv[1];
825257Sshannon 		else switch (argv[1][1]) {
835257Sshannon 
845257Sshannon 		case 'v':
855257Sshannon 			vflag++;
865257Sshannon 			break;
875257Sshannon 
885257Sshannon 		case '0': case '1': case '2': case '3': case '4':
895257Sshannon 		case '5': case '6': case '7': case '8': case '9':
905257Sshannon 			BR = atoi(&argv[1][1]);
915257Sshannon 			break;
925257Sshannon 
935257Sshannon 		default:
945257Sshannon 			fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
955257Sshannon 			break;
965257Sshannon 		}
975257Sshannon 	}
985257Sshannon 
997593Sshannon 	if (system == NOSTR)
1007593Sshannon 		goto notnumber;
10127004Sdonn 	if (isalpha(*system))
10227004Sdonn 		goto notnumber;
10325550Sdonn 	/*
10425550Sdonn 	 * System name is really a phone number...
10525550Sdonn 	 * Copy the number then stomp on the original (in case the number
10625550Sdonn 	 *	is private, we don't want 'ps' or 'w' to find it).
10725550Sdonn 	 */
10825550Sdonn 	if (strlen(system) > sizeof PNbuf - 1) {
10925550Sdonn 		fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
11025550Sdonn 			sizeof PNbuf - 1);
11125550Sdonn 		exit(1);
11225550Sdonn 	}
11325550Sdonn 	strncpy( PNbuf, system, sizeof PNbuf - 1 );
11425550Sdonn 	for (p = system; *p; p++)
11525550Sdonn 		*p = '\0';
11625550Sdonn 	PN = PNbuf;
11732513Sbostic 	(void)sprintf(sbuf, "tip%d", BR);
11832513Sbostic 	system = sbuf;
1195257Sshannon 
1205257Sshannon notnumber:
121*40695Sbostic 	(void)signal(SIGINT, cleanup);
122*40695Sbostic 	(void)signal(SIGQUIT, cleanup);
123*40695Sbostic 	(void)signal(SIGHUP, cleanup);
124*40695Sbostic 	(void)signal(SIGTERM, cleanup);
1253898Ssam 
1263696Sroot 	if ((i = hunt(system)) == 0) {
1273696Sroot 		printf("all ports busy\n");
1283696Sroot 		exit(3);
1293696Sroot 	}
1303696Sroot 	if (i == -1) {
1313696Sroot 		printf("link down\n");
13235460Sbostic 		(void)uu_unlock(uucplock);
1333696Sroot 		exit(3);
1343696Sroot 	}
1353719Ssam 	setbuf(stdout, NULL);
1363696Sroot 	loginit();
1375257Sshannon 
1383696Sroot 	/*
1393696Sroot 	 * Kludge, their's no easy way to get the initialization
1403696Sroot 	 *   in the right order, so force it here
1413696Sroot 	 */
1423696Sroot 	if ((PH = getenv("PHONES")) == NOSTR)
14337857Sbostic 		PH = _PATH_PHONES;
1443696Sroot 	vinit();				/* init variables */
14513430Ssam 	setparity("even");			/* set the parity table */
1464004Ssam 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
1473696Sroot 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
14835460Sbostic 		(void)uu_unlock(uucplock);
1493696Sroot 		exit(3);
1503696Sroot 	}
1513898Ssam 
1524004Ssam 	/*
15325905Skarels 	 * Now that we have the logfile and the ACU open
15425905Skarels 	 *  return to the real uid and gid.  These things will
15525905Skarels 	 *  be closed on exit.  Swap real and effective uid's
15625905Skarels 	 *  so we can get the original permissions back
15725905Skarels 	 *  for removing the uucp lock.
15825905Skarels 	 */
15930458Skarels 	user_uid();
16025905Skarels 
16125905Skarels 	/*
1624004Ssam 	 * Hardwired connections require the
1634004Ssam 	 *  line speed set before they make any transmissions
1644004Ssam 	 *  (this is particularly true of things like a DF03-AC)
1654004Ssam 	 */
1664004Ssam 	if (HW)
1674004Ssam 		ttysetup(i);
1683898Ssam 	if (p = connect()) {
1693898Ssam 		printf("\07%s\n[EOT]\n", p);
17030458Skarels 		daemon_uid();
17135460Sbostic 		(void)uu_unlock(uucplock);
1723898Ssam 		exit(1);
1733898Ssam 	}
1744004Ssam 	if (!HW)
1754004Ssam 		ttysetup(i);
1765136Ssam cucommon:
1773696Sroot 	/*
1785136Ssam 	 * From here down the code is shared with
1795136Ssam 	 * the "cu" version of tip.
1803696Sroot 	 */
18125905Skarels 
1824004Ssam 	ioctl(0, TIOCGETP, (char *)&defarg);
1834004Ssam 	ioctl(0, TIOCGETC, (char *)&defchars);
18412478Sroot 	ioctl(0, TIOCGLTC, (char *)&deflchars);
1854004Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1863696Sroot 	arg = defarg;
1873696Sroot 	arg.sg_flags = ANYP | CBREAK;
1883696Sroot 	tchars = defchars;
1893696Sroot 	tchars.t_intrc = tchars.t_quitc = -1;
19012478Sroot 	ltchars = deflchars;
19112478Sroot 	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
19212478Sroot 		= ltchars.t_lnextc = -1;
1933696Sroot 	raw();
1944004Ssam 
1953696Sroot 	pipe(fildes); pipe(repdes);
196*40695Sbostic 	(void)signal(SIGALRM, timeout);
1973898Ssam 
1983898Ssam 	/*
1993898Ssam 	 * Everything's set up now:
20017236Shelge 	 *	connection established (hardwired or dialup)
2013898Ssam 	 *	line conditioned (baud rate, mode, etc.)
2023898Ssam 	 *	internal data structures (variables)
2033898Ssam 	 * so, fork one process for local side and one for remote.
2043898Ssam 	 */
2055136Ssam 	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
2063696Sroot 	if (pid = fork())
2073696Sroot 		tipin();
2083696Sroot 	else
2093696Sroot 		tipout();
2103696Sroot 	/*NOTREACHED*/
2113696Sroot }
2123696Sroot 
21339254Sbostic void
2143696Sroot cleanup()
2153696Sroot {
21613279Ssam 
21730458Skarels 	daemon_uid();
21835460Sbostic 	(void)uu_unlock(uucplock);
2193898Ssam 	if (odisc)
2203898Ssam 		ioctl(0, TIOCSETD, (char *)&odisc);
2213696Sroot 	exit(0);
2223696Sroot }
2233696Sroot 
2243696Sroot /*
22530458Skarels  * Muck with user ID's.  We are setuid to the owner of the lock
22630458Skarels  * directory when we start.  user_uid() reverses real and effective
22730458Skarels  * ID's after startup, to run with the user's permissions.
22830458Skarels  * daemon_uid() switches back to the privileged uid for unlocking.
22930458Skarels  * Finally, to avoid running a shell with the wrong real uid,
23030458Skarels  * shell_uid() sets real and effective uid's to the user's real ID.
23130458Skarels  */
23230458Skarels static int uidswapped;
23330458Skarels 
23430458Skarels user_uid()
23530458Skarels {
23630458Skarels 	if (uidswapped == 0) {
23730458Skarels 		setregid(egid, gid);
23830458Skarels 		setreuid(euid, uid);
23930458Skarels 		uidswapped = 1;
24030458Skarels 	}
24130458Skarels }
24230458Skarels 
24330458Skarels daemon_uid()
24430458Skarels {
24530458Skarels 
24630458Skarels 	if (uidswapped) {
24730458Skarels 		setreuid(uid, euid);
24830458Skarels 		setregid(gid, egid);
24930458Skarels 		uidswapped = 0;
25030458Skarels 	}
25130458Skarels }
25230458Skarels 
25330458Skarels shell_uid()
25430458Skarels {
25530458Skarels 
25630458Skarels 	setreuid(uid, uid);
25730458Skarels 	setregid(gid, gid);
25830458Skarels }
25930458Skarels 
26030458Skarels /*
2613696Sroot  * put the controlling keyboard into raw mode
2623696Sroot  */
2633696Sroot raw()
2643696Sroot {
26513279Ssam 
2663696Sroot 	ioctl(0, TIOCSETP, &arg);
2673696Sroot 	ioctl(0, TIOCSETC, &tchars);
26812478Sroot 	ioctl(0, TIOCSLTC, &ltchars);
2694004Ssam 	ioctl(0, TIOCSETD, (char *)&disc);
2703696Sroot }
2713696Sroot 
2723696Sroot 
2733696Sroot /*
2743696Sroot  * return keyboard to normal mode
2753696Sroot  */
2763696Sroot unraw()
2773696Sroot {
27813279Ssam 
2794004Ssam 	ioctl(0, TIOCSETD, (char *)&odisc);
2804004Ssam 	ioctl(0, TIOCSETP, (char *)&defarg);
2814004Ssam 	ioctl(0, TIOCSETC, (char *)&defchars);
28212478Sroot 	ioctl(0, TIOCSLTC, (char *)&deflchars);
2833696Sroot }
2843696Sroot 
28513279Ssam static	jmp_buf promptbuf;
28613279Ssam 
2873696Sroot /*
2883696Sroot  * Print string ``s'', then read a string
2893696Sroot  *  in from the terminal.  Handles signals & allows use of
2903696Sroot  *  normal erase and kill characters.
2913696Sroot  */
2923696Sroot prompt(s, p)
2933696Sroot 	char *s;
2943696Sroot 	register char *p;
2953696Sroot {
2963696Sroot 	register char *b = p;
29739254Sbostic 	sig_t oint, oquit;
2983696Sroot 
2993696Sroot 	stoprompt = 0;
30013279Ssam 	oint = signal(SIGINT, intprompt);
301*40695Sbostic 	oquit = signal(SIGQUIT, SIG_IGN);
3023696Sroot 	unraw();
3033696Sroot 	printf("%s", s);
30413279Ssam 	if (setjmp(promptbuf) == 0)
30513279Ssam 		while ((*p = getchar()) != EOF && *p != '\n')
30613279Ssam 			p++;
3073696Sroot 	*p = '\0';
30813279Ssam 
3093696Sroot 	raw();
310*40695Sbostic 	(void)signal(SIGINT, oint);
311*40695Sbostic 	(void)signal(SIGQUIT, oquit);
31213279Ssam 	return (stoprompt || p == b);
3133696Sroot }
3143696Sroot 
3153696Sroot /*
3163696Sroot  * Interrupt service routine during prompting
3173696Sroot  */
31839254Sbostic void
3193696Sroot intprompt()
3203696Sroot {
32113279Ssam 
322*40695Sbostic 	(void)signal(SIGINT, SIG_IGN);
3233696Sroot 	stoprompt = 1;
3243696Sroot 	printf("\r\n");
32513279Ssam 	longjmp(promptbuf, 1);
3263696Sroot }
3273696Sroot 
3283696Sroot /*
3293696Sroot  * ****TIPIN   TIPIN****
3303696Sroot  */
3313696Sroot tipin()
3323696Sroot {
3333696Sroot 	char gch, bol = 1;
3343696Sroot 
3353796Ssam 	/*
3363796Ssam 	 * Kinda klugey here...
3373796Ssam 	 *   check for scripting being turned on from the .tiprc file,
3383796Ssam 	 *   but be careful about just using setscript(), as we may
3393796Ssam 	 *   send a SIGEMT before tipout has a chance to set up catching
3403796Ssam 	 *   it; so wait a second, then setscript()
3413796Ssam 	 */
3423796Ssam 	if (boolean(value(SCRIPT))) {
3433796Ssam 		sleep(1);
3443796Ssam 		setscript();
3453796Ssam 	}
3463796Ssam 
3473696Sroot 	while (1) {
3483696Sroot 		gch = getchar()&0177;
3493696Sroot 		if ((gch == character(value(ESCAPE))) && bol) {
3503696Sroot 			if (!(gch = escape()))
3513696Sroot 				continue;
3525136Ssam 		} else if (!cumode && gch == character(value(RAISECHAR))) {
3533696Sroot 			boolean(value(RAISE)) = !boolean(value(RAISE));
3543696Sroot 			continue;
3553696Sroot 		} else if (gch == '\r') {
3563696Sroot 			bol = 1;
35713139Sralph 			pwrite(FD, &gch, 1);
35813139Sralph 			if (boolean(value(HALFDUPLEX)))
35913139Sralph 				printf("\r\n");
3603696Sroot 			continue;
3615136Ssam 		} else if (!cumode && gch == character(value(FORCE)))
3623696Sroot 			gch = getchar()&0177;
3633696Sroot 		bol = any(gch, value(EOL));
3643696Sroot 		if (boolean(value(RAISE)) && islower(gch))
36513139Sralph 			gch = toupper(gch);
36613139Sralph 		pwrite(FD, &gch, 1);
36713139Sralph 		if (boolean(value(HALFDUPLEX)))
36813139Sralph 			printf("%c", gch);
3693696Sroot 	}
3703696Sroot }
3713696Sroot 
3723696Sroot /*
3733696Sroot  * Escape handler --
3743696Sroot  *  called on recognition of ``escapec'' at the beginning of a line
3753696Sroot  */
3763696Sroot escape()
3773696Sroot {
3783696Sroot 	register char gch;
3793696Sroot 	register esctable_t *p;
3803696Sroot 	char c = character(value(ESCAPE));
3813696Sroot 	extern esctable_t etable[];
3823696Sroot 
3833696Sroot 	gch = (getchar()&0177);
3843696Sroot 	for (p = etable; p->e_char; p++)
3853696Sroot 		if (p->e_char == gch) {
38630458Skarels 			if ((p->e_flags&PRIV) && uid)
3873696Sroot 				continue;
3883696Sroot 			printf("%s", ctrl(c));
3893696Sroot 			(*p->e_func)(gch);
39013279Ssam 			return (0);
3913696Sroot 		}
3924146Ssam 	/* ESCAPE ESCAPE forces ESCAPE */
3934146Ssam 	if (c != gch)
39413139Sralph 		pwrite(FD, &c, 1);
39513279Ssam 	return (gch);
3963696Sroot }
3973696Sroot 
3983696Sroot speed(n)
39913279Ssam 	int n;
4003696Sroot {
4013696Sroot 	register int *p;
4023696Sroot 
4033696Sroot 	for (p = bauds; *p != -1;  p++)
4043696Sroot 		if (*p == n)
40513279Ssam 			return (p - bauds);
40613279Ssam 	return (NULL);
4073696Sroot }
4083696Sroot 
4093696Sroot any(c, p)
4103696Sroot 	register char c, *p;
4113696Sroot {
41213279Ssam 	while (p && *p)
4133696Sroot 		if (*p++ == c)
41413279Ssam 			return (1);
41513279Ssam 	return (0);
4163696Sroot }
4173696Sroot 
4183696Sroot size(s)
4193696Sroot 	register char	*s;
4203696Sroot {
42113279Ssam 	register int i = 0;
4223696Sroot 
42313279Ssam 	while (s && *s++)
42413279Ssam 		i++;
42513279Ssam 	return (i);
4263696Sroot }
4273696Sroot 
4283696Sroot char *
4293696Sroot interp(s)
4303696Sroot 	register char *s;
4313696Sroot {
4323696Sroot 	static char buf[256];
4333696Sroot 	register char *p = buf, c, *q;
4343696Sroot 
4353696Sroot 	while (c = *s++) {
4363696Sroot 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
4373696Sroot 			if (*q++ == c) {
4383696Sroot 				*p++ = '\\'; *p++ = *q;
4393696Sroot 				goto next;
4403696Sroot 			}
4413696Sroot 		if (c < 040) {
4423696Sroot 			*p++ = '^'; *p++ = c + 'A'-1;
4433696Sroot 		} else if (c == 0177) {
4443696Sroot 			*p++ = '^'; *p++ = '?';
4453696Sroot 		} else
4463696Sroot 			*p++ = c;
4473696Sroot 	next:
4483696Sroot 		;
4493696Sroot 	}
4503696Sroot 	*p = '\0';
45113279Ssam 	return (buf);
4523696Sroot }
4533696Sroot 
4543696Sroot char *
4553696Sroot ctrl(c)
4563696Sroot 	char c;
4573696Sroot {
4583696Sroot 	static char s[3];
4593696Sroot 
4603696Sroot 	if (c < 040 || c == 0177) {
4613696Sroot 		s[0] = '^';
4623696Sroot 		s[1] = c == 0177 ? '?' : c+'A'-1;
4633696Sroot 		s[2] = '\0';
4643696Sroot 	} else {
4653696Sroot 		s[0] = c;
4663696Sroot 		s[1] = '\0';
4673696Sroot 	}
46813279Ssam 	return (s);
4693696Sroot }
4703696Sroot 
4713696Sroot /*
4723696Sroot  * Help command
4733696Sroot  */
4743696Sroot help(c)
4753696Sroot 	char c;
4763696Sroot {
4773696Sroot 	register esctable_t *p;
4783696Sroot 	extern esctable_t etable[];
4793696Sroot 
4803696Sroot 	printf("%c\r\n", c);
4813696Sroot 	for (p = etable; p->e_char; p++) {
48230458Skarels 		if ((p->e_flags&PRIV) && uid)
4833696Sroot 			continue;
4843696Sroot 		printf("%2s", ctrl(character(value(ESCAPE))));
4853696Sroot 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
4863696Sroot 			p->e_flags&EXP ? '*': ' ', p->e_help);
4873696Sroot 	}
4883696Sroot }
4894004Ssam 
4904004Ssam /*
4914004Ssam  * Set up the "remote" tty's state
4924004Ssam  */
4934004Ssam ttysetup(speed)
49413279Ssam 	int speed;
4954004Ssam {
4964004Ssam 	unsigned bits = LDECCTQ;
4974004Ssam 
4984004Ssam 	arg.sg_ispeed = arg.sg_ospeed = speed;
49913279Ssam 	arg.sg_flags = RAW;
50013139Sralph 	if (boolean(value(TAND)))
50113279Ssam 		arg.sg_flags |= TANDEM;
5024004Ssam 	ioctl(FD, TIOCSETP, (char *)&arg);
5034004Ssam 	ioctl(FD, TIOCLBIS, (char *)&bits);
5044004Ssam }
5055257Sshannon 
5065257Sshannon /*
5075257Sshannon  * Return "simple" name from a file name,
5085257Sshannon  * strip leading directories.
5095257Sshannon  */
5105257Sshannon char *
5115257Sshannon sname(s)
5125257Sshannon 	register char *s;
5135257Sshannon {
5145257Sshannon 	register char *p = s;
5155257Sshannon 
5165257Sshannon 	while (*s)
5175257Sshannon 		if (*s++ == '/')
5185257Sshannon 			p = s;
5195257Sshannon 	return (p);
5205257Sshannon }
52113139Sralph 
52213139Sralph static char partab[0200];
52340240Skarels static int bits8;
52413139Sralph 
52513139Sralph /*
52613279Ssam  * Do a write to the remote machine with the correct parity.
52713279Ssam  * We are doing 8 bit wide output, so we just generate a character
52813139Sralph  * with the right parity and output it.
52913139Sralph  */
53013139Sralph pwrite(fd, buf, n)
53113139Sralph 	int fd;
53213139Sralph 	char *buf;
53313139Sralph 	register int n;
53413139Sralph {
53513139Sralph 	register int i;
53613279Ssam 	register char *bp;
53715188Ssam 	extern int errno;
53813139Sralph 
53913279Ssam 	bp = buf;
54040240Skarels 	if (bits8 == 0)
54140240Skarels 		for (i = 0; i < n; i++) {
54240240Skarels 			*bp = partab[(*bp) & 0177];
54340240Skarels 			bp++;
54440240Skarels 		}
54515188Ssam 	if (write(fd, buf, n) < 0) {
54615188Ssam 		if (errno == EIO)
54715188Ssam 			abort("Lost carrier.");
54815188Ssam 		/* this is questionable */
54915188Ssam 		perror("write");
55015188Ssam 	}
55113139Sralph }
55213139Sralph 
55313139Sralph /*
55413279Ssam  * Build a parity table with appropriate high-order bit.
55513139Sralph  */
55613430Ssam setparity(defparity)
55713430Ssam 	char *defparity;
55813139Sralph {
55913279Ssam 	register int i;
56013139Sralph 	char *parity;
56113279Ssam 	extern char evenpartab[];
56213139Sralph 
56313139Sralph 	if (value(PARITY) == NOSTR)
56413430Ssam 		value(PARITY) = defparity;
56513139Sralph 	parity = value(PARITY);
56640240Skarels 	if (equal(parity, "none")) {
56740240Skarels 		bits8 = 1;
56840240Skarels 		return;
56940240Skarels 	} else
57040240Skarels 		bits8 = 0;
57113139Sralph 	for (i = 0; i < 0200; i++)
57213279Ssam 		partab[i] = evenpartab[i];
57313279Ssam 	if (equal(parity, "even"))
57413279Ssam 		return;
57513139Sralph 	if (equal(parity, "odd")) {
57613139Sralph 		for (i = 0; i < 0200; i++)
57713139Sralph 			partab[i] ^= 0200;	/* reverse bit 7 */
57813279Ssam 		return;
57913139Sralph 	}
58040240Skarels 	if (equal(parity, "zero")) {
58113139Sralph 		for (i = 0; i < 0200; i++)
58213139Sralph 			partab[i] &= ~0200;	/* turn off bit 7 */
58313279Ssam 		return;
58413139Sralph 	}
58513279Ssam 	if (equal(parity, "one")) {
58613139Sralph 		for (i = 0; i < 0200; i++)
58713139Sralph 			partab[i] |= 0200;	/* turn on bit 7 */
58813279Ssam 		return;
58913139Sralph 	}
59013279Ssam 	fprintf(stderr, "%s: unknown parity value\n", PA);
59113279Ssam 	fflush(stderr);
59213139Sralph }
593