1 /* 2 * Chat -- a program for automatic session establishment (i.e. dial 3 * the phone and log in). 4 * 5 * This software is in the public domain. 6 * 7 * Please send all bug reports, requests for information, etc. to: 8 * 9 * Al Longyear (longyear@netcom.com) 10 * (I was the last person to change this code.) 11 * 12 * The original author is: 13 * 14 * Karl Fox <karl@MorningStar.Com> 15 * Morning Star Technologies, Inc. 16 * 1760 Zollinger Road 17 * Columbus, OH 43221 18 * (614)451-1883 19 */ 20 21 static char rcsid[] = "$Id: chat.c,v 1.2 1994/12/19 01:02:11 ache Exp $"; 22 23 #include <stdio.h> 24 #include <fcntl.h> 25 #include <signal.h> 26 #include <errno.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <syslog.h> 32 33 #ifndef TERMIO 34 #undef TERMIOS 35 #define TERMIOS 36 #endif 37 38 #ifdef sun 39 # if defined(SUNOS) && SUNOS >= 41 40 # ifndef HDB 41 # define HDB 42 # endif 43 # endif 44 #endif 45 46 #ifdef TERMIO 47 #include <termio.h> 48 #endif 49 #ifdef TERMIOS 50 #include <termios.h> 51 #endif 52 53 #define STR_LEN 1024 54 55 #ifndef SIGTYPE 56 #define SIGTYPE void 57 #endif 58 59 #ifdef __STDC__ 60 #undef __P 61 #define __P(x) x 62 #else 63 #define __P(x) () 64 #define const 65 #endif 66 67 /*************** Micro getopt() *********************************************/ 68 #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 69 (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 70 &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 71 #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 72 (_O=4,(char*)0):(char*)0) 73 #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 74 #define ARG(c,v) (c?(--c,*v++):(char*)0) 75 76 static int _O = 0; /* Internal state */ 77 /*************** Micro getopt() *********************************************/ 78 79 char *program_name; 80 81 #ifndef LOCK_DIR 82 # if defined(__NetBSD__) || defined(__FreeBSD__) 83 # define PIDSTRING 84 # define LOCK_DIR "/var/spool/lock" 85 # else 86 # ifdef HDB 87 # define PIDSTRING 88 # define LOCK_DIR "/usr/spool/locks" 89 # else /* HDB */ 90 # define LOCK_DIR "/usr/spool/uucp" 91 # endif /* HDB */ 92 # endif 93 #endif /* LOCK_DIR */ 94 95 #define MAX_ABORTS 50 96 #define DEFAULT_CHAT_TIMEOUT 45 97 98 int verbose = 0; 99 int quiet = 0; 100 char *lock_file = (char *)0; 101 char *chat_file = (char *)0; 102 int timeout = DEFAULT_CHAT_TIMEOUT; 103 104 int have_tty_parameters = 0; 105 #ifdef TERMIO 106 struct termio saved_tty_parameters; 107 #endif 108 #ifdef TERMIOS 109 struct termios saved_tty_parameters; 110 #endif 111 112 char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 113 fail_buffer[50]; 114 int n_aborts = 0, abort_next = 0, timeout_next = 0; 115 116 void *dup_mem __P((void *b, size_t c)); 117 void *copy_of __P((char *s)); 118 void usage __P((void)); 119 void logf __P((const char *str)); 120 void logflush __P((void)); 121 void fatal __P((const char *msg)); 122 void sysfatal __P((const char *msg)); 123 SIGTYPE sigalrm __P((int signo)); 124 SIGTYPE sigint __P((int signo)); 125 SIGTYPE sigterm __P((int signo)); 126 SIGTYPE sighup __P((int signo)); 127 void unalarm __P((void)); 128 void init __P((void)); 129 void set_tty_parameters __P((void)); 130 void break_sequence __P((void)); 131 void terminate __P((int status)); 132 void do_file __P((char *chat_file)); 133 void lock __P((void)); 134 void delay __P((void)); 135 int get_string __P((register char *string)); 136 int put_string __P((register char *s)); 137 int write_char __P((int c)); 138 int put_char __P((char c)); 139 int get_char __P((void)); 140 void chat_send __P((register char *s)); 141 char *character __P((char c)); 142 void chat_expect __P((register char *s)); 143 char *clean __P((register char *s, int sending)); 144 void unlock __P((void)); 145 void lock __P((void)); 146 void break_sequence __P((void)); 147 void terminate __P((int status)); 148 void die __P((void)); 149 150 void *dup_mem(b, c) 151 void *b; 152 size_t c; 153 { 154 void *ans = malloc (c); 155 if (!ans) 156 fatal ("memory error!\n"); 157 memcpy (ans, b, c); 158 return ans; 159 } 160 161 void *copy_of (s) 162 char *s; 163 { 164 return dup_mem (s, strlen (s) + 1); 165 } 166 167 /* 168 * chat [ -v ] [ -t timeout ] [ -l lock-file ] [ -f chat-file ] \ 169 * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 170 * 171 * Perform a UUCP-dialer-like chat script on stdin and stdout. 172 */ 173 int 174 main(argc, argv) 175 int argc; 176 char **argv; 177 { 178 int option; 179 char *arg; 180 181 program_name = *argv; 182 183 while (option = OPTION(argc, argv)) 184 switch (option) 185 { 186 case 'v': 187 ++verbose; 188 break; 189 190 case 'f': 191 if (arg = OPTARG(argc, argv)) 192 chat_file = copy_of(arg); 193 else 194 usage(); 195 196 break; 197 198 case 'l': 199 if (arg = OPTARG(argc, argv)) 200 lock_file = copy_of(arg); 201 else 202 usage(); 203 204 break; 205 206 case 't': 207 if (arg = OPTARG(argc, argv)) 208 timeout = atoi(arg); 209 else 210 usage(); 211 212 break; 213 214 default: 215 usage(); 216 } 217 218 #ifdef ultrix 219 openlog("chat", LOG_PID); 220 #else 221 openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 222 223 if (verbose) { 224 setlogmask(LOG_UPTO(LOG_INFO)); 225 } else { 226 setlogmask(LOG_UPTO(LOG_WARNING)); 227 } 228 #endif 229 230 init(); 231 232 if (chat_file != NULL) 233 { 234 arg = ARG(argc, argv); 235 if (arg != NULL) 236 usage(); 237 else 238 do_file (chat_file); 239 } 240 else 241 { 242 while (arg = ARG(argc, argv)) 243 { 244 chat_expect(arg); 245 246 if (arg = ARG(argc, argv)) 247 chat_send(arg); 248 } 249 } 250 251 terminate(0); 252 } 253 254 /* 255 * Process a chat script when read from a file. 256 */ 257 258 void do_file (chat_file) 259 char *chat_file; 260 { 261 int linect, len, sendflg; 262 char *sp, *arg, quote; 263 char buf [STR_LEN]; 264 FILE *cfp; 265 266 if ((cfp = fopen (chat_file, "r")) == NULL) 267 { 268 syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 269 terminate (1); 270 } 271 272 linect = 0; 273 sendflg = 0; 274 275 while (fgets(buf, STR_LEN, cfp) != NULL) 276 { 277 sp = strchr (buf, '\n'); 278 if (sp) 279 *sp = '\0'; 280 281 linect++; 282 sp = buf; 283 while (*sp != '\0') 284 { 285 if (*sp == ' ' || *sp == '\t') 286 { 287 ++sp; 288 continue; 289 } 290 291 if (*sp == '"' || *sp == '\'') 292 { 293 quote = *sp++; 294 arg = sp; 295 while (*sp != quote) 296 { 297 if (*sp == '\0') 298 { 299 syslog (LOG_ERR, "unterminated quote (line %d)", 300 linect); 301 terminate (1); 302 } 303 304 if (*sp++ == '\\') 305 if (*sp != '\0') 306 ++sp; 307 } 308 } 309 else 310 { 311 arg = sp; 312 while (*sp != '\0' && *sp != ' ' && *sp != '\t') 313 ++sp; 314 } 315 316 if (*sp != '\0') 317 *sp++ = '\0'; 318 319 if (sendflg) 320 { 321 chat_send (arg); 322 } 323 else 324 { 325 chat_expect (arg); 326 } 327 sendflg = !sendflg; 328 } 329 } 330 fclose (cfp); 331 } 332 333 /* 334 * We got an error parsing the command line. 335 */ 336 void usage() 337 { 338 fprintf(stderr, "\ 339 Usage: %s [-v] [-l lock-file] [-t timeout] {-f chat-file || chat-script}\n", 340 program_name); 341 exit(1); 342 } 343 344 char line[256]; 345 char *p; 346 347 void logf (str) 348 const char *str; 349 { 350 p = line + strlen(line); 351 strcat (p, str); 352 353 if (str[strlen(str)-1] == '\n') 354 { 355 syslog (LOG_INFO, "%s", line); 356 line[0] = 0; 357 } 358 } 359 360 void logflush() 361 { 362 if (line[0] != 0) 363 { 364 syslog(LOG_INFO, "%s", line); 365 line[0] = 0; 366 } 367 } 368 369 /* 370 * Unlock and terminate with an error. 371 */ 372 void die() 373 { 374 unlock(); 375 terminate(1); 376 } 377 378 /* 379 * Print an error message and terminate. 380 */ 381 382 void fatal (msg) 383 const char *msg; 384 { 385 syslog(LOG_ERR, "%s", msg); 386 unlock(); 387 terminate(1); 388 } 389 390 /* 391 * Print an error message along with the system error message and 392 * terminate. 393 */ 394 395 void sysfatal (msg) 396 const char *msg; 397 { 398 syslog(LOG_ERR, "%s: %m", msg); 399 unlock(); 400 terminate(1); 401 } 402 403 int alarmed = 0; 404 405 SIGTYPE sigalrm(signo) 406 int signo; 407 { 408 int flags; 409 410 alarm(1); 411 alarmed = 1; /* Reset alarm to avoid race window */ 412 signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 413 414 logflush(); 415 if ((flags = fcntl(0, F_GETFL, 0)) == -1) 416 sysfatal("Can't get file mode flags on stdin"); 417 else 418 if (fcntl(0, F_SETFL, flags | FNDELAY) == -1) 419 sysfatal("Can't set file mode flags on stdin"); 420 421 if (verbose) 422 { 423 syslog(LOG_INFO, "alarm"); 424 } 425 } 426 427 void unalarm() 428 { 429 int flags; 430 431 if ((flags = fcntl(0, F_GETFL, 0)) == -1) 432 sysfatal("Can't get file mode flags on stdin"); 433 else 434 if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1) 435 sysfatal("Can't set file mode flags on stdin"); 436 } 437 438 SIGTYPE sigint(signo) 439 int signo; 440 { 441 fatal("SIGINT"); 442 } 443 444 SIGTYPE sigterm(signo) 445 int signo; 446 { 447 fatal("SIGTERM"); 448 } 449 450 SIGTYPE sighup(signo) 451 int signo; 452 { 453 fatal("SIGHUP"); 454 } 455 456 void init() 457 { 458 signal(SIGINT, sigint); 459 signal(SIGTERM, sigterm); 460 signal(SIGHUP, sighup); 461 462 if (lock_file) 463 lock(); 464 465 set_tty_parameters(); 466 signal(SIGALRM, sigalrm); 467 alarm(0); 468 alarmed = 0; 469 } 470 471 void set_tty_parameters() 472 { 473 #ifdef TERMIO 474 struct termio t; 475 476 if (ioctl(0, TCGETA, &t) < 0) 477 sysfatal("Can't get terminal parameters"); 478 #endif 479 #ifdef TERMIOS 480 struct termios t; 481 482 if (tcgetattr(0, &t) < 0) 483 sysfatal("Can't get terminal parameters"); 484 #endif 485 486 saved_tty_parameters = t; 487 have_tty_parameters = 1; 488 489 t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 490 t.c_oflag = 0; 491 t.c_lflag = 0; 492 t.c_cc[VERASE] = t.c_cc[VKILL] = 0; 493 t.c_cc[VMIN] = 1; 494 t.c_cc[VTIME] = 0; 495 496 #ifdef TERMIO 497 if (ioctl(0, TCSETA, &t) < 0) 498 sysfatal("Can't set terminal parameters"); 499 #endif 500 #ifdef TERMIOS 501 if (tcsetattr(0, TCSANOW, &t) < 0) 502 sysfatal("Can't set terminal parameters"); 503 #endif 504 } 505 506 void break_sequence() 507 { 508 #ifdef TERMIOS 509 tcsendbreak (0, 0); 510 #endif 511 } 512 513 void terminate(status) 514 int status; 515 { 516 if (have_tty_parameters && 517 #ifdef TERMIO 518 ioctl(0, TCSETA, &saved_tty_parameters) < 0 519 #endif 520 #ifdef TERMIOS 521 tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0 522 #endif 523 ) { 524 syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 525 unlock(); 526 exit(1); 527 } 528 exit(status); 529 } 530 531 /* 532 * Create a lock file for the named lock device 533 */ 534 void lock() 535 { 536 int fd, pid; 537 # ifdef PIDSTRING 538 char hdb_lock_buffer[12]; 539 # endif 540 541 lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR) 542 + 1 + strlen(lock_file) + 1), 543 LOCK_DIR), "/"), lock_file); 544 545 if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) 546 { 547 char *s = lock_file; 548 lock_file = (char *)0; /* Don't remove someone else's lock file! */ 549 syslog(LOG_ERR, "Can't get lock file '%s': %m", s); 550 die(); 551 } 552 553 # ifdef PIDSTRING 554 sprintf(hdb_lock_buffer, "%10d\n", getpid()); 555 write(fd, hdb_lock_buffer, 11); 556 # else 557 pid = getpid(); 558 write(fd, &pid, sizeof pid); 559 # endif 560 561 close(fd); 562 } 563 564 /* 565 * Remove our lockfile 566 */ 567 void unlock() 568 { 569 if (lock_file) 570 { 571 unlink(lock_file); 572 lock_file = (char *)0; 573 } 574 } 575 576 /* 577 * 'Clean up' this string. 578 */ 579 char *clean(s, sending) 580 register char *s; 581 int sending; 582 { 583 char temp[STR_LEN], cur_chr; 584 register char *s1; 585 int add_return = sending; 586 #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 587 588 s1 = temp; 589 while (*s) 590 { 591 cur_chr = *s++; 592 if (cur_chr == '^') 593 { 594 cur_chr = *s++; 595 if (cur_chr == '\0') 596 { 597 *s1++ = '^'; 598 break; 599 } 600 cur_chr &= 0x1F; 601 if (cur_chr != 0) 602 *s1++ = cur_chr; 603 continue; 604 } 605 606 if (cur_chr != '\\') 607 { 608 *s1++ = cur_chr; 609 continue; 610 } 611 612 cur_chr = *s++; 613 if (cur_chr == '\0') 614 { 615 if (sending) 616 { 617 *s1++ = '\\'; 618 *s1++ = '\\'; 619 } 620 break; 621 } 622 623 switch (cur_chr) 624 { 625 case 'b': 626 *s1++ = '\b'; 627 break; 628 629 case 'c': 630 if (sending && *s == '\0') 631 add_return = 0; 632 else 633 *s1++ = cur_chr; 634 break; 635 636 case '\\': 637 case 'K': 638 case 'p': 639 case 'd': 640 if (sending) 641 *s1++ = '\\'; 642 643 *s1++ = cur_chr; 644 break; 645 646 case 'q': 647 quiet = ! quiet; 648 break; 649 650 case 'r': 651 *s1++ = '\r'; 652 break; 653 654 case 'n': 655 *s1++ = '\n'; 656 break; 657 658 case 's': 659 *s1++ = ' '; 660 break; 661 662 case 't': 663 *s1++ = '\t'; 664 break; 665 666 case 'N': 667 if (sending) 668 { 669 *s1++ = '\\'; 670 *s1++ = '\0'; 671 } 672 else 673 *s1++ = 'N'; 674 break; 675 676 default: 677 if (isoctal (cur_chr)) 678 { 679 cur_chr &= 0x07; 680 if (isoctal (*s)) 681 { 682 cur_chr <<= 3; 683 cur_chr |= *s++ - '0'; 684 if (isoctal (*s)) 685 { 686 cur_chr <<= 3; 687 cur_chr |= *s++ - '0'; 688 } 689 } 690 691 if (cur_chr != 0 || sending) 692 { 693 if (sending && (cur_chr == '\\' || cur_chr == 0)) 694 *s1++ = '\\'; 695 *s1++ = cur_chr; 696 } 697 break; 698 } 699 700 if (sending) 701 *s1++ = '\\'; 702 *s1++ = cur_chr; 703 break; 704 } 705 } 706 707 if (add_return) 708 *s1++ = '\r'; 709 710 *s1++ = '\0'; /* guarantee closure */ 711 *s1++ = '\0'; /* terminate the string */ 712 return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 713 } 714 715 /* 716 * Process the expect string 717 */ 718 void chat_expect(s) 719 register char *s; 720 { 721 if (strcmp(s, "ABORT") == 0) 722 { 723 ++abort_next; 724 return; 725 } 726 727 if (strcmp(s, "TIMEOUT") == 0) 728 { 729 ++timeout_next; 730 return; 731 } 732 733 while (*s) 734 { 735 register char *hyphen; 736 737 for (hyphen = s; *hyphen; ++hyphen) 738 if (*hyphen == '-') 739 if (hyphen == s || hyphen[-1] != '\\') 740 break; 741 742 if (*hyphen == '-') 743 { 744 *hyphen = '\0'; 745 746 if (get_string(s)) 747 return; 748 else 749 { 750 s = hyphen + 1; 751 752 for (hyphen = s; *hyphen; ++hyphen) 753 if (*hyphen == '-') 754 if (hyphen == s || hyphen[-1] != '\\') 755 break; 756 757 if (*hyphen == '-') 758 { 759 *hyphen = '\0'; 760 761 chat_send(s); 762 s = hyphen + 1; 763 } 764 else 765 { 766 chat_send(s); 767 return; 768 } 769 } 770 } 771 else 772 if (get_string(s)) 773 return; 774 else 775 { 776 if (fail_reason) 777 syslog(LOG_INFO, "Failed (%s)", fail_reason); 778 else 779 syslog(LOG_INFO, "Failed"); 780 781 unlock(); 782 terminate(1); 783 } 784 } 785 } 786 787 char *character(c) 788 char c; 789 { 790 static char string[10]; 791 char *meta; 792 793 meta = (c & 0x80) ? "M-" : ""; 794 c &= 0x7F; 795 796 if (c < 32) 797 sprintf(string, "%s^%c", meta, (int)c + '@'); 798 else 799 if (c == 127) 800 sprintf(string, "%s^?", meta); 801 else 802 sprintf(string, "%s%c", meta, c); 803 804 return (string); 805 } 806 807 /* 808 * process the reply string 809 */ 810 void chat_send (s) 811 register char *s; 812 { 813 if (abort_next) 814 { 815 char *s1; 816 817 abort_next = 0; 818 819 if (n_aborts >= MAX_ABORTS) 820 fatal("Too many ABORT strings"); 821 822 s1 = clean(s, 0); 823 824 if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 825 { 826 syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 827 die(); 828 } 829 830 abort_string[n_aborts++] = s1; 831 832 if (verbose) 833 { 834 logf("abort on ("); 835 836 for (s1 = s; *s1; ++s1) 837 logf(character(*s1)); 838 839 logf(")\n"); 840 } 841 } 842 else 843 if (timeout_next) 844 { 845 timeout_next = 0; 846 timeout = atoi(s); 847 848 if (timeout <= 0) 849 timeout = DEFAULT_CHAT_TIMEOUT; 850 851 if (verbose) 852 { 853 syslog(LOG_INFO, "timeout set to %d seconds", timeout); 854 } 855 } 856 else 857 { 858 if (strcmp(s, "EOT") == 0) 859 s = "^D\\c"; 860 else 861 if (strcmp(s, "BREAK") == 0) 862 s = "\\K\\c"; 863 if ( ! put_string(s)) 864 { 865 syslog(LOG_INFO, "Failed"); 866 unlock(); 867 terminate(1); 868 } 869 } 870 } 871 872 int get_char() 873 { 874 int status; 875 char c; 876 877 status = read(0, &c, 1); 878 879 switch (status) 880 { 881 case 1: 882 return ((int)c & 0x7F); 883 884 default: 885 syslog(LOG_WARNING, "warning: read() on stdin returned %d", 886 status); 887 888 case -1: 889 if ((status = fcntl(0, F_GETFL, 0)) == -1) 890 sysfatal("Can't get file mode flags on stdin"); 891 else 892 if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) 893 sysfatal("Can't set file mode flags on stdin"); 894 895 return (-1); 896 } 897 } 898 899 int put_char(c) 900 char c; 901 { 902 int status; 903 904 delay(); 905 906 status = write(1, &c, 1); 907 908 switch (status) 909 { 910 case 1: 911 return (0); 912 913 default: 914 syslog(LOG_WARNING, "warning: write() on stdout returned %d", 915 status); 916 917 case -1: 918 if ((status = fcntl(0, F_GETFL, 0)) == -1) 919 sysfatal("Can't get file mode flags on stdin"); 920 else 921 if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) 922 sysfatal("Can't set file mode flags on stdin"); 923 924 return (-1); 925 } 926 } 927 928 int write_char (c) 929 int c; 930 { 931 if (alarmed || put_char(c) < 0) 932 { 933 extern int errno; 934 935 alarm(0); alarmed = 0; 936 937 if (verbose) 938 { 939 if (errno == EINTR || errno == EWOULDBLOCK) 940 syslog(LOG_INFO, " -- write timed out"); 941 else 942 syslog(LOG_INFO, " -- write failed: %m"); 943 } 944 return (0); 945 } 946 return (1); 947 } 948 949 int put_string (s) 950 register char *s; 951 { 952 s = clean(s, 1); 953 954 if (verbose) 955 { 956 logf("send ("); 957 958 if (quiet) 959 logf("??????"); 960 else 961 { 962 register char *s1 = s; 963 964 for (s1 = s; *s1; ++s1) 965 logf(character(*s1)); 966 } 967 968 logf(")\n"); 969 } 970 971 alarm(timeout); alarmed = 0; 972 973 while (*s) 974 { 975 register char c = *s++; 976 977 if (c != '\\') 978 { 979 if (!write_char (c)) 980 return 0; 981 continue; 982 } 983 984 c = *s++; 985 switch (c) 986 { 987 case 'd': 988 sleep(1); 989 break; 990 991 case 'K': 992 break_sequence(); 993 break; 994 995 case 'p': 996 usleep(10000); /* 1/100th of a second. */ 997 break; 998 999 default: 1000 if (!write_char (c)) 1001 return 0; 1002 break; 1003 } 1004 } 1005 1006 alarm(0); 1007 alarmed = 0; 1008 return (1); 1009 } 1010 1011 /* 1012 * 'Wait for' this string to appear on this file descriptor. 1013 */ 1014 int get_string(string) 1015 register char *string; 1016 { 1017 char temp[STR_LEN]; 1018 int c, printed = 0, len, minlen; 1019 register char *s = temp, *end = s + STR_LEN; 1020 1021 fail_reason = (char *)0; 1022 string = clean(string, 0); 1023 len = strlen(string); 1024 minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 1025 1026 if (verbose) 1027 { 1028 register char *s1; 1029 1030 logf("expect ("); 1031 1032 for (s1 = string; *s1; ++s1) 1033 logf(character(*s1)); 1034 1035 logf(")\n"); 1036 } 1037 1038 if (len > STR_LEN) 1039 { 1040 syslog(LOG_INFO, "expect string is too long"); 1041 return 0; 1042 } 1043 1044 if (len == 0) 1045 { 1046 if (verbose) 1047 { 1048 syslog(LOG_INFO, "got it"); 1049 } 1050 1051 return (1); 1052 } 1053 1054 alarm(timeout); alarmed = 0; 1055 1056 while ( ! alarmed && (c = get_char()) >= 0) 1057 { 1058 int n, abort_len; 1059 1060 if (verbose) 1061 { 1062 if (c == '\n') 1063 logf("\n"); 1064 else 1065 logf(character(c)); 1066 } 1067 1068 *s++ = c; 1069 1070 if (s - temp >= len && 1071 c == string[len - 1] && 1072 strncmp(s - len, string, len) == 0) 1073 { 1074 if (verbose) 1075 { 1076 logf(" -- got it\n"); 1077 } 1078 1079 alarm(0); alarmed = 0; 1080 return (1); 1081 } 1082 1083 for (n = 0; n < n_aborts; ++n) 1084 if (s - temp >= (abort_len = strlen(abort_string[n])) && 1085 strncmp(s - abort_len, abort_string[n], abort_len) == 0) 1086 { 1087 if (verbose) 1088 { 1089 logf(" -- failed\n"); 1090 } 1091 1092 alarm(0); alarmed = 0; 1093 strcpy(fail_reason = fail_buffer, abort_string[n]); 1094 return (0); 1095 } 1096 1097 if (s >= end) 1098 { 1099 strncpy(temp, s - minlen, minlen); 1100 s = temp + minlen; 1101 } 1102 1103 if (alarmed && verbose) 1104 syslog(LOG_WARNING, "warning: alarm synchronization problem"); 1105 } 1106 1107 alarm(0); 1108 1109 if (verbose && printed) 1110 { 1111 if (alarmed) 1112 logf(" -- read timed out\n"); 1113 else 1114 { 1115 logflush(); 1116 syslog(LOG_INFO, " -- read failed: %m"); 1117 } 1118 } 1119 1120 alarmed = 0; 1121 return (0); 1122 } 1123 1124 #ifdef ultrix 1125 #undef NO_USLEEP 1126 #include <sys/types.h> 1127 #include <sys/time.h> 1128 1129 /* 1130 usleep -- support routine for 4.2BSD system call emulations 1131 last edit: 29-Oct-1984 D A Gwyn 1132 */ 1133 1134 extern int select(); 1135 1136 int 1137 usleep( usec ) /* returns 0 if ok, else -1 */ 1138 long usec; /* delay in microseconds */ 1139 { 1140 static struct /* `timeval' */ 1141 { 1142 long tv_sec; /* seconds */ 1143 long tv_usec; /* microsecs */ 1144 } delay; /* _select() timeout */ 1145 1146 delay.tv_sec = usec / 1000000L; 1147 delay.tv_usec = usec % 1000000L; 1148 1149 return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 1150 } 1151 #endif 1152 1153 /* 1154 * Delay an amount appropriate for between typed characters. 1155 */ 1156 void delay() 1157 { 1158 # ifdef NO_USLEEP 1159 register int i; 1160 1161 for (i = 0; i < 30000; ++i) /* ... did we just say appropriate? */ 1162 ; 1163 # else /* NO_USLEEP */ 1164 usleep(100); 1165 # endif /* NO_USLEEP */ 1166 } 1167