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