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) 4/3/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: }