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