19b1aec48SLars Fredriksen /* 29b1aec48SLars Fredriksen * Chat -- a program for automatic session establishment (i.e. dial 39b1aec48SLars Fredriksen * the phone and log in). 49b1aec48SLars Fredriksen * 59f65f104SPeter Wemm * Standard termination codes: 69f65f104SPeter Wemm * 0 - successful completion of the script 79f65f104SPeter Wemm * 1 - invalid argument, expect string too large, etc. 801c855caSPeter Wemm * 2 - error on an I/O operation or fatal error condition. 99f65f104SPeter Wemm * 3 - timeout waiting for a simple string. 109f65f104SPeter Wemm * 4 - the first string declared as "ABORT" 119f65f104SPeter Wemm * 5 - the second string declared as "ABORT" 129f65f104SPeter Wemm * 6 - ... and so on for successive ABORT strings. 139f65f104SPeter Wemm * 149b1aec48SLars Fredriksen * This software is in the public domain. 159b1aec48SLars Fredriksen * 163d793cf1SPeter Wemm * ----------------- 1701c855caSPeter Wemm * added -T and -U option and \T and \U substitution to pass a phone 1801c855caSPeter Wemm * number into chat script. Two are needed for some ISDN TA applications. 1901c855caSPeter Wemm * Keith Dart <kdart@cisco.com> 2001c855caSPeter Wemm * 219b1aec48SLars Fredriksen * 223d793cf1SPeter Wemm * Added SAY keyword to send output to stderr. 233d793cf1SPeter Wemm * This allows to turn ECHO OFF and to output specific, user selected, 243d793cf1SPeter Wemm * text to give progress messages. This best works when stderr 253d793cf1SPeter Wemm * exists (i.e.: pppd in nodetach mode). 263d793cf1SPeter Wemm * 273d793cf1SPeter Wemm * Added HANGUP directives to allow for us to be called 283d793cf1SPeter Wemm * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 293d793cf1SPeter Wemm * We rely on timeouts in that case. 303d793cf1SPeter Wemm * 313d793cf1SPeter Wemm * Added CLR_ABORT to clear previously set ABORT string. This has been 323d793cf1SPeter Wemm * dictated by the HANGUP above as "NO CARRIER" (for example) must be 333d793cf1SPeter Wemm * an ABORT condition until we know the other host is going to close 343d793cf1SPeter Wemm * the connection for call back. As soon as we have completed the 353d793cf1SPeter Wemm * first stage of the call back sequence, "NO CARRIER" is a valid, non 363d793cf1SPeter Wemm * fatal string. As soon as we got called back (probably get "CONNECT"), 373d793cf1SPeter Wemm * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 383d793cf1SPeter Wemm * Note that CLR_ABORT packs the abort_strings[] array so that we do not 393d793cf1SPeter Wemm * have unused entries not being reclaimed. 403d793cf1SPeter Wemm * 413d793cf1SPeter Wemm * In the same vein as above, added CLR_REPORT keyword. 423d793cf1SPeter Wemm * 433d793cf1SPeter Wemm * Allow for comments. Line starting with '#' are comments and are 443d793cf1SPeter Wemm * ignored. If a '#' is to be expected as the first character, the 453d793cf1SPeter Wemm * expect string must be quoted. 463d793cf1SPeter Wemm * 473d793cf1SPeter Wemm * 483d793cf1SPeter Wemm * Francis Demierre <Francis@SwissMail.Com> 493d793cf1SPeter Wemm * Thu May 15 17:15:40 MET DST 1997 503d793cf1SPeter Wemm * 519b1aec48SLars Fredriksen * 529f65f104SPeter Wemm * Added -r "report file" switch & REPORT keyword. 539f65f104SPeter Wemm * Robert Geer <bgeer@xmission.com> 549f65f104SPeter Wemm * 5501c855caSPeter Wemm * Added -s "use stderr" and -S "don't use syslog" switches. 5601c855caSPeter Wemm * June 18, 1997 5701c855caSPeter Wemm * Karl O. Pinc <kop@meme.com> 5801c855caSPeter Wemm * 593d793cf1SPeter Wemm * 603d793cf1SPeter Wemm * Added -e "echo" switch & ECHO keyword 613d793cf1SPeter Wemm * Dick Streefland <dicks@tasking.nl> 623d793cf1SPeter Wemm * 633d793cf1SPeter Wemm * 643d793cf1SPeter Wemm * Considerable updates and modifications by 653d793cf1SPeter Wemm * Al Longyear <longyear@pobox.com> 663d793cf1SPeter Wemm * Paul Mackerras <paulus@cs.anu.edu.au> 673d793cf1SPeter Wemm * 683d793cf1SPeter Wemm * 699b1aec48SLars Fredriksen * The original author is: 709b1aec48SLars Fredriksen * 719b1aec48SLars Fredriksen * Karl Fox <karl@MorningStar.Com> 729b1aec48SLars Fredriksen * Morning Star Technologies, Inc. 739b1aec48SLars Fredriksen * 1760 Zollinger Road 749b1aec48SLars Fredriksen * Columbus, OH 43221 759b1aec48SLars Fredriksen * (614)451-1883 769f65f104SPeter Wemm * 773d793cf1SPeter Wemm * 789b1aec48SLars Fredriksen */ 799b1aec48SLars Fredriksen 803d793cf1SPeter Wemm #ifndef lint 81fa146c53SArchie Cobbs static const char rcsid[] = 82c3aac50fSPeter Wemm "$FreeBSD$"; 833d793cf1SPeter Wemm #endif 849b1aec48SLars Fredriksen 859b1aec48SLars Fredriksen #include <stdio.h> 863d793cf1SPeter Wemm #include <ctype.h> 879f65f104SPeter Wemm #include <time.h> 889b1aec48SLars Fredriksen #include <fcntl.h> 899b1aec48SLars Fredriksen #include <signal.h> 909b1aec48SLars Fredriksen #include <errno.h> 919b1aec48SLars Fredriksen #include <string.h> 929b1aec48SLars Fredriksen #include <stdlib.h> 933d793cf1SPeter Wemm #include <unistd.h> 949b1aec48SLars Fredriksen #include <sys/types.h> 959b1aec48SLars Fredriksen #include <sys/stat.h> 969b1aec48SLars Fredriksen #include <syslog.h> 979b1aec48SLars Fredriksen 989b1aec48SLars Fredriksen #ifndef TERMIO 999b1aec48SLars Fredriksen #undef TERMIOS 1009b1aec48SLars Fredriksen #define TERMIOS 1019b1aec48SLars Fredriksen #endif 1029b1aec48SLars Fredriksen 1039b1aec48SLars Fredriksen #ifdef TERMIO 1049b1aec48SLars Fredriksen #include <termio.h> 1059b1aec48SLars Fredriksen #endif 1069b1aec48SLars Fredriksen #ifdef TERMIOS 1079b1aec48SLars Fredriksen #include <termios.h> 1089b1aec48SLars Fredriksen #endif 1099b1aec48SLars Fredriksen 1109b1aec48SLars Fredriksen #define STR_LEN 1024 1119b1aec48SLars Fredriksen 1129b1aec48SLars Fredriksen #ifndef SIGTYPE 1139b1aec48SLars Fredriksen #define SIGTYPE void 1149b1aec48SLars Fredriksen #endif 1159b1aec48SLars Fredriksen 1169b1aec48SLars Fredriksen #undef __P 11701c855caSPeter Wemm #undef __V 11801c855caSPeter Wemm 11901c855caSPeter Wemm #ifdef __STDC__ 12001c855caSPeter Wemm #include <stdarg.h> 12101c855caSPeter Wemm #define __V(x) x 1229b1aec48SLars Fredriksen #define __P(x) x 1239b1aec48SLars Fredriksen #else 12401c855caSPeter Wemm #include <varargs.h> 12501c855caSPeter Wemm #define __V(x) (va_alist) va_dcl 1269b1aec48SLars Fredriksen #define __P(x) () 1279b1aec48SLars Fredriksen #define const 1289b1aec48SLars Fredriksen #endif 1299b1aec48SLars Fredriksen 1309f65f104SPeter Wemm #ifndef O_NONBLOCK 1319f65f104SPeter Wemm #define O_NONBLOCK O_NDELAY 1329f65f104SPeter Wemm #endif 1339f65f104SPeter Wemm 13401c855caSPeter Wemm #ifdef SUNOS 13501c855caSPeter Wemm extern int sys_nerr; 13601c855caSPeter Wemm extern char *sys_errlist[]; 13701c855caSPeter Wemm #define memmove(to, from, n) bcopy(from, to, n) 13801c855caSPeter Wemm #define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 13901c855caSPeter Wemm "unknown error") 14001c855caSPeter Wemm #endif 14101c855caSPeter Wemm 1429b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1439b1aec48SLars Fredriksen #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1449b1aec48SLars Fredriksen (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1459b1aec48SLars Fredriksen &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1469b1aec48SLars Fredriksen #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1479b1aec48SLars Fredriksen (_O=4,(char*)0):(char*)0) 1489b1aec48SLars Fredriksen #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1499b1aec48SLars Fredriksen #define ARG(c,v) (c?(--c,*v++):(char*)0) 1509b1aec48SLars Fredriksen 1519b1aec48SLars Fredriksen static int _O = 0; /* Internal state */ 1529b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1539b1aec48SLars Fredriksen 1549b1aec48SLars Fredriksen #define MAX_ABORTS 50 1559f65f104SPeter Wemm #define MAX_REPORTS 50 1569b1aec48SLars Fredriksen #define DEFAULT_CHAT_TIMEOUT 45 1579b1aec48SLars Fredriksen 1583d793cf1SPeter Wemm int echo = 0; 1599b1aec48SLars Fredriksen int verbose = 0; 16001c855caSPeter Wemm int to_log = 1; 16101c855caSPeter Wemm int to_stderr = 0; 1623d793cf1SPeter Wemm int Verbose = 0; 1639b1aec48SLars Fredriksen int quiet = 0; 1649f65f104SPeter Wemm int report = 0; 1659f65f104SPeter Wemm int exit_code = 0; 1669f65f104SPeter Wemm FILE* report_fp = (FILE *) 0; 1679f65f104SPeter Wemm char *report_file = (char *) 0; 1689b1aec48SLars Fredriksen char *chat_file = (char *) 0; 16901c855caSPeter Wemm char *phone_num = (char *) 0; 17001c855caSPeter Wemm char *phone_num2 = (char *) 0; 1719b1aec48SLars Fredriksen int timeout = DEFAULT_CHAT_TIMEOUT; 1729b1aec48SLars Fredriksen 1739b1aec48SLars Fredriksen int have_tty_parameters = 0; 1749f65f104SPeter Wemm 1759b1aec48SLars Fredriksen #ifdef TERMIO 1769f65f104SPeter Wemm #define term_parms struct termio 1779f65f104SPeter Wemm #define get_term_param(param) ioctl(0, TCGETA, param) 1789f65f104SPeter Wemm #define set_term_param(param) ioctl(0, TCSETA, param) 1799b1aec48SLars Fredriksen struct termio saved_tty_parameters; 1809b1aec48SLars Fredriksen #endif 1819f65f104SPeter Wemm 1829b1aec48SLars Fredriksen #ifdef TERMIOS 1839f65f104SPeter Wemm #define term_parms struct termios 1849f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param) 1859f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param) 1869b1aec48SLars Fredriksen struct termios saved_tty_parameters; 1879b1aec48SLars Fredriksen #endif 1889b1aec48SLars Fredriksen 1899b1aec48SLars Fredriksen char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1909b1aec48SLars Fredriksen fail_buffer[50]; 1913d793cf1SPeter Wemm int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 1923d793cf1SPeter Wemm int clear_abort_next = 0; 1939b1aec48SLars Fredriksen 1949f65f104SPeter Wemm char *report_string[MAX_REPORTS] ; 1959f65f104SPeter Wemm char report_buffer[50] ; 1969f65f104SPeter Wemm int n_reports = 0, report_next = 0, report_gathering = 0 ; 1973d793cf1SPeter Wemm int clear_report_next = 0; 1983d793cf1SPeter Wemm 1993d793cf1SPeter Wemm int say_next = 0, hup_next = 0; 2009f65f104SPeter Wemm 2019b1aec48SLars Fredriksen void *dup_mem __P((void *b, size_t c)); 2029b1aec48SLars Fredriksen void *copy_of __P((char *s)); 203afaeb553SPhilippe Charnier static void usage __P((void)); 20401c855caSPeter Wemm void logf __P((const char *fmt, ...)); 20501c855caSPeter Wemm void fatal __P((int code, const char *fmt, ...)); 2069b1aec48SLars Fredriksen SIGTYPE sigalrm __P((int signo)); 2079b1aec48SLars Fredriksen SIGTYPE sigint __P((int signo)); 2089b1aec48SLars Fredriksen SIGTYPE sigterm __P((int signo)); 2099b1aec48SLars Fredriksen SIGTYPE sighup __P((int signo)); 2109b1aec48SLars Fredriksen void unalarm __P((void)); 2119b1aec48SLars Fredriksen void init __P((void)); 2129b1aec48SLars Fredriksen void set_tty_parameters __P((void)); 2133d793cf1SPeter Wemm void echo_stderr __P((int)); 2149b1aec48SLars Fredriksen void break_sequence __P((void)); 2159b1aec48SLars Fredriksen void terminate __P((int status)); 2169b1aec48SLars Fredriksen void do_file __P((char *chat_file)); 2179b1aec48SLars Fredriksen int get_string __P((register char *string)); 2189b1aec48SLars Fredriksen int put_string __P((register char *s)); 2199b1aec48SLars Fredriksen int write_char __P((int c)); 2209f65f104SPeter Wemm int put_char __P((int c)); 2219b1aec48SLars Fredriksen int get_char __P((void)); 2229b1aec48SLars Fredriksen void chat_send __P((register char *s)); 2239f65f104SPeter Wemm char *character __P((int c)); 2249b1aec48SLars Fredriksen void chat_expect __P((register char *s)); 2259b1aec48SLars Fredriksen char *clean __P((register char *s, int sending)); 2269b1aec48SLars Fredriksen void break_sequence __P((void)); 2279b1aec48SLars Fredriksen void terminate __P((int status)); 2283d793cf1SPeter Wemm void pack_array __P((char **array, int end)); 2293d793cf1SPeter Wemm char *expect_strtok __P((char *, char *)); 23001c855caSPeter Wemm int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */ 2313d793cf1SPeter Wemm 2323d793cf1SPeter Wemm int main __P((int, char *[])); 2339b1aec48SLars Fredriksen 2349b1aec48SLars Fredriksen void *dup_mem(b, c) 2359b1aec48SLars Fredriksen void *b; 2369b1aec48SLars Fredriksen size_t c; 2379b1aec48SLars Fredriksen { 2389b1aec48SLars Fredriksen void *ans = malloc (c); 2399b1aec48SLars Fredriksen if (!ans) 24001c855caSPeter Wemm fatal(2, "memory error!"); 24101c855caSPeter Wemm 2429b1aec48SLars Fredriksen memcpy (ans, b, c); 2439b1aec48SLars Fredriksen return ans; 2449b1aec48SLars Fredriksen } 2459b1aec48SLars Fredriksen 2469b1aec48SLars Fredriksen void *copy_of (s) 2479b1aec48SLars Fredriksen char *s; 2489b1aec48SLars Fredriksen { 2499b1aec48SLars Fredriksen return dup_mem (s, strlen (s) + 1); 2509b1aec48SLars Fredriksen } 2519b1aec48SLars Fredriksen 2529b1aec48SLars Fredriksen /* 25301c855caSPeter Wemm * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ 25401c855caSPeter Wemm * [ -r report-file ] \ 2559b1aec48SLars Fredriksen * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2569b1aec48SLars Fredriksen * 2579b1aec48SLars Fredriksen * Perform a UUCP-dialer-like chat script on stdin and stdout. 2589b1aec48SLars Fredriksen */ 2599b1aec48SLars Fredriksen int 2609b1aec48SLars Fredriksen main(argc, argv) 2619b1aec48SLars Fredriksen int argc; 2629b1aec48SLars Fredriksen char **argv; 2639b1aec48SLars Fredriksen { 2649b1aec48SLars Fredriksen int option; 2659b1aec48SLars Fredriksen char *arg; 2669b1aec48SLars Fredriksen 2679f65f104SPeter Wemm tzset(); 2689b1aec48SLars Fredriksen 26901c855caSPeter Wemm while ((option = OPTION(argc, argv)) != 0) { 27001c855caSPeter Wemm switch (option) { 2713d793cf1SPeter Wemm case 'e': 2723d793cf1SPeter Wemm ++echo; 2733d793cf1SPeter Wemm break; 2743d793cf1SPeter Wemm 2759b1aec48SLars Fredriksen case 'v': 2769b1aec48SLars Fredriksen ++verbose; 2779b1aec48SLars Fredriksen break; 2789b1aec48SLars Fredriksen 2793d793cf1SPeter Wemm case 'V': 2803d793cf1SPeter Wemm ++Verbose; 2813d793cf1SPeter Wemm break; 2823d793cf1SPeter Wemm 28301c855caSPeter Wemm case 's': 28401c855caSPeter Wemm ++to_stderr; 28501c855caSPeter Wemm break; 28601c855caSPeter Wemm 28701c855caSPeter Wemm case 'S': 28801c855caSPeter Wemm to_log = 0; 28901c855caSPeter Wemm break; 29001c855caSPeter Wemm 2919b1aec48SLars Fredriksen case 'f': 2923d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 2939b1aec48SLars Fredriksen chat_file = copy_of(arg); 2949b1aec48SLars Fredriksen else 2959b1aec48SLars Fredriksen usage(); 2969b1aec48SLars Fredriksen break; 2979b1aec48SLars Fredriksen 2989b1aec48SLars Fredriksen case 't': 2993d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 3009b1aec48SLars Fredriksen timeout = atoi(arg); 3019b1aec48SLars Fredriksen else 3029b1aec48SLars Fredriksen usage(); 3039f65f104SPeter Wemm break; 3049b1aec48SLars Fredriksen 3059f65f104SPeter Wemm case 'r': 3069f65f104SPeter Wemm arg = OPTARG (argc, argv); 30701c855caSPeter Wemm if (arg) { 3089f65f104SPeter Wemm if (report_fp != NULL) 3099f65f104SPeter Wemm fclose (report_fp); 3109f65f104SPeter Wemm report_file = copy_of (arg); 3119f65f104SPeter Wemm report_fp = fopen (report_file, "a"); 31201c855caSPeter Wemm if (report_fp != NULL) { 3139f65f104SPeter Wemm if (verbose) 3149f65f104SPeter Wemm fprintf (report_fp, "Opening \"%s\"...\n", 3159f65f104SPeter Wemm report_file); 3169f65f104SPeter Wemm report = 1; 3179f65f104SPeter Wemm } 3189f65f104SPeter Wemm } 3199b1aec48SLars Fredriksen break; 3209b1aec48SLars Fredriksen 32101c855caSPeter Wemm case 'T': 32201c855caSPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 32301c855caSPeter Wemm phone_num = copy_of(arg); 32401c855caSPeter Wemm else 32501c855caSPeter Wemm usage(); 32601c855caSPeter Wemm break; 32701c855caSPeter Wemm 32801c855caSPeter Wemm case 'U': 32901c855caSPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 33001c855caSPeter Wemm phone_num2 = copy_of(arg); 33101c855caSPeter Wemm else 33201c855caSPeter Wemm usage(); 33301c855caSPeter Wemm break; 33401c855caSPeter Wemm 3359b1aec48SLars Fredriksen default: 3369b1aec48SLars Fredriksen usage(); 3379f65f104SPeter Wemm break; 3389f65f104SPeter Wemm } 3399f65f104SPeter Wemm } 3409f65f104SPeter Wemm /* 3419f65f104SPeter Wemm * Default the report file to the stderr location 3429f65f104SPeter Wemm */ 3439f65f104SPeter Wemm if (report_fp == NULL) 3449f65f104SPeter Wemm report_fp = stderr; 3459b1aec48SLars Fredriksen 34601c855caSPeter Wemm if (to_log) { 3479b1aec48SLars Fredriksen #ifdef ultrix 3489b1aec48SLars Fredriksen openlog("chat", LOG_PID); 3499b1aec48SLars Fredriksen #else 3509b1aec48SLars Fredriksen openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3519b1aec48SLars Fredriksen 3529f65f104SPeter Wemm if (verbose) 3539b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_INFO)); 3549f65f104SPeter Wemm else 3559b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_WARNING)); 3569b1aec48SLars Fredriksen #endif 35701c855caSPeter Wemm } 3589b1aec48SLars Fredriksen 3599b1aec48SLars Fredriksen init(); 3609b1aec48SLars Fredriksen 36101c855caSPeter Wemm if (chat_file != NULL) { 3629b1aec48SLars Fredriksen arg = ARG(argc, argv); 3639b1aec48SLars Fredriksen if (arg != NULL) 3649b1aec48SLars Fredriksen usage(); 3659b1aec48SLars Fredriksen else 3669b1aec48SLars Fredriksen do_file (chat_file); 36701c855caSPeter Wemm } else { 36801c855caSPeter Wemm while ((arg = ARG(argc, argv)) != NULL) { 3699b1aec48SLars Fredriksen chat_expect(arg); 3709b1aec48SLars Fredriksen 3713d793cf1SPeter Wemm if ((arg = ARG(argc, argv)) != NULL) 3729b1aec48SLars Fredriksen chat_send(arg); 3739b1aec48SLars Fredriksen } 3749b1aec48SLars Fredriksen } 3759b1aec48SLars Fredriksen 3769b1aec48SLars Fredriksen terminate(0); 3773d793cf1SPeter Wemm return 0; 3789b1aec48SLars Fredriksen } 3799b1aec48SLars Fredriksen 3809b1aec48SLars Fredriksen /* 3819b1aec48SLars Fredriksen * Process a chat script when read from a file. 3829b1aec48SLars Fredriksen */ 3839b1aec48SLars Fredriksen 3849b1aec48SLars Fredriksen void do_file (chat_file) 3859b1aec48SLars Fredriksen char *chat_file; 3869b1aec48SLars Fredriksen { 387d7d10053SAlexander Langer int linect, sendflg; 3889b1aec48SLars Fredriksen char *sp, *arg, quote; 3899b1aec48SLars Fredriksen char buf [STR_LEN]; 3909b1aec48SLars Fredriksen FILE *cfp; 3919b1aec48SLars Fredriksen 3929f65f104SPeter Wemm cfp = fopen (chat_file, "r"); 3939f65f104SPeter Wemm if (cfp == NULL) 39401c855caSPeter Wemm fatal(1, "%s -- open failed: %m", chat_file); 3959b1aec48SLars Fredriksen 3969b1aec48SLars Fredriksen linect = 0; 3979b1aec48SLars Fredriksen sendflg = 0; 3989b1aec48SLars Fredriksen 39901c855caSPeter Wemm while (fgets(buf, STR_LEN, cfp) != NULL) { 4009b1aec48SLars Fredriksen sp = strchr (buf, '\n'); 4019b1aec48SLars Fredriksen if (sp) 4029b1aec48SLars Fredriksen *sp = '\0'; 4039b1aec48SLars Fredriksen 4049b1aec48SLars Fredriksen linect++; 4059b1aec48SLars Fredriksen sp = buf; 4063d793cf1SPeter Wemm 4073d793cf1SPeter Wemm /* lines starting with '#' are comments. If a real '#' 4083d793cf1SPeter Wemm is to be expected, it should be quoted .... */ 40901c855caSPeter Wemm if ( *sp == '#' ) 41001c855caSPeter Wemm continue; 4113d793cf1SPeter Wemm 41201c855caSPeter Wemm while (*sp != '\0') { 41301c855caSPeter Wemm if (*sp == ' ' || *sp == '\t') { 4149b1aec48SLars Fredriksen ++sp; 4159b1aec48SLars Fredriksen continue; 4169b1aec48SLars Fredriksen } 4179b1aec48SLars Fredriksen 41801c855caSPeter Wemm if (*sp == '"' || *sp == '\'') { 4199b1aec48SLars Fredriksen quote = *sp++; 4209b1aec48SLars Fredriksen arg = sp; 42101c855caSPeter Wemm while (*sp != quote) { 4229b1aec48SLars Fredriksen if (*sp == '\0') 42301c855caSPeter Wemm fatal(1, "unterminated quote (line %d)", linect); 4249b1aec48SLars Fredriksen 42501c855caSPeter Wemm if (*sp++ == '\\') { 4269b1aec48SLars Fredriksen if (*sp != '\0') 4279b1aec48SLars Fredriksen ++sp; 4289b1aec48SLars Fredriksen } 4299b1aec48SLars Fredriksen } 4309f65f104SPeter Wemm } 43101c855caSPeter Wemm else { 4329b1aec48SLars Fredriksen arg = sp; 4339b1aec48SLars Fredriksen while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4349b1aec48SLars Fredriksen ++sp; 4359b1aec48SLars Fredriksen } 4369b1aec48SLars Fredriksen 4379b1aec48SLars Fredriksen if (*sp != '\0') 4389b1aec48SLars Fredriksen *sp++ = '\0'; 4399b1aec48SLars Fredriksen 4409b1aec48SLars Fredriksen if (sendflg) 4419b1aec48SLars Fredriksen chat_send (arg); 4429b1aec48SLars Fredriksen else 4439b1aec48SLars Fredriksen chat_expect (arg); 4449b1aec48SLars Fredriksen sendflg = !sendflg; 4459b1aec48SLars Fredriksen } 4469b1aec48SLars Fredriksen } 4479b1aec48SLars Fredriksen fclose (cfp); 4489b1aec48SLars Fredriksen } 4499b1aec48SLars Fredriksen 4509b1aec48SLars Fredriksen /* 4519b1aec48SLars Fredriksen * We got an error parsing the command line. 4529b1aec48SLars Fredriksen */ 453afaeb553SPhilippe Charnier static void 454afaeb553SPhilippe Charnier usage() 4559b1aec48SLars Fredriksen { 45601c855caSPeter Wemm fprintf(stderr, "\ 45701c855caSPeter Wemm Usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\ 45801c855caSPeter Wemm [-U phone-number2] {-f chat-file | chat-script}\n"); 4599b1aec48SLars Fredriksen exit(1); 4609b1aec48SLars Fredriksen } 4619b1aec48SLars Fredriksen 46201c855caSPeter Wemm char line[1024]; 4639b1aec48SLars Fredriksen 4649b1aec48SLars Fredriksen /* 46501c855caSPeter Wemm * Send a message to syslog and/or stderr. 4669b1aec48SLars Fredriksen */ 46701c855caSPeter Wemm void logf __V((const char *fmt, ...)) 4689b1aec48SLars Fredriksen { 46901c855caSPeter Wemm va_list args; 47001c855caSPeter Wemm 47101c855caSPeter Wemm #ifdef __STDC__ 47201c855caSPeter Wemm va_start(args, fmt); 47301c855caSPeter Wemm #else 47401c855caSPeter Wemm char *fmt; 47501c855caSPeter Wemm va_start(args); 47601c855caSPeter Wemm fmt = va_arg(args, char *); 47701c855caSPeter Wemm #endif 47801c855caSPeter Wemm 47901c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 48001c855caSPeter Wemm if (to_log) 48101c855caSPeter Wemm syslog(LOG_INFO, "%s", line); 48201c855caSPeter Wemm if (to_stderr) 48301c855caSPeter Wemm fprintf(stderr, "%s\n", line); 4849b1aec48SLars Fredriksen } 4859b1aec48SLars Fredriksen 4869b1aec48SLars Fredriksen /* 4879b1aec48SLars Fredriksen * Print an error message and terminate. 4889b1aec48SLars Fredriksen */ 4899b1aec48SLars Fredriksen 49001c855caSPeter Wemm void fatal __V((int code, const char *fmt, ...)) 4919b1aec48SLars Fredriksen { 49201c855caSPeter Wemm va_list args; 4939b1aec48SLars Fredriksen 49401c855caSPeter Wemm #ifdef __STDC__ 49501c855caSPeter Wemm va_start(args, fmt); 49601c855caSPeter Wemm #else 49701c855caSPeter Wemm int code; 49801c855caSPeter Wemm char *fmt; 49901c855caSPeter Wemm va_start(args); 50001c855caSPeter Wemm code = va_arg(args, int); 50101c855caSPeter Wemm fmt = va_arg(args, char *); 50201c855caSPeter Wemm #endif 5039b1aec48SLars Fredriksen 50401c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 50501c855caSPeter Wemm if (to_log) 50601c855caSPeter Wemm syslog(LOG_ERR, "%s", line); 50701c855caSPeter Wemm if (to_stderr) 50801c855caSPeter Wemm fprintf(stderr, "%s\n", line); 50901c855caSPeter Wemm terminate(code); 5109b1aec48SLars Fredriksen } 5119b1aec48SLars Fredriksen 5129b1aec48SLars Fredriksen int alarmed = 0; 5139b1aec48SLars Fredriksen 5149b1aec48SLars Fredriksen SIGTYPE sigalrm(signo) 5159b1aec48SLars Fredriksen int signo; 5169b1aec48SLars Fredriksen { 5179b1aec48SLars Fredriksen int flags; 5189b1aec48SLars Fredriksen 5199b1aec48SLars Fredriksen alarm(1); 5209b1aec48SLars Fredriksen alarmed = 1; /* Reset alarm to avoid race window */ 5219b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 5229b1aec48SLars Fredriksen 5239b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 52401c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 52501c855caSPeter Wemm 5269f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 52701c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 5289b1aec48SLars Fredriksen 5299b1aec48SLars Fredriksen if (verbose) 53001c855caSPeter Wemm logf("alarm"); 5319b1aec48SLars Fredriksen } 5329b1aec48SLars Fredriksen 5339b1aec48SLars Fredriksen void unalarm() 5349b1aec48SLars Fredriksen { 5359b1aec48SLars Fredriksen int flags; 5369b1aec48SLars Fredriksen 5379b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 53801c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 53901c855caSPeter Wemm 5409f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 54101c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 5429f65f104SPeter Wemm } 5439b1aec48SLars Fredriksen 5449b1aec48SLars Fredriksen SIGTYPE sigint(signo) 5459b1aec48SLars Fredriksen int signo; 5469b1aec48SLars Fredriksen { 54701c855caSPeter Wemm fatal(2, "SIGINT"); 5489b1aec48SLars Fredriksen } 5499b1aec48SLars Fredriksen 5509b1aec48SLars Fredriksen SIGTYPE sigterm(signo) 5519b1aec48SLars Fredriksen int signo; 5529b1aec48SLars Fredriksen { 55301c855caSPeter Wemm fatal(2, "SIGTERM"); 5549b1aec48SLars Fredriksen } 5559b1aec48SLars Fredriksen 5569b1aec48SLars Fredriksen SIGTYPE sighup(signo) 5579b1aec48SLars Fredriksen int signo; 5589b1aec48SLars Fredriksen { 55901c855caSPeter Wemm fatal(2, "SIGHUP"); 5609b1aec48SLars Fredriksen } 5619b1aec48SLars Fredriksen 5629b1aec48SLars Fredriksen void init() 5639b1aec48SLars Fredriksen { 5649b1aec48SLars Fredriksen signal(SIGINT, sigint); 5659b1aec48SLars Fredriksen signal(SIGTERM, sigterm); 5669b1aec48SLars Fredriksen signal(SIGHUP, sighup); 5679b1aec48SLars Fredriksen 5689b1aec48SLars Fredriksen set_tty_parameters(); 5699b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); 5709b1aec48SLars Fredriksen alarm(0); 5719b1aec48SLars Fredriksen alarmed = 0; 5729b1aec48SLars Fredriksen } 5739b1aec48SLars Fredriksen 5749b1aec48SLars Fredriksen void set_tty_parameters() 5759b1aec48SLars Fredriksen { 5769f65f104SPeter Wemm #if defined(get_term_param) 5779f65f104SPeter Wemm term_parms t; 5789b1aec48SLars Fredriksen 5799f65f104SPeter Wemm if (get_term_param (&t) < 0) 58001c855caSPeter Wemm fatal(2, "Can't get terminal parameters: %m"); 5819b1aec48SLars Fredriksen 5829b1aec48SLars Fredriksen saved_tty_parameters = t; 5839b1aec48SLars Fredriksen have_tty_parameters = 1; 5849b1aec48SLars Fredriksen 5859b1aec48SLars Fredriksen t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 5869b1aec48SLars Fredriksen t.c_oflag = 0; 5879b1aec48SLars Fredriksen t.c_lflag = 0; 5889f65f104SPeter Wemm t.c_cc[VERASE] = 5899f65f104SPeter Wemm t.c_cc[VKILL] = 0; 5909b1aec48SLars Fredriksen t.c_cc[VMIN] = 1; 5919b1aec48SLars Fredriksen t.c_cc[VTIME] = 0; 5929b1aec48SLars Fredriksen 5939f65f104SPeter Wemm if (set_term_param (&t) < 0) 59401c855caSPeter Wemm fatal(2, "Can't set terminal parameters: %m"); 5959b1aec48SLars Fredriksen #endif 5969b1aec48SLars Fredriksen } 5979b1aec48SLars Fredriksen 5989b1aec48SLars Fredriksen void break_sequence() 5999b1aec48SLars Fredriksen { 6009b1aec48SLars Fredriksen #ifdef TERMIOS 6019b1aec48SLars Fredriksen tcsendbreak (0, 0); 6029b1aec48SLars Fredriksen #endif 6039b1aec48SLars Fredriksen } 6049b1aec48SLars Fredriksen 6059b1aec48SLars Fredriksen void terminate(status) 6069b1aec48SLars Fredriksen int status; 6079b1aec48SLars Fredriksen { 6083d793cf1SPeter Wemm echo_stderr(-1); 60901c855caSPeter Wemm if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 6103d793cf1SPeter Wemm /* 6113d793cf1SPeter Wemm * Allow the last of the report string to be gathered before we terminate. 6123d793cf1SPeter Wemm */ 6133d793cf1SPeter Wemm if (report_gathering) { 6143d793cf1SPeter Wemm int c, rep_len; 6153d793cf1SPeter Wemm 6163d793cf1SPeter Wemm rep_len = strlen(report_buffer); 6173d793cf1SPeter Wemm while (rep_len + 1 <= sizeof(report_buffer)) { 6183d793cf1SPeter Wemm alarm(1); 6193d793cf1SPeter Wemm c = get_char(); 6203d793cf1SPeter Wemm alarm(0); 6213d793cf1SPeter Wemm if (c < 0 || iscntrl(c)) 6223d793cf1SPeter Wemm break; 6233d793cf1SPeter Wemm report_buffer[rep_len] = c; 6243d793cf1SPeter Wemm ++rep_len; 6253d793cf1SPeter Wemm } 6263d793cf1SPeter Wemm report_buffer[rep_len] = 0; 6273d793cf1SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 6283d793cf1SPeter Wemm } 6299f65f104SPeter Wemm if (verbose) 6309f65f104SPeter Wemm fprintf (report_fp, "Closing \"%s\".\n", report_file); 6319f65f104SPeter Wemm fclose (report_fp); 6329f65f104SPeter Wemm report_fp = (FILE *) NULL; 6339f65f104SPeter Wemm } 6349f65f104SPeter Wemm 6359f65f104SPeter Wemm #if defined(get_term_param) 63601c855caSPeter Wemm if (have_tty_parameters) { 6379f65f104SPeter Wemm if (set_term_param (&saved_tty_parameters) < 0) 63801c855caSPeter Wemm fatal(2, "Can't restore terminal parameters: %m"); 6399f65f104SPeter Wemm } 6409f65f104SPeter Wemm #endif 6419f65f104SPeter Wemm 6429b1aec48SLars Fredriksen exit(status); 6439b1aec48SLars Fredriksen } 6449b1aec48SLars Fredriksen 6459b1aec48SLars Fredriksen /* 6469b1aec48SLars Fredriksen * 'Clean up' this string. 6479b1aec48SLars Fredriksen */ 6489b1aec48SLars Fredriksen char *clean(s, sending) 6499b1aec48SLars Fredriksen register char *s; 65001c855caSPeter Wemm int sending; /* set to 1 when sending (putting) this string. */ 6519b1aec48SLars Fredriksen { 6529b1aec48SLars Fredriksen char temp[STR_LEN], cur_chr; 65301c855caSPeter Wemm register char *s1, *phchar; 6549b1aec48SLars Fredriksen int add_return = sending; 6559b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6569b1aec48SLars Fredriksen 6579b1aec48SLars Fredriksen s1 = temp; 6584e83a8feSKris Kennaway /* Don't overflow buffer, leave room for chars we append later */ 6594e83a8feSKris Kennaway while (*s && s1 - temp < sizeof(temp) - 2 - add_return) { 6609b1aec48SLars Fredriksen cur_chr = *s++; 66101c855caSPeter Wemm if (cur_chr == '^') { 6629b1aec48SLars Fredriksen cur_chr = *s++; 66301c855caSPeter Wemm if (cur_chr == '\0') { 6649b1aec48SLars Fredriksen *s1++ = '^'; 6659b1aec48SLars Fredriksen break; 6669b1aec48SLars Fredriksen } 6679b1aec48SLars Fredriksen cur_chr &= 0x1F; 66801c855caSPeter Wemm if (cur_chr != 0) { 6699b1aec48SLars Fredriksen *s1++ = cur_chr; 6709f65f104SPeter Wemm } 6719b1aec48SLars Fredriksen continue; 6729b1aec48SLars Fredriksen } 6739b1aec48SLars Fredriksen 67401c855caSPeter Wemm if (cur_chr != '\\') { 6759b1aec48SLars Fredriksen *s1++ = cur_chr; 6769b1aec48SLars Fredriksen continue; 6779b1aec48SLars Fredriksen } 6789b1aec48SLars Fredriksen 6799b1aec48SLars Fredriksen cur_chr = *s++; 68001c855caSPeter Wemm if (cur_chr == '\0') { 68101c855caSPeter Wemm if (sending) { 6829b1aec48SLars Fredriksen *s1++ = '\\'; 6839b1aec48SLars Fredriksen *s1++ = '\\'; 6849b1aec48SLars Fredriksen } 6859b1aec48SLars Fredriksen break; 6869b1aec48SLars Fredriksen } 6879b1aec48SLars Fredriksen 68801c855caSPeter Wemm switch (cur_chr) { 6899b1aec48SLars Fredriksen case 'b': 6909b1aec48SLars Fredriksen *s1++ = '\b'; 6919b1aec48SLars Fredriksen break; 6929b1aec48SLars Fredriksen 6939b1aec48SLars Fredriksen case 'c': 6949b1aec48SLars Fredriksen if (sending && *s == '\0') 6959b1aec48SLars Fredriksen add_return = 0; 6969b1aec48SLars Fredriksen else 6979b1aec48SLars Fredriksen *s1++ = cur_chr; 6989b1aec48SLars Fredriksen break; 6999b1aec48SLars Fredriksen 7009b1aec48SLars Fredriksen case '\\': 7019b1aec48SLars Fredriksen case 'K': 7029b1aec48SLars Fredriksen case 'p': 7039b1aec48SLars Fredriksen case 'd': 7049b1aec48SLars Fredriksen if (sending) 7059b1aec48SLars Fredriksen *s1++ = '\\'; 7069b1aec48SLars Fredriksen 7079b1aec48SLars Fredriksen *s1++ = cur_chr; 7089b1aec48SLars Fredriksen break; 7099b1aec48SLars Fredriksen 71001c855caSPeter Wemm case 'T': 71101c855caSPeter Wemm if (sending && phone_num) { 71201c855caSPeter Wemm for ( phchar = phone_num; *phchar != '\0'; phchar++) 71301c855caSPeter Wemm *s1++ = *phchar; 71401c855caSPeter Wemm } 71501c855caSPeter Wemm else { 71601c855caSPeter Wemm *s1++ = '\\'; 71701c855caSPeter Wemm *s1++ = 'T'; 71801c855caSPeter Wemm } 71901c855caSPeter Wemm break; 72001c855caSPeter Wemm 72101c855caSPeter Wemm case 'U': 72201c855caSPeter Wemm if (sending && phone_num2) { 72301c855caSPeter Wemm for ( phchar = phone_num2; *phchar != '\0'; phchar++) 72401c855caSPeter Wemm *s1++ = *phchar; 72501c855caSPeter Wemm } 72601c855caSPeter Wemm else { 72701c855caSPeter Wemm *s1++ = '\\'; 72801c855caSPeter Wemm *s1++ = 'U'; 72901c855caSPeter Wemm } 73001c855caSPeter Wemm break; 73101c855caSPeter Wemm 7329b1aec48SLars Fredriksen case 'q': 7333d793cf1SPeter Wemm quiet = 1; 7349b1aec48SLars Fredriksen break; 7359b1aec48SLars Fredriksen 7369b1aec48SLars Fredriksen case 'r': 7379b1aec48SLars Fredriksen *s1++ = '\r'; 7389b1aec48SLars Fredriksen break; 7399b1aec48SLars Fredriksen 7409b1aec48SLars Fredriksen case 'n': 7419b1aec48SLars Fredriksen *s1++ = '\n'; 7429b1aec48SLars Fredriksen break; 7439b1aec48SLars Fredriksen 7449b1aec48SLars Fredriksen case 's': 7459b1aec48SLars Fredriksen *s1++ = ' '; 7469b1aec48SLars Fredriksen break; 7479b1aec48SLars Fredriksen 7489b1aec48SLars Fredriksen case 't': 7499b1aec48SLars Fredriksen *s1++ = '\t'; 7509b1aec48SLars Fredriksen break; 7519b1aec48SLars Fredriksen 7529b1aec48SLars Fredriksen case 'N': 75301c855caSPeter Wemm if (sending) { 7549b1aec48SLars Fredriksen *s1++ = '\\'; 7559b1aec48SLars Fredriksen *s1++ = '\0'; 7569b1aec48SLars Fredriksen } 7579b1aec48SLars Fredriksen else 7589b1aec48SLars Fredriksen *s1++ = 'N'; 7599b1aec48SLars Fredriksen break; 7609b1aec48SLars Fredriksen 7619b1aec48SLars Fredriksen default: 76201c855caSPeter Wemm if (isoctal (cur_chr)) { 7639b1aec48SLars Fredriksen cur_chr &= 0x07; 76401c855caSPeter Wemm if (isoctal (*s)) { 7659b1aec48SLars Fredriksen cur_chr <<= 3; 7669b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 76701c855caSPeter Wemm if (isoctal (*s)) { 7689b1aec48SLars Fredriksen cur_chr <<= 3; 7699b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 7709b1aec48SLars Fredriksen } 7719b1aec48SLars Fredriksen } 7729b1aec48SLars Fredriksen 77301c855caSPeter Wemm if (cur_chr != 0 || sending) { 7749b1aec48SLars Fredriksen if (sending && (cur_chr == '\\' || cur_chr == 0)) 7759b1aec48SLars Fredriksen *s1++ = '\\'; 7769b1aec48SLars Fredriksen *s1++ = cur_chr; 7779b1aec48SLars Fredriksen } 7789b1aec48SLars Fredriksen break; 7799b1aec48SLars Fredriksen } 7809b1aec48SLars Fredriksen 7819b1aec48SLars Fredriksen if (sending) 7829b1aec48SLars Fredriksen *s1++ = '\\'; 7839b1aec48SLars Fredriksen *s1++ = cur_chr; 7849b1aec48SLars Fredriksen break; 7859b1aec48SLars Fredriksen } 7869b1aec48SLars Fredriksen } 7879b1aec48SLars Fredriksen 7889b1aec48SLars Fredriksen if (add_return) 7899b1aec48SLars Fredriksen *s1++ = '\r'; 7909b1aec48SLars Fredriksen 7919b1aec48SLars Fredriksen *s1++ = '\0'; /* guarantee closure */ 7929b1aec48SLars Fredriksen *s1++ = '\0'; /* terminate the string */ 7939b1aec48SLars Fredriksen return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7949b1aec48SLars Fredriksen } 7959b1aec48SLars Fredriksen 7969b1aec48SLars Fredriksen /* 7973d793cf1SPeter Wemm * A modified version of 'strtok'. This version skips \ sequences. 7983d793cf1SPeter Wemm */ 7993d793cf1SPeter Wemm 8003d793cf1SPeter Wemm char *expect_strtok (s, term) 8013d793cf1SPeter Wemm char *s, *term; 8023d793cf1SPeter Wemm { 8033d793cf1SPeter Wemm static char *str = ""; 8043d793cf1SPeter Wemm int escape_flag = 0; 8053d793cf1SPeter Wemm char *result; 80601c855caSPeter Wemm 8073d793cf1SPeter Wemm /* 8083d793cf1SPeter Wemm * If a string was specified then do initial processing. 8093d793cf1SPeter Wemm */ 8103d793cf1SPeter Wemm if (s) 8113d793cf1SPeter Wemm str = s; 81201c855caSPeter Wemm 8133d793cf1SPeter Wemm /* 8143d793cf1SPeter Wemm * If this is the escape flag then reset it and ignore the character. 8153d793cf1SPeter Wemm */ 8163d793cf1SPeter Wemm if (*str) 8173d793cf1SPeter Wemm result = str; 8183d793cf1SPeter Wemm else 8193d793cf1SPeter Wemm result = (char *) 0; 8203d793cf1SPeter Wemm 82101c855caSPeter Wemm while (*str) { 82201c855caSPeter Wemm if (escape_flag) { 8233d793cf1SPeter Wemm escape_flag = 0; 8243d793cf1SPeter Wemm ++str; 8253d793cf1SPeter Wemm continue; 8263d793cf1SPeter Wemm } 8273d793cf1SPeter Wemm 82801c855caSPeter Wemm if (*str == '\\') { 8293d793cf1SPeter Wemm ++str; 8303d793cf1SPeter Wemm escape_flag = 1; 8313d793cf1SPeter Wemm continue; 8323d793cf1SPeter Wemm } 83301c855caSPeter Wemm 8343d793cf1SPeter Wemm /* 8353d793cf1SPeter Wemm * If this is not in the termination string, continue. 8363d793cf1SPeter Wemm */ 83701c855caSPeter Wemm if (strchr (term, *str) == (char *) 0) { 8383d793cf1SPeter Wemm ++str; 8393d793cf1SPeter Wemm continue; 8403d793cf1SPeter Wemm } 84101c855caSPeter Wemm 8423d793cf1SPeter Wemm /* 8433d793cf1SPeter Wemm * This is the terminator. Mark the end of the string and stop. 8443d793cf1SPeter Wemm */ 8453d793cf1SPeter Wemm *str++ = '\0'; 8463d793cf1SPeter Wemm break; 8473d793cf1SPeter Wemm } 8483d793cf1SPeter Wemm return (result); 8493d793cf1SPeter Wemm } 8503d793cf1SPeter Wemm 8513d793cf1SPeter Wemm /* 8529b1aec48SLars Fredriksen * Process the expect string 8539b1aec48SLars Fredriksen */ 8543d793cf1SPeter Wemm 8559b1aec48SLars Fredriksen void chat_expect (s) 8563d793cf1SPeter Wemm char *s; 8579b1aec48SLars Fredriksen { 8583d793cf1SPeter Wemm char *expect; 8593d793cf1SPeter Wemm char *reply; 8603d793cf1SPeter Wemm 86101c855caSPeter Wemm if (strcmp(s, "HANGUP") == 0) { 8623d793cf1SPeter Wemm ++hup_next; 8633d793cf1SPeter Wemm return; 8643d793cf1SPeter Wemm } 8653d793cf1SPeter Wemm 86601c855caSPeter Wemm if (strcmp(s, "ABORT") == 0) { 8679b1aec48SLars Fredriksen ++abort_next; 8689b1aec48SLars Fredriksen return; 8699b1aec48SLars Fredriksen } 8709b1aec48SLars Fredriksen 87101c855caSPeter Wemm if (strcmp(s, "CLR_ABORT") == 0) { 8723d793cf1SPeter Wemm ++clear_abort_next; 8733d793cf1SPeter Wemm return; 8743d793cf1SPeter Wemm } 8753d793cf1SPeter Wemm 87601c855caSPeter Wemm if (strcmp(s, "REPORT") == 0) { 8779f65f104SPeter Wemm ++report_next; 8789f65f104SPeter Wemm return; 8799f65f104SPeter Wemm } 8809f65f104SPeter Wemm 88101c855caSPeter Wemm if (strcmp(s, "CLR_REPORT") == 0) { 8823d793cf1SPeter Wemm ++clear_report_next; 8833d793cf1SPeter Wemm return; 8843d793cf1SPeter Wemm } 8853d793cf1SPeter Wemm 88601c855caSPeter Wemm if (strcmp(s, "TIMEOUT") == 0) { 8879b1aec48SLars Fredriksen ++timeout_next; 8889b1aec48SLars Fredriksen return; 8899b1aec48SLars Fredriksen } 8909b1aec48SLars Fredriksen 89101c855caSPeter Wemm if (strcmp(s, "ECHO") == 0) { 8923d793cf1SPeter Wemm ++echo_next; 8933d793cf1SPeter Wemm return; 8943d793cf1SPeter Wemm } 89501c855caSPeter Wemm 89601c855caSPeter Wemm if (strcmp(s, "SAY") == 0) { 8973d793cf1SPeter Wemm ++say_next; 8983d793cf1SPeter Wemm return; 8993d793cf1SPeter Wemm } 90001c855caSPeter Wemm 9013d793cf1SPeter Wemm /* 9023d793cf1SPeter Wemm * Fetch the expect and reply string. 9033d793cf1SPeter Wemm */ 90401c855caSPeter Wemm for (;;) { 9053d793cf1SPeter Wemm expect = expect_strtok (s, "-"); 9063d793cf1SPeter Wemm s = (char *) 0; 9079b1aec48SLars Fredriksen 9083d793cf1SPeter Wemm if (expect == (char *) 0) 9093d793cf1SPeter Wemm return; 9103d793cf1SPeter Wemm 9113d793cf1SPeter Wemm reply = expect_strtok (s, "-"); 91201c855caSPeter Wemm 9133d793cf1SPeter Wemm /* 9143d793cf1SPeter Wemm * Handle the expect string. If successful then exit. 9153d793cf1SPeter Wemm */ 9163d793cf1SPeter Wemm if (get_string (expect)) 9173d793cf1SPeter Wemm return; 91801c855caSPeter Wemm 9193d793cf1SPeter Wemm /* 9203d793cf1SPeter Wemm * If there is a sub-reply string then send it. Otherwise any condition 9213d793cf1SPeter Wemm * is terminal. 9223d793cf1SPeter Wemm */ 9233d793cf1SPeter Wemm if (reply == (char *) 0 || exit_code != 3) 9249b1aec48SLars Fredriksen break; 9259b1aec48SLars Fredriksen 9263d793cf1SPeter Wemm chat_send (reply); 9279f65f104SPeter Wemm } 92801c855caSPeter Wemm 9293d793cf1SPeter Wemm /* 9303d793cf1SPeter Wemm * The expectation did not occur. This is terminal. 9313d793cf1SPeter Wemm */ 9329b1aec48SLars Fredriksen if (fail_reason) 93301c855caSPeter Wemm logf("Failed (%s)", fail_reason); 9349b1aec48SLars Fredriksen else 93501c855caSPeter Wemm logf("Failed"); 9369f65f104SPeter Wemm terminate(exit_code); 9379f65f104SPeter Wemm } 9383d793cf1SPeter Wemm 9393d793cf1SPeter Wemm /* 9403d793cf1SPeter Wemm * Translate the input character to the appropriate string for printing 9413d793cf1SPeter Wemm * the data. 9423d793cf1SPeter Wemm */ 9439b1aec48SLars Fredriksen 9449b1aec48SLars Fredriksen char *character(c) 9459f65f104SPeter Wemm int c; 9469b1aec48SLars Fredriksen { 9479b1aec48SLars Fredriksen static char string[10]; 9489b1aec48SLars Fredriksen char *meta; 9499b1aec48SLars Fredriksen 9509b1aec48SLars Fredriksen meta = (c & 0x80) ? "M-" : ""; 9519b1aec48SLars Fredriksen c &= 0x7F; 9529b1aec48SLars Fredriksen 9539b1aec48SLars Fredriksen if (c < 32) 9549b1aec48SLars Fredriksen sprintf(string, "%s^%c", meta, (int)c + '@'); 95501c855caSPeter Wemm else if (c == 127) 9569b1aec48SLars Fredriksen sprintf(string, "%s^?", meta); 9579b1aec48SLars Fredriksen else 9589b1aec48SLars Fredriksen sprintf(string, "%s%c", meta, c); 9599b1aec48SLars Fredriksen 9609b1aec48SLars Fredriksen return (string); 9619b1aec48SLars Fredriksen } 9629b1aec48SLars Fredriksen 9639b1aec48SLars Fredriksen /* 9649b1aec48SLars Fredriksen * process the reply string 9659b1aec48SLars Fredriksen */ 9669b1aec48SLars Fredriksen void chat_send (s) 9679b1aec48SLars Fredriksen register char *s; 9689b1aec48SLars Fredriksen { 96901c855caSPeter Wemm if (say_next) { 9703d793cf1SPeter Wemm say_next = 0; 9713d793cf1SPeter Wemm s = clean(s,0); 9723d793cf1SPeter Wemm write(2, s, strlen(s)); 9733d793cf1SPeter Wemm free(s); 9743d793cf1SPeter Wemm return; 9753d793cf1SPeter Wemm } 97601c855caSPeter Wemm 97701c855caSPeter Wemm if (hup_next) { 9783d793cf1SPeter Wemm hup_next = 0; 9793d793cf1SPeter Wemm if (strcmp(s, "OFF") == 0) 9803d793cf1SPeter Wemm signal(SIGHUP, SIG_IGN); 9813d793cf1SPeter Wemm else 9823d793cf1SPeter Wemm signal(SIGHUP, sighup); 9833d793cf1SPeter Wemm return; 9843d793cf1SPeter Wemm } 98501c855caSPeter Wemm 98601c855caSPeter Wemm if (echo_next) { 9873d793cf1SPeter Wemm echo_next = 0; 9883d793cf1SPeter Wemm echo = (strcmp(s, "ON") == 0); 9893d793cf1SPeter Wemm return; 9903d793cf1SPeter Wemm } 99101c855caSPeter Wemm 99201c855caSPeter Wemm if (abort_next) { 9939b1aec48SLars Fredriksen char *s1; 9949b1aec48SLars Fredriksen 9959b1aec48SLars Fredriksen abort_next = 0; 9969b1aec48SLars Fredriksen 9979b1aec48SLars Fredriksen if (n_aborts >= MAX_ABORTS) 99801c855caSPeter Wemm fatal(2, "Too many ABORT strings"); 9999b1aec48SLars Fredriksen 10009b1aec48SLars Fredriksen s1 = clean(s, 0); 10019b1aec48SLars Fredriksen 10029f65f104SPeter Wemm if (strlen(s1) > strlen(s) 10039f65f104SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 100401c855caSPeter Wemm fatal(1, "Illegal or too-long ABORT string ('%v')", s); 10059b1aec48SLars Fredriksen 10069b1aec48SLars Fredriksen abort_string[n_aborts++] = s1; 10079b1aec48SLars Fredriksen 10089b1aec48SLars Fredriksen if (verbose) 100901c855caSPeter Wemm logf("abort on (%v)", s); 10109f65f104SPeter Wemm return; 10119b1aec48SLars Fredriksen } 10129f65f104SPeter Wemm 101301c855caSPeter Wemm if (clear_abort_next) { 10143d793cf1SPeter Wemm char *s1; 10153d793cf1SPeter Wemm int i; 10163d793cf1SPeter Wemm int old_max; 10173d793cf1SPeter Wemm int pack = 0; 10183d793cf1SPeter Wemm 10193d793cf1SPeter Wemm clear_abort_next = 0; 10203d793cf1SPeter Wemm 10213d793cf1SPeter Wemm s1 = clean(s, 0); 10223d793cf1SPeter Wemm 10233d793cf1SPeter Wemm if (strlen(s1) > strlen(s) 10243d793cf1SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 102501c855caSPeter Wemm fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 10263d793cf1SPeter Wemm 10273d793cf1SPeter Wemm old_max = n_aborts; 102801c855caSPeter Wemm for (i=0; i < n_aborts; i++) { 102901c855caSPeter Wemm if ( strcmp(s1,abort_string[i]) == 0 ) { 10303d793cf1SPeter Wemm free(abort_string[i]); 10313d793cf1SPeter Wemm abort_string[i] = NULL; 10323d793cf1SPeter Wemm pack++; 10333d793cf1SPeter Wemm n_aborts--; 10343d793cf1SPeter Wemm if (verbose) 103501c855caSPeter Wemm logf("clear abort on (%v)", s); 10363d793cf1SPeter Wemm } 10373d793cf1SPeter Wemm } 10383d793cf1SPeter Wemm free(s1); 103901c855caSPeter Wemm if (pack) 104001c855caSPeter Wemm pack_array(abort_string,old_max); 10413d793cf1SPeter Wemm return; 10423d793cf1SPeter Wemm } 10433d793cf1SPeter Wemm 104401c855caSPeter Wemm if (report_next) { 10459f65f104SPeter Wemm char *s1; 10469f65f104SPeter Wemm 10479f65f104SPeter Wemm report_next = 0; 10489f65f104SPeter Wemm if (n_reports >= MAX_REPORTS) 104901c855caSPeter Wemm fatal(2, "Too many REPORT strings"); 10509f65f104SPeter Wemm 10519f65f104SPeter Wemm s1 = clean(s, 0); 10529f65f104SPeter Wemm 10539f65f104SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 105401c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 10559f65f104SPeter Wemm 10569f65f104SPeter Wemm report_string[n_reports++] = s1; 10579f65f104SPeter Wemm 10589f65f104SPeter Wemm if (verbose) 105901c855caSPeter Wemm logf("report (%v)", s); 10609f65f104SPeter Wemm return; 10619f65f104SPeter Wemm } 10629f65f104SPeter Wemm 106301c855caSPeter Wemm if (clear_report_next) { 10643d793cf1SPeter Wemm char *s1; 10653d793cf1SPeter Wemm int i; 10663d793cf1SPeter Wemm int old_max; 10673d793cf1SPeter Wemm int pack = 0; 10683d793cf1SPeter Wemm 10693d793cf1SPeter Wemm clear_report_next = 0; 10703d793cf1SPeter Wemm 10713d793cf1SPeter Wemm s1 = clean(s, 0); 10723d793cf1SPeter Wemm 10733d793cf1SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 107401c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 10753d793cf1SPeter Wemm 10763d793cf1SPeter Wemm old_max = n_reports; 107701c855caSPeter Wemm for (i=0; i < n_reports; i++) { 107801c855caSPeter Wemm if ( strcmp(s1,report_string[i]) == 0 ) { 10793d793cf1SPeter Wemm free(report_string[i]); 10803d793cf1SPeter Wemm report_string[i] = NULL; 10813d793cf1SPeter Wemm pack++; 10823d793cf1SPeter Wemm n_reports--; 10833d793cf1SPeter Wemm if (verbose) 108401c855caSPeter Wemm logf("clear report (%v)", s); 10853d793cf1SPeter Wemm } 10863d793cf1SPeter Wemm } 10873d793cf1SPeter Wemm free(s1); 108801c855caSPeter Wemm if (pack) 108901c855caSPeter Wemm pack_array(report_string,old_max); 10903d793cf1SPeter Wemm 10913d793cf1SPeter Wemm return; 10923d793cf1SPeter Wemm } 10933d793cf1SPeter Wemm 109401c855caSPeter Wemm if (timeout_next) { 10959b1aec48SLars Fredriksen timeout_next = 0; 10969b1aec48SLars Fredriksen timeout = atoi(s); 10979b1aec48SLars Fredriksen 10989b1aec48SLars Fredriksen if (timeout <= 0) 10999b1aec48SLars Fredriksen timeout = DEFAULT_CHAT_TIMEOUT; 11009b1aec48SLars Fredriksen 11019b1aec48SLars Fredriksen if (verbose) 110201c855caSPeter Wemm logf("timeout set to %d seconds", timeout); 110301c855caSPeter Wemm 11049f65f104SPeter Wemm return; 11059f65f104SPeter Wemm } 11069f65f104SPeter Wemm 11079f65f104SPeter Wemm if (strcmp(s, "EOT") == 0) 11089f65f104SPeter Wemm s = "^D\\c"; 110901c855caSPeter Wemm else if (strcmp(s, "BREAK") == 0) 11109b1aec48SLars Fredriksen s = "\\K\\c"; 11119f65f104SPeter Wemm 11129b1aec48SLars Fredriksen if (!put_string(s)) 111301c855caSPeter Wemm fatal(1, "Failed"); 11149b1aec48SLars Fredriksen } 11159b1aec48SLars Fredriksen 11169b1aec48SLars Fredriksen int get_char() 11179b1aec48SLars Fredriksen { 11189b1aec48SLars Fredriksen int status; 11199b1aec48SLars Fredriksen char c; 11209b1aec48SLars Fredriksen 11219b1aec48SLars Fredriksen status = read(0, &c, 1); 11229b1aec48SLars Fredriksen 112301c855caSPeter Wemm switch (status) { 11249b1aec48SLars Fredriksen case 1: 11259b1aec48SLars Fredriksen return ((int)c & 0x7F); 11269b1aec48SLars Fredriksen 11279b1aec48SLars Fredriksen default: 112801c855caSPeter Wemm logf("warning: read() on stdin returned %d", status); 11299b1aec48SLars Fredriksen 11309b1aec48SLars Fredriksen case -1: 11319b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 113201c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 113301c855caSPeter Wemm 11349f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113501c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 11369b1aec48SLars Fredriksen 11379b1aec48SLars Fredriksen return (-1); 11389b1aec48SLars Fredriksen } 11399b1aec48SLars Fredriksen } 11409b1aec48SLars Fredriksen 11419b1aec48SLars Fredriksen int put_char(c) 11429f65f104SPeter Wemm int c; 11439b1aec48SLars Fredriksen { 11449b1aec48SLars Fredriksen int status; 11459f65f104SPeter Wemm char ch = c; 11469b1aec48SLars Fredriksen 11479f65f104SPeter Wemm usleep(10000); /* inter-character typing delay (?) */ 11489b1aec48SLars Fredriksen 11499f65f104SPeter Wemm status = write(1, &ch, 1); 11509b1aec48SLars Fredriksen 115101c855caSPeter Wemm switch (status) { 11529b1aec48SLars Fredriksen case 1: 11539b1aec48SLars Fredriksen return (0); 11549b1aec48SLars Fredriksen 11559b1aec48SLars Fredriksen default: 115601c855caSPeter Wemm logf("warning: write() on stdout returned %d", status); 11579b1aec48SLars Fredriksen 11589b1aec48SLars Fredriksen case -1: 11599b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 116001c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin, %m"); 116101c855caSPeter Wemm 11629f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 116301c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 11649b1aec48SLars Fredriksen 11659b1aec48SLars Fredriksen return (-1); 11669b1aec48SLars Fredriksen } 11679b1aec48SLars Fredriksen } 11689b1aec48SLars Fredriksen 11699b1aec48SLars Fredriksen int write_char (c) 11709b1aec48SLars Fredriksen int c; 11719b1aec48SLars Fredriksen { 117201c855caSPeter Wemm if (alarmed || put_char(c) < 0) { 11739f65f104SPeter Wemm alarm(0); 11749f65f104SPeter Wemm alarmed = 0; 11759b1aec48SLars Fredriksen 117601c855caSPeter Wemm if (verbose) { 11779b1aec48SLars Fredriksen if (errno == EINTR || errno == EWOULDBLOCK) 117801c855caSPeter Wemm logf(" -- write timed out"); 11799b1aec48SLars Fredriksen else 118001c855caSPeter Wemm logf(" -- write failed: %m"); 11819f65f104SPeter Wemm } 11829b1aec48SLars Fredriksen return (0); 11839b1aec48SLars Fredriksen } 11849b1aec48SLars Fredriksen return (1); 11859b1aec48SLars Fredriksen } 11869b1aec48SLars Fredriksen 11879b1aec48SLars Fredriksen int put_string (s) 11889b1aec48SLars Fredriksen register char *s; 11899b1aec48SLars Fredriksen { 11903d793cf1SPeter Wemm quiet = 0; 11919b1aec48SLars Fredriksen s = clean(s, 1); 11929b1aec48SLars Fredriksen 119301c855caSPeter Wemm if (verbose) { 11949b1aec48SLars Fredriksen if (quiet) 119501c855caSPeter Wemm logf("send (??????)"); 11969b1aec48SLars Fredriksen else 119701c855caSPeter Wemm logf("send (%v)", s); 11989b1aec48SLars Fredriksen } 11999b1aec48SLars Fredriksen 12009b1aec48SLars Fredriksen alarm(timeout); alarmed = 0; 12019b1aec48SLars Fredriksen 120201c855caSPeter Wemm while (*s) { 12039b1aec48SLars Fredriksen register char c = *s++; 12049b1aec48SLars Fredriksen 120501c855caSPeter Wemm if (c != '\\') { 12069b1aec48SLars Fredriksen if (!write_char (c)) 12079b1aec48SLars Fredriksen return 0; 12089b1aec48SLars Fredriksen continue; 12099b1aec48SLars Fredriksen } 12109b1aec48SLars Fredriksen 12119b1aec48SLars Fredriksen c = *s++; 121201c855caSPeter Wemm switch (c) { 12139b1aec48SLars Fredriksen case 'd': 12149b1aec48SLars Fredriksen sleep(1); 12159b1aec48SLars Fredriksen break; 12169b1aec48SLars Fredriksen 12179b1aec48SLars Fredriksen case 'K': 12189b1aec48SLars Fredriksen break_sequence(); 12199b1aec48SLars Fredriksen break; 12209b1aec48SLars Fredriksen 12219b1aec48SLars Fredriksen case 'p': 12229f65f104SPeter Wemm usleep(10000); /* 1/100th of a second (arg is microseconds) */ 12239b1aec48SLars Fredriksen break; 12249b1aec48SLars Fredriksen 12259b1aec48SLars Fredriksen default: 12269b1aec48SLars Fredriksen if (!write_char (c)) 12279b1aec48SLars Fredriksen return 0; 12289b1aec48SLars Fredriksen break; 12299b1aec48SLars Fredriksen } 12309b1aec48SLars Fredriksen } 12319b1aec48SLars Fredriksen 12329b1aec48SLars Fredriksen alarm(0); 12339b1aec48SLars Fredriksen alarmed = 0; 12349b1aec48SLars Fredriksen return (1); 12359b1aec48SLars Fredriksen } 12369b1aec48SLars Fredriksen 12379b1aec48SLars Fredriksen /* 12383d793cf1SPeter Wemm * Echo a character to stderr. 12393d793cf1SPeter Wemm * When called with -1, a '\n' character is generated when 12403d793cf1SPeter Wemm * the cursor is not at the beginning of a line. 12413d793cf1SPeter Wemm */ 12423d793cf1SPeter Wemm void echo_stderr(n) 12433d793cf1SPeter Wemm int n; 12443d793cf1SPeter Wemm { 12453d793cf1SPeter Wemm static int need_lf; 12463d793cf1SPeter Wemm char *s; 12473d793cf1SPeter Wemm 124801c855caSPeter Wemm switch (n) { 12493d793cf1SPeter Wemm case '\r': /* ignore '\r' */ 12503d793cf1SPeter Wemm break; 12513d793cf1SPeter Wemm case -1: 12523d793cf1SPeter Wemm if (need_lf == 0) 12533d793cf1SPeter Wemm break; 12543d793cf1SPeter Wemm /* fall through */ 12553d793cf1SPeter Wemm case '\n': 12563d793cf1SPeter Wemm write(2, "\n", 1); 12573d793cf1SPeter Wemm need_lf = 0; 12583d793cf1SPeter Wemm break; 12593d793cf1SPeter Wemm default: 12603d793cf1SPeter Wemm s = character(n); 12613d793cf1SPeter Wemm write(2, s, strlen(s)); 12623d793cf1SPeter Wemm need_lf = 1; 12633d793cf1SPeter Wemm break; 12643d793cf1SPeter Wemm } 12653d793cf1SPeter Wemm } 12663d793cf1SPeter Wemm 12673d793cf1SPeter Wemm /* 12689b1aec48SLars Fredriksen * 'Wait for' this string to appear on this file descriptor. 12699b1aec48SLars Fredriksen */ 12709b1aec48SLars Fredriksen int get_string(string) 12719b1aec48SLars Fredriksen register char *string; 12729b1aec48SLars Fredriksen { 12739b1aec48SLars Fredriksen char temp[STR_LEN]; 12749b1aec48SLars Fredriksen int c, printed = 0, len, minlen; 12759b1aec48SLars Fredriksen register char *s = temp, *end = s + STR_LEN; 127601c855caSPeter Wemm char *logged = temp; 12779b1aec48SLars Fredriksen 12789b1aec48SLars Fredriksen fail_reason = (char *)0; 12794e83a8feSKris Kennaway 12804e83a8feSKris Kennaway if (strlen(string) > STR_LEN) { 12814e83a8feSKris Kennaway logf("expect string is too long"); 12824e83a8feSKris Kennaway exit_code = 1; 12834e83a8feSKris Kennaway return 0; 12844e83a8feSKris Kennaway } 12854e83a8feSKris Kennaway 12869b1aec48SLars Fredriksen string = clean(string, 0); 12879b1aec48SLars Fredriksen len = strlen(string); 12889b1aec48SLars Fredriksen minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12899b1aec48SLars Fredriksen 12909b1aec48SLars Fredriksen if (verbose) 129101c855caSPeter Wemm logf("expect (%v)", string); 12929b1aec48SLars Fredriksen 129301c855caSPeter Wemm if (len == 0) { 12949b1aec48SLars Fredriksen if (verbose) 129501c855caSPeter Wemm logf("got it"); 12969b1aec48SLars Fredriksen return (1); 12979b1aec48SLars Fredriksen } 12989b1aec48SLars Fredriksen 12999f65f104SPeter Wemm alarm(timeout); 13009f65f104SPeter Wemm alarmed = 0; 13019b1aec48SLars Fredriksen 130201c855caSPeter Wemm while ( ! alarmed && (c = get_char()) >= 0) { 13039f65f104SPeter Wemm int n, abort_len, report_len; 13049b1aec48SLars Fredriksen 13053d793cf1SPeter Wemm if (echo) 13063d793cf1SPeter Wemm echo_stderr(c); 130701c855caSPeter Wemm if (verbose && c == '\n') { 130801c855caSPeter Wemm if (s == logged) 130901c855caSPeter Wemm logf(""); /* blank line */ 13109b1aec48SLars Fredriksen else 131101c855caSPeter Wemm logf("%0.*v", s - logged, logged); 131201c855caSPeter Wemm logged = s + 1; 13133d793cf1SPeter Wemm } 13143d793cf1SPeter Wemm 13159b1aec48SLars Fredriksen *s++ = c; 13169b1aec48SLars Fredriksen 131701c855caSPeter Wemm if (verbose && s >= logged + 80) { 131801c855caSPeter Wemm logf("%0.*v", s - logged, logged); 131901c855caSPeter Wemm logged = s; 132001c855caSPeter Wemm } 132101c855caSPeter Wemm 132201c855caSPeter Wemm if (Verbose) { 132301c855caSPeter Wemm if (c == '\n') 132401c855caSPeter Wemm fputc( '\n', stderr ); 132501c855caSPeter Wemm else if (c != '\r') 132601c855caSPeter Wemm fprintf( stderr, "%s", character(c) ); 132701c855caSPeter Wemm } 132801c855caSPeter Wemm 132901c855caSPeter Wemm if (!report_gathering) { 133001c855caSPeter Wemm for (n = 0; n < n_reports; ++n) { 13319f65f104SPeter Wemm if ((report_string[n] != (char*) NULL) && 13329f65f104SPeter Wemm s - temp >= (report_len = strlen(report_string[n])) && 133301c855caSPeter Wemm strncmp(s - report_len, report_string[n], report_len) == 0) { 13349f65f104SPeter Wemm time_t time_now = time ((time_t*) NULL); 13359f65f104SPeter Wemm struct tm* tm_now = localtime (&time_now); 13369f65f104SPeter Wemm 13379f65f104SPeter Wemm strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 13389f65f104SPeter Wemm strcat (report_buffer, report_string[n]); 13399f65f104SPeter Wemm 13409f65f104SPeter Wemm report_string[n] = (char *) NULL; 13419f65f104SPeter Wemm report_gathering = 1; 13429f65f104SPeter Wemm break; 13439f65f104SPeter Wemm } 13449f65f104SPeter Wemm } 13459f65f104SPeter Wemm } 134601c855caSPeter Wemm else { 134701c855caSPeter Wemm if (!iscntrl (c)) { 13489f65f104SPeter Wemm int rep_len = strlen (report_buffer); 13499f65f104SPeter Wemm report_buffer[rep_len] = c; 13509f65f104SPeter Wemm report_buffer[rep_len + 1] = '\0'; 13519f65f104SPeter Wemm } 135201c855caSPeter Wemm else { 13539f65f104SPeter Wemm report_gathering = 0; 13549f65f104SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 13559f65f104SPeter Wemm } 13569f65f104SPeter Wemm } 13579b1aec48SLars Fredriksen 13583d793cf1SPeter Wemm if (s - temp >= len && 13593d793cf1SPeter Wemm c == string[len - 1] && 136001c855caSPeter Wemm strncmp(s - len, string, len) == 0) { 136101c855caSPeter Wemm if (verbose) { 136201c855caSPeter Wemm if (s > logged) 136301c855caSPeter Wemm logf("%0.*v", s - logged, logged); 13643d793cf1SPeter Wemm logf(" -- got it\n"); 13653d793cf1SPeter Wemm } 13663d793cf1SPeter Wemm 13673d793cf1SPeter Wemm alarm(0); 13683d793cf1SPeter Wemm alarmed = 0; 13693d793cf1SPeter Wemm return (1); 13703d793cf1SPeter Wemm } 13713d793cf1SPeter Wemm 137201c855caSPeter Wemm for (n = 0; n < n_aborts; ++n) { 13733d793cf1SPeter Wemm if (s - temp >= (abort_len = strlen(abort_string[n])) && 137401c855caSPeter Wemm strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 137501c855caSPeter Wemm if (verbose) { 137601c855caSPeter Wemm if (s > logged) 137701c855caSPeter Wemm logf("%0.*v", s - logged, logged); 137801c855caSPeter Wemm logf(" -- failed"); 13793d793cf1SPeter Wemm } 13803d793cf1SPeter Wemm 13813d793cf1SPeter Wemm alarm(0); 13823d793cf1SPeter Wemm alarmed = 0; 13833d793cf1SPeter Wemm exit_code = n + 4; 13843d793cf1SPeter Wemm strcpy(fail_reason = fail_buffer, abort_string[n]); 13853d793cf1SPeter Wemm return (0); 13863d793cf1SPeter Wemm } 13873d793cf1SPeter Wemm } 13883d793cf1SPeter Wemm 138901c855caSPeter Wemm if (s >= end) { 139001c855caSPeter Wemm if (logged < s - minlen) { 139101c855caSPeter Wemm logf("%0.*v", s - logged, logged); 139201c855caSPeter Wemm logged = s; 139301c855caSPeter Wemm } 139401c855caSPeter Wemm s -= minlen; 139501c855caSPeter Wemm memmove(temp, s, minlen); 139601c855caSPeter Wemm logged = temp + (logged - s); 13979b1aec48SLars Fredriksen s = temp + minlen; 13989b1aec48SLars Fredriksen } 13999b1aec48SLars Fredriksen 14009b1aec48SLars Fredriksen if (alarmed && verbose) 140101c855caSPeter Wemm logf("warning: alarm synchronization problem"); 14029f65f104SPeter Wemm } 14039b1aec48SLars Fredriksen 14049b1aec48SLars Fredriksen alarm(0); 14059b1aec48SLars Fredriksen 140601c855caSPeter Wemm if (verbose && printed) { 14079b1aec48SLars Fredriksen if (alarmed) 140801c855caSPeter Wemm logf(" -- read timed out"); 14099b1aec48SLars Fredriksen else 141001c855caSPeter Wemm logf(" -- read failed: %m"); 14119b1aec48SLars Fredriksen } 14129b1aec48SLars Fredriksen 14139f65f104SPeter Wemm exit_code = 3; 14149b1aec48SLars Fredriksen alarmed = 0; 14159b1aec48SLars Fredriksen return (0); 14169b1aec48SLars Fredriksen } 14179b1aec48SLars Fredriksen 14187288c503SPeter Wemm /* 14197288c503SPeter Wemm * Gross kludge to handle Solaris versions >= 2.6 having usleep. 14207288c503SPeter Wemm */ 14217288c503SPeter Wemm #ifdef SOL2 14227288c503SPeter Wemm #include <sys/param.h> 14237288c503SPeter Wemm #if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 14247288c503SPeter Wemm #undef NO_USLEEP 14257288c503SPeter Wemm #endif 14267288c503SPeter Wemm #endif /* SOL2 */ 14277288c503SPeter Wemm 14289f65f104SPeter Wemm #ifdef NO_USLEEP 14299b1aec48SLars Fredriksen #include <sys/types.h> 14309b1aec48SLars Fredriksen #include <sys/time.h> 14319b1aec48SLars Fredriksen 14329b1aec48SLars Fredriksen /* 14339b1aec48SLars Fredriksen usleep -- support routine for 4.2BSD system call emulations 14349b1aec48SLars Fredriksen last edit: 29-Oct-1984 D A Gwyn 14359b1aec48SLars Fredriksen */ 14369b1aec48SLars Fredriksen 14379b1aec48SLars Fredriksen extern int select(); 14389b1aec48SLars Fredriksen 14399b1aec48SLars Fredriksen int 14409b1aec48SLars Fredriksen usleep( usec ) /* returns 0 if ok, else -1 */ 14419b1aec48SLars Fredriksen long usec; /* delay in microseconds */ 14429b1aec48SLars Fredriksen { 144301c855caSPeter Wemm static struct { /* `timeval' */ 14449b1aec48SLars Fredriksen long tv_sec; /* seconds */ 14459b1aec48SLars Fredriksen long tv_usec; /* microsecs */ 14469b1aec48SLars Fredriksen } delay; /* _select() timeout */ 14479b1aec48SLars Fredriksen 14489b1aec48SLars Fredriksen delay.tv_sec = usec / 1000000L; 14499b1aec48SLars Fredriksen delay.tv_usec = usec % 1000000L; 14509b1aec48SLars Fredriksen 14519b1aec48SLars Fredriksen return select(0, (long *)0, (long *)0, (long *)0, &delay); 14529b1aec48SLars Fredriksen } 14539b1aec48SLars Fredriksen #endif 14543d793cf1SPeter Wemm 14553d793cf1SPeter Wemm void 14563d793cf1SPeter Wemm pack_array (array, end) 14573d793cf1SPeter Wemm char **array; /* The address of the array of string pointers */ 14583d793cf1SPeter Wemm int end; /* The index of the next free entry before CLR_ */ 14593d793cf1SPeter Wemm { 14603d793cf1SPeter Wemm int i, j; 14613d793cf1SPeter Wemm 14623d793cf1SPeter Wemm for (i = 0; i < end; i++) { 14633d793cf1SPeter Wemm if (array[i] == NULL) { 14643d793cf1SPeter Wemm for (j = i+1; j < end; ++j) 14653d793cf1SPeter Wemm if (array[j] != NULL) 14663d793cf1SPeter Wemm array[i++] = array[j]; 14673d793cf1SPeter Wemm for (; i < end; ++i) 14683d793cf1SPeter Wemm array[i] = NULL; 14693d793cf1SPeter Wemm break; 14703d793cf1SPeter Wemm } 14713d793cf1SPeter Wemm } 14723d793cf1SPeter Wemm } 147301c855caSPeter Wemm 147401c855caSPeter Wemm /* 147501c855caSPeter Wemm * vfmtmsg - format a message into a buffer. Like vsprintf except we 147601c855caSPeter Wemm * also specify the length of the output buffer, and we handle the 147701c855caSPeter Wemm * %m (error message) format. 147801c855caSPeter Wemm * Doesn't do floating-point formats. 147901c855caSPeter Wemm * Returns the number of chars put into buf. 148001c855caSPeter Wemm */ 148101c855caSPeter Wemm #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 148201c855caSPeter Wemm 148301c855caSPeter Wemm int 148401c855caSPeter Wemm vfmtmsg(buf, buflen, fmt, args) 148501c855caSPeter Wemm char *buf; 148601c855caSPeter Wemm int buflen; 148701c855caSPeter Wemm const char *fmt; 148801c855caSPeter Wemm va_list args; 148901c855caSPeter Wemm { 149001c855caSPeter Wemm int c, i, n; 149101c855caSPeter Wemm int width, prec, fillch; 149201c855caSPeter Wemm int base, len, neg, quoted; 149301c855caSPeter Wemm unsigned long val = 0; 149401c855caSPeter Wemm char *str, *buf0; 149501c855caSPeter Wemm const char *f; 149601c855caSPeter Wemm unsigned char *p; 149701c855caSPeter Wemm char num[32]; 149801c855caSPeter Wemm static char hexchars[] = "0123456789abcdef"; 149901c855caSPeter Wemm 150001c855caSPeter Wemm buf0 = buf; 150101c855caSPeter Wemm --buflen; 150201c855caSPeter Wemm while (buflen > 0) { 150301c855caSPeter Wemm for (f = fmt; *f != '%' && *f != 0; ++f) 150401c855caSPeter Wemm ; 150501c855caSPeter Wemm if (f > fmt) { 150601c855caSPeter Wemm len = f - fmt; 150701c855caSPeter Wemm if (len > buflen) 150801c855caSPeter Wemm len = buflen; 150901c855caSPeter Wemm memcpy(buf, fmt, len); 151001c855caSPeter Wemm buf += len; 151101c855caSPeter Wemm buflen -= len; 151201c855caSPeter Wemm fmt = f; 151301c855caSPeter Wemm } 151401c855caSPeter Wemm if (*fmt == 0) 151501c855caSPeter Wemm break; 151601c855caSPeter Wemm c = *++fmt; 151701c855caSPeter Wemm width = prec = 0; 151801c855caSPeter Wemm fillch = ' '; 151901c855caSPeter Wemm if (c == '0') { 152001c855caSPeter Wemm fillch = '0'; 152101c855caSPeter Wemm c = *++fmt; 152201c855caSPeter Wemm } 152301c855caSPeter Wemm if (c == '*') { 152401c855caSPeter Wemm width = va_arg(args, int); 152501c855caSPeter Wemm c = *++fmt; 152601c855caSPeter Wemm } else { 152701c855caSPeter Wemm while (isdigit(c)) { 152801c855caSPeter Wemm width = width * 10 + c - '0'; 152901c855caSPeter Wemm c = *++fmt; 153001c855caSPeter Wemm } 153101c855caSPeter Wemm } 153201c855caSPeter Wemm if (c == '.') { 153301c855caSPeter Wemm c = *++fmt; 153401c855caSPeter Wemm if (c == '*') { 153501c855caSPeter Wemm prec = va_arg(args, int); 153601c855caSPeter Wemm c = *++fmt; 153701c855caSPeter Wemm } else { 153801c855caSPeter Wemm while (isdigit(c)) { 153901c855caSPeter Wemm prec = prec * 10 + c - '0'; 154001c855caSPeter Wemm c = *++fmt; 154101c855caSPeter Wemm } 154201c855caSPeter Wemm } 154301c855caSPeter Wemm } 154401c855caSPeter Wemm str = 0; 154501c855caSPeter Wemm base = 0; 154601c855caSPeter Wemm neg = 0; 154701c855caSPeter Wemm ++fmt; 154801c855caSPeter Wemm switch (c) { 154901c855caSPeter Wemm case 'd': 155001c855caSPeter Wemm i = va_arg(args, int); 155101c855caSPeter Wemm if (i < 0) { 155201c855caSPeter Wemm neg = 1; 155301c855caSPeter Wemm val = -i; 155401c855caSPeter Wemm } else 155501c855caSPeter Wemm val = i; 155601c855caSPeter Wemm base = 10; 155701c855caSPeter Wemm break; 155801c855caSPeter Wemm case 'o': 155901c855caSPeter Wemm val = va_arg(args, unsigned int); 156001c855caSPeter Wemm base = 8; 156101c855caSPeter Wemm break; 156201c855caSPeter Wemm case 'x': 156301c855caSPeter Wemm val = va_arg(args, unsigned int); 156401c855caSPeter Wemm base = 16; 156501c855caSPeter Wemm break; 156601c855caSPeter Wemm case 'p': 156701c855caSPeter Wemm val = (unsigned long) va_arg(args, void *); 156801c855caSPeter Wemm base = 16; 156901c855caSPeter Wemm neg = 2; 157001c855caSPeter Wemm break; 157101c855caSPeter Wemm case 's': 157201c855caSPeter Wemm str = va_arg(args, char *); 157301c855caSPeter Wemm break; 157401c855caSPeter Wemm case 'c': 157501c855caSPeter Wemm num[0] = va_arg(args, int); 157601c855caSPeter Wemm num[1] = 0; 157701c855caSPeter Wemm str = num; 157801c855caSPeter Wemm break; 157901c855caSPeter Wemm case 'm': 158001c855caSPeter Wemm str = strerror(errno); 158101c855caSPeter Wemm break; 158201c855caSPeter Wemm case 'v': /* "visible" string */ 158301c855caSPeter Wemm case 'q': /* quoted string */ 158401c855caSPeter Wemm quoted = c == 'q'; 158501c855caSPeter Wemm p = va_arg(args, unsigned char *); 158601c855caSPeter Wemm if (fillch == '0' && prec > 0) { 158701c855caSPeter Wemm n = prec; 158801c855caSPeter Wemm } else { 158901c855caSPeter Wemm n = strlen((char *)p); 159001c855caSPeter Wemm if (prec > 0 && prec < n) 159101c855caSPeter Wemm n = prec; 159201c855caSPeter Wemm } 159301c855caSPeter Wemm while (n > 0 && buflen > 0) { 159401c855caSPeter Wemm c = *p++; 159501c855caSPeter Wemm --n; 159601c855caSPeter Wemm if (!quoted && c >= 0x80) { 159701c855caSPeter Wemm OUTCHAR('M'); 159801c855caSPeter Wemm OUTCHAR('-'); 159901c855caSPeter Wemm c -= 0x80; 160001c855caSPeter Wemm } 160101c855caSPeter Wemm if (quoted && (c == '"' || c == '\\')) 160201c855caSPeter Wemm OUTCHAR('\\'); 160301c855caSPeter Wemm if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 160401c855caSPeter Wemm if (quoted) { 160501c855caSPeter Wemm OUTCHAR('\\'); 160601c855caSPeter Wemm switch (c) { 160701c855caSPeter Wemm case '\t': OUTCHAR('t'); break; 160801c855caSPeter Wemm case '\n': OUTCHAR('n'); break; 160901c855caSPeter Wemm case '\b': OUTCHAR('b'); break; 161001c855caSPeter Wemm case '\f': OUTCHAR('f'); break; 161101c855caSPeter Wemm default: 161201c855caSPeter Wemm OUTCHAR('x'); 161301c855caSPeter Wemm OUTCHAR(hexchars[c >> 4]); 161401c855caSPeter Wemm OUTCHAR(hexchars[c & 0xf]); 161501c855caSPeter Wemm } 161601c855caSPeter Wemm } else { 161701c855caSPeter Wemm if (c == '\t') 161801c855caSPeter Wemm OUTCHAR(c); 161901c855caSPeter Wemm else { 162001c855caSPeter Wemm OUTCHAR('^'); 162101c855caSPeter Wemm OUTCHAR(c ^ 0x40); 162201c855caSPeter Wemm } 162301c855caSPeter Wemm } 162401c855caSPeter Wemm } else 162501c855caSPeter Wemm OUTCHAR(c); 162601c855caSPeter Wemm } 162701c855caSPeter Wemm continue; 162801c855caSPeter Wemm default: 162901c855caSPeter Wemm *buf++ = '%'; 163001c855caSPeter Wemm if (c != '%') 163101c855caSPeter Wemm --fmt; /* so %z outputs %z etc. */ 163201c855caSPeter Wemm --buflen; 163301c855caSPeter Wemm continue; 163401c855caSPeter Wemm } 163501c855caSPeter Wemm if (base != 0) { 163601c855caSPeter Wemm str = num + sizeof(num); 163701c855caSPeter Wemm *--str = 0; 163801c855caSPeter Wemm while (str > num + neg) { 163901c855caSPeter Wemm *--str = hexchars[val % base]; 164001c855caSPeter Wemm val = val / base; 164101c855caSPeter Wemm if (--prec <= 0 && val == 0) 164201c855caSPeter Wemm break; 164301c855caSPeter Wemm } 164401c855caSPeter Wemm switch (neg) { 164501c855caSPeter Wemm case 1: 164601c855caSPeter Wemm *--str = '-'; 164701c855caSPeter Wemm break; 164801c855caSPeter Wemm case 2: 164901c855caSPeter Wemm *--str = 'x'; 165001c855caSPeter Wemm *--str = '0'; 165101c855caSPeter Wemm break; 165201c855caSPeter Wemm } 165301c855caSPeter Wemm len = num + sizeof(num) - 1 - str; 165401c855caSPeter Wemm } else { 165501c855caSPeter Wemm len = strlen(str); 165601c855caSPeter Wemm if (prec > 0 && len > prec) 165701c855caSPeter Wemm len = prec; 165801c855caSPeter Wemm } 165901c855caSPeter Wemm if (width > 0) { 166001c855caSPeter Wemm if (width > buflen) 166101c855caSPeter Wemm width = buflen; 166201c855caSPeter Wemm if ((n = width - len) > 0) { 166301c855caSPeter Wemm buflen -= n; 166401c855caSPeter Wemm for (; n > 0; --n) 166501c855caSPeter Wemm *buf++ = fillch; 166601c855caSPeter Wemm } 166701c855caSPeter Wemm } 166801c855caSPeter Wemm if (len > buflen) 166901c855caSPeter Wemm len = buflen; 167001c855caSPeter Wemm memcpy(buf, str, len); 167101c855caSPeter Wemm buf += len; 167201c855caSPeter Wemm buflen -= len; 167301c855caSPeter Wemm } 167401c855caSPeter Wemm *buf = 0; 167501c855caSPeter Wemm return buf - buf0; 167601c855caSPeter Wemm } 1677