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, <chars); 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