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