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.1.1.1 1994/11/12 05:25:32 lars 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 sysfatal("Can't get terminal parameters"); 546 } 547 548 saved_tty_parameters = t; 549 have_tty_parameters = 1; 550 551 t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 552 t.c_oflag = 0; 553 t.c_lflag = 0; 554 t.c_cc[VERASE] = 555 t.c_cc[VKILL] = 0; 556 t.c_cc[VMIN] = 1; 557 t.c_cc[VTIME] = 0; 558 559 if (set_term_param (&t) < 0) 560 { 561 sysfatal("Can't set terminal parameters"); 562 } 563 #endif 564 } 565 566 void break_sequence() 567 { 568 #ifdef TERMIOS 569 tcsendbreak (0, 0); 570 #endif 571 } 572 573 void terminate(status) 574 int status; 575 { 576 if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 577 { 578 if (verbose) 579 { 580 fprintf (report_fp, "Closing \"%s\".\n", report_file); 581 } 582 fclose (report_fp); 583 report_fp = (FILE*) NULL; 584 } 585 586 #if defined(get_term_param) 587 if (have_tty_parameters) 588 { 589 if (set_term_param (&saved_tty_parameters) < 0) 590 { 591 syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 592 exit(1); 593 } 594 } 595 #endif 596 597 exit(status); 598 } 599 600 /* 601 * 'Clean up' this string. 602 */ 603 char *clean(s, sending) 604 register char *s; 605 int sending; 606 { 607 char temp[STR_LEN], cur_chr; 608 register char *s1; 609 int add_return = sending; 610 #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 611 612 s1 = temp; 613 while (*s) 614 { 615 cur_chr = *s++; 616 if (cur_chr == '^') 617 { 618 cur_chr = *s++; 619 if (cur_chr == '\0') 620 { 621 *s1++ = '^'; 622 break; 623 } 624 cur_chr &= 0x1F; 625 if (cur_chr != 0) 626 { 627 *s1++ = cur_chr; 628 } 629 continue; 630 } 631 632 if (cur_chr != '\\') 633 { 634 *s1++ = cur_chr; 635 continue; 636 } 637 638 cur_chr = *s++; 639 if (cur_chr == '\0') 640 { 641 if (sending) 642 { 643 *s1++ = '\\'; 644 *s1++ = '\\'; 645 } 646 break; 647 } 648 649 switch (cur_chr) 650 { 651 case 'b': 652 *s1++ = '\b'; 653 break; 654 655 case 'c': 656 if (sending && *s == '\0') 657 { 658 add_return = 0; 659 } 660 else 661 { 662 *s1++ = cur_chr; 663 } 664 break; 665 666 case '\\': 667 case 'K': 668 case 'p': 669 case 'd': 670 if (sending) 671 { 672 *s1++ = '\\'; 673 } 674 675 *s1++ = cur_chr; 676 break; 677 678 case 'q': 679 quiet = ! quiet; 680 break; 681 682 case 'r': 683 *s1++ = '\r'; 684 break; 685 686 case 'n': 687 *s1++ = '\n'; 688 break; 689 690 case 's': 691 *s1++ = ' '; 692 break; 693 694 case 't': 695 *s1++ = '\t'; 696 break; 697 698 case 'N': 699 if (sending) 700 { 701 *s1++ = '\\'; 702 *s1++ = '\0'; 703 } 704 else 705 { 706 *s1++ = 'N'; 707 } 708 break; 709 710 default: 711 if (isoctal (cur_chr)) 712 { 713 cur_chr &= 0x07; 714 if (isoctal (*s)) 715 { 716 cur_chr <<= 3; 717 cur_chr |= *s++ - '0'; 718 if (isoctal (*s)) 719 { 720 cur_chr <<= 3; 721 cur_chr |= *s++ - '0'; 722 } 723 } 724 725 if (cur_chr != 0 || sending) 726 { 727 if (sending && (cur_chr == '\\' || cur_chr == 0)) 728 { 729 *s1++ = '\\'; 730 } 731 *s1++ = cur_chr; 732 } 733 break; 734 } 735 736 if (sending) 737 { 738 *s1++ = '\\'; 739 } 740 *s1++ = cur_chr; 741 break; 742 } 743 } 744 745 if (add_return) 746 { 747 *s1++ = '\r'; 748 } 749 750 *s1++ = '\0'; /* guarantee closure */ 751 *s1++ = '\0'; /* terminate the string */ 752 return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 753 } 754 755 /* 756 * Process the expect string 757 */ 758 void chat_expect(s) 759 register char *s; 760 { 761 if (strcmp(s, "ABORT") == 0) 762 { 763 ++abort_next; 764 return; 765 } 766 767 if (strcmp(s, "REPORT") == 0) 768 { 769 ++report_next; 770 return; 771 } 772 773 if (strcmp(s, "TIMEOUT") == 0) 774 { 775 ++timeout_next; 776 return; 777 } 778 779 while (*s) 780 { 781 register char *hyphen; 782 783 for (hyphen = s; *hyphen; ++hyphen) 784 { 785 if (*hyphen == '-') 786 { 787 if (hyphen == s || hyphen[-1] != '\\') 788 { 789 break; 790 } 791 } 792 } 793 794 if (*hyphen == '-') 795 { 796 *hyphen = '\0'; 797 798 if (get_string(s)) 799 { 800 return; 801 } 802 else 803 { 804 s = hyphen + 1; 805 806 for (hyphen = s; *hyphen; ++hyphen) 807 { 808 if (*hyphen == '-') 809 { 810 if (hyphen == s || hyphen[-1] != '\\') 811 { 812 break; 813 } 814 } 815 } 816 817 if (*hyphen == '-') 818 { 819 *hyphen = '\0'; 820 821 chat_send(s); 822 s = hyphen + 1; 823 } 824 else 825 { 826 chat_send(s); 827 return; 828 } 829 } 830 } 831 else 832 { 833 if (get_string(s)) 834 { 835 return; 836 } 837 else 838 { 839 if (fail_reason) 840 { 841 syslog(LOG_INFO, "Failed (%s)", fail_reason); 842 } 843 else 844 { 845 syslog(LOG_INFO, "Failed"); 846 } 847 848 terminate(exit_code); 849 } 850 } 851 } 852 } 853 854 char *character(c) 855 int c; 856 { 857 static char string[10]; 858 char *meta; 859 860 meta = (c & 0x80) ? "M-" : ""; 861 c &= 0x7F; 862 863 if (c < 32) 864 { 865 sprintf(string, "%s^%c", meta, (int)c + '@'); 866 } 867 else 868 { 869 if (c == 127) 870 { 871 sprintf(string, "%s^?", meta); 872 } 873 else 874 { 875 sprintf(string, "%s%c", meta, c); 876 } 877 } 878 879 return (string); 880 } 881 882 /* 883 * process the reply string 884 */ 885 void chat_send (s) 886 register char *s; 887 { 888 if (abort_next) 889 { 890 char *s1; 891 892 abort_next = 0; 893 894 if (n_aborts >= MAX_ABORTS) 895 { 896 fatal("Too many ABORT strings"); 897 } 898 899 s1 = clean(s, 0); 900 901 if (strlen(s1) > strlen(s) 902 || strlen(s1) + 1 > sizeof(fail_buffer)) 903 { 904 syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 905 die(); 906 } 907 908 abort_string[n_aborts++] = s1; 909 910 if (verbose) 911 { 912 logf("abort on ("); 913 914 for (s1 = s; *s1; ++s1) 915 { 916 logf(character(*s1)); 917 } 918 919 logf(")\n"); 920 } 921 return; 922 } 923 924 if (report_next) 925 { 926 char *s1; 927 928 report_next = 0; 929 if (n_reports >= MAX_REPORTS) 930 { 931 fatal("Too many REPORT strings"); 932 } 933 934 s1 = clean(s, 0); 935 936 if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 937 { 938 syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 939 die(); 940 } 941 942 report_string[n_reports++] = s1; 943 944 if (verbose) 945 { 946 logf("report ("); 947 s1 = s; 948 while (*s1) 949 { 950 logf(character(*s1)); 951 ++s1; 952 } 953 logf(")\n"); 954 } 955 return; 956 } 957 958 if (timeout_next) 959 { 960 timeout_next = 0; 961 timeout = atoi(s); 962 963 if (timeout <= 0) 964 { 965 timeout = DEFAULT_CHAT_TIMEOUT; 966 } 967 968 if (verbose) 969 { 970 syslog(LOG_INFO, "timeout set to %d seconds", timeout); 971 } 972 return; 973 } 974 975 if (strcmp(s, "EOT") == 0) 976 { 977 s = "^D\\c"; 978 } 979 else 980 { 981 if (strcmp(s, "BREAK") == 0) 982 { 983 s = "\\K\\c"; 984 } 985 } 986 987 if (!put_string(s)) 988 { 989 syslog(LOG_INFO, "Failed"); 990 terminate(1); 991 } 992 } 993 994 int get_char() 995 { 996 int status; 997 char c; 998 999 status = read(0, &c, 1); 1000 1001 switch (status) 1002 { 1003 case 1: 1004 return ((int)c & 0x7F); 1005 1006 default: 1007 syslog(LOG_WARNING, "warning: read() on stdin returned %d", 1008 status); 1009 1010 case -1: 1011 if ((status = fcntl(0, F_GETFL, 0)) == -1) 1012 { 1013 sysfatal("Can't get file mode flags on stdin"); 1014 } 1015 else 1016 { 1017 if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 1018 { 1019 sysfatal("Can't set file mode flags on stdin"); 1020 } 1021 } 1022 1023 return (-1); 1024 } 1025 } 1026 1027 int put_char(c) 1028 int c; 1029 { 1030 int status; 1031 char ch = c; 1032 1033 usleep(10000); /* inter-character typing delay (?) */ 1034 1035 status = write(1, &ch, 1); 1036 1037 switch (status) 1038 { 1039 case 1: 1040 return (0); 1041 1042 default: 1043 syslog(LOG_WARNING, "warning: write() on stdout returned %d", 1044 status); 1045 1046 case -1: 1047 if ((status = fcntl(0, F_GETFL, 0)) == -1) 1048 { 1049 sysfatal("Can't get file mode flags on stdin"); 1050 } 1051 else 1052 { 1053 if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 1054 { 1055 sysfatal("Can't set file mode flags on stdin"); 1056 } 1057 } 1058 1059 return (-1); 1060 } 1061 } 1062 1063 int write_char (c) 1064 int c; 1065 { 1066 if (alarmed || put_char(c) < 0) 1067 { 1068 extern int errno; 1069 1070 alarm(0); 1071 alarmed = 0; 1072 1073 if (verbose) 1074 { 1075 if (errno == EINTR || errno == EWOULDBLOCK) 1076 { 1077 syslog(LOG_INFO, " -- write timed out"); 1078 } 1079 else 1080 { 1081 syslog(LOG_INFO, " -- write failed: %m"); 1082 } 1083 } 1084 return (0); 1085 } 1086 return (1); 1087 } 1088 1089 int put_string (s) 1090 register char *s; 1091 { 1092 s = clean(s, 1); 1093 1094 if (verbose) 1095 { 1096 logf("send ("); 1097 1098 if (quiet) 1099 { 1100 logf("??????"); 1101 } 1102 else 1103 { 1104 register char *s1 = s; 1105 1106 for (s1 = s; *s1; ++s1) 1107 { 1108 logf(character(*s1)); 1109 } 1110 } 1111 1112 logf(")\n"); 1113 } 1114 1115 alarm(timeout); alarmed = 0; 1116 1117 while (*s) 1118 { 1119 register char c = *s++; 1120 1121 if (c != '\\') 1122 { 1123 if (!write_char (c)) 1124 { 1125 return 0; 1126 } 1127 continue; 1128 } 1129 1130 c = *s++; 1131 switch (c) 1132 { 1133 case 'd': 1134 sleep(1); 1135 break; 1136 1137 case 'K': 1138 break_sequence(); 1139 break; 1140 1141 case 'p': 1142 usleep(10000); /* 1/100th of a second (arg is microseconds) */ 1143 break; 1144 1145 default: 1146 if (!write_char (c)) 1147 return 0; 1148 break; 1149 } 1150 } 1151 1152 alarm(0); 1153 alarmed = 0; 1154 return (1); 1155 } 1156 1157 /* 1158 * 'Wait for' this string to appear on this file descriptor. 1159 */ 1160 int get_string(string) 1161 register char *string; 1162 { 1163 char temp[STR_LEN]; 1164 int c, printed = 0, len, minlen; 1165 register char *s = temp, *end = s + STR_LEN; 1166 1167 fail_reason = (char *)0; 1168 string = clean(string, 0); 1169 len = strlen(string); 1170 minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 1171 1172 if (verbose) 1173 { 1174 register char *s1; 1175 1176 logf("expect ("); 1177 1178 for (s1 = string; *s1; ++s1) 1179 { 1180 logf(character(*s1)); 1181 } 1182 1183 logf(")\n"); 1184 } 1185 1186 if (len > STR_LEN) 1187 { 1188 syslog(LOG_INFO, "expect string is too long"); 1189 exit_code = 1; 1190 return 0; 1191 } 1192 1193 if (len == 0) 1194 { 1195 if (verbose) 1196 { 1197 syslog(LOG_INFO, "got it"); 1198 } 1199 1200 return (1); 1201 } 1202 1203 alarm(timeout); 1204 alarmed = 0; 1205 1206 while ( ! alarmed && (c = get_char()) >= 0) 1207 { 1208 int n, abort_len, report_len; 1209 1210 if (verbose) 1211 { 1212 if (c == '\n') 1213 { 1214 logf("\n"); 1215 } 1216 else 1217 { 1218 logf(character(c)); 1219 } 1220 } 1221 1222 *s++ = c; 1223 1224 if (s - temp >= len && 1225 c == string[len - 1] && 1226 strncmp(s - len, string, len) == 0) 1227 { 1228 if (verbose) 1229 { 1230 logf(" -- got it\n"); 1231 } 1232 1233 alarm(0); 1234 alarmed = 0; 1235 return (1); 1236 } 1237 1238 for (n = 0; n < n_aborts; ++n) 1239 { 1240 if (s - temp >= (abort_len = strlen(abort_string[n])) && 1241 strncmp(s - abort_len, abort_string[n], abort_len) == 0) 1242 { 1243 if (verbose) 1244 { 1245 logf(" -- failed\n"); 1246 } 1247 1248 alarm(0); 1249 alarmed = 0; 1250 exit_code = n + 4; 1251 strcpy(fail_reason = fail_buffer, abort_string[n]); 1252 return (0); 1253 } 1254 } 1255 1256 if (!report_gathering) 1257 { 1258 for (n = 0; n < n_reports; ++n) 1259 { 1260 if ((report_string[n] != (char*) NULL) && 1261 s - temp >= (report_len = strlen(report_string[n])) && 1262 strncmp(s - report_len, report_string[n], report_len) == 0) 1263 { 1264 time_t time_now = time ((time_t*) NULL); 1265 struct tm* tm_now = localtime (&time_now); 1266 1267 strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 1268 strcat (report_buffer, report_string[n]); 1269 1270 report_string[n] = (char *) NULL; 1271 report_gathering = 1; 1272 break; 1273 } 1274 } 1275 } 1276 else 1277 { 1278 if (!iscntrl (c)) 1279 { 1280 int rep_len = strlen (report_buffer); 1281 report_buffer[rep_len] = c; 1282 report_buffer[rep_len + 1] = '\0'; 1283 } 1284 else 1285 { 1286 report_gathering = 0; 1287 fprintf (report_fp, "chat: %s\n", report_buffer); 1288 } 1289 } 1290 1291 if (s >= end) 1292 { 1293 strncpy (temp, s - minlen, minlen); 1294 s = temp + minlen; 1295 } 1296 1297 if (alarmed && verbose) 1298 { 1299 syslog(LOG_WARNING, "warning: alarm synchronization problem"); 1300 } 1301 } 1302 1303 alarm(0); 1304 1305 if (verbose && printed) 1306 { 1307 if (alarmed) 1308 { 1309 logf(" -- read timed out\n"); 1310 } 1311 else 1312 { 1313 logflush(); 1314 syslog(LOG_INFO, " -- read failed: %m"); 1315 } 1316 } 1317 1318 exit_code = 3; 1319 alarmed = 0; 1320 return (0); 1321 } 1322 1323 #ifdef NO_USLEEP 1324 #include <sys/types.h> 1325 #include <sys/time.h> 1326 1327 /* 1328 usleep -- support routine for 4.2BSD system call emulations 1329 last edit: 29-Oct-1984 D A Gwyn 1330 */ 1331 1332 extern int select(); 1333 1334 int 1335 usleep( usec ) /* returns 0 if ok, else -1 */ 1336 long usec; /* delay in microseconds */ 1337 { 1338 static struct /* `timeval' */ 1339 { 1340 long tv_sec; /* seconds */ 1341 long tv_usec; /* microsecs */ 1342 } delay; /* _select() timeout */ 1343 1344 delay.tv_sec = usec / 1000000L; 1345 delay.tv_usec = usec % 1000000L; 1346 1347 return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 1348 } 1349 #endif 1350