xref: /csrg-svn/usr.bin/tip/tip.c (revision 4146)
1*4146Ssam /*	tip.c	4.7	81/08/16	*/
23696Sroot /*
33696Sroot  * tip - Unix link to other systems
43696Sroot  *  tip [-v] [-speed] system-name
53696Sroot  *
63696Sroot  * Uses remote file for system descriptions.
73696Sroot  * Current commands (escapes):
83696Sroot  *
93696Sroot  *	~!	fork a shell on the local machine
103696Sroot  *	~c	change working directory on local machine
113696Sroot  *	~^D	exit tip
123696Sroot  *	~<	fetch file from remote system
133696Sroot  *	~>	send file to remote system
143696Sroot  *	~t	take a file from a remote UNIX (uses cat & echo)
153696Sroot  *	~p	send a file to a remote UNIX (uses cat)
163696Sroot  *	~|	fetch file from remote system and pipe it to
173696Sroot  *		 a local process
183696Sroot  *	~%	fork and wait for a program which inherits file
193696Sroot  *		 descriptors 3 & 4 attached to the remote machine
203696Sroot  *		 (optional by CONNECT define)
213696Sroot  *	~s	set or show variable
223696Sroot  *	~?	give a help summary
233696Sroot  *
243696Sroot  * Samuel J. Leffler	1-18-81
253696Sroot  *
263696Sroot  * sjl			2-11-81
273696Sroot  * add auto-dial stuff for the BIZCOMP
283696Sroot  *
293696Sroot  * sjl			2-14-81
303696Sroot  * cleaned up auto-dialer stuff and added variables
313696Sroot  *
323696Sroot  * sjl			2-19-81
333696Sroot  * handle quit and interrupt during calls
343696Sroot  *
353696Sroot  * sjl			3-8-81
363696Sroot  * made to pass lint
373696Sroot  *
383696Sroot  * sjl			4-11-81
393696Sroot  * mods to handle both FIOCAPACITY and FIONREAD in biz.c
403696Sroot  *
413696Sroot  * sjl			4-17-81
423696Sroot  * added take and put, made piping stuff work
433696Sroot  * honor uucp locks
443696Sroot  * rewrite remote file stuff for DN-11 like acu's and just to clean
453696Sroot  *   it up
463898Ssam  *
473898Ssam  * sjl			6-16-81
483898Ssam  * real working setup for DN-11's
493696Sroot  */
503696Sroot 
513696Sroot #include "tip.h"
523696Sroot 
533696Sroot /*
543696Sroot  * Baud rate mapping table
553696Sroot  */
563696Sroot int bauds[] = {
573696Sroot 	0, 50, 75, 110, 134, 150, 200, 300, 600,
583696Sroot 	1200, 1800, 2400, 4800, 9600, 19200, -1
593696Sroot };
603696Sroot 
614004Ssam #ifdef VMUNIX
624004Ssam int	disc = OTTYDISC;		/* tip normally runs this way */
634004Ssam #endif
644004Ssam 
653696Sroot int	intprompt();
663696Sroot int	timeout();
673696Sroot static int cleanup();
683696Sroot 
693696Sroot main(argc, argv)
703696Sroot char *argv[];
713696Sroot {
723696Sroot 	char *system = NOSTR;
733696Sroot 	register int i;
743696Sroot 	char *p;
753696Sroot 
763696Sroot 	if (argc > 4) {
773696Sroot 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
783696Sroot 		exit(1);
793696Sroot 	}
803696Sroot 	if (!isatty(0)) {
813696Sroot 		fprintf(stderr, "tip: must be interactive\n");
823696Sroot 		exit(1);
833696Sroot 	}
843696Sroot 	if (argc > 1 && argv[argc-1][0] != '-')
853696Sroot 		system = argv[argc-1];		/* always last item */
863696Sroot 	signal(SIGINT, cleanup);
873696Sroot 	signal(SIGQUIT, cleanup);
883696Sroot 	signal(SIGHUP, cleanup);
893696Sroot 	signal(SIGTERM, cleanup);
903898Ssam 
913696Sroot 	if ((i = hunt(system)) == 0) {
923696Sroot 		printf("all ports busy\n");
933696Sroot 		exit(3);
943696Sroot 	}
953696Sroot 	if (i == -1) {
963696Sroot 		printf("link down\n");
973696Sroot 		exit(3);
983696Sroot 	}
993719Ssam 	setbuf(stdout, NULL);
1003696Sroot 	loginit();
1013696Sroot 	/*
1023696Sroot 	 * Now that we have the logfile and the ACU open
1033696Sroot 	 *  return to the real uid and gid.  These things will
1043696Sroot 	 *  be closed on exit.  Note that we can't run as root,
1053696Sroot 	 *  because locking mechanism on the tty and the accounting
1063696Sroot 	 *  will be bypassed.
1073696Sroot 	 */
1083696Sroot 	setuid(getuid());
1093696Sroot 	setgid(getgid());
1103696Sroot 	for (i = 1; i < argc-1; i++)
1113696Sroot 		if (equal(argv[i], "-v"))
1123696Sroot 			vflag++;
1133696Sroot 	/*
1143696Sroot 	 * Kludge, their's no easy way to get the initialization
1153696Sroot 	 *   in the right order, so force it here
1163696Sroot 	 */
1173696Sroot 	if ((PH = getenv("PHONES")) == NOSTR)
1183696Sroot 		PH = "/etc/phones";
1193696Sroot 	vinit();				/* init variables */
1203696Sroot 	for (i = 1; i < argc-1; i++)
1213696Sroot 		if (argv[i][0] == '-' && argv[i][1] != 'v') {
1223696Sroot 			if (isnum(argv[i][1]))
1233696Sroot 				number(value(BAUDRATE)) = atoi(&argv[i][1]);
1243696Sroot 			else
1253696Sroot 				printf("%s: unknown option\n", argv[i]);
1263696Sroot 		}
1274004Ssam 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
1283696Sroot 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
1293696Sroot 		delock(uucplock);
1303696Sroot 		exit(3);
1313696Sroot 	}
1323898Ssam 
1334004Ssam 	/*
1344004Ssam 	 * Hardwired connections require the
1354004Ssam 	 *  line speed set before they make any transmissions
1364004Ssam 	 *  (this is particularly true of things like a DF03-AC)
1374004Ssam 	 */
1384004Ssam 	if (HW)
1394004Ssam 		ttysetup(i);
1403898Ssam 	if (p = connect()) {
1413898Ssam 		printf("\07%s\n[EOT]\n", p);
1423898Ssam 		delock(uucplock);
1433898Ssam 		exit(1);
1443898Ssam 	}
1454004Ssam 	if (!HW)
1464004Ssam 		ttysetup(i);
1474004Ssam 
1483696Sroot 	/*
1494004Ssam 	 * Set up local tty state
1503696Sroot 	 */
1514004Ssam 	ioctl(0, TIOCGETP, (char *)&defarg);
1524004Ssam 	ioctl(0, TIOCGETC, (char *)&defchars);
1534013Ssam #ifdef VMUNIX
1544004Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1554013Ssam #endif
1563696Sroot 	arg = defarg;
1573696Sroot 	arg.sg_flags = ANYP | CBREAK;
1583696Sroot 	tchars = defchars;
1593696Sroot 	tchars.t_intrc = tchars.t_quitc = -1;
1603696Sroot 	raw();
1614004Ssam 
1623696Sroot 	pipe(fildes); pipe(repdes);
1633696Sroot 	signal(SIGALRM, timeout);
1643898Ssam 
1653898Ssam 	/*
1663898Ssam 	 * Everything's set up now:
1673898Ssam 	 *	connection established (hardwired or diaulup)
1683898Ssam 	 *	line conditioned (baud rate, mode, etc.)
1693898Ssam 	 *	internal data structures (variables)
1703898Ssam 	 * so, fork one process for local side and one for remote.
1713898Ssam 	 */
1723898Ssam 	write(1, "\07connected\r\n", 12);
1733696Sroot 	if (pid = fork())
1743696Sroot 		tipin();
1753696Sroot 	else
1763696Sroot 		tipout();
1773696Sroot 	/*NOTREACHED*/
1783696Sroot }
1793696Sroot 
1803696Sroot static
1813696Sroot cleanup()
1823696Sroot {
1833696Sroot 	delock(uucplock);
1843898Ssam #ifdef VMUNIX
1853898Ssam 	if (odisc)
1863898Ssam 		ioctl(0, TIOCSETD, (char *)&odisc);
1873898Ssam #endif
1883696Sroot 	exit(0);
1893696Sroot }
1903696Sroot 
1913696Sroot /*
1923696Sroot  * put the controlling keyboard into raw mode
1933696Sroot  */
1943696Sroot raw()
1953696Sroot {
1963696Sroot 	ioctl(0, TIOCSETP, &arg);
1973696Sroot 	ioctl(0, TIOCSETC, &tchars);
1984004Ssam #ifdef VMUNIX
1994004Ssam 	ioctl(0, TIOCSETD, (char *)&disc);
2004004Ssam #endif
2013696Sroot }
2023696Sroot 
2033696Sroot 
2043696Sroot /*
2053696Sroot  * return keyboard to normal mode
2063696Sroot  */
2073696Sroot unraw()
2083696Sroot {
2094004Ssam #ifdef VMUNIX
2104004Ssam 	ioctl(0, TIOCSETD, (char *)&odisc);
2114004Ssam #endif
2124004Ssam 	ioctl(0, TIOCSETP, (char *)&defarg);
2134004Ssam 	ioctl(0, TIOCSETC, (char *)&defchars);
2143696Sroot }
2153696Sroot 
2163696Sroot /*
2173696Sroot  * Print string ``s'', then read a string
2183696Sroot  *  in from the terminal.  Handles signals & allows use of
2193696Sroot  *  normal erase and kill characters.
2203696Sroot  */
2213696Sroot prompt(s, p)
2223696Sroot 	char *s;
2233696Sroot 	register char *p;
2243696Sroot {
2253696Sroot 	register char *b = p;
2263696Sroot 
2273696Sroot 	stoprompt = 0;
2283696Sroot 	signal(SIGINT, intprompt);
2293696Sroot 	signal(SIGQUIT, SIG_IGN);
2303696Sroot 	unraw();
2313696Sroot 	printf("%s", s);
2323696Sroot 	while ((*p = getchar()) != EOF && *p != '\n') {
2333696Sroot 		if (stoprompt)
2343696Sroot 			goto pbreak;
2353696Sroot 		p++;
2363696Sroot 	}
2373696Sroot 	*p = '\0';
2383696Sroot pbreak:
2393696Sroot 	raw();
2403696Sroot 	signal(SIGINT, SIG_DFL);
2413696Sroot 	signal(SIGQUIT,SIG_DFL);
2423696Sroot 	return(stoprompt || p == b);
2433696Sroot }
2443696Sroot 
2453696Sroot /*
2463696Sroot  * Interrupt service routine during prompting
2473696Sroot  */
2483696Sroot intprompt()
2493696Sroot {
2503696Sroot 	signal(SIGINT, SIG_IGN);
2513696Sroot 	stoprompt = 1;
2523696Sroot 	printf("\r\n");
2533696Sroot }
2543696Sroot 
2553696Sroot /*
2563696Sroot  * ****TIPIN   TIPIN****
2573696Sroot  */
2583696Sroot tipin()
2593696Sroot {
2603696Sroot 	char gch, bol = 1;
2613696Sroot 
2623796Ssam 	/*
2633796Ssam 	 * Kinda klugey here...
2643796Ssam 	 *   check for scripting being turned on from the .tiprc file,
2653796Ssam 	 *   but be careful about just using setscript(), as we may
2663796Ssam 	 *   send a SIGEMT before tipout has a chance to set up catching
2673796Ssam 	 *   it; so wait a second, then setscript()
2683796Ssam 	 */
2693796Ssam 	if (boolean(value(SCRIPT))) {
2703796Ssam 		sleep(1);
2713796Ssam 		setscript();
2723796Ssam 	}
2733796Ssam 
2743696Sroot 	while (1) {
2753696Sroot 		gch = getchar()&0177;
2763696Sroot 		if ((gch == character(value(ESCAPE))) && bol) {
2773696Sroot 			if (!(gch = escape()))
2783696Sroot 				continue;
2793696Sroot 		} else if (gch == character(value(RAISECHAR))) {
2803696Sroot 			boolean(value(RAISE)) = !boolean(value(RAISE));
2813696Sroot 			printf("%s", ctrl(character(value(RAISECHAR))));
2823696Sroot 			continue;
2833696Sroot 		} else if (gch == '\r') {
2843696Sroot 			bol = 1;
2853696Sroot 			write(FD, &gch, 1);
2863696Sroot 			continue;
2873696Sroot 		} else if (gch == character(value(FORCE))) {
2883696Sroot 			printf("%s", ctrl(character(value(FORCE))));
2893696Sroot 			gch = getchar()&0177;
2903696Sroot 		}
2913696Sroot 		bol = any(gch, value(EOL));
2923696Sroot 		if (boolean(value(RAISE)) && islower(gch))
2933696Sroot 			toupper(gch);
2943696Sroot 		write(FD, &gch, 1);
2953696Sroot 	}
2963696Sroot }
2973696Sroot 
2983696Sroot /*
2993696Sroot  * Escape handler --
3003696Sroot  *  called on recognition of ``escapec'' at the beginning of a line
3013696Sroot  */
3023696Sroot escape()
3033696Sroot {
3043696Sroot 	register char gch;
3053696Sroot 	register esctable_t *p;
3063696Sroot 	char c = character(value(ESCAPE));
3073696Sroot 	extern esctable_t etable[];
3083696Sroot 
3093696Sroot 	gch = (getchar()&0177);
3103696Sroot 	for (p = etable; p->e_char; p++)
3113696Sroot 		if (p->e_char == gch) {
3123696Sroot 			if ((p->e_flags&PRIV) && getuid())
3133696Sroot 				continue;
3143696Sroot 			printf("%s", ctrl(c));
3153696Sroot 			(*p->e_func)(gch);
3163696Sroot 			return(0);
3173696Sroot 		}
318*4146Ssam 	/* ESCAPE ESCAPE forces ESCAPE */
319*4146Ssam 	if (c != gch)
320*4146Ssam 		write(FD, &c, 1);
3213696Sroot 	return(gch);
3223696Sroot }
3233696Sroot 
3243696Sroot speed(n)
3253696Sroot {
3263696Sroot 	register int *p;
3273696Sroot 
3283696Sroot 	for (p = bauds; *p != -1;  p++)
3293696Sroot 		if (*p == n)
3303696Sroot 			return(p-bauds);
3313696Sroot 	return(NULL);
3323696Sroot }
3333696Sroot 
3343696Sroot any(c, p)
3353696Sroot 	register char c, *p;
3363696Sroot {
3373696Sroot 	while (*p)
3383696Sroot 		if (*p++ == c)
3393696Sroot 			return(1);
3403696Sroot 	return(0);
3413696Sroot }
3423696Sroot 
3433696Sroot size(s)
3443696Sroot 	register char	*s;
3453696Sroot {
3463696Sroot 	register int	i = 0;
3473696Sroot 
3483696Sroot 	while (*s++) i++;
3493696Sroot 	return(i);
3503696Sroot }
3513696Sroot 
3523696Sroot char *
3533696Sroot interp(s)
3543696Sroot 	register char *s;
3553696Sroot {
3563696Sroot 	static char buf[256];
3573696Sroot 	register char *p = buf, c, *q;
3583696Sroot 
3593696Sroot 	while (c = *s++) {
3603696Sroot 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
3613696Sroot 			if (*q++ == c) {
3623696Sroot 				*p++ = '\\'; *p++ = *q;
3633696Sroot 				goto next;
3643696Sroot 			}
3653696Sroot 		if (c < 040) {
3663696Sroot 			*p++ = '^'; *p++ = c + 'A'-1;
3673696Sroot 		} else if (c == 0177) {
3683696Sroot 			*p++ = '^'; *p++ = '?';
3693696Sroot 		} else
3703696Sroot 			*p++ = c;
3713696Sroot 	next:
3723696Sroot 		;
3733696Sroot 	}
3743696Sroot 	*p = '\0';
3753696Sroot 	return(buf);
3763696Sroot }
3773696Sroot 
3783696Sroot char *
3793696Sroot ctrl(c)
3803696Sroot 	char c;
3813696Sroot {
3823696Sroot 	static char s[3];
3833696Sroot 
3843696Sroot 	if (c < 040 || c == 0177) {
3853696Sroot 		s[0] = '^';
3863696Sroot 		s[1] = c == 0177 ? '?' : c+'A'-1;
3873696Sroot 		s[2] = '\0';
3883696Sroot 	} else {
3893696Sroot 		s[0] = c;
3903696Sroot 		s[1] = '\0';
3913696Sroot 	}
3923696Sroot 	return(s);
3933696Sroot }
3943696Sroot 
3953696Sroot /*
3963696Sroot  * Help command
3973696Sroot  */
3983696Sroot help(c)
3993696Sroot 	char c;
4003696Sroot {
4013696Sroot 	register esctable_t *p;
4023696Sroot 	extern esctable_t etable[];
4033696Sroot 
4043696Sroot 	printf("%c\r\n", c);
4053696Sroot 	for (p = etable; p->e_char; p++) {
4063696Sroot 		if ((p->e_flags&PRIV) && getuid())
4073696Sroot 			continue;
4083696Sroot 		printf("%2s", ctrl(character(value(ESCAPE))));
4093696Sroot 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
4103696Sroot 			p->e_flags&EXP ? '*': ' ', p->e_help);
4113696Sroot 	}
4123696Sroot }
4134004Ssam 
4144004Ssam /*
4154004Ssam  * Set up the "remote" tty's state
4164004Ssam  */
4174004Ssam static
4184004Ssam ttysetup(speed)
4194004Ssam {
4204004Ssam #ifdef VMUNIX
4214004Ssam 	unsigned bits = LDECCTQ;
4224004Ssam #endif
4234004Ssam 
4244004Ssam 	arg.sg_ispeed = arg.sg_ospeed = speed;
4254004Ssam 	arg.sg_flags = TANDEM|RAW;
4264004Ssam 	ioctl(FD, TIOCSETP, (char *)&arg);
4274004Ssam #ifdef VMUNIX
4284004Ssam 	ioctl(FD, TIOCLBIS, (char *)&bits);
4294004Ssam #endif
4304004Ssam }
431