1*13642Ssam #ifndef lint 2*13642Ssam static char sccsid[] = "@(#)conn.c 5.1 (Berkeley) 07/02/83"; 3*13642Ssam #endif 4*13642Ssam 5*13642Ssam #include "uucp.h" 6*13642Ssam #include <signal.h> 7*13642Ssam #include <setjmp.h> 8*13642Ssam #include <ctype.h> 9*13642Ssam #include <sys/types.h> 10*13642Ssam #include <time.h> 11*13642Ssam #include <errno.h> 12*13642Ssam #ifdef SYSIII 13*13642Ssam #include <termio.h> 14*13642Ssam #include <fcntl.h> 15*13642Ssam #endif 16*13642Ssam #ifndef SYSIII 17*13642Ssam #include <sgtty.h> 18*13642Ssam #endif 19*13642Ssam 20*13642Ssam #define MAXC 1000 21*13642Ssam 22*13642Ssam extern jmp_buf Sjbuf; 23*13642Ssam extern int errno; 24*13642Ssam 25*13642Ssam /* Parity control during login procedure */ 26*13642Ssam #define P_ZERO 0 27*13642Ssam #define P_ONE 1 28*13642Ssam #define P_EVEN 2 29*13642Ssam #define P_ODD 3 30*13642Ssam char par_tab[128]; /* must be power of two */ 31*13642Ssam 32*13642Ssam int next_fd = -1; /* predicted fd to close interrupted opens */ 33*13642Ssam /* rti!trt, courtesy unc!smb */ 34*13642Ssam /*** 35*13642Ssam * alarmtr() - catch alarm routine for "expect". 36*13642Ssam */ 37*13642Ssam alarmtr() 38*13642Ssam { 39*13642Ssam signal(SIGALRM, alarmtr); 40*13642Ssam if (next_fd >= 0) { 41*13642Ssam if (close(next_fd)) 42*13642Ssam logent("FAIL", "ACU LINE CLOSE"); 43*13642Ssam next_fd = -1; 44*13642Ssam } 45*13642Ssam longjmp(Sjbuf, 1); 46*13642Ssam } 47*13642Ssam 48*13642Ssam /******* 49*13642Ssam * conn(system) 50*13642Ssam * char *system; 51*13642Ssam * 52*13642Ssam * conn - place a telephone call to system and 53*13642Ssam * login, etc. 54*13642Ssam * 55*13642Ssam * return codes: 56*13642Ssam * CF_SYSTEM: don't know system 57*13642Ssam * CF_TIME: wrong time to call 58*13642Ssam * CF_DIAL: call failed 59*13642Ssam * CF_NODEV: no devices available to place call 60*13642Ssam * CF_LOGIN: login/password dialog failed 61*13642Ssam * 62*13642Ssam * >0 - file no. - connect ok 63*13642Ssam * 64*13642Ssam */ 65*13642Ssam 66*13642Ssam int Dcf = -1; 67*13642Ssam 68*13642Ssam conn(system) 69*13642Ssam char *system; 70*13642Ssam { 71*13642Ssam int ret, nf; 72*13642Ssam register int fn, fnd; 73*13642Ssam char info[MAXC], *flds[MAXC/10]; 74*13642Ssam register FILE *fsys; 75*13642Ssam int fcode = 0; 76*13642Ssam 77*13642Ssam nf = 0; 78*13642Ssam fnd = 0; 79*13642Ssam 80*13642Ssam 81*13642Ssam fsys = fopen(SYSFILE, "r"); 82*13642Ssam ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 83*13642Ssam 84*13642Ssam DEBUG(4, "finds %s\n", "called"); 85*13642Ssam while((nf = finds(fsys, system, info, flds)) > 0) { 86*13642Ssam DEBUG(4, "getto %s\n", "called"); 87*13642Ssam if ((fn = getto(flds)) > 0) { 88*13642Ssam fnd = 1; 89*13642Ssam Dcf = fn; 90*13642Ssam break; 91*13642Ssam } 92*13642Ssam fcode = (fn == FAIL ? CF_DIAL : fn); 93*13642Ssam } 94*13642Ssam fclose(fsys); 95*13642Ssam 96*13642Ssam if (nf <= 0) 97*13642Ssam return(fcode ? fcode : nf); 98*13642Ssam 99*13642Ssam DEBUG(4, "login %s\n", "called"); 100*13642Ssam ret = login(nf, flds, fn); 101*13642Ssam if (ret < 0) { 102*13642Ssam clsacu(); 103*13642Ssam return(CF_LOGIN); 104*13642Ssam } 105*13642Ssam /* rti!trt: avoid passing file to children */ 106*13642Ssam fioclex(fn); 107*13642Ssam return(fn); 108*13642Ssam } 109*13642Ssam 110*13642Ssam /*** 111*13642Ssam * getto(flds) connect to remote machine 112*13642Ssam * char *flds[]; 113*13642Ssam * 114*13642Ssam * return codes: 115*13642Ssam * >0 - file number - ok 116*13642Ssam * FAIL - failed 117*13642Ssam */ 118*13642Ssam 119*13642Ssam getto(flds) 120*13642Ssam register char *flds[]; 121*13642Ssam { 122*13642Ssam register struct condev *cd; 123*13642Ssam int nulldev(), diropn(); 124*13642Ssam 125*13642Ssam DEBUG(4, "call: no. %s ", flds[F_PHONE]); 126*13642Ssam DEBUG(4, "for sys %s\n", flds[F_NAME]); 127*13642Ssam 128*13642Ssam CU_end = nulldev; 129*13642Ssam for (cd = condevs; cd->CU_meth != NULL; cd++) { 130*13642Ssam if (snccmp(cd->CU_meth, flds[F_LINE]) == SAME) { 131*13642Ssam DEBUG(4, "Using %s to call\n", cd->CU_meth); 132*13642Ssam return((*(cd->CU_gen))(flds)); 133*13642Ssam } 134*13642Ssam } 135*13642Ssam logent(flds[F_LINE], "getto: Can't find, using DIR"); 136*13642Ssam return(diropn(flds)); /* search failed, so use direct */ 137*13642Ssam } 138*13642Ssam 139*13642Ssam /*** 140*13642Ssam * clsacu() close call unit 141*13642Ssam * 142*13642Ssam * return codes: none 143*13642Ssam */ 144*13642Ssam 145*13642Ssam int (*CU_end)() = nulldev; 146*13642Ssam clsacu() 147*13642Ssam { 148*13642Ssam (*(CU_end))(Dcf); 149*13642Ssam if (close(Dcf) == 0) { 150*13642Ssam DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 151*13642Ssam logent("clsacu", "NOT CLOSED by CU_clos"); 152*13642Ssam } 153*13642Ssam Dcf = -1; 154*13642Ssam CU_end = nulldev; 155*13642Ssam } 156*13642Ssam 157*13642Ssam /*** 158*13642Ssam * exphone - expand phone number for given prefix and number 159*13642Ssam * 160*13642Ssam * return code - none 161*13642Ssam */ 162*13642Ssam 163*13642Ssam exphone(in, out) 164*13642Ssam register char *in, *out; 165*13642Ssam { 166*13642Ssam FILE *fn; 167*13642Ssam char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 168*13642Ssam char buf[BUFSIZ]; 169*13642Ssam register char *s1; 170*13642Ssam 171*13642Ssam if (!isalpha(*in)) { 172*13642Ssam strcpy(out, in); 173*13642Ssam return; 174*13642Ssam } 175*13642Ssam 176*13642Ssam s1=pre; 177*13642Ssam while (isalpha(*in)) 178*13642Ssam *s1++ = *in++; 179*13642Ssam *s1 = '\0'; 180*13642Ssam s1 = npart; 181*13642Ssam while (*in != '\0') 182*13642Ssam *s1++ = *in++; 183*13642Ssam *s1 = '\0'; 184*13642Ssam 185*13642Ssam tpre[0] = '\0'; 186*13642Ssam if ((fn = fopen(DIALFILE, "r")) == NULL) 187*13642Ssam DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 188*13642Ssam else { 189*13642Ssam while (cfgets(buf, BUFSIZ, fn)) { 190*13642Ssam sscanf(buf, "%s%s", p, tpre); 191*13642Ssam if (strcmp(p, pre) == SAME) 192*13642Ssam goto found; 193*13642Ssam tpre[0] = '\0'; 194*13642Ssam } 195*13642Ssam DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 196*13642Ssam found:; 197*13642Ssam fclose(fn); 198*13642Ssam } 199*13642Ssam 200*13642Ssam strcpy(out, tpre); 201*13642Ssam strcat(out, npart); 202*13642Ssam return; 203*13642Ssam } 204*13642Ssam 205*13642Ssam /*** 206*13642Ssam * rddev - read and decode a line from device file 207*13642Ssam * 208*13642Ssam * return code - FAIL at end-of file; 0 otherwise 209*13642Ssam */ 210*13642Ssam 211*13642Ssam rddev(fp, dev) 212*13642Ssam register struct Devices *dev; 213*13642Ssam FILE *fp; 214*13642Ssam { 215*13642Ssam char *fdig(); 216*13642Ssam char buf[BUFSIZ]; 217*13642Ssam int na; 218*13642Ssam 219*13642Ssam if (!cfgets(buf, BUFSIZ, fp)) 220*13642Ssam return(FAIL); 221*13642Ssam 222*13642Ssam na = sscanf(buf, "%s%s%s%s%s", dev->D_type, dev->D_line, 223*13642Ssam dev->D_calldev, dev->D_class, dev->D_brand); 224*13642Ssam ASSERT(na >= 4, "BAD DEVICE ENTRY", buf, 0); 225*13642Ssam if (na != 5) dev->D_brand[0] = '\0'; 226*13642Ssam dev->D_speed = atoi(fdig(dev->D_class)); 227*13642Ssam return(0); 228*13642Ssam } 229*13642Ssam 230*13642Ssam /*** 231*13642Ssam * finds(fsys, sysnam, info, flds) set system attribute vector 232*13642Ssam * 233*13642Ssam * return codes: 234*13642Ssam * >0 - number of arguments in vector - succeeded 235*13642Ssam * CF_SYSTEM - system name not found 236*13642Ssam * CF_TIME - wrong time to call 237*13642Ssam */ 238*13642Ssam 239*13642Ssam finds(fsys, sysnam, info, flds) 240*13642Ssam char *sysnam, info[], *flds[]; 241*13642Ssam FILE *fsys; 242*13642Ssam { 243*13642Ssam char sysn[8]; 244*13642Ssam int na; 245*13642Ssam int fcode = 0; 246*13642Ssam 247*13642Ssam /* format of fields 248*13642Ssam * 0 name; 249*13642Ssam * 1 time 250*13642Ssam * 2 acu/hardwired 251*13642Ssam * 3 speed 252*13642Ssam * etc 253*13642Ssam */ 254*13642Ssam while (cfgets(info, MAXC, fsys) != NULL) { 255*13642Ssam na = getargs(info, flds); 256*13642Ssam sprintf(sysn, "%.7s", flds[F_NAME]); 257*13642Ssam if (strcmp(sysnam, sysn) != SAME) 258*13642Ssam continue; 259*13642Ssam if (ifdate(flds[F_TIME])) 260*13642Ssam /* found a good entry */ 261*13642Ssam return(na); 262*13642Ssam DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 263*13642Ssam fcode = CF_TIME; 264*13642Ssam } 265*13642Ssam return(fcode ? fcode : CF_SYSTEM); 266*13642Ssam } 267*13642Ssam 268*13642Ssam /*** 269*13642Ssam * login(nf, flds, dcr) do login conversation 270*13642Ssam * char *flds[]; 271*13642Ssam * int nf; 272*13642Ssam * 273*13642Ssam * return codes: 0 | FAIL 274*13642Ssam */ 275*13642Ssam 276*13642Ssam login(nf, flds, fn) 277*13642Ssam register char *flds[]; 278*13642Ssam int nf, fn; 279*13642Ssam { 280*13642Ssam register char *want, *altern; 281*13642Ssam extern char *index(); 282*13642Ssam int k, ok; 283*13642Ssam 284*13642Ssam ASSERT(nf > 4, "TOO FEW LOG FIELDS", "", nf); 285*13642Ssam for (k = F_LOGIN; k < nf; k += 2) { 286*13642Ssam want = flds[k]; 287*13642Ssam ok = FAIL; 288*13642Ssam while (ok != 0) { 289*13642Ssam altern = index(want, '-'); 290*13642Ssam if (altern != NULL) 291*13642Ssam *altern++ = '\0'; 292*13642Ssam DEBUG(4, "wanted %s ", want); 293*13642Ssam ok = expect(want, fn); 294*13642Ssam DEBUG(4, "got %s\n", ok ? "?" : "that"); 295*13642Ssam if (ok == 0) 296*13642Ssam break; 297*13642Ssam if (altern == NULL) { 298*13642Ssam logent("LOGIN", "FAILED"); 299*13642Ssam /* close *not* needed here. rti!trt */ 300*13642Ssam return(FAIL); 301*13642Ssam } 302*13642Ssam want = index(altern, '-'); 303*13642Ssam if (want != NULL) 304*13642Ssam *want++ = '\0'; 305*13642Ssam sendthem(altern, fn); 306*13642Ssam } 307*13642Ssam sleep(2); 308*13642Ssam if (k+1 < nf) 309*13642Ssam sendthem(flds[k+1], fn); 310*13642Ssam } 311*13642Ssam return(0); 312*13642Ssam } 313*13642Ssam 314*13642Ssam 315*13642Ssam /* rti!trt: conditional table generation to support odd speeds */ 316*13642Ssam /* Suggested in n44a.139 by n44!dan (Dan Ts'o) */ 317*13642Ssam struct sg_spds {int sp_val, sp_name;} spds[] = { 318*13642Ssam #ifdef B50 319*13642Ssam { 50, B50}, 320*13642Ssam #endif 321*13642Ssam #ifdef B75 322*13642Ssam { 75, B75}, 323*13642Ssam #endif 324*13642Ssam #ifdef B110 325*13642Ssam { 110, B110}, 326*13642Ssam #endif 327*13642Ssam #ifdef B150 328*13642Ssam { 150, B150}, 329*13642Ssam #endif 330*13642Ssam #ifdef B200 331*13642Ssam { 200, B200}, 332*13642Ssam #endif 333*13642Ssam #ifdef B300 334*13642Ssam { 300, B300}, 335*13642Ssam #endif 336*13642Ssam #ifdef B600 337*13642Ssam {600, B600}, 338*13642Ssam #endif 339*13642Ssam #ifdef B1200 340*13642Ssam {1200, B1200}, 341*13642Ssam #endif 342*13642Ssam #ifdef B1800 343*13642Ssam {1800, B1800}, 344*13642Ssam #endif 345*13642Ssam #ifdef B2000 346*13642Ssam {2000, B2000}, 347*13642Ssam #endif 348*13642Ssam #ifdef B2400 349*13642Ssam {2400, B2400}, 350*13642Ssam #endif 351*13642Ssam #ifdef B3600 352*13642Ssam {3600, B3600}, 353*13642Ssam #endif 354*13642Ssam #ifdef B4800 355*13642Ssam {4800, B4800}, 356*13642Ssam #endif 357*13642Ssam #ifdef B7200 358*13642Ssam {7200, B7200}, 359*13642Ssam #endif 360*13642Ssam #ifdef B9600 361*13642Ssam {9600, B9600}, 362*13642Ssam #endif 363*13642Ssam #ifdef B19200 364*13642Ssam {19200,B19200}, 365*13642Ssam #endif 366*13642Ssam {0, 0} 367*13642Ssam }; 368*13642Ssam 369*13642Ssam /*** 370*13642Ssam * fixline(tty, spwant) set speed/echo/mode... 371*13642Ssam * int tty, spwant; 372*13642Ssam * 373*13642Ssam * return codes: none 374*13642Ssam */ 375*13642Ssam 376*13642Ssam fixline(tty, spwant) 377*13642Ssam int tty, spwant; 378*13642Ssam { 379*13642Ssam #ifdef SYSIII 380*13642Ssam struct termio ttbuf; 381*13642Ssam #endif 382*13642Ssam #ifndef SYSIII 383*13642Ssam struct sgttyb ttbuf; 384*13642Ssam #endif 385*13642Ssam register struct sg_spds *ps; 386*13642Ssam int speed = -1; 387*13642Ssam int ret; 388*13642Ssam 389*13642Ssam for (ps = spds; ps->sp_val; ps++) 390*13642Ssam if (ps->sp_val == spwant) 391*13642Ssam speed = ps->sp_name; 392*13642Ssam ASSERT(speed >= 0, "BAD SPEED", "", speed); 393*13642Ssam #ifdef SYSIII 394*13642Ssam ioctl(tty, TCGETA, &ttbuf); 395*13642Ssam /* ttbuf.sg_flags = (ANYP|RAW); 396*13642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 397*13642Ssam ttbuf.c_iflag = (ushort)0; 398*13642Ssam ttbuf.c_oflag = (ushort)0; 399*13642Ssam ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 400*13642Ssam ttbuf.c_lflag = (ushort)0; 401*13642Ssam ttbuf.c_cc[VMIN] = 6; 402*13642Ssam ttbuf.c_cc[VTIME] = 1; 403*13642Ssam ret = ioctl(tty, TCSETA, &ttbuf); 404*13642Ssam #endif 405*13642Ssam #ifndef SYSIII 406*13642Ssam ioctl(tty, TIOCGETP, &ttbuf); 407*13642Ssam ttbuf.sg_flags = (ANYP|RAW); 408*13642Ssam ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 409*13642Ssam ret = ioctl(tty, TIOCSETP, &ttbuf); 410*13642Ssam #endif 411*13642Ssam ASSERT(ret >= 0, "RETURN FROM STTY", "", ret); 412*13642Ssam #ifndef SYSIII 413*13642Ssam ioctl(tty, TIOCHPCL, STBNULL); 414*13642Ssam ioctl(tty, TIOCEXCL, STBNULL); 415*13642Ssam #endif 416*13642Ssam return; 417*13642Ssam } 418*13642Ssam 419*13642Ssam 420*13642Ssam /* Bill Shannon recommends MR 2000, but that takes too much space on PDPs */ 421*13642Ssam /* Actually, the 'expect' algorithm should be rewritten. */ 422*13642Ssam #define MR 1000 423*13642Ssam 424*13642Ssam 425*13642Ssam /*** 426*13642Ssam * expect(str, fn) look for expected string 427*13642Ssam * char *str; 428*13642Ssam * 429*13642Ssam * return codes: 430*13642Ssam * 0 - found 431*13642Ssam * FAIL - lost line or too many characters read 432*13642Ssam * some character - timed out 433*13642Ssam */ 434*13642Ssam 435*13642Ssam expect(str, fn) 436*13642Ssam register char *str; 437*13642Ssam int fn; 438*13642Ssam { 439*13642Ssam static char rdvec[MR]; 440*13642Ssam register char *rp = rdvec; 441*13642Ssam int kr; 442*13642Ssam char nextch; 443*13642Ssam 444*13642Ssam if (strcmp(str, "\"\"") == SAME) 445*13642Ssam return(0); 446*13642Ssam *rp = 0; 447*13642Ssam if (setjmp(Sjbuf)) { 448*13642Ssam return(FAIL); 449*13642Ssam } 450*13642Ssam signal(SIGALRM, alarmtr); 451*13642Ssam /* change MAXCHARTIME to MAXMSGTIME, outside while loop -- brl-bmd!dpk */ 452*13642Ssam alarm(MAXMSGTIME); 453*13642Ssam while (notin(str, rdvec)) { 454*13642Ssam kr = read(fn, &nextch, 1); 455*13642Ssam if (kr <= 0) { 456*13642Ssam alarm(0); 457*13642Ssam DEBUG(4, "lost line kr - %d\n, ", kr); 458*13642Ssam logent("LOGIN", "LOST LINE"); 459*13642Ssam return(FAIL); 460*13642Ssam } 461*13642Ssam { 462*13642Ssam int c; 463*13642Ssam c = nextch & 0177; 464*13642Ssam DEBUG(4, c >= 040 ? "%c" : "\\%03o", c); 465*13642Ssam } 466*13642Ssam if ((*rp = nextch & 0177) != '\0') 467*13642Ssam rp++; 468*13642Ssam /* Check rdvec before null termination -- cmcl2!salkind */ 469*13642Ssam if (rp >= rdvec + MR) { 470*13642Ssam alarm(0); 471*13642Ssam return(FAIL); 472*13642Ssam } 473*13642Ssam *rp = '\0'; 474*13642Ssam } 475*13642Ssam alarm(0); 476*13642Ssam return(0); 477*13642Ssam } 478*13642Ssam 479*13642Ssam 480*13642Ssam /* 481*13642Ssam * Determine next file descriptor that would be allocated. 482*13642Ssam * This permits later closing of a file whose open was interrupted. 483*13642Ssam * It is a UNIX kernel problem, but it has to be handled. 484*13642Ssam * unc!smb (Steve Bellovin) probably first discovered it. 485*13642Ssam */ 486*13642Ssam getnextfd() 487*13642Ssam { 488*13642Ssam close(next_fd = open("/", 0)); 489*13642Ssam } 490*13642Ssam 491*13642Ssam /*** 492*13642Ssam * sendthem(str, fn) send line of login sequence 493*13642Ssam * char *str; 494*13642Ssam * 495*13642Ssam * return codes: none 496*13642Ssam */ 497*13642Ssam 498*13642Ssam sendthem(str, fn) 499*13642Ssam register char *str; 500*13642Ssam int fn; 501*13642Ssam { 502*13642Ssam register char *strptr; 503*13642Ssam int i, n, cr = 1; 504*13642Ssam static int p_init = 0; 505*13642Ssam 506*13642Ssam /* Note: debugging authorized only for privileged users */ 507*13642Ssam DEBUG(5, "send %s\n", str); 508*13642Ssam 509*13642Ssam if (!p_init) { 510*13642Ssam p_init++; 511*13642Ssam bld_partab(P_EVEN); 512*13642Ssam } 513*13642Ssam 514*13642Ssam if (prefix("BREAK", str)) { 515*13642Ssam sscanf(&str[5], "%1d", &i); 516*13642Ssam if (i <= 0 || i > 10) 517*13642Ssam i = 3; 518*13642Ssam /* send break */ 519*13642Ssam genbrk(fn, i); 520*13642Ssam return; 521*13642Ssam } 522*13642Ssam 523*13642Ssam if (prefix("PAUSE", str)) { 524*13642Ssam sscanf(&str[5], "%1d", &i); 525*13642Ssam if (i <= 0 || i > 10) 526*13642Ssam i = 3; 527*13642Ssam /* pause for a while */ 528*13642Ssam sleep((unsigned)i); 529*13642Ssam return; 530*13642Ssam } 531*13642Ssam 532*13642Ssam if (strcmp(str, "EOT") == SAME) { 533*13642Ssam p_chwrite(fn, '\04'); 534*13642Ssam return; 535*13642Ssam } 536*13642Ssam 537*13642Ssam /* LF, CR, and "" courtesy unc!smb */ 538*13642Ssam /* Send a '\n' */ 539*13642Ssam if (strcmp(str, "LF") == SAME) 540*13642Ssam str = "\\n\\c"; 541*13642Ssam 542*13642Ssam /* Send a '\r' */ 543*13642Ssam if (strcmp(str, "CR") == SAME) 544*13642Ssam str = "\\r\\c"; 545*13642Ssam 546*13642Ssam /* Set parity as needed */ 547*13642Ssam if (strcmp(str, "P_ZERO") == SAME) { 548*13642Ssam bld_partab(P_ZERO); 549*13642Ssam return; 550*13642Ssam } 551*13642Ssam if (strcmp(str, "P_ONE") == SAME) { 552*13642Ssam bld_partab(P_ONE); 553*13642Ssam return; 554*13642Ssam } 555*13642Ssam if (strcmp(str, "P_EVEN") == SAME) { 556*13642Ssam bld_partab(P_EVEN); 557*13642Ssam return; 558*13642Ssam } 559*13642Ssam if (strcmp(str, "P_ODD") == SAME) { 560*13642Ssam bld_partab(P_ODD); 561*13642Ssam return; 562*13642Ssam } 563*13642Ssam 564*13642Ssam /* If "", just send '\r' */ 565*13642Ssam if (strcmp(str, "\"\"") != SAME) 566*13642Ssam for (strptr = str; *strptr; strptr++) { 567*13642Ssam if (*strptr == '\\') switch(*++strptr) { 568*13642Ssam case 's': 569*13642Ssam DEBUG(5, "BLANK\n", ""); 570*13642Ssam *strptr = ' '; 571*13642Ssam break; 572*13642Ssam case 'd': 573*13642Ssam DEBUG(5, "DELAY\n", ""); 574*13642Ssam sleep(1); 575*13642Ssam continue; 576*13642Ssam case 'r': 577*13642Ssam DEBUG(5, "RETURN\n", ""); 578*13642Ssam *strptr = '\r'; 579*13642Ssam break; 580*13642Ssam case 'b': 581*13642Ssam if (isdigit(*(strptr+1))) { 582*13642Ssam i = (*++strptr - '0'); 583*13642Ssam if (i <= 0 || i > 10) 584*13642Ssam i = 3; 585*13642Ssam } else 586*13642Ssam i = 3; 587*13642Ssam /* send break */ 588*13642Ssam genbrk(fn, i); 589*13642Ssam continue; 590*13642Ssam case 'c': 591*13642Ssam if (*(strptr+1) == '\0') { 592*13642Ssam DEBUG(5, "NO CR\n", ""); 593*13642Ssam cr = 0; 594*13642Ssam continue; 595*13642Ssam } 596*13642Ssam DEBUG(5, "NO CR - MIDDLE IGNORED\n", ""); 597*13642Ssam continue; 598*13642Ssam default: 599*13642Ssam if (isdigit(strptr[1])) { 600*13642Ssam i = 0; 601*13642Ssam n = 0; 602*13642Ssam while (isdigit(strptr[1]) && ++n <= 3) 603*13642Ssam i = i*8 + (*++strptr - '0'); 604*13642Ssam p_chwrite(fn, i); 605*13642Ssam continue; 606*13642Ssam } 607*13642Ssam DEBUG(5, "BACKSLASH\n", ""); 608*13642Ssam strptr--; 609*13642Ssam } 610*13642Ssam p_chwrite(fn, *strptr); 611*13642Ssam } 612*13642Ssam 613*13642Ssam /* '\n' changed to '\r'--a better default. rti!trt */ 614*13642Ssam if (cr) 615*13642Ssam p_chwrite(fn, '\r'); 616*13642Ssam return; 617*13642Ssam } 618*13642Ssam 619*13642Ssam p_chwrite(fd, c) 620*13642Ssam int fd; 621*13642Ssam int c; 622*13642Ssam { 623*13642Ssam char t[2]; 624*13642Ssam 625*13642Ssam t[0] = par_tab[c&0177]; 626*13642Ssam t[1] = '\0'; 627*13642Ssam ASSERT(write(fd, t, 1) == 1, "BAD WRITE", "", t[0]); 628*13642Ssam } 629*13642Ssam 630*13642Ssam /* 631*13642Ssam * generate parity table for use by p_chwrite. 632*13642Ssam */ 633*13642Ssam bld_partab(type) 634*13642Ssam int type; 635*13642Ssam { 636*13642Ssam register int i, j, n; 637*13642Ssam 638*13642Ssam for (i = 0; i < sizeof(par_tab); i++) { 639*13642Ssam n = 0; 640*13642Ssam for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 641*13642Ssam n++; 642*13642Ssam par_tab[i] = i; 643*13642Ssam if (type == P_ONE 644*13642Ssam || (type == P_EVEN && (n&01) != 0) 645*13642Ssam || (type == P_ODD && (n&01) == 0)) 646*13642Ssam par_tab[i] |= sizeof(par_tab); 647*13642Ssam } 648*13642Ssam } 649*13642Ssam 650*13642Ssam #define BSPEED B150 651*13642Ssam 652*13642Ssam /*** 653*13642Ssam * genbrk send a break 654*13642Ssam * 655*13642Ssam * return codes; none 656*13642Ssam */ 657*13642Ssam 658*13642Ssam genbrk(fn, bnulls) 659*13642Ssam register int fn, bnulls; 660*13642Ssam { 661*13642Ssam register int ret; 662*13642Ssam #ifdef SYSIII 663*13642Ssam ret = ioctl(fn, TCSBRK, STBNULL); 664*13642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 665*13642Ssam #endif 666*13642Ssam #ifndef SYSIII 667*13642Ssam #ifdef TIOCSBRK 668*13642Ssam ret = ioctl(fn, TIOCSBRK, STBNULL); 669*13642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 670*13642Ssam #ifdef TIOCCBRK 671*13642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 672*13642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 673*13642Ssam sleep(1); 674*13642Ssam ret = ioctl(fn, TIOCCBRK, STBNULL); 675*13642Ssam DEBUG(5, "break ioctl ret %d\n", ret); 676*13642Ssam #endif 677*13642Ssam DEBUG(4, "ioctl 1 second break\n", STBNULL); 678*13642Ssam #else 679*13642Ssam struct sgttyb ttbuf; 680*13642Ssam register int sospeed; 681*13642Ssam 682*13642Ssam ret = ioctl(fn, TIOCGETP, &ttbuf); 683*13642Ssam sospeed = ttbuf.sg_ospeed; 684*13642Ssam ttbuf.sg_ospeed = BSPEED; 685*13642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 686*13642Ssam ret = write(fn, "\0\0\0\0\0\0\0\0\0\0\0\0", bnulls); 687*13642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 688*13642Ssam ttbuf.sg_ospeed = sospeed; 689*13642Ssam ret = ioctl(fn, TIOCSETP, &ttbuf); 690*13642Ssam ret = write(fn, "@", 1); 691*13642Ssam ASSERT(ret > 0, "BAD WRITE genbrk", "", ret); 692*13642Ssam DEBUG(4, "sent BREAK nulls - %d\n", bnulls); 693*13642Ssam #endif 694*13642Ssam #endif 695*13642Ssam } 696*13642Ssam 697*13642Ssam 698*13642Ssam /*** 699*13642Ssam * notin(sh, lg) check for occurrence of substring "sh" 700*13642Ssam * char *sh, *lg; 701*13642Ssam * 702*13642Ssam * return codes: 703*13642Ssam * 0 - found the string 704*13642Ssam * 1 - not in the string 705*13642Ssam */ 706*13642Ssam 707*13642Ssam notin(sh, lg) 708*13642Ssam register char *sh, *lg; 709*13642Ssam { 710*13642Ssam while (*lg != '\0') { 711*13642Ssam /* Dave Martingale: permit wild cards in 'expect' */ 712*13642Ssam if (wprefix(sh, lg)) 713*13642Ssam return(0); 714*13642Ssam else 715*13642Ssam lg++; 716*13642Ssam } 717*13642Ssam return(1); 718*13642Ssam } 719*13642Ssam 720*13642Ssam 721*13642Ssam /******* 722*13642Ssam * ifdate(s) 723*13642Ssam * char *s; 724*13642Ssam * 725*13642Ssam * ittvax!swatt 726*13642Ssam * Allow multiple date specifications separated by '|'. 727*13642Ssam * Calls ifadate, formerly "ifdate". 728*13642Ssam * 729*13642Ssam * return codes: 730*13642Ssam * see ifadate 731*13642Ssam */ 732*13642Ssam 733*13642Ssam ifdate(s) 734*13642Ssam char *s; 735*13642Ssam { 736*13642Ssam register char *p; 737*13642Ssam register int ret; 738*13642Ssam 739*13642Ssam for (p = s; p && (*p == '|' ? *++p : *p); p = index(p, '|')) 740*13642Ssam if (ret = ifadate(p)) 741*13642Ssam return(ret); 742*13642Ssam return(0); 743*13642Ssam } 744*13642Ssam 745*13642Ssam 746*13642Ssam /******* 747*13642Ssam * ifadate(s) 748*13642Ssam * char *s; 749*13642Ssam * 750*13642Ssam * ifadate - this routine will check a string (s) 751*13642Ssam * like "MoTu0800-1730" to see if the present 752*13642Ssam * time is within the given limits. 753*13642Ssam * SIDE EFFECT - Retrytime is set 754*13642Ssam * 755*13642Ssam * String alternatives: 756*13642Ssam * Wk - Mo thru Fr 757*13642Ssam * zero or one time means all day 758*13642Ssam * Any - any day 759*13642Ssam * 760*13642Ssam * return codes: 761*13642Ssam * 0 - not within limits 762*13642Ssam * 1 - within limits 763*13642Ssam */ 764*13642Ssam 765*13642Ssam ifadate(s) 766*13642Ssam char *s; 767*13642Ssam { 768*13642Ssam static char *days[]={ 769*13642Ssam "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 770*13642Ssam }; 771*13642Ssam time_t clock; 772*13642Ssam int rtime; 773*13642Ssam int i, tl, th, tn, flag, dayok=0; 774*13642Ssam struct tm *localtime(); 775*13642Ssam struct tm *tp; 776*13642Ssam char *index(); 777*13642Ssam char *p; 778*13642Ssam 779*13642Ssam /* pick up retry time for failures */ 780*13642Ssam /* global variable Retrytime is set here */ 781*13642Ssam if ((p = index(s, ',')) == NULL) { 782*13642Ssam Retrytime = RETRYTIME; 783*13642Ssam } 784*13642Ssam else { 785*13642Ssam i = sscanf(p+1, "%d", &rtime); 786*13642Ssam if (i < 1 || rtime < 5) 787*13642Ssam rtime = 5; 788*13642Ssam Retrytime = rtime * 60; 789*13642Ssam } 790*13642Ssam 791*13642Ssam time(&clock); 792*13642Ssam tp = localtime(&clock); 793*13642Ssam while (isalpha(*s)) { 794*13642Ssam for (i = 0; days[i]; i++) { 795*13642Ssam if (prefix(days[i], s)) 796*13642Ssam if (tp->tm_wday == i) 797*13642Ssam dayok = 1; 798*13642Ssam } 799*13642Ssam 800*13642Ssam if (prefix("Wk", s)) 801*13642Ssam if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 802*13642Ssam dayok = 1; 803*13642Ssam if (prefix("Any", s)) 804*13642Ssam dayok = 1; 805*13642Ssam s++; 806*13642Ssam } 807*13642Ssam 808*13642Ssam if (dayok == 0) 809*13642Ssam return(0); 810*13642Ssam i = sscanf(s, "%d-%d", &tl, &th); 811*13642Ssam tn = tp->tm_hour * 100 + tp->tm_min; 812*13642Ssam if (i < 2) 813*13642Ssam return(1); 814*13642Ssam if (th < tl) 815*13642Ssam flag = 0; /* set up for crossover 2400 test */ 816*13642Ssam else 817*13642Ssam flag = 1; 818*13642Ssam if ((tn >= tl && tn <= th) 819*13642Ssam || (tn >= th && tn <= tl)) /* test for crossover 2400 */ 820*13642Ssam return(flag); 821*13642Ssam else 822*13642Ssam return(!flag); 823*13642Ssam } 824*13642Ssam 825*13642Ssam 826*13642Ssam /*** 827*13642Ssam * char * 828*13642Ssam * lastc(s) return pointer to last character 829*13642Ssam * char *s; 830*13642Ssam * 831*13642Ssam */ 832*13642Ssam 833*13642Ssam char * 834*13642Ssam lastc(s) 835*13642Ssam register char *s; 836*13642Ssam { 837*13642Ssam while (*s != '\0') s++; 838*13642Ssam return(s); 839*13642Ssam } 840*13642Ssam 841*13642Ssam 842*13642Ssam /*** 843*13642Ssam * char * 844*13642Ssam * fdig(cp) find first digit in string 845*13642Ssam * 846*13642Ssam * return - pointer to first digit in string or end of string 847*13642Ssam */ 848*13642Ssam 849*13642Ssam char * 850*13642Ssam fdig(cp) 851*13642Ssam register char *cp; 852*13642Ssam { 853*13642Ssam register char *c; 854*13642Ssam 855*13642Ssam for (c = cp; *c; c++) 856*13642Ssam if (*c >= '0' && *c <= '9') 857*13642Ssam break; 858*13642Ssam return(c); 859*13642Ssam } 860*13642Ssam 861*13642Ssam 862*13642Ssam /* 863*13642Ssam * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 864*13642Ssam * Strings are compared as if they contain all capital letters. 865*13642Ssam */ 866*13642Ssam 867*13642Ssam snccmp(s1, s2) 868*13642Ssam register char *s1, *s2; 869*13642Ssam { 870*13642Ssam char c1, c2; 871*13642Ssam 872*13642Ssam if (islower(*s1)) c1 = toupper(*s1); 873*13642Ssam else c1 = *s1; 874*13642Ssam if (islower(*s2)) c2 = toupper(*s2); 875*13642Ssam else c2 = *s2; 876*13642Ssam 877*13642Ssam while (c1 == c2) { 878*13642Ssam if (*s1++=='\0') 879*13642Ssam return(0); 880*13642Ssam s2++; 881*13642Ssam if (islower(*s1)) c1 = toupper(*s1); 882*13642Ssam else c1 = *s1; 883*13642Ssam if (islower(*s2)) c2 = toupper(*s2); 884*13642Ssam else c2 = *s2; 885*13642Ssam } 886*13642Ssam return(c1 - c2); 887*13642Ssam } 888