/* @(#)conn.c 1.16 */ #include "uucp.h" VERSION(@(#)conn.c 1.16); static char _ProtoStr[20] = ""; /* protocol string from Systems file entry */ extern jmp_buf Sjbuf; int alarmtr(); static void getProto(); /* static getto(), finds(); PUT this back after altconn is included */ extern getto(); static finds(); static notin(), ifdate(), classmatch(); extern struct caller caller[]; /* Needed for cu for force which line will be used */ #ifdef STANDALONE extern char *Myline; #endif STANDALONE /* * conn - place a telephone call to system and login, etc. * * return codes: * FAIL - connection failed * >0 - file no. - connect ok * When a failure occurs, Uerror is set. */ conn(system) char *system; { int nf, fn = FAIL; char *flds[F_MAX+1]; FILE *fsys; #ifdef MANYSYS int nsys = 0; int lerror = 0; /* local copy so first error is saved */ FILE *sysopen(); #endif CDEBUG(4, "conn(%s)\n", system); #ifndef MANYSYS fsys = fopen(SYSFILE, "r"); ASSERT(fsys != NULL, Ct_OPEN, SYSFILE, errno); #else sysrewind(); while ((fsys = sysopen("r")) != NULL) { nsys++; #endif Uerror = 0; while ((nf = finds(fsys, system, flds, F_MAX)) > 0) { fn = getto(flds); CDEBUG(4, "getto ret %d\n", fn); if (fn < 0) continue; #ifdef STANDALONE fclose(fsys); return(fn); #else !STANDALONE if (chat(nf - F_LOGIN, flds + F_LOGIN, fn,"","") == SUCCESS) { fclose(fsys); return(fn); /* successful return */ } /* login failed */ DEBUG(6, "close caller (%d)\n", fn); close(fn); if (Dc[0] != NULLCHAR) { DEBUG(6, "delock(%s)\n", Dc); delock(Dc); } #endif STANDALONE } /* finds or getto failed */ fclose(fsys); #ifdef MANYSYS if (lerror == 0 && Uerror != SS_BADSYSTEM) lerror = Uerror; CDEBUG(4, "not in this Systems; Uerror %d\n", Uerror); } ASSERT(nsys != 0, Ct_OPEN, SYSFILE, errno); if (lerror) Uerror = lerror; #endif CDEBUG(1, "Call Failed: %s\n", UERRORTEXT); return(FAIL); } /* * getto - connect to remote machine * * return codes: * >0 - file number - ok * FAIL - failed */ getto(flds) char *flds[]; { FILE *dfp; char *dev[D_MAX+2], devbuf[BUFSIZ]; register int status; register int dcf = -1; int reread = 0; int tries = 0; /* count of call attempts - for limit purposes */ CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]); dfp = fopen(DEVFILE, "r"); ASSERT(dfp != NULL, Ct_OPEN, DEVFILE, errno); Uerror = 0; while (tries < TRYCALLS) { if ((status=rddev(dfp, flds[F_TYPE], dev, devbuf, D_MAX)) == FAIL) { if (tries == 0 || ++reread >= TRYCALLS) break; rewind(dfp); continue; } /* check class, check (and possibly set) speed */ if (classmatch(flds, dev) != SUCCESS) continue; if ((dcf = processdev(flds, dev)) >= 0) break; switch(Uerror) { case SS_CANT_ACCESS_DEVICE: case SS_DEVICE_FAILED: case SS_LOCKED_DEVICE: break; default: tries++; break; } } (void) fclose(dfp); if (status == FAIL && !Uerror) { CDEBUG(1, "Requested Device Type Not Found\n", 0); Uerror = SS_NO_DEVICE; } return(dcf); } /* * classmatch - process 'Any' in Devices and Systems and * determine the correct speed, or match for == */ static int classmatch(flds, dev) char *flds[], *dev[]; { /* check class, check (and possibly set) speed */ if (EQUALS(flds[F_CLASS], "Any") && EQUALS(dev[D_CLASS], "Any")) { dev[D_CLASS] = flds[F_CLASS] = DEFAULT_BAUDRATE; return(SUCCESS); } else if (EQUALS(dev[F_CLASS], "Any")) { dev[D_CLASS] = flds[F_CLASS]; return(SUCCESS); } else if (EQUALS(flds[F_CLASS], "Any")) { flds[D_CLASS] = dev[F_CLASS]; return(SUCCESS); } else if (EQUALS(flds[F_CLASS], dev[D_CLASS])) return(SUCCESS); else return(FAIL); } /*** * rddev - find and unpack a line from device file for this caller type * lines starting with whitespace of '#' are comments * * return codes: * >0 - number of arguments in vector - succeeded * FAIL - EOF ***/ rddev(fp, type, dev, buf, devcount) FILE *fp; char *type; char *dev[]; char *buf; { int na; while (fgets(buf, BUFSIZ, fp) != NULL) { if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n' || buf[0] == '\0' || buf[0] == '#') continue; na = getargs(buf, dev, devcount); ASSERT(na >= D_CALLER, "BAD LINE", buf, na); /* For cu -- to force the requested line to be used */ #ifdef STANDALONE if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])) ) continue; #endif STANDALONE bsfix(dev); /* replace \X fields */ if (EQUALS(dev[D_TYPE], type)) return(na); } return(FAIL); } /* * finds - set system attribute vector * * input: * fsys - open Systems file descriptor * sysnam - system name to find * output: * flds - attibute vector from Systems file * fldcount - number of fields in flds * return codes: * >0 - number of arguments in vector - succeeded * FAIL - failed * Uerror set: * 0 - found a line in Systems file * SS_BADSYSTEM - no line found in Systems file * SS_TIME_WRONG - wrong time to call */ static finds(fsys, sysnam, flds, fldcount) char *sysnam, *flds[]; FILE *fsys; { static char info[BUFSIZ]; int na; /* format of fields * 0 name; * 1 time * 2 acu/hardwired * 3 speed * etc */ while (fgets(info, BUFSIZ, fsys) != NULL) { if (info[0] == '#') continue; na = getargs(info, flds, fldcount); bsfix(flds); /* replace \X fields */ if ( !EQUALSN(sysnam, flds[F_NAME], SYSNSIZE)) continue; #ifndef STANDALONE if (ifdate(flds[F_TIME])) { /* found a good entry */ getProto(flds[F_TYPE]); Uerror = 0; return(na); /* FOUND OK LINE */ } CDEBUG(1, "Wrong Time To Call: %s\n", flds[F_TIME]); Uerror = SS_TIME_WRONG; #else !STANDALONE Uerror = 0; return(na); /* FOUND OK LINE */ #endif STANDALONE } if (!Uerror) Uerror = SS_BADSYSTEM; return(FAIL); } /* * getProto - get the protocol letters from the input string. * input: * str - string from Systems file (flds[F_TYPE])--the , * delimits the protocol string * e.g. ACU,g or DK,d * output: * str - the , (if present) will be replaced with NULLCHAR * global ProtoStr will be modified * return: none */ static void getProto(str) char *str; { register char *p; if ( (p=strchr(str, ',')) != NULL) { *p = NULLCHAR; (void) strcpy(_ProtoStr, p+1); DEBUG(7, "ProtoStr = %s\n", _ProtoStr); } else *_ProtoStr = NULLCHAR; } /* * check for a specified protocol selection string * return: * protocol string pointer * NULL if none specified for LOGNAME */ char * protoString() { return(_ProtoStr[0] == NULLCHAR ? NULL : _ProtoStr); } static int _Echoflag; static int _Slowflag; /* * chat - do conversation * input: * flds - fields from Systems file * nf - number of fields in flds array * dcr - write file number * phstr1 - phone number to replace \D * phstr2 - phone number to replace \T * * return codes: 0 | FAIL */ chat(nf, flds, fn, phstr1, phstr2) char *flds[], *phstr1, *phstr2; int nf, fn; { char *want, *altern; extern char *index(); int k, ok; _Echoflag = 0; _Slowflag = 0; for (k = 0; k < nf; k += 2) { want = flds[k]; ok = FAIL; while (ok != 0) { altern = index(want, '-'); if (altern != NULL) *altern++ = NULLCHAR; ok = expect(want, fn); if (ok == 0) break; if (altern == NULL) { Uerror = SS_LOGIN_FAILED; logent(UERRORTEXT, "FAILED"); return(FAIL); } want = index(altern, '-'); if (want != NULL) *want++ = NULLCHAR; sendthem(altern, fn, phstr1, phstr2); } sleep(2); if (flds[k+1]) sendthem(flds[k+1], fn, phstr1, phstr2); } return(0); } #define MR 500 /*** * expect(str, fn) look for expected string * char *str; * * return codes: * 0 - found * FAIL - lost line or too many characters read * some character - timed out */ expect(str, fn) char *str; int fn; { static char rdvec[MR]; char *rp = rdvec; register int kr, c; char nextch; extern errno; *rp = 0; CDEBUG(4, "expect: (", 0); for (c=0; kr=str[c]; c++) if (kr < 040) { CDEBUG(4, "^%c", kr | 0100); } else CDEBUG(4, "%c", kr); CDEBUG(4, ")\n", 0); if (EQUALS(str, "\"\"")) { CDEBUG(4, "got it\n", 0); return(0); } if (setjmp(Sjbuf)) { return(FAIL); } (void) signal(SIGALRM, alarmtr); alarm(MAXEXPECTTIME); while (notin(str, rdvec)) { errno = 0; kr = read(fn, &nextch, 1); if (kr <= 0) { alarm(0); CDEBUG(4, "lost line errno - %d\n", errno); logent("LOGIN", "LOST LINE"); return(FAIL); } c = nextch & 0177; if ((*rp = c) != NULLCHAR) { CDEBUG(4, "%s", c < 040 ? "^" : ""); CDEBUG(4, "%c", c < 040 ? c | 0100 : c); rp++; } if (rp >= rdvec + MR) { CDEBUG(4, "enough already\n", 0); alarm(0); return(FAIL); } *rp = NULLCHAR; } alarm(0); CDEBUG(4, "got it\n", 0); return(0); } /*** * alarmtr() - catch alarm routine for "expect". */ alarmtr() { CDEBUG(6, "timed out\n", 0); longjmp(Sjbuf, 1); } /*** * sendthem(str, fn, phstr1, phstr2) send line of chat sequence * char *str, *phstr; * * return codes: none */ sendthem(str, fn, phstr1, phstr2) char *str, *phstr1, *phstr2; int fn; { int sendcr = 1; register char *sptr, *pptr; if (PREFIX("BREAK", str)) { /* send break */ CDEBUG(5, "BREAK\n", 0); genbrk(fn); return; } if (EQUALS(str, "EOT")) { CDEBUG(5, "EOT\n", 0); (void) write(fn, EOTMSG, strlen(EOTMSG)); return; } if (EQUALS(str, "\"\"")) { CDEBUG(5, "\"\"\n", 0); str += 2; } CDEBUG(5, "sendthem (", ""); if (setjmp(Sjbuf)) /* Timer so echo check doesn't last forever */ goto err; (void) signal(SIGALRM, alarmtr); alarm(MAXEXPECTTIME); for (sptr = str; *sptr; sptr++) { if (*sptr == '\\') switch(*++sptr) { case 'D': for (pptr=phstr1; *pptr; pptr++) if (wrchar(fn, pptr)) goto err; continue; case 'T': for (pptr=phstr2; *pptr; pptr++) if (wrchar(fn, pptr)) goto err; continue; case 'N': *sptr = 0; break; case 'd': CDEBUG(5, "DELAY\n", 0); sleep(2); continue; case 'c': if (*(sptr+1) == NULLCHAR) { CDEBUG(5, "<NO CR>", 0); sendcr = 0; continue; } CDEBUG(5, "<NO CR - MIDDLE IGNORED>\n", 0); continue; case 's': *sptr = ' '; break; case 'p': CDEBUG(5, "PAUSE\n", 0); nap(HZ/4); /* approximately 1/4 second */ continue; case 'E': CDEBUG(5, "ECHO CHECK ON\n", 0); _Echoflag = 1; continue; case 'e': CDEBUG(5, "ECHO CHECK OFF\n", 0); _Echoflag = 0; continue; case 'K': CDEBUG(5, "BREAK\n", 0); genbrk(fn); continue; case 'W': _Slowflag = 1; continue; case 'w': _Slowflag = 0; continue; case '\\': /* backslash escapes itself */ break; default: /* send the backslash */ --sptr; break; } if (wrchar(fn, sptr)) goto err; } if (sendcr) { CDEBUG(5, "^M", 0); (void) write(fn, "\r", 1); } err: alarm(0); CDEBUG(5, ")\n", 0); return; } wrchar(fn, sptr) register int fn; register char *sptr; { if (GRPCHK(getgid())) /* protect Systems file */ { CDEBUG(5, "%s", *sptr < 040 ? "^" : ""); CDEBUG(5, "%c", *sptr < 040 ? *sptr | 0100 : *sptr); } if ((write(fn, sptr, 1)) != 1) return(FAIL); if (_Echoflag) { char chr; while(1) { /* Should set a timer here */ if (read(fn, &chr, 1) != 1) return(FAIL); chr &= 0177; CDEBUG(4, "%s", chr < 040 ? "^" : ""); CDEBUG(4, "%c", chr < 040 ? chr | 0100 : chr); if (chr == ((*sptr) & 0177)) break; } } if (_Slowflag) sleep(1); return(SUCCESS); } /*** * notin(sh, lg) check for occurrence of substring "sh" * char *sh, *lg; * * return codes: * 0 - found the string * 1 - not in the string */ static notin(sh, lg) char *sh, *lg; { while (*lg != NULLCHAR) { if (PREFIX(sh, lg)) return(0); else lg++; } return(1); } /******* * ifdate(s) * char *s; * * ifdate - this routine will check a string (s) * like "MoTu0800-1730" to see if the present * time is within the given limits. * SIDE EFFECT - Retrytime is set to number following ";" * * String alternatives: * Wk - Mo thru Fr * zero or one time means all day * Any - any day * * return codes: * 0 - not within limits * 1 - within limits */ static ifdate(s) char *s; { static char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 }; time_t clock; int t__now; char *p, *rindex(), *index(); struct tm *tp; time(&clock); tp = localtime(&clock); t__now = tp->tm_hour * 100 + tp->tm_min; /* "navy" time */ /* * pick up retry time for failures * global variable Retrytime is set here */ if ((p = rindex(s, ';')) != NULL) if (isdigit(p[1])) { if (sscanf(p+1, "%d", &Retrytime) < 1) Retrytime = 5; /* 5 minutes is error default */ Retrytime *= 60; *p = NULLCHAR; } while (*s) { int i, dayok; for (dayok = 0; (!dayok) && isalpha(*s); s++) { if (PREFIX("Any", s)) dayok = 1; else if (PREFIX("Wk", s)) { if (tp->tm_wday >= 1 && tp->tm_wday <= 5) dayok = 1; } else for (i = 0; days[i]; i++) if (PREFIX(days[i], s)) if (tp->tm_wday == i) dayok = 1; } if (dayok) { int t__low, t__high; while (isalpha(*s)) /* flush remaining day stuff */ s++; if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2) || (t__low == t__high)) return(1); /* 0000 crossover? */ if (t__low < t__high) { if (t__low <= t__now && t__now <= t__high) return(1); } else if (t__low <= t__now || t__now <= t__high) return(1); /* aim at next time slot */ if ((s = index(s, ',')) == NULL) break; } s++; } return(0); } /*** * char * * fdig(cp) find first digit in string * * return - pointer to first digit in string or end of string */ char * fdig(cp) char *cp; { char *c; for (c = cp; *c; c++) if (*c >= '0' && *c <= '9') break; return(c); } #ifdef FASTTIMER /* Sleep in increments of 60ths of second. */ nap (time) register int time; { static int fd; if (fd == 0) fd = open (FASTTIMER, 0); read (fd, 0, time); } #endif FASTTIMER #ifdef BSD4_2 /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */ /* This version, by Mark Horton, uses the select system call */ nap(n) unsigned n; { struct timeval tv; int rc; if (n==0) return; tv.tv_sec = n/60; tv.tv_usec = ((n%60)*1000000L)/60; rc = select(32, 0, 0, 0, &tv); } #endif BSD4_2 #ifdef NONAP /* nap(n) where n is ticks * * loop using n/HZ part of a second * if n represents more than 1 second, then * use sleep(time) where time is the equivalent * seconds rounded off to full seconds * NOTE - this is a rough approximation and chews up * processor resource! */ nap(n) unsigned n; { struct tms tbuf; long endtime; int i; if (n > HZ) { /* > second, use sleep, rounding time */ sleep( (int) (((n)+HZ/2)/HZ) ); return; } /* use timing loop for < 1 second */ endtime = times(&tbuf) + 3*n/4; /* use 3/4 because of scheduler! */ while (times(&tbuf) < endtime) { for (i=0; i<1000; i++, i*i) ; } return; } #endif NONAP