113279Ssam #ifndef lint 2*17236Shelge static char sccsid[] = "@(#)tip.c 4.18 (Berkeley) 10/06/84"; 313279Ssam #endif 45136Ssam 53696Sroot /* 65136Ssam * tip - UNIX link to other systems 73696Sroot * tip [-v] [-speed] system-name 85136Ssam * or 95136Ssam * cu phone-number [-s speed] [-l line] [-a acu] 103696Sroot */ 113696Sroot #include "tip.h" 123696Sroot 133696Sroot /* 143696Sroot * Baud rate mapping table 153696Sroot */ 163696Sroot int bauds[] = { 173696Sroot 0, 50, 75, 110, 134, 150, 200, 300, 600, 183696Sroot 1200, 1800, 2400, 4800, 9600, 19200, -1 193696Sroot }; 203696Sroot 214004Ssam int disc = OTTYDISC; /* tip normally runs this way */ 223696Sroot int intprompt(); 233696Sroot int timeout(); 245136Ssam int cleanup(); 255257Sshannon char *sname(); 265257Sshannon extern char *sprintf(); 273696Sroot 283696Sroot main(argc, argv) 294962Ssam char *argv[]; 303696Sroot { 313696Sroot char *system = NOSTR; 323696Sroot register int i; 335257Sshannon register char *p; 345257Sshannon char sbuf[12]; 353696Sroot 365257Sshannon if (equal(sname(argv[0]), "cu")) { 375136Ssam cumain(argc, argv); 385136Ssam cumode = 1; 395136Ssam goto cucommon; 405136Ssam } 415136Ssam 423696Sroot if (argc > 4) { 433696Sroot fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); 443696Sroot exit(1); 453696Sroot } 463696Sroot if (!isatty(0)) { 473696Sroot fprintf(stderr, "tip: must be interactive\n"); 483696Sroot exit(1); 493696Sroot } 505257Sshannon 515257Sshannon for (; argc > 1; argv++, argc--) { 525257Sshannon if (argv[1][0] != '-') 535257Sshannon system = argv[1]; 545257Sshannon else switch (argv[1][1]) { 555257Sshannon 565257Sshannon case 'v': 575257Sshannon vflag++; 585257Sshannon break; 595257Sshannon 605257Sshannon case '0': case '1': case '2': case '3': case '4': 615257Sshannon case '5': case '6': case '7': case '8': case '9': 625257Sshannon BR = atoi(&argv[1][1]); 635257Sshannon break; 645257Sshannon 655257Sshannon default: 665257Sshannon fprintf(stderr, "tip: %s, unknown option\n", argv[1]); 675257Sshannon break; 685257Sshannon } 695257Sshannon } 705257Sshannon 717593Sshannon if (system == NOSTR) 727593Sshannon goto notnumber; 735257Sshannon for (p = system; *p; p++) 745257Sshannon if (isalpha(*p)) 755257Sshannon goto notnumber; 765257Sshannon PN = system; /* system name is really a phone number */ 775257Sshannon system = sprintf(sbuf, "tip%d", BR); 785257Sshannon 795257Sshannon notnumber: 803696Sroot signal(SIGINT, cleanup); 813696Sroot signal(SIGQUIT, cleanup); 823696Sroot signal(SIGHUP, cleanup); 833696Sroot signal(SIGTERM, cleanup); 843898Ssam 853696Sroot if ((i = hunt(system)) == 0) { 863696Sroot printf("all ports busy\n"); 873696Sroot exit(3); 883696Sroot } 893696Sroot if (i == -1) { 903696Sroot printf("link down\n"); 914232Ssam delock(uucplock); 923696Sroot exit(3); 933696Sroot } 943719Ssam setbuf(stdout, NULL); 953696Sroot loginit(); 963696Sroot /* 973696Sroot * Now that we have the logfile and the ACU open 983696Sroot * return to the real uid and gid. These things will 993696Sroot * be closed on exit. Note that we can't run as root, 1003696Sroot * because locking mechanism on the tty and the accounting 1013696Sroot * will be bypassed. 1023696Sroot */ 10313139Sralph setgid(getgid()); 1043696Sroot setuid(getuid()); 1055257Sshannon 1063696Sroot /* 1073696Sroot * Kludge, their's no easy way to get the initialization 1083696Sroot * in the right order, so force it here 1093696Sroot */ 1103696Sroot if ((PH = getenv("PHONES")) == NOSTR) 1113696Sroot PH = "/etc/phones"; 1123696Sroot vinit(); /* init variables */ 11313430Ssam setparity("even"); /* set the parity table */ 1144004Ssam if ((i = speed(number(value(BAUDRATE)))) == NULL) { 1153696Sroot printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); 1163696Sroot delock(uucplock); 1173696Sroot exit(3); 1183696Sroot } 1193898Ssam 1204004Ssam /* 1214004Ssam * Hardwired connections require the 1224004Ssam * line speed set before they make any transmissions 1234004Ssam * (this is particularly true of things like a DF03-AC) 1244004Ssam */ 1254004Ssam if (HW) 1264004Ssam ttysetup(i); 1273898Ssam if (p = connect()) { 1283898Ssam printf("\07%s\n[EOT]\n", p); 1293898Ssam delock(uucplock); 1303898Ssam exit(1); 1313898Ssam } 1324004Ssam if (!HW) 1334004Ssam ttysetup(i); 1345136Ssam cucommon: 1353696Sroot /* 1365136Ssam * From here down the code is shared with 1375136Ssam * the "cu" version of tip. 1383696Sroot */ 1394004Ssam ioctl(0, TIOCGETP, (char *)&defarg); 1404004Ssam ioctl(0, TIOCGETC, (char *)&defchars); 14112478Sroot ioctl(0, TIOCGLTC, (char *)&deflchars); 1424004Ssam ioctl(0, TIOCGETD, (char *)&odisc); 1433696Sroot arg = defarg; 1443696Sroot arg.sg_flags = ANYP | CBREAK; 1453696Sroot tchars = defchars; 1463696Sroot tchars.t_intrc = tchars.t_quitc = -1; 14712478Sroot ltchars = deflchars; 14812478Sroot ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc 14912478Sroot = ltchars.t_lnextc = -1; 1503696Sroot raw(); 1514004Ssam 1523696Sroot pipe(fildes); pipe(repdes); 1533696Sroot signal(SIGALRM, timeout); 1543898Ssam 1553898Ssam /* 1563898Ssam * Everything's set up now: 157*17236Shelge * connection established (hardwired or dialup) 1583898Ssam * line conditioned (baud rate, mode, etc.) 1593898Ssam * internal data structures (variables) 1603898Ssam * so, fork one process for local side and one for remote. 1613898Ssam */ 1625136Ssam printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 1633696Sroot if (pid = fork()) 1643696Sroot tipin(); 1653696Sroot else 1663696Sroot tipout(); 1673696Sroot /*NOTREACHED*/ 1683696Sroot } 1693696Sroot 1703696Sroot cleanup() 1713696Sroot { 17213279Ssam 1733696Sroot delock(uucplock); 1743898Ssam if (odisc) 1753898Ssam ioctl(0, TIOCSETD, (char *)&odisc); 1763696Sroot exit(0); 1773696Sroot } 1783696Sroot 1793696Sroot /* 1803696Sroot * put the controlling keyboard into raw mode 1813696Sroot */ 1823696Sroot raw() 1833696Sroot { 18413279Ssam 1853696Sroot ioctl(0, TIOCSETP, &arg); 1863696Sroot ioctl(0, TIOCSETC, &tchars); 18712478Sroot ioctl(0, TIOCSLTC, <chars); 1884004Ssam ioctl(0, TIOCSETD, (char *)&disc); 1893696Sroot } 1903696Sroot 1913696Sroot 1923696Sroot /* 1933696Sroot * return keyboard to normal mode 1943696Sroot */ 1953696Sroot unraw() 1963696Sroot { 19713279Ssam 1984004Ssam ioctl(0, TIOCSETD, (char *)&odisc); 1994004Ssam ioctl(0, TIOCSETP, (char *)&defarg); 2004004Ssam ioctl(0, TIOCSETC, (char *)&defchars); 20112478Sroot ioctl(0, TIOCSLTC, (char *)&deflchars); 2023696Sroot } 2033696Sroot 20413279Ssam static jmp_buf promptbuf; 20513279Ssam 2063696Sroot /* 2073696Sroot * Print string ``s'', then read a string 2083696Sroot * in from the terminal. Handles signals & allows use of 2093696Sroot * normal erase and kill characters. 2103696Sroot */ 2113696Sroot prompt(s, p) 2123696Sroot char *s; 2133696Sroot register char *p; 2143696Sroot { 2153696Sroot register char *b = p; 21613279Ssam int (*oint)(), (*oquit)(); 2173696Sroot 2183696Sroot stoprompt = 0; 21913279Ssam oint = signal(SIGINT, intprompt); 22013279Ssam oint = signal(SIGQUIT, SIG_IGN); 2213696Sroot unraw(); 2223696Sroot printf("%s", s); 22313279Ssam if (setjmp(promptbuf) == 0) 22413279Ssam while ((*p = getchar()) != EOF && *p != '\n') 22513279Ssam p++; 2263696Sroot *p = '\0'; 22713279Ssam 2283696Sroot raw(); 22913279Ssam signal(SIGINT, oint); 23013279Ssam signal(SIGQUIT, oint); 23113279Ssam return (stoprompt || p == b); 2323696Sroot } 2333696Sroot 2343696Sroot /* 2353696Sroot * Interrupt service routine during prompting 2363696Sroot */ 2373696Sroot intprompt() 2383696Sroot { 23913279Ssam 2403696Sroot signal(SIGINT, SIG_IGN); 2413696Sroot stoprompt = 1; 2423696Sroot printf("\r\n"); 24313279Ssam longjmp(promptbuf, 1); 2443696Sroot } 2453696Sroot 2463696Sroot /* 2473696Sroot * ****TIPIN TIPIN**** 2483696Sroot */ 2493696Sroot tipin() 2503696Sroot { 2513696Sroot char gch, bol = 1; 2523696Sroot 2533796Ssam /* 2543796Ssam * Kinda klugey here... 2553796Ssam * check for scripting being turned on from the .tiprc file, 2563796Ssam * but be careful about just using setscript(), as we may 2573796Ssam * send a SIGEMT before tipout has a chance to set up catching 2583796Ssam * it; so wait a second, then setscript() 2593796Ssam */ 2603796Ssam if (boolean(value(SCRIPT))) { 2613796Ssam sleep(1); 2623796Ssam setscript(); 2633796Ssam } 2643796Ssam 2653696Sroot while (1) { 2663696Sroot gch = getchar()&0177; 2673696Sroot if ((gch == character(value(ESCAPE))) && bol) { 2683696Sroot if (!(gch = escape())) 2693696Sroot continue; 2705136Ssam } else if (!cumode && gch == character(value(RAISECHAR))) { 2713696Sroot boolean(value(RAISE)) = !boolean(value(RAISE)); 2723696Sroot continue; 2733696Sroot } else if (gch == '\r') { 2743696Sroot bol = 1; 27513139Sralph pwrite(FD, &gch, 1); 27613139Sralph if (boolean(value(HALFDUPLEX))) 27713139Sralph printf("\r\n"); 2783696Sroot continue; 2795136Ssam } else if (!cumode && gch == character(value(FORCE))) 2803696Sroot gch = getchar()&0177; 2813696Sroot bol = any(gch, value(EOL)); 2823696Sroot if (boolean(value(RAISE)) && islower(gch)) 28313139Sralph gch = toupper(gch); 28413139Sralph pwrite(FD, &gch, 1); 28513139Sralph if (boolean(value(HALFDUPLEX))) 28613139Sralph printf("%c", gch); 2873696Sroot } 2883696Sroot } 2893696Sroot 2903696Sroot /* 2913696Sroot * Escape handler -- 2923696Sroot * called on recognition of ``escapec'' at the beginning of a line 2933696Sroot */ 2943696Sroot escape() 2953696Sroot { 2963696Sroot register char gch; 2973696Sroot register esctable_t *p; 2983696Sroot char c = character(value(ESCAPE)); 2993696Sroot extern esctable_t etable[]; 3003696Sroot 3013696Sroot gch = (getchar()&0177); 3023696Sroot for (p = etable; p->e_char; p++) 3033696Sroot if (p->e_char == gch) { 3043696Sroot if ((p->e_flags&PRIV) && getuid()) 3053696Sroot continue; 3063696Sroot printf("%s", ctrl(c)); 3073696Sroot (*p->e_func)(gch); 30813279Ssam return (0); 3093696Sroot } 3104146Ssam /* ESCAPE ESCAPE forces ESCAPE */ 3114146Ssam if (c != gch) 31213139Sralph pwrite(FD, &c, 1); 31313279Ssam return (gch); 3143696Sroot } 3153696Sroot 3163696Sroot speed(n) 31713279Ssam int n; 3183696Sroot { 3193696Sroot register int *p; 3203696Sroot 3213696Sroot for (p = bauds; *p != -1; p++) 3223696Sroot if (*p == n) 32313279Ssam return (p - bauds); 32413279Ssam return (NULL); 3253696Sroot } 3263696Sroot 3273696Sroot any(c, p) 3283696Sroot register char c, *p; 3293696Sroot { 33013279Ssam while (p && *p) 3313696Sroot if (*p++ == c) 33213279Ssam return (1); 33313279Ssam return (0); 3343696Sroot } 3353696Sroot 3363696Sroot size(s) 3373696Sroot register char *s; 3383696Sroot { 33913279Ssam register int i = 0; 3403696Sroot 34113279Ssam while (s && *s++) 34213279Ssam i++; 34313279Ssam return (i); 3443696Sroot } 3453696Sroot 3463696Sroot char * 3473696Sroot interp(s) 3483696Sroot register char *s; 3493696Sroot { 3503696Sroot static char buf[256]; 3513696Sroot register char *p = buf, c, *q; 3523696Sroot 3533696Sroot while (c = *s++) { 3543696Sroot for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 3553696Sroot if (*q++ == c) { 3563696Sroot *p++ = '\\'; *p++ = *q; 3573696Sroot goto next; 3583696Sroot } 3593696Sroot if (c < 040) { 3603696Sroot *p++ = '^'; *p++ = c + 'A'-1; 3613696Sroot } else if (c == 0177) { 3623696Sroot *p++ = '^'; *p++ = '?'; 3633696Sroot } else 3643696Sroot *p++ = c; 3653696Sroot next: 3663696Sroot ; 3673696Sroot } 3683696Sroot *p = '\0'; 36913279Ssam return (buf); 3703696Sroot } 3713696Sroot 3723696Sroot char * 3733696Sroot ctrl(c) 3743696Sroot char c; 3753696Sroot { 3763696Sroot static char s[3]; 3773696Sroot 3783696Sroot if (c < 040 || c == 0177) { 3793696Sroot s[0] = '^'; 3803696Sroot s[1] = c == 0177 ? '?' : c+'A'-1; 3813696Sroot s[2] = '\0'; 3823696Sroot } else { 3833696Sroot s[0] = c; 3843696Sroot s[1] = '\0'; 3853696Sroot } 38613279Ssam return (s); 3873696Sroot } 3883696Sroot 3893696Sroot /* 3903696Sroot * Help command 3913696Sroot */ 3923696Sroot help(c) 3933696Sroot char c; 3943696Sroot { 3953696Sroot register esctable_t *p; 3963696Sroot extern esctable_t etable[]; 3973696Sroot 3983696Sroot printf("%c\r\n", c); 3993696Sroot for (p = etable; p->e_char; p++) { 4003696Sroot if ((p->e_flags&PRIV) && getuid()) 4013696Sroot continue; 4023696Sroot printf("%2s", ctrl(character(value(ESCAPE)))); 4033696Sroot printf("%-2s %c %s\r\n", ctrl(p->e_char), 4043696Sroot p->e_flags&EXP ? '*': ' ', p->e_help); 4053696Sroot } 4063696Sroot } 4074004Ssam 4084004Ssam /* 4094004Ssam * Set up the "remote" tty's state 4104004Ssam */ 4114004Ssam ttysetup(speed) 41213279Ssam int speed; 4134004Ssam { 4144004Ssam unsigned bits = LDECCTQ; 4154004Ssam 4164004Ssam arg.sg_ispeed = arg.sg_ospeed = speed; 41713279Ssam arg.sg_flags = RAW; 41813139Sralph if (boolean(value(TAND))) 41913279Ssam arg.sg_flags |= TANDEM; 4204004Ssam ioctl(FD, TIOCSETP, (char *)&arg); 4214004Ssam ioctl(FD, TIOCLBIS, (char *)&bits); 4224004Ssam } 4235257Sshannon 4245257Sshannon /* 4255257Sshannon * Return "simple" name from a file name, 4265257Sshannon * strip leading directories. 4275257Sshannon */ 4285257Sshannon char * 4295257Sshannon sname(s) 4305257Sshannon register char *s; 4315257Sshannon { 4325257Sshannon register char *p = s; 4335257Sshannon 4345257Sshannon while (*s) 4355257Sshannon if (*s++ == '/') 4365257Sshannon p = s; 4375257Sshannon return (p); 4385257Sshannon } 43913139Sralph 44013139Sralph static char partab[0200]; 44113139Sralph 44213139Sralph /* 44313279Ssam * Do a write to the remote machine with the correct parity. 44413279Ssam * We are doing 8 bit wide output, so we just generate a character 44513139Sralph * with the right parity and output it. 44613139Sralph */ 44713139Sralph pwrite(fd, buf, n) 44813139Sralph int fd; 44913139Sralph char *buf; 45013139Sralph register int n; 45113139Sralph { 45213139Sralph register int i; 45313279Ssam register char *bp; 45415188Ssam extern int errno; 45513139Sralph 45613279Ssam bp = buf; 45713279Ssam for (i = 0; i < n; i++) { 45813139Sralph *bp = partab[(*bp) & 0177]; 45913279Ssam bp++; 46013139Sralph } 46115188Ssam if (write(fd, buf, n) < 0) { 46215188Ssam if (errno == EIO) 46315188Ssam abort("Lost carrier."); 46415188Ssam /* this is questionable */ 46515188Ssam perror("write"); 46615188Ssam } 46713139Sralph } 46813139Sralph 46913139Sralph /* 47013279Ssam * Build a parity table with appropriate high-order bit. 47113139Sralph */ 47213430Ssam setparity(defparity) 47313430Ssam char *defparity; 47413139Sralph { 47513279Ssam register int i; 47613139Sralph char *parity; 47713279Ssam extern char evenpartab[]; 47813139Sralph 47913139Sralph if (value(PARITY) == NOSTR) 48013430Ssam value(PARITY) = defparity; 48113139Sralph parity = value(PARITY); 48213139Sralph for (i = 0; i < 0200; i++) 48313279Ssam partab[i] = evenpartab[i]; 48413279Ssam if (equal(parity, "even")) 48513279Ssam return; 48613139Sralph if (equal(parity, "odd")) { 48713139Sralph for (i = 0; i < 0200; i++) 48813139Sralph partab[i] ^= 0200; /* reverse bit 7 */ 48913279Ssam return; 49013139Sralph } 49113279Ssam if (equal(parity, "none") || equal(parity, "zero")) { 49213139Sralph for (i = 0; i < 0200; i++) 49313139Sralph partab[i] &= ~0200; /* turn off bit 7 */ 49413279Ssam return; 49513139Sralph } 49613279Ssam if (equal(parity, "one")) { 49713139Sralph for (i = 0; i < 0200; i++) 49813139Sralph partab[i] |= 0200; /* turn on bit 7 */ 49913279Ssam return; 50013139Sralph } 50113279Ssam fprintf(stderr, "%s: unknown parity value\n", PA); 50213279Ssam fflush(stderr); 50313139Sralph } 504