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 11601c855caSPeter Wemm #include <stdarg.h> 1179b1aec48SLars Fredriksen 1189f65f104SPeter Wemm #ifndef O_NONBLOCK 1199f65f104SPeter Wemm #define O_NONBLOCK O_NDELAY 1209f65f104SPeter Wemm #endif 1219f65f104SPeter Wemm 12201c855caSPeter Wemm #ifdef SUNOS 12301c855caSPeter Wemm extern int sys_nerr; 12401c855caSPeter Wemm extern char *sys_errlist[]; 12501c855caSPeter Wemm #define memmove(to, from, n) bcopy(from, to, n) 12601c855caSPeter Wemm #define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 12701c855caSPeter Wemm "unknown error") 12801c855caSPeter Wemm #endif 12901c855caSPeter Wemm 1309b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1319b1aec48SLars Fredriksen #define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1329b1aec48SLars Fredriksen (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1339b1aec48SLars Fredriksen &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1349b1aec48SLars Fredriksen #define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1359b1aec48SLars Fredriksen (_O=4,(char*)0):(char*)0) 1369b1aec48SLars Fredriksen #define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1379b1aec48SLars Fredriksen #define ARG(c,v) (c?(--c,*v++):(char*)0) 1389b1aec48SLars Fredriksen 1399b1aec48SLars Fredriksen static int _O = 0; /* Internal state */ 1409b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/ 1419b1aec48SLars Fredriksen 1429b1aec48SLars Fredriksen #define MAX_ABORTS 50 1439f65f104SPeter Wemm #define MAX_REPORTS 50 1449b1aec48SLars Fredriksen #define DEFAULT_CHAT_TIMEOUT 45 1459b1aec48SLars Fredriksen 1463d793cf1SPeter Wemm int echo = 0; 1479b1aec48SLars Fredriksen int verbose = 0; 14801c855caSPeter Wemm int to_log = 1; 14901c855caSPeter Wemm int to_stderr = 0; 1503d793cf1SPeter Wemm int Verbose = 0; 1519b1aec48SLars Fredriksen int quiet = 0; 1529f65f104SPeter Wemm int report = 0; 1539f65f104SPeter Wemm int exit_code = 0; 1549f65f104SPeter Wemm FILE* report_fp = (FILE *) 0; 1559f65f104SPeter Wemm char *report_file = (char *) 0; 1569b1aec48SLars Fredriksen char *chat_file = (char *) 0; 15701c855caSPeter Wemm char *phone_num = (char *) 0; 15801c855caSPeter Wemm char *phone_num2 = (char *) 0; 1599b1aec48SLars Fredriksen int timeout = DEFAULT_CHAT_TIMEOUT; 1609b1aec48SLars Fredriksen 1619b1aec48SLars Fredriksen int have_tty_parameters = 0; 1629f65f104SPeter Wemm 1639b1aec48SLars Fredriksen #ifdef TERMIO 1649f65f104SPeter Wemm #define term_parms struct termio 1659f65f104SPeter Wemm #define get_term_param(param) ioctl(0, TCGETA, param) 1669f65f104SPeter Wemm #define set_term_param(param) ioctl(0, TCSETA, param) 1679b1aec48SLars Fredriksen struct termio saved_tty_parameters; 1689b1aec48SLars Fredriksen #endif 1699f65f104SPeter Wemm 1709b1aec48SLars Fredriksen #ifdef TERMIOS 1719f65f104SPeter Wemm #define term_parms struct termios 1729f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param) 1739f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param) 1749b1aec48SLars Fredriksen struct termios saved_tty_parameters; 1759b1aec48SLars Fredriksen #endif 1769b1aec48SLars Fredriksen 1779b1aec48SLars Fredriksen char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1789b1aec48SLars Fredriksen fail_buffer[50]; 1793d793cf1SPeter Wemm int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 1803d793cf1SPeter Wemm int clear_abort_next = 0; 1819b1aec48SLars Fredriksen 1829f65f104SPeter Wemm char *report_string[MAX_REPORTS] ; 1839f65f104SPeter Wemm char report_buffer[50] ; 1849f65f104SPeter Wemm int n_reports = 0, report_next = 0, report_gathering = 0 ; 1853d793cf1SPeter Wemm int clear_report_next = 0; 1863d793cf1SPeter Wemm 1873d793cf1SPeter Wemm int say_next = 0, hup_next = 0; 1889f65f104SPeter Wemm 189f1bb2cd2SWarner Losh void *dup_mem(void *b, size_t c); 190f1bb2cd2SWarner Losh void *copy_of(char *s); 191f1bb2cd2SWarner Losh static void usage(void); 192f1bb2cd2SWarner Losh void logf(const char *fmt, ...); 193f1bb2cd2SWarner Losh void fatal(int code, const char *fmt, ...); 194f1bb2cd2SWarner Losh SIGTYPE sigalrm(int signo); 195f1bb2cd2SWarner Losh SIGTYPE sigint(int signo); 196f1bb2cd2SWarner Losh SIGTYPE sigterm(int signo); 197f1bb2cd2SWarner Losh SIGTYPE sighup(int signo); 198f1bb2cd2SWarner Losh void unalarm(void); 199f1bb2cd2SWarner Losh void init(void); 200f1bb2cd2SWarner Losh void set_tty_parameters(void); 201f1bb2cd2SWarner Losh void echo_stderr(int); 202f1bb2cd2SWarner Losh void break_sequence(void); 203f1bb2cd2SWarner Losh void terminate(int status); 204f1bb2cd2SWarner Losh void do_file(char *chat_file); 205f1bb2cd2SWarner Losh int get_string(register char *string); 206f1bb2cd2SWarner Losh int put_string(register char *s); 207f1bb2cd2SWarner Losh int write_char(int c); 208f1bb2cd2SWarner Losh int put_char(int c); 209f1bb2cd2SWarner Losh int get_char(void); 210f1bb2cd2SWarner Losh void chat_send(register char *s); 211f1bb2cd2SWarner Losh char *character(int c); 212f1bb2cd2SWarner Losh void chat_expect(register char *s); 213f1bb2cd2SWarner Losh char *clean(register char *s, int sending); 214f1bb2cd2SWarner Losh void break_sequence(void); 215f1bb2cd2SWarner Losh void terminate(int status); 216f1bb2cd2SWarner Losh void pack_array(char **array, int end); 217f1bb2cd2SWarner Losh char *expect_strtok(char *, char *); 218f1bb2cd2SWarner Losh int vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */ 2193d793cf1SPeter Wemm 2209b1aec48SLars Fredriksen void *dup_mem(b, c) 2219b1aec48SLars Fredriksen void *b; 2229b1aec48SLars Fredriksen size_t c; 2239b1aec48SLars Fredriksen { 2249b1aec48SLars Fredriksen void *ans = malloc (c); 2259b1aec48SLars Fredriksen if (!ans) 22601c855caSPeter Wemm fatal(2, "memory error!"); 22701c855caSPeter Wemm 2289b1aec48SLars Fredriksen memcpy (ans, b, c); 2299b1aec48SLars Fredriksen return ans; 2309b1aec48SLars Fredriksen } 2319b1aec48SLars Fredriksen 2329b1aec48SLars Fredriksen void *copy_of (s) 2339b1aec48SLars Fredriksen char *s; 2349b1aec48SLars Fredriksen { 2359b1aec48SLars Fredriksen return dup_mem (s, strlen (s) + 1); 2369b1aec48SLars Fredriksen } 2379b1aec48SLars Fredriksen 2389b1aec48SLars Fredriksen /* 23901c855caSPeter Wemm * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ 24001c855caSPeter Wemm * [ -r report-file ] \ 2419b1aec48SLars Fredriksen * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2429b1aec48SLars Fredriksen * 2439b1aec48SLars Fredriksen * Perform a UUCP-dialer-like chat script on stdin and stdout. 2449b1aec48SLars Fredriksen */ 2459b1aec48SLars Fredriksen int 2469b1aec48SLars Fredriksen main(argc, argv) 2479b1aec48SLars Fredriksen int argc; 2489b1aec48SLars Fredriksen char **argv; 2499b1aec48SLars Fredriksen { 2509b1aec48SLars Fredriksen int option; 2519b1aec48SLars Fredriksen char *arg; 2529b1aec48SLars Fredriksen 2539f65f104SPeter Wemm tzset(); 2549b1aec48SLars Fredriksen 25501c855caSPeter Wemm while ((option = OPTION(argc, argv)) != 0) { 25601c855caSPeter Wemm switch (option) { 2573d793cf1SPeter Wemm case 'e': 2583d793cf1SPeter Wemm ++echo; 2593d793cf1SPeter Wemm break; 2603d793cf1SPeter Wemm 2619b1aec48SLars Fredriksen case 'v': 2629b1aec48SLars Fredriksen ++verbose; 2639b1aec48SLars Fredriksen break; 2649b1aec48SLars Fredriksen 2653d793cf1SPeter Wemm case 'V': 2663d793cf1SPeter Wemm ++Verbose; 2673d793cf1SPeter Wemm break; 2683d793cf1SPeter Wemm 26901c855caSPeter Wemm case 's': 27001c855caSPeter Wemm ++to_stderr; 27101c855caSPeter Wemm break; 27201c855caSPeter Wemm 27301c855caSPeter Wemm case 'S': 27401c855caSPeter Wemm to_log = 0; 27501c855caSPeter Wemm break; 27601c855caSPeter Wemm 2779b1aec48SLars Fredriksen case 'f': 2783d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 2799b1aec48SLars Fredriksen chat_file = copy_of(arg); 2809b1aec48SLars Fredriksen else 2819b1aec48SLars Fredriksen usage(); 2829b1aec48SLars Fredriksen break; 2839b1aec48SLars Fredriksen 2849b1aec48SLars Fredriksen case 't': 2853d793cf1SPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 2869b1aec48SLars Fredriksen timeout = atoi(arg); 2879b1aec48SLars Fredriksen else 2889b1aec48SLars Fredriksen usage(); 2899f65f104SPeter Wemm break; 2909b1aec48SLars Fredriksen 2919f65f104SPeter Wemm case 'r': 2929f65f104SPeter Wemm arg = OPTARG (argc, argv); 29301c855caSPeter Wemm if (arg) { 2949f65f104SPeter Wemm if (report_fp != NULL) 2959f65f104SPeter Wemm fclose (report_fp); 2969f65f104SPeter Wemm report_file = copy_of (arg); 2979f65f104SPeter Wemm report_fp = fopen (report_file, "a"); 29801c855caSPeter Wemm if (report_fp != NULL) { 2999f65f104SPeter Wemm if (verbose) 3009f65f104SPeter Wemm fprintf (report_fp, "Opening \"%s\"...\n", 3019f65f104SPeter Wemm report_file); 3029f65f104SPeter Wemm report = 1; 3039f65f104SPeter Wemm } 3049f65f104SPeter Wemm } 3059b1aec48SLars Fredriksen break; 3069b1aec48SLars Fredriksen 30701c855caSPeter Wemm case 'T': 30801c855caSPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 30901c855caSPeter Wemm phone_num = copy_of(arg); 31001c855caSPeter Wemm else 31101c855caSPeter Wemm usage(); 31201c855caSPeter Wemm break; 31301c855caSPeter Wemm 31401c855caSPeter Wemm case 'U': 31501c855caSPeter Wemm if ((arg = OPTARG(argc, argv)) != NULL) 31601c855caSPeter Wemm phone_num2 = copy_of(arg); 31701c855caSPeter Wemm else 31801c855caSPeter Wemm usage(); 31901c855caSPeter Wemm break; 32001c855caSPeter Wemm 3219b1aec48SLars Fredriksen default: 3229b1aec48SLars Fredriksen usage(); 3239f65f104SPeter Wemm break; 3249f65f104SPeter Wemm } 3259f65f104SPeter Wemm } 3269f65f104SPeter Wemm /* 3279f65f104SPeter Wemm * Default the report file to the stderr location 3289f65f104SPeter Wemm */ 3299f65f104SPeter Wemm if (report_fp == NULL) 3309f65f104SPeter Wemm report_fp = stderr; 3319b1aec48SLars Fredriksen 33201c855caSPeter Wemm if (to_log) { 3339b1aec48SLars Fredriksen #ifdef ultrix 3349b1aec48SLars Fredriksen openlog("chat", LOG_PID); 3359b1aec48SLars Fredriksen #else 3369b1aec48SLars Fredriksen openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3379b1aec48SLars Fredriksen 3389f65f104SPeter Wemm if (verbose) 3399b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_INFO)); 3409f65f104SPeter Wemm else 3419b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_WARNING)); 3429b1aec48SLars Fredriksen #endif 34301c855caSPeter Wemm } 3449b1aec48SLars Fredriksen 3459b1aec48SLars Fredriksen init(); 3469b1aec48SLars Fredriksen 34701c855caSPeter Wemm if (chat_file != NULL) { 3489b1aec48SLars Fredriksen arg = ARG(argc, argv); 3499b1aec48SLars Fredriksen if (arg != NULL) 3509b1aec48SLars Fredriksen usage(); 3519b1aec48SLars Fredriksen else 3529b1aec48SLars Fredriksen do_file (chat_file); 35301c855caSPeter Wemm } else { 35401c855caSPeter Wemm while ((arg = ARG(argc, argv)) != NULL) { 3559b1aec48SLars Fredriksen chat_expect(arg); 3569b1aec48SLars Fredriksen 3573d793cf1SPeter Wemm if ((arg = ARG(argc, argv)) != NULL) 3589b1aec48SLars Fredriksen chat_send(arg); 3599b1aec48SLars Fredriksen } 3609b1aec48SLars Fredriksen } 3619b1aec48SLars Fredriksen 3629b1aec48SLars Fredriksen terminate(0); 3633d793cf1SPeter Wemm return 0; 3649b1aec48SLars Fredriksen } 3659b1aec48SLars Fredriksen 3669b1aec48SLars Fredriksen /* 3679b1aec48SLars Fredriksen * Process a chat script when read from a file. 3689b1aec48SLars Fredriksen */ 3699b1aec48SLars Fredriksen 3709b1aec48SLars Fredriksen void do_file (chat_file) 3719b1aec48SLars Fredriksen char *chat_file; 3729b1aec48SLars Fredriksen { 373d7d10053SAlexander Langer int linect, sendflg; 3749b1aec48SLars Fredriksen char *sp, *arg, quote; 3759b1aec48SLars Fredriksen char buf [STR_LEN]; 3769b1aec48SLars Fredriksen FILE *cfp; 3779b1aec48SLars Fredriksen 3789f65f104SPeter Wemm cfp = fopen (chat_file, "r"); 3799f65f104SPeter Wemm if (cfp == NULL) 38001c855caSPeter Wemm fatal(1, "%s -- open failed: %m", chat_file); 3819b1aec48SLars Fredriksen 3829b1aec48SLars Fredriksen linect = 0; 3839b1aec48SLars Fredriksen sendflg = 0; 3849b1aec48SLars Fredriksen 38501c855caSPeter Wemm while (fgets(buf, STR_LEN, cfp) != NULL) { 3869b1aec48SLars Fredriksen sp = strchr (buf, '\n'); 3879b1aec48SLars Fredriksen if (sp) 3889b1aec48SLars Fredriksen *sp = '\0'; 3899b1aec48SLars Fredriksen 3909b1aec48SLars Fredriksen linect++; 3919b1aec48SLars Fredriksen sp = buf; 3923d793cf1SPeter Wemm 3933d793cf1SPeter Wemm /* lines starting with '#' are comments. If a real '#' 3943d793cf1SPeter Wemm is to be expected, it should be quoted .... */ 39501c855caSPeter Wemm if ( *sp == '#' ) 39601c855caSPeter Wemm continue; 3973d793cf1SPeter Wemm 39801c855caSPeter Wemm while (*sp != '\0') { 39901c855caSPeter Wemm if (*sp == ' ' || *sp == '\t') { 4009b1aec48SLars Fredriksen ++sp; 4019b1aec48SLars Fredriksen continue; 4029b1aec48SLars Fredriksen } 4039b1aec48SLars Fredriksen 40401c855caSPeter Wemm if (*sp == '"' || *sp == '\'') { 4059b1aec48SLars Fredriksen quote = *sp++; 4069b1aec48SLars Fredriksen arg = sp; 40701c855caSPeter Wemm while (*sp != quote) { 4089b1aec48SLars Fredriksen if (*sp == '\0') 40901c855caSPeter Wemm fatal(1, "unterminated quote (line %d)", linect); 4109b1aec48SLars Fredriksen 41101c855caSPeter Wemm if (*sp++ == '\\') { 4129b1aec48SLars Fredriksen if (*sp != '\0') 4139b1aec48SLars Fredriksen ++sp; 4149b1aec48SLars Fredriksen } 4159b1aec48SLars Fredriksen } 4169f65f104SPeter Wemm } 41701c855caSPeter Wemm else { 4189b1aec48SLars Fredriksen arg = sp; 4199b1aec48SLars Fredriksen while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4209b1aec48SLars Fredriksen ++sp; 4219b1aec48SLars Fredriksen } 4229b1aec48SLars Fredriksen 4239b1aec48SLars Fredriksen if (*sp != '\0') 4249b1aec48SLars Fredriksen *sp++ = '\0'; 4259b1aec48SLars Fredriksen 4269b1aec48SLars Fredriksen if (sendflg) 4279b1aec48SLars Fredriksen chat_send (arg); 4289b1aec48SLars Fredriksen else 4299b1aec48SLars Fredriksen chat_expect (arg); 4309b1aec48SLars Fredriksen sendflg = !sendflg; 4319b1aec48SLars Fredriksen } 4329b1aec48SLars Fredriksen } 4339b1aec48SLars Fredriksen fclose (cfp); 4349b1aec48SLars Fredriksen } 4359b1aec48SLars Fredriksen 4369b1aec48SLars Fredriksen /* 4379b1aec48SLars Fredriksen * We got an error parsing the command line. 4389b1aec48SLars Fredriksen */ 439afaeb553SPhilippe Charnier static void 440afaeb553SPhilippe Charnier usage() 4419b1aec48SLars Fredriksen { 44201c855caSPeter Wemm fprintf(stderr, "\ 44301c855caSPeter Wemm Usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\ 44401c855caSPeter Wemm [-U phone-number2] {-f chat-file | chat-script}\n"); 4459b1aec48SLars Fredriksen exit(1); 4469b1aec48SLars Fredriksen } 4479b1aec48SLars Fredriksen 44801c855caSPeter Wemm char line[1024]; 4499b1aec48SLars Fredriksen 4509b1aec48SLars Fredriksen /* 45101c855caSPeter Wemm * Send a message to syslog and/or stderr. 4529b1aec48SLars Fredriksen */ 453f1bb2cd2SWarner Losh void logf(const char *fmt, ...) 4549b1aec48SLars Fredriksen { 45501c855caSPeter Wemm va_list args; 45601c855caSPeter Wemm 45701c855caSPeter Wemm va_start(args, fmt); 45801c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 45901c855caSPeter Wemm if (to_log) 46001c855caSPeter Wemm syslog(LOG_INFO, "%s", line); 46101c855caSPeter Wemm if (to_stderr) 46201c855caSPeter Wemm fprintf(stderr, "%s\n", line); 4639b1aec48SLars Fredriksen } 4649b1aec48SLars Fredriksen 4659b1aec48SLars Fredriksen /* 4669b1aec48SLars Fredriksen * Print an error message and terminate. 4679b1aec48SLars Fredriksen */ 4689b1aec48SLars Fredriksen 469f1bb2cd2SWarner Losh void fatal(int code, const char *fmt, ...) 4709b1aec48SLars Fredriksen { 47101c855caSPeter Wemm va_list args; 4729b1aec48SLars Fredriksen 47301c855caSPeter Wemm va_start(args, fmt); 47401c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 47501c855caSPeter Wemm if (to_log) 47601c855caSPeter Wemm syslog(LOG_ERR, "%s", line); 47701c855caSPeter Wemm if (to_stderr) 47801c855caSPeter Wemm fprintf(stderr, "%s\n", line); 47901c855caSPeter Wemm terminate(code); 4809b1aec48SLars Fredriksen } 4819b1aec48SLars Fredriksen 4829b1aec48SLars Fredriksen int alarmed = 0; 4839b1aec48SLars Fredriksen 4849b1aec48SLars Fredriksen SIGTYPE sigalrm(signo) 4859b1aec48SLars Fredriksen int signo; 4869b1aec48SLars Fredriksen { 4879b1aec48SLars Fredriksen int flags; 4889b1aec48SLars Fredriksen 4899b1aec48SLars Fredriksen alarm(1); 4909b1aec48SLars Fredriksen alarmed = 1; /* Reset alarm to avoid race window */ 4919b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4929b1aec48SLars Fredriksen 4939b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 49401c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 49501c855caSPeter Wemm 4969f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 49701c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 4989b1aec48SLars Fredriksen 4999b1aec48SLars Fredriksen if (verbose) 50001c855caSPeter Wemm logf("alarm"); 5019b1aec48SLars Fredriksen } 5029b1aec48SLars Fredriksen 5039b1aec48SLars Fredriksen void unalarm() 5049b1aec48SLars Fredriksen { 5059b1aec48SLars Fredriksen int flags; 5069b1aec48SLars Fredriksen 5079b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 50801c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 50901c855caSPeter Wemm 5109f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 51101c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 5129f65f104SPeter Wemm } 5139b1aec48SLars Fredriksen 5149b1aec48SLars Fredriksen SIGTYPE sigint(signo) 5159b1aec48SLars Fredriksen int signo; 5169b1aec48SLars Fredriksen { 51701c855caSPeter Wemm fatal(2, "SIGINT"); 5189b1aec48SLars Fredriksen } 5199b1aec48SLars Fredriksen 5209b1aec48SLars Fredriksen SIGTYPE sigterm(signo) 5219b1aec48SLars Fredriksen int signo; 5229b1aec48SLars Fredriksen { 52301c855caSPeter Wemm fatal(2, "SIGTERM"); 5249b1aec48SLars Fredriksen } 5259b1aec48SLars Fredriksen 5269b1aec48SLars Fredriksen SIGTYPE sighup(signo) 5279b1aec48SLars Fredriksen int signo; 5289b1aec48SLars Fredriksen { 52901c855caSPeter Wemm fatal(2, "SIGHUP"); 5309b1aec48SLars Fredriksen } 5319b1aec48SLars Fredriksen 5329b1aec48SLars Fredriksen void init() 5339b1aec48SLars Fredriksen { 5349b1aec48SLars Fredriksen signal(SIGINT, sigint); 5359b1aec48SLars Fredriksen signal(SIGTERM, sigterm); 5369b1aec48SLars Fredriksen signal(SIGHUP, sighup); 5379b1aec48SLars Fredriksen 5389b1aec48SLars Fredriksen set_tty_parameters(); 5399b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); 5409b1aec48SLars Fredriksen alarm(0); 5419b1aec48SLars Fredriksen alarmed = 0; 5429b1aec48SLars Fredriksen } 5439b1aec48SLars Fredriksen 5449b1aec48SLars Fredriksen void set_tty_parameters() 5459b1aec48SLars Fredriksen { 5469f65f104SPeter Wemm #if defined(get_term_param) 5479f65f104SPeter Wemm term_parms t; 5489b1aec48SLars Fredriksen 5499f65f104SPeter Wemm if (get_term_param (&t) < 0) 55001c855caSPeter Wemm fatal(2, "Can't get terminal parameters: %m"); 5519b1aec48SLars Fredriksen 5529b1aec48SLars Fredriksen saved_tty_parameters = t; 5539b1aec48SLars Fredriksen have_tty_parameters = 1; 5549b1aec48SLars Fredriksen 5559b1aec48SLars Fredriksen t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 5569b1aec48SLars Fredriksen t.c_oflag = 0; 5579b1aec48SLars Fredriksen t.c_lflag = 0; 5589f65f104SPeter Wemm t.c_cc[VERASE] = 5599f65f104SPeter Wemm t.c_cc[VKILL] = 0; 5609b1aec48SLars Fredriksen t.c_cc[VMIN] = 1; 5619b1aec48SLars Fredriksen t.c_cc[VTIME] = 0; 5629b1aec48SLars Fredriksen 5639f65f104SPeter Wemm if (set_term_param (&t) < 0) 56401c855caSPeter Wemm fatal(2, "Can't set terminal parameters: %m"); 5659b1aec48SLars Fredriksen #endif 5669b1aec48SLars Fredriksen } 5679b1aec48SLars Fredriksen 5689b1aec48SLars Fredriksen void break_sequence() 5699b1aec48SLars Fredriksen { 5709b1aec48SLars Fredriksen #ifdef TERMIOS 5719b1aec48SLars Fredriksen tcsendbreak (0, 0); 5729b1aec48SLars Fredriksen #endif 5739b1aec48SLars Fredriksen } 5749b1aec48SLars Fredriksen 5759b1aec48SLars Fredriksen void terminate(status) 5769b1aec48SLars Fredriksen int status; 5779b1aec48SLars Fredriksen { 5783d793cf1SPeter Wemm echo_stderr(-1); 57901c855caSPeter Wemm if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 5803d793cf1SPeter Wemm /* 5813d793cf1SPeter Wemm * Allow the last of the report string to be gathered before we terminate. 5823d793cf1SPeter Wemm */ 5833d793cf1SPeter Wemm if (report_gathering) { 5843d793cf1SPeter Wemm int c, rep_len; 5853d793cf1SPeter Wemm 5863d793cf1SPeter Wemm rep_len = strlen(report_buffer); 5873d793cf1SPeter Wemm while (rep_len + 1 <= sizeof(report_buffer)) { 5883d793cf1SPeter Wemm alarm(1); 5893d793cf1SPeter Wemm c = get_char(); 5903d793cf1SPeter Wemm alarm(0); 5913d793cf1SPeter Wemm if (c < 0 || iscntrl(c)) 5923d793cf1SPeter Wemm break; 5933d793cf1SPeter Wemm report_buffer[rep_len] = c; 5943d793cf1SPeter Wemm ++rep_len; 5953d793cf1SPeter Wemm } 5963d793cf1SPeter Wemm report_buffer[rep_len] = 0; 5973d793cf1SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 5983d793cf1SPeter Wemm } 5999f65f104SPeter Wemm if (verbose) 6009f65f104SPeter Wemm fprintf (report_fp, "Closing \"%s\".\n", report_file); 6019f65f104SPeter Wemm fclose (report_fp); 6029f65f104SPeter Wemm report_fp = (FILE *) NULL; 6039f65f104SPeter Wemm } 6049f65f104SPeter Wemm 6059f65f104SPeter Wemm #if defined(get_term_param) 60601c855caSPeter Wemm if (have_tty_parameters) { 6079f65f104SPeter Wemm if (set_term_param (&saved_tty_parameters) < 0) 60801c855caSPeter Wemm fatal(2, "Can't restore terminal parameters: %m"); 6099f65f104SPeter Wemm } 6109f65f104SPeter Wemm #endif 6119f65f104SPeter Wemm 6129b1aec48SLars Fredriksen exit(status); 6139b1aec48SLars Fredriksen } 6149b1aec48SLars Fredriksen 6159b1aec48SLars Fredriksen /* 6169b1aec48SLars Fredriksen * 'Clean up' this string. 6179b1aec48SLars Fredriksen */ 6189b1aec48SLars Fredriksen char *clean(s, sending) 6199b1aec48SLars Fredriksen register char *s; 62001c855caSPeter Wemm int sending; /* set to 1 when sending (putting) this string. */ 6219b1aec48SLars Fredriksen { 6229b1aec48SLars Fredriksen char temp[STR_LEN], cur_chr; 62301c855caSPeter Wemm register char *s1, *phchar; 6249b1aec48SLars Fredriksen int add_return = sending; 6259b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6269b1aec48SLars Fredriksen 6279b1aec48SLars Fredriksen s1 = temp; 6284e83a8feSKris Kennaway /* Don't overflow buffer, leave room for chars we append later */ 6294e83a8feSKris Kennaway while (*s && s1 - temp < sizeof(temp) - 2 - add_return) { 6309b1aec48SLars Fredriksen cur_chr = *s++; 63101c855caSPeter Wemm if (cur_chr == '^') { 6329b1aec48SLars Fredriksen cur_chr = *s++; 63301c855caSPeter Wemm if (cur_chr == '\0') { 6349b1aec48SLars Fredriksen *s1++ = '^'; 6359b1aec48SLars Fredriksen break; 6369b1aec48SLars Fredriksen } 6379b1aec48SLars Fredriksen cur_chr &= 0x1F; 63801c855caSPeter Wemm if (cur_chr != 0) { 6399b1aec48SLars Fredriksen *s1++ = cur_chr; 6409f65f104SPeter Wemm } 6419b1aec48SLars Fredriksen continue; 6429b1aec48SLars Fredriksen } 6439b1aec48SLars Fredriksen 64401c855caSPeter Wemm if (cur_chr != '\\') { 6459b1aec48SLars Fredriksen *s1++ = cur_chr; 6469b1aec48SLars Fredriksen continue; 6479b1aec48SLars Fredriksen } 6489b1aec48SLars Fredriksen 6499b1aec48SLars Fredriksen cur_chr = *s++; 65001c855caSPeter Wemm if (cur_chr == '\0') { 65101c855caSPeter Wemm if (sending) { 6529b1aec48SLars Fredriksen *s1++ = '\\'; 6539b1aec48SLars Fredriksen *s1++ = '\\'; 6549b1aec48SLars Fredriksen } 6559b1aec48SLars Fredriksen break; 6569b1aec48SLars Fredriksen } 6579b1aec48SLars Fredriksen 65801c855caSPeter Wemm switch (cur_chr) { 6599b1aec48SLars Fredriksen case 'b': 6609b1aec48SLars Fredriksen *s1++ = '\b'; 6619b1aec48SLars Fredriksen break; 6629b1aec48SLars Fredriksen 6639b1aec48SLars Fredriksen case 'c': 6649b1aec48SLars Fredriksen if (sending && *s == '\0') 6659b1aec48SLars Fredriksen add_return = 0; 6669b1aec48SLars Fredriksen else 6679b1aec48SLars Fredriksen *s1++ = cur_chr; 6689b1aec48SLars Fredriksen break; 6699b1aec48SLars Fredriksen 6709b1aec48SLars Fredriksen case '\\': 6719b1aec48SLars Fredriksen case 'K': 6729b1aec48SLars Fredriksen case 'p': 6739b1aec48SLars Fredriksen case 'd': 6749b1aec48SLars Fredriksen if (sending) 6759b1aec48SLars Fredriksen *s1++ = '\\'; 6769b1aec48SLars Fredriksen 6779b1aec48SLars Fredriksen *s1++ = cur_chr; 6789b1aec48SLars Fredriksen break; 6799b1aec48SLars Fredriksen 68001c855caSPeter Wemm case 'T': 68101c855caSPeter Wemm if (sending && phone_num) { 68201c855caSPeter Wemm for ( phchar = phone_num; *phchar != '\0'; phchar++) 68301c855caSPeter Wemm *s1++ = *phchar; 68401c855caSPeter Wemm } 68501c855caSPeter Wemm else { 68601c855caSPeter Wemm *s1++ = '\\'; 68701c855caSPeter Wemm *s1++ = 'T'; 68801c855caSPeter Wemm } 68901c855caSPeter Wemm break; 69001c855caSPeter Wemm 69101c855caSPeter Wemm case 'U': 69201c855caSPeter Wemm if (sending && phone_num2) { 69301c855caSPeter Wemm for ( phchar = phone_num2; *phchar != '\0'; phchar++) 69401c855caSPeter Wemm *s1++ = *phchar; 69501c855caSPeter Wemm } 69601c855caSPeter Wemm else { 69701c855caSPeter Wemm *s1++ = '\\'; 69801c855caSPeter Wemm *s1++ = 'U'; 69901c855caSPeter Wemm } 70001c855caSPeter Wemm break; 70101c855caSPeter Wemm 7029b1aec48SLars Fredriksen case 'q': 7033d793cf1SPeter Wemm quiet = 1; 7049b1aec48SLars Fredriksen break; 7059b1aec48SLars Fredriksen 7069b1aec48SLars Fredriksen case 'r': 7079b1aec48SLars Fredriksen *s1++ = '\r'; 7089b1aec48SLars Fredriksen break; 7099b1aec48SLars Fredriksen 7109b1aec48SLars Fredriksen case 'n': 7119b1aec48SLars Fredriksen *s1++ = '\n'; 7129b1aec48SLars Fredriksen break; 7139b1aec48SLars Fredriksen 7149b1aec48SLars Fredriksen case 's': 7159b1aec48SLars Fredriksen *s1++ = ' '; 7169b1aec48SLars Fredriksen break; 7179b1aec48SLars Fredriksen 7189b1aec48SLars Fredriksen case 't': 7199b1aec48SLars Fredriksen *s1++ = '\t'; 7209b1aec48SLars Fredriksen break; 7219b1aec48SLars Fredriksen 7229b1aec48SLars Fredriksen case 'N': 72301c855caSPeter Wemm if (sending) { 7249b1aec48SLars Fredriksen *s1++ = '\\'; 7259b1aec48SLars Fredriksen *s1++ = '\0'; 7269b1aec48SLars Fredriksen } 7279b1aec48SLars Fredriksen else 7289b1aec48SLars Fredriksen *s1++ = 'N'; 7299b1aec48SLars Fredriksen break; 7309b1aec48SLars Fredriksen 7319b1aec48SLars Fredriksen default: 73201c855caSPeter Wemm if (isoctal (cur_chr)) { 7339b1aec48SLars Fredriksen cur_chr &= 0x07; 73401c855caSPeter Wemm if (isoctal (*s)) { 7359b1aec48SLars Fredriksen cur_chr <<= 3; 7369b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 73701c855caSPeter Wemm if (isoctal (*s)) { 7389b1aec48SLars Fredriksen cur_chr <<= 3; 7399b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 7409b1aec48SLars Fredriksen } 7419b1aec48SLars Fredriksen } 7429b1aec48SLars Fredriksen 74301c855caSPeter Wemm if (cur_chr != 0 || sending) { 7449b1aec48SLars Fredriksen if (sending && (cur_chr == '\\' || cur_chr == 0)) 7459b1aec48SLars Fredriksen *s1++ = '\\'; 7469b1aec48SLars Fredriksen *s1++ = cur_chr; 7479b1aec48SLars Fredriksen } 7489b1aec48SLars Fredriksen break; 7499b1aec48SLars Fredriksen } 7509b1aec48SLars Fredriksen 7519b1aec48SLars Fredriksen if (sending) 7529b1aec48SLars Fredriksen *s1++ = '\\'; 7539b1aec48SLars Fredriksen *s1++ = cur_chr; 7549b1aec48SLars Fredriksen break; 7559b1aec48SLars Fredriksen } 7569b1aec48SLars Fredriksen } 7579b1aec48SLars Fredriksen 7589b1aec48SLars Fredriksen if (add_return) 7599b1aec48SLars Fredriksen *s1++ = '\r'; 7609b1aec48SLars Fredriksen 7619b1aec48SLars Fredriksen *s1++ = '\0'; /* guarantee closure */ 7629b1aec48SLars Fredriksen *s1++ = '\0'; /* terminate the string */ 7639b1aec48SLars Fredriksen return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7649b1aec48SLars Fredriksen } 7659b1aec48SLars Fredriksen 7669b1aec48SLars Fredriksen /* 7673d793cf1SPeter Wemm * A modified version of 'strtok'. This version skips \ sequences. 7683d793cf1SPeter Wemm */ 7693d793cf1SPeter Wemm 7703d793cf1SPeter Wemm char *expect_strtok (s, term) 7713d793cf1SPeter Wemm char *s, *term; 7723d793cf1SPeter Wemm { 7733d793cf1SPeter Wemm static char *str = ""; 7743d793cf1SPeter Wemm int escape_flag = 0; 7753d793cf1SPeter Wemm char *result; 77601c855caSPeter Wemm 7773d793cf1SPeter Wemm /* 7783d793cf1SPeter Wemm * If a string was specified then do initial processing. 7793d793cf1SPeter Wemm */ 7803d793cf1SPeter Wemm if (s) 7813d793cf1SPeter Wemm str = s; 78201c855caSPeter Wemm 7833d793cf1SPeter Wemm /* 7843d793cf1SPeter Wemm * If this is the escape flag then reset it and ignore the character. 7853d793cf1SPeter Wemm */ 7863d793cf1SPeter Wemm if (*str) 7873d793cf1SPeter Wemm result = str; 7883d793cf1SPeter Wemm else 7893d793cf1SPeter Wemm result = (char *) 0; 7903d793cf1SPeter Wemm 79101c855caSPeter Wemm while (*str) { 79201c855caSPeter Wemm if (escape_flag) { 7933d793cf1SPeter Wemm escape_flag = 0; 7943d793cf1SPeter Wemm ++str; 7953d793cf1SPeter Wemm continue; 7963d793cf1SPeter Wemm } 7973d793cf1SPeter Wemm 79801c855caSPeter Wemm if (*str == '\\') { 7993d793cf1SPeter Wemm ++str; 8003d793cf1SPeter Wemm escape_flag = 1; 8013d793cf1SPeter Wemm continue; 8023d793cf1SPeter Wemm } 80301c855caSPeter Wemm 8043d793cf1SPeter Wemm /* 8053d793cf1SPeter Wemm * If this is not in the termination string, continue. 8063d793cf1SPeter Wemm */ 80701c855caSPeter Wemm if (strchr (term, *str) == (char *) 0) { 8083d793cf1SPeter Wemm ++str; 8093d793cf1SPeter Wemm continue; 8103d793cf1SPeter Wemm } 81101c855caSPeter Wemm 8123d793cf1SPeter Wemm /* 8133d793cf1SPeter Wemm * This is the terminator. Mark the end of the string and stop. 8143d793cf1SPeter Wemm */ 8153d793cf1SPeter Wemm *str++ = '\0'; 8163d793cf1SPeter Wemm break; 8173d793cf1SPeter Wemm } 8183d793cf1SPeter Wemm return (result); 8193d793cf1SPeter Wemm } 8203d793cf1SPeter Wemm 8213d793cf1SPeter Wemm /* 8229b1aec48SLars Fredriksen * Process the expect string 8239b1aec48SLars Fredriksen */ 8243d793cf1SPeter Wemm 8259b1aec48SLars Fredriksen void chat_expect (s) 8263d793cf1SPeter Wemm char *s; 8279b1aec48SLars Fredriksen { 8283d793cf1SPeter Wemm char *expect; 8293d793cf1SPeter Wemm char *reply; 8303d793cf1SPeter Wemm 83101c855caSPeter Wemm if (strcmp(s, "HANGUP") == 0) { 8323d793cf1SPeter Wemm ++hup_next; 8333d793cf1SPeter Wemm return; 8343d793cf1SPeter Wemm } 8353d793cf1SPeter Wemm 83601c855caSPeter Wemm if (strcmp(s, "ABORT") == 0) { 8379b1aec48SLars Fredriksen ++abort_next; 8389b1aec48SLars Fredriksen return; 8399b1aec48SLars Fredriksen } 8409b1aec48SLars Fredriksen 84101c855caSPeter Wemm if (strcmp(s, "CLR_ABORT") == 0) { 8423d793cf1SPeter Wemm ++clear_abort_next; 8433d793cf1SPeter Wemm return; 8443d793cf1SPeter Wemm } 8453d793cf1SPeter Wemm 84601c855caSPeter Wemm if (strcmp(s, "REPORT") == 0) { 8479f65f104SPeter Wemm ++report_next; 8489f65f104SPeter Wemm return; 8499f65f104SPeter Wemm } 8509f65f104SPeter Wemm 85101c855caSPeter Wemm if (strcmp(s, "CLR_REPORT") == 0) { 8523d793cf1SPeter Wemm ++clear_report_next; 8533d793cf1SPeter Wemm return; 8543d793cf1SPeter Wemm } 8553d793cf1SPeter Wemm 85601c855caSPeter Wemm if (strcmp(s, "TIMEOUT") == 0) { 8579b1aec48SLars Fredriksen ++timeout_next; 8589b1aec48SLars Fredriksen return; 8599b1aec48SLars Fredriksen } 8609b1aec48SLars Fredriksen 86101c855caSPeter Wemm if (strcmp(s, "ECHO") == 0) { 8623d793cf1SPeter Wemm ++echo_next; 8633d793cf1SPeter Wemm return; 8643d793cf1SPeter Wemm } 86501c855caSPeter Wemm 86601c855caSPeter Wemm if (strcmp(s, "SAY") == 0) { 8673d793cf1SPeter Wemm ++say_next; 8683d793cf1SPeter Wemm return; 8693d793cf1SPeter Wemm } 87001c855caSPeter Wemm 8713d793cf1SPeter Wemm /* 8723d793cf1SPeter Wemm * Fetch the expect and reply string. 8733d793cf1SPeter Wemm */ 87401c855caSPeter Wemm for (;;) { 8753d793cf1SPeter Wemm expect = expect_strtok (s, "-"); 8763d793cf1SPeter Wemm s = (char *) 0; 8779b1aec48SLars Fredriksen 8783d793cf1SPeter Wemm if (expect == (char *) 0) 8793d793cf1SPeter Wemm return; 8803d793cf1SPeter Wemm 8813d793cf1SPeter Wemm reply = expect_strtok (s, "-"); 88201c855caSPeter Wemm 8833d793cf1SPeter Wemm /* 8843d793cf1SPeter Wemm * Handle the expect string. If successful then exit. 8853d793cf1SPeter Wemm */ 8863d793cf1SPeter Wemm if (get_string (expect)) 8873d793cf1SPeter Wemm return; 88801c855caSPeter Wemm 8893d793cf1SPeter Wemm /* 8903d793cf1SPeter Wemm * If there is a sub-reply string then send it. Otherwise any condition 8913d793cf1SPeter Wemm * is terminal. 8923d793cf1SPeter Wemm */ 8933d793cf1SPeter Wemm if (reply == (char *) 0 || exit_code != 3) 8949b1aec48SLars Fredriksen break; 8959b1aec48SLars Fredriksen 8963d793cf1SPeter Wemm chat_send (reply); 8979f65f104SPeter Wemm } 89801c855caSPeter Wemm 8993d793cf1SPeter Wemm /* 9003d793cf1SPeter Wemm * The expectation did not occur. This is terminal. 9013d793cf1SPeter Wemm */ 9029b1aec48SLars Fredriksen if (fail_reason) 90301c855caSPeter Wemm logf("Failed (%s)", fail_reason); 9049b1aec48SLars Fredriksen else 90501c855caSPeter Wemm logf("Failed"); 9069f65f104SPeter Wemm terminate(exit_code); 9079f65f104SPeter Wemm } 9083d793cf1SPeter Wemm 9093d793cf1SPeter Wemm /* 9103d793cf1SPeter Wemm * Translate the input character to the appropriate string for printing 9113d793cf1SPeter Wemm * the data. 9123d793cf1SPeter Wemm */ 9139b1aec48SLars Fredriksen 9149b1aec48SLars Fredriksen char *character(c) 9159f65f104SPeter Wemm int c; 9169b1aec48SLars Fredriksen { 9179b1aec48SLars Fredriksen static char string[10]; 9189b1aec48SLars Fredriksen char *meta; 9199b1aec48SLars Fredriksen 9209b1aec48SLars Fredriksen meta = (c & 0x80) ? "M-" : ""; 9219b1aec48SLars Fredriksen c &= 0x7F; 9229b1aec48SLars Fredriksen 9239b1aec48SLars Fredriksen if (c < 32) 9249b1aec48SLars Fredriksen sprintf(string, "%s^%c", meta, (int)c + '@'); 92501c855caSPeter Wemm else if (c == 127) 9269b1aec48SLars Fredriksen sprintf(string, "%s^?", meta); 9279b1aec48SLars Fredriksen else 9289b1aec48SLars Fredriksen sprintf(string, "%s%c", meta, c); 9299b1aec48SLars Fredriksen 9309b1aec48SLars Fredriksen return (string); 9319b1aec48SLars Fredriksen } 9329b1aec48SLars Fredriksen 9339b1aec48SLars Fredriksen /* 9349b1aec48SLars Fredriksen * process the reply string 9359b1aec48SLars Fredriksen */ 9369b1aec48SLars Fredriksen void chat_send (s) 9379b1aec48SLars Fredriksen register char *s; 9389b1aec48SLars Fredriksen { 93901c855caSPeter Wemm if (say_next) { 9403d793cf1SPeter Wemm say_next = 0; 9413d793cf1SPeter Wemm s = clean(s,0); 942e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s)); 9433d793cf1SPeter Wemm free(s); 9443d793cf1SPeter Wemm return; 9453d793cf1SPeter Wemm } 94601c855caSPeter Wemm 94701c855caSPeter Wemm if (hup_next) { 9483d793cf1SPeter Wemm hup_next = 0; 9493d793cf1SPeter Wemm if (strcmp(s, "OFF") == 0) 9503d793cf1SPeter Wemm signal(SIGHUP, SIG_IGN); 9513d793cf1SPeter Wemm else 9523d793cf1SPeter Wemm signal(SIGHUP, sighup); 9533d793cf1SPeter Wemm return; 9543d793cf1SPeter Wemm } 95501c855caSPeter Wemm 95601c855caSPeter Wemm if (echo_next) { 9573d793cf1SPeter Wemm echo_next = 0; 9583d793cf1SPeter Wemm echo = (strcmp(s, "ON") == 0); 9593d793cf1SPeter Wemm return; 9603d793cf1SPeter Wemm } 96101c855caSPeter Wemm 96201c855caSPeter Wemm if (abort_next) { 9639b1aec48SLars Fredriksen char *s1; 9649b1aec48SLars Fredriksen 9659b1aec48SLars Fredriksen abort_next = 0; 9669b1aec48SLars Fredriksen 9679b1aec48SLars Fredriksen if (n_aborts >= MAX_ABORTS) 96801c855caSPeter Wemm fatal(2, "Too many ABORT strings"); 9699b1aec48SLars Fredriksen 9709b1aec48SLars Fredriksen s1 = clean(s, 0); 9719b1aec48SLars Fredriksen 9729f65f104SPeter Wemm if (strlen(s1) > strlen(s) 9739f65f104SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 97401c855caSPeter Wemm fatal(1, "Illegal or too-long ABORT string ('%v')", s); 9759b1aec48SLars Fredriksen 9769b1aec48SLars Fredriksen abort_string[n_aborts++] = s1; 9779b1aec48SLars Fredriksen 9789b1aec48SLars Fredriksen if (verbose) 97901c855caSPeter Wemm logf("abort on (%v)", s); 9809f65f104SPeter Wemm return; 9819b1aec48SLars Fredriksen } 9829f65f104SPeter Wemm 98301c855caSPeter Wemm if (clear_abort_next) { 9843d793cf1SPeter Wemm char *s1; 9853d793cf1SPeter Wemm int i; 9863d793cf1SPeter Wemm int old_max; 9873d793cf1SPeter Wemm int pack = 0; 9883d793cf1SPeter Wemm 9893d793cf1SPeter Wemm clear_abort_next = 0; 9903d793cf1SPeter Wemm 9913d793cf1SPeter Wemm s1 = clean(s, 0); 9923d793cf1SPeter Wemm 9933d793cf1SPeter Wemm if (strlen(s1) > strlen(s) 9943d793cf1SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 99501c855caSPeter Wemm fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 9963d793cf1SPeter Wemm 9973d793cf1SPeter Wemm old_max = n_aborts; 99801c855caSPeter Wemm for (i=0; i < n_aborts; i++) { 99901c855caSPeter Wemm if ( strcmp(s1,abort_string[i]) == 0 ) { 10003d793cf1SPeter Wemm free(abort_string[i]); 10013d793cf1SPeter Wemm abort_string[i] = NULL; 10023d793cf1SPeter Wemm pack++; 10033d793cf1SPeter Wemm n_aborts--; 10043d793cf1SPeter Wemm if (verbose) 100501c855caSPeter Wemm logf("clear abort on (%v)", s); 10063d793cf1SPeter Wemm } 10073d793cf1SPeter Wemm } 10083d793cf1SPeter Wemm free(s1); 100901c855caSPeter Wemm if (pack) 101001c855caSPeter Wemm pack_array(abort_string,old_max); 10113d793cf1SPeter Wemm return; 10123d793cf1SPeter Wemm } 10133d793cf1SPeter Wemm 101401c855caSPeter Wemm if (report_next) { 10159f65f104SPeter Wemm char *s1; 10169f65f104SPeter Wemm 10179f65f104SPeter Wemm report_next = 0; 10189f65f104SPeter Wemm if (n_reports >= MAX_REPORTS) 101901c855caSPeter Wemm fatal(2, "Too many REPORT strings"); 10209f65f104SPeter Wemm 10219f65f104SPeter Wemm s1 = clean(s, 0); 10229f65f104SPeter Wemm 10239f65f104SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 102401c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 10259f65f104SPeter Wemm 10269f65f104SPeter Wemm report_string[n_reports++] = s1; 10279f65f104SPeter Wemm 10289f65f104SPeter Wemm if (verbose) 102901c855caSPeter Wemm logf("report (%v)", s); 10309f65f104SPeter Wemm return; 10319f65f104SPeter Wemm } 10329f65f104SPeter Wemm 103301c855caSPeter Wemm if (clear_report_next) { 10343d793cf1SPeter Wemm char *s1; 10353d793cf1SPeter Wemm int i; 10363d793cf1SPeter Wemm int old_max; 10373d793cf1SPeter Wemm int pack = 0; 10383d793cf1SPeter Wemm 10393d793cf1SPeter Wemm clear_report_next = 0; 10403d793cf1SPeter Wemm 10413d793cf1SPeter Wemm s1 = clean(s, 0); 10423d793cf1SPeter Wemm 10433d793cf1SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 104401c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 10453d793cf1SPeter Wemm 10463d793cf1SPeter Wemm old_max = n_reports; 104701c855caSPeter Wemm for (i=0; i < n_reports; i++) { 104801c855caSPeter Wemm if ( strcmp(s1,report_string[i]) == 0 ) { 10493d793cf1SPeter Wemm free(report_string[i]); 10503d793cf1SPeter Wemm report_string[i] = NULL; 10513d793cf1SPeter Wemm pack++; 10523d793cf1SPeter Wemm n_reports--; 10533d793cf1SPeter Wemm if (verbose) 105401c855caSPeter Wemm logf("clear report (%v)", s); 10553d793cf1SPeter Wemm } 10563d793cf1SPeter Wemm } 10573d793cf1SPeter Wemm free(s1); 105801c855caSPeter Wemm if (pack) 105901c855caSPeter Wemm pack_array(report_string,old_max); 10603d793cf1SPeter Wemm 10613d793cf1SPeter Wemm return; 10623d793cf1SPeter Wemm } 10633d793cf1SPeter Wemm 106401c855caSPeter Wemm if (timeout_next) { 10659b1aec48SLars Fredriksen timeout_next = 0; 10669b1aec48SLars Fredriksen timeout = atoi(s); 10679b1aec48SLars Fredriksen 10689b1aec48SLars Fredriksen if (timeout <= 0) 10699b1aec48SLars Fredriksen timeout = DEFAULT_CHAT_TIMEOUT; 10709b1aec48SLars Fredriksen 10719b1aec48SLars Fredriksen if (verbose) 107201c855caSPeter Wemm logf("timeout set to %d seconds", timeout); 107301c855caSPeter Wemm 10749f65f104SPeter Wemm return; 10759f65f104SPeter Wemm } 10769f65f104SPeter Wemm 10779f65f104SPeter Wemm if (strcmp(s, "EOT") == 0) 10789f65f104SPeter Wemm s = "^D\\c"; 107901c855caSPeter Wemm else if (strcmp(s, "BREAK") == 0) 10809b1aec48SLars Fredriksen s = "\\K\\c"; 10819f65f104SPeter Wemm 10829b1aec48SLars Fredriksen if (!put_string(s)) 108301c855caSPeter Wemm fatal(1, "Failed"); 10849b1aec48SLars Fredriksen } 10859b1aec48SLars Fredriksen 10869b1aec48SLars Fredriksen int get_char() 10879b1aec48SLars Fredriksen { 10889b1aec48SLars Fredriksen int status; 10899b1aec48SLars Fredriksen char c; 10909b1aec48SLars Fredriksen 1091e1b4d8d0SSheldon Hearn status = read(STDIN_FILENO, &c, 1); 10929b1aec48SLars Fredriksen 109301c855caSPeter Wemm switch (status) { 10949b1aec48SLars Fredriksen case 1: 10959b1aec48SLars Fredriksen return ((int)c & 0x7F); 10969b1aec48SLars Fredriksen 10979b1aec48SLars Fredriksen default: 109801c855caSPeter Wemm logf("warning: read() on stdin returned %d", status); 10999b1aec48SLars Fredriksen 11009b1aec48SLars Fredriksen case -1: 11019b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 110201c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 110301c855caSPeter Wemm 11049f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 110501c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 11069b1aec48SLars Fredriksen 11079b1aec48SLars Fredriksen return (-1); 11089b1aec48SLars Fredriksen } 11099b1aec48SLars Fredriksen } 11109b1aec48SLars Fredriksen 11119b1aec48SLars Fredriksen int put_char(c) 11129f65f104SPeter Wemm int c; 11139b1aec48SLars Fredriksen { 11149b1aec48SLars Fredriksen int status; 11159f65f104SPeter Wemm char ch = c; 11169b1aec48SLars Fredriksen 11179f65f104SPeter Wemm usleep(10000); /* inter-character typing delay (?) */ 11189b1aec48SLars Fredriksen 1119e1b4d8d0SSheldon Hearn status = write(STDOUT_FILENO, &ch, 1); 11209b1aec48SLars Fredriksen 112101c855caSPeter Wemm switch (status) { 11229b1aec48SLars Fredriksen case 1: 11239b1aec48SLars Fredriksen return (0); 11249b1aec48SLars Fredriksen 11259b1aec48SLars Fredriksen default: 112601c855caSPeter Wemm logf("warning: write() on stdout returned %d", status); 11279b1aec48SLars Fredriksen 11289b1aec48SLars Fredriksen case -1: 11299b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 113001c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin, %m"); 113101c855caSPeter Wemm 11329f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113301c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 11349b1aec48SLars Fredriksen 11359b1aec48SLars Fredriksen return (-1); 11369b1aec48SLars Fredriksen } 11379b1aec48SLars Fredriksen } 11389b1aec48SLars Fredriksen 11399b1aec48SLars Fredriksen int write_char (c) 11409b1aec48SLars Fredriksen int c; 11419b1aec48SLars Fredriksen { 114201c855caSPeter Wemm if (alarmed || put_char(c) < 0) { 11439f65f104SPeter Wemm alarm(0); 11449f65f104SPeter Wemm alarmed = 0; 11459b1aec48SLars Fredriksen 114601c855caSPeter Wemm if (verbose) { 11479b1aec48SLars Fredriksen if (errno == EINTR || errno == EWOULDBLOCK) 114801c855caSPeter Wemm logf(" -- write timed out"); 11499b1aec48SLars Fredriksen else 115001c855caSPeter Wemm logf(" -- write failed: %m"); 11519f65f104SPeter Wemm } 11529b1aec48SLars Fredriksen return (0); 11539b1aec48SLars Fredriksen } 11549b1aec48SLars Fredriksen return (1); 11559b1aec48SLars Fredriksen } 11569b1aec48SLars Fredriksen 11579b1aec48SLars Fredriksen int put_string (s) 11589b1aec48SLars Fredriksen register char *s; 11599b1aec48SLars Fredriksen { 11603d793cf1SPeter Wemm quiet = 0; 11619b1aec48SLars Fredriksen s = clean(s, 1); 11629b1aec48SLars Fredriksen 116301c855caSPeter Wemm if (verbose) { 11649b1aec48SLars Fredriksen if (quiet) 116501c855caSPeter Wemm logf("send (??????)"); 11669b1aec48SLars Fredriksen else 116701c855caSPeter Wemm logf("send (%v)", s); 11689b1aec48SLars Fredriksen } 11699b1aec48SLars Fredriksen 11709b1aec48SLars Fredriksen alarm(timeout); alarmed = 0; 11719b1aec48SLars Fredriksen 117201c855caSPeter Wemm while (*s) { 11739b1aec48SLars Fredriksen register char c = *s++; 11749b1aec48SLars Fredriksen 117501c855caSPeter Wemm if (c != '\\') { 11769b1aec48SLars Fredriksen if (!write_char (c)) 11779b1aec48SLars Fredriksen return 0; 11789b1aec48SLars Fredriksen continue; 11799b1aec48SLars Fredriksen } 11809b1aec48SLars Fredriksen 11819b1aec48SLars Fredriksen c = *s++; 118201c855caSPeter Wemm switch (c) { 11839b1aec48SLars Fredriksen case 'd': 11849b1aec48SLars Fredriksen sleep(1); 11859b1aec48SLars Fredriksen break; 11869b1aec48SLars Fredriksen 11879b1aec48SLars Fredriksen case 'K': 11889b1aec48SLars Fredriksen break_sequence(); 11899b1aec48SLars Fredriksen break; 11909b1aec48SLars Fredriksen 11919b1aec48SLars Fredriksen case 'p': 11929f65f104SPeter Wemm usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11939b1aec48SLars Fredriksen break; 11949b1aec48SLars Fredriksen 11959b1aec48SLars Fredriksen default: 11969b1aec48SLars Fredriksen if (!write_char (c)) 11979b1aec48SLars Fredriksen return 0; 11989b1aec48SLars Fredriksen break; 11999b1aec48SLars Fredriksen } 12009b1aec48SLars Fredriksen } 12019b1aec48SLars Fredriksen 12029b1aec48SLars Fredriksen alarm(0); 12039b1aec48SLars Fredriksen alarmed = 0; 12049b1aec48SLars Fredriksen return (1); 12059b1aec48SLars Fredriksen } 12069b1aec48SLars Fredriksen 12079b1aec48SLars Fredriksen /* 12083d793cf1SPeter Wemm * Echo a character to stderr. 12093d793cf1SPeter Wemm * When called with -1, a '\n' character is generated when 12103d793cf1SPeter Wemm * the cursor is not at the beginning of a line. 12113d793cf1SPeter Wemm */ 12123d793cf1SPeter Wemm void echo_stderr(n) 12133d793cf1SPeter Wemm int n; 12143d793cf1SPeter Wemm { 12153d793cf1SPeter Wemm static int need_lf; 12163d793cf1SPeter Wemm char *s; 12173d793cf1SPeter Wemm 121801c855caSPeter Wemm switch (n) { 12193d793cf1SPeter Wemm case '\r': /* ignore '\r' */ 12203d793cf1SPeter Wemm break; 12213d793cf1SPeter Wemm case -1: 12223d793cf1SPeter Wemm if (need_lf == 0) 12233d793cf1SPeter Wemm break; 122493b0017fSPhilippe Charnier /* FALLTHROUGH */ 12253d793cf1SPeter Wemm case '\n': 1226e1b4d8d0SSheldon Hearn write(STDERR_FILENO, "\n", 1); 12273d793cf1SPeter Wemm need_lf = 0; 12283d793cf1SPeter Wemm break; 12293d793cf1SPeter Wemm default: 12303d793cf1SPeter Wemm s = character(n); 1231e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s)); 12323d793cf1SPeter Wemm need_lf = 1; 12333d793cf1SPeter Wemm break; 12343d793cf1SPeter Wemm } 12353d793cf1SPeter Wemm } 12363d793cf1SPeter Wemm 12373d793cf1SPeter Wemm /* 12389b1aec48SLars Fredriksen * 'Wait for' this string to appear on this file descriptor. 12399b1aec48SLars Fredriksen */ 12409b1aec48SLars Fredriksen int get_string(string) 12419b1aec48SLars Fredriksen register char *string; 12429b1aec48SLars Fredriksen { 12439b1aec48SLars Fredriksen char temp[STR_LEN]; 12449b1aec48SLars Fredriksen int c, printed = 0, len, minlen; 12459b1aec48SLars Fredriksen register char *s = temp, *end = s + STR_LEN; 124601c855caSPeter Wemm char *logged = temp; 12479b1aec48SLars Fredriksen 12489b1aec48SLars Fredriksen fail_reason = (char *)0; 12494e83a8feSKris Kennaway 12504e83a8feSKris Kennaway if (strlen(string) > STR_LEN) { 12514e83a8feSKris Kennaway logf("expect string is too long"); 12524e83a8feSKris Kennaway exit_code = 1; 12534e83a8feSKris Kennaway return 0; 12544e83a8feSKris Kennaway } 12554e83a8feSKris Kennaway 12569b1aec48SLars Fredriksen string = clean(string, 0); 12579b1aec48SLars Fredriksen len = strlen(string); 12589b1aec48SLars Fredriksen minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12599b1aec48SLars Fredriksen 12609b1aec48SLars Fredriksen if (verbose) 126101c855caSPeter Wemm logf("expect (%v)", string); 12629b1aec48SLars Fredriksen 126301c855caSPeter Wemm if (len == 0) { 12649b1aec48SLars Fredriksen if (verbose) 126501c855caSPeter Wemm logf("got it"); 12669b1aec48SLars Fredriksen return (1); 12679b1aec48SLars Fredriksen } 12689b1aec48SLars Fredriksen 12699f65f104SPeter Wemm alarm(timeout); 12709f65f104SPeter Wemm alarmed = 0; 12719b1aec48SLars Fredriksen 127201c855caSPeter Wemm while ( ! alarmed && (c = get_char()) >= 0) { 12739f65f104SPeter Wemm int n, abort_len, report_len; 12749b1aec48SLars Fredriksen 12753d793cf1SPeter Wemm if (echo) 12763d793cf1SPeter Wemm echo_stderr(c); 127701c855caSPeter Wemm if (verbose && c == '\n') { 127801c855caSPeter Wemm if (s == logged) 127901c855caSPeter Wemm logf(""); /* blank line */ 12809b1aec48SLars Fredriksen else 128101c855caSPeter Wemm logf("%0.*v", s - logged, logged); 128201c855caSPeter Wemm logged = s + 1; 12833d793cf1SPeter Wemm } 12843d793cf1SPeter Wemm 12859b1aec48SLars Fredriksen *s++ = c; 12869b1aec48SLars Fredriksen 128701c855caSPeter Wemm if (verbose && s >= logged + 80) { 128801c855caSPeter Wemm logf("%0.*v", s - logged, logged); 128901c855caSPeter Wemm logged = s; 129001c855caSPeter Wemm } 129101c855caSPeter Wemm 129201c855caSPeter Wemm if (Verbose) { 129301c855caSPeter Wemm if (c == '\n') 129401c855caSPeter Wemm fputc( '\n', stderr ); 129501c855caSPeter Wemm else if (c != '\r') 129601c855caSPeter Wemm fprintf( stderr, "%s", character(c) ); 129701c855caSPeter Wemm } 129801c855caSPeter Wemm 129901c855caSPeter Wemm if (!report_gathering) { 130001c855caSPeter Wemm for (n = 0; n < n_reports; ++n) { 13019f65f104SPeter Wemm if ((report_string[n] != (char*) NULL) && 13029f65f104SPeter Wemm s - temp >= (report_len = strlen(report_string[n])) && 130301c855caSPeter Wemm strncmp(s - report_len, report_string[n], report_len) == 0) { 13049f65f104SPeter Wemm time_t time_now = time ((time_t*) NULL); 13059f65f104SPeter Wemm struct tm* tm_now = localtime (&time_now); 13069f65f104SPeter Wemm 13079f65f104SPeter Wemm strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 13089f65f104SPeter Wemm strcat (report_buffer, report_string[n]); 13099f65f104SPeter Wemm 13109f65f104SPeter Wemm report_string[n] = (char *) NULL; 13119f65f104SPeter Wemm report_gathering = 1; 13129f65f104SPeter Wemm break; 13139f65f104SPeter Wemm } 13149f65f104SPeter Wemm } 13159f65f104SPeter Wemm } 131601c855caSPeter Wemm else { 131701c855caSPeter Wemm if (!iscntrl (c)) { 13189f65f104SPeter Wemm int rep_len = strlen (report_buffer); 13199f65f104SPeter Wemm report_buffer[rep_len] = c; 13209f65f104SPeter Wemm report_buffer[rep_len + 1] = '\0'; 13219f65f104SPeter Wemm } 132201c855caSPeter Wemm else { 13239f65f104SPeter Wemm report_gathering = 0; 13249f65f104SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 13259f65f104SPeter Wemm } 13269f65f104SPeter Wemm } 13279b1aec48SLars Fredriksen 13283d793cf1SPeter Wemm if (s - temp >= len && 13293d793cf1SPeter Wemm c == string[len - 1] && 133001c855caSPeter Wemm strncmp(s - len, string, len) == 0) { 133101c855caSPeter Wemm if (verbose) { 133201c855caSPeter Wemm if (s > logged) 133301c855caSPeter Wemm logf("%0.*v", s - logged, logged); 13343d793cf1SPeter Wemm logf(" -- got it\n"); 13353d793cf1SPeter Wemm } 13363d793cf1SPeter Wemm 13373d793cf1SPeter Wemm alarm(0); 13383d793cf1SPeter Wemm alarmed = 0; 13393d793cf1SPeter Wemm return (1); 13403d793cf1SPeter Wemm } 13413d793cf1SPeter Wemm 134201c855caSPeter Wemm for (n = 0; n < n_aborts; ++n) { 13433d793cf1SPeter Wemm if (s - temp >= (abort_len = strlen(abort_string[n])) && 134401c855caSPeter Wemm strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 134501c855caSPeter Wemm if (verbose) { 134601c855caSPeter Wemm if (s > logged) 134701c855caSPeter Wemm logf("%0.*v", s - logged, logged); 134801c855caSPeter Wemm logf(" -- failed"); 13493d793cf1SPeter Wemm } 13503d793cf1SPeter Wemm 13513d793cf1SPeter Wemm alarm(0); 13523d793cf1SPeter Wemm alarmed = 0; 13533d793cf1SPeter Wemm exit_code = n + 4; 13543d793cf1SPeter Wemm strcpy(fail_reason = fail_buffer, abort_string[n]); 13553d793cf1SPeter Wemm return (0); 13563d793cf1SPeter Wemm } 13573d793cf1SPeter Wemm } 13583d793cf1SPeter Wemm 135901c855caSPeter Wemm if (s >= end) { 136001c855caSPeter Wemm if (logged < s - minlen) { 136101c855caSPeter Wemm logf("%0.*v", s - logged, logged); 136201c855caSPeter Wemm logged = s; 136301c855caSPeter Wemm } 136401c855caSPeter Wemm s -= minlen; 136501c855caSPeter Wemm memmove(temp, s, minlen); 136601c855caSPeter Wemm logged = temp + (logged - s); 13679b1aec48SLars Fredriksen s = temp + minlen; 13689b1aec48SLars Fredriksen } 13699b1aec48SLars Fredriksen 13709b1aec48SLars Fredriksen if (alarmed && verbose) 137101c855caSPeter Wemm logf("warning: alarm synchronization problem"); 13729f65f104SPeter Wemm } 13739b1aec48SLars Fredriksen 13749b1aec48SLars Fredriksen alarm(0); 13759b1aec48SLars Fredriksen 137601c855caSPeter Wemm if (verbose && printed) { 13779b1aec48SLars Fredriksen if (alarmed) 137801c855caSPeter Wemm logf(" -- read timed out"); 13799b1aec48SLars Fredriksen else 138001c855caSPeter Wemm logf(" -- read failed: %m"); 13819b1aec48SLars Fredriksen } 13829b1aec48SLars Fredriksen 13839f65f104SPeter Wemm exit_code = 3; 13849b1aec48SLars Fredriksen alarmed = 0; 13859b1aec48SLars Fredriksen return (0); 13869b1aec48SLars Fredriksen } 13879b1aec48SLars Fredriksen 13887288c503SPeter Wemm /* 13897288c503SPeter Wemm * Gross kludge to handle Solaris versions >= 2.6 having usleep. 13907288c503SPeter Wemm */ 13917288c503SPeter Wemm #ifdef SOL2 13927288c503SPeter Wemm #include <sys/param.h> 13937288c503SPeter Wemm #if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 13947288c503SPeter Wemm #undef NO_USLEEP 13957288c503SPeter Wemm #endif 13967288c503SPeter Wemm #endif /* SOL2 */ 13977288c503SPeter Wemm 13989f65f104SPeter Wemm #ifdef NO_USLEEP 13999b1aec48SLars Fredriksen #include <sys/types.h> 14009b1aec48SLars Fredriksen #include <sys/time.h> 14019b1aec48SLars Fredriksen 14029b1aec48SLars Fredriksen /* 14039b1aec48SLars Fredriksen usleep -- support routine for 4.2BSD system call emulations 14049b1aec48SLars Fredriksen last edit: 29-Oct-1984 D A Gwyn 14059b1aec48SLars Fredriksen */ 14069b1aec48SLars Fredriksen 14079b1aec48SLars Fredriksen extern int select(); 14089b1aec48SLars Fredriksen 14099b1aec48SLars Fredriksen int 14109b1aec48SLars Fredriksen usleep( usec ) /* returns 0 if ok, else -1 */ 14119b1aec48SLars Fredriksen long usec; /* delay in microseconds */ 14129b1aec48SLars Fredriksen { 141301c855caSPeter Wemm static struct { /* `timeval' */ 14149b1aec48SLars Fredriksen long tv_sec; /* seconds */ 14159b1aec48SLars Fredriksen long tv_usec; /* microsecs */ 14169b1aec48SLars Fredriksen } delay; /* _select() timeout */ 14179b1aec48SLars Fredriksen 14189b1aec48SLars Fredriksen delay.tv_sec = usec / 1000000L; 14199b1aec48SLars Fredriksen delay.tv_usec = usec % 1000000L; 14209b1aec48SLars Fredriksen 14219b1aec48SLars Fredriksen return select(0, (long *)0, (long *)0, (long *)0, &delay); 14229b1aec48SLars Fredriksen } 14239b1aec48SLars Fredriksen #endif 14243d793cf1SPeter Wemm 14253d793cf1SPeter Wemm void 14263d793cf1SPeter Wemm pack_array (array, end) 14273d793cf1SPeter Wemm char **array; /* The address of the array of string pointers */ 14283d793cf1SPeter Wemm int end; /* The index of the next free entry before CLR_ */ 14293d793cf1SPeter Wemm { 14303d793cf1SPeter Wemm int i, j; 14313d793cf1SPeter Wemm 14323d793cf1SPeter Wemm for (i = 0; i < end; i++) { 14333d793cf1SPeter Wemm if (array[i] == NULL) { 14343d793cf1SPeter Wemm for (j = i+1; j < end; ++j) 14353d793cf1SPeter Wemm if (array[j] != NULL) 14363d793cf1SPeter Wemm array[i++] = array[j]; 14373d793cf1SPeter Wemm for (; i < end; ++i) 14383d793cf1SPeter Wemm array[i] = NULL; 14393d793cf1SPeter Wemm break; 14403d793cf1SPeter Wemm } 14413d793cf1SPeter Wemm } 14423d793cf1SPeter Wemm } 144301c855caSPeter Wemm 144401c855caSPeter Wemm /* 144501c855caSPeter Wemm * vfmtmsg - format a message into a buffer. Like vsprintf except we 144601c855caSPeter Wemm * also specify the length of the output buffer, and we handle the 144701c855caSPeter Wemm * %m (error message) format. 144801c855caSPeter Wemm * Doesn't do floating-point formats. 144901c855caSPeter Wemm * Returns the number of chars put into buf. 145001c855caSPeter Wemm */ 145101c855caSPeter Wemm #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 145201c855caSPeter Wemm 145301c855caSPeter Wemm int 145401c855caSPeter Wemm vfmtmsg(buf, buflen, fmt, args) 145501c855caSPeter Wemm char *buf; 145601c855caSPeter Wemm int buflen; 145701c855caSPeter Wemm const char *fmt; 145801c855caSPeter Wemm va_list args; 145901c855caSPeter Wemm { 146001c855caSPeter Wemm int c, i, n; 146101c855caSPeter Wemm int width, prec, fillch; 146201c855caSPeter Wemm int base, len, neg, quoted; 146301c855caSPeter Wemm unsigned long val = 0; 146401c855caSPeter Wemm char *str, *buf0; 146501c855caSPeter Wemm const char *f; 146601c855caSPeter Wemm unsigned char *p; 146701c855caSPeter Wemm char num[32]; 146801c855caSPeter Wemm static char hexchars[] = "0123456789abcdef"; 146901c855caSPeter Wemm 147001c855caSPeter Wemm buf0 = buf; 147101c855caSPeter Wemm --buflen; 147201c855caSPeter Wemm while (buflen > 0) { 147301c855caSPeter Wemm for (f = fmt; *f != '%' && *f != 0; ++f) 147401c855caSPeter Wemm ; 147501c855caSPeter Wemm if (f > fmt) { 147601c855caSPeter Wemm len = f - fmt; 147701c855caSPeter Wemm if (len > buflen) 147801c855caSPeter Wemm len = buflen; 147901c855caSPeter Wemm memcpy(buf, fmt, len); 148001c855caSPeter Wemm buf += len; 148101c855caSPeter Wemm buflen -= len; 148201c855caSPeter Wemm fmt = f; 148301c855caSPeter Wemm } 148401c855caSPeter Wemm if (*fmt == 0) 148501c855caSPeter Wemm break; 148601c855caSPeter Wemm c = *++fmt; 148701c855caSPeter Wemm width = prec = 0; 148801c855caSPeter Wemm fillch = ' '; 148901c855caSPeter Wemm if (c == '0') { 149001c855caSPeter Wemm fillch = '0'; 149101c855caSPeter Wemm c = *++fmt; 149201c855caSPeter Wemm } 149301c855caSPeter Wemm if (c == '*') { 149401c855caSPeter Wemm width = va_arg(args, int); 149501c855caSPeter Wemm c = *++fmt; 149601c855caSPeter Wemm } else { 149701c855caSPeter Wemm while (isdigit(c)) { 149801c855caSPeter Wemm width = width * 10 + c - '0'; 149901c855caSPeter Wemm c = *++fmt; 150001c855caSPeter Wemm } 150101c855caSPeter Wemm } 150201c855caSPeter Wemm if (c == '.') { 150301c855caSPeter Wemm c = *++fmt; 150401c855caSPeter Wemm if (c == '*') { 150501c855caSPeter Wemm prec = va_arg(args, int); 150601c855caSPeter Wemm c = *++fmt; 150701c855caSPeter Wemm } else { 150801c855caSPeter Wemm while (isdigit(c)) { 150901c855caSPeter Wemm prec = prec * 10 + c - '0'; 151001c855caSPeter Wemm c = *++fmt; 151101c855caSPeter Wemm } 151201c855caSPeter Wemm } 151301c855caSPeter Wemm } 151401c855caSPeter Wemm str = 0; 151501c855caSPeter Wemm base = 0; 151601c855caSPeter Wemm neg = 0; 151701c855caSPeter Wemm ++fmt; 151801c855caSPeter Wemm switch (c) { 151901c855caSPeter Wemm case 'd': 152001c855caSPeter Wemm i = va_arg(args, int); 152101c855caSPeter Wemm if (i < 0) { 152201c855caSPeter Wemm neg = 1; 152301c855caSPeter Wemm val = -i; 152401c855caSPeter Wemm } else 152501c855caSPeter Wemm val = i; 152601c855caSPeter Wemm base = 10; 152701c855caSPeter Wemm break; 152801c855caSPeter Wemm case 'o': 152901c855caSPeter Wemm val = va_arg(args, unsigned int); 153001c855caSPeter Wemm base = 8; 153101c855caSPeter Wemm break; 153201c855caSPeter Wemm case 'x': 153301c855caSPeter Wemm val = va_arg(args, unsigned int); 153401c855caSPeter Wemm base = 16; 153501c855caSPeter Wemm break; 153601c855caSPeter Wemm case 'p': 153701c855caSPeter Wemm val = (unsigned long) va_arg(args, void *); 153801c855caSPeter Wemm base = 16; 153901c855caSPeter Wemm neg = 2; 154001c855caSPeter Wemm break; 154101c855caSPeter Wemm case 's': 154201c855caSPeter Wemm str = va_arg(args, char *); 154301c855caSPeter Wemm break; 154401c855caSPeter Wemm case 'c': 154501c855caSPeter Wemm num[0] = va_arg(args, int); 154601c855caSPeter Wemm num[1] = 0; 154701c855caSPeter Wemm str = num; 154801c855caSPeter Wemm break; 154901c855caSPeter Wemm case 'm': 155001c855caSPeter Wemm str = strerror(errno); 155101c855caSPeter Wemm break; 155201c855caSPeter Wemm case 'v': /* "visible" string */ 155301c855caSPeter Wemm case 'q': /* quoted string */ 155401c855caSPeter Wemm quoted = c == 'q'; 155501c855caSPeter Wemm p = va_arg(args, unsigned char *); 155601c855caSPeter Wemm if (fillch == '0' && prec > 0) { 155701c855caSPeter Wemm n = prec; 155801c855caSPeter Wemm } else { 155901c855caSPeter Wemm n = strlen((char *)p); 156001c855caSPeter Wemm if (prec > 0 && prec < n) 156101c855caSPeter Wemm n = prec; 156201c855caSPeter Wemm } 156301c855caSPeter Wemm while (n > 0 && buflen > 0) { 156401c855caSPeter Wemm c = *p++; 156501c855caSPeter Wemm --n; 156601c855caSPeter Wemm if (!quoted && c >= 0x80) { 156701c855caSPeter Wemm OUTCHAR('M'); 156801c855caSPeter Wemm OUTCHAR('-'); 156901c855caSPeter Wemm c -= 0x80; 157001c855caSPeter Wemm } 157101c855caSPeter Wemm if (quoted && (c == '"' || c == '\\')) 157201c855caSPeter Wemm OUTCHAR('\\'); 157301c855caSPeter Wemm if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 157401c855caSPeter Wemm if (quoted) { 157501c855caSPeter Wemm OUTCHAR('\\'); 157601c855caSPeter Wemm switch (c) { 157701c855caSPeter Wemm case '\t': OUTCHAR('t'); break; 157801c855caSPeter Wemm case '\n': OUTCHAR('n'); break; 157901c855caSPeter Wemm case '\b': OUTCHAR('b'); break; 158001c855caSPeter Wemm case '\f': OUTCHAR('f'); break; 158101c855caSPeter Wemm default: 158201c855caSPeter Wemm OUTCHAR('x'); 158301c855caSPeter Wemm OUTCHAR(hexchars[c >> 4]); 158401c855caSPeter Wemm OUTCHAR(hexchars[c & 0xf]); 158501c855caSPeter Wemm } 158601c855caSPeter Wemm } else { 158701c855caSPeter Wemm if (c == '\t') 158801c855caSPeter Wemm OUTCHAR(c); 158901c855caSPeter Wemm else { 159001c855caSPeter Wemm OUTCHAR('^'); 159101c855caSPeter Wemm OUTCHAR(c ^ 0x40); 159201c855caSPeter Wemm } 159301c855caSPeter Wemm } 159401c855caSPeter Wemm } else 159501c855caSPeter Wemm OUTCHAR(c); 159601c855caSPeter Wemm } 159701c855caSPeter Wemm continue; 159801c855caSPeter Wemm default: 159901c855caSPeter Wemm *buf++ = '%'; 160001c855caSPeter Wemm if (c != '%') 160101c855caSPeter Wemm --fmt; /* so %z outputs %z etc. */ 160201c855caSPeter Wemm --buflen; 160301c855caSPeter Wemm continue; 160401c855caSPeter Wemm } 160501c855caSPeter Wemm if (base != 0) { 160601c855caSPeter Wemm str = num + sizeof(num); 160701c855caSPeter Wemm *--str = 0; 160801c855caSPeter Wemm while (str > num + neg) { 160901c855caSPeter Wemm *--str = hexchars[val % base]; 161001c855caSPeter Wemm val = val / base; 161101c855caSPeter Wemm if (--prec <= 0 && val == 0) 161201c855caSPeter Wemm break; 161301c855caSPeter Wemm } 161401c855caSPeter Wemm switch (neg) { 161501c855caSPeter Wemm case 1: 161601c855caSPeter Wemm *--str = '-'; 161701c855caSPeter Wemm break; 161801c855caSPeter Wemm case 2: 161901c855caSPeter Wemm *--str = 'x'; 162001c855caSPeter Wemm *--str = '0'; 162101c855caSPeter Wemm break; 162201c855caSPeter Wemm } 162301c855caSPeter Wemm len = num + sizeof(num) - 1 - str; 162401c855caSPeter Wemm } else { 162501c855caSPeter Wemm len = strlen(str); 162601c855caSPeter Wemm if (prec > 0 && len > prec) 162701c855caSPeter Wemm len = prec; 162801c855caSPeter Wemm } 162901c855caSPeter Wemm if (width > 0) { 163001c855caSPeter Wemm if (width > buflen) 163101c855caSPeter Wemm width = buflen; 163201c855caSPeter Wemm if ((n = width - len) > 0) { 163301c855caSPeter Wemm buflen -= n; 163401c855caSPeter Wemm for (; n > 0; --n) 163501c855caSPeter Wemm *buf++ = fillch; 163601c855caSPeter Wemm } 163701c855caSPeter Wemm } 163801c855caSPeter Wemm if (len > buflen) 163901c855caSPeter Wemm len = buflen; 164001c855caSPeter Wemm memcpy(buf, str, len); 164101c855caSPeter Wemm buf += len; 164201c855caSPeter Wemm buflen -= len; 164301c855caSPeter Wemm } 164401c855caSPeter Wemm *buf = 0; 164501c855caSPeter Wemm return buf - buf0; 164601c855caSPeter Wemm } 1647