/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "uucp.h" #include GLOBAL char _Protocol[40]; /* working protocol string */ static char _ProtoSys[40]; /* protocol string from Systems file entry */ static char _ProtoDev[40]; /* protocol string from Devices file entry */ EXTERN char _ProtoCfg[]; /* protocol string from Config file entry */ EXTERN jmp_buf Sjbuf; EXTERN unsigned expecttime; GLOBAL int Modemctrl; EXTERN void alarmtr(); static void addProto(), mergeProto(), removeProto(); static char *nextProto(); EXTERN char *findProto(); static void getProto(); static int finds(); EXTERN int getto(); /* make this static when ct uses altconn() */ EXTERN int chat(), rddev(), expect(), wrstr(), wrchr(); EXTERN int processdev(), getdevline(), getsysline(), sysaccess(); EXTERN int clear_hup(); EXTERN char *currsys(), *currdev(); static int finds(); static int wait_for_hangup(), expect_str(); EXTERN void sendthem(), nap(); static int notin(), ifdate(), classmatch(); GLOBAL char *Myline = CNULL; /* to force which line will be used */ GLOBAL char *Mytype = CNULL; /* to force selection of specific device type */ /* * 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. */ GLOBAL int conn(system) char *system; { int nf, fn = FAIL; char *flds[F_MAX+1]; EXTERN void sysreset(); trace1(TR_conn, 0); CDEBUG(4, "conn(%s)\n", system); Uerror = 0; while ((nf = finds(system, flds, F_MAX)) > 0) { fn = getto(flds); CDEBUG(4, "getto ret %d\n", fn); if (fn < 0) continue; if (EQUALS(Progname, "uucico")) { if (chat(nf - F_LOGIN, flds + F_LOGIN, fn,"","") == SUCCESS) { sysreset(); trace1(TR_conn, 1); return (fn); /* successful return */ } /* login failed */ DEBUG(6, "close caller (%d)\n", fn); fd_rmlock(fn); close(fn); if (Dc[0] != NULLCHAR) { /*EMPTY*/ DEBUG(6, "delock line (%s)\n", Dc); } } else { sysreset(); trace1(TR_conn, 1); return (fn); } } /* finds or getto failed */ sysreset(); CDEBUG(1, "Call Failed: %s\n", UERRORTEXT); trace1(TR_conn, 1); return (FAIL); } /* * getto - connect to remote machine * * return codes: * >0 - file number - ok * FAIL - failed */ GLOBAL int getto(flds) char *flds[]; { 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 */ EXTERN void devreset(); trace1(TR_getto, 0); CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]); Uerror = 0; while (tries < TRYCALLS) { if ((status=rddev(flds[F_TYPE], dev, devbuf, D_MAX)) == FAIL) { if (tries == 0 || ++reread >= TRYCALLS) break; devreset(); continue; } /* check class, check (and possibly set) speed */ if (classmatch(flds, dev) != SUCCESS) { DEBUG(7, "Skipping entry in '%s'", currdev()); DEBUG(7, " - class (%s) not wanted.\n", dev[D_CLASS]); continue; } DEBUG(5, "Trying device entry from '%s'.\n", currdev()); 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; } } devreset(); /* reset devices file(s) */ if (status == FAIL && !Uerror) { CDEBUG(1, "Requested Device Type Not Found\n%s", ""); Uerror = SS_NO_DEVICE; } trace1(TR_getto, 1); return (dcf); } /* * classmatch - process 'Any' in Devices and Systems and * determine the correct speed, or match for == */ static int classmatch(flds, dev) char *flds[]; char *dev[]; { /* check class, check (and possibly set) speed */ trace1(TR_classmatch, 0); if (EQUALS(flds[F_CLASS], "Any") && EQUALS(dev[D_CLASS], "Any")) { dev[D_CLASS] = DEFAULT_BAUDRATE; trace1(TR_classmatch, 1); return (SUCCESS); } else if (EQUALS(dev[D_CLASS], "Any")) { dev[D_CLASS] = flds[F_CLASS]; trace1(TR_classmatch, 1); return (SUCCESS); } else if (EQUALS(flds[F_CLASS], "Any") || EQUALS(flds[F_CLASS], dev[D_CLASS])) { trace1(TR_classmatch, 1); return (SUCCESS); } else { trace1(TR_classmatch, 1); 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 */ GLOBAL int rddev(char *type, char *dev[], char *buf, int devcount) { char *commap, d_type[BUFSIZ]; int na; trace1(TR_rddev, 0); while (getdevline(buf, BUFSIZ)) { 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); if (strncmp(dev[D_LINE],"/dev/",5) == 0) { /* since cu (altconn()) strips off leading */ /* "/dev/", do the same here. */ strcpy(dev[D_LINE], &(dev[D_LINE][5])); } /* may have ",M" subfield in D_LINE */ Modemctrl = FALSE; if ((commap = strchr(dev[D_LINE], ',')) != (char *)NULL) { if (strcmp(commap, ",M") == SAME) Modemctrl = TRUE; *commap = '\0'; } /* * D_TYPE field may have protocol subfield, which * must be pulled off before comparing to desired type. */ (void)strcpy(d_type, dev[D_TYPE]); if ((commap = strchr(d_type, ',')) != (char *)NULL) *commap = '\0'; /* to force the requested device type to be used. */ if ((Mytype != NULL) && (!EQUALS(Mytype, d_type))) continue; /* to force the requested line to be used */ if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE]))) continue; bsfix(dev); /* replace \X fields */ if (EQUALS(d_type, type)) { getProto(_ProtoDev, dev[D_TYPE]); trace1(TR_rddev, 1); return (na); } } trace1(TR_rddev, 1); 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 int finds(char *sysnam, char *flds[], int fldcount) { static char *info; /* dynamically allocated BUFSIZ */ int na; /* format of fields * 0 name; * 1 time * 2 acu/hardwired * 3 speed * etc */ trace1(TR_finds, 0); if (sysnam == 0 || *sysnam == 0) { Uerror = SS_BADSYSTEM; trace1(TR_finds, 1); return (FAIL); } if (info == NULL) { info = (char *)malloc(BUFSIZ); if (info == NULL) { DEBUG(1, "malloc failed for info in finds\n", 0); return (0); } } while (getsysline(info, BUFSIZ)) { na = getargs(info, flds, fldcount); bsfix(flds); /* replace \X fields */ if (!EQUALSN(sysnam, flds[F_NAME], MAXBASENAME)) continue; /* check if requested Mytype device type */ if ((Mytype != CNULL) && (!EQUALSN(flds[F_TYPE], Mytype, strlen(Mytype)))) { DEBUG(7, "Skipping entry in '%s'", currsys()); DEBUG(7, " - type (%s) not wanted.\n", flds[F_TYPE]); continue; } else { /*EMPTY*/ DEBUG(5, "Trying entry from '%s'", currsys()); DEBUG(5, " - device type %s.\n", flds[F_TYPE]); } /* OK if not uucico (ie. ct or cu) or the time is right */ if (!EQUALS(Progname, "uucico") || ifdate(flds[F_TIME])) { /* found a good entry */ getProto(_ProtoSys, flds[F_TYPE]); Uerror = 0; trace1(TR_finds, 1); return (na); /* FOUND OK LINE */ } CDEBUG(1, "Wrong Time To Call: %s\n", flds[F_TIME]); Uerror = SS_TIME_WRONG; } if (!Uerror) Uerror = SS_BADSYSTEM; trace1(TR_finds, 1); return (FAIL); } /* * getProto - get the protocol letters from the input string. * input: * str - string from Systems/Devices/Config file, * a ',' delimits the protocol string * e.g. ACU,g or DK,d * output: * str - the , (if present) will be replaced with NULLCHAR * * return: none */ static void getProto(save, str) char *save; char *str; { register char *p; trace1(TR_getProto, 0); *save = NULLCHAR; if ((p=strchr(str, ',')) != NULL) { *p = NULLCHAR; (void) strcpy(save, p+1); DEBUG(7, "Protocol = %s\n", save); } trace1(TR_getProto, 1); return; } /* * check for a specified protocol selection string * return: * protocol string pointer * NULL if none specified for LOGNAME */ GLOBAL char * protoString(valid) char *valid; { char *save; trace1(TR_protoString, 0); save =strdup(valid); _Protocol[0] = '\0'; if (_ProtoSys[0] != '\0') addProto(_ProtoSys, valid); if (_ProtoDev[0] != '\0') addProto(_ProtoDev, valid); if (_ProtoCfg[0] != '\0') addProto(_ProtoCfg, valid); if (_Protocol[0] == '\0') { (void) strcpy(valid, save); (void) strcpy(_Protocol, save); } trace1(TR_protoString, 1); return (_Protocol[0] == NULLCHAR ? NULL : _Protocol); } /* * addProto * * Verify that the desired protocols from the Systems and Devices file * have been compiled into this application. * * desired - list of desired protocols * valid - list of protocols that are compiled in. */ static void addProto (desired, valid) char *desired; char *valid; { register char * protoPtr; register char * wantPtr; trace1(TR_addProto, 0); if (*desired == '\0') { trace1(TR_addProto, 1); return; } if (*(protoPtr = _Protocol) != NULLCHAR) { while (*(protoPtr = nextProto(protoPtr)) != NULLCHAR) { if (*(wantPtr = findProto(desired, *protoPtr)) == NULLCHAR) { removeProto(valid, *protoPtr); removeProto(protoPtr, *protoPtr); } else { mergeProto(protoPtr, wantPtr); protoPtr++; } } } else { wantPtr = desired; while (*(wantPtr = nextProto(wantPtr)) != NULLCHAR) { if (*(findProto(valid, *wantPtr)) != NULLCHAR) { mergeProto(protoPtr, wantPtr); } wantPtr++; } } if (*(protoPtr = _Protocol) != NULLCHAR) { while (*(protoPtr = nextProto(protoPtr)) != NULLCHAR) *(valid++) = *(protoPtr++); *valid = NULLCHAR; } trace1(TR_addProto, 1); return; } /* * mergeProto * * input * char *tostring, *fromstring; */ static void mergeProto(tostring, fromstring) char *tostring, *fromstring; { char buffer[BUFSIZ]; int length; trace1(TR_mergeProto, 0); while (*(tostring = nextProto(tostring)) != NULLCHAR) { if (*tostring == *fromstring) break; else tostring++; } if (*tostring == NULLCHAR) { length = nextProto(fromstring + 1) - fromstring; (void) strncpy(tostring, fromstring, length); *(tostring + length) = NULLCHAR; } else { tostring++; fromstring++; if ((*tostring != '(') && (*fromstring == '(')) { (void) strcpy(buffer, tostring); length = nextProto(fromstring) - fromstring; (void) strncpy(tostring, fromstring, length); (void) strcpy(tostring+length, buffer); } } trace1(TR_mergeProto, 1); return; } /* * removeProto * * char *old * char letter * * return * none */ static void removeProto(string, letter) char *string, letter; { trace1(TR_removeProto, 0); while (*(string = nextProto(string)) != NULLCHAR) { if (*string == letter) (void) strcpy(string, nextProto(string+1)); else string++; } trace1(TR_removeProto, 1); } /* * nextProto * char *string; * return * char * to next non-parameter letter */ static char * nextProto(string) char *string; { trace1(TR_nextProto, 0); if (*string == '(') while (*string != NULLCHAR) if (*(string++) == ')') break; trace1(TR_nextProto, 1); return (string); } /* * findProto * char *desired, * char protoPtr; * return * char *pointer to found or string terminating NULLCHAR */ GLOBAL char * findProto(string, letter) char *string; char letter; { trace1(TR_findProto, 0); while (*(string = nextProto(string)) != NULLCHAR) if (*string == letter) break; else string++; trace1(TR_findProto, 1); return (string); } /* * chat - do conversation * input: * nf - number of fields in flds array * flds - fields from Systems file * fn - write file number * phstr1 - phone number to replace \D * phstr2 - phone number to replace \T * * return codes: 0 | FAIL */ GLOBAL int chat(nf, flds, fn, phstr1, phstr2) char *flds[], *phstr1, *phstr2; int nf, fn; { char *want, *altern; int k, ok; trace3(TR_chat, 0, nf, fn); 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"); trace1(TR_chat, 1); 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); } trace1(TR_chat, 1); return (0); } #define MR 1000 /* * expect(str, fn) look for expected string w/ possible special chars * char *str; * * return codes: * 0 - found * FAIL - lost line or too many characters read * some character - timed out */ GLOBAL int expect(str, fn) char *str; int fn; { register char *bptr, *sptr; char buf[BUFSIZ]; bptr = buf; for (sptr = str; *sptr; sptr++) { if (*sptr == '\\') { switch (*++sptr) { case 'H': *bptr++ = '\0'; if (expect_str(buf, fn) == FAIL) { return (FAIL); } if (wait_for_hangup(fn) == FAIL) { return (FAIL); } bptr = buf; continue; case '\\': *bptr++ = '\\'; continue; default: *bptr++ = '\\'; *bptr++ = *sptr; continue; } } else *bptr++ = *sptr; } *bptr = '\0'; if (expect_str(buf, fn) == FAIL) { return (FAIL); } return (0); } /* * expect_str(str, fn) look for expected string, w/ no special chars * * return codes: * 0 - found * FAIL - too many characters read * some character - timed out */ GLOBAL int expect_str(str, fn) char *str; int fn; { static char rdvec[MR]; char *rp = rdvec; register int kr, c; char nextch; trace2(TR_expect, 0, fn); *rp = 0; CDEBUG(4, "expect: (%s", ""); for (c=0; (kr=str[c]) != 0 ; c++) if (kr < 040) { /*EMPTY*/ CDEBUG(4, "^%c", kr | 0100); } else { /*EMPTY*/ CDEBUG(4, "%c", kr); } CDEBUG(4, ")\n%s", ""); if (EQUALS(str, "\"\"")) { CDEBUG(4, "got it\n%s", ""); trace1(TR_expect, 1); return (0); } if (*str== '\0') { return(0); } if (setjmp(Sjbuf)) { trace1(TR_expect, 1); return (FAIL); } (void) signal(SIGALRM, alarmtr); alarm(expecttime); 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"); trace1(TR_expect, 1); return (FAIL); } c = nextch & 0177; CDEBUG(4, "%s", c < 040 ? "^" : ""); CDEBUG(4, "%c", c < 040 ? c | 0100 : c); if ((*rp = nextch & 0177) != NULLCHAR) rp++; if (rp >= rdvec + MR) { CDEBUG(4, "enough already\n%s", ""); alarm(0); trace1(TR_expect, 1); return (FAIL); } *rp = NULLCHAR; } alarm(0); CDEBUG(4, "got it\n%s", ""); trace1(TR_expect, 1); return (0); } /* * alarmtr() - catch alarm routine for "expect". */ /*ARGSUSED*/ GLOBAL void alarmtr(sig) int sig; { trace2(TR_alarmtr, 0, sig); CDEBUG(6, "timed out\n%s", ""); longjmp(Sjbuf, 1); trace2(TR_alarmtr, 1, sig); } /* * wait_for_hangup() - wait for a hangup to occur on the given device */ int wait_for_hangup(dcf) int dcf; { int rval; char buff[BUFSIZ]; CDEBUG(4, "Waiting for hangup\n%s", ""); while((rval = read(dcf, buff, BUFSIZ)) > 0); if (rval < 0) { return (FAIL); } CDEBUG(4, "Received hangup\n%s", ""); if (clear_hup(dcf) != SUCCESS) { CDEBUG(4, "Unable to clear hup on device\n%s", ""); return (FAIL); } return (SUCCESS); } /* * sendthem(str, fn, phstr1, phstr2) send line of chat sequence * char *str, *phstr; * * return codes: none */ #define FLUSH() {\ if ((bptr - buf) > 0)\ if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS)\ goto err;\ bptr = buf;\ } GLOBAL void sendthem(str, fn, phstr1, phstr2) char *str, *phstr1, *phstr2; int fn; { int sendcr = 1, echocheck = 0; register char *sptr, *bptr; char buf[BUFSIZ]; struct termio ttybuf; /* should be EQUALS, but previous versions had BREAK n for integer n */ trace2(TR_sendthem, 0, fn); if (PREFIX("BREAK", str)) { /* send break */ CDEBUG(5, "BREAK\n%s", ""); (*genbrk)(fn); trace1(TR_sendthem, 1); return; } if (EQUALS(str, "EOT")) { CDEBUG(5, "EOT\n%s", ""); (void) (*Write)(fn, EOTMSG, strlen(EOTMSG)); trace1(TR_sendthem, 1); return; } if (EQUALS(str, "\"\"")) { CDEBUG(5, "\"\"\n%s", ""); str += 2; } bptr = buf; CDEBUG(5, "sendthem (%s", ""); for (sptr = str; *sptr; sptr++) { if (*sptr == '\\') { switch(*++sptr) { /* adjust switches */ case 'c': /* no CR after string */ FLUSH(); if (sptr[1] == NULLCHAR) { CDEBUG(5, "%s", ""); sendcr = 0; } else { /*EMPTY*/ CDEBUG(5, "\n%s", ""); } continue; } /* stash in buf and continue */ switch(*sptr) { case 'D': /* raw phnum */ strcpy(bptr, phstr1); bptr += strlen(bptr); continue; case 'T': /* translated phnum */ strcpy(bptr, phstr2); bptr += strlen(bptr); continue; case 'N': /* null */ *bptr++ = 0; continue; case 's': /* space */ *bptr++ = ' '; continue; case '\\': /* backslash escapes itself */ *bptr++ = *sptr; continue; default: /* send the backslash */ *bptr++ = '\\'; *bptr++ = *sptr; continue; /* flush buf, perform action, and continue */ case 'E': /* echo check on */ FLUSH(); CDEBUG(5, "ECHO CHECK ON\n%s", ""); echocheck = 1; continue; case 'e': /* echo check off */ FLUSH(); CDEBUG(5, "ECHO CHECK OFF\n%s", ""); echocheck = 0; continue; case 'd': /* sleep briefly */ FLUSH(); CDEBUG(5, "DELAY\n%s", ""); sleep(2); continue; case 'p': /* pause momentarily */ FLUSH(); CDEBUG(5, "PAUSE\n%s", ""); nap(HZ/4); /* approximately 1/4 second */ continue; case 'K': /* inline break */ FLUSH(); CDEBUG(5, "BREAK\n%s", ""); (*genbrk)(fn); continue; case 'M': /* modem control - set CLOCAL */ case 'm': /* no modem control - clear CLOCAL */ FLUSH(); CDEBUG(5, ")\n%s CLOCAL ", (*sptr == 'M' ? "set" : "clear")); if ((*Ioctl)(fn, TCGETA, &ttybuf) != 0 ) { /*EMPTY*/ CDEBUG(5, "ignored. TCGETA failed, errno %d", errno); } else { if (*sptr == 'M') ttybuf.c_cflag |= CLOCAL; else ttybuf.c_cflag &= ~CLOCAL; if ((*Ioctl)(fn, TCSETAW, &ttybuf) != 0) /*EMPTY*/ CDEBUG(5, "failed. TCSETAW failed, errno %d", errno); } CDEBUG(5, "\n%s", ""); continue; } } else *bptr++ = *sptr; } if (sendcr) *bptr++ = '\r'; if ((bptr - buf) > 0) (void) wrstr(fn, buf, bptr - buf, echocheck); err: CDEBUG(5, ")\n%s", ""); trace1(TR_sendthem, 1); return; } #undef FLUSH GLOBAL int wrstr(int fn, char *buf, int len, int echocheck) { int i; int dummy; char dbuf[BUFSIZ], *dbptr = dbuf; trace1(TR_wrstr, 0); buf[len] = 0; if (echocheck) { dummy = wrchr(fn, buf, len); trace1(TR_wrstr, 1); return (dummy); } if (Debug >= 5) { if (sysaccess(ACCESS_SYSTEMS) == 0) { /* Systems file access ok */ for (i = 0; i < len; i++) { *dbptr = buf[i]; if (*dbptr < 040) { *dbptr++ = '^'; *dbptr = buf[i] | 0100; } dbptr++; } *dbptr = 0; } else strcpy(dbuf, "????????"); CDEBUG(5, "%s", dbuf); } if ((*Write)(fn, buf, len) != len) { trace1(TR_wrstr, 1); return (FAIL); } trace1(TR_wrstr, 1); return (SUCCESS); } GLOBAL int wrchr(int fn, char *buf, int len) { int i, saccess; char cin, cout; trace2(TR_wrchr, 0, fn); saccess = (sysaccess(ACCESS_SYSTEMS) == 0); /* protect Systems file */ if (setjmp(Sjbuf)) { trace1(TR_wrchr, 1); return (FAIL); } (void) signal(SIGALRM, alarmtr); for (i = 0; i < len; i++) { cout = buf[i]; if (saccess) { /*EMPTY*/ CDEBUG(5, "%s", cout < 040 ? "^" : ""); CDEBUG(5, "%c", cout < 040 ? cout | 0100 : cout); } else { /*EMPTY*/ CDEBUG(5, "?%s", ""); } if (((*Write)(fn, &cout, 1)) != 1) { trace1(TR_wrchr, 1); return (FAIL); } do { (void) alarm(expecttime); if ((*Read)(fn, &cin, 1) != 1) { trace1(TR_wrchr, 1); return (FAIL); } (void) alarm(0); cin &= 0177; if (saccess) { /*EMPTY*/ CDEBUG(5, "%s", cin < 040 ? "^" : ""); CDEBUG(5, "%c", cin < 040 ? cin | 0100 : cin); } else { /*EMPTY*/ CDEBUG(5, "?%s", ""); } } while (cout != (cin & 0177)); } trace1(TR_wrchr, 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 int notin(sh, lg) char *sh, *lg; { trace1(TR_notin, 0); while (*lg != NULLCHAR) { if (PREFIX(sh, lg)) { trace1(TR_notin, 1); return (0); } else lg++; } trace1(TR_notin, 1); 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 int ifdate(s) char *s; { static char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 }; time_t clock; int t__now; char *p; struct tm *tp; trace1(TR_ifdate, 0); 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, "%ld", &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)) { trace1(TR_ifdate, 1); return (1); } /* 0000 crossover? */ if (t__low < t__high) { if (t__low <= t__now && t__now <= t__high) { trace1(TR_ifdate, 1); return (1); } } else if (t__low <= t__now || t__now <= t__high) { trace1(TR_ifdate, 1); return (1); } /* aim at next time slot */ if ((s = index(s, ',')) == NULL) break; } if (*s) s++; } trace1(TR_ifdate, 1); return (0); } /* * char * * fdig(cp) find first digit in string * * return - pointer to first digit in string or end of string */ GLOBAL char * fdig(cp) char *cp; { char *c; trace1(TR_fdig, 0); for (c = cp; *c; c++) if (*c >= '0' && *c <= '9') break; trace1(TR_fdig, 1); return (c); } #ifdef FASTTIMER /* Sleep in increments of 60ths of second. */ GLOBAL void nap (time) register int time; { static int fd; trace2(TR_nap, 0, time); if (fd == 0) fd = open (FASTTIMER, 0); (void) (*Read)(fd, 0, time); trace1(TR_nap, 1); return; } #endif /* FASTTIMER */ #if defined(BSD4_2) || defined(ATTSVR4) /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */ /* This version uses the select system call */ GLOBAL void nap(n) unsigned n; { struct timeval tv; int rc; trace2(TR_nap, 0, n); if (n==0) { trace1(TR_nap, 1); return; } tv.tv_sec = n/60; tv.tv_usec = ((n%60)*1000000L)/60; rc = select(32, 0, 0, 0, &tv); trace1(TR_nap, 1); return; } #endif /* BSD4_2 || ATTSVR4 */ #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! */ GLOBAL void nap(n) unsigned n; { struct tms tbuf; long endtime; int i; trace2(TR_nap, 0, n); if (n > HZ) { /* > second, use sleep, rounding time */ sleep((int) (((n)+HZ/2)/HZ)); trace1(TR_nap, 1); 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++, (void) (i*i)) ; } trace1(TR_nap, 1); return; } #endif /* NONAP */ /* * altconn - place a telephone call to system * from cu when telephone number or direct line used * * return codes: * FAIL - connection failed * >0 - file no. - connect ok * When a failure occurs, Uerror is set. */ GLOBAL int altconn(call) struct call *call; { int fn = FAIL; char *alt[7]; EXTERN char *Myline; /* * replace the Systems file fields * needed for getto(); [F_TYPE] and * [F_PHONE] assignment below. */ alt[F_NAME] = "dummy"; alt[F_TIME] = "Any"; alt[F_TYPE] = ""; alt[F_CLASS] = call->speed; alt[F_PHONE] = ""; alt[F_LOGIN] = ""; alt[6] = NULL; trace1(TR_altconn, 0); CDEBUG(4,"altconn called\r\n%s", ""); /* cu -l dev ... */ /* if is "/dev/device", strip off "/dev/" because must */ /* exactly match entries in Devices file, which usually */ /* omit the "/dev/". if doesn't begin with "/dev/", */ /* either they've omitted the "/dev/" or it's a non- */ /* standard path name. in either case, leave it as is */ if (call->line != NULL) { if (strncmp(call->line, "/dev/", 5) == 0) { Myline = (call->line + 5); } else { Myline = call->line; } } /* cu ... telno */ if (call->telno != NULL) { alt[F_PHONE] = call->telno; alt[F_TYPE] = "ACU"; } else { /* cu direct line */ alt[F_TYPE] = "Direct"; } if (call->type != NULL) alt[F_TYPE] = call->type; fn = getto(alt); CDEBUG(4, "getto ret %d\n", fn); trace1(TR_altconn, 1); return (fn); }