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. 89f65f104SPeter Wemm * 2 - error on an I/O operation or fatal error condtion. 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 * ----------------- 179b1aec48SLars Fredriksen * 183d793cf1SPeter Wemm * Added SAY keyword to send output to stderr. 193d793cf1SPeter Wemm * This allows to turn ECHO OFF and to output specific, user selected, 203d793cf1SPeter Wemm * text to give progress messages. This best works when stderr 213d793cf1SPeter Wemm * exists (i.e.: pppd in nodetach mode). 223d793cf1SPeter Wemm * 233d793cf1SPeter Wemm * Added HANGUP directives to allow for us to be called 243d793cf1SPeter Wemm * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 253d793cf1SPeter Wemm * We rely on timeouts in that case. 263d793cf1SPeter Wemm * 273d793cf1SPeter Wemm * Added CLR_ABORT to clear previously set ABORT string. This has been 283d793cf1SPeter Wemm * dictated by the HANGUP above as "NO CARRIER" (for example) must be 293d793cf1SPeter Wemm * an ABORT condition until we know the other host is going to close 303d793cf1SPeter Wemm * the connection for call back. As soon as we have completed the 313d793cf1SPeter Wemm * first stage of the call back sequence, "NO CARRIER" is a valid, non 323d793cf1SPeter Wemm * fatal string. As soon as we got called back (probably get "CONNECT"), 333d793cf1SPeter Wemm * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 343d793cf1SPeter Wemm * Note that CLR_ABORT packs the abort_strings[] array so that we do not 353d793cf1SPeter Wemm * have unused entries not being reclaimed. 363d793cf1SPeter Wemm * 373d793cf1SPeter Wemm * In the same vein as above, added CLR_REPORT keyword. 383d793cf1SPeter Wemm * 393d793cf1SPeter Wemm * Allow for comments. Line starting with '#' are comments and are 403d793cf1SPeter Wemm * ignored. If a '#' is to be expected as the first character, the 413d793cf1SPeter Wemm * expect string must be quoted. 423d793cf1SPeter Wemm * 433d793cf1SPeter Wemm * 443d793cf1SPeter Wemm * Francis Demierre <Francis@SwissMail.Com> 453d793cf1SPeter Wemm * Thu May 15 17:15:40 MET DST 1997 463d793cf1SPeter Wemm * 479b1aec48SLars Fredriksen * 489f65f104SPeter Wemm * Added -r "report file" switch & REPORT keyword. 499f65f104SPeter Wemm * Robert Geer <bgeer@xmission.com> 509f65f104SPeter Wemm * 513d793cf1SPeter Wemm * 523d793cf1SPeter Wemm * Added -e "echo" switch & ECHO keyword 533d793cf1SPeter Wemm * Dick Streefland <dicks@tasking.nl> 543d793cf1SPeter Wemm * 553d793cf1SPeter Wemm * 563d793cf1SPeter Wemm * Considerable updates and modifications by 573d793cf1SPeter Wemm * Al Longyear <longyear@pobox.com> 583d793cf1SPeter Wemm * Paul Mackerras <paulus@cs.anu.edu.au> 593d793cf1SPeter Wemm * 603d793cf1SPeter Wemm * 619b1aec48SLars Fredriksen * The original author is: 629b1aec48SLars Fredriksen * 639b1aec48SLars Fredriksen * Karl Fox <karl@MorningStar.Com> 649b1aec48SLars Fredriksen * Morning Star Technologies, Inc. 659b1aec48SLars Fredriksen * 1760 Zollinger Road 669b1aec48SLars Fredriksen * Columbus, OH 43221 679b1aec48SLars Fredriksen * (614)451-1883 689f65f104SPeter Wemm * 693d793cf1SPeter Wemm * 709b1aec48SLars Fredriksen */ 719b1aec48SLars Fredriksen 723d793cf1SPeter Wemm #ifndef lint 73d7d10053SAlexander Langer static char rcsid[] = "$Id: chat.c,v 1.9 1997/08/22 15:24:36 peter Exp $"; 743d793cf1SPeter Wemm #endif 759b1aec48SLars Fredriksen 769b1aec48SLars Fredriksen #include <stdio.h> 773d793cf1SPeter Wemm #include <ctype.h> 789f65f104SPeter Wemm #include <time.h> 799b1aec48SLars Fredriksen #include <fcntl.h> 809b1aec48SLars Fredriksen #include <signal.h> 819b1aec48SLars Fredriksen #include <errno.h> 829b1aec48SLars Fredriksen #include <string.h> 839b1aec48SLars Fredriksen #include <stdlib.h> 843d793cf1SPeter Wemm #include <unistd.h> 859b1aec48SLars Fredriksen #include <sys/types.h> 869b1aec48SLars Fredriksen #include <sys/stat.h> 879b1aec48SLars Fredriksen #include <syslog.h> 889b1aec48SLars Fredriksen 899b1aec48SLars Fredriksen #ifndef TERMIO 909b1aec48SLars Fredriksen #undef TERMIOS 919b1aec48SLars Fredriksen #define TERMIOS 929b1aec48SLars Fredriksen #endif 939b1aec48SLars Fredriksen 949b1aec48SLars Fredriksen #ifdef TERMIO 959b1aec48SLars Fredriksen #include <termio.h> 969b1aec48SLars Fredriksen #endif 979b1aec48SLars Fredriksen #ifdef TERMIOS 989b1aec48SLars Fredriksen #include <termios.h> 999b1aec48SLars Fredriksen #endif 1009b1aec48SLars Fredriksen 1019b1aec48SLars Fredriksen #define STR_LEN 1024 1029b1aec48SLars Fredriksen 1039b1aec48SLars Fredriksen #ifndef SIGTYPE 1049b1aec48SLars Fredriksen #define SIGTYPE void 1059b1aec48SLars Fredriksen #endif 1069b1aec48SLars Fredriksen 1079b1aec48SLars Fredriksen #ifdef __STDC__ 1089b1aec48SLars Fredriksen #undef __P 1099b1aec48SLars Fredriksen #define __P(x) x 1109b1aec48SLars Fredriksen #else 1119b1aec48SLars Fredriksen #define __P(x) () 1129b1aec48SLars Fredriksen #define const 1139b1aec48SLars Fredriksen #endif 1149b1aec48SLars Fredriksen 1159f65f104SPeter Wemm #ifndef O_NONBLOCK 1169f65f104SPeter Wemm #define O_NONBLOCK O_NDELAY 1179f65f104SPeter Wemm #endif 1189f65f104SPeter Wemm 1199b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1209b1aec48SLars Fredriksen #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1219b1aec48SLars Fredriksen (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1229b1aec48SLars Fredriksen &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1239b1aec48SLars Fredriksen #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1249b1aec48SLars Fredriksen (_O=4,(char*)0):(char*)0) 1259b1aec48SLars Fredriksen #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1269b1aec48SLars Fredriksen #define ARG(c,v) (c?(--c,*v++):(char*)0) 1279b1aec48SLars Fredriksen 1289b1aec48SLars Fredriksen static int _O = 0; /* Internal state */ 1299b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1309b1aec48SLars Fredriksen 1319b1aec48SLars Fredriksen #define MAX_ABORTS 50 1329f65f104SPeter Wemm #define MAX_REPORTS 50 1339b1aec48SLars Fredriksen #define DEFAULT_CHAT_TIMEOUT 45 1349b1aec48SLars Fredriksen 1353d793cf1SPeter Wemm int echo = 0; 1369b1aec48SLars Fredriksen int verbose = 0; 1373d793cf1SPeter Wemm int Verbose = 0; 1389b1aec48SLars Fredriksen int quiet = 0; 1399f65f104SPeter Wemm int report = 0; 1409f65f104SPeter Wemm int exit_code = 0; 1419f65f104SPeter Wemm FILE* report_fp = (FILE *) 0; 1429f65f104SPeter Wemm char *report_file = (char *) 0; 1439b1aec48SLars Fredriksen char *chat_file = (char *) 0; 1449b1aec48SLars Fredriksen int timeout = DEFAULT_CHAT_TIMEOUT; 1459b1aec48SLars Fredriksen 1469b1aec48SLars Fredriksen int have_tty_parameters = 0; 1479f65f104SPeter Wemm 1489b1aec48SLars Fredriksen #ifdef TERMIO 1499f65f104SPeter Wemm #define term_parms struct termio 1509f65f104SPeter Wemm #define get_term_param(param) ioctl(0, TCGETA, param) 1519f65f104SPeter Wemm #define set_term_param(param) ioctl(0, TCSETA, param) 1529b1aec48SLars Fredriksen struct termio saved_tty_parameters; 1539b1aec48SLars Fredriksen #endif 1549f65f104SPeter Wemm 1559b1aec48SLars Fredriksen #ifdef TERMIOS 1569f65f104SPeter Wemm #define term_parms struct termios 1579f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param) 1589f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param) 1599b1aec48SLars Fredriksen struct termios saved_tty_parameters; 1609b1aec48SLars Fredriksen #endif 1619b1aec48SLars Fredriksen 1629b1aec48SLars Fredriksen char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1639b1aec48SLars Fredriksen fail_buffer[50]; 1643d793cf1SPeter Wemm int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 1653d793cf1SPeter Wemm int clear_abort_next = 0; 1669b1aec48SLars Fredriksen 1679f65f104SPeter Wemm char *report_string[MAX_REPORTS] ; 1689f65f104SPeter Wemm char report_buffer[50] ; 1699f65f104SPeter Wemm int n_reports = 0, report_next = 0, report_gathering = 0 ; 1703d793cf1SPeter Wemm int clear_report_next = 0; 1713d793cf1SPeter Wemm 1723d793cf1SPeter Wemm int say_next = 0, hup_next = 0; 1739f65f104SPeter Wemm 1749b1aec48SLars Fredriksen void *dup_mem __P((void *b, size_t c)); 1759b1aec48SLars Fredriksen void *copy_of __P((char *s)); 176afaeb553SPhilippe Charnier static void usage __P((void)); 1779b1aec48SLars Fredriksen void logf __P((const char *str)); 1789b1aec48SLars Fredriksen void logflush __P((void)); 1799b1aec48SLars Fredriksen void fatal __P((const char *msg)); 1809b1aec48SLars Fredriksen void sysfatal __P((const char *msg)); 1819b1aec48SLars Fredriksen SIGTYPE sigalrm __P((int signo)); 1829b1aec48SLars Fredriksen SIGTYPE sigint __P((int signo)); 1839b1aec48SLars Fredriksen SIGTYPE sigterm __P((int signo)); 1849b1aec48SLars Fredriksen SIGTYPE sighup __P((int signo)); 1859b1aec48SLars Fredriksen void unalarm __P((void)); 1869b1aec48SLars Fredriksen void init __P((void)); 1879b1aec48SLars Fredriksen void set_tty_parameters __P((void)); 1883d793cf1SPeter Wemm void echo_stderr __P((int)); 1899b1aec48SLars Fredriksen void break_sequence __P((void)); 1909b1aec48SLars Fredriksen void terminate __P((int status)); 1919b1aec48SLars Fredriksen void do_file __P((char *chat_file)); 1929b1aec48SLars Fredriksen int get_string __P((register char *string)); 1939b1aec48SLars Fredriksen int put_string __P((register char *s)); 1949b1aec48SLars Fredriksen int write_char __P((int c)); 1959f65f104SPeter Wemm int put_char __P((int c)); 1969b1aec48SLars Fredriksen int get_char __P((void)); 1979b1aec48SLars Fredriksen void chat_send __P((register char *s)); 1989f65f104SPeter Wemm char *character __P((int c)); 1999b1aec48SLars Fredriksen void chat_expect __P((register char *s)); 2009b1aec48SLars Fredriksen char *clean __P((register char *s, int sending)); 2019b1aec48SLars Fredriksen void break_sequence __P((void)); 2029b1aec48SLars Fredriksen void terminate __P((int status)); 2039b1aec48SLars Fredriksen void die __P((void)); 2043d793cf1SPeter Wemm void pack_array __P((char **array, int end)); 2053d793cf1SPeter Wemm char *expect_strtok __P((char *, char *)); 2063d793cf1SPeter Wemm 2073d793cf1SPeter Wemm int main __P((int, char *[])); 2089b1aec48SLars Fredriksen 2099b1aec48SLars Fredriksen void *dup_mem(b, c) 2109b1aec48SLars Fredriksen void *b; 2119b1aec48SLars Fredriksen size_t c; 2129b1aec48SLars Fredriksen { 2139b1aec48SLars Fredriksen void *ans = malloc (c); 2149b1aec48SLars Fredriksen if (!ans) 2159f65f104SPeter Wemm { 2169b1aec48SLars Fredriksen fatal ("memory error!\n"); 2179f65f104SPeter Wemm } 2189b1aec48SLars Fredriksen memcpy (ans, b, c); 2199b1aec48SLars Fredriksen return ans; 2209b1aec48SLars Fredriksen } 2219b1aec48SLars Fredriksen 2229b1aec48SLars Fredriksen void *copy_of (s) 2239b1aec48SLars Fredriksen char *s; 2249b1aec48SLars Fredriksen { 2259b1aec48SLars Fredriksen return dup_mem (s, strlen (s) + 1); 2269b1aec48SLars Fredriksen } 2279b1aec48SLars Fredriksen 2289b1aec48SLars Fredriksen /* 2299f65f104SPeter Wemm * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \ 2309b1aec48SLars Fredriksen * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2319b1aec48SLars Fredriksen * 2329b1aec48SLars Fredriksen * Perform a UUCP-dialer-like chat script on stdin and stdout. 2339b1aec48SLars Fredriksen */ 2349b1aec48SLars Fredriksen int 2359b1aec48SLars Fredriksen main(argc, argv) 2369b1aec48SLars Fredriksen int argc; 2379b1aec48SLars Fredriksen char **argv; 2389b1aec48SLars Fredriksen { 2399b1aec48SLars Fredriksen int option; 2409b1aec48SLars Fredriksen char *arg; 2419b1aec48SLars Fredriksen 2429f65f104SPeter Wemm tzset(); 2439b1aec48SLars Fredriksen 2443d793cf1SPeter Wemm while ((option = OPTION(argc, argv)) != 0) 2459f65f104SPeter Wemm { 2469b1aec48SLars Fredriksen switch (option) 2479b1aec48SLars Fredriksen { 2483d793cf1SPeter Wemm case 'e': 2493d793cf1SPeter Wemm ++echo; 2503d793cf1SPeter Wemm break; 2513d793cf1SPeter Wemm 2529b1aec48SLars Fredriksen case 'v': 2539b1aec48SLars Fredriksen ++verbose; 2549b1aec48SLars Fredriksen break; 2559b1aec48SLars Fredriksen 2563d793cf1SPeter Wemm case 'V': 2573d793cf1SPeter Wemm ++Verbose; 2583d793cf1SPeter Wemm break; 2593d793cf1SPeter Wemm 2609b1aec48SLars Fredriksen case 'f': 2613d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 2629f65f104SPeter Wemm { 2639b1aec48SLars Fredriksen chat_file = copy_of(arg); 2649f65f104SPeter Wemm } 2659b1aec48SLars Fredriksen else 2669f65f104SPeter Wemm { 2679b1aec48SLars Fredriksen usage(); 2689f65f104SPeter Wemm } 2699b1aec48SLars Fredriksen break; 2709b1aec48SLars Fredriksen 2719b1aec48SLars Fredriksen case 't': 2723d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 2739f65f104SPeter Wemm { 2749b1aec48SLars Fredriksen timeout = atoi(arg); 2759f65f104SPeter Wemm } 2769b1aec48SLars Fredriksen else 2779f65f104SPeter Wemm { 2789b1aec48SLars Fredriksen usage(); 2799f65f104SPeter Wemm } 2809f65f104SPeter Wemm break; 2819b1aec48SLars Fredriksen 2829f65f104SPeter Wemm case 'r': 2839f65f104SPeter Wemm arg = OPTARG (argc, argv); 2849f65f104SPeter Wemm if (arg) 2859f65f104SPeter Wemm { 2869f65f104SPeter Wemm if (report_fp != NULL) 2879f65f104SPeter Wemm { 2889f65f104SPeter Wemm fclose (report_fp); 2899f65f104SPeter Wemm } 2909f65f104SPeter Wemm report_file = copy_of (arg); 2919f65f104SPeter Wemm report_fp = fopen (report_file, "a"); 2929f65f104SPeter Wemm if (report_fp != NULL) 2939f65f104SPeter Wemm { 2949f65f104SPeter Wemm if (verbose) 2959f65f104SPeter Wemm { 2969f65f104SPeter Wemm fprintf (report_fp, "Opening \"%s\"...\n", 2979f65f104SPeter Wemm report_file); 2989f65f104SPeter Wemm } 2999f65f104SPeter Wemm report = 1; 3009f65f104SPeter Wemm } 3019f65f104SPeter Wemm } 3029b1aec48SLars Fredriksen break; 3039b1aec48SLars Fredriksen 3049b1aec48SLars Fredriksen default: 3059b1aec48SLars Fredriksen usage(); 3069f65f104SPeter Wemm break; 3079f65f104SPeter Wemm } 3089f65f104SPeter Wemm } 3099f65f104SPeter Wemm /* 3109f65f104SPeter Wemm * Default the report file to the stderr location 3119f65f104SPeter Wemm */ 3129f65f104SPeter Wemm if (report_fp == NULL) 3139f65f104SPeter Wemm { 3149f65f104SPeter Wemm report_fp = stderr; 3159b1aec48SLars Fredriksen } 3169b1aec48SLars Fredriksen 3179b1aec48SLars Fredriksen #ifdef ultrix 3189b1aec48SLars Fredriksen openlog("chat", LOG_PID); 3199b1aec48SLars Fredriksen #else 3209b1aec48SLars Fredriksen openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3219b1aec48SLars Fredriksen 3229f65f104SPeter Wemm if (verbose) 3239f65f104SPeter Wemm { 3249b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_INFO)); 3259f65f104SPeter Wemm } 3269f65f104SPeter Wemm else 3279f65f104SPeter Wemm { 3289b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_WARNING)); 3299b1aec48SLars Fredriksen } 3309b1aec48SLars Fredriksen #endif 3319b1aec48SLars Fredriksen 3329b1aec48SLars Fredriksen init(); 3339b1aec48SLars Fredriksen 3349b1aec48SLars Fredriksen if (chat_file != NULL) 3359b1aec48SLars Fredriksen { 3369b1aec48SLars Fredriksen arg = ARG(argc, argv); 3379b1aec48SLars Fredriksen if (arg != NULL) 3389f65f104SPeter Wemm { 3399b1aec48SLars Fredriksen usage(); 3409f65f104SPeter Wemm } 3419b1aec48SLars Fredriksen else 3429f65f104SPeter Wemm { 3439b1aec48SLars Fredriksen do_file (chat_file); 3449b1aec48SLars Fredriksen } 3459f65f104SPeter Wemm } 3469b1aec48SLars Fredriksen else 3479b1aec48SLars Fredriksen { 3483d793cf1SPeter Wemm while ((arg = ARG(argc, argv)) != NULL) 3499b1aec48SLars Fredriksen { 3509b1aec48SLars Fredriksen chat_expect(arg); 3519b1aec48SLars Fredriksen 3523d793cf1SPeter Wemm if ((arg = ARG(argc, argv)) != NULL) 3539f65f104SPeter Wemm { 3549b1aec48SLars Fredriksen chat_send(arg); 3559b1aec48SLars Fredriksen } 3569b1aec48SLars Fredriksen } 3579f65f104SPeter Wemm } 3589b1aec48SLars Fredriksen 3599b1aec48SLars Fredriksen terminate(0); 3603d793cf1SPeter Wemm return 0; 3619b1aec48SLars Fredriksen } 3629b1aec48SLars Fredriksen 3639b1aec48SLars Fredriksen /* 3649b1aec48SLars Fredriksen * Process a chat script when read from a file. 3659b1aec48SLars Fredriksen */ 3669b1aec48SLars Fredriksen 3679b1aec48SLars Fredriksen void do_file (chat_file) 3689b1aec48SLars Fredriksen char *chat_file; 3699b1aec48SLars Fredriksen { 370d7d10053SAlexander Langer int linect, sendflg; 3719b1aec48SLars Fredriksen char *sp, *arg, quote; 3729b1aec48SLars Fredriksen char buf [STR_LEN]; 3739b1aec48SLars Fredriksen FILE *cfp; 3749b1aec48SLars Fredriksen 3759f65f104SPeter Wemm cfp = fopen (chat_file, "r"); 3769f65f104SPeter Wemm if (cfp == NULL) 3779b1aec48SLars Fredriksen { 3789b1aec48SLars Fredriksen syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 3799b1aec48SLars Fredriksen terminate (1); 3809b1aec48SLars Fredriksen } 3819b1aec48SLars Fredriksen 3829b1aec48SLars Fredriksen linect = 0; 3839b1aec48SLars Fredriksen sendflg = 0; 3849b1aec48SLars Fredriksen 3859b1aec48SLars Fredriksen while (fgets(buf, STR_LEN, cfp) != NULL) 3869b1aec48SLars Fredriksen { 3879b1aec48SLars Fredriksen sp = strchr (buf, '\n'); 3889b1aec48SLars Fredriksen if (sp) 3899f65f104SPeter Wemm { 3909b1aec48SLars Fredriksen *sp = '\0'; 3919f65f104SPeter Wemm } 3929b1aec48SLars Fredriksen 3939b1aec48SLars Fredriksen linect++; 3949b1aec48SLars Fredriksen sp = buf; 3953d793cf1SPeter Wemm 3963d793cf1SPeter Wemm /* lines starting with '#' are comments. If a real '#' 3973d793cf1SPeter Wemm is to be expected, it should be quoted .... */ 3983d793cf1SPeter Wemm if ( *sp == '#' ) continue; 3993d793cf1SPeter Wemm 4009b1aec48SLars Fredriksen while (*sp != '\0') 4019b1aec48SLars Fredriksen { 4029b1aec48SLars Fredriksen if (*sp == ' ' || *sp == '\t') 4039b1aec48SLars Fredriksen { 4049b1aec48SLars Fredriksen ++sp; 4059b1aec48SLars Fredriksen continue; 4069b1aec48SLars Fredriksen } 4079b1aec48SLars Fredriksen 4089b1aec48SLars Fredriksen if (*sp == '"' || *sp == '\'') 4099b1aec48SLars Fredriksen { 4109b1aec48SLars Fredriksen quote = *sp++; 4119b1aec48SLars Fredriksen arg = sp; 4129b1aec48SLars Fredriksen while (*sp != quote) 4139b1aec48SLars Fredriksen { 4149b1aec48SLars Fredriksen if (*sp == '\0') 4159b1aec48SLars Fredriksen { 4169b1aec48SLars Fredriksen syslog (LOG_ERR, "unterminated quote (line %d)", 4179b1aec48SLars Fredriksen linect); 4189b1aec48SLars Fredriksen terminate (1); 4199b1aec48SLars Fredriksen } 4209b1aec48SLars Fredriksen 4219b1aec48SLars Fredriksen if (*sp++ == '\\') 4229f65f104SPeter Wemm { 4239b1aec48SLars Fredriksen if (*sp != '\0') 4249f65f104SPeter Wemm { 4259b1aec48SLars Fredriksen ++sp; 4269b1aec48SLars Fredriksen } 4279b1aec48SLars Fredriksen } 4289f65f104SPeter Wemm } 4299f65f104SPeter Wemm } 4309b1aec48SLars Fredriksen else 4319b1aec48SLars Fredriksen { 4329b1aec48SLars Fredriksen arg = sp; 4339b1aec48SLars Fredriksen while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4349f65f104SPeter Wemm { 4359b1aec48SLars Fredriksen ++sp; 4369b1aec48SLars Fredriksen } 4379f65f104SPeter Wemm } 4389b1aec48SLars Fredriksen 4399b1aec48SLars Fredriksen if (*sp != '\0') 4409f65f104SPeter Wemm { 4419b1aec48SLars Fredriksen *sp++ = '\0'; 4429f65f104SPeter Wemm } 4439b1aec48SLars Fredriksen 4449b1aec48SLars Fredriksen if (sendflg) 4459b1aec48SLars Fredriksen { 4469b1aec48SLars Fredriksen chat_send (arg); 4479b1aec48SLars Fredriksen } 4489b1aec48SLars Fredriksen else 4499b1aec48SLars Fredriksen { 4509b1aec48SLars Fredriksen chat_expect (arg); 4519b1aec48SLars Fredriksen } 4529b1aec48SLars Fredriksen sendflg = !sendflg; 4539b1aec48SLars Fredriksen } 4549b1aec48SLars Fredriksen } 4559b1aec48SLars Fredriksen fclose (cfp); 4569b1aec48SLars Fredriksen } 4579b1aec48SLars Fredriksen 4589b1aec48SLars Fredriksen /* 4599b1aec48SLars Fredriksen * We got an error parsing the command line. 4609b1aec48SLars Fredriksen */ 461afaeb553SPhilippe Charnier static void 462afaeb553SPhilippe Charnier usage() 4639b1aec48SLars Fredriksen { 464afaeb553SPhilippe Charnier fprintf(stderr, "%s %s\n", 4653d793cf1SPeter Wemm "usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file]", 466afaeb553SPhilippe Charnier "{-f chat-file | chat-script}"); 4679b1aec48SLars Fredriksen exit(1); 4689b1aec48SLars Fredriksen } 4699b1aec48SLars Fredriksen 4709b1aec48SLars Fredriksen char line[256]; 4719b1aec48SLars Fredriksen char *p; 4729b1aec48SLars Fredriksen 4739b1aec48SLars Fredriksen void logf (str) 4749b1aec48SLars Fredriksen const char *str; 4759b1aec48SLars Fredriksen { 4763d793cf1SPeter Wemm int l = strlen(line); 4779b1aec48SLars Fredriksen 4783d793cf1SPeter Wemm if (l + strlen(str) >= sizeof(line)) { 4793d793cf1SPeter Wemm syslog(LOG_INFO, "%s", line); 4803d793cf1SPeter Wemm l = 0; 4813d793cf1SPeter Wemm } 4823d793cf1SPeter Wemm strcpy(line + l, str); 4833d793cf1SPeter Wemm 4843d793cf1SPeter Wemm if (str[strlen(str)-1] == '\n') { 4859b1aec48SLars Fredriksen syslog (LOG_INFO, "%s", line); 4869b1aec48SLars Fredriksen line[0] = 0; 4879b1aec48SLars Fredriksen } 4889b1aec48SLars Fredriksen } 4899b1aec48SLars Fredriksen 4909b1aec48SLars Fredriksen void logflush() 4919b1aec48SLars Fredriksen { 4929b1aec48SLars Fredriksen if (line[0] != 0) 4939b1aec48SLars Fredriksen { 4949b1aec48SLars Fredriksen syslog(LOG_INFO, "%s", line); 4959b1aec48SLars Fredriksen line[0] = 0; 4969b1aec48SLars Fredriksen } 4979b1aec48SLars Fredriksen } 4989b1aec48SLars Fredriksen 4999b1aec48SLars Fredriksen /* 5009f65f104SPeter Wemm * Terminate with an error. 5019b1aec48SLars Fredriksen */ 5029b1aec48SLars Fredriksen void die() 5039b1aec48SLars Fredriksen { 5049b1aec48SLars Fredriksen terminate(1); 5059b1aec48SLars Fredriksen } 5069b1aec48SLars Fredriksen 5079b1aec48SLars Fredriksen /* 5089b1aec48SLars Fredriksen * Print an error message and terminate. 5099b1aec48SLars Fredriksen */ 5109b1aec48SLars Fredriksen 5119b1aec48SLars Fredriksen void fatal (msg) 5129b1aec48SLars Fredriksen const char *msg; 5139b1aec48SLars Fredriksen { 5149b1aec48SLars Fredriksen syslog(LOG_ERR, "%s", msg); 5159f65f104SPeter Wemm terminate(2); 5169b1aec48SLars Fredriksen } 5179b1aec48SLars Fredriksen 5189b1aec48SLars Fredriksen /* 5199b1aec48SLars Fredriksen * Print an error message along with the system error message and 5209b1aec48SLars Fredriksen * terminate. 5219b1aec48SLars Fredriksen */ 5229b1aec48SLars Fredriksen 5239b1aec48SLars Fredriksen void sysfatal (msg) 5249b1aec48SLars Fredriksen const char *msg; 5259b1aec48SLars Fredriksen { 5269b1aec48SLars Fredriksen syslog(LOG_ERR, "%s: %m", msg); 5279f65f104SPeter Wemm terminate(2); 5289b1aec48SLars Fredriksen } 5299b1aec48SLars Fredriksen 5309b1aec48SLars Fredriksen int alarmed = 0; 5319b1aec48SLars Fredriksen 5329b1aec48SLars Fredriksen SIGTYPE sigalrm(signo) 5339b1aec48SLars Fredriksen int signo; 5349b1aec48SLars Fredriksen { 5359b1aec48SLars Fredriksen int flags; 5369b1aec48SLars Fredriksen 5379b1aec48SLars Fredriksen alarm(1); 5389b1aec48SLars Fredriksen alarmed = 1; /* Reset alarm to avoid race window */ 5399b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 5409b1aec48SLars Fredriksen 5419b1aec48SLars Fredriksen logflush(); 5429b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 5439f65f104SPeter Wemm { 5449b1aec48SLars Fredriksen sysfatal("Can't get file mode flags on stdin"); 5459f65f104SPeter Wemm } 5469b1aec48SLars Fredriksen else 5479f65f104SPeter Wemm { 5489f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 5499f65f104SPeter Wemm { 5509b1aec48SLars Fredriksen sysfatal("Can't set file mode flags on stdin"); 5519f65f104SPeter Wemm } 5529f65f104SPeter Wemm } 5539b1aec48SLars Fredriksen 5549b1aec48SLars Fredriksen if (verbose) 5559b1aec48SLars Fredriksen { 5569b1aec48SLars Fredriksen syslog(LOG_INFO, "alarm"); 5579b1aec48SLars Fredriksen } 5589b1aec48SLars Fredriksen } 5599b1aec48SLars Fredriksen 5609b1aec48SLars Fredriksen void unalarm() 5619b1aec48SLars Fredriksen { 5629b1aec48SLars Fredriksen int flags; 5639b1aec48SLars Fredriksen 5649b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 5659f65f104SPeter Wemm { 5669b1aec48SLars Fredriksen sysfatal("Can't get file mode flags on stdin"); 5679f65f104SPeter Wemm } 5689b1aec48SLars Fredriksen else 5699f65f104SPeter Wemm { 5709f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 5719f65f104SPeter Wemm { 5729b1aec48SLars Fredriksen sysfatal("Can't set file mode flags on stdin"); 5739b1aec48SLars Fredriksen } 5749f65f104SPeter Wemm } 5759f65f104SPeter Wemm } 5769b1aec48SLars Fredriksen 5779b1aec48SLars Fredriksen SIGTYPE sigint(signo) 5789b1aec48SLars Fredriksen int signo; 5799b1aec48SLars Fredriksen { 5809b1aec48SLars Fredriksen fatal("SIGINT"); 5819b1aec48SLars Fredriksen } 5829b1aec48SLars Fredriksen 5839b1aec48SLars Fredriksen SIGTYPE sigterm(signo) 5849b1aec48SLars Fredriksen int signo; 5859b1aec48SLars Fredriksen { 5869b1aec48SLars Fredriksen fatal("SIGTERM"); 5879b1aec48SLars Fredriksen } 5889b1aec48SLars Fredriksen 5899b1aec48SLars Fredriksen SIGTYPE sighup(signo) 5909b1aec48SLars Fredriksen int signo; 5919b1aec48SLars Fredriksen { 5929b1aec48SLars Fredriksen fatal("SIGHUP"); 5939b1aec48SLars Fredriksen } 5949b1aec48SLars Fredriksen 5959b1aec48SLars Fredriksen void init() 5969b1aec48SLars Fredriksen { 5979b1aec48SLars Fredriksen signal(SIGINT, sigint); 5989b1aec48SLars Fredriksen signal(SIGTERM, sigterm); 5999b1aec48SLars Fredriksen signal(SIGHUP, sighup); 6009b1aec48SLars Fredriksen 6019b1aec48SLars Fredriksen set_tty_parameters(); 6029b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); 6039b1aec48SLars Fredriksen alarm(0); 6049b1aec48SLars Fredriksen alarmed = 0; 6059b1aec48SLars Fredriksen } 6069b1aec48SLars Fredriksen 6079b1aec48SLars Fredriksen void set_tty_parameters() 6089b1aec48SLars Fredriksen { 6099f65f104SPeter Wemm #if defined(get_term_param) 6109f65f104SPeter Wemm term_parms t; 6119b1aec48SLars Fredriksen 6129f65f104SPeter Wemm if (get_term_param (&t) < 0) 6139f65f104SPeter Wemm { 61439746e46SJohn-Mark Gurney have_tty_parameters = 0; 61539746e46SJohn-Mark Gurney return; 6169f65f104SPeter Wemm } 6179b1aec48SLars Fredriksen 6189b1aec48SLars Fredriksen saved_tty_parameters = t; 6199b1aec48SLars Fredriksen have_tty_parameters = 1; 6209b1aec48SLars Fredriksen 6219b1aec48SLars Fredriksen t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 6229b1aec48SLars Fredriksen t.c_oflag = 0; 6239b1aec48SLars Fredriksen t.c_lflag = 0; 6249f65f104SPeter Wemm t.c_cc[VERASE] = 6259f65f104SPeter Wemm t.c_cc[VKILL] = 0; 6269b1aec48SLars Fredriksen t.c_cc[VMIN] = 1; 6279b1aec48SLars Fredriksen t.c_cc[VTIME] = 0; 6289b1aec48SLars Fredriksen 6299f65f104SPeter Wemm if (set_term_param (&t) < 0) 6309f65f104SPeter Wemm { 6319b1aec48SLars Fredriksen sysfatal("Can't set terminal parameters"); 6329f65f104SPeter Wemm } 6339b1aec48SLars Fredriksen #endif 6349b1aec48SLars Fredriksen } 6359b1aec48SLars Fredriksen 6369b1aec48SLars Fredriksen void break_sequence() 6379b1aec48SLars Fredriksen { 6389b1aec48SLars Fredriksen #ifdef TERMIOS 6399b1aec48SLars Fredriksen tcsendbreak (0, 0); 6409b1aec48SLars Fredriksen #endif 6419b1aec48SLars Fredriksen } 6429b1aec48SLars Fredriksen 6439b1aec48SLars Fredriksen void terminate(status) 6449b1aec48SLars Fredriksen int status; 6459b1aec48SLars Fredriksen { 6463d793cf1SPeter Wemm echo_stderr(-1); 6479f65f104SPeter Wemm if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 6489f65f104SPeter Wemm { 6493d793cf1SPeter Wemm /* 6503d793cf1SPeter Wemm * Allow the last of the report string to be gathered before we terminate. 6513d793cf1SPeter Wemm */ 6523d793cf1SPeter Wemm if (report_gathering) { 6533d793cf1SPeter Wemm int c, rep_len; 6543d793cf1SPeter Wemm 6553d793cf1SPeter Wemm rep_len = strlen(report_buffer); 6563d793cf1SPeter Wemm while (rep_len + 1 <= sizeof(report_buffer)) { 6573d793cf1SPeter Wemm alarm(1); 6583d793cf1SPeter Wemm c = get_char(); 6593d793cf1SPeter Wemm alarm(0); 6603d793cf1SPeter Wemm if (c < 0 || iscntrl(c)) 6613d793cf1SPeter Wemm break; 6623d793cf1SPeter Wemm report_buffer[rep_len] = c; 6633d793cf1SPeter Wemm ++rep_len; 6643d793cf1SPeter Wemm } 6653d793cf1SPeter Wemm report_buffer[rep_len] = 0; 6663d793cf1SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 6673d793cf1SPeter Wemm } 6689f65f104SPeter Wemm if (verbose) 6699f65f104SPeter Wemm { 6709f65f104SPeter Wemm fprintf (report_fp, "Closing \"%s\".\n", report_file); 6719f65f104SPeter Wemm } 6729f65f104SPeter Wemm fclose (report_fp); 6739f65f104SPeter Wemm report_fp = (FILE *) NULL; 6749f65f104SPeter Wemm } 6759f65f104SPeter Wemm 6769f65f104SPeter Wemm #if defined(get_term_param) 6779f65f104SPeter Wemm if (have_tty_parameters) 6789f65f104SPeter Wemm { 6799f65f104SPeter Wemm if (set_term_param (&saved_tty_parameters) < 0) 6809f65f104SPeter Wemm { 6819b1aec48SLars Fredriksen syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 6829b1aec48SLars Fredriksen exit(1); 6839b1aec48SLars Fredriksen } 6849f65f104SPeter Wemm } 6859f65f104SPeter Wemm #endif 6869f65f104SPeter Wemm 6879b1aec48SLars Fredriksen exit(status); 6889b1aec48SLars Fredriksen } 6899b1aec48SLars Fredriksen 6909b1aec48SLars Fredriksen /* 6919b1aec48SLars Fredriksen * 'Clean up' this string. 6929b1aec48SLars Fredriksen */ 6939b1aec48SLars Fredriksen char *clean(s, sending) 6949b1aec48SLars Fredriksen register char *s; 6959b1aec48SLars Fredriksen int sending; 6969b1aec48SLars Fredriksen { 6979b1aec48SLars Fredriksen char temp[STR_LEN], cur_chr; 6989b1aec48SLars Fredriksen register char *s1; 6999b1aec48SLars Fredriksen int add_return = sending; 7009b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 7019b1aec48SLars Fredriksen 7029b1aec48SLars Fredriksen s1 = temp; 7039b1aec48SLars Fredriksen while (*s) 7049b1aec48SLars Fredriksen { 7059b1aec48SLars Fredriksen cur_chr = *s++; 7069b1aec48SLars Fredriksen if (cur_chr == '^') 7079b1aec48SLars Fredriksen { 7089b1aec48SLars Fredriksen cur_chr = *s++; 7099b1aec48SLars Fredriksen if (cur_chr == '\0') 7109b1aec48SLars Fredriksen { 7119b1aec48SLars Fredriksen *s1++ = '^'; 7129b1aec48SLars Fredriksen break; 7139b1aec48SLars Fredriksen } 7149b1aec48SLars Fredriksen cur_chr &= 0x1F; 7159b1aec48SLars Fredriksen if (cur_chr != 0) 7169f65f104SPeter Wemm { 7179b1aec48SLars Fredriksen *s1++ = cur_chr; 7189f65f104SPeter Wemm } 7199b1aec48SLars Fredriksen continue; 7209b1aec48SLars Fredriksen } 7219b1aec48SLars Fredriksen 7229b1aec48SLars Fredriksen if (cur_chr != '\\') 7239b1aec48SLars Fredriksen { 7249b1aec48SLars Fredriksen *s1++ = cur_chr; 7259b1aec48SLars Fredriksen continue; 7269b1aec48SLars Fredriksen } 7279b1aec48SLars Fredriksen 7289b1aec48SLars Fredriksen cur_chr = *s++; 7299b1aec48SLars Fredriksen if (cur_chr == '\0') 7309b1aec48SLars Fredriksen { 7319b1aec48SLars Fredriksen if (sending) 7329b1aec48SLars Fredriksen { 7339b1aec48SLars Fredriksen *s1++ = '\\'; 7349b1aec48SLars Fredriksen *s1++ = '\\'; 7359b1aec48SLars Fredriksen } 7369b1aec48SLars Fredriksen break; 7379b1aec48SLars Fredriksen } 7389b1aec48SLars Fredriksen 7399b1aec48SLars Fredriksen switch (cur_chr) 7409b1aec48SLars Fredriksen { 7419b1aec48SLars Fredriksen case 'b': 7429b1aec48SLars Fredriksen *s1++ = '\b'; 7439b1aec48SLars Fredriksen break; 7449b1aec48SLars Fredriksen 7459b1aec48SLars Fredriksen case 'c': 7469b1aec48SLars Fredriksen if (sending && *s == '\0') 7479f65f104SPeter Wemm { 7489b1aec48SLars Fredriksen add_return = 0; 7499f65f104SPeter Wemm } 7509b1aec48SLars Fredriksen else 7519f65f104SPeter Wemm { 7529b1aec48SLars Fredriksen *s1++ = cur_chr; 7539f65f104SPeter Wemm } 7549b1aec48SLars Fredriksen break; 7559b1aec48SLars Fredriksen 7569b1aec48SLars Fredriksen case '\\': 7579b1aec48SLars Fredriksen case 'K': 7589b1aec48SLars Fredriksen case 'p': 7599b1aec48SLars Fredriksen case 'd': 7609b1aec48SLars Fredriksen if (sending) 7619f65f104SPeter Wemm { 7629b1aec48SLars Fredriksen *s1++ = '\\'; 7639f65f104SPeter Wemm } 7649b1aec48SLars Fredriksen 7659b1aec48SLars Fredriksen *s1++ = cur_chr; 7669b1aec48SLars Fredriksen break; 7679b1aec48SLars Fredriksen 7689b1aec48SLars Fredriksen case 'q': 7693d793cf1SPeter Wemm quiet = 1; 7709b1aec48SLars Fredriksen break; 7719b1aec48SLars Fredriksen 7729b1aec48SLars Fredriksen case 'r': 7739b1aec48SLars Fredriksen *s1++ = '\r'; 7749b1aec48SLars Fredriksen break; 7759b1aec48SLars Fredriksen 7769b1aec48SLars Fredriksen case 'n': 7779b1aec48SLars Fredriksen *s1++ = '\n'; 7789b1aec48SLars Fredriksen break; 7799b1aec48SLars Fredriksen 7809b1aec48SLars Fredriksen case 's': 7819b1aec48SLars Fredriksen *s1++ = ' '; 7829b1aec48SLars Fredriksen break; 7839b1aec48SLars Fredriksen 7849b1aec48SLars Fredriksen case 't': 7859b1aec48SLars Fredriksen *s1++ = '\t'; 7869b1aec48SLars Fredriksen break; 7879b1aec48SLars Fredriksen 7889b1aec48SLars Fredriksen case 'N': 7899b1aec48SLars Fredriksen if (sending) 7909b1aec48SLars Fredriksen { 7919b1aec48SLars Fredriksen *s1++ = '\\'; 7929b1aec48SLars Fredriksen *s1++ = '\0'; 7939b1aec48SLars Fredriksen } 7949b1aec48SLars Fredriksen else 7959f65f104SPeter Wemm { 7969b1aec48SLars Fredriksen *s1++ = 'N'; 7979f65f104SPeter Wemm } 7989b1aec48SLars Fredriksen break; 7999b1aec48SLars Fredriksen 8009b1aec48SLars Fredriksen default: 8019b1aec48SLars Fredriksen if (isoctal (cur_chr)) 8029b1aec48SLars Fredriksen { 8039b1aec48SLars Fredriksen cur_chr &= 0x07; 8049b1aec48SLars Fredriksen if (isoctal (*s)) 8059b1aec48SLars Fredriksen { 8069b1aec48SLars Fredriksen cur_chr <<= 3; 8079b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 8089b1aec48SLars Fredriksen if (isoctal (*s)) 8099b1aec48SLars Fredriksen { 8109b1aec48SLars Fredriksen cur_chr <<= 3; 8119b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 8129b1aec48SLars Fredriksen } 8139b1aec48SLars Fredriksen } 8149b1aec48SLars Fredriksen 8159b1aec48SLars Fredriksen if (cur_chr != 0 || sending) 8169b1aec48SLars Fredriksen { 8179b1aec48SLars Fredriksen if (sending && (cur_chr == '\\' || cur_chr == 0)) 8189f65f104SPeter Wemm { 8199b1aec48SLars Fredriksen *s1++ = '\\'; 8209f65f104SPeter Wemm } 8219b1aec48SLars Fredriksen *s1++ = cur_chr; 8229b1aec48SLars Fredriksen } 8239b1aec48SLars Fredriksen break; 8249b1aec48SLars Fredriksen } 8259b1aec48SLars Fredriksen 8269b1aec48SLars Fredriksen if (sending) 8279f65f104SPeter Wemm { 8289b1aec48SLars Fredriksen *s1++ = '\\'; 8299f65f104SPeter Wemm } 8309b1aec48SLars Fredriksen *s1++ = cur_chr; 8319b1aec48SLars Fredriksen break; 8329b1aec48SLars Fredriksen } 8339b1aec48SLars Fredriksen } 8349b1aec48SLars Fredriksen 8359b1aec48SLars Fredriksen if (add_return) 8369f65f104SPeter Wemm { 8379b1aec48SLars Fredriksen *s1++ = '\r'; 8389f65f104SPeter Wemm } 8399b1aec48SLars Fredriksen 8409b1aec48SLars Fredriksen *s1++ = '\0'; /* guarantee closure */ 8419b1aec48SLars Fredriksen *s1++ = '\0'; /* terminate the string */ 8429b1aec48SLars Fredriksen return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 8439b1aec48SLars Fredriksen } 8449b1aec48SLars Fredriksen 8459b1aec48SLars Fredriksen /* 8463d793cf1SPeter Wemm * A modified version of 'strtok'. This version skips \ sequences. 8473d793cf1SPeter Wemm */ 8483d793cf1SPeter Wemm 8493d793cf1SPeter Wemm char *expect_strtok (s, term) 8503d793cf1SPeter Wemm char *s, *term; 8513d793cf1SPeter Wemm { 8523d793cf1SPeter Wemm static char *str = ""; 8533d793cf1SPeter Wemm int escape_flag = 0; 8543d793cf1SPeter Wemm char *result; 8553d793cf1SPeter Wemm /* 8563d793cf1SPeter Wemm * If a string was specified then do initial processing. 8573d793cf1SPeter Wemm */ 8583d793cf1SPeter Wemm if (s) 8593d793cf1SPeter Wemm { 8603d793cf1SPeter Wemm str = s; 8613d793cf1SPeter Wemm } 8623d793cf1SPeter Wemm /* 8633d793cf1SPeter Wemm * If this is the escape flag then reset it and ignore the character. 8643d793cf1SPeter Wemm */ 8653d793cf1SPeter Wemm if (*str) 8663d793cf1SPeter Wemm { 8673d793cf1SPeter Wemm result = str; 8683d793cf1SPeter Wemm } 8693d793cf1SPeter Wemm else 8703d793cf1SPeter Wemm { 8713d793cf1SPeter Wemm result = (char *) 0; 8723d793cf1SPeter Wemm } 8733d793cf1SPeter Wemm 8743d793cf1SPeter Wemm while (*str) 8753d793cf1SPeter Wemm { 8763d793cf1SPeter Wemm if (escape_flag) 8773d793cf1SPeter Wemm { 8783d793cf1SPeter Wemm escape_flag = 0; 8793d793cf1SPeter Wemm ++str; 8803d793cf1SPeter Wemm continue; 8813d793cf1SPeter Wemm } 8823d793cf1SPeter Wemm 8833d793cf1SPeter Wemm if (*str == '\\') 8843d793cf1SPeter Wemm { 8853d793cf1SPeter Wemm ++str; 8863d793cf1SPeter Wemm escape_flag = 1; 8873d793cf1SPeter Wemm continue; 8883d793cf1SPeter Wemm } 8893d793cf1SPeter Wemm /* 8903d793cf1SPeter Wemm * If this is not in the termination string, continue. 8913d793cf1SPeter Wemm */ 8923d793cf1SPeter Wemm if (strchr (term, *str) == (char *) 0) 8933d793cf1SPeter Wemm { 8943d793cf1SPeter Wemm ++str; 8953d793cf1SPeter Wemm continue; 8963d793cf1SPeter Wemm } 8973d793cf1SPeter Wemm /* 8983d793cf1SPeter Wemm * This is the terminator. Mark the end of the string and stop. 8993d793cf1SPeter Wemm */ 9003d793cf1SPeter Wemm *str++ = '\0'; 9013d793cf1SPeter Wemm break; 9023d793cf1SPeter Wemm } 9033d793cf1SPeter Wemm return (result); 9043d793cf1SPeter Wemm } 9053d793cf1SPeter Wemm 9063d793cf1SPeter Wemm /* 9079b1aec48SLars Fredriksen * Process the expect string 9089b1aec48SLars Fredriksen */ 9093d793cf1SPeter Wemm 9109b1aec48SLars Fredriksen void chat_expect (s) 9113d793cf1SPeter Wemm char *s; 9129b1aec48SLars Fredriksen { 9133d793cf1SPeter Wemm char *expect; 9143d793cf1SPeter Wemm char *reply; 9153d793cf1SPeter Wemm 9163d793cf1SPeter Wemm if (strcmp(s, "HANGUP") == 0) 9173d793cf1SPeter Wemm { 9183d793cf1SPeter Wemm ++hup_next; 9193d793cf1SPeter Wemm return; 9203d793cf1SPeter Wemm } 9213d793cf1SPeter Wemm 9229b1aec48SLars Fredriksen if (strcmp(s, "ABORT") == 0) 9239b1aec48SLars Fredriksen { 9249b1aec48SLars Fredriksen ++abort_next; 9259b1aec48SLars Fredriksen return; 9269b1aec48SLars Fredriksen } 9279b1aec48SLars Fredriksen 9283d793cf1SPeter Wemm if (strcmp(s, "CLR_ABORT") == 0) 9293d793cf1SPeter Wemm { 9303d793cf1SPeter Wemm ++clear_abort_next; 9313d793cf1SPeter Wemm return; 9323d793cf1SPeter Wemm } 9333d793cf1SPeter Wemm 9349f65f104SPeter Wemm if (strcmp(s, "REPORT") == 0) 9359f65f104SPeter Wemm { 9369f65f104SPeter Wemm ++report_next; 9379f65f104SPeter Wemm return; 9389f65f104SPeter Wemm } 9399f65f104SPeter Wemm 9403d793cf1SPeter Wemm if (strcmp(s, "CLR_REPORT") == 0) 9413d793cf1SPeter Wemm { 9423d793cf1SPeter Wemm ++clear_report_next; 9433d793cf1SPeter Wemm return; 9443d793cf1SPeter Wemm } 9453d793cf1SPeter Wemm 9469b1aec48SLars Fredriksen if (strcmp(s, "TIMEOUT") == 0) 9479b1aec48SLars Fredriksen { 9489b1aec48SLars Fredriksen ++timeout_next; 9499b1aec48SLars Fredriksen return; 9509b1aec48SLars Fredriksen } 9519b1aec48SLars Fredriksen 9523d793cf1SPeter Wemm if (strcmp(s, "ECHO") == 0) 9539b1aec48SLars Fredriksen { 9543d793cf1SPeter Wemm ++echo_next; 9553d793cf1SPeter Wemm return; 9563d793cf1SPeter Wemm } 9573d793cf1SPeter Wemm if (strcmp(s, "SAY") == 0) 9583d793cf1SPeter Wemm { 9593d793cf1SPeter Wemm ++say_next; 9603d793cf1SPeter Wemm return; 9613d793cf1SPeter Wemm } 9623d793cf1SPeter Wemm /* 9633d793cf1SPeter Wemm * Fetch the expect and reply string. 9643d793cf1SPeter Wemm */ 9653d793cf1SPeter Wemm for (;;) 9663d793cf1SPeter Wemm { 9673d793cf1SPeter Wemm expect = expect_strtok (s, "-"); 9683d793cf1SPeter Wemm s = (char *) 0; 9699b1aec48SLars Fredriksen 9703d793cf1SPeter Wemm if (expect == (char *) 0) 9719f65f104SPeter Wemm { 9723d793cf1SPeter Wemm return; 9733d793cf1SPeter Wemm } 9743d793cf1SPeter Wemm 9753d793cf1SPeter Wemm reply = expect_strtok (s, "-"); 9763d793cf1SPeter Wemm /* 9773d793cf1SPeter Wemm * Handle the expect string. If successful then exit. 9783d793cf1SPeter Wemm */ 9793d793cf1SPeter Wemm if (get_string (expect)) 9809f65f104SPeter Wemm { 9813d793cf1SPeter Wemm return; 9823d793cf1SPeter Wemm } 9833d793cf1SPeter Wemm /* 9843d793cf1SPeter Wemm * If there is a sub-reply string then send it. Otherwise any condition 9853d793cf1SPeter Wemm * is terminal. 9863d793cf1SPeter Wemm */ 9873d793cf1SPeter Wemm if (reply == (char *) 0 || exit_code != 3) 9889f65f104SPeter Wemm { 9899b1aec48SLars Fredriksen break; 9909f65f104SPeter Wemm } 9919b1aec48SLars Fredriksen 9923d793cf1SPeter Wemm chat_send (reply); 9939f65f104SPeter Wemm } 9943d793cf1SPeter Wemm /* 9953d793cf1SPeter Wemm * The expectation did not occur. This is terminal. 9963d793cf1SPeter Wemm */ 9979b1aec48SLars Fredriksen if (fail_reason) 9989f65f104SPeter Wemm { 9999b1aec48SLars Fredriksen syslog(LOG_INFO, "Failed (%s)", fail_reason); 10009f65f104SPeter Wemm } 10019b1aec48SLars Fredriksen else 10029f65f104SPeter Wemm { 10039b1aec48SLars Fredriksen syslog(LOG_INFO, "Failed"); 10049f65f104SPeter Wemm } 10059f65f104SPeter Wemm terminate(exit_code); 10069f65f104SPeter Wemm } 10073d793cf1SPeter Wemm 10083d793cf1SPeter Wemm /* 10093d793cf1SPeter Wemm * Translate the input character to the appropriate string for printing 10103d793cf1SPeter Wemm * the data. 10113d793cf1SPeter Wemm */ 10129b1aec48SLars Fredriksen 10139b1aec48SLars Fredriksen char *character(c) 10149f65f104SPeter Wemm int c; 10159b1aec48SLars Fredriksen { 10169b1aec48SLars Fredriksen static char string[10]; 10179b1aec48SLars Fredriksen char *meta; 10189b1aec48SLars Fredriksen 10199b1aec48SLars Fredriksen meta = (c & 0x80) ? "M-" : ""; 10209b1aec48SLars Fredriksen c &= 0x7F; 10219b1aec48SLars Fredriksen 10229b1aec48SLars Fredriksen if (c < 32) 10239f65f104SPeter Wemm { 10249b1aec48SLars Fredriksen sprintf(string, "%s^%c", meta, (int)c + '@'); 10259f65f104SPeter Wemm } 10269b1aec48SLars Fredriksen else 10279f65f104SPeter Wemm { 10289b1aec48SLars Fredriksen if (c == 127) 10299f65f104SPeter Wemm { 10309b1aec48SLars Fredriksen sprintf(string, "%s^?", meta); 10319f65f104SPeter Wemm } 10329b1aec48SLars Fredriksen else 10339f65f104SPeter Wemm { 10349b1aec48SLars Fredriksen sprintf(string, "%s%c", meta, c); 10359f65f104SPeter Wemm } 10369f65f104SPeter Wemm } 10379b1aec48SLars Fredriksen 10389b1aec48SLars Fredriksen return (string); 10399b1aec48SLars Fredriksen } 10409b1aec48SLars Fredriksen 10419b1aec48SLars Fredriksen /* 10429b1aec48SLars Fredriksen * process the reply string 10439b1aec48SLars Fredriksen */ 10449b1aec48SLars Fredriksen void chat_send (s) 10459b1aec48SLars Fredriksen register char *s; 10469b1aec48SLars Fredriksen { 10473d793cf1SPeter Wemm if (say_next) 10483d793cf1SPeter Wemm { 10493d793cf1SPeter Wemm say_next = 0; 10503d793cf1SPeter Wemm s = clean(s,0); 10513d793cf1SPeter Wemm write(2, s, strlen(s)); 10523d793cf1SPeter Wemm free(s); 10533d793cf1SPeter Wemm return; 10543d793cf1SPeter Wemm } 10553d793cf1SPeter Wemm if (hup_next) 10563d793cf1SPeter Wemm { 10573d793cf1SPeter Wemm hup_next = 0; 10583d793cf1SPeter Wemm if (strcmp(s, "OFF") == 0) 10593d793cf1SPeter Wemm signal(SIGHUP, SIG_IGN); 10603d793cf1SPeter Wemm else 10613d793cf1SPeter Wemm signal(SIGHUP, sighup); 10623d793cf1SPeter Wemm return; 10633d793cf1SPeter Wemm } 10643d793cf1SPeter Wemm if (echo_next) 10653d793cf1SPeter Wemm { 10663d793cf1SPeter Wemm echo_next = 0; 10673d793cf1SPeter Wemm echo = (strcmp(s, "ON") == 0); 10683d793cf1SPeter Wemm return; 10693d793cf1SPeter Wemm } 10709b1aec48SLars Fredriksen if (abort_next) 10719b1aec48SLars Fredriksen { 10729b1aec48SLars Fredriksen char *s1; 10739b1aec48SLars Fredriksen 10749b1aec48SLars Fredriksen abort_next = 0; 10759b1aec48SLars Fredriksen 10769b1aec48SLars Fredriksen if (n_aborts >= MAX_ABORTS) 10779f65f104SPeter Wemm { 10789b1aec48SLars Fredriksen fatal("Too many ABORT strings"); 10799f65f104SPeter Wemm } 10809b1aec48SLars Fredriksen 10819b1aec48SLars Fredriksen s1 = clean(s, 0); 10829b1aec48SLars Fredriksen 10839f65f104SPeter Wemm if (strlen(s1) > strlen(s) 10849f65f104SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 10859b1aec48SLars Fredriksen { 10869b1aec48SLars Fredriksen syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 10879b1aec48SLars Fredriksen die(); 10889b1aec48SLars Fredriksen } 10899b1aec48SLars Fredriksen 10909b1aec48SLars Fredriksen abort_string[n_aborts++] = s1; 10919b1aec48SLars Fredriksen 10929b1aec48SLars Fredriksen if (verbose) 10939b1aec48SLars Fredriksen { 10949b1aec48SLars Fredriksen logf("abort on ("); 10959b1aec48SLars Fredriksen 10969b1aec48SLars Fredriksen for (s1 = s; *s1; ++s1) 10979f65f104SPeter Wemm { 10989b1aec48SLars Fredriksen logf(character(*s1)); 10999f65f104SPeter Wemm } 11009b1aec48SLars Fredriksen 11019b1aec48SLars Fredriksen logf(")\n"); 11029b1aec48SLars Fredriksen } 11039f65f104SPeter Wemm return; 11049b1aec48SLars Fredriksen } 11059f65f104SPeter Wemm 11063d793cf1SPeter Wemm if (clear_abort_next) 11073d793cf1SPeter Wemm { 11083d793cf1SPeter Wemm char *s1; 11093d793cf1SPeter Wemm char *s2 = s; 11103d793cf1SPeter Wemm int i; 11113d793cf1SPeter Wemm int old_max; 11123d793cf1SPeter Wemm int pack = 0; 11133d793cf1SPeter Wemm 11143d793cf1SPeter Wemm clear_abort_next = 0; 11153d793cf1SPeter Wemm 11163d793cf1SPeter Wemm s1 = clean(s, 0); 11173d793cf1SPeter Wemm 11183d793cf1SPeter Wemm if (strlen(s1) > strlen(s) 11193d793cf1SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 11203d793cf1SPeter Wemm { 11213d793cf1SPeter Wemm syslog(LOG_WARNING, "Illegal or too-long CLR_ABORT string ('%s')", s); 11223d793cf1SPeter Wemm die(); 11233d793cf1SPeter Wemm } 11243d793cf1SPeter Wemm 11253d793cf1SPeter Wemm old_max = n_aborts; 11263d793cf1SPeter Wemm for (i=0; i < n_aborts; i++) 11273d793cf1SPeter Wemm { 11283d793cf1SPeter Wemm if ( strcmp(s1,abort_string[i]) == 0 ) 11293d793cf1SPeter Wemm { 11303d793cf1SPeter Wemm free(abort_string[i]); 11313d793cf1SPeter Wemm abort_string[i] = NULL; 11323d793cf1SPeter Wemm pack++; 11333d793cf1SPeter Wemm n_aborts--; 11343d793cf1SPeter Wemm if (verbose) 11353d793cf1SPeter Wemm { 11363d793cf1SPeter Wemm logf("clear abort on ("); 11373d793cf1SPeter Wemm 11383d793cf1SPeter Wemm for (s2 = s; *s2; ++s2) 11393d793cf1SPeter Wemm { 11403d793cf1SPeter Wemm logf(character(*s2)); 11413d793cf1SPeter Wemm } 11423d793cf1SPeter Wemm 11433d793cf1SPeter Wemm logf(")\n"); 11443d793cf1SPeter Wemm } 11453d793cf1SPeter Wemm } 11463d793cf1SPeter Wemm } 11473d793cf1SPeter Wemm free(s1); 11483d793cf1SPeter Wemm if (pack) pack_array(abort_string,old_max); 11493d793cf1SPeter Wemm return; 11503d793cf1SPeter Wemm } 11513d793cf1SPeter Wemm 11529f65f104SPeter Wemm if (report_next) 11539f65f104SPeter Wemm { 11549f65f104SPeter Wemm char *s1; 11559f65f104SPeter Wemm 11569f65f104SPeter Wemm report_next = 0; 11579f65f104SPeter Wemm if (n_reports >= MAX_REPORTS) 11589f65f104SPeter Wemm { 11599f65f104SPeter Wemm fatal("Too many REPORT strings"); 11609f65f104SPeter Wemm } 11619f65f104SPeter Wemm 11629f65f104SPeter Wemm s1 = clean(s, 0); 11639f65f104SPeter Wemm 11649f65f104SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 11659f65f104SPeter Wemm { 11669f65f104SPeter Wemm syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 11679f65f104SPeter Wemm die(); 11689f65f104SPeter Wemm } 11699f65f104SPeter Wemm 11709f65f104SPeter Wemm report_string[n_reports++] = s1; 11719f65f104SPeter Wemm 11729f65f104SPeter Wemm if (verbose) 11739f65f104SPeter Wemm { 11749f65f104SPeter Wemm logf("report ("); 11759f65f104SPeter Wemm s1 = s; 11769f65f104SPeter Wemm while (*s1) 11779f65f104SPeter Wemm { 11789f65f104SPeter Wemm logf(character(*s1)); 11799f65f104SPeter Wemm ++s1; 11809f65f104SPeter Wemm } 11819f65f104SPeter Wemm logf(")\n"); 11829f65f104SPeter Wemm } 11839f65f104SPeter Wemm return; 11849f65f104SPeter Wemm } 11859f65f104SPeter Wemm 11863d793cf1SPeter Wemm if (clear_report_next) 11873d793cf1SPeter Wemm { 11883d793cf1SPeter Wemm char *s1; 11893d793cf1SPeter Wemm char *s2 = s; 11903d793cf1SPeter Wemm int i; 11913d793cf1SPeter Wemm int old_max; 11923d793cf1SPeter Wemm int pack = 0; 11933d793cf1SPeter Wemm 11943d793cf1SPeter Wemm clear_report_next = 0; 11953d793cf1SPeter Wemm 11963d793cf1SPeter Wemm s1 = clean(s, 0); 11973d793cf1SPeter Wemm 11983d793cf1SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 11993d793cf1SPeter Wemm { 12003d793cf1SPeter Wemm syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 12013d793cf1SPeter Wemm die(); 12023d793cf1SPeter Wemm } 12033d793cf1SPeter Wemm 12043d793cf1SPeter Wemm old_max = n_reports; 12053d793cf1SPeter Wemm for (i=0; i < n_reports; i++) 12063d793cf1SPeter Wemm { 12073d793cf1SPeter Wemm if ( strcmp(s1,report_string[i]) == 0 ) 12083d793cf1SPeter Wemm { 12093d793cf1SPeter Wemm free(report_string[i]); 12103d793cf1SPeter Wemm report_string[i] = NULL; 12113d793cf1SPeter Wemm pack++; 12123d793cf1SPeter Wemm n_reports--; 12133d793cf1SPeter Wemm if (verbose) 12143d793cf1SPeter Wemm { 12153d793cf1SPeter Wemm logf("clear report ("); 12163d793cf1SPeter Wemm 12173d793cf1SPeter Wemm for (s2 = s; *s2; ++s2) 12183d793cf1SPeter Wemm { 12193d793cf1SPeter Wemm logf(character(*s2)); 12203d793cf1SPeter Wemm } 12213d793cf1SPeter Wemm 12223d793cf1SPeter Wemm logf(")\n"); 12233d793cf1SPeter Wemm } 12243d793cf1SPeter Wemm } 12253d793cf1SPeter Wemm } 12263d793cf1SPeter Wemm free(s1); 12273d793cf1SPeter Wemm if (pack) pack_array(report_string,old_max); 12283d793cf1SPeter Wemm 12293d793cf1SPeter Wemm return; 12303d793cf1SPeter Wemm } 12313d793cf1SPeter Wemm 12329b1aec48SLars Fredriksen if (timeout_next) 12339b1aec48SLars Fredriksen { 12349b1aec48SLars Fredriksen timeout_next = 0; 12359b1aec48SLars Fredriksen timeout = atoi(s); 12369b1aec48SLars Fredriksen 12379b1aec48SLars Fredriksen if (timeout <= 0) 12389f65f104SPeter Wemm { 12399b1aec48SLars Fredriksen timeout = DEFAULT_CHAT_TIMEOUT; 12409f65f104SPeter Wemm } 12419b1aec48SLars Fredriksen 12429b1aec48SLars Fredriksen if (verbose) 12439b1aec48SLars Fredriksen { 12449b1aec48SLars Fredriksen syslog(LOG_INFO, "timeout set to %d seconds", timeout); 12459b1aec48SLars Fredriksen } 12469f65f104SPeter Wemm return; 12479f65f104SPeter Wemm } 12489f65f104SPeter Wemm 12499f65f104SPeter Wemm if (strcmp(s, "EOT") == 0) 12509f65f104SPeter Wemm { 12519f65f104SPeter Wemm s = "^D\\c"; 12529b1aec48SLars Fredriksen } 12539b1aec48SLars Fredriksen else 12549b1aec48SLars Fredriksen { 12559b1aec48SLars Fredriksen if (strcmp(s, "BREAK") == 0) 12569f65f104SPeter Wemm { 12579b1aec48SLars Fredriksen s = "\\K\\c"; 12589f65f104SPeter Wemm } 12599f65f104SPeter Wemm } 12609f65f104SPeter Wemm 12619b1aec48SLars Fredriksen if (!put_string(s)) 12629b1aec48SLars Fredriksen { 12639b1aec48SLars Fredriksen syslog(LOG_INFO, "Failed"); 12649b1aec48SLars Fredriksen terminate(1); 12659b1aec48SLars Fredriksen } 12669b1aec48SLars Fredriksen } 12679b1aec48SLars Fredriksen 12689b1aec48SLars Fredriksen int get_char() 12699b1aec48SLars Fredriksen { 12709b1aec48SLars Fredriksen int status; 12719b1aec48SLars Fredriksen char c; 12729b1aec48SLars Fredriksen 12739b1aec48SLars Fredriksen status = read(0, &c, 1); 12749b1aec48SLars Fredriksen 12759b1aec48SLars Fredriksen switch (status) 12769b1aec48SLars Fredriksen { 12779b1aec48SLars Fredriksen case 1: 12789b1aec48SLars Fredriksen return ((int)c & 0x7F); 12799b1aec48SLars Fredriksen 12809b1aec48SLars Fredriksen default: 12819b1aec48SLars Fredriksen syslog(LOG_WARNING, "warning: read() on stdin returned %d", 12829b1aec48SLars Fredriksen status); 12839b1aec48SLars Fredriksen 12849b1aec48SLars Fredriksen case -1: 12859b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 12869f65f104SPeter Wemm { 12879b1aec48SLars Fredriksen sysfatal("Can't get file mode flags on stdin"); 12889f65f104SPeter Wemm } 12899b1aec48SLars Fredriksen else 12909f65f104SPeter Wemm { 12919f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 12929f65f104SPeter Wemm { 12939b1aec48SLars Fredriksen sysfatal("Can't set file mode flags on stdin"); 12949f65f104SPeter Wemm } 12959f65f104SPeter Wemm } 12969b1aec48SLars Fredriksen 12979b1aec48SLars Fredriksen return (-1); 12989b1aec48SLars Fredriksen } 12999b1aec48SLars Fredriksen } 13009b1aec48SLars Fredriksen 13019b1aec48SLars Fredriksen int put_char(c) 13029f65f104SPeter Wemm int c; 13039b1aec48SLars Fredriksen { 13049b1aec48SLars Fredriksen int status; 13059f65f104SPeter Wemm char ch = c; 13069b1aec48SLars Fredriksen 13079f65f104SPeter Wemm usleep(10000); /* inter-character typing delay (?) */ 13089b1aec48SLars Fredriksen 13099f65f104SPeter Wemm status = write(1, &ch, 1); 13109b1aec48SLars Fredriksen 13119b1aec48SLars Fredriksen switch (status) 13129b1aec48SLars Fredriksen { 13139b1aec48SLars Fredriksen case 1: 13149b1aec48SLars Fredriksen return (0); 13159b1aec48SLars Fredriksen 13169b1aec48SLars Fredriksen default: 13179b1aec48SLars Fredriksen syslog(LOG_WARNING, "warning: write() on stdout returned %d", 13189b1aec48SLars Fredriksen status); 13199b1aec48SLars Fredriksen 13209b1aec48SLars Fredriksen case -1: 13219b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 13229f65f104SPeter Wemm { 13239b1aec48SLars Fredriksen sysfatal("Can't get file mode flags on stdin"); 13249f65f104SPeter Wemm } 13259b1aec48SLars Fredriksen else 13269f65f104SPeter Wemm { 13279f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 13289f65f104SPeter Wemm { 13299b1aec48SLars Fredriksen sysfatal("Can't set file mode flags on stdin"); 13309f65f104SPeter Wemm } 13319f65f104SPeter Wemm } 13329b1aec48SLars Fredriksen 13339b1aec48SLars Fredriksen return (-1); 13349b1aec48SLars Fredriksen } 13359b1aec48SLars Fredriksen } 13369b1aec48SLars Fredriksen 13379b1aec48SLars Fredriksen int write_char (c) 13389b1aec48SLars Fredriksen int c; 13399b1aec48SLars Fredriksen { 13409b1aec48SLars Fredriksen if (alarmed || put_char(c) < 0) 13419b1aec48SLars Fredriksen { 13429b1aec48SLars Fredriksen extern int errno; 13439b1aec48SLars Fredriksen 13449f65f104SPeter Wemm alarm(0); 13459f65f104SPeter Wemm alarmed = 0; 13469b1aec48SLars Fredriksen 13479b1aec48SLars Fredriksen if (verbose) 13489b1aec48SLars Fredriksen { 13499b1aec48SLars Fredriksen if (errno == EINTR || errno == EWOULDBLOCK) 13509f65f104SPeter Wemm { 13519b1aec48SLars Fredriksen syslog(LOG_INFO, " -- write timed out"); 13529f65f104SPeter Wemm } 13539b1aec48SLars Fredriksen else 13549f65f104SPeter Wemm { 13559b1aec48SLars Fredriksen syslog(LOG_INFO, " -- write failed: %m"); 13569b1aec48SLars Fredriksen } 13579f65f104SPeter Wemm } 13589b1aec48SLars Fredriksen return (0); 13599b1aec48SLars Fredriksen } 13609b1aec48SLars Fredriksen return (1); 13619b1aec48SLars Fredriksen } 13629b1aec48SLars Fredriksen 13639b1aec48SLars Fredriksen int put_string (s) 13649b1aec48SLars Fredriksen register char *s; 13659b1aec48SLars Fredriksen { 13663d793cf1SPeter Wemm quiet = 0; 13679b1aec48SLars Fredriksen s = clean(s, 1); 13689b1aec48SLars Fredriksen 13699b1aec48SLars Fredriksen if (verbose) 13709b1aec48SLars Fredriksen { 13719b1aec48SLars Fredriksen logf("send ("); 13729b1aec48SLars Fredriksen 13739b1aec48SLars Fredriksen if (quiet) 13749f65f104SPeter Wemm { 13759b1aec48SLars Fredriksen logf("??????"); 13769f65f104SPeter Wemm } 13779b1aec48SLars Fredriksen else 13789b1aec48SLars Fredriksen { 13799b1aec48SLars Fredriksen register char *s1 = s; 13809b1aec48SLars Fredriksen 13819b1aec48SLars Fredriksen for (s1 = s; *s1; ++s1) 13829f65f104SPeter Wemm { 13839b1aec48SLars Fredriksen logf(character(*s1)); 13849b1aec48SLars Fredriksen } 13859f65f104SPeter Wemm } 13869b1aec48SLars Fredriksen 13879b1aec48SLars Fredriksen logf(")\n"); 13889b1aec48SLars Fredriksen } 13899b1aec48SLars Fredriksen 13909b1aec48SLars Fredriksen alarm(timeout); alarmed = 0; 13919b1aec48SLars Fredriksen 13929b1aec48SLars Fredriksen while (*s) 13939b1aec48SLars Fredriksen { 13949b1aec48SLars Fredriksen register char c = *s++; 13959b1aec48SLars Fredriksen 13969b1aec48SLars Fredriksen if (c != '\\') 13979b1aec48SLars Fredriksen { 13989b1aec48SLars Fredriksen if (!write_char (c)) 13999f65f104SPeter Wemm { 14009b1aec48SLars Fredriksen return 0; 14019f65f104SPeter Wemm } 14029b1aec48SLars Fredriksen continue; 14039b1aec48SLars Fredriksen } 14049b1aec48SLars Fredriksen 14059b1aec48SLars Fredriksen c = *s++; 14069b1aec48SLars Fredriksen switch (c) 14079b1aec48SLars Fredriksen { 14089b1aec48SLars Fredriksen case 'd': 14099b1aec48SLars Fredriksen sleep(1); 14109b1aec48SLars Fredriksen break; 14119b1aec48SLars Fredriksen 14129b1aec48SLars Fredriksen case 'K': 14139b1aec48SLars Fredriksen break_sequence(); 14149b1aec48SLars Fredriksen break; 14159b1aec48SLars Fredriksen 14169b1aec48SLars Fredriksen case 'p': 14179f65f104SPeter Wemm usleep(10000); /* 1/100th of a second (arg is microseconds) */ 14189b1aec48SLars Fredriksen break; 14199b1aec48SLars Fredriksen 14209b1aec48SLars Fredriksen default: 14219b1aec48SLars Fredriksen if (!write_char (c)) 14229b1aec48SLars Fredriksen return 0; 14239b1aec48SLars Fredriksen break; 14249b1aec48SLars Fredriksen } 14259b1aec48SLars Fredriksen } 14269b1aec48SLars Fredriksen 14279b1aec48SLars Fredriksen alarm(0); 14289b1aec48SLars Fredriksen alarmed = 0; 14299b1aec48SLars Fredriksen return (1); 14309b1aec48SLars Fredriksen } 14319b1aec48SLars Fredriksen 14329b1aec48SLars Fredriksen /* 14333d793cf1SPeter Wemm * Echo a character to stderr. 14343d793cf1SPeter Wemm * When called with -1, a '\n' character is generated when 14353d793cf1SPeter Wemm * the cursor is not at the beginning of a line. 14363d793cf1SPeter Wemm */ 14373d793cf1SPeter Wemm void echo_stderr(n) 14383d793cf1SPeter Wemm int n; 14393d793cf1SPeter Wemm { 14403d793cf1SPeter Wemm static int need_lf; 14413d793cf1SPeter Wemm char *s; 14423d793cf1SPeter Wemm 14433d793cf1SPeter Wemm switch (n) 14443d793cf1SPeter Wemm { 14453d793cf1SPeter Wemm case '\r': /* ignore '\r' */ 14463d793cf1SPeter Wemm break; 14473d793cf1SPeter Wemm case -1: 14483d793cf1SPeter Wemm if (need_lf == 0) 14493d793cf1SPeter Wemm break; 14503d793cf1SPeter Wemm /* fall through */ 14513d793cf1SPeter Wemm case '\n': 14523d793cf1SPeter Wemm write(2, "\n", 1); 14533d793cf1SPeter Wemm need_lf = 0; 14543d793cf1SPeter Wemm break; 14553d793cf1SPeter Wemm default: 14563d793cf1SPeter Wemm s = character(n); 14573d793cf1SPeter Wemm write(2, s, strlen(s)); 14583d793cf1SPeter Wemm need_lf = 1; 14593d793cf1SPeter Wemm break; 14603d793cf1SPeter Wemm } 14613d793cf1SPeter Wemm } 14623d793cf1SPeter Wemm 14633d793cf1SPeter Wemm /* 14649b1aec48SLars Fredriksen * 'Wait for' this string to appear on this file descriptor. 14659b1aec48SLars Fredriksen */ 14669b1aec48SLars Fredriksen int get_string(string) 14679b1aec48SLars Fredriksen register char *string; 14689b1aec48SLars Fredriksen { 14699b1aec48SLars Fredriksen char temp[STR_LEN]; 14709b1aec48SLars Fredriksen int c, printed = 0, len, minlen; 14719b1aec48SLars Fredriksen register char *s = temp, *end = s + STR_LEN; 14729b1aec48SLars Fredriksen 14739b1aec48SLars Fredriksen fail_reason = (char *)0; 14749b1aec48SLars Fredriksen string = clean(string, 0); 14759b1aec48SLars Fredriksen len = strlen(string); 14769b1aec48SLars Fredriksen minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 14779b1aec48SLars Fredriksen 14789b1aec48SLars Fredriksen if (verbose) 14799b1aec48SLars Fredriksen { 14809b1aec48SLars Fredriksen register char *s1; 14819b1aec48SLars Fredriksen 14829b1aec48SLars Fredriksen logf("expect ("); 14839b1aec48SLars Fredriksen 14849b1aec48SLars Fredriksen for (s1 = string; *s1; ++s1) 14859f65f104SPeter Wemm { 14869b1aec48SLars Fredriksen logf(character(*s1)); 14879f65f104SPeter Wemm } 14889b1aec48SLars Fredriksen 14899b1aec48SLars Fredriksen logf(")\n"); 14909b1aec48SLars Fredriksen } 14919b1aec48SLars Fredriksen 14929b1aec48SLars Fredriksen if (len > STR_LEN) 14939b1aec48SLars Fredriksen { 14949b1aec48SLars Fredriksen syslog(LOG_INFO, "expect string is too long"); 14959f65f104SPeter Wemm exit_code = 1; 14969b1aec48SLars Fredriksen return 0; 14979b1aec48SLars Fredriksen } 14989b1aec48SLars Fredriksen 14999b1aec48SLars Fredriksen if (len == 0) 15009b1aec48SLars Fredriksen { 15019b1aec48SLars Fredriksen if (verbose) 15029b1aec48SLars Fredriksen { 15039b1aec48SLars Fredriksen syslog(LOG_INFO, "got it"); 15049b1aec48SLars Fredriksen } 15059b1aec48SLars Fredriksen 15069b1aec48SLars Fredriksen return (1); 15079b1aec48SLars Fredriksen } 15089b1aec48SLars Fredriksen 15099f65f104SPeter Wemm alarm(timeout); 15109f65f104SPeter Wemm alarmed = 0; 15119b1aec48SLars Fredriksen 15129b1aec48SLars Fredriksen while ( ! alarmed && (c = get_char()) >= 0) 15139b1aec48SLars Fredriksen { 15149f65f104SPeter Wemm int n, abort_len, report_len; 15159b1aec48SLars Fredriksen 15163d793cf1SPeter Wemm if (echo) 15173d793cf1SPeter Wemm { 15183d793cf1SPeter Wemm echo_stderr(c); 15193d793cf1SPeter Wemm } 15209b1aec48SLars Fredriksen if (verbose) 15219b1aec48SLars Fredriksen { 15229b1aec48SLars Fredriksen if (c == '\n') 15239f65f104SPeter Wemm { 15249b1aec48SLars Fredriksen logf("\n"); 15259f65f104SPeter Wemm } 15269b1aec48SLars Fredriksen else 15279f65f104SPeter Wemm { 15289b1aec48SLars Fredriksen logf(character(c)); 15299b1aec48SLars Fredriksen } 15309f65f104SPeter Wemm } 15319b1aec48SLars Fredriksen 15323d793cf1SPeter Wemm if (Verbose) { 15333d793cf1SPeter Wemm if (c == '\n') fputc( '\n', stderr ); 15343d793cf1SPeter Wemm else if (c != '\r') fprintf( stderr, "%s", character(c) ); 15353d793cf1SPeter Wemm } 15363d793cf1SPeter Wemm 15379b1aec48SLars Fredriksen *s++ = c; 15389b1aec48SLars Fredriksen 15399f65f104SPeter Wemm if (!report_gathering) 15409f65f104SPeter Wemm { 15419f65f104SPeter Wemm for (n = 0; n < n_reports; ++n) 15429f65f104SPeter Wemm { 15439f65f104SPeter Wemm if ((report_string[n] != (char*) NULL) && 15449f65f104SPeter Wemm s - temp >= (report_len = strlen(report_string[n])) && 15459f65f104SPeter Wemm strncmp(s - report_len, report_string[n], report_len) == 0) 15469f65f104SPeter Wemm { 15479f65f104SPeter Wemm time_t time_now = time ((time_t*) NULL); 15489f65f104SPeter Wemm struct tm* tm_now = localtime (&time_now); 15499f65f104SPeter Wemm 15509f65f104SPeter Wemm strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 15519f65f104SPeter Wemm strcat (report_buffer, report_string[n]); 15529f65f104SPeter Wemm 15539f65f104SPeter Wemm report_string[n] = (char *) NULL; 15549f65f104SPeter Wemm report_gathering = 1; 15559f65f104SPeter Wemm break; 15569f65f104SPeter Wemm } 15579f65f104SPeter Wemm } 15589f65f104SPeter Wemm } 15599f65f104SPeter Wemm else 15609f65f104SPeter Wemm { 15619f65f104SPeter Wemm if (!iscntrl (c)) 15629f65f104SPeter Wemm { 15639f65f104SPeter Wemm int rep_len = strlen (report_buffer); 15649f65f104SPeter Wemm report_buffer[rep_len] = c; 15659f65f104SPeter Wemm report_buffer[rep_len + 1] = '\0'; 15669f65f104SPeter Wemm } 15679f65f104SPeter Wemm else 15689f65f104SPeter Wemm { 15699f65f104SPeter Wemm report_gathering = 0; 15709f65f104SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 15719f65f104SPeter Wemm } 15729f65f104SPeter Wemm } 15739b1aec48SLars Fredriksen 15743d793cf1SPeter Wemm if (s - temp >= len && 15753d793cf1SPeter Wemm c == string[len - 1] && 15763d793cf1SPeter Wemm strncmp(s - len, string, len) == 0) 15773d793cf1SPeter Wemm { 15783d793cf1SPeter Wemm if (verbose) 15793d793cf1SPeter Wemm { 15803d793cf1SPeter Wemm logf(" -- got it\n"); 15813d793cf1SPeter Wemm } 15823d793cf1SPeter Wemm 15833d793cf1SPeter Wemm alarm(0); 15843d793cf1SPeter Wemm alarmed = 0; 15853d793cf1SPeter Wemm return (1); 15863d793cf1SPeter Wemm } 15873d793cf1SPeter Wemm 15883d793cf1SPeter Wemm for (n = 0; n < n_aborts; ++n) 15893d793cf1SPeter Wemm { 15903d793cf1SPeter Wemm if (s - temp >= (abort_len = strlen(abort_string[n])) && 15913d793cf1SPeter Wemm strncmp(s - abort_len, abort_string[n], abort_len) == 0) 15923d793cf1SPeter Wemm { 15933d793cf1SPeter Wemm if (verbose) 15943d793cf1SPeter Wemm { 15953d793cf1SPeter Wemm logf(" -- failed\n"); 15963d793cf1SPeter Wemm } 15973d793cf1SPeter Wemm 15983d793cf1SPeter Wemm alarm(0); 15993d793cf1SPeter Wemm alarmed = 0; 16003d793cf1SPeter Wemm exit_code = n + 4; 16013d793cf1SPeter Wemm strcpy(fail_reason = fail_buffer, abort_string[n]); 16023d793cf1SPeter Wemm return (0); 16033d793cf1SPeter Wemm } 16043d793cf1SPeter Wemm } 16053d793cf1SPeter Wemm 16069b1aec48SLars Fredriksen if (s >= end) 16079b1aec48SLars Fredriksen { 16089b1aec48SLars Fredriksen strncpy (temp, s - minlen, minlen); 16099b1aec48SLars Fredriksen s = temp + minlen; 16109b1aec48SLars Fredriksen } 16119b1aec48SLars Fredriksen 16129b1aec48SLars Fredriksen if (alarmed && verbose) 16139f65f104SPeter Wemm { 16149b1aec48SLars Fredriksen syslog(LOG_WARNING, "warning: alarm synchronization problem"); 16159b1aec48SLars Fredriksen } 16169f65f104SPeter Wemm } 16179b1aec48SLars Fredriksen 16189b1aec48SLars Fredriksen alarm(0); 16199b1aec48SLars Fredriksen 16209b1aec48SLars Fredriksen if (verbose && printed) 16219b1aec48SLars Fredriksen { 16229b1aec48SLars Fredriksen if (alarmed) 16239f65f104SPeter Wemm { 16249b1aec48SLars Fredriksen logf(" -- read timed out\n"); 16259f65f104SPeter Wemm } 16269b1aec48SLars Fredriksen else 16279b1aec48SLars Fredriksen { 16289b1aec48SLars Fredriksen logflush(); 16299b1aec48SLars Fredriksen syslog(LOG_INFO, " -- read failed: %m"); 16309b1aec48SLars Fredriksen } 16319b1aec48SLars Fredriksen } 16329b1aec48SLars Fredriksen 16339f65f104SPeter Wemm exit_code = 3; 16349b1aec48SLars Fredriksen alarmed = 0; 16359b1aec48SLars Fredriksen return (0); 16369b1aec48SLars Fredriksen } 16379b1aec48SLars Fredriksen 16389f65f104SPeter Wemm #ifdef NO_USLEEP 16399b1aec48SLars Fredriksen #include <sys/types.h> 16409b1aec48SLars Fredriksen #include <sys/time.h> 16419b1aec48SLars Fredriksen 16429b1aec48SLars Fredriksen /* 16439b1aec48SLars Fredriksen usleep -- support routine for 4.2BSD system call emulations 16449b1aec48SLars Fredriksen last edit: 29-Oct-1984 D A Gwyn 16459b1aec48SLars Fredriksen */ 16469b1aec48SLars Fredriksen 16479b1aec48SLars Fredriksen extern int select(); 16489b1aec48SLars Fredriksen 16499b1aec48SLars Fredriksen int 16509b1aec48SLars Fredriksen usleep( usec ) /* returns 0 if ok, else -1 */ 16519b1aec48SLars Fredriksen long usec; /* delay in microseconds */ 16529b1aec48SLars Fredriksen { 16539b1aec48SLars Fredriksen static struct /* `timeval' */ 16549b1aec48SLars Fredriksen { 16559b1aec48SLars Fredriksen long tv_sec; /* seconds */ 16569b1aec48SLars Fredriksen long tv_usec; /* microsecs */ 16579b1aec48SLars Fredriksen } delay; /* _select() timeout */ 16589b1aec48SLars Fredriksen 16599b1aec48SLars Fredriksen delay.tv_sec = usec / 1000000L; 16609b1aec48SLars Fredriksen delay.tv_usec = usec % 1000000L; 16619b1aec48SLars Fredriksen 16629b1aec48SLars Fredriksen return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 16639b1aec48SLars Fredriksen } 16649b1aec48SLars Fredriksen #endif 16653d793cf1SPeter Wemm 16663d793cf1SPeter Wemm void 16673d793cf1SPeter Wemm pack_array (array, end) 16683d793cf1SPeter Wemm char **array; /* The address of the array of string pointers */ 16693d793cf1SPeter Wemm int end; /* The index of the next free entry before CLR_ */ 16703d793cf1SPeter Wemm { 16713d793cf1SPeter Wemm int i, j; 16723d793cf1SPeter Wemm 16733d793cf1SPeter Wemm for (i = 0; i < end; i++) { 16743d793cf1SPeter Wemm if (array[i] == NULL) { 16753d793cf1SPeter Wemm for (j = i+1; j < end; ++j) 16763d793cf1SPeter Wemm if (array[j] != NULL) 16773d793cf1SPeter Wemm array[i++] = array[j]; 16783d793cf1SPeter Wemm for (; i < end; ++i) 16793d793cf1SPeter Wemm array[i] = NULL; 16803d793cf1SPeter Wemm break; 16813d793cf1SPeter Wemm } 16823d793cf1SPeter Wemm } 16833d793cf1SPeter Wemm } 1684