xref: /original-bsd/usr.bin/tip/tip.c (revision de38840f)
1 /*	tip.c	4.6	81/07/13	*/
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 #ifdef VMUNIX
62 int	disc = OTTYDISC;		/* tip normally runs this way */
63 #endif
64 
65 int	intprompt();
66 int	timeout();
67 static int cleanup();
68 
69 main(argc, argv)
70 char *argv[];
71 {
72 	char *system = NOSTR;
73 	register int i;
74 	char *p;
75 
76 	if (argc > 4) {
77 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
78 		exit(1);
79 	}
80 	if (!isatty(0)) {
81 		fprintf(stderr, "tip: must be interactive\n");
82 		exit(1);
83 	}
84 	if (argc > 1 && argv[argc-1][0] != '-')
85 		system = argv[argc-1];		/* always last item */
86 	signal(SIGINT, cleanup);
87 	signal(SIGQUIT, cleanup);
88 	signal(SIGHUP, cleanup);
89 	signal(SIGTERM, cleanup);
90 
91 	if ((i = hunt(system)) == 0) {
92 		printf("all ports busy\n");
93 		exit(3);
94 	}
95 	if (i == -1) {
96 		printf("link down\n");
97 		exit(3);
98 	}
99 	setbuf(stdout, NULL);
100 	loginit();
101 	/*
102 	 * Now that we have the logfile and the ACU open
103 	 *  return to the real uid and gid.  These things will
104 	 *  be closed on exit.  Note that we can't run as root,
105 	 *  because locking mechanism on the tty and the accounting
106 	 *  will be bypassed.
107 	 */
108 	setuid(getuid());
109 	setgid(getgid());
110 	for (i = 1; i < argc-1; i++)
111 		if (equal(argv[i], "-v"))
112 			vflag++;
113 	/*
114 	 * Kludge, their's no easy way to get the initialization
115 	 *   in the right order, so force it here
116 	 */
117 	if ((PH = getenv("PHONES")) == NOSTR)
118 		PH = "/etc/phones";
119 	vinit();				/* init variables */
120 	for (i = 1; i < argc-1; i++)
121 		if (argv[i][0] == '-' && argv[i][1] != 'v') {
122 			if (isnum(argv[i][1]))
123 				number(value(BAUDRATE)) = atoi(&argv[i][1]);
124 			else
125 				printf("%s: unknown option\n", argv[i]);
126 		}
127 	if ((i = speed(number(value(BAUDRATE)))) == NULL) {
128 		printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
129 		delock(uucplock);
130 		exit(3);
131 	}
132 
133 	/*
134 	 * Hardwired connections require the
135 	 *  line speed set before they make any transmissions
136 	 *  (this is particularly true of things like a DF03-AC)
137 	 */
138 	if (HW)
139 		ttysetup(i);
140 	if (p = connect()) {
141 		printf("\07%s\n[EOT]\n", p);
142 		delock(uucplock);
143 		exit(1);
144 	}
145 	if (!HW)
146 		ttysetup(i);
147 
148 	/*
149 	 * Set up local tty state
150 	 */
151 	ioctl(0, TIOCGETP, (char *)&defarg);
152 	ioctl(0, TIOCGETC, (char *)&defchars);
153 #ifdef VMUNIX
154 	ioctl(0, TIOCGETD, (char *)&odisc);
155 #endif
156 	arg = defarg;
157 	arg.sg_flags = ANYP | CBREAK;
158 	tchars = defchars;
159 	tchars.t_intrc = tchars.t_quitc = -1;
160 	raw();
161 
162 	pipe(fildes); pipe(repdes);
163 	signal(SIGALRM, timeout);
164 
165 	/*
166 	 * Everything's set up now:
167 	 *	connection established (hardwired or diaulup)
168 	 *	line conditioned (baud rate, mode, etc.)
169 	 *	internal data structures (variables)
170 	 * so, fork one process for local side and one for remote.
171 	 */
172 	write(1, "\07connected\r\n", 12);
173 	if (pid = fork())
174 		tipin();
175 	else
176 		tipout();
177 	/*NOTREACHED*/
178 }
179 
180 static
181 cleanup()
182 {
183 	delock(uucplock);
184 #ifdef VMUNIX
185 	if (odisc)
186 		ioctl(0, TIOCSETD, (char *)&odisc);
187 #endif
188 	exit(0);
189 }
190 
191 /*
192  * put the controlling keyboard into raw mode
193  */
194 raw()
195 {
196 	ioctl(0, TIOCSETP, &arg);
197 	ioctl(0, TIOCSETC, &tchars);
198 #ifdef VMUNIX
199 	ioctl(0, TIOCSETD, (char *)&disc);
200 #endif
201 }
202 
203 
204 /*
205  * return keyboard to normal mode
206  */
207 unraw()
208 {
209 #ifdef VMUNIX
210 	ioctl(0, TIOCSETD, (char *)&odisc);
211 #endif
212 	ioctl(0, TIOCSETP, (char *)&defarg);
213 	ioctl(0, TIOCSETC, (char *)&defchars);
214 }
215 
216 /*
217  * Print string ``s'', then read a string
218  *  in from the terminal.  Handles signals & allows use of
219  *  normal erase and kill characters.
220  */
221 prompt(s, p)
222 	char *s;
223 	register char *p;
224 {
225 	register char *b = p;
226 
227 	stoprompt = 0;
228 	signal(SIGINT, intprompt);
229 	signal(SIGQUIT, SIG_IGN);
230 	unraw();
231 	printf("%s", s);
232 	while ((*p = getchar()) != EOF && *p != '\n') {
233 		if (stoprompt)
234 			goto pbreak;
235 		p++;
236 	}
237 	*p = '\0';
238 pbreak:
239 	raw();
240 	signal(SIGINT, SIG_DFL);
241 	signal(SIGQUIT,SIG_DFL);
242 	return(stoprompt || p == b);
243 }
244 
245 /*
246  * Interrupt service routine during prompting
247  */
248 intprompt()
249 {
250 	signal(SIGINT, SIG_IGN);
251 	stoprompt = 1;
252 	printf("\r\n");
253 }
254 
255 /*
256  * ****TIPIN   TIPIN****
257  */
258 tipin()
259 {
260 	char gch, bol = 1;
261 
262 	/*
263 	 * Kinda klugey here...
264 	 *   check for scripting being turned on from the .tiprc file,
265 	 *   but be careful about just using setscript(), as we may
266 	 *   send a SIGEMT before tipout has a chance to set up catching
267 	 *   it; so wait a second, then setscript()
268 	 */
269 	if (boolean(value(SCRIPT))) {
270 		sleep(1);
271 		setscript();
272 	}
273 
274 	while (1) {
275 		gch = getchar()&0177;
276 		if ((gch == character(value(ESCAPE))) && bol) {
277 			if (!(gch = escape()))
278 				continue;
279 		} else if (gch == character(value(RAISECHAR))) {
280 			boolean(value(RAISE)) = !boolean(value(RAISE));
281 			printf("%s", ctrl(character(value(RAISECHAR))));
282 			continue;
283 		} else if (gch == '\r') {
284 			bol = 1;
285 			write(FD, &gch, 1);
286 			continue;
287 		} else if (gch == character(value(FORCE))) {
288 			printf("%s", ctrl(character(value(FORCE))));
289 			gch = getchar()&0177;
290 		}
291 		bol = any(gch, value(EOL));
292 		if (boolean(value(RAISE)) && islower(gch))
293 			toupper(gch);
294 		write(FD, &gch, 1);
295 	}
296 }
297 
298 /*
299  * Escape handler --
300  *  called on recognition of ``escapec'' at the beginning of a line
301  */
302 escape()
303 {
304 	register char gch;
305 	register esctable_t *p;
306 	char c = character(value(ESCAPE));
307 	extern esctable_t etable[];
308 
309 	gch = (getchar()&0177);
310 	for (p = etable; p->e_char; p++)
311 		if (p->e_char == gch) {
312 			if ((p->e_flags&PRIV) && getuid())
313 				continue;
314 			printf("%s", ctrl(c));
315 			(*p->e_func)(gch);
316 			return(0);
317 		}
318 
319 	write(FD, &c, 1);
320 	return(gch);
321 }
322 
323 speed(n)
324 {
325 	register int *p;
326 
327 	for (p = bauds; *p != -1;  p++)
328 		if (*p == n)
329 			return(p-bauds);
330 	return(NULL);
331 }
332 
333 any(c, p)
334 	register char c, *p;
335 {
336 	while (*p)
337 		if (*p++ == c)
338 			return(1);
339 	return(0);
340 }
341 
342 size(s)
343 	register char	*s;
344 {
345 	register int	i = 0;
346 
347 	while (*s++) i++;
348 	return(i);
349 }
350 
351 char *
352 interp(s)
353 	register char *s;
354 {
355 	static char buf[256];
356 	register char *p = buf, c, *q;
357 
358 	while (c = *s++) {
359 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
360 			if (*q++ == c) {
361 				*p++ = '\\'; *p++ = *q;
362 				goto next;
363 			}
364 		if (c < 040) {
365 			*p++ = '^'; *p++ = c + 'A'-1;
366 		} else if (c == 0177) {
367 			*p++ = '^'; *p++ = '?';
368 		} else
369 			*p++ = c;
370 	next:
371 		;
372 	}
373 	*p = '\0';
374 	return(buf);
375 }
376 
377 char *
378 ctrl(c)
379 	char c;
380 {
381 	static char s[3];
382 
383 	if (c < 040 || c == 0177) {
384 		s[0] = '^';
385 		s[1] = c == 0177 ? '?' : c+'A'-1;
386 		s[2] = '\0';
387 	} else {
388 		s[0] = c;
389 		s[1] = '\0';
390 	}
391 	return(s);
392 }
393 
394 /*
395  * Help command
396  */
397 help(c)
398 	char c;
399 {
400 	register esctable_t *p;
401 	extern esctable_t etable[];
402 
403 	printf("%c\r\n", c);
404 	for (p = etable; p->e_char; p++) {
405 		if ((p->e_flags&PRIV) && getuid())
406 			continue;
407 		printf("%2s", ctrl(character(value(ESCAPE))));
408 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
409 			p->e_flags&EXP ? '*': ' ', p->e_help);
410 	}
411 }
412 
413 /*
414  * Set up the "remote" tty's state
415  */
416 static
417 ttysetup(speed)
418 {
419 #ifdef VMUNIX
420 	unsigned bits = LDECCTQ;
421 #endif
422 
423 	arg.sg_ispeed = arg.sg_ospeed = speed;
424 	arg.sg_flags = TANDEM|RAW;
425 	ioctl(FD, TIOCSETP, (char *)&arg);
426 #ifdef VMUNIX
427 	ioctl(FD, TIOCLBIS, (char *)&bits);
428 #endif
429 }
430