113642Ssam #ifndef lint 2*18619Sralph static char sccsid[] = "@(#)conn.c 5.5 (Berkeley) 04/10/85"; 313642Ssam #endif 413642Ssam 513642Ssam #include "uucp.h" 613642Ssam #include <signal.h> 713642Ssam #include <setjmp.h> 813642Ssam #include <ctype.h> 913642Ssam #include <errno.h> 1017834Sralph #ifdef USG 1113642Ssam #include <termio.h> 1213642Ssam #include <fcntl.h> 1313642Ssam #endif 1417834Sralph #ifndef USG 1513642Ssam #include <sgtty.h> 1613642Ssam #endif 1717834Sralph #ifdef BSD4_2 1817834Sralph #include <sys/time.h> 1917834Sralph #else 2017834Sralph #include <time.h> 2117834Sralph #endif 2213642Ssam 2313642Ssam #define MAXC 1000 2413642Ssam 2513642Ssam extern jmp_buf Sjbuf; 2617834Sralph jmp_buf Cjbuf; 27*18619Sralph extern int errno, onesys; 2817834Sralph extern char *sys_errlist[]; 29*18619Sralph extern char MaxGrade, DefMaxGrade; 3013642Ssam 3113642Ssam /* Parity control during login procedure */ 3213642Ssam #define P_ZERO 0 3313642Ssam #define P_ONE 1 3413642Ssam #define P_EVEN 2 3513642Ssam #define P_ODD 3 3617834Sralph 3717834Sralph #define ABORT -2 3817834Sralph 3917834Sralph char *AbortOn = NULL; 4013642Ssam char par_tab[128]; /* must be power of two */ 4117834Sralph int linebaudrate; /* used for the sleep test in pk1.c */ 4213642Ssam int next_fd = -1; /* predicted fd to close interrupted opens */ 4313642Ssam /* rti!trt, courtesy unc!smb */ 4413642Ssam /*** 4513642Ssam * alarmtr() - catch alarm routine for "expect". 4613642Ssam */ 4713642Ssam alarmtr() 4813642Ssam { 4913642Ssam signal(SIGALRM, alarmtr); 5013642Ssam if (next_fd >= 0) { 5113642Ssam if (close(next_fd)) 5213642Ssam logent("FAIL", "ACU LINE CLOSE"); 5313642Ssam next_fd = -1; 5413642Ssam } 5513642Ssam longjmp(Sjbuf, 1); 5613642Ssam } 5713642Ssam 58*18619Sralph /* 59*18619Sralph * place a telephone call to system and login, etc. 6013642Ssam * 6113642Ssam * return codes: 6213642Ssam * CF_SYSTEM: don't know system 6313642Ssam * CF_TIME: wrong time to call 6413642Ssam * CF_DIAL: call failed 6513642Ssam * CF_NODEV: no devices available to place call 6613642Ssam * CF_LOGIN: login/password dialog failed 6713642Ssam * 6813642Ssam * >0 - file no. - connect ok 6913642Ssam */ 7013642Ssam 7113642Ssam int Dcf = -1; 7217834Sralph char *Flds[MAXC/10]; 7317834Sralph extern int LocalOnly; 7413642Ssam 7513642Ssam conn(system) 7613642Ssam char *system; 7713642Ssam { 7813642Ssam int ret, nf; 7917834Sralph register int fn = 0; 80*18619Sralph char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE]; 8113642Ssam register FILE *fsys; 8213642Ssam int fcode = 0; 8313642Ssam 8413642Ssam nf = 0; 8513642Ssam 8613642Ssam fsys = fopen(SYSFILE, "r"); 8713642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 8813642Ssam 8917834Sralph DEBUG(4, "finds (%s) called\n", system); 9017834Sralph while((nf = finds(fsys, system, info, Flds)) > 0) { 9117834Sralph if (LocalOnly) { 9217834Sralph if (strcmp("TCP", Flds[F_LINE]) 9317834Sralph && strcmp("DIR", Flds[F_LINE]) 9417834Sralph && strcmp("LOCAL", Flds[F_LINE]) ) 9517834Sralph fn = CF_TIME; 9617834Sralph } 97*18619Sralph sprintf(wkpre, "%c.%.7s", CMDPRE, Rmtname); 98*18619Sralph if (!onesys && MaxGrade != DefMaxGrade && 99*18619Sralph !iswrk(file, "chk", Spool, wkpre)) 100*18619Sralph fn = CF_TIME; 10117834Sralph if (fn != CF_TIME && (fn = getto(Flds)) > 0) { 10213642Ssam Dcf = fn; 10313642Ssam break; 10413642Ssam } 10513642Ssam fcode = (fn == FAIL ? CF_DIAL : fn); 10613642Ssam } 10713642Ssam fclose(fsys); 10813642Ssam 10913642Ssam if (nf <= 0) 11017834Sralph return fcode ? fcode : nf; 11113642Ssam 11213642Ssam DEBUG(4, "login %s\n", "called"); 11317834Sralph ret = login(nf, Flds, fn); 11417834Sralph if (ret == FAIL) { 11513642Ssam clsacu(); 11617834Sralph return CF_LOGIN; 11713642Ssam } 11813642Ssam /* rti!trt: avoid passing file to children */ 11913642Ssam fioclex(fn); 12017834Sralph return fn; 12113642Ssam } 12213642Ssam 12313642Ssam /*** 12413642Ssam * getto(flds) connect to remote machine 12513642Ssam * char *flds[]; 12613642Ssam * 12713642Ssam * return codes: 12813642Ssam * >0 - file number - ok 12913642Ssam * FAIL - failed 13013642Ssam */ 13113642Ssam 13213642Ssam getto(flds) 13313642Ssam register char *flds[]; 13413642Ssam { 13513642Ssam register struct condev *cd; 13613642Ssam int nulldev(), diropn(); 13713642Ssam 13817834Sralph DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 13913642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 14013642Ssam 14113642Ssam CU_end = nulldev; 14213642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 14313642Ssam if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) { 14413642Ssam DEBUG(4, "Using %s to call\n", cd->CU_meth); 14517834Sralph return (*(cd->CU_gen))(flds); 14613642Ssam } 14713642Ssam } 14817834Sralph DEBUG(1, "Can't find %s, assuming DIR", flds[F_LINE]); 14917834Sralph return diropn(flds); /* search failed, so use direct */ 15017834Sralph } 15113642Ssam 15213642Ssam /*** 15313642Ssam * clsacu() close call unit 15413642Ssam * 15513642Ssam * return codes: none 15613642Ssam */ 15713642Ssam 15813642Ssam int (*CU_end)() = nulldev; 15913642Ssam clsacu() 16013642Ssam { 16117834Sralph /* make *sure* Dcf is no longer exclusive. 16217834Sralph * Otherwise dual call-in/call-out modems could get stuck. 16317834Sralph * Unfortunately, doing this here is not ideal, but it is the 16417834Sralph * easiest place to put the call. 16517834Sralph * Hopefully everyone honors the LCK protocol, of course 16617834Sralph */ 16717834Sralph #ifndef USG 16817834Sralph ioctl(Dcf, TIOCNXCL, STBNULL); 16917834Sralph #endif 17017834Sralph if (setjmp(Sjbuf)) 17117834Sralph logent(Rmtname, "CLOSE TIMEOUT"); 17217834Sralph else { 17317834Sralph signal(SIGALRM, alarmtr); 17417834Sralph alarm(20); 17517834Sralph (*(CU_end))(Dcf); 17617834Sralph alarm(0); 17717834Sralph } 17813642Ssam if (close(Dcf) == 0) { 17913642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 18013642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 18113642Ssam } 18213642Ssam Dcf = -1; 18313642Ssam CU_end = nulldev; 18413642Ssam } 18513642Ssam 18613642Ssam /*** 18713642Ssam * exphone - expand phone number for given prefix and number 18813642Ssam * 18913642Ssam * return code - none 19013642Ssam */ 19113642Ssam 19213642Ssam exphone(in, out) 19313642Ssam register char *in, *out; 19413642Ssam { 19513642Ssam FILE *fn; 19613642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 19713642Ssam char buf[BUFSIZ]; 19813642Ssam register char *s1; 19913642Ssam 20017834Sralph if (!isascii(*in) || !isalpha(*in)) { 20113642Ssam strcpy(out, in); 20213642Ssam return; 20313642Ssam } 20413642Ssam 20513642Ssam s1=pre; 20617834Sralph while (isascii(*in) && isalpha(*in)) 20713642Ssam *s1++ = *in++; 20813642Ssam *s1 = '\0'; 20913642Ssam s1 = npart; 21013642Ssam while (*in != '\0') 21113642Ssam *s1++ = *in++; 21213642Ssam *s1 = '\0'; 21313642Ssam 21413642Ssam tpre[0] = '\0'; 21513642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 21613642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 21713642Ssam else { 21813642Ssam while (cfgets(buf, BUFSIZ, fn)) { 21917834Sralph if (sscanf(buf, "%s%s", p, tpre) != 2) 22017834Sralph continue; 22113642Ssam if (strcmp(p, pre) == SAME) 22213642Ssam goto found; 22313642Ssam tpre[0] = '\0'; 22413642Ssam } 22513642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 22613642Ssam found:; 22713642Ssam fclose(fn); 22813642Ssam } 22913642Ssam 23013642Ssam strcpy(out, tpre); 23113642Ssam strcat(out, npart); 23213642Ssam } 23313642Ssam 234*18619Sralph /* 235*18619Sralph * read and decode a line from device file 23613642Ssam * 23713642Ssam * return code - FAIL at end-of file; 0 otherwise 23813642Ssam */ 23913642Ssam 24013642Ssam rddev(fp, dev) 24113642Ssam register struct Devices *dev; 24213642Ssam FILE *fp; 24313642Ssam { 24417834Sralph register int na; 24513642Ssam 24617834Sralph if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) 24717834Sralph return FAIL; 24817834Sralph na = getargs(dev->D_argbfr, dev->D_arg, 20); 24917834Sralph ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); 25017834Sralph if (na == 4) { 25117834Sralph dev->D_brand = ""; 25217834Sralph na++; 25317834Sralph } 25413642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 25517834Sralph dev->D_numargs = na; 25617834Sralph return 0; 25713642Ssam } 25813642Ssam 259*18619Sralph /* 260*18619Sralph * set system attribute vector 26113642Ssam * 26213642Ssam * return codes: 26313642Ssam * >0 - number of arguments in vector - succeeded 26413642Ssam * CF_SYSTEM - system name not found 26513642Ssam * CF_TIME - wrong time to call 26613642Ssam */ 26713642Ssam 26813642Ssam finds(fsys, sysnam, info, flds) 26913642Ssam char *sysnam, info[], *flds[]; 27013642Ssam FILE *fsys; 27113642Ssam { 27213642Ssam int na; 27313642Ssam int fcode = 0; 27413642Ssam 27513642Ssam /* format of fields 27613642Ssam * 0 name; 27713642Ssam * 1 time 27813642Ssam * 2 acu/hardwired 27913642Ssam * 3 speed 28013642Ssam * etc 28113642Ssam */ 28213642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 28317834Sralph na = getargs(info, flds, MAXC/10); 284*18619Sralph if (strncmp(sysnam, flds[F_NAME], 7) != SAME) 28513642Ssam continue; 286*18619Sralph if (ifdate(flds[F_TIME]) != FAIL) 28713642Ssam /* found a good entry */ 28817834Sralph return na; 28913642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 29013642Ssam fcode = CF_TIME; 29113642Ssam } 29217834Sralph return fcode ? fcode : CF_SYSTEM; 29313642Ssam } 29413642Ssam 295*18619Sralph /* 296*18619Sralph * do login conversation 29713642Ssam * 29813642Ssam * return codes: 0 | FAIL 29913642Ssam */ 30013642Ssam 30113642Ssam login(nf, flds, fn) 30213642Ssam register char *flds[]; 30313642Ssam int nf, fn; 30413642Ssam { 30513642Ssam register char *want, *altern; 30613642Ssam extern char *index(); 30713642Ssam int k, ok; 30813642Ssam 30917834Sralph ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); 31017834Sralph if (setjmp(Cjbuf)) 31117834Sralph return FAIL; 31217834Sralph AbortOn = NULL; 31313642Ssam for (k = F_LOGIN; k < nf; k += 2) { 31413642Ssam want = flds[k]; 31513642Ssam ok = FAIL; 31617834Sralph while (ok != SUCCESS) { 31713642Ssam altern = index(want, '-'); 31813642Ssam if (altern != NULL) 31913642Ssam *altern++ = '\0'; 32017834Sralph if (strcmp(want, "ABORT") == 0) { 32117834Sralph AbortOn = flds[k+1]; 32217834Sralph DEBUG(4, "ABORT ON: %s\n", AbortOn); 32317834Sralph goto nextfield; 32417834Sralph } 32517834Sralph DEBUG(4, "wanted: %s\n", want); 32613642Ssam ok = expect(want, fn); 32717834Sralph DEBUG(4, "got: %s\n", ok ? "?" : "that"); 32817834Sralph if (ok == FAIL) { 32917834Sralph if (altern == NULL) { 33017834Sralph logent("LOGIN", _FAILED); 33117834Sralph return FAIL; 33217834Sralph } 33317834Sralph want = index(altern, '-'); 33417834Sralph if (want != NULL) 33517834Sralph *want++ = '\0'; 33617834Sralph sendthem(altern, fn); 33717834Sralph } else 33817834Sralph if (ok == ABORT) { 33917834Sralph logent("LOGIN ABORTED", _FAILED); 34017834Sralph return FAIL; 34117834Sralph } 34213642Ssam } 34317834Sralph sleep(1); 34413642Ssam if (k+1 < nf) 34513642Ssam sendthem(flds[k+1], fn); 34617834Sralph nextfield: ; 34713642Ssam } 34817834Sralph return SUCCESS; 34913642Ssam } 35013642Ssam 35113642Ssam 35217834Sralph /* conditional table generation to support odd speeds */ 35313642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 35413642Ssam #ifdef B50 35513642Ssam { 50, B50}, 35613642Ssam #endif 35713642Ssam #ifdef B75 35813642Ssam { 75, B75}, 35913642Ssam #endif 36013642Ssam #ifdef B110 36113642Ssam { 110, B110}, 36213642Ssam #endif 36313642Ssam #ifdef B150 36413642Ssam { 150, B150}, 36513642Ssam #endif 36613642Ssam #ifdef B200 36713642Ssam { 200, B200}, 36813642Ssam #endif 36913642Ssam #ifdef B300 37013642Ssam { 300, B300}, 37113642Ssam #endif 37213642Ssam #ifdef B600 37313642Ssam {600, B600}, 37413642Ssam #endif 37513642Ssam #ifdef B1200 37613642Ssam {1200, B1200}, 37713642Ssam #endif 37813642Ssam #ifdef B1800 37913642Ssam {1800, B1800}, 38013642Ssam #endif 38113642Ssam #ifdef B2000 38213642Ssam {2000, B2000}, 38313642Ssam #endif 38413642Ssam #ifdef B2400 38513642Ssam {2400, B2400}, 38613642Ssam #endif 38713642Ssam #ifdef B3600 38813642Ssam {3600, B3600}, 38913642Ssam #endif 39013642Ssam #ifdef B4800 39113642Ssam {4800, B4800}, 39213642Ssam #endif 39313642Ssam #ifdef B7200 39413642Ssam {7200, B7200}, 39513642Ssam #endif 39613642Ssam #ifdef B9600 39713642Ssam {9600, B9600}, 39813642Ssam #endif 39913642Ssam #ifdef B19200 40017834Sralph {19200, B19200}, 40113642Ssam #endif 40217834Sralph #ifdef EXTA 40317834Sralph {19200, EXTA}, 40417834Sralph #endif 40513642Ssam {0, 0} 40613642Ssam }; 40713642Ssam 408*18619Sralph /* 409*18619Sralph * set speed/echo/mode... 41013642Ssam * 41113642Ssam * return codes: none 41213642Ssam */ 41313642Ssam 41413642Ssam fixline(tty, spwant) 41513642Ssam int tty, spwant; 41613642Ssam { 41717834Sralph #ifdef USG 41813642Ssam struct termio ttbuf; 41917834Sralph #else !USG 42013642Ssam struct sgttyb ttbuf; 42117834Sralph #endif !USG 42213642Ssam register struct sg_spds *ps; 42313642Ssam int speed = -1; 42413642Ssam int ret; 42513642Ssam 42613642Ssam for (ps = spds; ps->sp_val; ps++) 42713642Ssam if (ps->sp_val == spwant) 42813642Ssam speed = ps->sp_name; 42917834Sralph ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); 43017834Sralph #ifdef USG 43113642Ssam ioctl(tty, TCGETA, &ttbuf); 43213642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 43313642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 43413642Ssam ttbuf.c_iflag = (ushort)0; 43513642Ssam ttbuf.c_oflag = (ushort)0; 43613642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 43713642Ssam ttbuf.c_lflag = (ushort)0; 43813642Ssam ttbuf.c_cc[VMIN] = 6; 43913642Ssam ttbuf.c_cc[VTIME] = 1; 44013642Ssam ret = ioctl(tty, TCSETA, &ttbuf); 44117834Sralph #else !USG 44213642Ssam ioctl(tty, TIOCGETP, &ttbuf); 44313642Ssam ttbuf.sg_flags = (ANYP|RAW); 44413642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 44513642Ssam ret = ioctl(tty, TIOCSETP, &ttbuf); 44613642Ssam #endif 44717834Sralph ASSERT(ret >= 0, "RETURN FROM STTY", CNULL, ret); 44817834Sralph #ifndef USG 44913642Ssam ioctl(tty, TIOCHPCL, STBNULL); 45013642Ssam ioctl(tty, TIOCEXCL, STBNULL); 45113642Ssam #endif 45217834Sralph linebaudrate = spwant; 45313642Ssam return; 45413642Ssam } 45513642Ssam 45617834Sralph #define MR 100 45713642Ssam 458*18619Sralph /* 459*18619Sralph * look for expected string 46013642Ssam * 46113642Ssam * return codes: 46213642Ssam * 0 - found 46313642Ssam * FAIL - lost line or too many characters read 46413642Ssam * some character - timed out 46513642Ssam */ 46613642Ssam 46713642Ssam expect(str, fn) 46813642Ssam register char *str; 46913642Ssam int fn; 47013642Ssam { 47114592Skarels char rdvec[MR]; 47217834Sralph register char *rp = rdvec, *strptr; 47317834Sralph int kr, cnt_char; 47413642Ssam char nextch; 47513642Ssam 47617834Sralph if (*str == '\0' || strcmp(str, "\"\"") == SAME) 47717834Sralph return SUCCESS; 47817834Sralph /* Cleanup str, convert \0xx strings to one char */ 47917834Sralph for (strptr = str; *strptr; strptr++) { 48017834Sralph if (*strptr == '\\') 48117834Sralph switch(*++strptr) { 48217834Sralph case 's': 48317834Sralph DEBUG(5, "BLANK\n", CNULL); 48417834Sralph *strptr = ' '; 48517834Sralph break; 48617834Sralph default: 48717834Sralph strptr--; /* back up to backslash */ 48817834Sralph sscanf(strptr + 1,"%o", &cnt_char); 48917834Sralph DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 49017834Sralph *strptr = (char) (cnt_char); 49117834Sralph strcpy(&strptr[1], &strptr[4]); 49217834Sralph } 49317834Sralph } 49417834Sralph 49513642Ssam *rp = 0; 49617834Sralph if (setjmp(Sjbuf)) 49717834Sralph return FAIL; 49813642Ssam signal(SIGALRM, alarmtr); 49913642Ssam alarm(MAXMSGTIME); 50013642Ssam while (notin(str, rdvec)) { 50117834Sralph if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 50217834Sralph DEBUG(1, "Call aborted on '%s'\n", AbortOn); 50317834Sralph alarm(0); 50417834Sralph return ABORT; 50517834Sralph } 50613642Ssam kr = read(fn, &nextch, 1); 50713642Ssam if (kr <= 0) { 50813642Ssam alarm(0); 50913642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 51013642Ssam logent("LOGIN", "LOST LINE"); 51117834Sralph return FAIL; 51213642Ssam } 51313642Ssam { 51413642Ssam int c; 51513642Ssam c = nextch & 0177; 51613642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 51717834Sralph if (c == '\n') 51817834Sralph DEBUG(4,"\n", CNULL); 51913642Ssam } 52013642Ssam if ((*rp = nextch & 0177) != '\0') 52113642Ssam rp++; 52213642Ssam if (rp >= rdvec + MR) { 52317834Sralph register char *p; 52417834Sralph for (p = rdvec+MR/2; p < rp; p++) 52517834Sralph *(p-MR/2) = *p; 52617834Sralph rp -= MR/2; 52713642Ssam } 52813642Ssam *rp = '\0'; 52913642Ssam } 53013642Ssam alarm(0); 53117834Sralph return SUCCESS; 53213642Ssam } 53313642Ssam 53413642Ssam 53513642Ssam /* 53613642Ssam * Determine next file descriptor that would be allocated. 53713642Ssam * This permits later closing of a file whose open was interrupted. 53813642Ssam * It is a UNIX kernel problem, but it has to be handled. 53913642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 54013642Ssam */ 54113642Ssam getnextfd() 54213642Ssam { 54313642Ssam close(next_fd = open("/", 0)); 54413642Ssam } 54513642Ssam 54617834Sralph /* 54717834Sralph * send line of login sequence 54813642Ssam * 54913642Ssam * return codes: none 55013642Ssam */ 55113642Ssam sendthem(str, fn) 55213642Ssam register char *str; 55313642Ssam int fn; 55413642Ssam { 55513642Ssam register char *strptr; 55613642Ssam int i, n, cr = 1; 55717834Sralph register char c; 55813642Ssam static int p_init = 0; 55913642Ssam 56013642Ssam DEBUG(5, "send %s\n", str); 56113642Ssam 56213642Ssam if (!p_init) { 56313642Ssam p_init++; 56413642Ssam bld_partab(P_EVEN); 56513642Ssam } 56613642Ssam 56713642Ssam if (prefix("BREAK", str)) { 56813642Ssam sscanf(&str[5], "%1d", &i); 56913642Ssam if (i <= 0 || i > 10) 57013642Ssam i = 3; 57113642Ssam /* send break */ 57213642Ssam genbrk(fn, i); 57313642Ssam return; 57413642Ssam } 57513642Ssam 57613642Ssam if (prefix("PAUSE", str)) { 57713642Ssam sscanf(&str[5], "%1d", &i); 57813642Ssam if (i <= 0 || i > 10) 57913642Ssam i = 3; 58013642Ssam /* pause for a while */ 58113642Ssam sleep((unsigned)i); 58213642Ssam return; 58313642Ssam } 58413642Ssam 58513642Ssam if (strcmp(str, "EOT") == SAME) { 58613642Ssam p_chwrite(fn, '\04'); 58713642Ssam return; 58813642Ssam } 58913642Ssam 59013642Ssam /* Send a '\n' */ 59113642Ssam if (strcmp(str, "LF") == SAME) 59213642Ssam str = "\\n\\c"; 59313642Ssam 59413642Ssam /* Send a '\r' */ 59513642Ssam if (strcmp(str, "CR") == SAME) 59613642Ssam str = "\\r\\c"; 59713642Ssam 59813642Ssam /* Set parity as needed */ 59913642Ssam if (strcmp(str, "P_ZERO") == SAME) { 60013642Ssam bld_partab(P_ZERO); 60113642Ssam return; 60213642Ssam } 60313642Ssam if (strcmp(str, "P_ONE") == SAME) { 60413642Ssam bld_partab(P_ONE); 60513642Ssam return; 60613642Ssam } 60713642Ssam if (strcmp(str, "P_EVEN") == SAME) { 60813642Ssam bld_partab(P_EVEN); 60913642Ssam return; 61013642Ssam } 61113642Ssam if (strcmp(str, "P_ODD") == SAME) { 61213642Ssam bld_partab(P_ODD); 61313642Ssam return; 61413642Ssam } 61513642Ssam 61613642Ssam /* If "", just send '\r' */ 61717834Sralph if (strcmp(str, "\"\"") == SAME) { 61817834Sralph p_chwrite(fn, '\r'); 61917834Sralph return; 62017834Sralph } 62117834Sralph 62217834Sralph for (strptr = str; c = *strptr++;) { 62317834Sralph if (c == '\\') { 62417834Sralph switch(*strptr++) { 62517834Sralph case 's': 62617834Sralph DEBUG(5, "BLANK\n", CNULL); 62717834Sralph p_chwrite(fn, ' '); 62817834Sralph break; 62917834Sralph case 'd': 63017834Sralph DEBUG(5, "DELAY\n", CNULL); 63117834Sralph sleep(1); 63217834Sralph continue; 63317834Sralph case 'r': 63417834Sralph DEBUG(5, "RETURN\n", CNULL); 63517834Sralph p_chwrite(fn, '\r'); 63617834Sralph break; 63717834Sralph case 'b': 63817834Sralph if (isdigit(*strptr)) { 63917834Sralph i = (*strptr++ - '0'); 64017834Sralph if (i <= 0 || i > 10) 64117834Sralph i = 3; 64217834Sralph } else 64313642Ssam i = 3; 64417834Sralph /* send break */ 64517834Sralph genbrk(fn, i); 64617834Sralph if (*strptr == '\0') 64717834Sralph cr = 0; 64813642Ssam continue; 64917834Sralph case 'c': 65017834Sralph if (*strptr == '\0') { 65117834Sralph DEBUG(5, "NO CR\n", CNULL); 65217834Sralph cr = 0; 65317834Sralph continue; 65417834Sralph } 65517834Sralph DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL); 65613642Ssam continue; 65717834Sralph default: 65817834Sralph if (isdigit(*strptr)) { 65917834Sralph i = 0; 66017834Sralph n = 0; 66117834Sralph while (isdigit(*strptr) && ++n <= 3) 66217834Sralph i = i*8 + (*strptr++ - '0'); 66317834Sralph p_chwrite(fn, (char)i); 66417834Sralph continue; 66517834Sralph } 66617834Sralph DEBUG(5, "BACKSLASH\n", CNULL); 66717834Sralph --strptr; 66813642Ssam } 66917834Sralph } else 67017834Sralph p_chwrite(fn, c); 67113642Ssam } 67213642Ssam 67313642Ssam if (cr) 67413642Ssam p_chwrite(fn, '\r'); 67513642Ssam return; 67613642Ssam } 67713642Ssam 67813642Ssam p_chwrite(fd, c) 67913642Ssam int fd; 68017834Sralph char c; 68113642Ssam { 68217834Sralph c = par_tab[c&0177]; 68317834Sralph if (write(fd, &c, 1) != 1) { 68417834Sralph logent(sys_errlist[errno], "BAD WRITE"); 68517834Sralph longjmp(Cjbuf, 2); 68617834Sralph } 68713642Ssam } 68813642Ssam 68913642Ssam /* 69013642Ssam * generate parity table for use by p_chwrite. 69113642Ssam */ 69213642Ssam bld_partab(type) 69313642Ssam int type; 69413642Ssam { 69513642Ssam register int i, j, n; 69613642Ssam 69713642Ssam for (i = 0; i < sizeof(par_tab); i++) { 69813642Ssam n = 0; 69913642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 70013642Ssam n++; 70113642Ssam par_tab[i] = i; 70213642Ssam if (type == P_ONE 70313642Ssam || (type == P_EVEN && (n&01) != 0) 70413642Ssam || (type == P_ODD && (n&01) == 0)) 70513642Ssam par_tab[i] |= sizeof(par_tab); 70613642Ssam } 70713642Ssam } 70813642Ssam 70913642Ssam #define BSPEED B150 71013642Ssam 711*18619Sralph /* 712*18619Sralph * send a break 71313642Ssam * 71413642Ssam * return codes; none 71513642Ssam */ 71613642Ssam 71713642Ssam genbrk(fn, bnulls) 71813642Ssam register int fn, bnulls; 71913642Ssam { 72013642Ssam register int ret; 72117834Sralph #ifdef USG 72213642Ssam ret = ioctl(fn, TCSBRK, STBNULL); 72313642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 72417834Sralph #else !USG 72513642Ssam #ifdef TIOCSBRK 72613642Ssam ret = ioctl(fn, TIOCSBRK, STBNULL); 72713642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 72813642Ssam #ifdef TIOCCBRK 72913642Ssam sleep(1); 73013642Ssam ret = ioctl(fn, TIOCCBRK, STBNULL); 73113642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 73217834Sralph #endif TIOCCBRK 73317834Sralph DEBUG(4, "ioctl %d second break\n", bnulls ); 73417834Sralph #else !TIOCSBRK 73513642Ssam struct sgttyb ttbuf; 73613642Ssam register int sospeed; 73713642Ssam 73813642Ssam ret = ioctl(fn, TIOCGETP, &ttbuf); 73913642Ssam sospeed = ttbuf.sg_ospeed; 74013642Ssam ttbuf.sg_ospeed = BSPEED; 74113642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 74213642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 74317834Sralph if (ret != bnulls) { 74417834Sralph badbreak: 74517834Sralph logent(sys_errlist[errno], "BAD WRITE genbrk"); 74617834Sralph alarm(0); 74717834Sralph longjmp(Sjbuf, 3); 74817834Sralph } 74913642Ssam ttbuf.sg_ospeed = sospeed; 75013642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 75113642Ssam ret = write(fn, "@", 1); 75217834Sralph if (ret != 1) 75317834Sralph goto badbreak; 75413642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 75517834Sralph #endif !TIOCSBRK 75617834Sralph #endif !USG 75713642Ssam } 75813642Ssam 759*18619Sralph /* 760*18619Sralph * check for occurrence of substring "sh" 76113642Ssam * 76213642Ssam * return codes: 76313642Ssam * 0 - found the string 76413642Ssam * 1 - not in the string 76513642Ssam */ 76613642Ssam notin(sh, lg) 76713642Ssam register char *sh, *lg; 76813642Ssam { 76913642Ssam while (*lg != '\0') { 77013642Ssam if (wprefix(sh, lg)) 771*18619Sralph return 0; 77213642Ssam else 77313642Ssam lg++; 77413642Ssam } 775*18619Sralph return 1; 77613642Ssam } 77713642Ssam 778*18619Sralph /* 77913642Ssam * Allow multiple date specifications separated by '|'. 78013642Ssam */ 781*18619Sralph ifdate(p) 782*18619Sralph register char *p; 78313642Ssam { 784*18619Sralph register int ret, g; 78513642Ssam 786*18619Sralph ret = FAIL; 787*18619Sralph MaxGrade = '\0'; 788*18619Sralph do { 789*18619Sralph g = ifadate(p); 790*18619Sralph DEBUG(11,"ifadate returns %o\n", g); 791*18619Sralph if (g != FAIL) { 792*18619Sralph ret = SUCCESS; 793*18619Sralph if (g > MaxGrade) 794*18619Sralph MaxGrade = g; 795*18619Sralph } 796*18619Sralph p = index(p, '|'); 797*18619Sralph } while (p++ && *p); 798*18619Sralph return ret; 79913642Ssam } 80013642Ssam 801*18619Sralph /* 802*18619Sralph * this routine will check a string (string) 80313642Ssam * like "MoTu0800-1730" to see if the present 80413642Ssam * time is within the given limits. 80513642Ssam * SIDE EFFECT - Retrytime is set 80613642Ssam * 80713642Ssam * return codes: 80813642Ssam * 0 - not within limits 80913642Ssam * 1 - within limits 81013642Ssam */ 81113642Ssam 812*18619Sralph ifadate(string) 813*18619Sralph char *string; 81413642Ssam { 81513642Ssam static char *days[]={ 81613642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 81713642Ssam }; 81813642Ssam time_t clock; 819*18619Sralph register char *s = string; 82013642Ssam int rtime; 82117834Sralph int i, tl, th, tn, dayok=0; 82213642Ssam struct tm *localtime(); 82313642Ssam struct tm *tp; 824*18619Sralph char *p, MGrade; 82513642Ssam 82613642Ssam /* pick up retry time for failures */ 82713642Ssam /* global variable Retrytime is set here */ 82813642Ssam if ((p = index(s, ',')) == NULL) { 82913642Ssam Retrytime = RETRYTIME; 83017834Sralph } else { 83113642Ssam i = sscanf(p+1, "%d", &rtime); 83217834Sralph if (i < 1 || rtime < 0) 83313642Ssam rtime = 5; 83413642Ssam Retrytime = rtime * 60; 83513642Ssam } 83613642Ssam 837*18619Sralph if ((p = index(s, '@')) == NULL) 838*18619Sralph MGrade = DefMaxGrade; 839*18619Sralph else 840*18619Sralph MGrade = p[1]; 841*18619Sralph 84213642Ssam time(&clock); 84313642Ssam tp = localtime(&clock); 84417834Sralph while (isascii(*s) && isalpha(*s)) { 84513642Ssam for (i = 0; days[i]; i++) { 84613642Ssam if (prefix(days[i], s)) 84713642Ssam if (tp->tm_wday == i) 84813642Ssam dayok = 1; 84913642Ssam } 85013642Ssam 85113642Ssam if (prefix("Wk", s)) 85213642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 85313642Ssam dayok = 1; 85413642Ssam if (prefix("Any", s)) 85513642Ssam dayok = 1; 85617834Sralph if (prefix("Evening", s)) { 85717834Sralph /* Sat or Sun */ 85817834Sralph if (tp->tm_wday == 6 || tp->tm_wday == 0 85917834Sralph || tp->tm_hour >= 17 || tp->tm_hour < 8) 86017834Sralph dayok = 1; 86117834Sralph } 86217834Sralph if (prefix("Night", s)) { 86317834Sralph if (tp->tm_wday == 6 /* Sat */ 864*18619Sralph || tp->tm_hour >= 23 || tp->tm_hour < 8 865*18619Sralph /* Sunday before 5pm */ 866*18619Sralph || (tp->tm_wday == 0 && tp->tm_hour < 17)) 86717834Sralph dayok = 1; 86817834Sralph } 86913642Ssam s++; 87013642Ssam } 87113642Ssam 872*18619Sralph if (dayok == 0 && s != string) 873*18619Sralph return FAIL; 87413642Ssam i = sscanf(s, "%d-%d", &tl, &th); 875*18619Sralph if (i < 2) 876*18619Sralph return MGrade; 877*18619Sralph tn = tp->tm_hour * 100 + tp->tm_min; 878*18619Sralph if (th < tl) { /* crosses midnight */ 879*18619Sralph if (tl <= tn || tn < th) 880*18619Sralph return MGrade; 881*18619Sralph } else 882*18619Sralph 88313642Ssam if (i < 2) 884*18619Sralph return MGrade; 885*18619Sralph if (th < tl) { /* crosses midnight */ 88617834Sralph if (tl <= tn || tn < th) 887*18619Sralph return MGrade; 88817834Sralph } else 88917834Sralph if (tl <= tn && tn < th) 890*18619Sralph return MGrade; 891*18619Sralph return FAIL; 89213642Ssam } 89313642Ssam 894*18619Sralph /* 895*18619Sralph * find first digit in string 89613642Ssam * 89713642Ssam * return - pointer to first digit in string or end of string 89813642Ssam */ 89913642Ssam char * 90013642Ssam fdig(cp) 90113642Ssam register char *cp; 90213642Ssam { 90313642Ssam register char *c; 90413642Ssam 90513642Ssam for (c = cp; *c; c++) 90613642Ssam if (*c >= '0' && *c <= '9') 90713642Ssam break; 90817834Sralph return c; 90913642Ssam } 91013642Ssam 91113642Ssam /* 91213642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 91313642Ssam * Strings are compared as if they contain all capital letters. 91413642Ssam */ 91513642Ssam snccmp(s1, s2) 91613642Ssam register char *s1, *s2; 91713642Ssam { 91813642Ssam char c1, c2; 91913642Ssam 92013642Ssam if (islower(*s1)) c1 = toupper(*s1); 92113642Ssam else c1 = *s1; 92213642Ssam if (islower(*s2)) c2 = toupper(*s2); 92313642Ssam else c2 = *s2; 92413642Ssam 92513642Ssam while (c1 == c2) { 92613642Ssam if (*s1++=='\0') 92717834Sralph return 0; 92813642Ssam s2++; 92913642Ssam if (islower(*s1)) c1 = toupper(*s1); 93013642Ssam else c1 = *s1; 93113642Ssam if (islower(*s2)) c2 = toupper(*s2); 93213642Ssam else c2 = *s2; 93313642Ssam } 93417834Sralph return c1 - c2; 93513642Ssam } 93617834Sralph /* 93717834Sralph * do chat script 93817834Sralph * occurs after local port is opened, 93917834Sralph * before 'dialing' the other machine. 94017834Sralph */ 94117834Sralph dochat(dev, flds, fd) 94217834Sralph register struct Devices *dev; 94317834Sralph char *flds[]; 94417834Sralph int fd; 94517834Sralph { 94617834Sralph register int i; 94717834Sralph register char *p; 94817834Sralph char bfr[sizeof(dev->D_argbfr)]; 94917834Sralph 95017834Sralph if (dev->D_numargs <= 5) 95117834Sralph return(0); 95217834Sralph DEBUG(4, "dochat called %d\n", dev->D_numargs); 95317834Sralph for (i = 0; i < dev->D_numargs-5; i++) { 95417834Sralph sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 95517834Sralph if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 95617834Sralph p = malloc((unsigned)strlen(bfr)+1); 95717834Sralph if (p != NULL) { 95817834Sralph strcpy(p, bfr); 95917834Sralph dev->D_arg[D_CHAT+i] = p; 96017834Sralph } 96117834Sralph } 96217834Sralph } 96317834Sralph /* following is a kludge because login() arglist is a kludge */ 96417834Sralph i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 96517834Sralph /* 96617834Sralph * If login() last did a sendthem(), must pause so things can settle. 96717834Sralph * But don't bother if chat failed. 96817834Sralph */ 96917834Sralph if (i == 0 && (dev->D_numargs&01)) 97017834Sralph sleep(2); 97117834Sralph return(i); 97217834Sralph } 973