113642Ssam #ifndef lint 2*14592Skarels static char sccsid[] = "@(#)conn.c 5.3 (Berkeley) 08/13/83"; 313642Ssam #endif 413642Ssam 513642Ssam #include "uucp.h" 613642Ssam #include <signal.h> 713642Ssam #include <setjmp.h> 813642Ssam #include <ctype.h> 913642Ssam #include <sys/types.h> 1013705Ssam #include <sys/time.h> 1113642Ssam #include <errno.h> 1213642Ssam #ifdef SYSIII 1313642Ssam #include <termio.h> 1413642Ssam #include <fcntl.h> 1513642Ssam #endif 1613642Ssam #ifndef SYSIII 1713642Ssam #include <sgtty.h> 1813642Ssam #endif 1913642Ssam 2013642Ssam #define MAXC 1000 2113642Ssam 2213642Ssam extern jmp_buf Sjbuf; 2313642Ssam extern int errno; 2413642Ssam 2513642Ssam /* Parity control during login procedure */ 2613642Ssam #define P_ZERO 0 2713642Ssam #define P_ONE 1 2813642Ssam #define P_EVEN 2 2913642Ssam #define P_ODD 3 3013642Ssam char par_tab[128]; /* must be power of two */ 3113642Ssam 3213642Ssam int next_fd = -1; /* predicted fd to close interrupted opens */ 3313642Ssam /* rti!trt, courtesy unc!smb */ 3413642Ssam /*** 3513642Ssam * alarmtr() - catch alarm routine for "expect". 3613642Ssam */ 3713642Ssam alarmtr() 3813642Ssam { 3913642Ssam signal(SIGALRM, alarmtr); 4013642Ssam if (next_fd >= 0) { 4113642Ssam if (close(next_fd)) 4213642Ssam logent("FAIL", "ACU LINE CLOSE"); 4313642Ssam next_fd = -1; 4413642Ssam } 4513642Ssam longjmp(Sjbuf, 1); 4613642Ssam } 4713642Ssam 4813642Ssam /******* 4913642Ssam * conn(system) 5013642Ssam * char *system; 5113642Ssam * 5213642Ssam * conn - place a telephone call to system and 5313642Ssam * login, etc. 5413642Ssam * 5513642Ssam * return codes: 5613642Ssam * CF_SYSTEM: don't know system 5713642Ssam * CF_TIME: wrong time to call 5813642Ssam * CF_DIAL: call failed 5913642Ssam * CF_NODEV: no devices available to place call 6013642Ssam * CF_LOGIN: login/password dialog failed 6113642Ssam * 6213642Ssam * >0 - file no. - connect ok 6313642Ssam * 6413642Ssam */ 6513642Ssam 6613642Ssam int Dcf = -1; 6713642Ssam 6813642Ssam conn(system) 6913642Ssam char *system; 7013642Ssam { 7113642Ssam int ret, nf; 7213642Ssam register int fn, fnd; 7313642Ssam char info[MAXC], *flds[MAXC/10]; 7413642Ssam register FILE *fsys; 7513642Ssam int fcode = 0; 7613642Ssam 7713642Ssam nf = 0; 7813642Ssam fnd = 0; 7913642Ssam 8013642Ssam 8113642Ssam fsys = fopen(SYSFILE, "r"); 8213642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 8313642Ssam 8413642Ssam DEBUG(4, "finds %s\n", "called"); 8513642Ssam while((nf = finds(fsys, system, info, flds)) > 0) { 8613642Ssam DEBUG(4, "getto %s\n", "called"); 8713642Ssam if ((fn = getto(flds)) > 0) { 8813642Ssam fnd = 1; 8913642Ssam Dcf = fn; 9013642Ssam break; 9113642Ssam } 9213642Ssam fcode = (fn == FAIL ? CF_DIAL : fn); 9313642Ssam } 9413642Ssam fclose(fsys); 9513642Ssam 9613642Ssam if (nf <= 0) 9713642Ssam return(fcode ? fcode : nf); 9813642Ssam 9913642Ssam DEBUG(4, "login %s\n", "called"); 10013642Ssam ret = login(nf, flds, fn); 10113642Ssam if (ret < 0) { 10213642Ssam clsacu(); 10313642Ssam return(CF_LOGIN); 10413642Ssam } 10513642Ssam /* rti!trt: avoid passing file to children */ 10613642Ssam fioclex(fn); 10713642Ssam return(fn); 10813642Ssam } 10913642Ssam 11013642Ssam /*** 11113642Ssam * getto(flds) connect to remote machine 11213642Ssam * char *flds[]; 11313642Ssam * 11413642Ssam * return codes: 11513642Ssam * >0 - file number - ok 11613642Ssam * FAIL - failed 11713642Ssam */ 11813642Ssam 11913642Ssam getto(flds) 12013642Ssam register char *flds[]; 12113642Ssam { 12213642Ssam register struct condev *cd; 12313642Ssam int nulldev(), diropn(); 12413642Ssam 12513642Ssam DEBUG(4, "call: no. %s ", flds[F_PHONE]); 12613642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 12713642Ssam 12813642Ssam CU_end = nulldev; 12913642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 13013642Ssam if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) { 13113642Ssam DEBUG(4, "Using %s to call\n", cd->CU_meth); 13213642Ssam return((*(cd->CU_gen))(flds)); 13313642Ssam } 13413642Ssam } 13513642Ssam logent(flds[F_LINE], "getto: Can't find, using DIR"); 13613642Ssam return(diropn(flds)); /* search failed, so use direct */ 13713642Ssam } 13813642Ssam 13913642Ssam /*** 14013642Ssam * clsacu() close call unit 14113642Ssam * 14213642Ssam * return codes: none 14313642Ssam */ 14413642Ssam 14513642Ssam int (*CU_end)() = nulldev; 14613642Ssam clsacu() 14713642Ssam { 14813642Ssam (*(CU_end))(Dcf); 14913642Ssam if (close(Dcf) == 0) { 15013642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 15113642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 15213642Ssam } 15313642Ssam Dcf = -1; 15413642Ssam CU_end = nulldev; 15513642Ssam } 15613642Ssam 15713642Ssam /*** 15813642Ssam * exphone - expand phone number for given prefix and number 15913642Ssam * 16013642Ssam * return code - none 16113642Ssam */ 16213642Ssam 16313642Ssam exphone(in, out) 16413642Ssam register char *in, *out; 16513642Ssam { 16613642Ssam FILE *fn; 16713642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 16813642Ssam char buf[BUFSIZ]; 16913642Ssam register char *s1; 17013642Ssam 17113642Ssam if (!isalpha(*in)) { 17213642Ssam strcpy(out, in); 17313642Ssam return; 17413642Ssam } 17513642Ssam 17613642Ssam s1=pre; 17713642Ssam while (isalpha(*in)) 17813642Ssam *s1++ = *in++; 17913642Ssam *s1 = '\0'; 18013642Ssam s1 = npart; 18113642Ssam while (*in != '\0') 18213642Ssam *s1++ = *in++; 18313642Ssam *s1 = '\0'; 18413642Ssam 18513642Ssam tpre[0] = '\0'; 18613642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 18713642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 18813642Ssam else { 18913642Ssam while (cfgets(buf, BUFSIZ, fn)) { 19013642Ssam sscanf(buf, "%s%s", p, tpre); 19113642Ssam if (strcmp(p, pre) == SAME) 19213642Ssam goto found; 19313642Ssam tpre[0] = '\0'; 19413642Ssam } 19513642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 19613642Ssam found:; 19713642Ssam fclose(fn); 19813642Ssam } 19913642Ssam 20013642Ssam strcpy(out, tpre); 20113642Ssam strcat(out, npart); 20213642Ssam return; 20313642Ssam } 20413642Ssam 20513642Ssam /*** 20613642Ssam * rddev - read and decode a line from device file 20713642Ssam * 20813642Ssam * return code - FAIL at end-of file; 0 otherwise 20913642Ssam */ 21013642Ssam 21113642Ssam rddev(fp, dev) 21213642Ssam register struct Devices *dev; 21313642Ssam FILE *fp; 21413642Ssam { 21513642Ssam char *fdig(); 21613642Ssam char buf[BUFSIZ]; 21713642Ssam int na; 21813642Ssam 21913642Ssam if (!cfgets(buf, BUFSIZ, fp)) 22013642Ssam return(FAIL); 22113642Ssam 22213642Ssam na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line, 22313642Ssam dev->D_calldev, dev->D_class, dev->D_brand); 22413642Ssam ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0); 22513642Ssam if (na != 5) dev->D_brand[0] = '\0'; 22613642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 22713642Ssam return(0); 22813642Ssam } 22913642Ssam 23013642Ssam /*** 23113642Ssam * finds(fsys, sysnam, info, flds) set system attribute vector 23213642Ssam * 23313642Ssam * return codes: 23413642Ssam * >0 - number of arguments in vector - succeeded 23513642Ssam * CF_SYSTEM - system name not found 23613642Ssam * CF_TIME - wrong time to call 23713642Ssam */ 23813642Ssam 23913642Ssam finds(fsys, sysnam, info, flds) 24013642Ssam char *sysnam, info[], *flds[]; 24113642Ssam FILE *fsys; 24213642Ssam { 24313642Ssam char sysn[8]; 24413642Ssam int na; 24513642Ssam int fcode = 0; 24613642Ssam 24713642Ssam /* format of fields 24813642Ssam * 0 name; 24913642Ssam * 1 time 25013642Ssam * 2 acu/hardwired 25113642Ssam * 3 speed 25213642Ssam * etc 25313642Ssam */ 25413642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 25513642Ssam na = getargs(info, flds); 25613642Ssam sprintf(sysn, "%.7s", flds[F_NAME]); 25713642Ssam if (strcmp(sysnam, sysn) != SAME) 25813642Ssam continue; 25913642Ssam if (ifdate(flds[F_TIME])) 26013642Ssam /* found a good entry */ 26113642Ssam return(na); 26213642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 26313642Ssam fcode = CF_TIME; 26413642Ssam } 26513642Ssam return(fcode ? fcode : CF_SYSTEM); 26613642Ssam } 26713642Ssam 26813642Ssam /*** 26913642Ssam * login(nf, flds, dcr) do login conversation 27013642Ssam * char *flds[]; 27113642Ssam * int nf; 27213642Ssam * 27313642Ssam * return codes: 0 | FAIL 27413642Ssam */ 27513642Ssam 27613642Ssam login(nf, flds, fn) 27713642Ssam register char *flds[]; 27813642Ssam int nf, fn; 27913642Ssam { 28013642Ssam register char *want, *altern; 28113642Ssam extern char *index(); 28213642Ssam int k, ok; 28313642Ssam 28413642Ssam ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf); 28513642Ssam for (k = F_LOGIN; k < nf; k += 2) { 28613642Ssam want = flds[k]; 28713642Ssam ok = FAIL; 28813642Ssam while (ok != 0) { 28913642Ssam altern = index(want, '-'); 29013642Ssam if (altern != NULL) 29113642Ssam *altern++ = '\0'; 29213642Ssam DEBUG(4, "wanted %s ", want); 29313642Ssam ok = expect(want, fn); 29413642Ssam DEBUG(4, "got %s\n", ok ? "?" : "that"); 29513642Ssam if (ok == 0) 29613642Ssam break; 29713642Ssam if (altern == NULL) { 29813642Ssam logent("LOGIN", "FAILED"); 29913642Ssam /* close *not* needed here. rti!trt */ 30013642Ssam return(FAIL); 30113642Ssam } 30213642Ssam want = index(altern, '-'); 30313642Ssam if (want != NULL) 30413642Ssam *want++ = '\0'; 30513642Ssam sendthem(altern, fn); 30613642Ssam } 30713642Ssam sleep(2); 30813642Ssam if (k+1 < nf) 30913642Ssam sendthem(flds[k+1], fn); 31013642Ssam } 31113642Ssam return(0); 31213642Ssam } 31313642Ssam 31413642Ssam 31513642Ssam /* rti!trt: conditional table generation to support odd speeds */ 31613642Ssam /* Suggested in n44a.139 by n44!dan (Dan Ts'o) */ 31713642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 31813642Ssam #ifdef B50 31913642Ssam { 50, B50}, 32013642Ssam #endif 32113642Ssam #ifdef B75 32213642Ssam { 75, B75}, 32313642Ssam #endif 32413642Ssam #ifdef B110 32513642Ssam { 110, B110}, 32613642Ssam #endif 32713642Ssam #ifdef B150 32813642Ssam { 150, B150}, 32913642Ssam #endif 33013642Ssam #ifdef B200 33113642Ssam { 200, B200}, 33213642Ssam #endif 33313642Ssam #ifdef B300 33413642Ssam { 300, B300}, 33513642Ssam #endif 33613642Ssam #ifdef B600 33713642Ssam {600, B600}, 33813642Ssam #endif 33913642Ssam #ifdef B1200 34013642Ssam {1200, B1200}, 34113642Ssam #endif 34213642Ssam #ifdef B1800 34313642Ssam {1800, B1800}, 34413642Ssam #endif 34513642Ssam #ifdef B2000 34613642Ssam {2000, B2000}, 34713642Ssam #endif 34813642Ssam #ifdef B2400 34913642Ssam {2400, B2400}, 35013642Ssam #endif 35113642Ssam #ifdef B3600 35213642Ssam {3600, B3600}, 35313642Ssam #endif 35413642Ssam #ifdef B4800 35513642Ssam {4800, B4800}, 35613642Ssam #endif 35713642Ssam #ifdef B7200 35813642Ssam {7200, B7200}, 35913642Ssam #endif 36013642Ssam #ifdef B9600 36113642Ssam {9600, B9600}, 36213642Ssam #endif 36313642Ssam #ifdef B19200 36413642Ssam {19200,B19200}, 36513642Ssam #endif 36613642Ssam {0, 0} 36713642Ssam }; 36813642Ssam 36913642Ssam /*** 37013642Ssam * fixline(tty, spwant) set speed/echo/mode... 37113642Ssam * int tty, spwant; 37213642Ssam * 37313642Ssam * return codes: none 37413642Ssam */ 37513642Ssam 37613642Ssam fixline(tty, spwant) 37713642Ssam int tty, spwant; 37813642Ssam { 37913642Ssam #ifdef SYSIII 38013642Ssam struct termio ttbuf; 38113642Ssam #endif 38213642Ssam #ifndef SYSIII 38313642Ssam struct sgttyb ttbuf; 38413642Ssam #endif 38513642Ssam register struct sg_spds *ps; 38613642Ssam int speed = -1; 38713642Ssam int ret; 38813642Ssam 38913642Ssam for (ps = spds; ps->sp_val; ps++) 39013642Ssam if (ps->sp_val == spwant) 39113642Ssam speed = ps->sp_name; 39213642Ssam ASSERT(speed >= 0, "BAD SPEED", "", speed); 39313642Ssam #ifdef SYSIII 39413642Ssam ioctl(tty, TCGETA, &ttbuf); 39513642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 39613642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 39713642Ssam ttbuf.c_iflag = (ushort)0; 39813642Ssam ttbuf.c_oflag = (ushort)0; 39913642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 40013642Ssam ttbuf.c_lflag = (ushort)0; 40113642Ssam ttbuf.c_cc[VMIN] = 6; 40213642Ssam ttbuf.c_cc[VTIME] = 1; 40313642Ssam ret = ioctl(tty, TCSETA, &ttbuf); 40413642Ssam #endif 40513642Ssam #ifndef SYSIII 40613642Ssam ioctl(tty, TIOCGETP, &ttbuf); 40713642Ssam ttbuf.sg_flags = (ANYP|RAW); 40813642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 40913642Ssam ret = ioctl(tty, TIOCSETP, &ttbuf); 41013642Ssam #endif 41113642Ssam ASSERT(ret >= 0, "RETURN FROM STTY", "", ret); 41213642Ssam #ifndef SYSIII 41313642Ssam ioctl(tty, TIOCHPCL, STBNULL); 41413642Ssam ioctl(tty, TIOCEXCL, STBNULL); 41513642Ssam #endif 41613642Ssam return; 41713642Ssam } 41813642Ssam 41913642Ssam 42013642Ssam /* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */ 42113642Ssam /* Actually, the 'expect' algorithm should be rewritten. */ 42213642Ssam #define MR 1000 42313642Ssam 42413642Ssam 42513642Ssam /*** 42613642Ssam * expect(str, fn) look for expected string 42713642Ssam * char *str; 42813642Ssam * 42913642Ssam * return codes: 43013642Ssam * 0 - found 43113642Ssam * FAIL - lost line or too many characters read 43213642Ssam * some character - timed out 43313642Ssam */ 43413642Ssam 43513642Ssam expect(str, fn) 43613642Ssam register char *str; 43713642Ssam int fn; 43813642Ssam { 439*14592Skarels char rdvec[MR]; 44013642Ssam register char *rp = rdvec; 44113642Ssam int kr; 44213642Ssam char nextch; 44313642Ssam 44413642Ssam if (strcmp(str, "\"\"") == SAME) 44513642Ssam return(0); 44613642Ssam *rp = 0; 44713642Ssam if (setjmp(Sjbuf)) { 44813642Ssam return(FAIL); 44913642Ssam } 45013642Ssam signal(SIGALRM, alarmtr); 45113642Ssam /* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */ 45213642Ssam alarm(MAXMSGTIME); 45313642Ssam while (notin(str, rdvec)) { 45413642Ssam kr = read(fn, &nextch, 1); 45513642Ssam if (kr <= 0) { 45613642Ssam alarm(0); 45713642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 45813642Ssam logent("LOGIN", "LOST LINE"); 45913642Ssam return(FAIL); 46013642Ssam } 46113642Ssam { 46213642Ssam int c; 46313642Ssam c = nextch & 0177; 46413642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 46513642Ssam } 46613642Ssam if ((*rp = nextch & 0177) != '\0') 46713642Ssam rp++; 46813642Ssam /* Check rdvec before null termination -- cmcl2!salkind */ 46913642Ssam if (rp >= rdvec + MR) { 47013642Ssam alarm(0); 47113642Ssam return(FAIL); 47213642Ssam } 47313642Ssam *rp = '\0'; 47413642Ssam } 47513642Ssam alarm(0); 47613642Ssam return(0); 47713642Ssam } 47813642Ssam 47913642Ssam 48013642Ssam /* 48113642Ssam * Determine next file descriptor that would be allocated. 48213642Ssam * This permits later closing of a file whose open was interrupted. 48313642Ssam * It is a UNIX kernel problem, but it has to be handled. 48413642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 48513642Ssam */ 48613642Ssam getnextfd() 48713642Ssam { 48813642Ssam close(next_fd = open("/", 0)); 48913642Ssam } 49013642Ssam 49113642Ssam /*** 49213642Ssam * sendthem(str, fn) send line of login sequence 49313642Ssam * char *str; 49413642Ssam * 49513642Ssam * return codes: none 49613642Ssam */ 49713642Ssam 49813642Ssam sendthem(str, fn) 49913642Ssam register char *str; 50013642Ssam int fn; 50113642Ssam { 50213642Ssam register char *strptr; 50313642Ssam int i, n, cr = 1; 50413642Ssam static int p_init = 0; 50513642Ssam 50613642Ssam /* Note: debugging authorized only for privileged users */ 50713642Ssam DEBUG(5, "send %s\n", str); 50813642Ssam 50913642Ssam if (!p_init) { 51013642Ssam p_init++; 51113642Ssam bld_partab(P_EVEN); 51213642Ssam } 51313642Ssam 51413642Ssam if (prefix("BREAK", str)) { 51513642Ssam sscanf(&str[5], "%1d", &i); 51613642Ssam if (i <= 0 || i > 10) 51713642Ssam i = 3; 51813642Ssam /* send break */ 51913642Ssam genbrk(fn, i); 52013642Ssam return; 52113642Ssam } 52213642Ssam 52313642Ssam if (prefix("PAUSE", str)) { 52413642Ssam sscanf(&str[5], "%1d", &i); 52513642Ssam if (i <= 0 || i > 10) 52613642Ssam i = 3; 52713642Ssam /* pause for a while */ 52813642Ssam sleep((unsigned)i); 52913642Ssam return; 53013642Ssam } 53113642Ssam 53213642Ssam if (strcmp(str, "EOT") == SAME) { 53313642Ssam p_chwrite(fn, '\04'); 53413642Ssam return; 53513642Ssam } 53613642Ssam 53713642Ssam /* LF, CR, and "" courtesy unc!smb */ 53813642Ssam /* Send a '\n' */ 53913642Ssam if (strcmp(str, "LF") == SAME) 54013642Ssam str = "\\n\\c"; 54113642Ssam 54213642Ssam /* Send a '\r' */ 54313642Ssam if (strcmp(str, "CR") == SAME) 54413642Ssam str = "\\r\\c"; 54513642Ssam 54613642Ssam /* Set parity as needed */ 54713642Ssam if (strcmp(str, "P_ZERO") == SAME) { 54813642Ssam bld_partab(P_ZERO); 54913642Ssam return; 55013642Ssam } 55113642Ssam if (strcmp(str, "P_ONE") == SAME) { 55213642Ssam bld_partab(P_ONE); 55313642Ssam return; 55413642Ssam } 55513642Ssam if (strcmp(str, "P_EVEN") == SAME) { 55613642Ssam bld_partab(P_EVEN); 55713642Ssam return; 55813642Ssam } 55913642Ssam if (strcmp(str, "P_ODD") == SAME) { 56013642Ssam bld_partab(P_ODD); 56113642Ssam return; 56213642Ssam } 56313642Ssam 56413642Ssam /* If "", just send '\r' */ 56513642Ssam if (strcmp(str, "\"\"") != SAME) 56613642Ssam for (strptr = str; *strptr; strptr++) { 56713642Ssam if (*strptr == '\\') switch(*++strptr) { 56813642Ssam case 's': 56913642Ssam DEBUG(5, "BLANK\n", ""); 57013642Ssam *strptr = ' '; 57113642Ssam break; 57213642Ssam case 'd': 57313642Ssam DEBUG(5, "DELAY\n", ""); 57413642Ssam sleep(1); 57513642Ssam continue; 57613642Ssam case 'r': 57713642Ssam DEBUG(5, "RETURN\n", ""); 57813642Ssam *strptr = '\r'; 57913642Ssam break; 58013642Ssam case 'b': 58113642Ssam if (isdigit(*(strptr+1))) { 58213642Ssam i = (*++strptr - '0'); 58313642Ssam if (i <= 0 || i > 10) 58413642Ssam i = 3; 58513642Ssam } else 58613642Ssam i = 3; 58713642Ssam /* send break */ 58813642Ssam genbrk(fn, i); 58913642Ssam continue; 59013642Ssam case 'c': 59113642Ssam if (*(strptr+1) == '\0') { 59213642Ssam DEBUG(5, "NO CR\n", ""); 59313642Ssam cr = 0; 59413642Ssam continue; 59513642Ssam } 59613642Ssam DEBUG(5, "NO CR - MIDDLE IGNORED\n", ""); 59713642Ssam continue; 59813642Ssam default: 59913642Ssam if (isdigit(strptr[1])) { 60013642Ssam i = 0; 60113642Ssam n = 0; 60213642Ssam while (isdigit(strptr[1]) && ++n <= 3) 60313642Ssam i = i*8 + (*++strptr - '0'); 60413642Ssam p_chwrite(fn, i); 60513642Ssam continue; 60613642Ssam } 60713642Ssam DEBUG(5, "BACKSLASH\n", ""); 60813642Ssam strptr--; 60913642Ssam } 61013642Ssam p_chwrite(fn, *strptr); 61113642Ssam } 61213642Ssam 61313642Ssam /* '\n' changed to '\r'--a better default. rti!trt */ 61413642Ssam if (cr) 61513642Ssam p_chwrite(fn, '\r'); 61613642Ssam return; 61713642Ssam } 61813642Ssam 61913642Ssam p_chwrite(fd, c) 62013642Ssam int fd; 62113642Ssam int c; 62213642Ssam { 62313642Ssam char t[2]; 62413642Ssam 62513642Ssam t[0] = par_tab[c&0177]; 62613642Ssam t[1] = '\0'; 62713642Ssam ASSERT(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]); 62813642Ssam } 62913642Ssam 63013642Ssam /* 63113642Ssam * generate parity table for use by p_chwrite. 63213642Ssam */ 63313642Ssam bld_partab(type) 63413642Ssam int type; 63513642Ssam { 63613642Ssam register int i, j, n; 63713642Ssam 63813642Ssam for (i = 0; i < sizeof(par_tab); i++) { 63913642Ssam n = 0; 64013642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 64113642Ssam n++; 64213642Ssam par_tab[i] = i; 64313642Ssam if (type == P_ONE 64413642Ssam || (type == P_EVEN && (n&01) != 0) 64513642Ssam || (type == P_ODD && (n&01) == 0)) 64613642Ssam par_tab[i] |= sizeof(par_tab); 64713642Ssam } 64813642Ssam } 64913642Ssam 65013642Ssam #define BSPEED B150 65113642Ssam 65213642Ssam /*** 65313642Ssam * genbrk send a break 65413642Ssam * 65513642Ssam * return codes; none 65613642Ssam */ 65713642Ssam 65813642Ssam genbrk(fn, bnulls) 65913642Ssam register int fn, bnulls; 66013642Ssam { 66113642Ssam register int ret; 66213642Ssam #ifdef SYSIII 66313642Ssam ret = ioctl(fn, TCSBRK, STBNULL); 66413642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 66513642Ssam #endif 66613642Ssam #ifndef SYSIII 66713642Ssam #ifdef TIOCSBRK 66813642Ssam ret = ioctl(fn, TIOCSBRK, STBNULL); 66913642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 67013642Ssam #ifdef TIOCCBRK 67113642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 67213642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 67313642Ssam sleep(1); 67413642Ssam ret = ioctl(fn, TIOCCBRK, STBNULL); 67513642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 67613642Ssam #endif 67713642Ssam DEBUG(4, "ioctl 1 second break\n", STBNULL); 67813642Ssam #else 67913642Ssam struct sgttyb ttbuf; 68013642Ssam register int sospeed; 68113642Ssam 68213642Ssam ret = ioctl(fn, TIOCGETP, &ttbuf); 68313642Ssam sospeed = ttbuf.sg_ospeed; 68413642Ssam ttbuf.sg_ospeed = BSPEED; 68513642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 68613642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 68713642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 68813642Ssam ttbuf.sg_ospeed = sospeed; 68913642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 69013642Ssam ret = write(fn, "@", 1); 69113642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 69213642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 69313642Ssam #endif 69413642Ssam #endif 69513642Ssam } 69613642Ssam 69713642Ssam 69813642Ssam /*** 69913642Ssam * notin(sh, lg) check for occurrence of substring "sh" 70013642Ssam * char *sh, *lg; 70113642Ssam * 70213642Ssam * return codes: 70313642Ssam * 0 - found the string 70413642Ssam * 1 - not in the string 70513642Ssam */ 70613642Ssam 70713642Ssam notin(sh, lg) 70813642Ssam register char *sh, *lg; 70913642Ssam { 71013642Ssam while (*lg != '\0') { 71113642Ssam /* Dave Martingale: permit wild cards in 'expect' */ 71213642Ssam if (wprefix(sh, lg)) 71313642Ssam return(0); 71413642Ssam else 71513642Ssam lg++; 71613642Ssam } 71713642Ssam return(1); 71813642Ssam } 71913642Ssam 72013642Ssam 72113642Ssam /******* 72213642Ssam * ifdate(s) 72313642Ssam * char *s; 72413642Ssam * 72513642Ssam * ittvax!swatt 72613642Ssam * Allow multiple date specifications separated by '|'. 72713642Ssam * Calls ifadate, formerly "ifdate". 72813642Ssam * 72913642Ssam * return codes: 73013642Ssam * see ifadate 73113642Ssam */ 73213642Ssam 73313642Ssam ifdate(s) 73413642Ssam char *s; 73513642Ssam { 73613642Ssam register char *p; 73713642Ssam register int ret; 73813642Ssam 73913642Ssam for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|')) 74013642Ssam if (ret = ifadate(p)) 74113642Ssam return(ret); 74213642Ssam return(0); 74313642Ssam } 74413642Ssam 74513642Ssam 74613642Ssam /******* 74713642Ssam * ifadate(s) 74813642Ssam * char *s; 74913642Ssam * 75013642Ssam * ifadate - this routine will check a string (s) 75113642Ssam * like "MoTu0800-1730" to see if the present 75213642Ssam * time is within the given limits. 75313642Ssam * SIDE EFFECT - Retrytime is set 75413642Ssam * 75513642Ssam * String alternatives: 75613642Ssam * Wk - Mo thru Fr 75713642Ssam * zero or one time means all day 75813642Ssam * Any - any day 75913642Ssam * 76013642Ssam * return codes: 76113642Ssam * 0 - not within limits 76213642Ssam * 1 - within limits 76313642Ssam */ 76413642Ssam 76513642Ssam ifadate(s) 76613642Ssam char *s; 76713642Ssam { 76813642Ssam static char *days[]={ 76913642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 77013642Ssam }; 77113642Ssam time_t clock; 77213642Ssam int rtime; 77313642Ssam int i, tl, th, tn, flag, dayok=0; 77413642Ssam struct tm *localtime(); 77513642Ssam struct tm *tp; 77613642Ssam char *index(); 77713642Ssam char *p; 77813642Ssam 77913642Ssam /* pick up retry time for failures */ 78013642Ssam /* global variable Retrytime is set here */ 78113642Ssam if ((p = index(s, ',')) == NULL) { 78213642Ssam Retrytime = RETRYTIME; 78313642Ssam } 78413642Ssam else { 78513642Ssam i = sscanf(p+1, "%d", &rtime); 78613642Ssam if (i < 1 || rtime < 5) 78713642Ssam rtime = 5; 78813642Ssam Retrytime = rtime * 60; 78913642Ssam } 79013642Ssam 79113642Ssam time(&clock); 79213642Ssam tp = localtime(&clock); 79313642Ssam while (isalpha(*s)) { 79413642Ssam for (i = 0; days[i]; i++) { 79513642Ssam if (prefix(days[i], s)) 79613642Ssam if (tp->tm_wday == i) 79713642Ssam dayok = 1; 79813642Ssam } 79913642Ssam 80013642Ssam if (prefix("Wk", s)) 80113642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 80213642Ssam dayok = 1; 80313642Ssam if (prefix("Any", s)) 80413642Ssam dayok = 1; 80513642Ssam s++; 80613642Ssam } 80713642Ssam 80813642Ssam if (dayok == 0) 80913642Ssam return(0); 81013642Ssam i = sscanf(s, "%d-%d", &tl, &th); 81113642Ssam tn = tp->tm_hour * 100 + tp->tm_min; 81213642Ssam if (i < 2) 81313642Ssam return(1); 81413642Ssam if (th < tl) 81513642Ssam flag = 0; /* set up for crossover 2400 test */ 81613642Ssam else 81713642Ssam flag = 1; 81813642Ssam if ((tn >= tl && tn <= th) 81913642Ssam || (tn >= th && tn <= tl)) /* test for crossover 2400 */ 82013642Ssam return(flag); 82113642Ssam else 82213642Ssam return(!flag); 82313642Ssam } 82413642Ssam 82513642Ssam 82613642Ssam /*** 82713642Ssam * char * 82813642Ssam * lastc(s) return pointer to last character 82913642Ssam * char *s; 83013642Ssam * 83113642Ssam */ 83213642Ssam 83313642Ssam char * 83413642Ssam lastc(s) 83513642Ssam register char *s; 83613642Ssam { 83713642Ssam while (*s != '\0') s++; 83813642Ssam return(s); 83913642Ssam } 84013642Ssam 84113642Ssam 84213642Ssam /*** 84313642Ssam * char * 84413642Ssam * fdig(cp) find first digit in string 84513642Ssam * 84613642Ssam * return - pointer to first digit in string or end of string 84713642Ssam */ 84813642Ssam 84913642Ssam char * 85013642Ssam fdig(cp) 85113642Ssam register char *cp; 85213642Ssam { 85313642Ssam register char *c; 85413642Ssam 85513642Ssam for (c = cp; *c; c++) 85613642Ssam if (*c >= '0' && *c <= '9') 85713642Ssam break; 85813642Ssam return(c); 85913642Ssam } 86013642Ssam 86113642Ssam 86213642Ssam /* 86313642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 86413642Ssam * Strings are compared as if they contain all capital letters. 86513642Ssam */ 86613642Ssam 86713642Ssam snccmp(s1, s2) 86813642Ssam register char *s1, *s2; 86913642Ssam { 87013642Ssam char c1, c2; 87113642Ssam 87213642Ssam if (islower(*s1)) c1 = toupper(*s1); 87313642Ssam else c1 = *s1; 87413642Ssam if (islower(*s2)) c2 = toupper(*s2); 87513642Ssam else c2 = *s2; 87613642Ssam 87713642Ssam while (c1 == c2) { 87813642Ssam if (*s1++=='\0') 87913642Ssam return(0); 88013642Ssam s2++; 88113642Ssam if (islower(*s1)) c1 = toupper(*s1); 88213642Ssam else c1 = *s1; 88313642Ssam if (islower(*s2)) c2 = toupper(*s2); 88413642Ssam else c2 = *s2; 88513642Ssam } 88613642Ssam return(c1 - c2); 88713642Ssam } 888