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