xref: /csrg-svn/usr.bin/tip/tip.c (revision 17236)
113279Ssam #ifndef lint
2*17236Shelge static char sccsid[] = "@(#)tip.c	4.18 (Berkeley) 10/06/84";
313279Ssam #endif
45136Ssam 
53696Sroot /*
65136Ssam  * tip - UNIX link to other systems
73696Sroot  *  tip [-v] [-speed] system-name
85136Ssam  * or
95136Ssam  *  cu phone-number [-s speed] [-l line] [-a acu]
103696Sroot  */
113696Sroot #include "tip.h"
123696Sroot 
133696Sroot /*
143696Sroot  * Baud rate mapping table
153696Sroot  */
163696Sroot int bauds[] = {
173696Sroot 	0, 50, 75, 110, 134, 150, 200, 300, 600,
183696Sroot 	1200, 1800, 2400, 4800, 9600, 19200, -1
193696Sroot };
203696Sroot 
214004Ssam int	disc = OTTYDISC;		/* tip normally runs this way */
223696Sroot int	intprompt();
233696Sroot int	timeout();
245136Ssam int	cleanup();
255257Sshannon char	*sname();
265257Sshannon extern char *sprintf();
273696Sroot 
283696Sroot main(argc, argv)
294962Ssam 	char *argv[];
303696Sroot {
313696Sroot 	char *system = NOSTR;
323696Sroot 	register int i;
335257Sshannon 	register char *p;
345257Sshannon 	char sbuf[12];
353696Sroot 
365257Sshannon 	if (equal(sname(argv[0]), "cu")) {
375136Ssam 		cumain(argc, argv);
385136Ssam 		cumode = 1;
395136Ssam 		goto cucommon;
405136Ssam 	}
415136Ssam 
423696Sroot 	if (argc > 4) {
433696Sroot 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
443696Sroot 		exit(1);
453696Sroot 	}
463696Sroot 	if (!isatty(0)) {
473696Sroot 		fprintf(stderr, "tip: must be interactive\n");
483696Sroot 		exit(1);
493696Sroot 	}
505257Sshannon 
515257Sshannon 	for (; argc > 1; argv++, argc--) {
525257Sshannon 		if (argv[1][0] != '-')
535257Sshannon 			system = argv[1];
545257Sshannon 		else switch (argv[1][1]) {
555257Sshannon 
565257Sshannon 		case 'v':
575257Sshannon 			vflag++;
585257Sshannon 			break;
595257Sshannon 
605257Sshannon 		case '0': case '1': case '2': case '3': case '4':
615257Sshannon 		case '5': case '6': case '7': case '8': case '9':
625257Sshannon 			BR = atoi(&argv[1][1]);
635257Sshannon 			break;
645257Sshannon 
655257Sshannon 		default:
665257Sshannon 			fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
675257Sshannon 			break;
685257Sshannon 		}
695257Sshannon 	}
705257Sshannon 
717593Sshannon 	if (system == NOSTR)
727593Sshannon 		goto notnumber;
735257Sshannon 	for (p = system; *p; p++)
745257Sshannon 		if (isalpha(*p))
755257Sshannon 			goto notnumber;
765257Sshannon 	PN = system;		/* system name is really a phone number */
775257Sshannon 	system = sprintf(sbuf, "tip%d", BR);
785257Sshannon 
795257Sshannon notnumber:
803696Sroot 	signal(SIGINT, cleanup);
813696Sroot 	signal(SIGQUIT, cleanup);
823696Sroot 	signal(SIGHUP, cleanup);
833696Sroot 	signal(SIGTERM, cleanup);
843898Ssam 
853696Sroot 	if ((i = hunt(system)) == 0) {
863696Sroot 		printf("all ports busy\n");
873696Sroot 		exit(3);
883696Sroot 	}
893696Sroot 	if (i == -1) {
903696Sroot 		printf("link down\n");
914232Ssam 		delock(uucplock);
923696Sroot 		exit(3);
933696Sroot 	}
943719Ssam 	setbuf(stdout, NULL);
953696Sroot 	loginit();
963696Sroot 	/*
973696Sroot 	 * Now that we have the logfile and the ACU open
983696Sroot 	 *  return to the real uid and gid.  These things will
993696Sroot 	 *  be closed on exit.  Note that we can't run as root,
1003696Sroot 	 *  because locking mechanism on the tty and the accounting
1013696Sroot 	 *  will be bypassed.
1023696Sroot 	 */
10313139Sralph 	setgid(getgid());
1043696Sroot 	setuid(getuid());
1055257Sshannon 
1063696Sroot 	/*
1073696Sroot 	 * Kludge, their's no easy way to get the initialization
1083696Sroot 	 *   in the right order, so force it here
1093696Sroot 	 */
1103696Sroot 	if ((PH = getenv("PHONES")) == NOSTR)
1113696Sroot 		PH = "/etc/phones";
1123696Sroot 	vinit();				/* init variables */
11313430Ssam 	setparity("even");			/* set the parity table */
1144004Ssam 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
1153696Sroot 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
1163696Sroot 		delock(uucplock);
1173696Sroot 		exit(3);
1183696Sroot 	}
1193898Ssam 
1204004Ssam 	/*
1214004Ssam 	 * Hardwired connections require the
1224004Ssam 	 *  line speed set before they make any transmissions
1234004Ssam 	 *  (this is particularly true of things like a DF03-AC)
1244004Ssam 	 */
1254004Ssam 	if (HW)
1264004Ssam 		ttysetup(i);
1273898Ssam 	if (p = connect()) {
1283898Ssam 		printf("\07%s\n[EOT]\n", p);
1293898Ssam 		delock(uucplock);
1303898Ssam 		exit(1);
1313898Ssam 	}
1324004Ssam 	if (!HW)
1334004Ssam 		ttysetup(i);
1345136Ssam cucommon:
1353696Sroot 	/*
1365136Ssam 	 * From here down the code is shared with
1375136Ssam 	 * the "cu" version of tip.
1383696Sroot 	 */
1394004Ssam 	ioctl(0, TIOCGETP, (char *)&defarg);
1404004Ssam 	ioctl(0, TIOCGETC, (char *)&defchars);
14112478Sroot 	ioctl(0, TIOCGLTC, (char *)&deflchars);
1424004Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1433696Sroot 	arg = defarg;
1443696Sroot 	arg.sg_flags = ANYP | CBREAK;
1453696Sroot 	tchars = defchars;
1463696Sroot 	tchars.t_intrc = tchars.t_quitc = -1;
14712478Sroot 	ltchars = deflchars;
14812478Sroot 	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
14912478Sroot 		= ltchars.t_lnextc = -1;
1503696Sroot 	raw();
1514004Ssam 
1523696Sroot 	pipe(fildes); pipe(repdes);
1533696Sroot 	signal(SIGALRM, timeout);
1543898Ssam 
1553898Ssam 	/*
1563898Ssam 	 * Everything's set up now:
157*17236Shelge 	 *	connection established (hardwired or dialup)
1583898Ssam 	 *	line conditioned (baud rate, mode, etc.)
1593898Ssam 	 *	internal data structures (variables)
1603898Ssam 	 * so, fork one process for local side and one for remote.
1613898Ssam 	 */
1625136Ssam 	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
1633696Sroot 	if (pid = fork())
1643696Sroot 		tipin();
1653696Sroot 	else
1663696Sroot 		tipout();
1673696Sroot 	/*NOTREACHED*/
1683696Sroot }
1693696Sroot 
1703696Sroot cleanup()
1713696Sroot {
17213279Ssam 
1733696Sroot 	delock(uucplock);
1743898Ssam 	if (odisc)
1753898Ssam 		ioctl(0, TIOCSETD, (char *)&odisc);
1763696Sroot 	exit(0);
1773696Sroot }
1783696Sroot 
1793696Sroot /*
1803696Sroot  * put the controlling keyboard into raw mode
1813696Sroot  */
1823696Sroot raw()
1833696Sroot {
18413279Ssam 
1853696Sroot 	ioctl(0, TIOCSETP, &arg);
1863696Sroot 	ioctl(0, TIOCSETC, &tchars);
18712478Sroot 	ioctl(0, TIOCSLTC, &ltchars);
1884004Ssam 	ioctl(0, TIOCSETD, (char *)&disc);
1893696Sroot }
1903696Sroot 
1913696Sroot 
1923696Sroot /*
1933696Sroot  * return keyboard to normal mode
1943696Sroot  */
1953696Sroot unraw()
1963696Sroot {
19713279Ssam 
1984004Ssam 	ioctl(0, TIOCSETD, (char *)&odisc);
1994004Ssam 	ioctl(0, TIOCSETP, (char *)&defarg);
2004004Ssam 	ioctl(0, TIOCSETC, (char *)&defchars);
20112478Sroot 	ioctl(0, TIOCSLTC, (char *)&deflchars);
2023696Sroot }
2033696Sroot 
20413279Ssam static	jmp_buf promptbuf;
20513279Ssam 
2063696Sroot /*
2073696Sroot  * Print string ``s'', then read a string
2083696Sroot  *  in from the terminal.  Handles signals & allows use of
2093696Sroot  *  normal erase and kill characters.
2103696Sroot  */
2113696Sroot prompt(s, p)
2123696Sroot 	char *s;
2133696Sroot 	register char *p;
2143696Sroot {
2153696Sroot 	register char *b = p;
21613279Ssam 	int (*oint)(), (*oquit)();
2173696Sroot 
2183696Sroot 	stoprompt = 0;
21913279Ssam 	oint = signal(SIGINT, intprompt);
22013279Ssam 	oint = signal(SIGQUIT, SIG_IGN);
2213696Sroot 	unraw();
2223696Sroot 	printf("%s", s);
22313279Ssam 	if (setjmp(promptbuf) == 0)
22413279Ssam 		while ((*p = getchar()) != EOF && *p != '\n')
22513279Ssam 			p++;
2263696Sroot 	*p = '\0';
22713279Ssam 
2283696Sroot 	raw();
22913279Ssam 	signal(SIGINT, oint);
23013279Ssam 	signal(SIGQUIT, oint);
23113279Ssam 	return (stoprompt || p == b);
2323696Sroot }
2333696Sroot 
2343696Sroot /*
2353696Sroot  * Interrupt service routine during prompting
2363696Sroot  */
2373696Sroot intprompt()
2383696Sroot {
23913279Ssam 
2403696Sroot 	signal(SIGINT, SIG_IGN);
2413696Sroot 	stoprompt = 1;
2423696Sroot 	printf("\r\n");
24313279Ssam 	longjmp(promptbuf, 1);
2443696Sroot }
2453696Sroot 
2463696Sroot /*
2473696Sroot  * ****TIPIN   TIPIN****
2483696Sroot  */
2493696Sroot tipin()
2503696Sroot {
2513696Sroot 	char gch, bol = 1;
2523696Sroot 
2533796Ssam 	/*
2543796Ssam 	 * Kinda klugey here...
2553796Ssam 	 *   check for scripting being turned on from the .tiprc file,
2563796Ssam 	 *   but be careful about just using setscript(), as we may
2573796Ssam 	 *   send a SIGEMT before tipout has a chance to set up catching
2583796Ssam 	 *   it; so wait a second, then setscript()
2593796Ssam 	 */
2603796Ssam 	if (boolean(value(SCRIPT))) {
2613796Ssam 		sleep(1);
2623796Ssam 		setscript();
2633796Ssam 	}
2643796Ssam 
2653696Sroot 	while (1) {
2663696Sroot 		gch = getchar()&0177;
2673696Sroot 		if ((gch == character(value(ESCAPE))) && bol) {
2683696Sroot 			if (!(gch = escape()))
2693696Sroot 				continue;
2705136Ssam 		} else if (!cumode && gch == character(value(RAISECHAR))) {
2713696Sroot 			boolean(value(RAISE)) = !boolean(value(RAISE));
2723696Sroot 			continue;
2733696Sroot 		} else if (gch == '\r') {
2743696Sroot 			bol = 1;
27513139Sralph 			pwrite(FD, &gch, 1);
27613139Sralph 			if (boolean(value(HALFDUPLEX)))
27713139Sralph 				printf("\r\n");
2783696Sroot 			continue;
2795136Ssam 		} else if (!cumode && gch == character(value(FORCE)))
2803696Sroot 			gch = getchar()&0177;
2813696Sroot 		bol = any(gch, value(EOL));
2823696Sroot 		if (boolean(value(RAISE)) && islower(gch))
28313139Sralph 			gch = toupper(gch);
28413139Sralph 		pwrite(FD, &gch, 1);
28513139Sralph 		if (boolean(value(HALFDUPLEX)))
28613139Sralph 			printf("%c", gch);
2873696Sroot 	}
2883696Sroot }
2893696Sroot 
2903696Sroot /*
2913696Sroot  * Escape handler --
2923696Sroot  *  called on recognition of ``escapec'' at the beginning of a line
2933696Sroot  */
2943696Sroot escape()
2953696Sroot {
2963696Sroot 	register char gch;
2973696Sroot 	register esctable_t *p;
2983696Sroot 	char c = character(value(ESCAPE));
2993696Sroot 	extern esctable_t etable[];
3003696Sroot 
3013696Sroot 	gch = (getchar()&0177);
3023696Sroot 	for (p = etable; p->e_char; p++)
3033696Sroot 		if (p->e_char == gch) {
3043696Sroot 			if ((p->e_flags&PRIV) && getuid())
3053696Sroot 				continue;
3063696Sroot 			printf("%s", ctrl(c));
3073696Sroot 			(*p->e_func)(gch);
30813279Ssam 			return (0);
3093696Sroot 		}
3104146Ssam 	/* ESCAPE ESCAPE forces ESCAPE */
3114146Ssam 	if (c != gch)
31213139Sralph 		pwrite(FD, &c, 1);
31313279Ssam 	return (gch);
3143696Sroot }
3153696Sroot 
3163696Sroot speed(n)
31713279Ssam 	int n;
3183696Sroot {
3193696Sroot 	register int *p;
3203696Sroot 
3213696Sroot 	for (p = bauds; *p != -1;  p++)
3223696Sroot 		if (*p == n)
32313279Ssam 			return (p - bauds);
32413279Ssam 	return (NULL);
3253696Sroot }
3263696Sroot 
3273696Sroot any(c, p)
3283696Sroot 	register char c, *p;
3293696Sroot {
33013279Ssam 	while (p && *p)
3313696Sroot 		if (*p++ == c)
33213279Ssam 			return (1);
33313279Ssam 	return (0);
3343696Sroot }
3353696Sroot 
3363696Sroot size(s)
3373696Sroot 	register char	*s;
3383696Sroot {
33913279Ssam 	register int i = 0;
3403696Sroot 
34113279Ssam 	while (s && *s++)
34213279Ssam 		i++;
34313279Ssam 	return (i);
3443696Sroot }
3453696Sroot 
3463696Sroot char *
3473696Sroot interp(s)
3483696Sroot 	register char *s;
3493696Sroot {
3503696Sroot 	static char buf[256];
3513696Sroot 	register char *p = buf, c, *q;
3523696Sroot 
3533696Sroot 	while (c = *s++) {
3543696Sroot 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
3553696Sroot 			if (*q++ == c) {
3563696Sroot 				*p++ = '\\'; *p++ = *q;
3573696Sroot 				goto next;
3583696Sroot 			}
3593696Sroot 		if (c < 040) {
3603696Sroot 			*p++ = '^'; *p++ = c + 'A'-1;
3613696Sroot 		} else if (c == 0177) {
3623696Sroot 			*p++ = '^'; *p++ = '?';
3633696Sroot 		} else
3643696Sroot 			*p++ = c;
3653696Sroot 	next:
3663696Sroot 		;
3673696Sroot 	}
3683696Sroot 	*p = '\0';
36913279Ssam 	return (buf);
3703696Sroot }
3713696Sroot 
3723696Sroot char *
3733696Sroot ctrl(c)
3743696Sroot 	char c;
3753696Sroot {
3763696Sroot 	static char s[3];
3773696Sroot 
3783696Sroot 	if (c < 040 || c == 0177) {
3793696Sroot 		s[0] = '^';
3803696Sroot 		s[1] = c == 0177 ? '?' : c+'A'-1;
3813696Sroot 		s[2] = '\0';
3823696Sroot 	} else {
3833696Sroot 		s[0] = c;
3843696Sroot 		s[1] = '\0';
3853696Sroot 	}
38613279Ssam 	return (s);
3873696Sroot }
3883696Sroot 
3893696Sroot /*
3903696Sroot  * Help command
3913696Sroot  */
3923696Sroot help(c)
3933696Sroot 	char c;
3943696Sroot {
3953696Sroot 	register esctable_t *p;
3963696Sroot 	extern esctable_t etable[];
3973696Sroot 
3983696Sroot 	printf("%c\r\n", c);
3993696Sroot 	for (p = etable; p->e_char; p++) {
4003696Sroot 		if ((p->e_flags&PRIV) && getuid())
4013696Sroot 			continue;
4023696Sroot 		printf("%2s", ctrl(character(value(ESCAPE))));
4033696Sroot 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
4043696Sroot 			p->e_flags&EXP ? '*': ' ', p->e_help);
4053696Sroot 	}
4063696Sroot }
4074004Ssam 
4084004Ssam /*
4094004Ssam  * Set up the "remote" tty's state
4104004Ssam  */
4114004Ssam ttysetup(speed)
41213279Ssam 	int speed;
4134004Ssam {
4144004Ssam 	unsigned bits = LDECCTQ;
4154004Ssam 
4164004Ssam 	arg.sg_ispeed = arg.sg_ospeed = speed;
41713279Ssam 	arg.sg_flags = RAW;
41813139Sralph 	if (boolean(value(TAND)))
41913279Ssam 		arg.sg_flags |= TANDEM;
4204004Ssam 	ioctl(FD, TIOCSETP, (char *)&arg);
4214004Ssam 	ioctl(FD, TIOCLBIS, (char *)&bits);
4224004Ssam }
4235257Sshannon 
4245257Sshannon /*
4255257Sshannon  * Return "simple" name from a file name,
4265257Sshannon  * strip leading directories.
4275257Sshannon  */
4285257Sshannon char *
4295257Sshannon sname(s)
4305257Sshannon 	register char *s;
4315257Sshannon {
4325257Sshannon 	register char *p = s;
4335257Sshannon 
4345257Sshannon 	while (*s)
4355257Sshannon 		if (*s++ == '/')
4365257Sshannon 			p = s;
4375257Sshannon 	return (p);
4385257Sshannon }
43913139Sralph 
44013139Sralph static char partab[0200];
44113139Sralph 
44213139Sralph /*
44313279Ssam  * Do a write to the remote machine with the correct parity.
44413279Ssam  * We are doing 8 bit wide output, so we just generate a character
44513139Sralph  * with the right parity and output it.
44613139Sralph  */
44713139Sralph pwrite(fd, buf, n)
44813139Sralph 	int fd;
44913139Sralph 	char *buf;
45013139Sralph 	register int n;
45113139Sralph {
45213139Sralph 	register int i;
45313279Ssam 	register char *bp;
45415188Ssam 	extern int errno;
45513139Sralph 
45613279Ssam 	bp = buf;
45713279Ssam 	for (i = 0; i < n; i++) {
45813139Sralph 		*bp = partab[(*bp) & 0177];
45913279Ssam 		bp++;
46013139Sralph 	}
46115188Ssam 	if (write(fd, buf, n) < 0) {
46215188Ssam 		if (errno == EIO)
46315188Ssam 			abort("Lost carrier.");
46415188Ssam 		/* this is questionable */
46515188Ssam 		perror("write");
46615188Ssam 	}
46713139Sralph }
46813139Sralph 
46913139Sralph /*
47013279Ssam  * Build a parity table with appropriate high-order bit.
47113139Sralph  */
47213430Ssam setparity(defparity)
47313430Ssam 	char *defparity;
47413139Sralph {
47513279Ssam 	register int i;
47613139Sralph 	char *parity;
47713279Ssam 	extern char evenpartab[];
47813139Sralph 
47913139Sralph 	if (value(PARITY) == NOSTR)
48013430Ssam 		value(PARITY) = defparity;
48113139Sralph 	parity = value(PARITY);
48213139Sralph 	for (i = 0; i < 0200; i++)
48313279Ssam 		partab[i] = evenpartab[i];
48413279Ssam 	if (equal(parity, "even"))
48513279Ssam 		return;
48613139Sralph 	if (equal(parity, "odd")) {
48713139Sralph 		for (i = 0; i < 0200; i++)
48813139Sralph 			partab[i] ^= 0200;	/* reverse bit 7 */
48913279Ssam 		return;
49013139Sralph 	}
49113279Ssam 	if (equal(parity, "none") || equal(parity, "zero")) {
49213139Sralph 		for (i = 0; i < 0200; i++)
49313139Sralph 			partab[i] &= ~0200;	/* turn off bit 7 */
49413279Ssam 		return;
49513139Sralph 	}
49613279Ssam 	if (equal(parity, "one")) {
49713139Sralph 		for (i = 0; i < 0200; i++)
49813139Sralph 			partab[i] |= 0200;	/* turn on bit 7 */
49913279Ssam 		return;
50013139Sralph 	}
50113279Ssam 	fprintf(stderr, "%s: unknown parity value\n", PA);
50213279Ssam 	fflush(stderr);
50313139Sralph }
504