xref: /original-bsd/usr.bin/tip/tip.c (revision 1f3a482a)
1 /*	tip.c	4.4	81/06/16	*/
2 /*
3  * tip - Unix link to other systems
4  *  tip [-v] [-speed] system-name
5  *
6  * Uses remote file for system descriptions.
7  * Current commands (escapes):
8  *
9  *	~!	fork a shell on the local machine
10  *	~c	change working directory on local machine
11  *	~^D	exit tip
12  *	~<	fetch file from remote system
13  *	~>	send file to remote system
14  *	~t	take a file from a remote UNIX (uses cat & echo)
15  *	~p	send a file to a remote UNIX (uses cat)
16  *	~|	fetch file from remote system and pipe it to
17  *		 a local process
18  *	~%	fork and wait for a program which inherits file
19  *		 descriptors 3 & 4 attached to the remote machine
20  *		 (optional by CONNECT define)
21  *	~s	set or show variable
22  *	~?	give a help summary
23  *
24  * Samuel J. Leffler	1-18-81
25  *
26  * sjl			2-11-81
27  * add auto-dial stuff for the BIZCOMP
28  *
29  * sjl			2-14-81
30  * cleaned up auto-dialer stuff and added variables
31  *
32  * sjl			2-19-81
33  * handle quit and interrupt during calls
34  *
35  * sjl			3-8-81
36  * made to pass lint
37  *
38  * sjl			4-11-81
39  * mods to handle both FIOCAPACITY and FIONREAD in biz.c
40  *
41  * sjl			4-17-81
42  * added take and put, made piping stuff work
43  * honor uucp locks
44  * rewrite remote file stuff for DN-11 like acu's and just to clean
45  *   it up
46  *
47  * sjl			6-16-81
48  * real working setup for DN-11's
49  */
50 
51 #include "tip.h"
52 
53 /*
54  * Baud rate mapping table
55  */
56 int bauds[] = {
57 	0, 50, 75, 110, 134, 150, 200, 300, 600,
58 	1200, 1800, 2400, 4800, 9600, 19200, -1
59 };
60 
61 int	intprompt();
62 int	timeout();
63 static int cleanup();
64 
65 main(argc, argv)
66 char *argv[];
67 {
68 	char *system = NOSTR;
69 	register int i;
70 #ifdef VMUNIX
71 	int disc;
72 #endif
73 	char *p;
74 
75 	if (argc > 4) {
76 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
77 		exit(1);
78 	}
79 	if (!isatty(0)) {
80 		fprintf(stderr, "tip: must be interactive\n");
81 		exit(1);
82 	}
83 	if (argc > 1 && argv[argc-1][0] != '-')
84 		system = argv[argc-1];		/* always last item */
85 	signal(SIGINT, cleanup);
86 	signal(SIGQUIT, cleanup);
87 	signal(SIGHUP, cleanup);
88 	signal(SIGTERM, cleanup);
89 
90 	if ((i = hunt(system)) == 0) {
91 		printf("all ports busy\n");
92 		exit(3);
93 	}
94 	if (i == -1) {
95 		printf("link down\n");
96 		exit(3);
97 	}
98 	setbuf(stdout, NULL);
99 	loginit();
100 	/*
101 	 * Now that we have the logfile and the ACU open
102 	 *  return to the real uid and gid.  These things will
103 	 *  be closed on exit.  Note that we can't run as root,
104 	 *  because locking mechanism on the tty and the accounting
105 	 *  will be bypassed.
106 	 */
107 	setuid(getuid());
108 	setgid(getgid());
109 	for (i = 1; i < argc-1; i++)
110 		if (equal(argv[i], "-v"))
111 			vflag++;
112 	/*
113 	 * Kludge, their's no easy way to get the initialization
114 	 *   in the right order, so force it here
115 	 */
116 	if ((PH = getenv("PHONES")) == NOSTR)
117 		PH = "/etc/phones";
118 	vinit();				/* init variables */
119 	for (i = 1; i < argc-1; i++)
120 		if (argv[i][0] == '-' && argv[i][1] != 'v') {
121 			if (isnum(argv[i][1]))
122 				number(value(BAUDRATE)) = atoi(&argv[i][1]);
123 			else
124 				printf("%s: unknown option\n", argv[i]);
125 		}
126 	if ((arg.sg_ispeed = speed(number(value(BAUDRATE)))) == NULL) {
127 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
128 		delock(uucplock);
129 		exit(3);
130 	}
131 
132 	if (p = connect()) {
133 		printf("\07%s\n[EOT]\n", p);
134 		delock(uucplock);
135 		exit(1);
136 	}
137 	arg.sg_ospeed = arg.sg_ispeed;
138 	/*
139 	 * NOTE that remote side runs in TANDEM mode,
140 	 *  if the host doesn't honor X-ON/X-OFF with default
141 	 *  start/stop chars, the remote description must be
142 	 *  extended and tchars will have to be set up here.
143 	 * If the host doesn't honor TANDEM mode, then watch
144 	 *  out, as you'll get garbage.
145 	 */
146 	arg.sg_flags = RAW | TANDEM;
147 	ioctl(FD, TIOCSETP, &arg);
148 
149 	ioctl(0, TIOCGETP, &defarg);	/* store initial status */
150 	ioctl(0, TIOCGETC, &defchars);
151 	arg = defarg;
152 	arg.sg_flags = ANYP | CBREAK;
153 	tchars = defchars;
154 	tchars.t_intrc = tchars.t_quitc = -1;
155 	raw();
156 #ifdef VMUNIX
157 	ioctl(0, TIOCGETD, (char *)&odisc);
158 	disc = OTTYDISC;
159 	ioctl(0, TIOCSETD, (char *)&disc);
160 #endif
161 	pipe(fildes); pipe(repdes);
162 	signal(SIGALRM, timeout);
163 
164 	/*
165 	 * Everything's set up now:
166 	 *	connection established (hardwired or diaulup)
167 	 *	line conditioned (baud rate, mode, etc.)
168 	 *	internal data structures (variables)
169 	 * so, fork one process for local side and one for remote.
170 	 */
171 	write(1, "\07connected\r\n", 12);
172 	if (pid = fork())
173 		tipin();
174 	else
175 		tipout();
176 	/*NOTREACHED*/
177 }
178 
179 static
180 cleanup()
181 {
182 	delock(uucplock);
183 #ifdef VMUNIX
184 	if (odisc)
185 		ioctl(0, TIOCSETD, (char *)&odisc);
186 #endif
187 	exit(0);
188 }
189 
190 /*
191  * put the controlling keyboard into raw mode
192  */
193 raw()
194 {
195 	ioctl(0, TIOCSETP, &arg);
196 	ioctl(0, TIOCSETC, &tchars);
197 }
198 
199 
200 /*
201  * return keyboard to normal mode
202  */
203 unraw()
204 {
205 	ioctl(0, TIOCSETP, &defarg);
206 	ioctl(0, TIOCSETC, &defchars);
207 }
208 
209 /*
210  * Print string ``s'', then read a string
211  *  in from the terminal.  Handles signals & allows use of
212  *  normal erase and kill characters.
213  */
214 prompt(s, p)
215 	char *s;
216 	register char *p;
217 {
218 	register char *b = p;
219 
220 	stoprompt = 0;
221 	signal(SIGINT, intprompt);
222 	signal(SIGQUIT, SIG_IGN);
223 	unraw();
224 	printf("%s", s);
225 	while ((*p = getchar()) != EOF && *p != '\n') {
226 		if (stoprompt)
227 			goto pbreak;
228 		p++;
229 	}
230 	*p = '\0';
231 pbreak:
232 	raw();
233 	signal(SIGINT, SIG_DFL);
234 	signal(SIGQUIT,SIG_DFL);
235 	return(stoprompt || p == b);
236 }
237 
238 /*
239  * Interrupt service routine during prompting
240  */
241 intprompt()
242 {
243 	signal(SIGINT, SIG_IGN);
244 	stoprompt = 1;
245 	printf("\r\n");
246 }
247 
248 /*
249  * ****TIPIN   TIPIN****
250  */
251 tipin()
252 {
253 	char gch, bol = 1;
254 
255 	/*
256 	 * Kinda klugey here...
257 	 *   check for scripting being turned on from the .tiprc file,
258 	 *   but be careful about just using setscript(), as we may
259 	 *   send a SIGEMT before tipout has a chance to set up catching
260 	 *   it; so wait a second, then setscript()
261 	 */
262 	if (boolean(value(SCRIPT))) {
263 		sleep(1);
264 		setscript();
265 	}
266 
267 	while (1) {
268 		gch = getchar()&0177;
269 		if ((gch == character(value(ESCAPE))) && bol) {
270 			if (!(gch = escape()))
271 				continue;
272 		} else if (gch == character(value(RAISECHAR))) {
273 			boolean(value(RAISE)) = !boolean(value(RAISE));
274 			printf("%s", ctrl(character(value(RAISECHAR))));
275 			continue;
276 		} else if (gch == '\r') {
277 			bol = 1;
278 			write(FD, &gch, 1);
279 			continue;
280 		} else if (gch == character(value(FORCE))) {
281 			printf("%s", ctrl(character(value(FORCE))));
282 			gch = getchar()&0177;
283 		}
284 		bol = any(gch, value(EOL));
285 		if (boolean(value(RAISE)) && islower(gch))
286 			toupper(gch);
287 		write(FD, &gch, 1);
288 	}
289 }
290 
291 /*
292  * Escape handler --
293  *  called on recognition of ``escapec'' at the beginning of a line
294  */
295 escape()
296 {
297 	register char gch;
298 	register esctable_t *p;
299 	char c = character(value(ESCAPE));
300 	extern esctable_t etable[];
301 
302 	gch = (getchar()&0177);
303 	for (p = etable; p->e_char; p++)
304 		if (p->e_char == gch) {
305 			if ((p->e_flags&PRIV) && getuid())
306 				continue;
307 			printf("%s", ctrl(c));
308 			(*p->e_func)(gch);
309 			return(0);
310 		}
311 
312 	write(FD, &c, 1);
313 	return(gch);
314 }
315 
316 speed(n)
317 {
318 	register int *p;
319 
320 	for (p = bauds; *p != -1;  p++)
321 		if (*p == n)
322 			return(p-bauds);
323 	return(NULL);
324 }
325 
326 any(c, p)
327 	register char c, *p;
328 {
329 	while (*p)
330 		if (*p++ == c)
331 			return(1);
332 	return(0);
333 }
334 
335 size(s)
336 	register char	*s;
337 {
338 	register int	i = 0;
339 
340 	while (*s++) i++;
341 	return(i);
342 }
343 
344 char *
345 interp(s)
346 	register char *s;
347 {
348 	static char buf[256];
349 	register char *p = buf, c, *q;
350 
351 	while (c = *s++) {
352 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
353 			if (*q++ == c) {
354 				*p++ = '\\'; *p++ = *q;
355 				goto next;
356 			}
357 		if (c < 040) {
358 			*p++ = '^'; *p++ = c + 'A'-1;
359 		} else if (c == 0177) {
360 			*p++ = '^'; *p++ = '?';
361 		} else
362 			*p++ = c;
363 	next:
364 		;
365 	}
366 	*p = '\0';
367 	return(buf);
368 }
369 
370 char *
371 ctrl(c)
372 	char c;
373 {
374 	static char s[3];
375 
376 	if (c < 040 || c == 0177) {
377 		s[0] = '^';
378 		s[1] = c == 0177 ? '?' : c+'A'-1;
379 		s[2] = '\0';
380 	} else {
381 		s[0] = c;
382 		s[1] = '\0';
383 	}
384 	return(s);
385 }
386 
387 /*
388  * Help command
389  */
390 help(c)
391 	char c;
392 {
393 	register esctable_t *p;
394 	extern esctable_t etable[];
395 
396 	printf("%c\r\n", c);
397 	for (p = etable; p->e_char; p++) {
398 		if ((p->e_flags&PRIV) && getuid())
399 			continue;
400 		printf("%2s", ctrl(character(value(ESCAPE))));
401 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
402 			p->e_flags&EXP ? '*': ' ', p->e_help);
403 	}
404 }
405