#include "mt.h"
#include "uucp.h"
static char _ProtoSys[40];
static char _ProtoDev[40];
static char _ProtoCfg[];
static jmp_buf Sjbuf;
static unsigned expecttime;
static int Modemctrl;
static void alarmtr(int);
static void getProto(char *, char *);
static int finds(char *, char *[], int);
static int getto(char *[]);
static int chat(int, char *[], int, char *, char *);
static int rddev(char *, char *[], char *, int);
static int expect(char *, int);
static int wrstr(int, char *, int, int);
static int wrchr(int, char *, int);
static int processdev(char *[], char *[]);
static int getdevline(char *, int);
static int getsysline(char *, int);
static int sysaccess(int);
static int clear_hup(int);
#ifndef SMALL
static char *currsys(void);
static char *currdev(void);
#endif
static int wait_for_hangup(int);
static int expect_str(char *, int);
static void sendthem(char *, int, char *, char *);
static void nap(unsigned int);
static int notin(char *, char *);
static int ifdate(char *);
static int classmatch(char *[], char *[]);
static char *Myline = CNULL;
static char *Mytype = CNULL;
static void sysreset(void);
static int
conn(char *system)
{
int nf, fn = FAIL;
char *flds[F_MAX+1];
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();
return (fn);
}
DEBUG(6, "close caller (%d)\n", fn);
fd_rmlock(fn);
(void) close(fn);
if (Dc[0] != NULLCHAR) {
DEBUG(6, "delock line (%s)\n", Dc);
}
} else {
sysreset();
return (fn);
}
}
sysreset();
CDEBUG(1, "Call Failed: %s\n", UERRORTEXT);
return (FAIL);
}
static void devreset(void);
static int
getto(char *flds[])
{
char *dev[D_MAX+2], devbuf[BUFSIZ];
int status;
int dcf = -1;
int reread = 0;
int tries = 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;
}
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();
if (status == FAIL && !Uerror) {
CDEBUG(1, "Requested Device Type Not Found\n%s", "");
Uerror = SS_NO_DEVICE;
}
return (dcf);
}
static int
classmatch(char *flds[], char *dev[])
{
if (EQUALS(flds[F_CLASS], "Any") && EQUALS(dev[D_CLASS], "Any")) {
dev[D_CLASS] = DEFAULT_BAUDRATE;
return (SUCCESS);
} else if (EQUALS(dev[D_CLASS], "Any")) {
dev[D_CLASS] = flds[F_CLASS];
return (SUCCESS);
} else if (EQUALS(flds[F_CLASS], "Any") ||
EQUALS(flds[F_CLASS], dev[D_CLASS]))
return (SUCCESS);
else
return (FAIL);
}
static int
rddev(char *type, char *dev[], char *buf, int devcount)
{
char *commap, d_type[BUFSIZ];
int na;
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) {
(void) strcpy(dev[D_LINE], &(dev[D_LINE][5]));
}
Modemctrl = FALSE;
if ((commap = strchr(dev[D_LINE], ',')) != NULL) {
if (strcmp(commap, ",M") == SAME)
Modemctrl = TRUE;
*commap = '\0';
}
(void) strcpy(d_type, dev[D_TYPE]);
if ((commap = strchr(d_type, ',')) != NULL)
*commap = '\0';
if ((Mytype != NULL) && (!EQUALS(Mytype, d_type)))
continue;
if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])))
continue;
bsfix(dev);
if (EQUALS(d_type, type)) {
getProto(_ProtoDev, dev[D_TYPE]);
return (na);
}
}
return (FAIL);
}
static int
finds(char *sysnam, char *flds[], int fldcount)
{
static char *info;
int na;
if (sysnam == 0 || *sysnam == 0) {
Uerror = SS_BADSYSTEM;
return (FAIL);
}
if (info == NULL) {
info = 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);
if (!EQUALSN(sysnam, flds[F_NAME], MAXBASENAME))
continue;
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 {
DEBUG(5, "Trying entry from '%s'", currsys());
DEBUG(5, " - device type %s.\n", flds[F_TYPE]);
}
if (!EQUALS(Progname, "uucico") || ifdate(flds[F_TIME])) {
getProto(_ProtoSys, flds[F_TYPE]);
Uerror = 0;
return (na);
}
CDEBUG(1, "Wrong Time To Call: %s\n", flds[F_TIME]);
Uerror = SS_TIME_WRONG;
}
if (!Uerror)
Uerror = SS_BADSYSTEM;
return (FAIL);
}
static void
getProto(char *save, char *str)
{
char *p;
*save = NULLCHAR;
if ((p = strchr(str, ',')) != NULL) {
*p = NULLCHAR;
(void) strcpy(save, p+1);
DEBUG(7, "Protocol = %s\n", save);
}
}
static int
chat(int nf, char *flds[], int fn, char *phstr1, char *phstr2)
{
char *want, *altern;
int k, ok;
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);
}
(void) sleep(2);
if (flds[k+1])
sendthem(flds[k+1], fn, phstr1, phstr2);
}
return (0);
}
#define MR 1000
static int
expect(char *str, int fn)
{
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);
}
static int
expect_str(char *str, int fn)
{
static char rdvec[MR];
char *rp = rdvec;
int kr, c;
char nextch;
*rp = 0;
CDEBUG(4, "expect: (%s", "");
for (c = 0; (kr = str[c]) != 0; c++)
if (kr < 040) {
CDEBUG(4, "^%c", kr | 0100);
} else {
CDEBUG(4, "%c", kr);
}
CDEBUG(4, ")\n%s", "");
if (EQUALS(str, "\"\"")) {
CDEBUG(4, "got it\n%s", "");
return (0);
}
if (*str == '\0')
return (0);
if (setjmp(Sjbuf))
return (FAIL);
(void) signal(SIGALRM, alarmtr);
(void) alarm(expecttime);
while (notin(str, rdvec)) {
errno = 0;
kr = (*Read)(fn, &nextch, 1);
if (kr <= 0) {
(void) alarm(0);
CDEBUG(4, "lost line errno - %d\n", errno);
logent("LOGIN", "LOST LINE");
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", "");
(void) alarm(0);
return (FAIL);
}
*rp = NULLCHAR;
}
(void) alarm(0);
CDEBUG(4, "got it\n%s", "");
return (0);
}
static void
alarmtr(int sig)
{
CDEBUG(6, "timed out\n%s", "");
longjmp(Sjbuf, 1);
}
int
wait_for_hangup(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);
}
#define FLUSH() { \
if ((bptr - buf) > 0) \
if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS) \
goto err; \
bptr = buf; \
}
static void
sendthem(char *str, int fn, char *phstr1, char *phstr2)
{
int sendcr = 1, echocheck = 0;
char *sptr, *bptr;
char buf[BUFSIZ];
struct termio ttybuf;
if (PREFIX("BREAK", str)) {
CDEBUG(5, "BREAK\n%s", "");
(*genbrk)(fn);
return;
}
if (EQUALS(str, "EOT")) {
CDEBUG(5, "EOT\n%s", "");
(void) (*Write)(fn, EOTMSG, strlen(EOTMSG));
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) {
case 'c':
FLUSH();
if (sptr[1] == NULLCHAR) {
CDEBUG(5, "<NO CR>%s", "");
sendcr = 0;
} else {
CDEBUG(5, "<NO CR IGNORED>\n%s", "");
}
continue;
}
switch (*sptr) {
case 'D':
(void) strcpy(bptr, phstr1);
bptr += strlen(bptr);
continue;
case 'T':
(void) strcpy(bptr, phstr2);
bptr += strlen(bptr);
continue;
case 'N':
*bptr++ = 0;
continue;
case 's':
*bptr++ = ' ';
continue;
case '\\':
*bptr++ = *sptr;
continue;
default:
*bptr++ = '\\';
*bptr++ = *sptr;
continue;
case 'E':
FLUSH();
CDEBUG(5, "ECHO CHECK ON\n%s", "");
echocheck = 1;
continue;
case 'e':
FLUSH();
CDEBUG(5, "ECHO CHECK OFF\n%s", "");
echocheck = 0;
continue;
case 'd':
FLUSH();
CDEBUG(5, "DELAY\n%s", "");
(void) sleep(2);
continue;
case 'p':
FLUSH();
CDEBUG(5, "PAUSE\n%s", "");
nap(HZ/4);
continue;
case 'K':
FLUSH();
CDEBUG(5, "BREAK\n%s", "");
(*genbrk)(fn);
continue;
case 'M':
case 'm':
FLUSH();
CDEBUG(5, ")\n%s CLOCAL ",
(*sptr == 'M' ? "set" : "clear"));
if ((*Ioctl)(fn, TCGETA, &ttybuf) != 0) {
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)
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", "");
}
#undef FLUSH
static int
wrstr(int fn, char *buf, int len, int echocheck)
{
int i;
char dbuf[BUFSIZ], *dbptr = dbuf;
buf[len] = 0;
if (echocheck)
return (wrchr(fn, buf, len));
if (Debug >= 5) {
if (sysaccess(ACCESS_SYSTEMS) == 0) {
for (i = 0; i < len; i++) {
*dbptr = buf[i];
if (*dbptr < 040) {
*dbptr++ = '^';
*dbptr = buf[i] | 0100;
}
dbptr++;
}
*dbptr = 0;
} else
(void) strcpy(dbuf, "????????");
CDEBUG(5, "%s", dbuf);
}
if ((*Write)(fn, buf, len) != len)
return (FAIL);
return (SUCCESS);
}
static int
wrchr(int fn, char *buf, int len)
{
int i, saccess;
char cin, cout;
saccess = (sysaccess(ACCESS_SYSTEMS) == 0);
if (setjmp(Sjbuf))
return (FAIL);
(void) signal(SIGALRM, alarmtr);
for (i = 0; i < len; i++) {
cout = buf[i];
if (saccess) {
CDEBUG(5, "%s", cout < 040 ? "^" : "");
CDEBUG(5, "%c", cout < 040 ? cout | 0100 : cout);
} else {
CDEBUG(5, "?%s", "");
}
if (((*Write)(fn, &cout, 1)) != 1)
return (FAIL);
do {
(void) alarm(expecttime);
if ((*Read)(fn, &cin, 1) != 1)
return (FAIL);
(void) alarm(0);
cin &= 0177;
if (saccess) {
CDEBUG(5, "%s", cin < 040 ? "^" : "");
CDEBUG(5, "%c", cin < 040 ? cin | 0100 : cin);
} else {
CDEBUG(5, "?%s", "");
}
} while (cout != (cin & 0177));
}
return (SUCCESS);
}
static int
notin(char *sh, char *lg)
{
while (*lg != NULLCHAR) {
if (PREFIX(sh, lg))
return (0);
else
lg++;
}
return (1);
}
static int
ifdate(char *s)
{
static char *days[] = {
"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
};
time_t clock;
int t__now;
char *p;
struct tm *tp;
(void) time(&clock);
tp = localtime(&clock);
t__now = tp->tm_hour * 100 + tp->tm_min;
if ((p = rindex(s, ';')) != NULL)
if (isdigit(p[1])) {
if (sscanf(p+1, "%ld", &Retrytime) < 1)
Retrytime = 5;
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))
s++;
if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2) ||
(t__low == t__high))
return (1);
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);
if ((s = index(s, ',')) == NULL)
break;
}
if (*s)
s++;
}
return (0);
}
static char *
fdig(char *cp)
{
char *c;
for (c = cp; *c; c++)
if (*c >= '0' && *c <= '9')
break;
return (c);
}
static void
nap(unsigned int n)
{
struct timeval tv;
if (n == 0)
return;
tv.tv_sec = n/60;
tv.tv_usec = ((n%60)*1000000L)/60;
(void) select(32, 0, 0, 0, &tv);
}