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.4 (Berkeley) 04/03/86"; 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 char PNbuf[256]; /* This limits the size of a number */ 39 extern char *sprintf(); 40 41 main(argc, argv) 42 char *argv[]; 43 { 44 char *system = NOSTR; 45 register int i; 46 register char *p; 47 char sbuf[12]; 48 49 if (equal(sname(argv[0]), "cu")) { 50 cumode = 1; 51 cumain(argc, argv); 52 goto cucommon; 53 } 54 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 } 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 84 if (system == NOSTR) 85 goto notnumber; 86 if (isalpha(*system)) 87 goto notnumber; 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; 102 system = sprintf(sbuf, "tip%d", BR); 103 104 notnumber: 105 signal(SIGINT, cleanup); 106 signal(SIGQUIT, cleanup); 107 signal(SIGHUP, cleanup); 108 signal(SIGTERM, cleanup); 109 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"); 116 delock(uucplock); 117 exit(3); 118 } 119 setbuf(stdout, NULL); 120 loginit(); 121 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 */ 129 setparity("even"); /* set the parity table */ 130 if ((i = speed(number(value(BAUDRATE)))) == NULL) { 131 printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); 132 delock(uucplock); 133 exit(3); 134 } 135 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 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); 157 if (p = connect()) { 158 printf("\07%s\n[EOT]\n", p); 159 setreuid(uid, euid); 160 setregid(gid, egid); 161 delock(uucplock); 162 exit(1); 163 } 164 if (!HW) 165 ttysetup(i); 166 cucommon: 167 /* 168 * From here down the code is shared with 169 * the "cu" version of tip. 170 */ 171 172 ioctl(0, TIOCGETP, (char *)&defarg); 173 ioctl(0, TIOCGETC, (char *)&defchars); 174 ioctl(0, TIOCGLTC, (char *)&deflchars); 175 ioctl(0, TIOCGETD, (char *)&odisc); 176 arg = defarg; 177 arg.sg_flags = ANYP | CBREAK; 178 tchars = defchars; 179 tchars.t_intrc = tchars.t_quitc = -1; 180 ltchars = deflchars; 181 ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc 182 = ltchars.t_lnextc = -1; 183 raw(); 184 185 pipe(fildes); pipe(repdes); 186 signal(SIGALRM, timeout); 187 188 /* 189 * Everything's set up now: 190 * connection established (hardwired or dialup) 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 */ 195 printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 196 if (pid = fork()) 197 tipin(); 198 else 199 tipout(); 200 /*NOTREACHED*/ 201 } 202 203 cleanup() 204 { 205 206 if (uid != getuid()) { 207 setreuid(uid, euid); 208 setregid(gid, egid); 209 } 210 delock(uucplock); 211 if (odisc) 212 ioctl(0, TIOCSETD, (char *)&odisc); 213 exit(0); 214 } 215 216 /* 217 * put the controlling keyboard into raw mode 218 */ 219 raw() 220 { 221 222 ioctl(0, TIOCSETP, &arg); 223 ioctl(0, TIOCSETC, &tchars); 224 ioctl(0, TIOCSLTC, <chars); 225 ioctl(0, TIOCSETD, (char *)&disc); 226 } 227 228 229 /* 230 * return keyboard to normal mode 231 */ 232 unraw() 233 { 234 235 ioctl(0, TIOCSETD, (char *)&odisc); 236 ioctl(0, TIOCSETP, (char *)&defarg); 237 ioctl(0, TIOCSETC, (char *)&defchars); 238 ioctl(0, TIOCSLTC, (char *)&deflchars); 239 } 240 241 static jmp_buf promptbuf; 242 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 */ 248 prompt(s, p) 249 char *s; 250 register char *p; 251 { 252 register char *b = p; 253 int (*oint)(), (*oquit)(); 254 255 stoprompt = 0; 256 oint = signal(SIGINT, intprompt); 257 oint = signal(SIGQUIT, SIG_IGN); 258 unraw(); 259 printf("%s", s); 260 if (setjmp(promptbuf) == 0) 261 while ((*p = getchar()) != EOF && *p != '\n') 262 p++; 263 *p = '\0'; 264 265 raw(); 266 signal(SIGINT, oint); 267 signal(SIGQUIT, oint); 268 return (stoprompt || p == b); 269 } 270 271 /* 272 * Interrupt service routine during prompting 273 */ 274 intprompt() 275 { 276 277 signal(SIGINT, SIG_IGN); 278 stoprompt = 1; 279 printf("\r\n"); 280 longjmp(promptbuf, 1); 281 } 282 283 /* 284 * ****TIPIN TIPIN**** 285 */ 286 tipin() 287 { 288 char gch, bol = 1; 289 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 302 while (1) { 303 gch = getchar()&0177; 304 if ((gch == character(value(ESCAPE))) && bol) { 305 if (!(gch = escape())) 306 continue; 307 } else if (!cumode && gch == character(value(RAISECHAR))) { 308 boolean(value(RAISE)) = !boolean(value(RAISE)); 309 continue; 310 } else if (gch == '\r') { 311 bol = 1; 312 pwrite(FD, &gch, 1); 313 if (boolean(value(HALFDUPLEX))) 314 printf("\r\n"); 315 continue; 316 } else if (!cumode && gch == character(value(FORCE))) 317 gch = getchar()&0177; 318 bol = any(gch, value(EOL)); 319 if (boolean(value(RAISE)) && islower(gch)) 320 gch = toupper(gch); 321 pwrite(FD, &gch, 1); 322 if (boolean(value(HALFDUPLEX))) 323 printf("%c", gch); 324 } 325 } 326 327 /* 328 * Escape handler -- 329 * called on recognition of ``escapec'' at the beginning of a line 330 */ 331 escape() 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); 345 return (0); 346 } 347 /* ESCAPE ESCAPE forces ESCAPE */ 348 if (c != gch) 349 pwrite(FD, &c, 1); 350 return (gch); 351 } 352 353 speed(n) 354 int n; 355 { 356 register int *p; 357 358 for (p = bauds; *p != -1; p++) 359 if (*p == n) 360 return (p - bauds); 361 return (NULL); 362 } 363 364 any(c, p) 365 register char c, *p; 366 { 367 while (p && *p) 368 if (*p++ == c) 369 return (1); 370 return (0); 371 } 372 373 size(s) 374 register char *s; 375 { 376 register int i = 0; 377 378 while (s && *s++) 379 i++; 380 return (i); 381 } 382 383 char * 384 interp(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'; 406 return (buf); 407 } 408 409 char * 410 ctrl(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 } 423 return (s); 424 } 425 426 /* 427 * Help command 428 */ 429 help(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 } 444 445 /* 446 * Set up the "remote" tty's state 447 */ 448 ttysetup(speed) 449 int speed; 450 { 451 unsigned bits = LDECCTQ; 452 453 arg.sg_ispeed = arg.sg_ospeed = speed; 454 arg.sg_flags = RAW; 455 if (boolean(value(TAND))) 456 arg.sg_flags |= TANDEM; 457 ioctl(FD, TIOCSETP, (char *)&arg); 458 ioctl(FD, TIOCLBIS, (char *)&bits); 459 } 460 461 /* 462 * Return "simple" name from a file name, 463 * strip leading directories. 464 */ 465 char * 466 sname(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 } 476 477 static char partab[0200]; 478 479 /* 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 482 * with the right parity and output it. 483 */ 484 pwrite(fd, buf, n) 485 int fd; 486 char *buf; 487 register int n; 488 { 489 register int i; 490 register char *bp; 491 extern int errno; 492 493 bp = buf; 494 for (i = 0; i < n; i++) { 495 *bp = partab[(*bp) & 0177]; 496 bp++; 497 } 498 if (write(fd, buf, n) < 0) { 499 if (errno == EIO) 500 abort("Lost carrier."); 501 /* this is questionable */ 502 perror("write"); 503 } 504 } 505 506 /* 507 * Build a parity table with appropriate high-order bit. 508 */ 509 setparity(defparity) 510 char *defparity; 511 { 512 register int i; 513 char *parity; 514 extern char evenpartab[]; 515 516 if (value(PARITY) == NOSTR) 517 value(PARITY) = defparity; 518 parity = value(PARITY); 519 for (i = 0; i < 0200; i++) 520 partab[i] = evenpartab[i]; 521 if (equal(parity, "even")) 522 return; 523 if (equal(parity, "odd")) { 524 for (i = 0; i < 0200; i++) 525 partab[i] ^= 0200; /* reverse bit 7 */ 526 return; 527 } 528 if (equal(parity, "none") || equal(parity, "zero")) { 529 for (i = 0; i < 0200; i++) 530 partab[i] &= ~0200; /* turn off bit 7 */ 531 return; 532 } 533 if (equal(parity, "one")) { 534 for (i = 0; i < 0200; i++) 535 partab[i] |= 0200; /* turn on bit 7 */ 536 return; 537 } 538 fprintf(stderr, "%s: unknown parity value\n", PA); 539 fflush(stderr); 540 } 541