SysIII/usr/src/cmd/uucp/conn.c
/* conn 3.12 1/5/80 13:51:15 */
#define CONN
#include "uucp.h"
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#include <sys/types.h>
#include <termio.h>
#include <time.h>
#include <fcntl.h>
#ifdef DATAKIT
#include <dk.h>
#endif
#define MAXPH 60
#define F_NAME 0
#define F_TIME 1
#define F_LINE 2
#define F_CLASS 3 /* an optional prefix and the speed */
#define F_PHONE 4
#define F_LOGIN 5
jmp_buf Sjbuf;
int alarmtr();
#define INVOKE(a, r) ret = a; if (ret<0) return(r);
/*******
* conn(system)
* char *system;
*
* conn - place a telephone call to system and
* login, etc.
*
* return codes:
* CF_SYSTEM: don't know system
* CF_TIME: wrong time to call
* CF_DIAL: call failed
* CF_LOGIN: login/password dialog failed
*
* >0 - file no. - connect ok
*
*/
conn(system)
char *system;
{
int ret, nf;
int fn;
char *flds[50];
FILE *fsys;
int fcode = 0;
fsys = fopen(SYSFILE, "r");
ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0);
DEBUG(4, "finds %s\n", "called");
while((nf = finds(fsys, system, flds)) > 0) {
DEBUG(4, "getto %s\n", "called");
if ((fn = getto(flds)) > 0)
break;
fcode = CF_DIAL;
}
fclose(fsys);
if (nf < 0)
return(fcode ? fcode : nf);
DEBUG(4, "login %s\n", "called");
INVOKE(login(nf, flds, fn), CF_LOGIN)
return(fn);
}
/* This structure tells about a device */
struct Devices {
char D_type[10];
char D_line[10];
char D_calldev[10];
char D_class[10];
int D_speed;
};
/***
* getto(flds) connect to remote machine
* char *flds[];
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
getto(flds)
char *flds[];
{
DEBUG(4, "call: no. %s ", flds[F_PHONE]);
DEBUG(4, "for sys %s ", flds[F_NAME]);
if (prefix("ACU", flds[F_LINE]))
return(call(flds));
#ifdef DATAKIT
else if (prefix("DK", flds[F_LINE]))
return(dkcall(flds));
#endif
else
return(direct(flds));
}
/***
* call(flds) call remote machine
* char *flds[];
*
* "flds" contains the call information (name, date, type, speed,
* phone no. ...
* Ndev has the device no.
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
call(flds)
char *flds[];
{
char phone[MAXPH+1];
int dcr, i;
exphone(flds[F_PHONE], phone);
for (i = 0; i < TRYCALLS; i++) {
DEBUG(4, "Dial %s\n", phone);
dcr = dialup(phone, flds);
DEBUG(4, "dcr returned as %d\n", dcr);
if (dcr != FAIL)
break;
}
return(dcr);
}
/***
* exphone - expand phone number for given prefix and number
*
* return code - none
*/
exphone(in, out)
char *in, *out;
{
FILE *fn;
char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
char buf[BUFSIZ];
char *s1;
if (!isalpha(*in)) {
strcpy(out, in);
return;
}
s1=pre;
while (isalpha(*in))
*s1++ = *in++;
*s1 = '\0';
s1 = npart;
while (*in != '\0')
*s1++ = *in++;
*s1 = '\0';
tpre[0] = '\0';
fn = fopen(DIALFILE, "r");
if (fn != NULL) {
while (fgets(buf, BUFSIZ, fn)) {
sscanf(buf, "%s%s", p, tpre);
if (strcmp(p, pre) == SAME)
break;
tpre[0] = '\0';
}
fclose(fn);
}
strcpy(out, tpre);
strcat(out, npart);
return;
}
/* file descriptor for call unit */
int Dnf = 0;
/***
* dialup(ph, flds) dial remote machine
* char *ph;
* char *flds[];
*
* return codes:
* file descriptor - succeeded
* FAIL - failed
*/
dialup(ph, flds)
char *ph;
char *flds[];
{
#ifdef DIALOUT
int dcf;
if ((dcf = dialout(ph, flds[F_CLASS])) < 0)
return(FAIL);
return(dcf);
#endif
#ifndef DIALOUT
char dcname[20], dnname[20], phone[MAXPH+2];
struct Devices dev;
struct termio ttbuf;
int status;
int nw, lt, pid, dcf;
unsigned timelim;
FILE *dfp;
dfp = fopen(DEVFILE, "r");
ASSERT(dfp != NULL, "CAN'T OPEN", DEVFILE, 0);
while ((status = rddev(dfp, &dev)) != FAIL) {
if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
continue;
if (strcmp(flds[F_LINE], dev.D_type) != SAME)
continue;
if (mlock(dev.D_line) == FAIL)
continue;
sprintf(dnname, "/dev/%s", dev.D_calldev);
sprintf(dcname, "/dev/%s", dev.D_line);
if ((Dnf = open(dnname, 1)) > 0)
break;
delock(dev.D_line);
}
fclose(dfp);
if (status == FAIL) {
logent("DEVICE", "NO");
DEBUG(4, "NO DEVICE %s", "");
return(FAIL);
}
sprintf(phone, "%s%s", ph, ACULAST);
DEBUG(4, "dc - %s, ", dcname);
DEBUG(4, "acu - %s\n", dnname);
if (setjmp(Sjbuf)) {
DEBUG(1, "DN write %s\n", "timeout");
logent("DIALUP DN write", "TIMEOUT");
delock(dev.D_line);
close(Dnf);
return(FAIL);
}
signal(SIGALRM, alarmtr);
timelim = 5 * strlen(phone);
alarm(timelim < 30 ? 30 : timelim);
pid = open(dcname, O_RDWR | O_NDELAY);
nw = write(Dnf, phone, lt = strlen(phone));
if (nw != lt) {
DEBUG(1, "ACU write %s\n", "error");
logent("DIALUP ACU write", "FAILED");
alarm(0);
close(Dnf);
close(pid);
return(FAIL);
}
else DEBUG(4, "ACU write ok%s\n", "");
dcf = open(dcname, 2);
close(pid);
DEBUG(4, "dcf is %d\n", dcf);
if (dcf < 0) {
DEBUG(1, "Line open %s\n", "failed");
logent("DIALUP LINE open", "FAILED");
alarm(0);
close(Dnf);
delock(dev.D_line);
return(FAIL);
}
ioctl(dcf, TCGETA, &ttbuf);
if(!(ttbuf.c_cflag & HUPCL)) {
ttbuf.c_cflag |= HUPCL;
ioctl(dcf, TCSETA, &ttbuf);
}
alarm(0);
fflush(stdout);
fixline(dcf, dev.D_speed);
return(dcf);
#endif
}
/***
* rddev - read and decode a line from device file
*
* return code - FAIL at end-of file; 0 otherwise
*/
rddev(fp, dev)
struct Devices *dev;
FILE *fp;
{
char *fdig();
char buf[BUFSIZ];
int na;
if (!fgets(buf, BUFSIZ, fp))
return(FAIL);
na = sscanf(buf, "%s%s%s%s", dev->D_type, dev->D_line,
dev->D_calldev, dev->D_class);
ASSERT(na >= 4, "BAD LINE", buf, 0);
dev->D_speed = atoi(fdig(dev->D_class));
return(0);
}
/***
* clsacu() close call unit
*
* return codes: none
*/
clsacu()
{
if (Dnf > 0) {
close(Dnf);
sleep(5);
Dnf = 0;
}
return;
}
/***
* direct(flds) connect to hardware line
* char *flds[];
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
direct(flds)
char *flds[];
{
int dcr, status;
struct Devices dev;
char dcname[20];
FILE *dfp;
dfp = fopen(DEVFILE, "r");
ASSERT(dfp != NULL, "CAN'T OPEN", DEVFILE, 0);
while ((status = rddev(dfp, &dev)) != FAIL) {
if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
continue;
if (strcmp(flds[F_LINE], dev.D_line) != SAME)
continue;
if (mlock(dev.D_line) != FAIL)
break;
}
fclose(dfp);
if (status == FAIL) {
logent("DEVICE", "NO");
DEBUG(4, "NO DEVICE %s", "");
return(FAIL);
}
sprintf(dcname, "/dev/%s", dev.D_line);
signal(SIGALRM, alarmtr);
alarm(10);
if (setjmp(Sjbuf)) {
delock(dev.D_line);
return(FAIL);
}
dcr = open(dcname, 2); /* read/write */
alarm(0);
if (dcr < 0) {
delock(dev.D_line);
return(FAIL);
}
fflush(stdout);
fixline(dcr, dev.D_speed);
return(dcr);
}
#ifdef DATAKIT
#define DKTRIES 2
/***
* dkcall(flds) make datakit connection
*
* return codes:
* >0 - file number - ok
* FAIL - failed
*/
dkcall(flds)
char *flds[];
{
int dkphone;
register char *cp;
register ret, i;
if (setjmp(Sjbuf))
return(FAIL);
signal(SIGALRM, alarmtr);
dkphone = 0;
cp = flds[F_PHONE];
while(*cp)
dkphone = 10 * dkphone + (*cp++ - '0');
DEBUG(4, "dkphone (%d) ", dkphone);
for (i = 0; i < DKTRIES; i++) {
ret = dkdial(D_SH, dkphone, 0);
DEBUG(4, "dkdial (%d)\n", ret);
if (ret > -1)
break;
}
return(ret);
}
#endif
#define MAXC 300
/***
* finds(fsys, sysnam, flds) set system attribute vector
*
* return codes:
* >0 - number of arguments in vector - succeeded
* CF_SYSTEM - system name not found
* CF_TIME - wrong time to call
*/
finds(fsys, sysnam, flds)
char *sysnam, *flds[];
FILE *fsys;
{
static char info[MAXC];
char sysn[8];
int na;
int fcode = 0;
/* format of fields
* 0 name;
* 1 time
* 2 acu/hardwired
* 3 speed
* etc
*/
while (fgets(info, MAXC, fsys) != NULL) {
na = getargs(info, flds);
sprintf(sysn, "%.7s", flds[F_NAME]);
if (strcmp(sysnam, sysn) != SAME)
continue;
if (ifdate(flds[F_TIME]))
/* found a good entry */
return(na);
logent(sysnam, "WRONG TIME TO CALL");
fcode = CF_TIME;
}
return(fcode ? fcode : CF_SYSTEM);
}
/***
* login(nf, flds, dcr) do log conversation
* char *flds[];
* int nf;
*
* return codes: 0 | FAIL
*/
login(nf, flds, fn)
char *flds[];
int nf, fn;
{
char *want, *altern;
extern char *index();
int k, ok;
ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf);
for (k = F_LOGIN; k < nf; k += 2) {
want = flds[k];
ok = FAIL;
while (ok != 0) {
altern = index(want, '-');
if (altern != NULL)
*altern++ = '\0';
DEBUG(4, "wanted %s ", want);
ok = expect(want, fn);
DEBUG(4, "got %s\n", ok ? "?" : "that");
if (ok == 0)
break;
if (altern == NULL) {
logent("LOGIN", "FAILED");
return(FAIL);
}
want = index(altern, '-');
if (want != NULL)
*want++ = '\0';
sendthem(altern, fn);
}
sleep(2);
sendthem(flds[k+1], fn);
}
return(0);
}
struct sg_spds {int sp_val, sp_name;} spds[] = {
{ 300, B300},
{1200, B1200},
{4800, B4800},
{9600, B9600},
{0, 0} };
/***
* fixline(tty, spwant) set speed/echo/mode...
* int tty, spwant;
*
* return codes: none
*/
fixline(tty, spwant)
int tty, spwant;
{
struct termio ttbuf;
struct sg_spds *ps;
int speed = -1;
int ret;
for (ps = spds; ps->sp_val; ps++)
if (ps->sp_val == spwant)
speed = ps->sp_name;
ASSERT(speed >= 0, "BAD SPEED", "", speed);
ioctl(tty, TCGETA, &ttbuf);
/* ttbuf.sg_flags =(ANYP|RAW);
ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */
ttbuf.c_iflag = (ushort)0;
ttbuf.c_oflag = (ushort)0;
ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD);
ttbuf.c_lflag = (ushort)0;
ttbuf.c_cc[VMIN] = 6;
ttbuf.c_cc[VTIME] = 1;
ret = ioctl(tty, TCSETA, &ttbuf);
ASSERT(ret >= 0, "RETURN FROM STTY", "", ret);
return;
}
#define MR 300
/***
* 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;
int kr;
char nextch;
if (strcmp(str, "\"\"") == SAME)
return(0);
*rp = 0;
if (setjmp(Sjbuf)) {
return(FAIL);
}
signal(SIGALRM, alarmtr);
while (notin(str, rdvec)) {
alarm(MAXCHARTIME);
kr = read(fn, &nextch, 1);
if (kr <= 0) {
alarm(0);
DEBUG(4, "lost line kr - %d\n, ", kr);
logent("LOGIN", "LOST LINE");
return(FAIL);
}
{
int c;
c = nextch & 0177;
DEBUG(4, "%c", c > 040 ? c : '_');
}
if ((*rp = nextch & 0177) != '\0')
rp++;
*rp = '\0';
if (rp >= rdvec + MR)
return(FAIL);
}
alarm(0);
return(0);
}
/***
* alarmtr() - catch alarm routine for "expect".
*/
alarmtr()
{
longjmp(Sjbuf, 1);
}
/***
* sendthem(str, fn) send line of login sequence
* char *str;
*
* return codes: none
*/
sendthem(str, fn)
char *str;
int fn;
{
int nw, ns;
int nulls;
if (prefix("BREAK", str)) {
sscanf(&str[5], "%1d", &nulls);
if (nulls <= 0 || nulls > 10)
nulls = 3;
/* send break */
genbrk(fn, nulls);
return;
}
if (strcmp(str, "EOT") == SAME) {
write(fn, EOTMSG, strlen(EOTMSG));
return;
}
if (strcmp(str, "") != SAME) {
nw = write(fn, str, ns = strlen(str));
ASSERT(nw == ns, "BAD WRITE", str, 0);
}
write(fn, "\n", 1);
return;
}
#define BSPEED B150
/***
* genbrk send a break
*
* return codes; none
*/
genbrk(fn, bnulls)
{
ioctl(fn, TCSBRK, 0);
return;
}
/***
* notin(sh, lg) check for occurrence of substring "sh"
* char *sh, *lg;
*
* return codes:
* 0 - found the string
* 1 - not in the string
*/
notin(sh, lg)
char *sh, *lg;
{
while (*lg != '\0') {
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
*
* 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
*/
ifdate(s)
char *s;
{
static char *days[]={
"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0
};
long clock;
int rtime;
int i, tl, th, tn, flag, dayok=0;
struct tm *localtime();
struct tm *tp;
char *index();
char *p;
/* pick up retry time for failures */
/* global variable Retrytime is set here */
if ((p = index(s, ',')) == NULL) {
Retrytime = RETRYTIME;
}
else {
i = sscanf(p+1, "%d", &rtime);
if (i < 1 || rtime < 5)
rtime = 5;
Retrytime = rtime * 60;
}
time(&clock);
tp = localtime(&clock);
while (isalpha(*s)) {
for (i = 0; days[i]; i++) {
if (prefix(days[i], s))
if (tp->tm_wday == i)
dayok = 1;
}
if (prefix("Wk", s))
if (tp->tm_wday >= 1 && tp->tm_wday <= 5)
dayok = 1;
if (prefix("Any", s))
dayok = 1;
s++;
}
if (dayok == 0)
return(0);
i = sscanf(s, "%d-%d", &tl, &th);
tn = tp->tm_hour * 100 + tp->tm_min;
if (i < 2)
return(1);
if (th < tl)
flag = 0; /* set up for crossover 2400 test */
else
flag = 1;
if ((tn >= tl && tn <= th)
|| (tn >= th && tn <= tl)) /* test for crossover 2400 */
return(flag);
else
return(!flag);
}
/***
* char *
* lastc(s) return pointer to last character
* char *s;
*
*/
char *
lastc(s)
char *s;
{
while (*s != '\0') s++;
return(s);
}
/***
* 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);
}