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