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