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