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