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