xref: /original-bsd/usr.bin/tip/tip.c (revision aba77441)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)tip.c	5.1 (Berkeley) 04/30/85";
15 #endif not lint
16 
17 /*
18  * tip - UNIX link to other systems
19  *  tip [-v] [-speed] system-name
20  * or
21  *  cu phone-number [-s speed] [-l line] [-a acu]
22  */
23 #include "tip.h"
24 
25 /*
26  * Baud rate mapping table
27  */
28 int bauds[] = {
29 	0, 50, 75, 110, 134, 150, 200, 300, 600,
30 	1200, 1800, 2400, 4800, 9600, 19200, -1
31 };
32 
33 int	disc = OTTYDISC;		/* tip normally runs this way */
34 int	intprompt();
35 int	timeout();
36 int	cleanup();
37 char	*sname();
38 extern char *sprintf();
39 
40 main(argc, argv)
41 	char *argv[];
42 {
43 	char *system = NOSTR;
44 	register int i;
45 	register char *p;
46 	char sbuf[12];
47 
48 	if (equal(sname(argv[0]), "cu")) {
49 		cumain(argc, argv);
50 		cumode = 1;
51 		goto cucommon;
52 	}
53 
54 	if (argc > 4) {
55 		fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
56 		exit(1);
57 	}
58 	if (!isatty(0)) {
59 		fprintf(stderr, "tip: must be interactive\n");
60 		exit(1);
61 	}
62 
63 	for (; argc > 1; argv++, argc--) {
64 		if (argv[1][0] != '-')
65 			system = argv[1];
66 		else switch (argv[1][1]) {
67 
68 		case 'v':
69 			vflag++;
70 			break;
71 
72 		case '0': case '1': case '2': case '3': case '4':
73 		case '5': case '6': case '7': case '8': case '9':
74 			BR = atoi(&argv[1][1]);
75 			break;
76 
77 		default:
78 			fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
79 			break;
80 		}
81 	}
82 
83 	if (system == NOSTR)
84 		goto notnumber;
85 	for (p = system; *p; p++)
86 		if (isalpha(*p))
87 			goto notnumber;
88 	PN = system;		/* system name is really a phone number */
89 	system = sprintf(sbuf, "tip%d", BR);
90 
91 notnumber:
92 	signal(SIGINT, cleanup);
93 	signal(SIGQUIT, cleanup);
94 	signal(SIGHUP, cleanup);
95 	signal(SIGTERM, cleanup);
96 
97 	if ((i = hunt(system)) == 0) {
98 		printf("all ports busy\n");
99 		exit(3);
100 	}
101 	if (i == -1) {
102 		printf("link down\n");
103 		delock(uucplock);
104 		exit(3);
105 	}
106 	setbuf(stdout, NULL);
107 	loginit();
108 	/*
109 	 * Now that we have the logfile and the ACU open
110 	 *  return to the real uid and gid.  These things will
111 	 *  be closed on exit.  Note that we can't run as root,
112 	 *  because locking mechanism on the tty and the accounting
113 	 *  will be bypassed.
114 	 */
115 	setgid(getgid());
116 	setuid(getuid());
117 
118 	/*
119 	 * Kludge, their's no easy way to get the initialization
120 	 *   in the right order, so force it here
121 	 */
122 	if ((PH = getenv("PHONES")) == NOSTR)
123 		PH = "/etc/phones";
124 	vinit();				/* init variables */
125 	setparity("even");			/* set the parity table */
126 	if ((i = 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 	/*
133 	 * Hardwired connections require the
134 	 *  line speed set before they make any transmissions
135 	 *  (this is particularly true of things like a DF03-AC)
136 	 */
137 	if (HW)
138 		ttysetup(i);
139 	if (p = connect()) {
140 		printf("\07%s\n[EOT]\n", p);
141 		delock(uucplock);
142 		exit(1);
143 	}
144 	if (!HW)
145 		ttysetup(i);
146 cucommon:
147 	/*
148 	 * From here down the code is shared with
149 	 * the "cu" version of tip.
150 	 */
151 	ioctl(0, TIOCGETP, (char *)&defarg);
152 	ioctl(0, TIOCGETC, (char *)&defchars);
153 	ioctl(0, TIOCGLTC, (char *)&deflchars);
154 	ioctl(0, TIOCGETD, (char *)&odisc);
155 	arg = defarg;
156 	arg.sg_flags = ANYP | CBREAK;
157 	tchars = defchars;
158 	tchars.t_intrc = tchars.t_quitc = -1;
159 	ltchars = deflchars;
160 	ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
161 		= ltchars.t_lnextc = -1;
162 	raw();
163 
164 	pipe(fildes); pipe(repdes);
165 	signal(SIGALRM, timeout);
166 
167 	/*
168 	 * Everything's set up now:
169 	 *	connection established (hardwired or dialup)
170 	 *	line conditioned (baud rate, mode, etc.)
171 	 *	internal data structures (variables)
172 	 * so, fork one process for local side and one for remote.
173 	 */
174 	printf(cumode ? "Connected\r\n" : "\07connected\r\n");
175 	if (pid = fork())
176 		tipin();
177 	else
178 		tipout();
179 	/*NOTREACHED*/
180 }
181 
182 cleanup()
183 {
184 
185 	delock(uucplock);
186 	if (odisc)
187 		ioctl(0, TIOCSETD, (char *)&odisc);
188 	exit(0);
189 }
190 
191 /*
192  * put the controlling keyboard into raw mode
193  */
194 raw()
195 {
196 
197 	ioctl(0, TIOCSETP, &arg);
198 	ioctl(0, TIOCSETC, &tchars);
199 	ioctl(0, TIOCSLTC, &ltchars);
200 	ioctl(0, TIOCSETD, (char *)&disc);
201 }
202 
203 
204 /*
205  * return keyboard to normal mode
206  */
207 unraw()
208 {
209 
210 	ioctl(0, TIOCSETD, (char *)&odisc);
211 	ioctl(0, TIOCSETP, (char *)&defarg);
212 	ioctl(0, TIOCSETC, (char *)&defchars);
213 	ioctl(0, TIOCSLTC, (char *)&deflchars);
214 }
215 
216 static	jmp_buf promptbuf;
217 
218 /*
219  * Print string ``s'', then read a string
220  *  in from the terminal.  Handles signals & allows use of
221  *  normal erase and kill characters.
222  */
223 prompt(s, p)
224 	char *s;
225 	register char *p;
226 {
227 	register char *b = p;
228 	int (*oint)(), (*oquit)();
229 
230 	stoprompt = 0;
231 	oint = signal(SIGINT, intprompt);
232 	oint = signal(SIGQUIT, SIG_IGN);
233 	unraw();
234 	printf("%s", s);
235 	if (setjmp(promptbuf) == 0)
236 		while ((*p = getchar()) != EOF && *p != '\n')
237 			p++;
238 	*p = '\0';
239 
240 	raw();
241 	signal(SIGINT, oint);
242 	signal(SIGQUIT, oint);
243 	return (stoprompt || p == b);
244 }
245 
246 /*
247  * Interrupt service routine during prompting
248  */
249 intprompt()
250 {
251 
252 	signal(SIGINT, SIG_IGN);
253 	stoprompt = 1;
254 	printf("\r\n");
255 	longjmp(promptbuf, 1);
256 }
257 
258 /*
259  * ****TIPIN   TIPIN****
260  */
261 tipin()
262 {
263 	char gch, bol = 1;
264 
265 	/*
266 	 * Kinda klugey here...
267 	 *   check for scripting being turned on from the .tiprc file,
268 	 *   but be careful about just using setscript(), as we may
269 	 *   send a SIGEMT before tipout has a chance to set up catching
270 	 *   it; so wait a second, then setscript()
271 	 */
272 	if (boolean(value(SCRIPT))) {
273 		sleep(1);
274 		setscript();
275 	}
276 
277 	while (1) {
278 		gch = getchar()&0177;
279 		if ((gch == character(value(ESCAPE))) && bol) {
280 			if (!(gch = escape()))
281 				continue;
282 		} else if (!cumode && gch == character(value(RAISECHAR))) {
283 			boolean(value(RAISE)) = !boolean(value(RAISE));
284 			continue;
285 		} else if (gch == '\r') {
286 			bol = 1;
287 			pwrite(FD, &gch, 1);
288 			if (boolean(value(HALFDUPLEX)))
289 				printf("\r\n");
290 			continue;
291 		} else if (!cumode && gch == character(value(FORCE)))
292 			gch = getchar()&0177;
293 		bol = any(gch, value(EOL));
294 		if (boolean(value(RAISE)) && islower(gch))
295 			gch = toupper(gch);
296 		pwrite(FD, &gch, 1);
297 		if (boolean(value(HALFDUPLEX)))
298 			printf("%c", gch);
299 	}
300 }
301 
302 /*
303  * Escape handler --
304  *  called on recognition of ``escapec'' at the beginning of a line
305  */
306 escape()
307 {
308 	register char gch;
309 	register esctable_t *p;
310 	char c = character(value(ESCAPE));
311 	extern esctable_t etable[];
312 
313 	gch = (getchar()&0177);
314 	for (p = etable; p->e_char; p++)
315 		if (p->e_char == gch) {
316 			if ((p->e_flags&PRIV) && getuid())
317 				continue;
318 			printf("%s", ctrl(c));
319 			(*p->e_func)(gch);
320 			return (0);
321 		}
322 	/* ESCAPE ESCAPE forces ESCAPE */
323 	if (c != gch)
324 		pwrite(FD, &c, 1);
325 	return (gch);
326 }
327 
328 speed(n)
329 	int n;
330 {
331 	register int *p;
332 
333 	for (p = bauds; *p != -1;  p++)
334 		if (*p == n)
335 			return (p - bauds);
336 	return (NULL);
337 }
338 
339 any(c, p)
340 	register char c, *p;
341 {
342 	while (p && *p)
343 		if (*p++ == c)
344 			return (1);
345 	return (0);
346 }
347 
348 size(s)
349 	register char	*s;
350 {
351 	register int i = 0;
352 
353 	while (s && *s++)
354 		i++;
355 	return (i);
356 }
357 
358 char *
359 interp(s)
360 	register char *s;
361 {
362 	static char buf[256];
363 	register char *p = buf, c, *q;
364 
365 	while (c = *s++) {
366 		for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
367 			if (*q++ == c) {
368 				*p++ = '\\'; *p++ = *q;
369 				goto next;
370 			}
371 		if (c < 040) {
372 			*p++ = '^'; *p++ = c + 'A'-1;
373 		} else if (c == 0177) {
374 			*p++ = '^'; *p++ = '?';
375 		} else
376 			*p++ = c;
377 	next:
378 		;
379 	}
380 	*p = '\0';
381 	return (buf);
382 }
383 
384 char *
385 ctrl(c)
386 	char c;
387 {
388 	static char s[3];
389 
390 	if (c < 040 || c == 0177) {
391 		s[0] = '^';
392 		s[1] = c == 0177 ? '?' : c+'A'-1;
393 		s[2] = '\0';
394 	} else {
395 		s[0] = c;
396 		s[1] = '\0';
397 	}
398 	return (s);
399 }
400 
401 /*
402  * Help command
403  */
404 help(c)
405 	char c;
406 {
407 	register esctable_t *p;
408 	extern esctable_t etable[];
409 
410 	printf("%c\r\n", c);
411 	for (p = etable; p->e_char; p++) {
412 		if ((p->e_flags&PRIV) && getuid())
413 			continue;
414 		printf("%2s", ctrl(character(value(ESCAPE))));
415 		printf("%-2s %c   %s\r\n", ctrl(p->e_char),
416 			p->e_flags&EXP ? '*': ' ', p->e_help);
417 	}
418 }
419 
420 /*
421  * Set up the "remote" tty's state
422  */
423 ttysetup(speed)
424 	int speed;
425 {
426 	unsigned bits = LDECCTQ;
427 
428 	arg.sg_ispeed = arg.sg_ospeed = speed;
429 	arg.sg_flags = RAW;
430 	if (boolean(value(TAND)))
431 		arg.sg_flags |= TANDEM;
432 	ioctl(FD, TIOCSETP, (char *)&arg);
433 	ioctl(FD, TIOCLBIS, (char *)&bits);
434 }
435 
436 /*
437  * Return "simple" name from a file name,
438  * strip leading directories.
439  */
440 char *
441 sname(s)
442 	register char *s;
443 {
444 	register char *p = s;
445 
446 	while (*s)
447 		if (*s++ == '/')
448 			p = s;
449 	return (p);
450 }
451 
452 static char partab[0200];
453 
454 /*
455  * Do a write to the remote machine with the correct parity.
456  * We are doing 8 bit wide output, so we just generate a character
457  * with the right parity and output it.
458  */
459 pwrite(fd, buf, n)
460 	int fd;
461 	char *buf;
462 	register int n;
463 {
464 	register int i;
465 	register char *bp;
466 	extern int errno;
467 
468 	bp = buf;
469 	for (i = 0; i < n; i++) {
470 		*bp = partab[(*bp) & 0177];
471 		bp++;
472 	}
473 	if (write(fd, buf, n) < 0) {
474 		if (errno == EIO)
475 			abort("Lost carrier.");
476 		/* this is questionable */
477 		perror("write");
478 	}
479 }
480 
481 /*
482  * Build a parity table with appropriate high-order bit.
483  */
484 setparity(defparity)
485 	char *defparity;
486 {
487 	register int i;
488 	char *parity;
489 	extern char evenpartab[];
490 
491 	if (value(PARITY) == NOSTR)
492 		value(PARITY) = defparity;
493 	parity = value(PARITY);
494 	for (i = 0; i < 0200; i++)
495 		partab[i] = evenpartab[i];
496 	if (equal(parity, "even"))
497 		return;
498 	if (equal(parity, "odd")) {
499 		for (i = 0; i < 0200; i++)
500 			partab[i] ^= 0200;	/* reverse bit 7 */
501 		return;
502 	}
503 	if (equal(parity, "none") || equal(parity, "zero")) {
504 		for (i = 0; i < 0200; i++)
505 			partab[i] &= ~0200;	/* turn off bit 7 */
506 		return;
507 	}
508 	if (equal(parity, "one")) {
509 		for (i = 0; i < 0200; i++)
510 			partab[i] |= 0200;	/* turn on bit 7 */
511 		return;
512 	}
513 	fprintf(stderr, "%s: unknown parity value\n", PA);
514 	fflush(stderr);
515 }
516