113642Ssam #ifndef lint 2*17834Sralph static char sccsid[] = "@(#)conn.c 5.4 (Berkeley) 01/22/85"; 313642Ssam #endif 413642Ssam 513642Ssam #include "uucp.h" 613642Ssam #include <signal.h> 713642Ssam #include <setjmp.h> 813642Ssam #include <ctype.h> 913642Ssam #include <sys/types.h> 1013642Ssam #include <errno.h> 11*17834Sralph #ifdef USG 1213642Ssam #include <termio.h> 1313642Ssam #include <fcntl.h> 1413642Ssam #endif 15*17834Sralph #ifndef USG 1613642Ssam #include <sgtty.h> 1713642Ssam #endif 18*17834Sralph #ifdef BSD4_2 19*17834Sralph #include <sys/time.h> 20*17834Sralph #else 21*17834Sralph #include <time.h> 22*17834Sralph #endif 2313642Ssam 2413642Ssam #define MAXC 1000 2513642Ssam 2613642Ssam extern jmp_buf Sjbuf; 27*17834Sralph jmp_buf Cjbuf; 2813642Ssam extern int errno; 29*17834Sralph extern char *sys_errlist[]; 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 36*17834Sralph 37*17834Sralph #define ABORT -2 38*17834Sralph 39*17834Sralph char *AbortOn = NULL; 4013642Ssam char par_tab[128]; /* must be power of two */ 41*17834Sralph 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 5813642Ssam /******* 5913642Ssam * conn(system) 6013642Ssam * char *system; 6113642Ssam * 6213642Ssam * conn - place a telephone call to system and 6313642Ssam * login, etc. 6413642Ssam * 6513642Ssam * return codes: 6613642Ssam * CF_SYSTEM: don't know system 6713642Ssam * CF_TIME: wrong time to call 6813642Ssam * CF_DIAL: call failed 6913642Ssam * CF_NODEV: no devices available to place call 7013642Ssam * CF_LOGIN: login/password dialog failed 7113642Ssam * 7213642Ssam * >0 - file no. - connect ok 7313642Ssam * 7413642Ssam */ 7513642Ssam 7613642Ssam int Dcf = -1; 77*17834Sralph char *Flds[MAXC/10]; 78*17834Sralph extern int LocalOnly; 7913642Ssam 8013642Ssam conn(system) 8113642Ssam char *system; 8213642Ssam { 8313642Ssam int ret, nf; 84*17834Sralph register int fn = 0; 85*17834Sralph char info[MAXC]; 8613642Ssam register FILE *fsys; 8713642Ssam int fcode = 0; 8813642Ssam 8913642Ssam nf = 0; 9013642Ssam 9113642Ssam fsys = fopen(SYSFILE, "r"); 9213642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 9313642Ssam 94*17834Sralph DEBUG(4, "finds (%s) called\n", system); 95*17834Sralph while((nf = finds(fsys, system, info, Flds)) > 0) { 96*17834Sralph if (LocalOnly) { 97*17834Sralph if (strcmp("TCP", Flds[F_LINE]) 98*17834Sralph && strcmp("DIR", Flds[F_LINE]) 99*17834Sralph && strcmp("LOCAL", Flds[F_LINE]) ) 100*17834Sralph fn = CF_TIME; 101*17834Sralph } 102*17834Sralph if (fn != CF_TIME && (fn = getto(Flds)) > 0) { 10313642Ssam Dcf = fn; 10413642Ssam break; 10513642Ssam } 10613642Ssam fcode = (fn == FAIL ? CF_DIAL : fn); 10713642Ssam } 10813642Ssam fclose(fsys); 10913642Ssam 11013642Ssam if (nf <= 0) 111*17834Sralph return fcode ? fcode : nf; 11213642Ssam 11313642Ssam DEBUG(4, "login %s\n", "called"); 114*17834Sralph ret = login(nf, Flds, fn); 115*17834Sralph if (ret == FAIL) { 11613642Ssam clsacu(); 117*17834Sralph return CF_LOGIN; 11813642Ssam } 11913642Ssam /* rti!trt: avoid passing file to children */ 12013642Ssam fioclex(fn); 121*17834Sralph return fn; 12213642Ssam } 12313642Ssam 12413642Ssam /*** 12513642Ssam * getto(flds) connect to remote machine 12613642Ssam * char *flds[]; 12713642Ssam * 12813642Ssam * return codes: 12913642Ssam * >0 - file number - ok 13013642Ssam * FAIL - failed 13113642Ssam */ 13213642Ssam 13313642Ssam getto(flds) 13413642Ssam register char *flds[]; 13513642Ssam { 13613642Ssam register struct condev *cd; 13713642Ssam int nulldev(), diropn(); 13813642Ssam 139*17834Sralph DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 14013642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 14113642Ssam 14213642Ssam CU_end = nulldev; 14313642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 14413642Ssam if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) { 14513642Ssam DEBUG(4, "Using %s to call\n", cd->CU_meth); 146*17834Sralph return (*(cd->CU_gen))(flds); 14713642Ssam } 14813642Ssam } 149*17834Sralph DEBUG(1, "Can't find %s, assuming DIR", flds[F_LINE]); 150*17834Sralph return diropn(flds); /* search failed, so use direct */ 151*17834Sralph } 15213642Ssam 15313642Ssam /*** 15413642Ssam * clsacu() close call unit 15513642Ssam * 15613642Ssam * return codes: none 15713642Ssam */ 15813642Ssam 15913642Ssam int (*CU_end)() = nulldev; 16013642Ssam clsacu() 16113642Ssam { 162*17834Sralph /* make *sure* Dcf is no longer exclusive. 163*17834Sralph * Otherwise dual call-in/call-out modems could get stuck. 164*17834Sralph * Unfortunately, doing this here is not ideal, but it is the 165*17834Sralph * easiest place to put the call. 166*17834Sralph * Hopefully everyone honors the LCK protocol, of course 167*17834Sralph */ 168*17834Sralph #ifndef USG 169*17834Sralph ioctl(Dcf, TIOCNXCL, STBNULL); 170*17834Sralph #endif 171*17834Sralph if (setjmp(Sjbuf)) 172*17834Sralph logent(Rmtname, "CLOSE TIMEOUT"); 173*17834Sralph else { 174*17834Sralph signal(SIGALRM, alarmtr); 175*17834Sralph alarm(20); 176*17834Sralph (*(CU_end))(Dcf); 177*17834Sralph alarm(0); 178*17834Sralph } 17913642Ssam if (close(Dcf) == 0) { 18013642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 18113642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 18213642Ssam } 18313642Ssam Dcf = -1; 18413642Ssam CU_end = nulldev; 18513642Ssam } 18613642Ssam 18713642Ssam /*** 18813642Ssam * exphone - expand phone number for given prefix and number 18913642Ssam * 19013642Ssam * return code - none 19113642Ssam */ 19213642Ssam 19313642Ssam exphone(in, out) 19413642Ssam register char *in, *out; 19513642Ssam { 19613642Ssam FILE *fn; 19713642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 19813642Ssam char buf[BUFSIZ]; 19913642Ssam register char *s1; 20013642Ssam 201*17834Sralph if (!isascii(*in) || !isalpha(*in)) { 20213642Ssam strcpy(out, in); 20313642Ssam return; 20413642Ssam } 20513642Ssam 20613642Ssam s1=pre; 207*17834Sralph while (isascii(*in) && isalpha(*in)) 20813642Ssam *s1++ = *in++; 20913642Ssam *s1 = '\0'; 21013642Ssam s1 = npart; 21113642Ssam while (*in != '\0') 21213642Ssam *s1++ = *in++; 21313642Ssam *s1 = '\0'; 21413642Ssam 21513642Ssam tpre[0] = '\0'; 21613642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 21713642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 21813642Ssam else { 21913642Ssam while (cfgets(buf, BUFSIZ, fn)) { 220*17834Sralph if (sscanf(buf, "%s%s", p, tpre) != 2) 221*17834Sralph continue; 22213642Ssam if (strcmp(p, pre) == SAME) 22313642Ssam goto found; 22413642Ssam tpre[0] = '\0'; 22513642Ssam } 22613642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 22713642Ssam found:; 22813642Ssam fclose(fn); 22913642Ssam } 23013642Ssam 23113642Ssam strcpy(out, tpre); 23213642Ssam strcat(out, npart); 23313642Ssam } 23413642Ssam 23513642Ssam /*** 23613642Ssam * rddev - read and decode a line from device file 23713642Ssam * 23813642Ssam * return code - FAIL at end-of file; 0 otherwise 23913642Ssam */ 24013642Ssam 24113642Ssam rddev(fp, dev) 24213642Ssam register struct Devices *dev; 24313642Ssam FILE *fp; 24413642Ssam { 245*17834Sralph register int na; 24613642Ssam 247*17834Sralph if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) 248*17834Sralph return FAIL; 249*17834Sralph na = getargs(dev->D_argbfr, dev->D_arg, 20); 250*17834Sralph ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); 251*17834Sralph if (na == 4) { 252*17834Sralph dev->D_brand = ""; 253*17834Sralph na++; 254*17834Sralph } 25513642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 256*17834Sralph dev->D_numargs = na; 257*17834Sralph return 0; 25813642Ssam } 25913642Ssam 26013642Ssam /*** 26113642Ssam * finds(fsys, sysnam, info, flds) set system attribute vector 26213642Ssam * 26313642Ssam * return codes: 26413642Ssam * >0 - number of arguments in vector - succeeded 26513642Ssam * CF_SYSTEM - system name not found 26613642Ssam * CF_TIME - wrong time to call 26713642Ssam */ 26813642Ssam 26913642Ssam finds(fsys, sysnam, info, flds) 27013642Ssam char *sysnam, info[], *flds[]; 27113642Ssam FILE *fsys; 27213642Ssam { 27313642Ssam char sysn[8]; 27413642Ssam int na; 27513642Ssam int fcode = 0; 27613642Ssam 27713642Ssam /* format of fields 27813642Ssam * 0 name; 27913642Ssam * 1 time 28013642Ssam * 2 acu/hardwired 28113642Ssam * 3 speed 28213642Ssam * etc 28313642Ssam */ 28413642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 285*17834Sralph na = getargs(info, flds, MAXC/10); 28613642Ssam sprintf(sysn, "%.7s", flds[F_NAME]); 28713642Ssam if (strcmp(sysnam, sysn) != SAME) 28813642Ssam continue; 28913642Ssam if (ifdate(flds[F_TIME])) 29013642Ssam /* found a good entry */ 291*17834Sralph return na; 29213642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 29313642Ssam fcode = CF_TIME; 29413642Ssam } 295*17834Sralph return fcode ? fcode : CF_SYSTEM; 29613642Ssam } 29713642Ssam 29813642Ssam /*** 29913642Ssam * login(nf, flds, dcr) do login conversation 30013642Ssam * char *flds[]; 30113642Ssam * int nf; 30213642Ssam * 30313642Ssam * return codes: 0 | FAIL 30413642Ssam */ 30513642Ssam 30613642Ssam login(nf, flds, fn) 30713642Ssam register char *flds[]; 30813642Ssam int nf, fn; 30913642Ssam { 31013642Ssam register char *want, *altern; 31113642Ssam extern char *index(); 31213642Ssam int k, ok; 31313642Ssam 314*17834Sralph ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); 315*17834Sralph if (setjmp(Cjbuf)) 316*17834Sralph return FAIL; 317*17834Sralph AbortOn = NULL; 31813642Ssam for (k = F_LOGIN; k < nf; k += 2) { 31913642Ssam want = flds[k]; 32013642Ssam ok = FAIL; 321*17834Sralph while (ok != SUCCESS) { 32213642Ssam altern = index(want, '-'); 32313642Ssam if (altern != NULL) 32413642Ssam *altern++ = '\0'; 325*17834Sralph if (strcmp(want, "ABORT") == 0) { 326*17834Sralph AbortOn = flds[k+1]; 327*17834Sralph DEBUG(4, "ABORT ON: %s\n", AbortOn); 328*17834Sralph goto nextfield; 329*17834Sralph } 330*17834Sralph DEBUG(4, "wanted: %s\n", want); 33113642Ssam ok = expect(want, fn); 332*17834Sralph DEBUG(4, "got: %s\n", ok ? "?" : "that"); 333*17834Sralph if (ok == FAIL) { 334*17834Sralph if (altern == NULL) { 335*17834Sralph logent("LOGIN", _FAILED); 336*17834Sralph return FAIL; 337*17834Sralph } 338*17834Sralph want = index(altern, '-'); 339*17834Sralph if (want != NULL) 340*17834Sralph *want++ = '\0'; 341*17834Sralph sendthem(altern, fn); 342*17834Sralph } else 343*17834Sralph if (ok == ABORT) { 344*17834Sralph logent("LOGIN ABORTED", _FAILED); 345*17834Sralph return FAIL; 346*17834Sralph } 34713642Ssam } 348*17834Sralph sleep(1); 34913642Ssam if (k+1 < nf) 35013642Ssam sendthem(flds[k+1], fn); 351*17834Sralph nextfield: ; 35213642Ssam } 353*17834Sralph return SUCCESS; 35413642Ssam } 35513642Ssam 35613642Ssam 357*17834Sralph /* conditional table generation to support odd speeds */ 35813642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 35913642Ssam #ifdef B50 36013642Ssam { 50, B50}, 36113642Ssam #endif 36213642Ssam #ifdef B75 36313642Ssam { 75, B75}, 36413642Ssam #endif 36513642Ssam #ifdef B110 36613642Ssam { 110, B110}, 36713642Ssam #endif 36813642Ssam #ifdef B150 36913642Ssam { 150, B150}, 37013642Ssam #endif 37113642Ssam #ifdef B200 37213642Ssam { 200, B200}, 37313642Ssam #endif 37413642Ssam #ifdef B300 37513642Ssam { 300, B300}, 37613642Ssam #endif 37713642Ssam #ifdef B600 37813642Ssam {600, B600}, 37913642Ssam #endif 38013642Ssam #ifdef B1200 38113642Ssam {1200, B1200}, 38213642Ssam #endif 38313642Ssam #ifdef B1800 38413642Ssam {1800, B1800}, 38513642Ssam #endif 38613642Ssam #ifdef B2000 38713642Ssam {2000, B2000}, 38813642Ssam #endif 38913642Ssam #ifdef B2400 39013642Ssam {2400, B2400}, 39113642Ssam #endif 39213642Ssam #ifdef B3600 39313642Ssam {3600, B3600}, 39413642Ssam #endif 39513642Ssam #ifdef B4800 39613642Ssam {4800, B4800}, 39713642Ssam #endif 39813642Ssam #ifdef B7200 39913642Ssam {7200, B7200}, 40013642Ssam #endif 40113642Ssam #ifdef B9600 40213642Ssam {9600, B9600}, 40313642Ssam #endif 40413642Ssam #ifdef B19200 405*17834Sralph {19200, B19200}, 40613642Ssam #endif 407*17834Sralph #ifdef EXTA 408*17834Sralph {19200, EXTA}, 409*17834Sralph #endif 41013642Ssam {0, 0} 41113642Ssam }; 41213642Ssam 41313642Ssam /*** 41413642Ssam * fixline(tty, spwant) set speed/echo/mode... 41513642Ssam * int tty, spwant; 41613642Ssam * 41713642Ssam * return codes: none 41813642Ssam */ 41913642Ssam 42013642Ssam fixline(tty, spwant) 42113642Ssam int tty, spwant; 42213642Ssam { 423*17834Sralph #ifdef USG 42413642Ssam struct termio ttbuf; 425*17834Sralph #else !USG 42613642Ssam struct sgttyb ttbuf; 427*17834Sralph #endif !USG 42813642Ssam register struct sg_spds *ps; 42913642Ssam int speed = -1; 43013642Ssam int ret; 43113642Ssam 43213642Ssam for (ps = spds; ps->sp_val; ps++) 43313642Ssam if (ps->sp_val == spwant) 43413642Ssam speed = ps->sp_name; 435*17834Sralph ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); 436*17834Sralph #ifdef USG 43713642Ssam ioctl(tty, TCGETA, &ttbuf); 43813642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 43913642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 44013642Ssam ttbuf.c_iflag = (ushort)0; 44113642Ssam ttbuf.c_oflag = (ushort)0; 44213642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 44313642Ssam ttbuf.c_lflag = (ushort)0; 44413642Ssam ttbuf.c_cc[VMIN] = 6; 44513642Ssam ttbuf.c_cc[VTIME] = 1; 44613642Ssam ret = ioctl(tty, TCSETA, &ttbuf); 447*17834Sralph #else !USG 44813642Ssam ioctl(tty, TIOCGETP, &ttbuf); 44913642Ssam ttbuf.sg_flags = (ANYP|RAW); 45013642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 45113642Ssam ret = ioctl(tty, TIOCSETP, &ttbuf); 45213642Ssam #endif 453*17834Sralph ASSERT(ret >= 0, "RETURN FROM STTY", CNULL, ret); 454*17834Sralph #ifndef USG 45513642Ssam ioctl(tty, TIOCHPCL, STBNULL); 45613642Ssam ioctl(tty, TIOCEXCL, STBNULL); 45713642Ssam #endif 458*17834Sralph linebaudrate = spwant; 45913642Ssam return; 46013642Ssam } 46113642Ssam 462*17834Sralph #define MR 100 46313642Ssam 46413642Ssam /*** 46513642Ssam * expect(str, fn) look for expected string 46613642Ssam * char *str; 46713642Ssam * 46813642Ssam * return codes: 46913642Ssam * 0 - found 47013642Ssam * FAIL - lost line or too many characters read 47113642Ssam * some character - timed out 47213642Ssam */ 47313642Ssam 47413642Ssam expect(str, fn) 47513642Ssam register char *str; 47613642Ssam int fn; 47713642Ssam { 47814592Skarels char rdvec[MR]; 479*17834Sralph register char *rp = rdvec, *strptr; 480*17834Sralph int kr, cnt_char; 48113642Ssam char nextch; 48213642Ssam 483*17834Sralph if (*str == '\0' || strcmp(str, "\"\"") == SAME) 484*17834Sralph return SUCCESS; 485*17834Sralph /* Cleanup str, convert \0xx strings to one char */ 486*17834Sralph for (strptr = str; *strptr; strptr++) { 487*17834Sralph if (*strptr == '\\') 488*17834Sralph switch(*++strptr) { 489*17834Sralph case 's': 490*17834Sralph DEBUG(5, "BLANK\n", CNULL); 491*17834Sralph *strptr = ' '; 492*17834Sralph break; 493*17834Sralph default: 494*17834Sralph strptr--; /* back up to backslash */ 495*17834Sralph sscanf(strptr + 1,"%o", &cnt_char); 496*17834Sralph DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 497*17834Sralph *strptr = (char) (cnt_char); 498*17834Sralph strcpy(&strptr[1], &strptr[4]); 499*17834Sralph } 500*17834Sralph } 501*17834Sralph 50213642Ssam *rp = 0; 503*17834Sralph if (setjmp(Sjbuf)) 504*17834Sralph return FAIL; 50513642Ssam signal(SIGALRM, alarmtr); 50613642Ssam alarm(MAXMSGTIME); 50713642Ssam while (notin(str, rdvec)) { 508*17834Sralph if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 509*17834Sralph DEBUG(1, "Call aborted on '%s'\n", AbortOn); 510*17834Sralph alarm(0); 511*17834Sralph return ABORT; 512*17834Sralph } 51313642Ssam kr = read(fn, &nextch, 1); 51413642Ssam if (kr <= 0) { 51513642Ssam alarm(0); 51613642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 51713642Ssam logent("LOGIN", "LOST LINE"); 518*17834Sralph return FAIL; 51913642Ssam } 52013642Ssam { 52113642Ssam int c; 52213642Ssam c = nextch & 0177; 52313642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 524*17834Sralph if (c == '\n') 525*17834Sralph DEBUG(4,"\n", CNULL); 52613642Ssam } 52713642Ssam if ((*rp = nextch & 0177) != '\0') 52813642Ssam rp++; 52913642Ssam if (rp >= rdvec + MR) { 530*17834Sralph register char *p; 531*17834Sralph for (p = rdvec+MR/2; p < rp; p++) 532*17834Sralph *(p-MR/2) = *p; 533*17834Sralph rp -= MR/2; 53413642Ssam } 53513642Ssam *rp = '\0'; 53613642Ssam } 53713642Ssam alarm(0); 538*17834Sralph return SUCCESS; 53913642Ssam } 54013642Ssam 54113642Ssam 54213642Ssam /* 54313642Ssam * Determine next file descriptor that would be allocated. 54413642Ssam * This permits later closing of a file whose open was interrupted. 54513642Ssam * It is a UNIX kernel problem, but it has to be handled. 54613642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 54713642Ssam */ 54813642Ssam getnextfd() 54913642Ssam { 55013642Ssam close(next_fd = open("/", 0)); 55113642Ssam } 55213642Ssam 553*17834Sralph /* 554*17834Sralph * send line of login sequence 55513642Ssam * 55613642Ssam * return codes: none 55713642Ssam */ 55813642Ssam sendthem(str, fn) 55913642Ssam register char *str; 56013642Ssam int fn; 56113642Ssam { 56213642Ssam register char *strptr; 56313642Ssam int i, n, cr = 1; 564*17834Sralph register char c; 56513642Ssam static int p_init = 0; 56613642Ssam 56713642Ssam DEBUG(5, "send %s\n", str); 56813642Ssam 56913642Ssam if (!p_init) { 57013642Ssam p_init++; 57113642Ssam bld_partab(P_EVEN); 57213642Ssam } 57313642Ssam 57413642Ssam if (prefix("BREAK", str)) { 57513642Ssam sscanf(&str[5], "%1d", &i); 57613642Ssam if (i <= 0 || i > 10) 57713642Ssam i = 3; 57813642Ssam /* send break */ 57913642Ssam genbrk(fn, i); 58013642Ssam return; 58113642Ssam } 58213642Ssam 58313642Ssam if (prefix("PAUSE", str)) { 58413642Ssam sscanf(&str[5], "%1d", &i); 58513642Ssam if (i <= 0 || i > 10) 58613642Ssam i = 3; 58713642Ssam /* pause for a while */ 58813642Ssam sleep((unsigned)i); 58913642Ssam return; 59013642Ssam } 59113642Ssam 59213642Ssam if (strcmp(str, "EOT") == SAME) { 59313642Ssam p_chwrite(fn, '\04'); 59413642Ssam return; 59513642Ssam } 59613642Ssam 59713642Ssam /* Send a '\n' */ 59813642Ssam if (strcmp(str, "LF") == SAME) 59913642Ssam str = "\\n\\c"; 60013642Ssam 60113642Ssam /* Send a '\r' */ 60213642Ssam if (strcmp(str, "CR") == SAME) 60313642Ssam str = "\\r\\c"; 60413642Ssam 60513642Ssam /* Set parity as needed */ 60613642Ssam if (strcmp(str, "P_ZERO") == SAME) { 60713642Ssam bld_partab(P_ZERO); 60813642Ssam return; 60913642Ssam } 61013642Ssam if (strcmp(str, "P_ONE") == SAME) { 61113642Ssam bld_partab(P_ONE); 61213642Ssam return; 61313642Ssam } 61413642Ssam if (strcmp(str, "P_EVEN") == SAME) { 61513642Ssam bld_partab(P_EVEN); 61613642Ssam return; 61713642Ssam } 61813642Ssam if (strcmp(str, "P_ODD") == SAME) { 61913642Ssam bld_partab(P_ODD); 62013642Ssam return; 62113642Ssam } 62213642Ssam 62313642Ssam /* If "", just send '\r' */ 624*17834Sralph if (strcmp(str, "\"\"") == SAME) { 625*17834Sralph p_chwrite(fn, '\r'); 626*17834Sralph return; 627*17834Sralph } 628*17834Sralph 629*17834Sralph for (strptr = str; c = *strptr++;) { 630*17834Sralph if (c == '\\') { 631*17834Sralph switch(*strptr++) { 632*17834Sralph case 's': 633*17834Sralph DEBUG(5, "BLANK\n", CNULL); 634*17834Sralph p_chwrite(fn, ' '); 635*17834Sralph break; 636*17834Sralph case 'd': 637*17834Sralph DEBUG(5, "DELAY\n", CNULL); 638*17834Sralph sleep(1); 639*17834Sralph continue; 640*17834Sralph case 'r': 641*17834Sralph DEBUG(5, "RETURN\n", CNULL); 642*17834Sralph p_chwrite(fn, '\r'); 643*17834Sralph break; 644*17834Sralph case 'b': 645*17834Sralph if (isdigit(*strptr)) { 646*17834Sralph i = (*strptr++ - '0'); 647*17834Sralph if (i <= 0 || i > 10) 648*17834Sralph i = 3; 649*17834Sralph } else 65013642Ssam i = 3; 651*17834Sralph /* send break */ 652*17834Sralph genbrk(fn, i); 653*17834Sralph if (*strptr == '\0') 654*17834Sralph cr = 0; 65513642Ssam continue; 656*17834Sralph case 'c': 657*17834Sralph if (*strptr == '\0') { 658*17834Sralph DEBUG(5, "NO CR\n", CNULL); 659*17834Sralph cr = 0; 660*17834Sralph continue; 661*17834Sralph } 662*17834Sralph DEBUG(5, "NO CR - MIDDLE IGNORED\n", CNULL); 66313642Ssam continue; 664*17834Sralph default: 665*17834Sralph if (isdigit(*strptr)) { 666*17834Sralph i = 0; 667*17834Sralph n = 0; 668*17834Sralph while (isdigit(*strptr) && ++n <= 3) 669*17834Sralph i = i*8 + (*strptr++ - '0'); 670*17834Sralph p_chwrite(fn, (char)i); 671*17834Sralph continue; 672*17834Sralph } 673*17834Sralph DEBUG(5, "BACKSLASH\n", CNULL); 674*17834Sralph --strptr; 67513642Ssam } 676*17834Sralph } else 677*17834Sralph p_chwrite(fn, c); 67813642Ssam } 67913642Ssam 68013642Ssam if (cr) 68113642Ssam p_chwrite(fn, '\r'); 68213642Ssam return; 68313642Ssam } 68413642Ssam 68513642Ssam p_chwrite(fd, c) 68613642Ssam int fd; 687*17834Sralph char c; 68813642Ssam { 689*17834Sralph c = par_tab[c&0177]; 690*17834Sralph if (write(fd, &c, 1) != 1) { 691*17834Sralph logent(sys_errlist[errno], "BAD WRITE"); 692*17834Sralph longjmp(Cjbuf, 2); 693*17834Sralph } 69413642Ssam } 69513642Ssam 69613642Ssam /* 69713642Ssam * generate parity table for use by p_chwrite. 69813642Ssam */ 69913642Ssam bld_partab(type) 70013642Ssam int type; 70113642Ssam { 70213642Ssam register int i, j, n; 70313642Ssam 70413642Ssam for (i = 0; i < sizeof(par_tab); i++) { 70513642Ssam n = 0; 70613642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 70713642Ssam n++; 70813642Ssam par_tab[i] = i; 70913642Ssam if (type == P_ONE 71013642Ssam || (type == P_EVEN && (n&01) != 0) 71113642Ssam || (type == P_ODD && (n&01) == 0)) 71213642Ssam par_tab[i] |= sizeof(par_tab); 71313642Ssam } 71413642Ssam } 71513642Ssam 71613642Ssam #define BSPEED B150 71713642Ssam 71813642Ssam /*** 71913642Ssam * genbrk send a break 72013642Ssam * 72113642Ssam * return codes; none 72213642Ssam */ 72313642Ssam 72413642Ssam genbrk(fn, bnulls) 72513642Ssam register int fn, bnulls; 72613642Ssam { 72713642Ssam register int ret; 728*17834Sralph #ifdef USG 72913642Ssam ret = ioctl(fn, TCSBRK, STBNULL); 73013642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 731*17834Sralph #else !USG 73213642Ssam #ifdef TIOCSBRK 73313642Ssam ret = ioctl(fn, TIOCSBRK, STBNULL); 73413642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 73513642Ssam #ifdef TIOCCBRK 73613642Ssam sleep(1); 73713642Ssam ret = ioctl(fn, TIOCCBRK, STBNULL); 73813642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 739*17834Sralph #endif TIOCCBRK 740*17834Sralph DEBUG(4, "ioctl %d second break\n", bnulls ); 741*17834Sralph #else !TIOCSBRK 74213642Ssam struct sgttyb ttbuf; 74313642Ssam register int sospeed; 74413642Ssam 74513642Ssam ret = ioctl(fn, TIOCGETP, &ttbuf); 74613642Ssam sospeed = ttbuf.sg_ospeed; 74713642Ssam ttbuf.sg_ospeed = BSPEED; 74813642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 74913642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 750*17834Sralph if (ret != bnulls) { 751*17834Sralph badbreak: 752*17834Sralph logent(sys_errlist[errno], "BAD WRITE genbrk"); 753*17834Sralph alarm(0); 754*17834Sralph longjmp(Sjbuf, 3); 755*17834Sralph } 75613642Ssam ttbuf.sg_ospeed = sospeed; 75713642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 75813642Ssam ret = write(fn, "@", 1); 759*17834Sralph if (ret != 1) 760*17834Sralph goto badbreak; 76113642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 762*17834Sralph #endif !TIOCSBRK 763*17834Sralph #endif !USG 76413642Ssam } 76513642Ssam 76613642Ssam /*** 76713642Ssam * notin(sh, lg) check for occurrence of substring "sh" 76813642Ssam * char *sh, *lg; 76913642Ssam * 77013642Ssam * return codes: 77113642Ssam * 0 - found the string 77213642Ssam * 1 - not in the string 77313642Ssam */ 77413642Ssam notin(sh, lg) 77513642Ssam register char *sh, *lg; 77613642Ssam { 77713642Ssam while (*lg != '\0') { 77813642Ssam if (wprefix(sh, lg)) 77913642Ssam return(0); 78013642Ssam else 78113642Ssam lg++; 78213642Ssam } 78313642Ssam return(1); 78413642Ssam } 78513642Ssam 78613642Ssam /******* 78713642Ssam * ifdate(s) 78813642Ssam * char *s; 78913642Ssam * 79013642Ssam * ittvax!swatt 79113642Ssam * Allow multiple date specifications separated by '|'. 79213642Ssam * Calls ifadate, formerly "ifdate". 79313642Ssam * 79413642Ssam * return codes: 79513642Ssam * see ifadate 79613642Ssam */ 79713642Ssam 79813642Ssam ifdate(s) 79913642Ssam char *s; 80013642Ssam { 80113642Ssam register char *p; 80213642Ssam register int ret; 80313642Ssam 80413642Ssam for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|')) 80513642Ssam if (ret = ifadate(p)) 806*17834Sralph return ret; 807*17834Sralph return 0; 80813642Ssam } 80913642Ssam 81013642Ssam /******* 81113642Ssam * ifadate(s) 81213642Ssam * char *s; 81313642Ssam * 81413642Ssam * ifadate - this routine will check a string (s) 81513642Ssam * like "MoTu0800-1730" to see if the present 81613642Ssam * time is within the given limits. 81713642Ssam * SIDE EFFECT - Retrytime is set 81813642Ssam * 81913642Ssam * String alternatives: 82013642Ssam * Wk - Mo thru Fr 82113642Ssam * zero or one time means all day 82213642Ssam * Any - any day 82313642Ssam * 82413642Ssam * return codes: 82513642Ssam * 0 - not within limits 82613642Ssam * 1 - within limits 82713642Ssam */ 82813642Ssam 82913642Ssam ifadate(s) 83013642Ssam char *s; 83113642Ssam { 83213642Ssam static char *days[]={ 83313642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 83413642Ssam }; 83513642Ssam time_t clock; 83613642Ssam int rtime; 837*17834Sralph int i, tl, th, tn, dayok=0; 83813642Ssam struct tm *localtime(); 83913642Ssam struct tm *tp; 84013642Ssam char *index(); 84113642Ssam char *p; 84213642Ssam 84313642Ssam /* pick up retry time for failures */ 84413642Ssam /* global variable Retrytime is set here */ 84513642Ssam if ((p = index(s, ',')) == NULL) { 84613642Ssam Retrytime = RETRYTIME; 847*17834Sralph } else { 84813642Ssam i = sscanf(p+1, "%d", &rtime); 849*17834Sralph if (i < 1 || rtime < 0) 85013642Ssam rtime = 5; 85113642Ssam Retrytime = rtime * 60; 85213642Ssam } 85313642Ssam 85413642Ssam time(&clock); 85513642Ssam tp = localtime(&clock); 856*17834Sralph while (isascii(*s) && isalpha(*s)) { 85713642Ssam for (i = 0; days[i]; i++) { 85813642Ssam if (prefix(days[i], s)) 85913642Ssam if (tp->tm_wday == i) 86013642Ssam dayok = 1; 86113642Ssam } 86213642Ssam 86313642Ssam if (prefix("Wk", s)) 86413642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 86513642Ssam dayok = 1; 86613642Ssam if (prefix("Any", s)) 86713642Ssam dayok = 1; 868*17834Sralph if (prefix("Evening", s)) { 869*17834Sralph /* Sat or Sun */ 870*17834Sralph if (tp->tm_wday == 6 || tp->tm_wday == 0 871*17834Sralph || tp->tm_hour >= 17 || tp->tm_hour < 8) 872*17834Sralph dayok = 1; 873*17834Sralph } 874*17834Sralph if (prefix("Night", s)) { 875*17834Sralph if (tp->tm_wday == 6 /* Sat */ 876*17834Sralph || tp->tm_hour > 23 || tp->tm_hour < 8) 877*17834Sralph dayok = 1; 878*17834Sralph } 87913642Ssam s++; 88013642Ssam } 88113642Ssam 88213642Ssam if (dayok == 0) 88313642Ssam return(0); 88413642Ssam i = sscanf(s, "%d-%d", &tl, &th); 88513642Ssam if (i < 2) 88613642Ssam return(1); 887*17834Sralph tn = tp->tm_hour * 100 + tp->tm_min; 888*17834Sralph if (th < tl) { /* crosses midnight */ 889*17834Sralph if (tl <= tn || tn < th) 890*17834Sralph return(1); 891*17834Sralph } else 892*17834Sralph if (tl <= tn && tn < th) 893*17834Sralph return(1); 894*17834Sralph return(0); 89513642Ssam } 89613642Ssam 89713642Ssam 89813642Ssam /*** 89913642Ssam * char * 90013642Ssam * lastc(s) return pointer to last character 90113642Ssam * char *s; 90213642Ssam * 90313642Ssam */ 90413642Ssam char * 90513642Ssam lastc(s) 90613642Ssam register char *s; 90713642Ssam { 908*17834Sralph while (*s != '\0') 909*17834Sralph s++; 910*17834Sralph return s; 91113642Ssam } 91213642Ssam 91313642Ssam /*** 91413642Ssam * char * 91513642Ssam * fdig(cp) find first digit in string 91613642Ssam * 91713642Ssam * return - pointer to first digit in string or end of string 91813642Ssam */ 91913642Ssam char * 92013642Ssam fdig(cp) 92113642Ssam register char *cp; 92213642Ssam { 92313642Ssam register char *c; 92413642Ssam 92513642Ssam for (c = cp; *c; c++) 92613642Ssam if (*c >= '0' && *c <= '9') 92713642Ssam break; 928*17834Sralph return c; 92913642Ssam } 93013642Ssam 93113642Ssam /* 93213642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 93313642Ssam * Strings are compared as if they contain all capital letters. 93413642Ssam */ 93513642Ssam snccmp(s1, s2) 93613642Ssam register char *s1, *s2; 93713642Ssam { 93813642Ssam char c1, c2; 93913642Ssam 94013642Ssam if (islower(*s1)) c1 = toupper(*s1); 94113642Ssam else c1 = *s1; 94213642Ssam if (islower(*s2)) c2 = toupper(*s2); 94313642Ssam else c2 = *s2; 94413642Ssam 94513642Ssam while (c1 == c2) { 94613642Ssam if (*s1++=='\0') 947*17834Sralph return 0; 94813642Ssam s2++; 94913642Ssam if (islower(*s1)) c1 = toupper(*s1); 95013642Ssam else c1 = *s1; 95113642Ssam if (islower(*s2)) c2 = toupper(*s2); 95213642Ssam else c2 = *s2; 95313642Ssam } 954*17834Sralph return c1 - c2; 95513642Ssam } 956*17834Sralph /* 957*17834Sralph * do chat script 958*17834Sralph * occurs after local port is opened, 959*17834Sralph * before 'dialing' the other machine. 960*17834Sralph */ 961*17834Sralph dochat(dev, flds, fd) 962*17834Sralph register struct Devices *dev; 963*17834Sralph char *flds[]; 964*17834Sralph int fd; 965*17834Sralph { 966*17834Sralph register int i; 967*17834Sralph register char *p; 968*17834Sralph char bfr[sizeof(dev->D_argbfr)]; 969*17834Sralph 970*17834Sralph if (dev->D_numargs <= 5) 971*17834Sralph return(0); 972*17834Sralph DEBUG(4, "dochat called %d\n", dev->D_numargs); 973*17834Sralph for (i = 0; i < dev->D_numargs-5; i++) { 974*17834Sralph sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 975*17834Sralph if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 976*17834Sralph p = malloc((unsigned)strlen(bfr)+1); 977*17834Sralph if (p != NULL) { 978*17834Sralph strcpy(p, bfr); 979*17834Sralph dev->D_arg[D_CHAT+i] = p; 980*17834Sralph } 981*17834Sralph } 982*17834Sralph } 983*17834Sralph /* following is a kludge because login() arglist is a kludge */ 984*17834Sralph i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 985*17834Sralph /* 986*17834Sralph * If login() last did a sendthem(), must pause so things can settle. 987*17834Sralph * But don't bother if chat failed. 988*17834Sralph */ 989*17834Sralph if (i == 0 && (dev->D_numargs&01)) 990*17834Sralph sleep(2); 991*17834Sralph return(i); 992*17834Sralph } 993