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