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