1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1994 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 34 #include "uucp.h" 35 36 GLOBAL char _Protocol[40] = ""; /* working protocol string */ 37 static char _ProtoSys[40] = ""; /* protocol string from Systems file entry */ 38 static char _ProtoDev[40] = ""; /* protocol string from Devices file entry */ 39 EXTERN char _ProtoCfg[]; /* protocol string from Config file entry */ 40 41 EXTERN jmp_buf Sjbuf; 42 EXTERN unsigned expecttime; 43 44 GLOBAL int Modemctrl; 45 46 /* Parity control during login procedure */ 47 #define P_ZERO 0 48 #define P_ONE 1 49 #define P_EVEN 2 50 #define P_ODD 3 51 52 static char par_tab[128]; 53 54 EXTERN void alarmtr(); 55 static void addProto(), mergeProto(), removeProto(); 56 static char *nextProto(); 57 EXTERN char *findProto(); 58 static void getProto(); 59 static finds(); 60 EXTERN int getto(); /* make this static when ct uses altconn() */ 61 EXTERN int chat(), rddev(), expect(), wrstr(), wrchr(); 62 EXTERN int processdev(), getdevline(), getsysline(), sysaccess(); 63 EXTERN int clear_hup(); 64 EXTERN char *currsys(), *currdev(); 65 static int finds(); 66 static int wait_for_hangup(), expect_str(); 67 68 EXTERN void sendthem(), nap(); 69 static int notin(), ifdate(), checkdate(), checktime(), classmatch(); 70 71 GLOBAL char *Myline = CNULL; /* to force which line will be used */ 72 GLOBAL char *Mytype = CNULL; /* to force selection of specific device type */ 73 GLOBAL int Dologin; /* to force login chat sequence */ 74 75 /* 76 * conn - place a telephone call to system and login, etc. 77 * 78 * return codes: 79 * FAIL - connection failed 80 * >0 - file no. - connect ok 81 * When a failure occurs, Uerror is set. 82 */ 83 84 GLOBAL int 85 conn(system) 86 char *system; 87 { 88 int nf, fn; 89 char *flds[F_MAX+1]; 90 EXTERN void sysreset(); 91 92 CDEBUG(4, "conn(%s)\n", system); 93 Uerror = 0; 94 while ((nf = finds(system, flds, F_MAX)) > 0) { 95 fn = getto(flds); 96 CDEBUG(4, "getto ret %d\n", fn); 97 if (fn < 0) 98 continue; 99 100 #ifdef TIOCSPGRP 101 { 102 #ifdef ATTSV 103 int pgrp = getpgrp(); 104 #else 105 int pgrp = getpgrp(0); 106 #endif 107 ioctl(fn, TIOCSPGRP, &pgrp); 108 } 109 #endif 110 if (Dologin || EQUALS(Progname, "uucico")) { 111 if (chat(nf - F_LOGIN, flds + F_LOGIN, fn,"","") == SUCCESS) { 112 sysreset(); 113 return(fn); /* successful return */ 114 } 115 116 /* login failed */ 117 DEBUG(6, "close caller (%d)\n", fn); 118 fd_rmlock(fn); 119 close(fn); 120 if (Dc[0] != NULLCHAR) { 121 DEBUG(6, "delock line (%s)\n", Dc); 122 } 123 } else { 124 sysreset(); 125 return(fn); 126 } 127 } 128 129 /* finds or getto failed */ 130 sysreset(); 131 CDEBUG(1, "Call Failed: %s\n", UERRORTEXT); 132 return(FAIL); 133 } 134 135 /* 136 * getto - connect to remote machine 137 * 138 * return codes: 139 * >0 - file number - ok 140 * FAIL - failed 141 */ 142 143 GLOBAL int 144 getto(flds) 145 char *flds[]; 146 { 147 char *dev[D_MAX+2], devbuf[BUFSIZ]; 148 register int status; 149 register int dcf = -1; 150 int reread = 0; 151 int tries = 0; /* count of call attempts - for limit purposes */ 152 EXTERN void devreset(); 153 154 CDEBUG(1, "Device Type %s wanted\n", flds[F_TYPE]); 155 Uerror = 0; 156 while (tries < TRYCALLS) { 157 if ((status=rddev(flds[F_TYPE], dev, devbuf, D_MAX)) == FAIL) { 158 if (tries == 0 || ++reread >= TRYCALLS) 159 break; 160 devreset(); 161 continue; 162 } 163 /* check class, check (and possibly set) speed */ 164 if (classmatch(flds, dev) != SUCCESS) { 165 DEBUG(7, "Skipping entry in '%s'", currdev()); 166 DEBUG(7, " - class (%s) not wanted.\n", dev[D_CLASS]); 167 continue; 168 } 169 DEBUG(5, "Trying device entry '%s' ", dev[D_LINE]); 170 DEBUG(5, "from '%s'.\n", currdev()); 171 if ((dcf = processdev(flds, dev)) >= 0) 172 break; 173 174 switch(Uerror) { 175 case SS_CANT_ACCESS_DEVICE: 176 case SS_DEVICE_FAILED: 177 case SS_LOCKED_DEVICE: 178 case SS_CHAT_FAILED: 179 break; 180 default: 181 tries++; 182 break; 183 } 184 } 185 devreset(); /* reset devices file(s) */ 186 if (status == FAIL && !Uerror) { 187 CDEBUG(1, "Requested Device Type Not Found\n%s", ""); 188 Uerror = SS_NO_DEVICE; 189 } 190 return(dcf); 191 } 192 193 /* 194 * classmatch - process 'Any' in Devices and Systems and 195 * determine the correct speed, or match for == 196 */ 197 198 static int 199 classmatch(flds, dev) 200 char *flds[], *dev[]; 201 { 202 /* check class, check (and possibly set) speed */ 203 if (EQUALS(flds[F_CLASS], "Any") 204 && EQUALS(dev[D_CLASS], "Any")) { 205 dev[D_CLASS] = DEFAULT_BAUDRATE; 206 return(SUCCESS); 207 } else if (EQUALS(dev[D_CLASS], "Any")) { 208 dev[D_CLASS] = flds[F_CLASS]; 209 return(SUCCESS); 210 } else if (EQUALS(flds[F_CLASS], "Any") || 211 EQUALS(flds[F_CLASS], dev[D_CLASS])) 212 return(SUCCESS); 213 else 214 return(FAIL); 215 } 216 217 218 /* 219 * rddev - find and unpack a line from device file for this caller type 220 * lines starting with whitespace of '#' are comments 221 * 222 * return codes: 223 * >0 - number of arguments in vector - succeeded 224 * FAIL - EOF 225 */ 226 227 GLOBAL int 228 rddev(type, dev, buf, devcount) 229 char *type; 230 char *dev[]; 231 char *buf; 232 { 233 char *commap, d_type[BUFSIZ]; 234 int na; 235 236 while (getdevline(buf, BUFSIZ)) { 237 if (buf[0] == ' ' || buf[0] == '\t' 238 || buf[0] == '\n' || buf[0] == '\0' || buf[0] == '#') 239 continue; 240 na = getargs(buf, dev, devcount); 241 ASSERT(na >= D_CALLER, "BAD LINE", buf, na); 242 243 if ( strncmp(dev[D_LINE],"/dev/",5) == 0 ) { 244 /* since cu (altconn()) strips off leading */ 245 /* "/dev/", do the same here. */ 246 strcpy(dev[D_LINE], &(dev[D_LINE][5]) ); 247 } 248 249 /* may have ",M" subfield in D_LINE */ 250 Modemctrl = FALSE; 251 if ( (commap = strchr(dev[D_LINE], ',')) != (char *)NULL ) { 252 if ( strcmp( commap, ",M") == SAME ) 253 Modemctrl = TRUE; 254 *commap = '\0'; 255 } 256 257 /* 258 * D_TYPE field may have protocol subfield, which 259 * must be pulled off before comparing to desired type. 260 */ 261 (void)strcpy(d_type, dev[D_TYPE]); 262 if ((commap = strchr(d_type, ',')) != (char *)NULL ) 263 *commap = '\0'; 264 265 /* to force the requested device type to be used. */ 266 if ((Mytype != NULL) && (!EQUALS(Mytype, d_type)) ) 267 continue; 268 /* to force the requested line to be used */ 269 if ((Myline != NULL) && (!EQUALS(Myline, dev[D_LINE])) ) 270 continue; 271 272 bsfix(dev); /* replace \X fields */ 273 274 if (EQUALS(d_type, type)) { 275 getProto( _ProtoDev, dev[D_TYPE] ); 276 return(na); 277 } 278 } 279 return(FAIL); 280 } 281 282 283 /* 284 * finds - set system attribute vector 285 * 286 * input: 287 * fsys - open Systems file descriptor 288 * sysnam - system name to find 289 * output: 290 * flds - attibute vector from Systems file 291 * fldcount - number of fields in flds 292 * return codes: 293 * >0 - number of arguments in vector - succeeded 294 * FAIL - failed 295 * Uerror set: 296 * 0 - found a line in Systems file 297 * SS_BADSYSTEM - no line found in Systems file 298 * SS_TIME_WRONG - wrong time to call 299 */ 300 301 static int 302 finds(sysnam, flds, fldcount) 303 char *sysnam, *flds[]; 304 { 305 static char info[BUFSIZ]; 306 int na; 307 308 /* format of fields 309 * 0 name; 310 * 1 time 311 * 2 acu/hardwired 312 * 3 speed 313 * etc 314 */ 315 if (sysnam == 0 || *sysnam == 0 ) { 316 Uerror = SS_BADSYSTEM; 317 return(FAIL); 318 } 319 320 while (getsysline(info, sizeof(info))) { 321 na = getargs(info, flds, fldcount); 322 bsfix(flds); /* replace \X fields */ 323 if ( !EQUALSN(sysnam, flds[F_NAME], MAXBASENAME)) 324 continue; 325 /* check if requested Mytype device type */ 326 if ((Mytype != CNULL) && 327 (na <= F_TYPE || 328 !EQUALSN(flds[F_TYPE], Mytype, strlen(Mytype)))) { 329 DEBUG(7, "Skipping entry in '%s'", currsys()); 330 DEBUG(7, " - type (%s) not wanted.\n", na > F_TYPE ? 331 flds[F_TYPE] : "Missing type entry"); 332 continue; 333 } else { 334 DEBUG(5, "Trying entry from '%s'", currsys()); 335 DEBUG(5, " - device type %s.\n", na > F_TYPE ? 336 flds[F_TYPE] : "<Missing type entry>"); 337 } 338 /* OK if not uucico (ie. ct or cu) or the time is right */ 339 if (!EQUALS(Progname, "uucico") || 340 (na > F_TIME && ifdate(flds[F_TIME]))) { 341 /* found a good entry */ 342 if (na > F_TYPE) { 343 getProto(_ProtoSys, flds[F_TYPE]); 344 Uerror = 0; 345 return(na); /* FOUND OK LINE */ 346 } 347 DEBUG(5, "Trying entry from '%s'", currsys()); 348 DEBUG(5, " - Missing type entry for <%s>.\n", 349 flds[F_NAME]); 350 } else { 351 CDEBUG(1, "Wrong Time To Call: %s\n", na > F_TIME ? 352 flds[F_TIME] : "<Missing time entry>"); 353 if (!Uerror) 354 Uerror = SS_TIME_WRONG; 355 } 356 } 357 if (!Uerror) 358 Uerror = SS_BADSYSTEM; 359 return(FAIL); 360 } 361 362 /* 363 * getProto - get the protocol letters from the input string. 364 * input: 365 * str - string from Systems/Devices/Config file, 366 * a ',' delimits the protocol string 367 * e.g. ACU,g or DK,d 368 * output: 369 * str - the , (if present) will be replaced with NULLCHAR 370 * 371 * return: none 372 */ 373 374 static void 375 getProto(save, str) 376 char *save; 377 char *str; 378 { 379 register char *p; 380 381 *save = NULLCHAR; 382 if ( (p=strchr(str, ',')) != NULL) { 383 *p = NULLCHAR; 384 (void) strcpy(save, p+1); 385 DEBUG(7, "Protocol = %s\n", save); 386 } 387 return; 388 } 389 390 /* 391 * check for a specified protocol selection string 392 * return: 393 * protocol string pointer 394 * NULL if none specified for LOGNAME 395 */ 396 GLOBAL char * 397 protoString(valid) 398 char *valid; 399 { 400 char *save; 401 402 save =strdup(valid); 403 _Protocol[0] = '\0'; 404 405 if ( _ProtoSys[0] != '\0' ) 406 addProto(_ProtoSys, valid); 407 if ( _ProtoDev[0] != '\0' ) 408 addProto(_ProtoDev, valid); 409 if ( _ProtoCfg[0] != '\0' ) 410 addProto(_ProtoCfg, valid); 411 412 if ( _Protocol[0] == '\0' ) { 413 (void) strcpy(valid, save); 414 (void) strcpy(_Protocol, save); 415 } 416 417 return(_Protocol[0] == NULLCHAR ? NULL : _Protocol); 418 } 419 420 /* 421 * addProto 422 * 423 * Verify that the desired protocols from the Systems and Devices file 424 * have been compiled into this application. 425 * 426 * desired - list of desired protocols 427 * valid - list of protocols that are compiled in. 428 */ 429 430 static void 431 addProto (desired, valid) 432 char *desired; 433 char *valid; 434 { 435 register char * protoPtr; 436 register char * wantPtr; 437 438 if ( *desired == '\0' ) 439 return; 440 441 if ( *(protoPtr = _Protocol) != NULLCHAR ) { 442 while ( *(protoPtr = nextProto(protoPtr)) != NULLCHAR ) { 443 if ( *(wantPtr = findProto(desired, *protoPtr)) == NULLCHAR ) { 444 removeProto(valid, *protoPtr); 445 removeProto(protoPtr, *protoPtr); 446 } else { 447 mergeProto(protoPtr, wantPtr); 448 protoPtr++; 449 } 450 } 451 } else { 452 wantPtr = desired; 453 while ( *(wantPtr = nextProto(wantPtr)) != NULLCHAR ) { 454 if ( *(findProto(valid, *wantPtr)) != NULLCHAR ) { 455 mergeProto(protoPtr, wantPtr); 456 } 457 wantPtr++; 458 } 459 } 460 if ( *(protoPtr = _Protocol) != NULLCHAR ) { 461 while ( *(protoPtr = nextProto(protoPtr)) != NULLCHAR ) 462 *(valid++) = *(protoPtr++); 463 *valid = NULLCHAR; 464 } 465 return; 466 } 467 468 /* 469 * mergeProto 470 * 471 * input 472 * char *tostring, *fromstring; 473 */ 474 static void 475 mergeProto(tostring, fromstring) 476 char *tostring, *fromstring; 477 { 478 char buffer[BUFSIZ]; 479 int length; 480 481 while ( *(tostring = nextProto(tostring)) != NULLCHAR ) { 482 if ( *tostring == *fromstring ) 483 break; 484 else 485 tostring++; 486 } 487 488 if ( *tostring == NULLCHAR ) { 489 length = nextProto(fromstring + 1) - fromstring; 490 (void) strncpy(tostring, fromstring, length); 491 *(tostring + length) = NULLCHAR; 492 } else { 493 tostring++; 494 fromstring++; 495 if ( (*tostring != '(') && (*fromstring == '(') ) { 496 (void) strcpy(buffer, tostring); 497 length = nextProto(fromstring) - fromstring; 498 (void) strncpy(tostring, fromstring, length); 499 (void) strcpy(tostring+length, buffer); 500 } 501 } 502 return; 503 } 504 505 /* 506 * removeProto 507 * 508 * char *old 509 * char letter 510 * 511 * return 512 * none 513 */ 514 static void 515 removeProto(string, letter) 516 char *string, letter; 517 { 518 while ( *(string = nextProto(string)) != NULLCHAR ) { 519 if ( *string == letter ) 520 (void) strcpy(string, nextProto(string+1)); 521 else 522 string++; 523 } 524 } 525 526 /* 527 * nextProto 528 * char *string; 529 * return 530 * char * to next non-parameter letter 531 */ 532 static char * 533 nextProto(string) 534 char *string; 535 { 536 if ( *string == '(' ) 537 while ( *string != NULLCHAR ) 538 if ( *(string++) == ')' ) 539 break; 540 return(string); 541 } 542 543 /* 544 * findProto 545 * char *desired, 546 * char protoPtr; 547 * return 548 * char *pointer to found or string terminating NULLCHAR 549 */ 550 GLOBAL char * 551 findProto(string, letter) 552 char *string; 553 char letter; 554 { 555 while ( *(string = nextProto(string)) != NULLCHAR ) 556 if ( *string == letter ) 557 break; 558 else 559 string++; 560 return(string); 561 } 562 563 /* 564 * chat - do conversation 565 * input: 566 * nf - number of fields in flds array 567 * flds - fields from Systems file 568 * fn - write file number 569 * phstr1 - phone number to replace \D 570 * phstr2 - phone number to replace \T 571 * 572 * return codes: 0 | FAIL 573 */ 574 575 GLOBAL int 576 chat(nf, flds, fn, phstr1, phstr2) 577 char *flds[], *phstr1, *phstr2; 578 int nf, fn; 579 { 580 char *want, *altern; 581 int k, ok; 582 583 for (k = 0; k < nf; k += 2) { 584 want = flds[k]; 585 ok = FAIL; 586 while (ok != 0) { 587 altern = index(want, '-'); 588 if (altern != NULL) 589 *altern++ = NULLCHAR; 590 ok = expect(want, fn); 591 if (ok == 0) 592 break; 593 if (altern == NULL) { 594 Uerror = SS_LOGIN_FAILED; 595 logent(UERRORTEXT, "FAILED"); 596 return(FAIL); 597 } 598 want = index(altern, '-'); 599 if (want != NULL) 600 *want++ = NULLCHAR; 601 sendthem(altern, fn, phstr1, phstr2); 602 } 603 sleep(2); 604 if (flds[k+1]) 605 sendthem(flds[k+1], fn, phstr1, phstr2); 606 } 607 return(0); 608 } 609 610 #define MR 1000 611 612 /* 613 * expect(str, fn) look for expected string w/ possible special chars 614 * 615 * return codes: 616 * 0 - found 617 * FAIL - too many characters read 618 * some character - timed out 619 */ 620 621 GLOBAL int 622 expect(str, fn) 623 char *str; 624 int fn; 625 { 626 register char *bptr, *sptr; 627 char buf[BUFSIZ]; 628 629 bptr = buf; 630 631 for (sptr = str; *sptr; sptr++) { 632 if (*sptr == '\\') { 633 switch (*++sptr) { 634 case 'H': 635 *bptr++ = '\0'; 636 if (expect_str(buf, fn) == FAIL) { 637 return (FAIL); 638 } 639 if (wait_for_hangup(fn) == FAIL) { 640 return (FAIL); 641 } 642 bptr = buf; 643 continue; 644 case '\\': 645 *bptr++ = '\\'; 646 continue; 647 default: 648 *bptr++ = '\\'; 649 *bptr++ = *sptr; 650 continue; 651 } 652 } else 653 *bptr++ = *sptr; 654 } 655 *bptr = '\0'; 656 if (expect_str(buf, fn) == FAIL) { 657 return (FAIL); 658 } 659 return (0); 660 } 661 662 /* 663 * expect_str(str, fn) look for expected string, w/ no special chars 664 * 665 * return codes: 666 * 0 - found 667 * FAIL - too many characters read 668 * some character - timed out 669 */ 670 671 GLOBAL int 672 expect_str(str, fn) 673 char *str; 674 int fn; 675 { 676 static char rdvec[MR]; 677 char *rp = rdvec; 678 register int kr, c; 679 char nextch; 680 681 *rp = 0; 682 683 CDEBUG(4, "expect: (%s", ""); 684 for (c=0; (kr=str[c]) != 0 ; c++) 685 if (kr < 040) { 686 CDEBUG(4, "^%c", kr | 0100); 687 } else 688 CDEBUG(4, "%c", kr); 689 CDEBUG(4, ")\n%s", ""); 690 691 if (EQUALS(str, "\"\"")) { 692 CDEBUG(4, "got it\n%s", ""); 693 return(0); 694 } 695 if (*str== '\0') { 696 return(0); 697 } 698 if (setjmp(Sjbuf)) { 699 return (FAIL); 700 } 701 (void) signal(SIGALRM, alarmtr); 702 alarm(expecttime); 703 while (notin(str, rdvec)) { 704 errno = 0; 705 kr = (*Read)(fn, &nextch, 1); 706 if (kr <= 0) { 707 alarm(0); 708 CDEBUG(4, "lost line errno - %d\n", errno); 709 logent("LOGIN", "LOST LINE"); 710 return(FAIL); 711 } 712 c = nextch & 0177; 713 CDEBUG(4, "%s", c < 040 ? "^" : ""); 714 CDEBUG(4, "%c", c < 040 ? c | 0100 : c); 715 if ((*rp = nextch & 0177) != NULLCHAR) 716 rp++; 717 if (rp >= rdvec + MR) { 718 CDEBUG(4, "enough already\n%s", ""); 719 alarm(0); 720 return(FAIL); 721 } 722 *rp = NULLCHAR; 723 } 724 alarm(0); 725 CDEBUG(4, "got it\n%s", ""); 726 return(0); 727 } 728 /* 729 * alarmtr() - catch alarm routine for "expect". 730 */ 731 /*ARGSUSED*/ 732 GLOBAL void 733 alarmtr(sig) 734 int sig; 735 { 736 CDEBUG(6, "timed out\n%s", ""); 737 longjmp(Sjbuf, 1); 738 } 739 740 /* 741 * wait_for_hangup() - wait for a hangup to occur on the given device 742 */ 743 int 744 wait_for_hangup(dcf) 745 int dcf; 746 { 747 int rval; 748 char buff[BUFSIZ]; 749 750 CDEBUG(4, "Waiting for hangup\n%s", ""); 751 while((rval = read(dcf, buff, BUFSIZ)) > 0); 752 753 if (rval < 0) { 754 return (FAIL); 755 } 756 CDEBUG(4, "Received hangup\n%s", ""); 757 758 if (clear_hup(dcf) != SUCCESS) { 759 CDEBUG(4, "Unable to clear hup on device\n%s", ""); 760 return (FAIL); 761 } 762 return (SUCCESS); 763 } 764 765 /* 766 * sendthem(str, fn, phstr1, phstr2) send line of chat sequence 767 * char *str, *phstr; 768 * 769 * return codes: none 770 */ 771 772 #define FLUSH() {\ 773 if ((bptr - buf) > 0)\ 774 if (wrstr(fn, buf, bptr - buf, echocheck) != SUCCESS)\ 775 goto err;\ 776 bptr = buf;\ 777 } 778 779 GLOBAL void 780 sendthem(str, fn, phstr1, phstr2) 781 char *str, *phstr1, *phstr2; 782 int fn; 783 { 784 int sendcr = 1, echocheck = 0; 785 register char *sptr, *bptr; 786 char buf[BUFSIZ]; 787 struct termio ttybuf; 788 static int p_init = 0; 789 790 if (!p_init) { 791 p_init++; 792 bld_partab(P_EVEN); 793 } 794 795 /* should be EQUALS, but previous versions had BREAK n for integer n */ 796 if (PREFIX("BREAK", str)) { 797 /* send break */ 798 CDEBUG(5, "BREAK\n%s", ""); 799 (*genbrk)(fn); 800 return; 801 } 802 803 if (PREFIX("STTY=", str)) { 804 CDEBUG(5, "STTY %s\n", str+5); 805 setmode(str+5, fn); 806 return; 807 } 808 809 if (EQUALS(str, "EOT")) { 810 CDEBUG(5, "EOT\n%s", ""); 811 bptr = buf; 812 for (sptr = EOTMSG; *sptr; sptr++) 813 *bptr++ = par_tab[*sptr&0177]; 814 (void) (*Write)(fn, buf, bptr - buf); 815 return; 816 } 817 818 /* Set parity as needed */ 819 if (EQUALS(str, "P_ZERO")) { 820 bld_partab(P_ZERO); 821 return; 822 } 823 if (EQUALS(str, "P_ONE")) { 824 bld_partab(P_ONE); 825 return; 826 } 827 if (EQUALS(str, "P_EVEN")) { 828 bld_partab(P_EVEN); 829 return; 830 } 831 if (EQUALS(str, "P_ODD")) { 832 bld_partab(P_ODD); 833 return; 834 } 835 836 if (EQUALS(str, "\"\"")) { 837 CDEBUG(5, "\"\"\n%s", ""); 838 str += 2; 839 } 840 841 bptr = buf; 842 CDEBUG(5, "sendthem (%s", ""); 843 for (sptr = str; *sptr; sptr++) { 844 if (*sptr == '\\') { 845 switch(*++sptr) { 846 847 /* adjust switches */ 848 case 'c': /* no CR after string */ 849 FLUSH(); 850 if (sptr[1] == NULLCHAR) { 851 CDEBUG(5, "<NO CR>%s", ""); 852 sendcr = 0; 853 } else 854 CDEBUG(5, "<NO CR IGNORED>\n%s", ""); 855 continue; 856 857 /* stash in buf and continue */ 858 case 'D': /* raw phnum */ 859 strcpy(bptr, phstr1); 860 bptr += strlen(bptr); 861 continue; 862 case 'T': /* translated phnum */ 863 strcpy(bptr, phstr2); 864 bptr += strlen(bptr); 865 continue; 866 case 'N': /* null */ 867 *bptr++ = 0; 868 continue; 869 case 's': /* space */ 870 *bptr++ = ' '; 871 continue; 872 case '\\': /* backslash escapes itself */ 873 *bptr++ = *sptr; 874 continue; 875 default: /* send the backslash */ 876 *bptr++ = '\\'; 877 *bptr++ = *sptr; 878 continue; 879 880 /* flush buf, perform action, and continue */ 881 case 'E': /* echo check on */ 882 FLUSH(); 883 CDEBUG(5, "ECHO CHECK ON\n%s", ""); 884 echocheck = 1; 885 continue; 886 case 'e': /* echo check off */ 887 FLUSH(); 888 CDEBUG(5, "ECHO CHECK OFF\n%s", ""); 889 echocheck = 0; 890 continue; 891 case 'd': /* sleep briefly */ 892 FLUSH(); 893 CDEBUG(5, "DELAY\n%s", ""); 894 sleep(2); 895 continue; 896 case 'p': /* pause momentarily */ 897 FLUSH(); 898 CDEBUG(5, "PAUSE\n%s", ""); 899 nap(HZ/4); /* approximately 1/4 second */ 900 continue; 901 case 'K': /* inline break */ 902 FLUSH(); 903 CDEBUG(5, "BREAK\n%s", ""); 904 (*genbrk)(fn); 905 continue; 906 case 'M': /* modem control - set CLOCAL */ 907 case 'm': /* no modem control - clear CLOCAL */ 908 FLUSH(); 909 CDEBUG(5, ")\n%s CLOCAL ", 910 (*sptr == 'M' ? "set" : "clear")); 911 #ifdef ATTSVTTY 912 if ( (*Ioctl)(fn, TCGETA, &ttybuf) != 0 ) { 913 CDEBUG(5, "ignored. TCGETA failed, errno %d", errno); 914 } else { 915 if (*sptr == 'M') 916 ttybuf.c_cflag |= CLOCAL; 917 else 918 ttybuf.c_cflag &= ~CLOCAL; 919 if ( (*Ioctl)(fn, TCSETAW, &ttybuf) != 0 ) 920 CDEBUG(5, "failed. TCSETAW failed, errno %d", errno); 921 } 922 #endif 923 CDEBUG(5, "\n%s", ""); 924 continue; 925 } 926 } else 927 *bptr++ = *sptr; 928 } 929 if (sendcr) 930 *bptr++ = '\r'; 931 if ( (bptr - buf) > 0 ) 932 (void) wrstr(fn, buf, bptr - buf, echocheck); 933 934 err: 935 CDEBUG(5, ")\n%s", ""); 936 return; 937 } 938 939 /* 940 * generate parity table for use by sendthem. 941 */ 942 bld_partab(type) 943 int type; 944 { 945 register int i, j, n; 946 947 for (i = 0; i < 128; i++) { 948 n = 0; 949 for (j = i&0177; j; j = (j-1)&j) 950 n++; 951 par_tab[i] = i; 952 if (type == P_ONE 953 || (type == P_EVEN && (n&01) != 0) 954 || (type == P_ODD && (n&01) == 0)) 955 par_tab[i] |= 0200; 956 } 957 } 958 959 #undef FLUSH 960 961 GLOBAL int 962 wrstr(fn, buf, len, echocheck) 963 char *buf; 964 { 965 int i; 966 char dbuf[BUFSIZ], *dbptr = dbuf; 967 968 if (echocheck) 969 return(wrchr(fn, buf, len)); 970 971 if (Debug >= 5) { 972 if (sysaccess(ACCESS_SYSTEMS) == 0) { /* Systems file access ok */ 973 for (i = 0; i < len; i++) { 974 *dbptr = buf[i]; 975 if (*dbptr < 040) { 976 *dbptr++ = '^'; 977 *dbptr = buf[i] | 0100; 978 } 979 dbptr++; 980 } 981 *dbptr = 0; 982 } else 983 strcpy(dbuf, "????????"); 984 CDEBUG(5, "%s", dbuf); 985 } 986 dbptr = dbuf; 987 for (i = 0; i < len; i++) 988 *dbptr++ = par_tab[buf[i]&0177]; 989 if ((*Write)(fn, dbuf, len) != len) 990 return(FAIL); 991 return(SUCCESS); 992 } 993 994 GLOBAL int 995 wrchr(fn, buf, len) 996 register int fn; 997 register char *buf; 998 { 999 int i, saccess; 1000 char cin, cout; 1001 1002 saccess = (sysaccess(ACCESS_SYSTEMS) == 0); /* protect Systems file */ 1003 if (setjmp(Sjbuf)) 1004 return(FAIL); 1005 (void) signal(SIGALRM, alarmtr); 1006 1007 for (i = 0; i < len; i++) { 1008 cout = buf[i]&0177; 1009 if (saccess) { 1010 CDEBUG(5, "%s", cout < 040 ? "^" : ""); 1011 CDEBUG(5, "%c", cout < 040 ? cout | 0100 : cout); 1012 } else 1013 CDEBUG(5, "?%s", ""); 1014 if (((*Write)(fn, &par_tab[cout], 1)) != 1) 1015 return(FAIL); 1016 do { 1017 (void) alarm(expecttime); 1018 if ((*Read)(fn, &cin, 1) != 1) 1019 return(FAIL); 1020 (void) alarm(0); 1021 cin &= 0177; 1022 if (saccess) { 1023 CDEBUG(5, "%s", cin < 040 ? "^" : ""); 1024 CDEBUG(5, "%c", cin < 040 ? cin | 0100 : cin); 1025 } else 1026 CDEBUG(5, "?%s", ""); 1027 } while (cout != cin); 1028 } 1029 return(SUCCESS); 1030 } 1031 1032 1033 /* 1034 * notin(sh, lg) check for occurrence of substring "sh" 1035 * char *sh, *lg; 1036 * 1037 * return codes: 1038 * 0 - found the string 1039 * 1 - not in the string 1040 */ 1041 1042 static int 1043 notin(sh, lg) 1044 char *sh, *lg; 1045 { 1046 while (*lg != NULLCHAR) { 1047 if (PREFIX(sh, lg)) 1048 return(0); 1049 else 1050 lg++; 1051 } 1052 return(1); 1053 } 1054 1055 1056 /* 1057 * ifdate(s) 1058 * char *s; 1059 * 1060 * ifdate - this routine will check a string (s) 1061 * like "MoTu0800-1730" to see if the present 1062 * time is within the given limits. 1063 * 1064 * SIDE EFFECT - Retrytime is set to number following ";" 1065 * SIDE EFFECT - MaxGrade is set to character following "/" 1066 * 1067 * if a grade is specified, iswrk() is consulted, so that we don't 1068 * place calls when there's only low priority work. this will appear 1069 * as a "wrong time to call" in the status file. sorry. 1070 * 1071 * String alternatives: 1072 * Wk - Mo thru Fr 1073 * zero or one time means all day 1074 * Any - any day 1075 * 1076 * return codes: 1077 * 0 - not within limits, or grade too low 1078 * 1 - within limits 1079 */ 1080 1081 static int 1082 ifdate(s) 1083 char *s; 1084 { 1085 char *r; 1086 #ifdef MAXGRADE 1087 char *m, grade; 1088 #endif 1089 struct tm *tp; 1090 time_t clock; 1091 int t__now; 1092 1093 time(&clock); 1094 tp = localtime(&clock); 1095 t__now = tp->tm_hour * 100 + tp->tm_min; /* "navy" time */ 1096 1097 /* 1098 * pick up retry time for failures and max grade 1099 * global variables Retrytime and MaxGrade are set here 1100 */ 1101 r = strrchr(s, ';'); 1102 1103 /* set retry time */ 1104 if (r != NULL) { 1105 if (isdigit(r[1])) { 1106 if (sscanf(r+1, "%ld", &Retrytime) < 1) 1107 Retrytime = 5; /* 5 minutes is error default */ 1108 DEBUG(5, "Retry time set to %d minutes\n", Retrytime); 1109 Retrytime *= 60; /* convert to seconds */ 1110 *r = NULLCHAR; /* blow away retry time field */ 1111 } 1112 } else 1113 Retrytime = 0; /* use exponential backoff */ 1114 1115 #ifdef MAXGRADE 1116 /* set grade */ 1117 MaxGrade = NULLCHAR; /* default */ 1118 m = strrchr(s, '/'); 1119 if (m != NULL) { 1120 if (isalnum(m[1])) 1121 MaxGrade = m[1]; /* you asked for it! */ 1122 *m = NULLCHAR; /* blow away max grade field */ 1123 DEBUG(5, "Max Grade set to %c\n", MaxGrade); 1124 } 1125 1126 /* test grade */ 1127 if (MaxGrade != NULLCHAR) { 1128 grade = iswrk(CNULL); 1129 if (grade == NULLCHAR || MaxGrade < grade) { 1130 DEBUG(4, "No work of grade %c -- no call\n", MaxGrade); 1131 return(0); 1132 } 1133 } 1134 #endif /* MAXGRADE */ 1135 1136 1137 while (checkdate(s, tp, t__now) == 0) { 1138 s = strchr(s, ','); 1139 if (s == CNULL) 1140 return(0); 1141 s++; 1142 } 1143 return(1); 1144 } 1145 1146 /* worker function for ifdate() */ 1147 static int 1148 checkdate(s, tp, t__now) 1149 char *s; 1150 struct tm *tp; 1151 int t__now; 1152 { 1153 static char *days[] = { 1154 "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", 0 1155 }; 1156 int i; 1157 1158 /* 1159 * check day of week 1160 */ 1161 1162 while (isalpha(*s)) { 1163 if (PREFIX("Any", s)) 1164 return(checktime(s, t__now)); 1165 1166 if (PREFIX("Wk", s) && tp->tm_wday >= 1 && tp->tm_wday <= 5) 1167 return(checktime(s, t__now)); 1168 1169 for (i = 0; days[i]; i++) 1170 if (PREFIX(days[i], s) && tp->tm_wday == i) 1171 return(checktime(s, t__now)); 1172 s++; 1173 } 1174 1175 return(0); /* day match failed */ 1176 } 1177 1178 /* day match ok -- check time */ 1179 static int 1180 checktime(s, t__now) 1181 char *s; 1182 int t__now; 1183 { 1184 int t__low, t__high; 1185 1186 while (isalpha(*s)) /* flush day stuff */ 1187 s++; 1188 1189 if ((sscanf(s, "%d-%d", &t__low, &t__high) < 2)) 1190 return(1); /* time match ok (default) */ 1191 1192 if (t__low == t__high) 1193 return(1); 1194 1195 /* 0000 crossover? */ 1196 if (t__low < t__high) { 1197 if (t__low <= t__now && t__now <= t__high) 1198 return(1); 1199 } else { 1200 if (t__low <= t__now || t__now <= t__high) 1201 return(1); 1202 } 1203 1204 return(0); 1205 } 1206 1207 /* 1208 * char * 1209 * fdig(cp) find first digit in string 1210 * 1211 * return - pointer to first digit in string or end of string 1212 */ 1213 1214 GLOBAL char * 1215 fdig(cp) 1216 char *cp; 1217 { 1218 char *c; 1219 1220 for (c = cp; *c; c++) 1221 if (*c >= '0' && *c <= '9') 1222 break; 1223 return(c); 1224 } 1225 1226 1227 #ifdef FASTTIMER 1228 /* Sleep in increments of 60ths of second. */ 1229 GLOBAL void 1230 nap (time) 1231 register int time; 1232 { 1233 static int fd; 1234 1235 if (fd == 0) 1236 fd = open (FASTTIMER, 0); 1237 1238 (void) (*Read)(fd, 0, time); 1239 return; 1240 } 1241 1242 #endif /* FASTTIMER */ 1243 1244 #if defined(BSD4_2) || defined(ATTSVR4) 1245 1246 /* nap(n) -- sleep for 'n' ticks of 1/60th sec each. */ 1247 /* This version uses the select system call */ 1248 1249 1250 GLOBAL void 1251 nap(n) 1252 unsigned n; 1253 { 1254 struct timeval tv; 1255 1256 if (n==0) 1257 return; 1258 tv.tv_sec = n/60; 1259 tv.tv_usec = ((n%60)*1000000L)/60; 1260 (void) select(32, 0, 0, 0, &tv); 1261 return; 1262 } 1263 1264 #endif /* BSD4_2 || ATTSVR4 */ 1265 1266 #ifdef NONAP 1267 1268 /* nap(n) where n is ticks 1269 * 1270 * loop using n/HZ part of a second 1271 * if n represents more than 1 second, then 1272 * use sleep(time) where time is the equivalent 1273 * seconds rounded off to full seconds 1274 * NOTE - this is a rough approximation and chews up 1275 * processor resource! 1276 */ 1277 1278 GLOBAL void 1279 nap(n) 1280 unsigned n; 1281 { 1282 struct tms tbuf; 1283 long endtime; 1284 int i; 1285 1286 if (n > HZ) { 1287 /* > second, use sleep, rounding time */ 1288 sleep( (int) (((n)+HZ/2)/HZ) ); 1289 return; 1290 } 1291 1292 /* use timing loop for < 1 second */ 1293 endtime = times(&tbuf) + 3*n/4; /* use 3/4 because of scheduler! */ 1294 while (times(&tbuf) < endtime) { 1295 for (i=0; i<1000; i++, (void) (i*i)) 1296 ; 1297 } 1298 return; 1299 } 1300 1301 #endif /* NONAP */ 1302 1303 /* 1304 1305 * altconn - place a telephone call to system 1306 * from cu when telephone number or direct line used 1307 * 1308 * return codes: 1309 * FAIL - connection failed 1310 * >0 - file no. - connect ok 1311 * When a failure occurs, Uerror is set. 1312 */ 1313 GLOBAL int 1314 altconn(call) 1315 struct call *call; 1316 { 1317 int fn = FAIL; 1318 char *alt[7]; 1319 EXTERN char *Myline; 1320 1321 alt[F_NAME] = "dummy"; /* to replace the Systems file fields */ 1322 alt[F_TIME] = "Any"; /* needed for getto(); [F_TYPE] and */ 1323 alt[F_TYPE] = ""; /* [F_PHONE] assignment below */ 1324 alt[F_CLASS] = call->speed; 1325 alt[F_PHONE] = ""; 1326 alt[F_LOGIN] = ""; 1327 alt[6] = NULL; 1328 1329 CDEBUG(4,"altconn called\r\n%s", ""); 1330 1331 /* cu -l dev ... */ 1332 /* if is "/dev/device", strip off "/dev/" because must */ 1333 /* exactly match entries in Devices file, which usually */ 1334 /* omit the "/dev/". if doesn't begin with "/dev/", */ 1335 /* either they've omitted the "/dev/" or it's a non- */ 1336 /* standard path name. in either case, leave it as is */ 1337 1338 if(call->line != NULL ) { 1339 if ( strncmp(call->line, "/dev/", 5) == 0 ) { 1340 Myline = (call->line + 5); 1341 } else { 1342 Myline = call->line; 1343 } 1344 } 1345 1346 /* cu ... telno */ 1347 if(call->telno != NULL) { 1348 alt[F_PHONE] = call->telno; 1349 alt[F_TYPE] = "ACU"; 1350 } else { 1351 /* cu direct line */ 1352 alt[F_TYPE] = "Direct"; 1353 } 1354 if (call->type != NULL) 1355 alt[F_TYPE] = call->type; 1356 fn = getto(alt); 1357 CDEBUG(4, "getto ret %d\n", fn); 1358 1359 return(fn); 1360 1361 } 1362