/*ARGSUSED*/ static void intEMT(int signo) { char c, line[256]; char *pline = line; char reply; read(fildes[0], &c, 1); while (c != '\n' && (size_t)(pline - line) < sizeof(line)) { *pline++ = c; read(fildes[0], &c, 1); } *pline = '\0'; if (boolean(value(SCRIPT)) && fscript != NULL) fclose(fscript); if (pline == line) { setboolean(value(SCRIPT), FALSE); reply = 'y'; } else { if ((fscript = fopen(line, "a")) == NULL) reply = 'n'; else { reply = 'y'; setboolean(value(SCRIPT), TRUE); } } write(repdes[1], &reply, 1); longjmp(sigbuf, 1); }
/* * ****TIPIN TIPIN**** */ static void tipin(void) { int bol = 1; int gch; char ch; /* * Kinda klugey here... * check for scripting being turned on from the .tiprc file, * but be careful about just using setscript(), as we may * send a SIGEMT before tipout has a chance to set up catching * it; so wait a second, then setscript() */ if (boolean(value(SCRIPT))) { sleep(1); setscript(); } while (1) { gch = getchar()&STRIP_PAR; /* XXX does not check for EOF */ if ((gch == character(value(ESCAPE))) && bol) { if (!noesc) { if (!(gch = escape())) continue; } } else if (!cumode && gch == character(value(RAISECHAR))) { setboolean(value(RAISE), !boolean(value(RAISE))); continue; } else if (gch == '\r') { bol = 1; ch = gch; parwrite(FD, &ch, 1); if (boolean(value(HALFDUPLEX))) printf("\r\n"); continue; } else if (!cumode && gch == character(value(FORCE))) gch = getchar()&STRIP_PAR; bol = any(gch, value(EOL)); if (boolean(value(RAISE)) && islower(gch)) gch = toupper(gch); ch = gch; parwrite(FD, &ch, 1); if (boolean(value(HALFDUPLEX))) printf("%c", ch); } }
/*VARARGS1*/ static void vassign(value_t *p, char *v) { if (!vaccess(p->v_access, WRITE)) { printf("access denied\r\n"); return; } switch (p->v_type&TMASK) { case STRING: if (p->v_value && equal(p->v_value, v)) return; if (!(p->v_type&(ENVIRON|INIT))) free(p->v_value); if ((p->v_value = strdup(v)) == NOSTR) { printf("out of core\r\n"); return; } p->v_type &= ~(ENVIRON|INIT); break; case NUMBER: if (number(p->v_value) == number(v)) return; setnumber(p->v_value, number(v)); break; case BOOL: if (boolean(p->v_value) == (*v != '!')) return; setboolean(p->v_value, (*v != '!')); break; case CHAR: if (character(p->v_value) == *v) return; setcharacter(p->v_value, *v); } p->v_access |= CHANGED; }
/* * Establish connection for tip * * If DU is true, we should dial an ACU whose type is AT. * The phone numbers are in PN, and the call unit is in CU. * * If the PN is an '@', then we consult the PHONES file for * the phone numbers. This file is /etc/phones, unless overriden * by an exported shell variable. * * The data base files must be in the format: * host-name[ \t]*phone-number * with the possibility of multiple phone numbers * for a single host acting as a rotary (in the order * found in the file). */ char * con(void) { char *cp = PN; char *phnum, string[256]; FILE *fd; volatile int tried = 0; if (!DU) { /* regular connect message */ if (CM != NOSTR) parwrite(FD, CM, size(CM)); logent(value(HOST), "", DV, "call completed"); return (NOSTR); } /* * @ =>'s use data base in PHONES environment variable * otherwise, use /etc/phones */ signal(SIGINT, acuabort); signal(SIGQUIT, acuabort); if (setjmp(jmpbuf)) { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); printf("\ncall aborted\n"); logent(value(HOST), "", "", "call aborted"); if (acu != NOACU) { setboolean(value(VERBOSE), FALSE); if (conflag) disconnect(NOSTR); else (*acu->acu_abort)(); } return ("interrupt"); } if ((acu = acutype(AT)) == NOACU) return ("unknown ACU type"); if (*cp != '@') { while (*cp) { phnum = cp; cp += strcspn(cp, ","); if (*cp != '\0') *cp++ = '\0'; if (strlen(phnum) == 0) continue; conflag = (*acu->acu_dialer)(phnum, CU); if (conflag) break; logent(value(HOST), phnum, acu->acu_name, "call failed"); tried++; } } else { if ((fd = fopen(PH, "r")) == NOFILE) { printf("%s: ", PH); return ("can't open phone number file"); } while (fgets(string, sizeof(string), fd) != NOSTR) { cp = &string[strcspn(string, " \t\n")]; if (*cp != '\0') *cp++ = '\0'; if (strcmp(string, value(HOST)) != 0) continue; cp += strspn(cp, " \t\n"); phnum = cp; *(cp + strcspn(cp, ",\n")) = '\0'; if (strlen(phnum) == 0) continue; conflag = (*acu->acu_dialer)(phnum, CU); if (conflag) break; logent(value(HOST), phnum, acu->acu_name, "call failed"); tried++; } fclose(fd); } if (conflag) { if (CM != NOSTR) parwrite(FD, CM, size(CM)); logent(value(HOST), phnum, acu->acu_name, "call completed"); return (NOSTR); } else if (!tried) { logent(value(HOST), "", acu->acu_name, "missing phone number"); return ("missing phone number"); } else { (*acu->acu_abort)(); return ("call failed"); } }
/*ARGSUSED*/ static void intSYS(int signo) { setboolean(value(BEAUTIFY), !boolean(value(BEAUTIFY))); longjmp(sigbuf, 1); }
static void getremcap(char *host) { char **p, ***q, *bp, *rempath; int stat; rempath = getenv("REMOTE"); if (rempath != NULL) { if (*rempath != '/') /* we have an entry */ cgetset(rempath); else { /* we have a path */ db_array[1] = rempath; db_array[2] = _PATH_REMOTE; } } if ((stat = cgetent(&bp, db_array, host)) < 0) { if ((DV != NULL) || (host[0] == '/' && access(DV = host, R_OK | W_OK) == 0)) { CU = DV; HO = host; HW = 1; DU = 0; if (!BR) BR = DEFBR; FS = DEFFS; return; } switch (stat) { case -1: fprintf(stderr, "%s: unknown host %s\n", __progname, host); break; case -2: fprintf(stderr, "%s: can't open host description file\n", __progname); break; case -3: fprintf(stderr, "%s: possible reference loop in host description file\n", __progname); break; } exit(3); } for (p = capstrings, q = caps; *p != NULL; p++, q++) if (**q == NULL) cgetstr(bp, *p, *q); if (!BR && (cgetnum(bp, "br", &BR) == -1)) BR = DEFBR; if (!LD && (cgetnum(bp, "ld", &LD) == -1)) LD = TTYDISC; if (cgetnum(bp, "fs", &FS) == -1) FS = DEFFS; if (DU < 0) DU = 0; else DU = cgetflag("du"); if (DV == NOSTR) { fprintf(stderr, "%s: missing device spec\n", host); exit(3); } if (DU && CU == NOSTR) CU = DV; if (DU && PN == NOSTR) { fprintf(stderr, "%s: missing phone number\n", host); exit(3); } if (DU && AT == NOSTR) { fprintf(stderr, "%s: missing acu type\n", host); exit(3); } HD = cgetflag("hd"); /* * This effectively eliminates the "hw" attribute * from the description file */ if (!HW) HW = (CU == NOSTR) || (DU && equal(DV, CU)); HO = host; /* * see if uppercase mode should be turned on initially */ if (cgetflag("ra")) setboolean(value(RAISE), 1); if (cgetflag("ec")) setboolean(value(ECHOCHECK), 1); if (cgetflag("be")) setboolean(value(BEAUTIFY), 1); if (cgetflag("nb")) setboolean(value(BEAUTIFY), 0); if (cgetflag("sc")) setboolean(value(SCRIPT), 1); if (cgetflag("tb")) setboolean(value(TABEXPAND), 1); if (cgetflag("vb")) setboolean(value(VERBOSE), 1); if (cgetflag("nv")) setboolean(value(VERBOSE), 0); if (cgetflag("ta")) setboolean(value(TAND), 1); if (cgetflag("nt")) setboolean(value(TAND), 0); if (cgetflag("rw")) setboolean(value(RAWFTP), 1); if (cgetflag("hd")) setboolean(value(HALFDUPLEX), 1); if (cgetflag("dc")) setboolean(value(DC), 1); if (cgetflag("hf")) setboolean(value(HARDWAREFLOW), 1); if (RE == NOSTR) RE = (char *)"tip.record"; if (EX == NOSTR) EX = (char *)"\t\n\b\f"; if (ES != NOSTR) vstring("es", ES); if (FO != NOSTR) vstring("fo", FO); if (PR != NOSTR) vstring("pr", PR); if (RC != NOSTR) vstring("rc", RC); if (cgetnum(bp, "dl", &DL) == -1) DL = 0; if (cgetnum(bp, "cl", &CL) == -1) CL = 0; if (cgetnum(bp, "et", &ET) == -1) ET = 10; }
int main(int argc, char *argv[]) { char *sys = NOSTR, sbuf[12], *p; int i; /* XXX preserve previous braindamaged behavior */ setboolean(value(DC), TRUE); gid = getgid(); egid = getegid(); uid = getuid(); euid = geteuid(); if (equal(__progname, "cu")) { cumode = 1; cumain(argc, argv); goto cucommon; } if (argc > 4) { fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); exit(1); } if (!isatty(0)) { fprintf(stderr, "%s: must be interactive\n", __progname); exit(1); } for (; argc > 1; argv++, argc--) { if (argv[1][0] != '-') sys = argv[1]; else switch (argv[1][1]) { case 'v': vflag++; break; case 'n': noesc++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': BR = atoi(&argv[1][1]); break; default: fprintf(stderr, "%s: %s, unknown option\n", __progname, argv[1]); break; } } if (sys == NOSTR) goto notnumber; if (isalpha(*sys)) goto notnumber; /* * System name is really a phone number... * Copy the number then stomp on the original (in case the number * is private, we don't want 'ps' or 'w' to find it). */ if (strlen(sys) > sizeof PNbuf - 1) { fprintf(stderr, "%s: phone number too long (max = %d bytes)\n", __progname, (int)sizeof(PNbuf) - 1); exit(1); } strlcpy(PNbuf, sys, sizeof PNbuf - 1); for (p = sys; *p; p++) *p = '\0'; PN = PNbuf; (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR); sys = sbuf; notnumber: (void)signal(SIGINT, cleanup); (void)signal(SIGQUIT, cleanup); (void)signal(SIGHUP, cleanup); (void)signal(SIGTERM, cleanup); (void)signal(SIGCHLD, SIG_DFL); if ((i = hunt(sys)) == 0) { printf("all ports busy\n"); exit(3); } if (i == -1) { printf("link down\n"); (void)uu_unlock(uucplock); exit(3); } setbuf(stdout, NULL); loginit(); /* * Now that we have the logfile and the ACU open * return to the real uid and gid. These things will * be closed on exit. Swap real and effective uid's * so we can get the original permissions back * for removing the uucp lock. */ user_uid(); /* * Kludge, their's no easy way to get the initialization * in the right order, so force it here */ if ((PH = getenv("PHONES")) == NOSTR) PH = _PATH_PHONES; vinit(); /* init variables */ setparity("none"); /* set the parity table */ /* * Hardwired connections require the * line speed set before they make any transmissions * (this is particularly true of things like a DF03-AC) */ if (HW && ttysetup(number(value(BAUDRATE)))) { fprintf(stderr, "%s: bad baud rate %ld\n", __progname, number(value(BAUDRATE))); daemon_uid(); (void)uu_unlock(uucplock); exit(3); } if ((p = con())) { printf("\07%s\n[EOT]\n", p); daemon_uid(); (void)uu_unlock(uucplock); exit(1); } if (!HW && ttysetup(number(value(BAUDRATE)))) { fprintf(stderr, "%s: bad baud rate %ld\n", __progname, number(value(BAUDRATE))); daemon_uid(); (void)uu_unlock(uucplock); exit(3); } cucommon: /* * From here down the code is shared with * the "cu" version of tip. */ i = fcntl(FD, F_GETFL); if (i == -1) { perror("fcntl"); cleanup(0); } i = fcntl(FD, F_SETFL, i & ~O_NONBLOCK); if (i == -1) { perror("fcntl"); cleanup(0); } tcgetattr(0, &defterm); gotdefterm = 1; term = defterm; term.c_lflag &= ~(ICANON|IEXTEN|ECHO); term.c_iflag &= ~(INPCK|ICRNL); term.c_oflag &= ~OPOST; term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; defchars = term; term.c_cc[VINTR] = term.c_cc[VQUIT] = term.c_cc[VSUSP] = term.c_cc[VDSUSP] = term.c_cc[VDISCARD] = term.c_cc[VLNEXT] = _POSIX_VDISABLE; raw(); pipe(fildes); pipe(repdes); (void)signal(SIGALRM, timeout); if (value(LINEDISC) != TTYDISC) { int ld = (int)(intptr_t)value(LINEDISC); ioctl(FD, TIOCSETD, &ld); } /* * Everything's set up now: * connection established (hardwired or dialup) * line conditioned (baud rate, mode, etc.) * internal data structures (variables) * so, fork one process for local side and one for remote. */ printf(cumode ? "Connected\r\n" : "\07connected\r\n"); tipin_pid = getpid(); if ((tipout_pid = fork())) tipin(); else tipout(); /*NOTREACHED*/ exit(0); }
/* * Botch the interface to look like cu's */ void cumain(int argc, char *argv[]) { int ch, i, parity; long l; char *cp; static char sbuf[12]; if (argc < 2) cuusage(); CU = DV = NOSTR; BR = DEFBR; parity = 0; /* none */ /* * We want to accept -# as a speed. It's easiest to look through * the arguments, replace -# with -s#, and let getopt() handle it. */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') { asprintf(&cp, "-s%s", argv[i] + 1); if (cp == NULL) { fprintf(stderr, "%s: cannot convert -# to -s#\n", __progname); exit(3); } argv[i] = cp; } } while ((ch = getopt(argc, argv, "a:l:s:htoe")) != -1) { switch (ch) { case 'a': CU = optarg; break; case 'l': if (DV != NULL) { fprintf(stderr, "%s: cannot specificy multiple -l options\n", __progname); exit(3); } if (strchr(optarg, '/')) DV = optarg; else asprintf(&DV, "/dev/%s", optarg); break; case 's': l = strtol(optarg, &cp, 10); if (*cp != '\0' || l < 0 || l >= INT_MAX) { fprintf(stderr, "%s: unsupported speed %s\n", __progname, optarg); exit(3); } BR = (int)l; break; case 'h': setboolean(value(LECHO), TRUE); HD = TRUE; break; case 't': HW = 1, DU = -1; break; case 'o': if (parity != 0) parity = 0; /* -e -o */ else parity = 1; /* odd */ break; case 'e': if (parity != 0) parity = 0; /* -o -e */ else parity = -1; /* even */ break; default: cuusage(); break; } } argc -= optind; argv += optind; switch (argc) { case 1: PN = argv[0]; break; case 0: break; default: cuusage(); break; } signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGHUP, cleanup); signal(SIGTERM, cleanup); signal(SIGCHLD, SIG_DFL); /* * The "cu" host name is used to define the * attributes of the generic dialer. */ (void)snprintf(sbuf, sizeof(sbuf), "cu%ld", BR); if ((i = hunt(sbuf)) == 0) { printf("all ports busy\n"); exit(3); } if (i == -1) { printf("link down\n"); (void)uu_unlock(uucplock); exit(3); } setbuf(stdout, NULL); loginit(); user_uid(); vinit(); switch (parity) { case -1: setparity("even"); break; case 1: setparity("odd"); break; default: setparity("none"); break; } setboolean(value(VERBOSE), FALSE); if (HW && ttysetup(BR)) { fprintf(stderr, "%s: unsupported speed %ld\n", __progname, BR); daemon_uid(); (void)uu_unlock(uucplock); exit(3); } if (con()) { printf("Connect failed\n"); daemon_uid(); (void)uu_unlock(uucplock); exit(1); } if (!HW && ttysetup(BR)) { fprintf(stderr, "%s: unsupported speed %ld\n", __progname, BR); daemon_uid(); (void)uu_unlock(uucplock); exit(3); } }