xref: /csrg-svn/usr.bin/tip/tip.c (revision 25550)
119806Sdist /*
219806Sdist  * Copyright (c) 1983 Regents of the University of California.
319806Sdist  * All rights reserved.  The Berkeley software License Agreement
419806Sdist  * specifies the terms and conditions for redistribution.
519806Sdist  */
619806Sdist 
713279Ssam #ifndef lint
819806Sdist char copyright[] =
919806Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1019806Sdist  All rights reserved.\n";
1119806Sdist #endif not lint
125136Ssam 
1319806Sdist #ifndef lint
14*25550Sdonn static char sccsid[] = "@(#)tip.c	5.2 (Berkeley) 11/29/85";
1519806Sdist #endif not lint
1619806Sdist 
173696Sroot /*
185136Ssam  * tip - UNIX link to other systems
193696Sroot  *  tip [-v] [-speed] system-name
205136Ssam  * or
215136Ssam  *  cu phone-number [-s speed] [-l line] [-a acu]
223696Sroot  */
233696Sroot #include "tip.h"
243696Sroot 
253696Sroot /*
263696Sroot  * Baud rate mapping table
273696Sroot  */
283696Sroot int bauds[] = {
293696Sroot 	0, 50, 75, 110, 134, 150, 200, 300, 600,
303696Sroot 	1200, 1800, 2400, 4800, 9600, 19200, -1
313696Sroot };
323696Sroot 
334004Ssam int	disc = OTTYDISC;		/* tip normally runs this way */
343696Sroot int	intprompt();
353696Sroot int	timeout();
365136Ssam int	cleanup();
375257Sshannon char	*sname();
38*25550Sdonn char	PNbuf[256];			/* This limits the size of a number */
395257Sshannon extern char *sprintf();
403696Sroot 
413696Sroot main(argc, argv)
424962Ssam 	char *argv[];
433696Sroot {
443696Sroot 	char *system = NOSTR;
453696Sroot 	register int i;
465257Sshannon 	register char *p;
475257Sshannon 	char sbuf[12];
483696Sroot 
495257Sshannon 	if (equal(sname(argv[0]), "cu")) {
505136Ssam 		cumain(argc, argv);
515136Ssam 		cumode = 1;
525136Ssam 		goto cucommon;
535136Ssam 	}
545136Ssam 
553696Sroot 	if (argc > 4) {
563696Sroot 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
573696Sroot 		exit(1);
583696Sroot 	}
593696Sroot 	if (!isatty(0)) {
603696Sroot 		fprintf(stderr, "tip: must be interactive\n");
613696Sroot 		exit(1);
623696Sroot 	}
635257Sshannon 
645257Sshannon 	for (; argc > 1; argv++, argc--) {
655257Sshannon 		if (argv[1][0] != '-')
665257Sshannon 			system = argv[1];
675257Sshannon 		else switch (argv[1][1]) {
685257Sshannon 
695257Sshannon 		case 'v':
705257Sshannon 			vflag++;
715257Sshannon 			break;
725257Sshannon 
735257Sshannon 		case '0': case '1': case '2': case '3': case '4':
745257Sshannon 		case '5': case '6': case '7': case '8': case '9':
755257Sshannon 			BR = atoi(&argv[1][1]);
765257Sshannon 			break;
775257Sshannon 
785257Sshannon 		default:
795257Sshannon 			fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
805257Sshannon 			break;
815257Sshannon 		}
825257Sshannon 	}
835257Sshannon 
847593Sshannon 	if (system == NOSTR)
857593Sshannon 		goto notnumber;
865257Sshannon 	for (p = system; *p; p++)
875257Sshannon 		if (isalpha(*p))
885257Sshannon 			goto notnumber;
89*25550Sdonn 	/*
90*25550Sdonn 	 * System name is really a phone number...
91*25550Sdonn 	 * Copy the number then stomp on the original (in case the number
92*25550Sdonn 	 *	is private, we don't want 'ps' or 'w' to find it).
93*25550Sdonn 	 */
94*25550Sdonn 	if (strlen(system) > sizeof PNbuf - 1) {
95*25550Sdonn 		fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
96*25550Sdonn 			sizeof PNbuf - 1);
97*25550Sdonn 		exit(1);
98*25550Sdonn 	}
99*25550Sdonn 	strncpy( PNbuf, system, sizeof PNbuf - 1 );
100*25550Sdonn 	for (p = system; *p; p++)
101*25550Sdonn 		*p = '\0';
102*25550Sdonn 	PN = PNbuf;
1035257Sshannon 	system = sprintf(sbuf, "tip%d", BR);
1045257Sshannon 
1055257Sshannon notnumber:
1063696Sroot 	signal(SIGINT, cleanup);
1073696Sroot 	signal(SIGQUIT, cleanup);
1083696Sroot 	signal(SIGHUP, cleanup);
1093696Sroot 	signal(SIGTERM, cleanup);
1103898Ssam 
1113696Sroot 	if ((i = hunt(system)) == 0) {
1123696Sroot 		printf("all ports busy\n");
1133696Sroot 		exit(3);
1143696Sroot 	}
1153696Sroot 	if (i == -1) {
1163696Sroot 		printf("link down\n");
1174232Ssam 		delock(uucplock);
1183696Sroot 		exit(3);
1193696Sroot 	}
1203719Ssam 	setbuf(stdout, NULL);
1213696Sroot 	loginit();
1223696Sroot 	/*
1233696Sroot 	 * Now that we have the logfile and the ACU open
1243696Sroot 	 *  return to the real uid and gid.  These things will
1253696Sroot 	 *  be closed on exit.  Note that we can't run as root,
1263696Sroot 	 *  because locking mechanism on the tty and the accounting
1273696Sroot 	 *  will be bypassed.
1283696Sroot 	 */
12913139Sralph 	setgid(getgid());
1303696Sroot 	setuid(getuid());
1315257Sshannon 
1323696Sroot 	/*
1333696Sroot 	 * Kludge, their's no easy way to get the initialization
1343696Sroot 	 *   in the right order, so force it here
1353696Sroot 	 */
1363696Sroot 	if ((PH = getenv("PHONES")) == NOSTR)
1373696Sroot 		PH = "/etc/phones";
1383696Sroot 	vinit();				/* init variables */
13913430Ssam 	setparity("even");			/* set the parity table */
1404004Ssam 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
1413696Sroot 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
1423696Sroot 		delock(uucplock);
1433696Sroot 		exit(3);
1443696Sroot 	}
1453898Ssam 
1464004Ssam 	/*
1474004Ssam 	 * Hardwired connections require the
1484004Ssam 	 *  line speed set before they make any transmissions
1494004Ssam 	 *  (this is particularly true of things like a DF03-AC)
1504004Ssam 	 */
1514004Ssam 	if (HW)
1524004Ssam 		ttysetup(i);
1533898Ssam 	if (p = connect()) {
1543898Ssam 		printf("\07%s\n[EOT]\n", p);
1553898Ssam 		delock(uucplock);
1563898Ssam 		exit(1);
1573898Ssam 	}
1584004Ssam 	if (!HW)
1594004Ssam 		ttysetup(i);
1605136Ssam cucommon:
1613696Sroot 	/*
1625136Ssam 	 * From here down the code is shared with
1635136Ssam 	 * the "cu" version of tip.
1643696Sroot 	 */
1654004Ssam 	ioctl(0, TIOCGETP, (char *)&defarg);
1664004Ssam 	ioctl(0, TIOCGETC, (char *)&defchars);
16712478Sroot 	ioctl(0, TIOCGLTC, (char *)&deflchars);
1684004Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1693696Sroot 	arg = defarg;
1703696Sroot 	arg.sg_flags = ANYP | CBREAK;
1713696Sroot 	tchars = defchars;
1723696Sroot 	tchars.t_intrc = tchars.t_quitc = -1;
17312478Sroot 	ltchars = deflchars;
17412478Sroot 	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
17512478Sroot 		= ltchars.t_lnextc = -1;
1763696Sroot 	raw();
1774004Ssam 
1783696Sroot 	pipe(fildes); pipe(repdes);
1793696Sroot 	signal(SIGALRM, timeout);
1803898Ssam 
1813898Ssam 	/*
1823898Ssam 	 * Everything's set up now:
18317236Shelge 	 *	connection established (hardwired or dialup)
1843898Ssam 	 *	line conditioned (baud rate, mode, etc.)
1853898Ssam 	 *	internal data structures (variables)
1863898Ssam 	 * so, fork one process for local side and one for remote.
1873898Ssam 	 */
1885136Ssam 	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1893696Sroot 	if (pid = fork())
1903696Sroot 		tipin();
1913696Sroot 	else
1923696Sroot 		tipout();
1933696Sroot 	/*NOTREACHED*/
1943696Sroot }
1953696Sroot 
1963696Sroot cleanup()
1973696Sroot {
19813279Ssam 
1993696Sroot 	delock(uucplock);
2003898Ssam 	if (odisc)
2013898Ssam 		ioctl(0, TIOCSETD, (char *)&odisc);
2023696Sroot 	exit(0);
2033696Sroot }
2043696Sroot 
2053696Sroot /*
2063696Sroot  * put the controlling keyboard into raw mode
2073696Sroot  */
2083696Sroot raw()
2093696Sroot {
21013279Ssam 
2113696Sroot 	ioctl(0, TIOCSETP, &arg);
2123696Sroot 	ioctl(0, TIOCSETC, &tchars);
21312478Sroot 	ioctl(0, TIOCSLTC, &ltchars);
2144004Ssam 	ioctl(0, TIOCSETD, (char *)&disc);
2153696Sroot }
2163696Sroot 
2173696Sroot 
2183696Sroot /*
2193696Sroot  * return keyboard to normal mode
2203696Sroot  */
2213696Sroot unraw()
2223696Sroot {
22313279Ssam 
2244004Ssam 	ioctl(0, TIOCSETD, (char *)&odisc);
2254004Ssam 	ioctl(0, TIOCSETP, (char *)&defarg);
2264004Ssam 	ioctl(0, TIOCSETC, (char *)&defchars);
22712478Sroot 	ioctl(0, TIOCSLTC, (char *)&deflchars);
2283696Sroot }
2293696Sroot 
23013279Ssam static	jmp_buf promptbuf;
23113279Ssam 
2323696Sroot /*
2333696Sroot  * Print string ``s'', then read a string
2343696Sroot  *  in from the terminal.  Handles signals & allows use of
2353696Sroot  *  normal erase and kill characters.
2363696Sroot  */
2373696Sroot prompt(s, p)
2383696Sroot 	char *s;
2393696Sroot 	register char *p;
2403696Sroot {
2413696Sroot 	register char *b = p;
24213279Ssam 	int (*oint)(), (*oquit)();
2433696Sroot 
2443696Sroot 	stoprompt = 0;
24513279Ssam 	oint = signal(SIGINT, intprompt);
24613279Ssam 	oint = signal(SIGQUIT, SIG_IGN);
2473696Sroot 	unraw();
2483696Sroot 	printf("%s", s);
24913279Ssam 	if (setjmp(promptbuf) == 0)
25013279Ssam 		while ((*p = getchar()) != EOF && *p != '\n')
25113279Ssam 			p++;
2523696Sroot 	*p = '\0';
25313279Ssam 
2543696Sroot 	raw();
25513279Ssam 	signal(SIGINT, oint);
25613279Ssam 	signal(SIGQUIT, oint);
25713279Ssam 	return (stoprompt || p == b);
2583696Sroot }
2593696Sroot 
2603696Sroot /*
2613696Sroot  * Interrupt service routine during prompting
2623696Sroot  */
2633696Sroot intprompt()
2643696Sroot {
26513279Ssam 
2663696Sroot 	signal(SIGINT, SIG_IGN);
2673696Sroot 	stoprompt = 1;
2683696Sroot 	printf("\r\n");
26913279Ssam 	longjmp(promptbuf, 1);
2703696Sroot }
2713696Sroot 
2723696Sroot /*
2733696Sroot  * ****TIPIN   TIPIN****
2743696Sroot  */
2753696Sroot tipin()
2763696Sroot {
2773696Sroot 	char gch, bol = 1;
2783696Sroot 
2793796Ssam 	/*
2803796Ssam 	 * Kinda klugey here...
2813796Ssam 	 *   check for scripting being turned on from the .tiprc file,
2823796Ssam 	 *   but be careful about just using setscript(), as we may
2833796Ssam 	 *   send a SIGEMT before tipout has a chance to set up catching
2843796Ssam 	 *   it; so wait a second, then setscript()
2853796Ssam 	 */
2863796Ssam 	if (boolean(value(SCRIPT))) {
2873796Ssam 		sleep(1);
2883796Ssam 		setscript();
2893796Ssam 	}
2903796Ssam 
2913696Sroot 	while (1) {
2923696Sroot 		gch = getchar()&0177;
2933696Sroot 		if ((gch == character(value(ESCAPE))) && bol) {
2943696Sroot 			if (!(gch = escape()))
2953696Sroot 				continue;
2965136Ssam 		} else if (!cumode && gch == character(value(RAISECHAR))) {
2973696Sroot 			boolean(value(RAISE)) = !boolean(value(RAISE));
2983696Sroot 			continue;
2993696Sroot 		} else if (gch == '\r') {
3003696Sroot 			bol = 1;
30113139Sralph 			pwrite(FD, &gch, 1);
30213139Sralph 			if (boolean(value(HALFDUPLEX)))
30313139Sralph 				printf("\r\n");
3043696Sroot 			continue;
3055136Ssam 		} else if (!cumode && gch == character(value(FORCE)))
3063696Sroot 			gch = getchar()&0177;
3073696Sroot 		bol = any(gch, value(EOL));
3083696Sroot 		if (boolean(value(RAISE)) && islower(gch))
30913139Sralph 			gch = toupper(gch);
31013139Sralph 		pwrite(FD, &gch, 1);
31113139Sralph 		if (boolean(value(HALFDUPLEX)))
31213139Sralph 			printf("%c", gch);
3133696Sroot 	}
3143696Sroot }
3153696Sroot 
3163696Sroot /*
3173696Sroot  * Escape handler --
3183696Sroot  *  called on recognition of ``escapec'' at the beginning of a line
3193696Sroot  */
3203696Sroot escape()
3213696Sroot {
3223696Sroot 	register char gch;
3233696Sroot 	register esctable_t *p;
3243696Sroot 	char c = character(value(ESCAPE));
3253696Sroot 	extern esctable_t etable[];
3263696Sroot 
3273696Sroot 	gch = (getchar()&0177);
3283696Sroot 	for (p = etable; p->e_char; p++)
3293696Sroot 		if (p->e_char == gch) {
3303696Sroot 			if ((p->e_flags&PRIV) && getuid())
3313696Sroot 				continue;
3323696Sroot 			printf("%s", ctrl(c));
3333696Sroot 			(*p->e_func)(gch);
33413279Ssam 			return (0);
3353696Sroot 		}
3364146Ssam 	/* ESCAPE ESCAPE forces ESCAPE */
3374146Ssam 	if (c != gch)
33813139Sralph 		pwrite(FD, &c, 1);
33913279Ssam 	return (gch);
3403696Sroot }
3413696Sroot 
3423696Sroot speed(n)
34313279Ssam 	int n;
3443696Sroot {
3453696Sroot 	register int *p;
3463696Sroot 
3473696Sroot 	for (p = bauds; *p != -1;  p++)
3483696Sroot 		if (*p == n)
34913279Ssam 			return (p - bauds);
35013279Ssam 	return (NULL);
3513696Sroot }
3523696Sroot 
3533696Sroot any(c, p)
3543696Sroot 	register char c, *p;
3553696Sroot {
35613279Ssam 	while (p && *p)
3573696Sroot 		if (*p++ == c)
35813279Ssam 			return (1);
35913279Ssam 	return (0);
3603696Sroot }
3613696Sroot 
3623696Sroot size(s)
3633696Sroot 	register char	*s;
3643696Sroot {
36513279Ssam 	register int i = 0;
3663696Sroot 
36713279Ssam 	while (s && *s++)
36813279Ssam 		i++;
36913279Ssam 	return (i);
3703696Sroot }
3713696Sroot 
3723696Sroot char *
3733696Sroot interp(s)
3743696Sroot 	register char *s;
3753696Sroot {
3763696Sroot 	static char buf[256];
3773696Sroot 	register char *p = buf, c, *q;
3783696Sroot 
3793696Sroot 	while (c = *s++) {
3803696Sroot 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
3813696Sroot 			if (*q++ == c) {
3823696Sroot 				*p++ = '\\'; *p++ = *q;
3833696Sroot 				goto next;
3843696Sroot 			}
3853696Sroot 		if (c < 040) {
3863696Sroot 			*p++ = '^'; *p++ = c + 'A'-1;
3873696Sroot 		} else if (c == 0177) {
3883696Sroot 			*p++ = '^'; *p++ = '?';
3893696Sroot 		} else
3903696Sroot 			*p++ = c;
3913696Sroot 	next:
3923696Sroot 		;
3933696Sroot 	}
3943696Sroot 	*p = '\0';
39513279Ssam 	return (buf);
3963696Sroot }
3973696Sroot 
3983696Sroot char *
3993696Sroot ctrl(c)
4003696Sroot 	char c;
4013696Sroot {
4023696Sroot 	static char s[3];
4033696Sroot 
4043696Sroot 	if (c < 040 || c == 0177) {
4053696Sroot 		s[0] = '^';
4063696Sroot 		s[1] = c == 0177 ? '?' : c+'A'-1;
4073696Sroot 		s[2] = '\0';
4083696Sroot 	} else {
4093696Sroot 		s[0] = c;
4103696Sroot 		s[1] = '\0';
4113696Sroot 	}
41213279Ssam 	return (s);
4133696Sroot }
4143696Sroot 
4153696Sroot /*
4163696Sroot  * Help command
4173696Sroot  */
4183696Sroot help(c)
4193696Sroot 	char c;
4203696Sroot {
4213696Sroot 	register esctable_t *p;
4223696Sroot 	extern esctable_t etable[];
4233696Sroot 
4243696Sroot 	printf("%c\r\n", c);
4253696Sroot 	for (p = etable; p->e_char; p++) {
4263696Sroot 		if ((p->e_flags&PRIV) && getuid())
4273696Sroot 			continue;
4283696Sroot 		printf("%2s", ctrl(character(value(ESCAPE))));
4293696Sroot 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
4303696Sroot 			p->e_flags&EXP ? '*': ' ', p->e_help);
4313696Sroot 	}
4323696Sroot }
4334004Ssam 
4344004Ssam /*
4354004Ssam  * Set up the "remote" tty's state
4364004Ssam  */
4374004Ssam ttysetup(speed)
43813279Ssam 	int speed;
4394004Ssam {
4404004Ssam 	unsigned bits = LDECCTQ;
4414004Ssam 
4424004Ssam 	arg.sg_ispeed = arg.sg_ospeed = speed;
44313279Ssam 	arg.sg_flags = RAW;
44413139Sralph 	if (boolean(value(TAND)))
44513279Ssam 		arg.sg_flags |= TANDEM;
4464004Ssam 	ioctl(FD, TIOCSETP, (char *)&arg);
4474004Ssam 	ioctl(FD, TIOCLBIS, (char *)&bits);
4484004Ssam }
4495257Sshannon 
4505257Sshannon /*
4515257Sshannon  * Return "simple" name from a file name,
4525257Sshannon  * strip leading directories.
4535257Sshannon  */
4545257Sshannon char *
4555257Sshannon sname(s)
4565257Sshannon 	register char *s;
4575257Sshannon {
4585257Sshannon 	register char *p = s;
4595257Sshannon 
4605257Sshannon 	while (*s)
4615257Sshannon 		if (*s++ == '/')
4625257Sshannon 			p = s;
4635257Sshannon 	return (p);
4645257Sshannon }
46513139Sralph 
46613139Sralph static char partab[0200];
46713139Sralph 
46813139Sralph /*
46913279Ssam  * Do a write to the remote machine with the correct parity.
47013279Ssam  * We are doing 8 bit wide output, so we just generate a character
47113139Sralph  * with the right parity and output it.
47213139Sralph  */
47313139Sralph pwrite(fd, buf, n)
47413139Sralph 	int fd;
47513139Sralph 	char *buf;
47613139Sralph 	register int n;
47713139Sralph {
47813139Sralph 	register int i;
47913279Ssam 	register char *bp;
48015188Ssam 	extern int errno;
48113139Sralph 
48213279Ssam 	bp = buf;
48313279Ssam 	for (i = 0; i < n; i++) {
48413139Sralph 		*bp = partab[(*bp) & 0177];
48513279Ssam 		bp++;
48613139Sralph 	}
48715188Ssam 	if (write(fd, buf, n) < 0) {
48815188Ssam 		if (errno == EIO)
48915188Ssam 			abort("Lost carrier.");
49015188Ssam 		/* this is questionable */
49115188Ssam 		perror("write");
49215188Ssam 	}
49313139Sralph }
49413139Sralph 
49513139Sralph /*
49613279Ssam  * Build a parity table with appropriate high-order bit.
49713139Sralph  */
49813430Ssam setparity(defparity)
49913430Ssam 	char *defparity;
50013139Sralph {
50113279Ssam 	register int i;
50213139Sralph 	char *parity;
50313279Ssam 	extern char evenpartab[];
50413139Sralph 
50513139Sralph 	if (value(PARITY) == NOSTR)
50613430Ssam 		value(PARITY) = defparity;
50713139Sralph 	parity = value(PARITY);
50813139Sralph 	for (i = 0; i < 0200; i++)
50913279Ssam 		partab[i] = evenpartab[i];
51013279Ssam 	if (equal(parity, "even"))
51113279Ssam 		return;
51213139Sralph 	if (equal(parity, "odd")) {
51313139Sralph 		for (i = 0; i < 0200; i++)
51413139Sralph 			partab[i] ^= 0200;	/* reverse bit 7 */
51513279Ssam 		return;
51613139Sralph 	}
51713279Ssam 	if (equal(parity, "none") || equal(parity, "zero")) {
51813139Sralph 		for (i = 0; i < 0200; i++)
51913139Sralph 			partab[i] &= ~0200;	/* turn off bit 7 */
52013279Ssam 		return;
52113139Sralph 	}
52213279Ssam 	if (equal(parity, "one")) {
52313139Sralph 		for (i = 0; i < 0200; i++)
52413139Sralph 			partab[i] |= 0200;	/* turn on bit 7 */
52513279Ssam 		return;
52613139Sralph 	}
52713279Ssam 	fprintf(stderr, "%s: unknown parity value\n", PA);
52813279Ssam 	fflush(stderr);
52913139Sralph }
530