/* * FTP - send single character * wait for echo & handle timeout */ static void send(int c) { char cc; int retry = 0; cc = c; parwrite(FD, &cc, 1); if (number(value(CDELAY)) > 0 && c != '\r') usleep(number(value(CDELAY))); if (!boolean(value(ECHOCHECK))) { if (number(value(LDELAY)) > 0 && c == '\r') usleep(number(value(LDELAY))); return; } tryagain: timedout = 0; alarm((unsigned int)lvalue(ETIMEOUT)); read(FD, &cc, 1); alarm(0); if (timedout) { printf("\r\ntimeout error (%s)\r\n", ctrl(c)); if (retry++ > 3) return; parwrite(FD, &null, 1); /* poke it */ goto tryagain; } }
/* * FTP - send single character * wait for echo & handle timeout */ void send(char c) { char cc; int retry = 0; cc = c; parwrite(FD, (unsigned char *)&cc, 1); #ifdef notdef if (number(value(CDELAY)) > 0 && c != '\r') nap(number(value(CDELAY))); #endif if (!boolean(value(ECHOCHECK))) { #ifdef notdef if (number(value(LDELAY)) > 0 && c == '\r') nap(number(value(LDELAY))); #endif return; } tryagain: timedout = 0; if (sigsetjmp(intbuf, 1) && timedout) { (void) printf("\r\ntimeout error (%s)\r\n", ctrl(c)); if (retry++ > 3) return; parwrite(FD, (unsigned char *)&null, 1); /* poke it */ goto tryagain; } (void) alarm(number(value(ETIMEOUT))); (void) read(FD, &cc, 1); (void) alarm(0); }
/* * ****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); } }
/* * ****TIPIN TIPIN**** */ void tipin(void) { unsigned char gch, c; int bol = 1; /* * 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))) { (void) sleep(1); setscript(); } for (;;) { gch = getchar()&0377; if ((gch == character(value(ESCAPE))) && bol) { if (!(gch = escape())) continue; } else if (!cumode && gch == character(value(RAISECHAR))) { boolean(value(RAISE)) = !boolean(value(RAISE)); continue; } else if (gch == '\r') { bol = 1; parwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) (void) printf("\r\n"); continue; } else if (!cumode && gch == character(value(FORCE))) gch = getchar()&0377; bol = any(gch, value(EOL)); if (boolean(value(RAISE)) && islower(gch)) gch = toupper(gch); c = gch; parwrite(FD, &gch, 1); if (boolean(value(HALFDUPLEX))) (void) putchar(c); } }
/* * Escape handler -- * called on recognition of ``escapec'' at the beginning of a line */ unsigned char escape(void) { unsigned char gch; esctable_t *p; char c = character(value(ESCAPE)); gch = (getchar()&0377); for (p = etable; p->e_char; p++) if (p->e_char == gch) { if ((p->e_flags&PRIV) && uid) continue; (void) printf("%s", ctrl(c)); (*p->e_func)(gch); return (0); } /* ESCAPE ESCAPE forces ESCAPE */ if (c != gch) parwrite(FD, (unsigned char *)&c, 1); return (gch); }
/* * Escape handler -- * called on recognition of ``escapec'' at the beginning of a line */ static int escape(void) { int gch; esctable_t *p; char c = character(value(ESCAPE)); gch = (getchar()&STRIP_PAR); /* XXX does not check for EOF */ for (p = etable; p->e_char; p++) if (p->e_char == gch) { if ((p->e_flags&PRIV) && uid) continue; printf("%s", ctrl(c)); (*p->e_func)(gch); return (0); } /* ESCAPE ESCAPE forces ESCAPE */ if (c != gch) parwrite(FD, &c, 1); return (gch); }
/* * 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"); } }
int main(int argc, char *argv[]) { char *system = NOSTR; int i; char *p; char sbuf[15]; gid = getgid(); egid = getegid(); uid = getuid(); euid = geteuid(); if (equal(sname(argv[0]), "cu")) { cumode = 1; cumain(argc, argv); goto cucommon; } if (argc > 4) { (void) fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); return (1); } if (!isatty(0)) { (void) fprintf(stderr, "tip: must be interactive\n"); return (1); } for (; argc > 1; argv++, argc--) { if (argv[1][0] != '-') system = argv[1]; else switch (argv[1][1]) { case 'v': vflag++; 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: (void) fprintf(stderr, "tip: %s, unknown option\n", argv[1]); break; } } (void) setlocale(LC_CTYPE, ""); if (system == NOSTR) goto notnumber; for (p = system; *p; p++) if (isalpha(*p)) 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(system) > sizeof (PNbuf) - 1) { (void) fprintf(stderr, "tip: phone number too long (max = %d bytes)\n", sizeof (PNbuf) - 1); return (1); } (void) strncpy(PNbuf, system, sizeof (PNbuf) - 1); for (p = system; *p; p++) *p = '\0'; PN = PNbuf; (void) snprintf(sbuf, sizeof (sbuf), "tip%d", BR); system = sbuf; notnumber: (void) signal(SIGINT, (sig_handler_t)cleanup); (void) signal(SIGQUIT, (sig_handler_t)cleanup); (void) signal(SIGHUP, (sig_handler_t)cleanup); (void) signal(SIGTERM, (sig_handler_t)cleanup); if ((i = hunt(system)) == 0) { (void) printf("all ports busy\n"); return (3); } if (i == -1) { (void) printf("link down\n"); delock(uucplock); return (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. The saved-setuid uid and gid * allows us to get the original setuid permissions back * for removing the uucp lock. */ userperm(); /* * Kludge, there's no easy way to get the initialization * in the right order, so force it here. * Do the open here, before we change back to real uid. * We will check whether the open succeeded later, when * (and if) we actually go to use the file. */ if ((PH = getenv("PHONES")) == NOSTR) { myperm(); PH = "/etc/phones"; } phfd = fopen(PH, "r"); userperm(); vinit(); /* init variables */ setparity("none"); /* set the parity table */ if ((i = speed(number(value(BAUDRATE)))) == NULL) { (void) printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); myperm(); delock(uucplock); return (3); } /* * 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(i); if (p = connect()) { (void) printf("\07%s\n[EOT]\n", p); myperm(); delock(uucplock); return (1); } /* * Always setup the tty again here in case hardware flow * control was selected, which can only be set after the * connection is made, or in case this is not a hardwired * modem (rare these days) that likewise can only be setup * after the connection is made. */ ttysetup(i); cucommon: /* * From here down the code is shared with * the "cu" version of tip. */ (void) ioctl(0, TCGETS, (char *)&defarg); arg = defarg; /* turn off input processing */ arg.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN); arg.c_cc[VMIN] = 1; arg.c_cc[VTIME] = 0; arg.c_iflag &= ~(INPCK|IXON|IXOFF|ICRNL); arg.c_oflag = 0; /* turn off all output processing */ /* handle tandem mode in case was set in remote file */ if (boolean(value(TAND))) tandem("on"); else tandem("off"); raw(); (void) pipe(fildes); (void) pipe(repdes); (void) signal(SIGALRM, (sig_handler_t)timeout); /* * 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. */ if (CM != NOSTR) { (void) sleep(2); /* let line settle */ parwrite(FD, (unsigned char *)CM, strlen(CM)); } (void) printf(cumode ? "Connected\r\n" : "\07connected\r\n"); (void) signal(SIGCHLD, (sig_handler_t)deadkid); if (pid = fork()) tipin(); else tipout(); /*NOTREACHED*/ }
/* * Bulk transfer routine -- * used by getfl(), cu_take(), and pipefile() */ static void transfer(char *buf, int fd, char *eofchars) { int ct, eof; char c, buffer[BUFSIZ]; char *p = buffer; size_t cnt; time_t start; sig_t f; char r; if (number(value(FRAMESIZE)) > BUFSIZ || number(value(FRAMESIZE)) < 1) { printf("framesize must be >= 1 and <= %d\r\n", BUFSIZ); close(fd); return; } parwrite(FD, buf, size(buf)); quit = 0; kill(tipout_pid, SIGIOT); read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ /* * finish command */ r = '\r'; parwrite(FD, &r, 1); do read(FD, &c, 1); while ((c&STRIP_PAR) != '\n'); tcsetattr(0, TCSAFLUSH, &defchars); (void) setjmp(intbuf); f = signal(SIGINT, intcopy); start = time(0); for (ct = 0; !quit;) { eof = read(FD, &c, 1) <= 0; c &= STRIP_PAR; if (quit) continue; if (eof || any(c, eofchars)) break; if (c == 0) continue; /* ignore nulls */ if (c == '\r') continue; *p++ = c; if (c == '\n' && boolean(value(VERBOSE))) printf("\r%d", ++ct); if ((cnt = (p-buffer)) == (size_t)number(value(FRAMESIZE))) { if ((size_t)write(fd, buffer, cnt) != cnt) { printf("\r\nwrite error\r\n"); quit = 1; } p = buffer; } } if ((cnt = (p-buffer))) if ((size_t)write(fd, buffer, cnt) != cnt) printf("\r\nwrite error\r\n"); if (boolean(value(VERBOSE))) prtime(" lines transferred in ", time(0)-start); tcsetattr(0, TCSAFLUSH, &term); write(fildes[1], (char *)&ccc, 1); signal(SIGINT, f); close(fd); }
/* * Bulk transfer routine -- * used by getfl(), cu_take(), and pipefile() */ void transfer(char *buf, int fd, char *eofchars) { int ct; char c, buffer[BUFSIZ]; char *p = buffer; /* can't be register because of longjmp */ int cnt, eof, bol; time_t start; sig_handler_t f; parwrite(FD, (unsigned char *)buf, strlen(buf)); (void) kill(pid, SIGIOT); /* Wait until read process stops */ (void) read(repdes[0], (char *)&ccc, 1); /* * finish command */ parwrite(FD, (unsigned char *)"\r", 1); do (void) read(FD, &c, 1); while ((c&0177) != '\n') ; if (sigsetjmp(intbuf, 1)) goto out; f = signal(SIGINT, (sig_handler_t)intcopy); intr("on"); start = time(0); bol = 1; ct = 0; for (;;) { eof = read(FD, &c, 1) <= 0; if (noparity) c &= 0377; else c &= 0177; if (eof || (bol && any(c, eofchars))) break; if (c == 0) continue; /* ignore nulls */ if (c == '\r') continue; *p++ = c; if (c == '\n') { bol = 1; if (boolean(value(VERBOSE))) (void) printf("\r%d", ++ct); } else bol = 0; if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { if (write(fd, buffer, cnt) != cnt) { (void) printf("\r\nwrite error\r\n"); goto out; } p = buffer; } } out: if ((cnt = (p-buffer)) != 0) if (write(fd, buffer, cnt) != cnt) (void) printf("\r\nwrite error\r\n"); if (boolean(value(VERBOSE))) prtime(" lines transferred in ", time(0)-start); intr("off"); (void) write(fildes[1], (char *)&ccc, 1); (void) signal(SIGINT, f); (void) close(fd); }