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