1 #ifndef lint 2 static char sccsid[] = "@(#)conn.c 5.10 (Berkeley) 01/24/86"; 3 #endif 4 5 #include <signal.h> 6 #include "uucp.h" 7 #include <setjmp.h> 8 #include <ctype.h> 9 #include <errno.h> 10 #ifdef USG 11 #include <termio.h> 12 #include <fcntl.h> 13 #endif 14 #ifndef USG 15 #include <sgtty.h> 16 #endif 17 #ifdef BSD4_2 18 #include <sys/time.h> 19 #else 20 #include <time.h> 21 #endif 22 23 #define MAXC 1000 24 25 extern jmp_buf Sjbuf; 26 jmp_buf Cjbuf; 27 extern int errno, onesys; 28 extern char *sys_errlist[]; 29 extern char MaxGrade, DefMaxGrade; 30 31 /* Parity control during login procedure */ 32 #define P_ZERO 0 33 #define P_ONE 1 34 #define P_EVEN 2 35 #define P_ODD 3 36 37 #define ABORT -2 38 39 char *AbortOn = NULL; 40 char par_tab[128]; /* must be power of two */ 41 int linebaudrate; /* used for the sleep test in pk1.c */ 42 int next_fd = -1; /* predicted fd to close interrupted opens */ 43 44 char *PCP = "PCP"; /* PC Pursuit device type */ 45 /* 46 * catch alarm routine for "expect". 47 */ 48 alarmtr() 49 { 50 signal(SIGALRM, alarmtr); 51 if (next_fd >= 0) { 52 if (close(next_fd)) 53 logent("FAIL", "ACU LINE CLOSE"); 54 next_fd = -1; 55 } 56 longjmp(Sjbuf, 1); 57 } 58 59 /* This template is for seismo to call ihnp4 60 * the 3 lines marked ---> will be overwritten for the appropriate city 61 */ 62 #define PCP_BAUD 3 63 #define PCP_PHONE 4 64 #define PCP_CALLBACK 8 65 #define PCP_CITY 10 66 #define PCP_RPHONE 12 67 #define NPCFIELDS 15 68 69 static char *PCFlds[] = { 70 "PC-PURSUIT", 71 "Any", 72 "ACU", 73 "1200", 74 CNULL, /* <--- **** Welcome to Telenet PC Pursuit ***** */ 75 "ABORT", 76 "Good", /* Abort of Good bye! */ 77 ")", /* <--- Enter your 7-digit phone number (xxx-xxxx) */ 78 CNULL, /* ---> 528-1234 */ 79 "call?", /* <--- Which city do you wish to call? */ 80 CNULL, /* ---> CHICAGO */ 81 ")", /* <--- Enter the phone number you wish to call (xxx-xxxx) */ 82 CNULL, /* ---> 690-7171 */ 83 "R)?", /* <--- You are #1 in the queue. Do you want to wait, or Restart (Y/N/R)? */ 84 "Y", 85 CNULL /* <--- .....Good Bye! */ 86 }; 87 88 static char PCP_brand[20]; 89 90 /* 91 * place a telephone call to system and login, etc. 92 * 93 * return codes: 94 * CF_SYSTEM: don't know system 95 * CF_TIME: wrong time to call 96 * CF_DIAL: call failed 97 * CF_NODEV: no devices available to place call 98 * CF_LOGIN: login/password dialog failed 99 * 100 * >0 - file no. - connect ok 101 */ 102 103 int Dcf = -1; 104 char *Flds[MAXC/10]; 105 char LineType[10]; 106 extern int LocalOnly; 107 108 conn(system) 109 char *system; 110 { 111 int nf; 112 char info[MAXC], wkpre[NAMESIZE], file[NAMESIZE]; 113 register FILE *fsys; 114 int fcode = 0; 115 116 nf = 0; 117 118 fsys = fopen(SYSFILE, "r"); 119 ASSERT(fsys != NULL, "CAN'T OPEN", SYSFILE, 0); 120 121 DEBUG(4, "finds (%s) called\n", system); 122 keeplooking: 123 while((nf = finds(fsys, system, info, Flds)) > 0) { 124 strncpy(LineType, Flds[F_LINE], 10); 125 if (LocalOnly) { 126 if (strcmp("TCP", LineType) 127 && strcmp("DIR", LineType) 128 && strcmp("LOCAL", LineType) ) { 129 fcode = CF_TIME; 130 continue; 131 } 132 } 133 sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname); 134 if (!onesys && MaxGrade != DefMaxGrade && 135 !iswrk(file, "chk", Spool, wkpre)) { 136 fcode = CF_TIME; 137 continue; 138 } 139 /* For GTE's PC Pursuit */ 140 if (snccmp(LineType, PCP) == SAME) { 141 FILE *dfp; 142 int status; 143 static struct Devices dev; 144 dfp = fopen(DEVFILE, "r"); 145 ASSERT(dfp != NULL, "Can't open", DEVFILE, 0); 146 while ((status=rddev(dfp, &dev)) != FAIL 147 && strcmp(PCP, dev.D_type) != SAME) 148 ; 149 fclose(dfp); 150 if (status == FAIL) 151 continue; 152 if (mlock(PCP) == FAIL) { 153 fcode = CF_NODEV; 154 logent("DEVICE", "NO"); 155 continue; 156 } 157 PCFlds[PCP_BAUD] = dev.D_class; 158 PCFlds[PCP_PHONE] = dev.D_calldev; 159 PCFlds[PCP_CALLBACK] = dev.D_arg[D_CHAT]; 160 PCFlds[PCP_CITY] = Flds[F_CLASS]; 161 PCFlds[PCP_RPHONE] = Flds[F_PHONE]; 162 strncpy(PCP_brand, dev.D_brand, sizeof(PCP_brand)); 163 if ((fcode = getto(PCFlds)) < 0) 164 continue; 165 Dcf = fcode; 166 fcode = login(NPCFIELDS, PCFlds, Dcf); 167 clsacu(); /* Hang up, they'll call back */ 168 if (fcode != SUCCESS) { 169 fcode = CF_DIAL; 170 continue; 171 } 172 Flds[F_CLASS] = dev.D_class; 173 Flds[F_PHONE] = dev.D_line; 174 175 } /* end PC Pursuit */ 176 if ((fcode = getto(Flds)) > 0) 177 break; 178 } 179 180 if (nf <= 0) { 181 fclose(fsys); 182 return fcode ? fcode : nf; 183 } 184 185 Dcf = fcode; 186 187 if (fcode >= 0 && snccmp(LineType, PCP) == SAME) { 188 AbortOn = "Good"; /* .... Good Bye */ 189 fcode = expect("****~300", Dcf); 190 if (fcode != SUCCESS) { 191 DEBUG(4, "\nexpect timed out\n", CNULL); 192 fcode = CF_DIAL; 193 } 194 } 195 if (fcode >= 0) { 196 DEBUG(4, "login %s\n", "called"); 197 fcode = login(nf, Flds, Dcf); 198 } 199 if (fcode < 0) { 200 clsacu(); 201 if (fcode == ABORT) { 202 fcode = CF_DIAL; 203 goto keeplooking; 204 } else { 205 fclose(fsys); 206 return CF_LOGIN; 207 } 208 } 209 fclose(fsys); 210 fioclex(Dcf); 211 return Dcf; 212 } 213 214 /* 215 * connect to remote machine 216 * 217 * return codes: 218 * >0 - file number - ok 219 * FAIL - failed 220 */ 221 222 getto(flds) 223 register char *flds[]; 224 { 225 register struct condev *cd; 226 int nulldev(), diropn(); 227 char *line; 228 229 DEBUG(4, "getto: call no. %s ", flds[F_PHONE]); 230 DEBUG(4, "for sys %s\n", flds[F_NAME]); 231 232 if (snccmp(flds[F_LINE], "LOCAL") == SAME) 233 line = "ACU"; 234 else 235 line = flds[F_LINE]; 236 #ifdef DIALINOUT 237 if (snccmp(line, "ACU") != SAME) 238 reenable(); 239 #endif DIALINOUT 240 CU_end = nulldev; 241 if (snccmp(line, PCP) == SAME) { 242 for(cd = condevs; cd->CU_meth != NULL; cd++) { 243 if (snccmp(PCP_brand, cd->CU_brand) == SAME) { 244 CU_end = cd->CU_clos; 245 return diropn(flds); 246 } 247 } 248 logent(PCP_brand, "UNSUPPORTED ACU TYPE"); 249 } else { 250 for (cd = condevs; cd->CU_meth != NULL; cd++) { 251 if (snccmp(cd->CU_meth, line) == SAME) { 252 DEBUG(4, "Using %s to call\n", cd->CU_meth); 253 return (*(cd->CU_gen))(flds); 254 } 255 } 256 DEBUG(1, "Can't find %s, assuming DIR\n", flds[F_LINE]); 257 } 258 return diropn(flds); /* search failed, so use direct */ 259 } 260 261 /* 262 * close call unit 263 * 264 * return codes: none 265 */ 266 267 int (*CU_end)() = nulldev; 268 clsacu() 269 { 270 /* make *sure* Dcf is no longer exclusive. 271 * Otherwise dual call-in/call-out modems could get stuck. 272 * Unfortunately, doing this here is not ideal, but it is the 273 * easiest place to put the call. 274 * Hopefully everyone honors the LCK protocol, of course 275 */ 276 #ifdef TIOCNXCL 277 if (!IsTcpIp && Dcf >= 0 && ioctl(Dcf, TIOCNXCL, STBNULL) < 0) 278 DEBUG(5, "clsacu ioctl %s\n", sys_errlist[errno]); 279 #endif 280 if (setjmp(Sjbuf)) 281 logent(Rmtname, "CLOSE TIMEOUT"); 282 else { 283 signal(SIGALRM, alarmtr); 284 alarm(20); 285 (*(CU_end))(Dcf); 286 alarm(0); 287 } 288 if (close(Dcf) == 0) { 289 DEBUG(4, "fd %d NOT CLOSED by CU_clos\n", Dcf); 290 logent("clsacu", "NOT CLOSED by CU_clos"); 291 } 292 Dcf = -1; 293 CU_end = nulldev; 294 } 295 296 /* 297 * expand phone number for given prefix and number 298 */ 299 300 exphone(in, out) 301 register char *in, *out; 302 { 303 FILE *fn; 304 char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH]; 305 char buf[BUFSIZ]; 306 register char *s1; 307 308 if (!isascii(*in) || !isalpha(*in)) { 309 strcpy(out, in); 310 return; 311 } 312 313 s1=pre; 314 while (isascii(*in) && isalpha(*in)) 315 *s1++ = *in++; 316 *s1 = '\0'; 317 s1 = npart; 318 while (*in != '\0') 319 *s1++ = *in++; 320 *s1 = '\0'; 321 322 tpre[0] = '\0'; 323 if ((fn = fopen(DIALFILE, "r")) == NULL) 324 DEBUG(2, "CAN'T OPEN %s\n", DIALFILE); 325 else { 326 while (cfgets(buf, BUFSIZ, fn)) { 327 if (sscanf(buf, "%s%s", p, tpre) != 2) 328 continue; 329 if (strcmp(p, pre) == SAME) 330 goto found; 331 tpre[0] = '\0'; 332 } 333 DEBUG(2, "CAN'T FIND dialcodes prefix '%s'\n", pre); 334 found:; 335 fclose(fn); 336 } 337 338 strcpy(out, tpre); 339 strcat(out, npart); 340 } 341 342 /* 343 * read and decode a line from device file 344 * 345 * return code - FAIL at end-of file; 0 otherwise 346 */ 347 348 rddev(fp, dev) 349 register struct Devices *dev; 350 FILE *fp; 351 { 352 register int na; 353 354 if (!cfgets(dev->D_argbfr, sizeof(dev->D_argbfr), fp)) 355 return FAIL; 356 na = getargs(dev->D_argbfr, dev->D_arg, 20); 357 ASSERT(na >= 4, "BAD DEVICE ENTRY", dev->D_argbfr, 0); 358 if (na == 4) { 359 dev->D_brand = ""; 360 na++; 361 } 362 dev->D_speed = atoi(fdig(dev->D_class)); 363 dev->D_numargs = na; 364 return 0; 365 } 366 367 /* 368 * set system attribute vector 369 * 370 * return codes: 371 * >0 - number of arguments in vector - succeeded 372 * CF_SYSTEM - system name not found 373 * CF_TIME - wrong time to call 374 */ 375 376 finds(fsys, sysnam, info, flds) 377 char *sysnam, info[], *flds[]; 378 FILE *fsys; 379 { 380 int na; 381 int fcode = 0; 382 383 /* format of fields 384 * 0 name; 385 * 1 time 386 * 2 acu/hardwired 387 * 3 speed 388 * etc 389 */ 390 while (cfgets(info, MAXC, fsys) != NULL) { 391 na = getargs(info, flds, MAXC/10); 392 if (strncmp(sysnam, flds[F_NAME], MAXBASENAME) != SAME) 393 continue; 394 if (ifdate(flds[F_TIME]) != FAIL) 395 /* found a good entry */ 396 return na; 397 DEBUG(2, "Wrong time ('%s') to call\n", flds[F_TIME]); 398 fcode = CF_TIME; 399 } 400 return fcode ? fcode : CF_SYSTEM; 401 } 402 403 /* 404 * do login conversation 405 * 406 * return codes: SUCCESS | FAIL 407 */ 408 409 login(nf, flds, fn) 410 register char *flds[]; 411 int nf, fn; 412 { 413 register char *want, *altern; 414 int k, ok; 415 416 ASSERT(nf > 4, "TOO FEW LOG FIELDS", CNULL, nf); 417 if (setjmp(Cjbuf)) 418 return FAIL; 419 AbortOn = NULL; 420 for (k = F_LOGIN; k < nf; k += 2) { 421 want = flds[k]; 422 ok = FAIL; 423 while (ok != SUCCESS) { 424 altern = index(want, '-'); 425 if (altern != NULL) 426 *altern++ = '\0'; 427 if (strcmp(want, "ABORT") == 0) { 428 AbortOn = flds[k+1]; 429 DEBUG(4, "ABORT ON: %s\n", AbortOn); 430 goto nextfield; 431 } 432 DEBUG(4, "wanted \"%s\"\n", want); 433 ok = expect(want, fn); 434 DEBUG(4, "got: %s\n", ok ? "?" : "that"); 435 if (ok == FAIL) { 436 if (altern == NULL) { 437 logent("LOGIN", _FAILED); 438 return FAIL; 439 } 440 want = index(altern, '-'); 441 if (want != NULL) 442 *want++ = '\0'; 443 sendthem(altern, fn); 444 } else 445 if (ok == ABORT) { 446 logent("LOGIN ABORTED", _FAILED); 447 return ABORT; 448 } 449 } 450 sleep(1); 451 if (k+1 < nf) 452 sendthem(flds[k+1], fn); 453 nextfield: ; 454 } 455 return SUCCESS; 456 } 457 458 459 /* conditional table generation to support odd speeds */ 460 struct sg_spds {int sp_val, sp_name;} spds[] = { 461 #ifdef B50 462 { 50, B50}, 463 #endif 464 #ifdef B75 465 { 75, B75}, 466 #endif 467 #ifdef B110 468 { 110, B110}, 469 #endif 470 #ifdef B150 471 { 150, B150}, 472 #endif 473 #ifdef B200 474 { 200, B200}, 475 #endif 476 #ifdef B300 477 { 300, B300}, 478 #endif 479 #ifdef B600 480 {600, B600}, 481 #endif 482 #ifdef B1200 483 {1200, B1200}, 484 #endif 485 #ifdef B1800 486 {1800, B1800}, 487 #endif 488 #ifdef B2000 489 {2000, B2000}, 490 #endif 491 #ifdef B2400 492 {2400, B2400}, 493 #endif 494 #ifdef B3600 495 {3600, B3600}, 496 #endif 497 #ifdef B4800 498 {4800, B4800}, 499 #endif 500 #ifdef B7200 501 {7200, B7200}, 502 #endif 503 #ifdef B9600 504 {9600, B9600}, 505 #endif 506 #ifdef B19200 507 {19200, B19200}, 508 #endif 509 #ifdef EXTA 510 {19200, EXTA}, 511 #endif 512 {0, 0} 513 }; 514 515 /* 516 * set speed/echo/mode... 517 * 518 * return codes: none 519 */ 520 521 fixline(tty, spwant) 522 int tty, spwant; 523 { 524 #ifdef USG 525 struct termio ttbuf; 526 #else !USG 527 struct sgttyb ttbuf; 528 #endif !USG 529 register struct sg_spds *ps; 530 int speed = -1; 531 532 for (ps = spds; ps->sp_val; ps++) 533 if (ps->sp_val == spwant) 534 speed = ps->sp_name; 535 ASSERT(speed >= 0, "BAD SPEED", CNULL, speed); 536 #ifdef USG 537 if (ioctl(tty, TCGETA, &ttbuf) < 0) 538 return FAIL; 539 /* ttbuf.sg_flags = (ANYP|RAW); 540 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; */ 541 ttbuf.c_iflag = (ushort)0; 542 ttbuf.c_oflag = (ushort)0; 543 ttbuf.c_cflag = (speed|CS8|HUPCL|CREAD); 544 ttbuf.c_lflag = (ushort)0; 545 ttbuf.c_cc[VMIN] = 6; 546 ttbuf.c_cc[VTIME] = 1; 547 if (ioctl(tty, TCSETA, &ttbuf) < 0) 548 return FAIL; 549 #else !USG 550 if (ioctl(tty, TIOCGETP, &ttbuf) < 0) 551 return FAIL; 552 ttbuf.sg_flags = (ANYP|RAW); 553 ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed; 554 if (ioctl(tty, TIOCSETP, &ttbuf) < 0) 555 return FAIL; 556 #endif 557 #ifndef USG 558 if (ioctl(tty, TIOCHPCL, STBNULL) < 0) 559 return FAIL; 560 if (ioctl(tty, TIOCEXCL, STBNULL) < 0) 561 return FAIL; 562 #endif 563 linebaudrate = spwant; 564 return SUCCESS; 565 } 566 567 #define MR 100 568 569 /* 570 * look for expected string 571 * 572 * return codes: 573 * 0 - found 574 * FAIL - lost line or too many characters read 575 * some character - timed out 576 */ 577 578 expect(str, fn) 579 register char *str; 580 int fn; 581 { 582 char rdvec[MR]; 583 register char *rp = rdvec, *strptr; 584 int kr, cnt_char; 585 char nextch; 586 int timo = MAXMSGTIME; 587 588 if (*str == '\0' || strcmp(str, "\"\"") == SAME) 589 return SUCCESS; 590 /* Cleanup str, convert \0xx strings to one char */ 591 for (strptr = str; *strptr; strptr++) { 592 if (*strptr == '\\') 593 switch(*++strptr) { 594 case 's': 595 DEBUG(5, "BLANK\n", CNULL); 596 *strptr = ' '; 597 break; 598 default: 599 strptr--; /* back up to backslash */ 600 sscanf(strptr + 1,"%o", &cnt_char); 601 DEBUG(6, "BACKSLASHED %02xH\n", cnt_char); 602 *strptr = (char) (cnt_char); 603 strcpy(&strptr[1], &strptr[4]); 604 } 605 } 606 607 strptr = index(str, '~'); 608 if (strptr != NULL) { 609 *strptr++ = '\0'; 610 timo = atoi(strptr); 611 if (timo <= 0) 612 timo = MAXMSGTIME; 613 } 614 615 if (setjmp(Sjbuf)) 616 return FAIL; 617 signal(SIGALRM, alarmtr); 618 alarm(timo); 619 *rp = 0; 620 while (notin(str, rdvec)) { 621 int c; 622 if(AbortOn != NULL && !notin(AbortOn, rdvec)) { 623 DEBUG(1, "Call aborted on '%s'\n", AbortOn); 624 alarm(0); 625 return ABORT; 626 } 627 kr = read(fn, &nextch, 1); 628 if (kr <= 0) { 629 alarm(0); 630 DEBUG(4, "lost line kr - %d\n, ", kr); 631 logent("LOGIN", "LOST LINE"); 632 return FAIL; 633 } 634 c = nextch & 0177; 635 if (c == '\0') 636 continue; 637 DEBUG(4, (isprint(c) || isspace(c)) ? "%c" : "\\%03o", c); 638 *rp++ = c; 639 if (rp >= rdvec + MR) { 640 register char *p; 641 for (p = rdvec+MR/2; p < rp; p++) 642 *(p-MR/2) = *p; 643 rp -= MR/2; 644 } 645 *rp = '\0'; 646 } 647 alarm(0); 648 return SUCCESS; 649 } 650 651 652 /* 653 * Determine next file descriptor that would be allocated. 654 * This permits later closing of a file whose open was interrupted. 655 * It is a UNIX kernel problem, but it has to be handled. 656 * unc!smb (Steve Bellovin) probably first discovered it. 657 */ 658 getnextfd() 659 { 660 close(next_fd = open("/", 0)); 661 } 662 663 /* 664 * send line of login sequence 665 * 666 * return codes: none 667 */ 668 sendthem(str, fn) 669 register char *str; 670 int fn; 671 { 672 register char *strptr; 673 int i, n, cr = 1; 674 register char c; 675 static int p_init = 0; 676 677 DEBUG(5, "send \"%s\"\n", str); 678 679 if (!p_init) { 680 p_init++; 681 bld_partab(P_EVEN); 682 } 683 684 if (prefix("BREAK", str)) { 685 sscanf(&str[5], "%1d", &i); 686 if (i <= 0 || i > 10) 687 i = 3; 688 /* send break */ 689 genbrk(fn, i); 690 return; 691 } 692 693 if (prefix("PAUSE", str)) { 694 sscanf(&str[5], "%1d", &i); 695 if (i <= 0 || i > 10) 696 i = 3; 697 /* pause for a while */ 698 sleep((unsigned)i); 699 return; 700 } 701 702 if (strcmp(str, "EOT") == SAME) { 703 p_chwrite(fn, '\04'); 704 return; 705 } 706 707 /* Send a '\n' */ 708 if (strcmp(str, "LF") == SAME) { 709 p_chwrite(fn, '\n'); 710 return; 711 } 712 713 /* Send a '\r' */ 714 if (strcmp(str, "CR") == SAME) { 715 p_chwrite(fn, '\r'); 716 return; 717 } 718 719 /* Set parity as needed */ 720 if (strcmp(str, "P_ZERO") == SAME) { 721 bld_partab(P_ZERO); 722 return; 723 } 724 if (strcmp(str, "P_ONE") == SAME) { 725 bld_partab(P_ONE); 726 return; 727 } 728 if (strcmp(str, "P_EVEN") == SAME) { 729 bld_partab(P_EVEN); 730 return; 731 } 732 if (strcmp(str, "P_ODD") == SAME) { 733 bld_partab(P_ODD); 734 return; 735 } 736 737 /* If "", just send '\r' */ 738 if (strcmp(str, "\"\"") == SAME) { 739 p_chwrite(fn, '\r'); 740 return; 741 } 742 743 strptr = str; 744 while ((c = *strptr++) != '\0') { 745 if (c == '\\') { 746 switch(*strptr++) { 747 case '\0': 748 DEBUG(5, "TRAILING BACKSLASH IGNORED\n", CNULL); 749 --strptr; 750 continue; 751 case 's': 752 DEBUG(5, "BLANK\n", CNULL); 753 c = ' '; 754 break; 755 case 'd': 756 DEBUG(5, "DELAY\n", CNULL); 757 sleep(1); 758 continue; 759 case 'n': 760 DEBUG(5, "NEW LINE\n", CNULL); 761 c = '\n'; 762 break; 763 case 'r': 764 DEBUG(5, "RETURN\n", CNULL); 765 c = '\r'; 766 break; 767 case 'b': 768 if (isdigit(*strptr)) { 769 i = (*strptr++ - '0'); 770 if (i <= 0 || i > 10) 771 i = 3; 772 } else 773 i = 3; 774 /* send break */ 775 genbrk(fn, i); 776 if (*strptr == '\0') 777 cr = 0; 778 continue; 779 case 'c': 780 if (*strptr == '\0') { 781 DEBUG(5, "NO CR\n", CNULL); 782 cr = 0; 783 } else 784 DEBUG(5, "NO CR - IGNORED NOT EOL\n", CNULL); 785 continue; 786 #define isoctal(x) ((x >= '0') && (x <= '7')) 787 default: 788 if (isoctal(strptr[-1])) { 789 i = 0; 790 n = 0; 791 --strptr; 792 while (isoctal(*strptr) && ++n <= 3) 793 i = i * 8 + (*strptr++ - '0'); 794 DEBUG(5, "\\%o\n", i); 795 p_chwrite(fn, (char)i); 796 continue; 797 } 798 } 799 } 800 p_chwrite(fn, c); 801 } 802 803 if (cr) 804 p_chwrite(fn, '\r'); 805 return; 806 } 807 808 p_chwrite(fd, c) 809 int fd; 810 char c; 811 { 812 c = par_tab[c&0177]; 813 if (write(fd, &c, 1) != 1) { 814 logent(sys_errlist[errno], "BAD WRITE"); 815 longjmp(Cjbuf, 2); 816 } 817 } 818 819 /* 820 * generate parity table for use by p_chwrite. 821 */ 822 bld_partab(type) 823 int type; 824 { 825 register int i, j, n; 826 827 for (i = 0; i < sizeof(par_tab); i++) { 828 n = 0; 829 for (j = i&(sizeof(par_tab)-1); j; j = (j-1)&j) 830 n++; 831 par_tab[i] = i; 832 if (type == P_ONE 833 || (type == P_EVEN && (n&01) != 0) 834 || (type == P_ODD && (n&01) == 0)) 835 par_tab[i] |= sizeof(par_tab); 836 } 837 } 838 839 /* 840 * check for occurrence of substring "sh" 841 * 842 * return codes: 843 * 0 - found the string 844 * 1 - not in the string 845 */ 846 notin(sh, lg) 847 register char *sh, *lg; 848 { 849 while (*lg != '\0') { 850 if (wprefix(sh, lg)) 851 return 0; 852 else 853 lg++; 854 } 855 return 1; 856 } 857 858 /* 859 * Allow multiple date specifications separated by ','. 860 */ 861 ifdate(p) 862 register char *p; 863 { 864 register char *np; 865 register int ret, g; 866 int rtime, i; 867 868 /* pick up retry time for failures */ 869 /* global variable Retrytime is set here */ 870 if ((np = index(p, ';')) == NULL) { 871 Retrytime = RETRYTIME; 872 } else { 873 i = sscanf(np+1, "%d", &rtime); 874 if (i < 1 || rtime < 0) 875 rtime = 5; 876 Retrytime = rtime * 60; 877 } 878 879 ret = FAIL; 880 MaxGrade = '\0'; 881 do { 882 np = strpbrk(p, ",|"); /* prefer , but allow | for compat */ 883 if (np) 884 *np = '\0'; 885 g = ifadate(p); 886 DEBUG(11,"ifadate returns %o\n", g); 887 if (g != FAIL) { 888 ret = SUCCESS; 889 if (g > MaxGrade) 890 MaxGrade = g; 891 } 892 if (np) 893 *np = ','; 894 p = np + 1; 895 } while (np); 896 if (MaxGrade == '\0') 897 MaxGrade = DefMaxGrade; 898 return ret; 899 } 900 901 /* 902 * this routine will check a string (string) 903 * like "MoTu0800-1730" to see if the present 904 * time is within the given limits. 905 * SIDE EFFECT - Retrytime is set 906 * 907 * return codes: 908 * 0 - not within limits 909 * 1 - within limits 910 */ 911 912 ifadate(string) 913 char *string; 914 { 915 static char *days[]={ 916 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 917 }; 918 time_t clock; 919 register char *s = string; 920 int i, tl, th, tn, dayok=0; 921 struct tm *localtime(); 922 struct tm *tp; 923 char *p, MGrade; 924 925 if ((p = index(s, '/')) == NULL) 926 MGrade = DefMaxGrade; 927 else 928 MGrade = p[1]; 929 930 time(&clock); 931 tp = localtime(&clock); 932 while (isascii(*s) && isalpha(*s)) { 933 for (i = 0; days[i]; i++) { 934 if (prefix(days[i], s)) 935 if (tp->tm_wday == i) 936 dayok = 1; 937 } 938 939 if (prefix("Wk", s)) 940 if (tp->tm_wday >= 1 && tp->tm_wday <= 5) 941 dayok = 1; 942 if (prefix("Any", s)) 943 dayok = 1; 944 if (prefix("Evening", s)) { 945 /* Sat or Sun */ 946 if (tp->tm_wday == 6 || tp->tm_wday == 0 947 || tp->tm_hour >= 17 || tp->tm_hour < 8) 948 dayok = 1; 949 } 950 if (prefix("Night", s)) { 951 if (tp->tm_wday == 6 /* Sat */ 952 || tp->tm_hour >= 23 || tp->tm_hour < 8 953 /* Sunday before 5pm */ 954 || (tp->tm_wday == 0 && tp->tm_hour < 17)) 955 dayok = 1; 956 } 957 if (prefix("NonPeak", s)) { /* For Tymnet and PC Pursuit */ 958 /* Sat or Sun */ 959 if (tp->tm_wday == 6 || tp->tm_wday == 0 960 || tp->tm_hour >= 18 || tp->tm_hour < 7) 961 dayok = 1; 962 } 963 s++; 964 } 965 966 if (dayok == 0 && s != string) 967 return FAIL; 968 i = sscanf(s, "%d-%d", &tl, &th); 969 if (i < 2) 970 return MGrade; 971 tn = tp->tm_hour * 100 + tp->tm_min; 972 if (th < tl) { /* crosses midnight */ 973 if (tl <= tn || tn < th) 974 return MGrade; 975 } else { 976 if (tl <= tn && tn < th) 977 return MGrade; 978 } 979 return FAIL; 980 } 981 982 /* 983 * find first digit in string 984 * 985 * return - pointer to first digit in string or end of string 986 */ 987 char * 988 fdig(cp) 989 register char *cp; 990 { 991 register char *c; 992 993 for (c = cp; *c; c++) 994 if (*c >= '0' && *c <= '9') 995 break; 996 return c; 997 } 998 999 /* 1000 * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 1001 * Strings are compared as if they contain all capital letters. 1002 */ 1003 snccmp(s1, s2) 1004 register char *s1, *s2; 1005 { 1006 char c1, c2; 1007 1008 if (islower(*s1)) 1009 c1 = toupper(*s1); 1010 else 1011 c1 = *s1; 1012 if (islower(*s2)) 1013 c2 = toupper(*s2); 1014 else 1015 c2 = *s2; 1016 1017 while (c1 == c2) { 1018 if (*s1++ == '\0') 1019 return 0; 1020 s2++; 1021 if (islower(*s1)) 1022 c1 = toupper(*s1); 1023 else 1024 c1 = *s1; 1025 if (islower(*s2)) 1026 c2 = toupper(*s2); 1027 else 1028 c2 = *s2; 1029 } 1030 return c1 - c2; 1031 } 1032 1033 /* 1034 * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0 1035 * Strings are compared as if they contain all capital letters. 1036 */ 1037 sncncmp(s1, s2, n) 1038 register char *s1, *s2; 1039 register int n; 1040 { 1041 char c1, c2; 1042 1043 if (islower(*s1)) 1044 c1 = toupper(*s1); 1045 else 1046 c1 = *s1; 1047 if (islower(*s2)) 1048 c2 = toupper(*s2); 1049 else 1050 c2 = *s2; 1051 1052 while ( --n >= 0 && c1 == c2) { 1053 if (*s1++ == '\0') 1054 return 0; 1055 s2++; 1056 if (islower(*s1)) 1057 c1 = toupper(*s1); 1058 else 1059 c1 = *s1; 1060 if (islower(*s2)) 1061 c2 = toupper(*s2); 1062 else 1063 c2 = *s2; 1064 } 1065 return n<0 ? 0 : (c1 - c2); 1066 } 1067 /* 1068 * do chat script 1069 * occurs after local port is opened, 1070 * before 'dialing' the other machine. 1071 */ 1072 dochat(dev, flds, fd) 1073 register struct Devices *dev; 1074 char *flds[]; 1075 int fd; 1076 { 1077 register int i; 1078 register char *p; 1079 char bfr[sizeof(dev->D_argbfr)]; 1080 1081 if (dev->D_numargs <= 5) 1082 return(0); 1083 DEBUG(4, "dochat called %d\n", dev->D_numargs); 1084 for (i = 0; i < dev->D_numargs-5; i++) { 1085 sprintf(bfr, dev->D_arg[D_CHAT+i], flds[F_PHONE]); 1086 if (strcmp(bfr, dev->D_arg[D_CHAT+i])) { 1087 p = malloc((unsigned)strlen(bfr)+1); 1088 if (p != NULL) { 1089 strcpy(p, bfr); 1090 dev->D_arg[D_CHAT+i] = p; 1091 } 1092 } 1093 } 1094 /* following is a kludge because login() arglist is a kludge */ 1095 i = login(dev->D_numargs, &dev->D_arg[D_CHAT-5], fd); 1096 /* 1097 * If login() last did a sendthem(), must pause so things can settle. 1098 * But don't bother if chat failed. 1099 */ 1100 if (i == 0 && (dev->D_numargs&01)) 1101 sleep(2); 1102 return(i); 1103 } 1104 1105 /* 1106 * fix kill/echo/raw on line 1107 * 1108 * return codes: none 1109 */ 1110 fixmode(tty) 1111 register int tty; 1112 { 1113 #ifdef USG 1114 struct termio ttbuf; 1115 #else !USG 1116 struct sgttyb ttbuf; 1117 #endif !USG 1118 register struct sg_spds *ps; 1119 int speed; 1120 1121 if (IsTcpIp) 1122 return; 1123 #ifdef USG 1124 ioctl(tty, TCGETA, &ttbuf); 1125 ttbuf.c_iflag = ttbuf.c_oflag = ttbuf.c_lflag = (ushort)0; 1126 speed = ttbuf.c_cflag &= (CBAUD); 1127 ttbuf.c_cflag |= (CS8|CREAD); 1128 ttbuf.c_cc[VMIN] = 6; 1129 ttbuf.c_cc[VTIME] = 1; 1130 ioctl(tty, TCSETA, &ttbuf); 1131 #else !USG 1132 ioctl(tty, TIOCGETP, &ttbuf); 1133 ttbuf.sg_flags = (ANYP | RAW); 1134 ioctl(tty, TIOCSETP, &ttbuf); 1135 speed = ttbuf.sg_ispeed; 1136 ioctl(tty, TIOCEXCL, STBNULL); 1137 #endif !USG 1138 1139 for (ps = spds; ps->sp_val; ps++) 1140 if (ps->sp_name == speed) { 1141 linebaudrate = ps->sp_val; 1142 DEBUG(9,"Incoming baudrate is %d\n", linebaudrate); 1143 return; 1144 } 1145 ASSERT(linebaudrate >= 0, "BAD SPEED", CNULL, speed); 1146 } 1147 1148