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