chat.c revision 32069
14374Slars/* 24374Slars * Chat -- a program for automatic session establishment (i.e. dial 34374Slars * the phone and log in). 44374Slars * 511990Speter * Standard termination codes: 611990Speter * 0 - successful completion of the script 711990Speter * 1 - invalid argument, expect string too large, etc. 811990Speter * 2 - error on an I/O operation or fatal error condtion. 911990Speter * 3 - timeout waiting for a simple string. 1011990Speter * 4 - the first string declared as "ABORT" 1111990Speter * 5 - the second string declared as "ABORT" 1211990Speter * 6 - ... and so on for successive ABORT strings. 1311990Speter * 144374Slars * This software is in the public domain. 154374Slars * 1628597Speter * ----------------- 174374Slars * 1828597Speter * Added SAY keyword to send output to stderr. 1928597Speter * This allows to turn ECHO OFF and to output specific, user selected, 2028597Speter * text to give progress messages. This best works when stderr 2128597Speter * exists (i.e.: pppd in nodetach mode). 224374Slars * 2328597Speter * Added HANGUP directives to allow for us to be called 2428597Speter * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 2528597Speter * We rely on timeouts in that case. 2628597Speter * 2728597Speter * Added CLR_ABORT to clear previously set ABORT string. This has been 2828597Speter * dictated by the HANGUP above as "NO CARRIER" (for example) must be 2928597Speter * an ABORT condition until we know the other host is going to close 3028597Speter * the connection for call back. As soon as we have completed the 3128597Speter * first stage of the call back sequence, "NO CARRIER" is a valid, non 3228597Speter * fatal string. As soon as we got called back (probably get "CONNECT"), 3328597Speter * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 3428597Speter * Note that CLR_ABORT packs the abort_strings[] array so that we do not 3528597Speter * have unused entries not being reclaimed. 3628597Speter * 3728597Speter * In the same vein as above, added CLR_REPORT keyword. 3828597Speter * 3928597Speter * Allow for comments. Line starting with '#' are comments and are 4028597Speter * ignored. If a '#' is to be expected as the first character, the 4128597Speter * expect string must be quoted. 4228597Speter * 4328597Speter * 4428597Speter * Francis Demierre <Francis@SwissMail.Com> 4528597Speter * Thu May 15 17:15:40 MET DST 1997 4628597Speter * 4728597Speter * 4811990Speter * Added -r "report file" switch & REPORT keyword. 4911990Speter * Robert Geer <bgeer@xmission.com> 5011990Speter * 5128597Speter * 5228597Speter * Added -e "echo" switch & ECHO keyword 5328597Speter * Dick Streefland <dicks@tasking.nl> 5428597Speter * 5528597Speter * 5628597Speter * Considerable updates and modifications by 5728597Speter * Al Longyear <longyear@pobox.com> 5828597Speter * Paul Mackerras <paulus@cs.anu.edu.au> 5928597Speter * 6028597Speter * 614374Slars * The original author is: 624374Slars * 634374Slars * Karl Fox <karl@MorningStar.Com> 644374Slars * Morning Star Technologies, Inc. 654374Slars * 1760 Zollinger Road 664374Slars * Columbus, OH 43221 674374Slars * (614)451-1883 6811990Speter * 6928597Speter * 704374Slars */ 714374Slars 7228597Speter#ifndef lint 7332069Salexstatic char rcsid[] = "$Id: chat.c,v 1.9 1997/08/22 15:24:36 peter Exp $"; 7428597Speter#endif 754374Slars 764374Slars#include <stdio.h> 7728597Speter#include <ctype.h> 7811990Speter#include <time.h> 794374Slars#include <fcntl.h> 804374Slars#include <signal.h> 814374Slars#include <errno.h> 824374Slars#include <string.h> 834374Slars#include <stdlib.h> 8428597Speter#include <unistd.h> 854374Slars#include <sys/types.h> 864374Slars#include <sys/stat.h> 874374Slars#include <syslog.h> 884374Slars 894374Slars#ifndef TERMIO 904374Slars#undef TERMIOS 914374Slars#define TERMIOS 924374Slars#endif 934374Slars 944374Slars#ifdef TERMIO 954374Slars#include <termio.h> 964374Slars#endif 974374Slars#ifdef TERMIOS 984374Slars#include <termios.h> 994374Slars#endif 1004374Slars 1014374Slars#define STR_LEN 1024 1024374Slars 1034374Slars#ifndef SIGTYPE 1044374Slars#define SIGTYPE void 1054374Slars#endif 1064374Slars 1074374Slars#ifdef __STDC__ 1084374Slars#undef __P 1094374Slars#define __P(x) x 1104374Slars#else 1114374Slars#define __P(x) () 1124374Slars#define const 1134374Slars#endif 1144374Slars 11511990Speter#ifndef O_NONBLOCK 11611990Speter#define O_NONBLOCK O_NDELAY 11711990Speter#endif 11811990Speter 1194374Slars/*************** Micro getopt() *********************************************/ 1204374Slars#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1214374Slars (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1224374Slars &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1234374Slars#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1244374Slars (_O=4,(char*)0):(char*)0) 1254374Slars#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1264374Slars#define ARG(c,v) (c?(--c,*v++):(char*)0) 1274374Slars 1284374Slarsstatic int _O = 0; /* Internal state */ 1294374Slars/*************** Micro getopt() *********************************************/ 1304374Slars 1314374Slars#define MAX_ABORTS 50 13211990Speter#define MAX_REPORTS 50 1334374Slars#define DEFAULT_CHAT_TIMEOUT 45 1344374Slars 13528597Speterint echo = 0; 13611990Speterint verbose = 0; 13728597Speterint Verbose = 0; 13811990Speterint quiet = 0; 13911990Speterint report = 0; 14011990Speterint exit_code = 0; 14111990SpeterFILE* report_fp = (FILE *) 0; 14211990Speterchar *report_file = (char *) 0; 14311990Speterchar *chat_file = (char *) 0; 14411990Speterint timeout = DEFAULT_CHAT_TIMEOUT; 1454374Slars 1464374Slarsint have_tty_parameters = 0; 14711990Speter 1484374Slars#ifdef TERMIO 14911990Speter#define term_parms struct termio 15011990Speter#define get_term_param(param) ioctl(0, TCGETA, param) 15111990Speter#define set_term_param(param) ioctl(0, TCSETA, param) 1524374Slarsstruct termio saved_tty_parameters; 1534374Slars#endif 15411990Speter 1554374Slars#ifdef TERMIOS 15611990Speter#define term_parms struct termios 15711990Speter#define get_term_param(param) tcgetattr(0, param) 15811990Speter#define set_term_param(param) tcsetattr(0, TCSANOW, param) 1594374Slarsstruct termios saved_tty_parameters; 1604374Slars#endif 1614374Slars 1624374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1634374Slars fail_buffer[50]; 16428597Speterint n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 16528597Speterint clear_abort_next = 0; 1664374Slars 16711990Speterchar *report_string[MAX_REPORTS] ; 16811990Speterchar report_buffer[50] ; 16911990Speterint n_reports = 0, report_next = 0, report_gathering = 0 ; 17028597Speterint clear_report_next = 0; 17111990Speter 17228597Speterint say_next = 0, hup_next = 0; 17328597Speter 1744374Slarsvoid *dup_mem __P((void *b, size_t c)); 1754374Slarsvoid *copy_of __P((char *s)); 17626880Scharnierstatic void usage __P((void)); 1774374Slarsvoid logf __P((const char *str)); 1784374Slarsvoid logflush __P((void)); 1794374Slarsvoid fatal __P((const char *msg)); 1804374Slarsvoid sysfatal __P((const char *msg)); 1814374SlarsSIGTYPE sigalrm __P((int signo)); 1824374SlarsSIGTYPE sigint __P((int signo)); 1834374SlarsSIGTYPE sigterm __P((int signo)); 1844374SlarsSIGTYPE sighup __P((int signo)); 1854374Slarsvoid unalarm __P((void)); 1864374Slarsvoid init __P((void)); 1874374Slarsvoid set_tty_parameters __P((void)); 18828597Spetervoid echo_stderr __P((int)); 1894374Slarsvoid break_sequence __P((void)); 1904374Slarsvoid terminate __P((int status)); 1914374Slarsvoid do_file __P((char *chat_file)); 1924374Slarsint get_string __P((register char *string)); 1934374Slarsint put_string __P((register char *s)); 1944374Slarsint write_char __P((int c)); 19511990Speterint put_char __P((int c)); 1964374Slarsint get_char __P((void)); 1974374Slarsvoid chat_send __P((register char *s)); 19811990Speterchar *character __P((int c)); 1994374Slarsvoid chat_expect __P((register char *s)); 2004374Slarschar *clean __P((register char *s, int sending)); 2014374Slarsvoid break_sequence __P((void)); 2024374Slarsvoid terminate __P((int status)); 2034374Slarsvoid die __P((void)); 20428597Spetervoid pack_array __P((char **array, int end)); 20528597Speterchar *expect_strtok __P((char *, char *)); 2064374Slars 20728597Speterint main __P((int, char *[])); 20828597Speter 2094374Slarsvoid *dup_mem(b, c) 2104374Slarsvoid *b; 2114374Slarssize_t c; 2124374Slars { 2134374Slars void *ans = malloc (c); 2144374Slars if (!ans) 21511990Speter { 2164374Slars fatal ("memory error!\n"); 21711990Speter } 2184374Slars memcpy (ans, b, c); 2194374Slars return ans; 2204374Slars } 2214374Slars 2224374Slarsvoid *copy_of (s) 2234374Slarschar *s; 2244374Slars { 2254374Slars return dup_mem (s, strlen (s) + 1); 2264374Slars } 2274374Slars 2284374Slars/* 22911990Speter * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \ 2304374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2314374Slars * 2324374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 2334374Slars */ 2344374Slarsint 2354374Slarsmain(argc, argv) 2364374Slarsint argc; 2374374Slarschar **argv; 2384374Slars { 2394374Slars int option; 2404374Slars char *arg; 2414374Slars 24211990Speter tzset(); 2434374Slars 24428597Speter while ((option = OPTION(argc, argv)) != 0) 24511990Speter { 2464374Slars switch (option) 2474374Slars { 24828597Speter case 'e': 24928597Speter ++echo; 25028597Speter break; 25128597Speter 2524374Slars case 'v': 2534374Slars ++verbose; 2544374Slars break; 2554374Slars 25628597Speter case 'V': 25728597Speter ++Verbose; 25828597Speter break; 25928597Speter 2604374Slars case 'f': 26128597Speter if ((arg = OPTARG(argc, argv)) != NULL) 26211990Speter { 2634374Slars chat_file = copy_of(arg); 26411990Speter } 2654374Slars else 26611990Speter { 2674374Slars usage(); 26811990Speter } 2694374Slars break; 2704374Slars 2714374Slars case 't': 27228597Speter if ((arg = OPTARG(argc, argv)) != NULL) 27311990Speter { 2744374Slars timeout = atoi(arg); 27511990Speter } 2764374Slars else 27711990Speter { 2784374Slars usage(); 27911990Speter } 28011990Speter break; 2814374Slars 28211990Speter case 'r': 28311990Speter arg = OPTARG (argc, argv); 28411990Speter if (arg) 28511990Speter { 28611990Speter if (report_fp != NULL) 28711990Speter { 28811990Speter fclose (report_fp); 28911990Speter } 29011990Speter report_file = copy_of (arg); 29111990Speter report_fp = fopen (report_file, "a"); 29211990Speter if (report_fp != NULL) 29311990Speter { 29411990Speter if (verbose) 29511990Speter { 29611990Speter fprintf (report_fp, "Opening \"%s\"...\n", 29711990Speter report_file); 29811990Speter } 29911990Speter report = 1; 30011990Speter } 30111990Speter } 3024374Slars break; 3034374Slars 3044374Slars default: 3054374Slars usage(); 30611990Speter break; 3074374Slars } 30811990Speter } 30911990Speter/* 31011990Speter * Default the report file to the stderr location 31111990Speter */ 31211990Speter if (report_fp == NULL) 31311990Speter { 31411990Speter report_fp = stderr; 31511990Speter } 3164374Slars 3174374Slars#ifdef ultrix 3184374Slars openlog("chat", LOG_PID); 3194374Slars#else 3204374Slars openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3214374Slars 32211990Speter if (verbose) 32311990Speter { 3244374Slars setlogmask(LOG_UPTO(LOG_INFO)); 32511990Speter } 32611990Speter else 32711990Speter { 3284374Slars setlogmask(LOG_UPTO(LOG_WARNING)); 32911990Speter } 3304374Slars#endif 3314374Slars 3324374Slars init(); 33311990Speter 3344374Slars if (chat_file != NULL) 3354374Slars { 3364374Slars arg = ARG(argc, argv); 3374374Slars if (arg != NULL) 33811990Speter { 3394374Slars usage(); 34011990Speter } 3414374Slars else 34211990Speter { 3434374Slars do_file (chat_file); 34411990Speter } 3454374Slars } 3464374Slars else 3474374Slars { 34828597Speter while ((arg = ARG(argc, argv)) != NULL) 3494374Slars { 3504374Slars chat_expect(arg); 3514374Slars 35228597Speter if ((arg = ARG(argc, argv)) != NULL) 35311990Speter { 3544374Slars chat_send(arg); 35511990Speter } 3564374Slars } 3574374Slars } 3584374Slars 3594374Slars terminate(0); 36028597Speter return 0; 3614374Slars } 3624374Slars 3634374Slars/* 3644374Slars * Process a chat script when read from a file. 3654374Slars */ 3664374Slars 3674374Slarsvoid do_file (chat_file) 3684374Slarschar *chat_file; 3694374Slars { 37032069Salex int linect, sendflg; 3714374Slars char *sp, *arg, quote; 3724374Slars char buf [STR_LEN]; 3734374Slars FILE *cfp; 3744374Slars 37511990Speter cfp = fopen (chat_file, "r"); 37611990Speter if (cfp == NULL) 3774374Slars { 3784374Slars syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 3794374Slars terminate (1); 3804374Slars } 3814374Slars 3824374Slars linect = 0; 3834374Slars sendflg = 0; 3844374Slars 3854374Slars while (fgets(buf, STR_LEN, cfp) != NULL) 3864374Slars { 3874374Slars sp = strchr (buf, '\n'); 3884374Slars if (sp) 38911990Speter { 3904374Slars *sp = '\0'; 39111990Speter } 3924374Slars 3934374Slars linect++; 3944374Slars sp = buf; 39528597Speter 39628597Speter /* lines starting with '#' are comments. If a real '#' 39728597Speter is to be expected, it should be quoted .... */ 39828597Speter if ( *sp == '#' ) continue; 39928597Speter 4004374Slars while (*sp != '\0') 4014374Slars { 4024374Slars if (*sp == ' ' || *sp == '\t') 4034374Slars { 4044374Slars ++sp; 4054374Slars continue; 4064374Slars } 4074374Slars 4084374Slars if (*sp == '"' || *sp == '\'') 4094374Slars { 4104374Slars quote = *sp++; 4114374Slars arg = sp; 4124374Slars while (*sp != quote) 4134374Slars { 4144374Slars if (*sp == '\0') 4154374Slars { 4164374Slars syslog (LOG_ERR, "unterminated quote (line %d)", 4174374Slars linect); 4184374Slars terminate (1); 4194374Slars } 42011990Speter 4214374Slars if (*sp++ == '\\') 42211990Speter { 4234374Slars if (*sp != '\0') 42411990Speter { 4254374Slars ++sp; 42611990Speter } 42711990Speter } 4284374Slars } 4294374Slars } 4304374Slars else 4314374Slars { 4324374Slars arg = sp; 4334374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 43411990Speter { 4354374Slars ++sp; 43611990Speter } 4374374Slars } 4384374Slars 4394374Slars if (*sp != '\0') 44011990Speter { 4414374Slars *sp++ = '\0'; 44211990Speter } 4434374Slars 4444374Slars if (sendflg) 4454374Slars { 4464374Slars chat_send (arg); 4474374Slars } 4484374Slars else 4494374Slars { 4504374Slars chat_expect (arg); 4514374Slars } 4524374Slars sendflg = !sendflg; 4534374Slars } 4544374Slars } 4554374Slars fclose (cfp); 4564374Slars } 4574374Slars 4584374Slars/* 4594374Slars * We got an error parsing the command line. 4604374Slars */ 46126880Scharnierstatic void 46226880Scharnierusage() 4634374Slars { 46426880Scharnier fprintf(stderr, "%s %s\n", 46528597Speter "usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file]", 46626880Scharnier "{-f chat-file | chat-script}"); 4674374Slars exit(1); 4684374Slars } 4694374Slars 4704374Slarschar line[256]; 4714374Slarschar *p; 4724374Slars 4734374Slarsvoid logf (str) 4744374Slarsconst char *str; 47528597Speter{ 47628597Speter int l = strlen(line); 4774374Slars 47828597Speter if (l + strlen(str) >= sizeof(line)) { 47928597Speter syslog(LOG_INFO, "%s", line); 48028597Speter l = 0; 48128597Speter } 48228597Speter strcpy(line + l, str); 48328597Speter 48428597Speter if (str[strlen(str)-1] == '\n') { 4854374Slars syslog (LOG_INFO, "%s", line); 4864374Slars line[0] = 0; 4874374Slars } 48828597Speter} 4894374Slars 4904374Slarsvoid logflush() 4914374Slars { 4924374Slars if (line[0] != 0) 4934374Slars { 4944374Slars syslog(LOG_INFO, "%s", line); 4954374Slars line[0] = 0; 4964374Slars } 4974374Slars } 4984374Slars 4994374Slars/* 50011990Speter * Terminate with an error. 5014374Slars */ 5024374Slarsvoid die() 5034374Slars { 5044374Slars terminate(1); 5054374Slars } 5064374Slars 5074374Slars/* 5084374Slars * Print an error message and terminate. 5094374Slars */ 5104374Slars 5114374Slarsvoid fatal (msg) 5124374Slarsconst char *msg; 5134374Slars { 5144374Slars syslog(LOG_ERR, "%s", msg); 51511990Speter terminate(2); 5164374Slars } 5174374Slars 5184374Slars/* 5194374Slars * Print an error message along with the system error message and 5204374Slars * terminate. 5214374Slars */ 5224374Slars 5234374Slarsvoid sysfatal (msg) 5244374Slarsconst char *msg; 5254374Slars { 5264374Slars syslog(LOG_ERR, "%s: %m", msg); 52711990Speter terminate(2); 5284374Slars } 5294374Slars 5304374Slarsint alarmed = 0; 5314374Slars 5324374SlarsSIGTYPE sigalrm(signo) 5334374Slarsint signo; 5344374Slars { 5354374Slars int flags; 5364374Slars 5374374Slars alarm(1); 5384374Slars alarmed = 1; /* Reset alarm to avoid race window */ 5394374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 5404374Slars 5414374Slars logflush(); 5424374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 54311990Speter { 5444374Slars sysfatal("Can't get file mode flags on stdin"); 54511990Speter } 5464374Slars else 54711990Speter { 54811990Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 54911990Speter { 5504374Slars sysfatal("Can't set file mode flags on stdin"); 55111990Speter } 55211990Speter } 5534374Slars 5544374Slars if (verbose) 5554374Slars { 5564374Slars syslog(LOG_INFO, "alarm"); 5574374Slars } 5584374Slars } 5594374Slars 5604374Slarsvoid unalarm() 5614374Slars { 5624374Slars int flags; 5634374Slars 5644374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 56511990Speter { 5664374Slars sysfatal("Can't get file mode flags on stdin"); 56711990Speter } 5684374Slars else 56911990Speter { 57011990Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 57111990Speter { 5724374Slars sysfatal("Can't set file mode flags on stdin"); 57311990Speter } 57411990Speter } 5754374Slars } 5764374Slars 5774374SlarsSIGTYPE sigint(signo) 5784374Slarsint signo; 5794374Slars { 5804374Slars fatal("SIGINT"); 5814374Slars } 5824374Slars 5834374SlarsSIGTYPE sigterm(signo) 5844374Slarsint signo; 5854374Slars { 5864374Slars fatal("SIGTERM"); 5874374Slars } 5884374Slars 5894374SlarsSIGTYPE sighup(signo) 5904374Slarsint signo; 5914374Slars { 5924374Slars fatal("SIGHUP"); 5934374Slars } 5944374Slars 5954374Slarsvoid init() 5964374Slars { 5974374Slars signal(SIGINT, sigint); 5984374Slars signal(SIGTERM, sigterm); 5994374Slars signal(SIGHUP, sighup); 6004374Slars 6014374Slars set_tty_parameters(); 6024374Slars signal(SIGALRM, sigalrm); 6034374Slars alarm(0); 6044374Slars alarmed = 0; 6054374Slars } 6064374Slars 6074374Slarsvoid set_tty_parameters() 6084374Slars { 60911990Speter#if defined(get_term_param) 61011990Speter term_parms t; 6114374Slars 61211990Speter if (get_term_param (&t) < 0) 61311990Speter { 61424541Sjmg have_tty_parameters = 0; 61524541Sjmg return; 61611990Speter } 6174374Slars 6184374Slars saved_tty_parameters = t; 61911990Speter have_tty_parameters = 1; 6204374Slars 62111990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 62211990Speter t.c_oflag = 0; 62311990Speter t.c_lflag = 0; 62411990Speter t.c_cc[VERASE] = 62511990Speter t.c_cc[VKILL] = 0; 62611990Speter t.c_cc[VMIN] = 1; 62711990Speter t.c_cc[VTIME] = 0; 6284374Slars 62911990Speter if (set_term_param (&t) < 0) 63011990Speter { 6314374Slars sysfatal("Can't set terminal parameters"); 63211990Speter } 6334374Slars#endif 6344374Slars } 6354374Slars 6364374Slarsvoid break_sequence() 6374374Slars { 6384374Slars#ifdef TERMIOS 6394374Slars tcsendbreak (0, 0); 6404374Slars#endif 6414374Slars } 6424374Slars 6434374Slarsvoid terminate(status) 6444374Slarsint status; 6454374Slars { 64628597Speter echo_stderr(-1); 64711990Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 64828597Speter { 64928597Speter/* 65028597Speter * Allow the last of the report string to be gathered before we terminate. 65128597Speter */ 65228597Speter if (report_gathering) { 65328597Speter int c, rep_len; 65428597Speter 65528597Speter rep_len = strlen(report_buffer); 65628597Speter while (rep_len + 1 <= sizeof(report_buffer)) { 65728597Speter alarm(1); 65828597Speter c = get_char(); 65928597Speter alarm(0); 66028597Speter if (c < 0 || iscntrl(c)) 66128597Speter break; 66228597Speter report_buffer[rep_len] = c; 66328597Speter ++rep_len; 66428597Speter } 66528597Speter report_buffer[rep_len] = 0; 66628597Speter fprintf (report_fp, "chat: %s\n", report_buffer); 66728597Speter } 66811990Speter if (verbose) 66911990Speter { 67011990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 67111990Speter } 67211990Speter fclose (report_fp); 67328597Speter report_fp = (FILE *) NULL; 6744374Slars } 6754374Slars 67611990Speter#if defined(get_term_param) 67711990Speter if (have_tty_parameters) 67811990Speter { 67911990Speter if (set_term_param (&saved_tty_parameters) < 0) 68011990Speter { 68111990Speter syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 68211990Speter exit(1); 68311990Speter } 68411990Speter } 68511990Speter#endif 6864374Slars 68711990Speter exit(status); 6884374Slars } 6894374Slars 6904374Slars/* 6914374Slars * 'Clean up' this string. 6924374Slars */ 6934374Slarschar *clean(s, sending) 6944374Slarsregister char *s; 6954374Slarsint sending; 6964374Slars { 6974374Slars char temp[STR_LEN], cur_chr; 6984374Slars register char *s1; 6994374Slars int add_return = sending; 7004374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 7014374Slars 7024374Slars s1 = temp; 7034374Slars while (*s) 7044374Slars { 7054374Slars cur_chr = *s++; 7064374Slars if (cur_chr == '^') 7074374Slars { 7084374Slars cur_chr = *s++; 7094374Slars if (cur_chr == '\0') 7104374Slars { 7114374Slars *s1++ = '^'; 7124374Slars break; 7134374Slars } 7144374Slars cur_chr &= 0x1F; 7154374Slars if (cur_chr != 0) 71611990Speter { 7174374Slars *s1++ = cur_chr; 71811990Speter } 7194374Slars continue; 7204374Slars } 7214374Slars 7224374Slars if (cur_chr != '\\') 7234374Slars { 7244374Slars *s1++ = cur_chr; 7254374Slars continue; 7264374Slars } 7274374Slars 7284374Slars cur_chr = *s++; 7294374Slars if (cur_chr == '\0') 7304374Slars { 7314374Slars if (sending) 7324374Slars { 7334374Slars *s1++ = '\\'; 7344374Slars *s1++ = '\\'; 7354374Slars } 7364374Slars break; 7374374Slars } 7384374Slars 7394374Slars switch (cur_chr) 7404374Slars { 7414374Slars case 'b': 7424374Slars *s1++ = '\b'; 7434374Slars break; 7444374Slars 7454374Slars case 'c': 7464374Slars if (sending && *s == '\0') 74711990Speter { 7484374Slars add_return = 0; 74911990Speter } 7504374Slars else 75111990Speter { 7524374Slars *s1++ = cur_chr; 75311990Speter } 7544374Slars break; 7554374Slars 7564374Slars case '\\': 7574374Slars case 'K': 7584374Slars case 'p': 7594374Slars case 'd': 7604374Slars if (sending) 76111990Speter { 7624374Slars *s1++ = '\\'; 76311990Speter } 7644374Slars 7654374Slars *s1++ = cur_chr; 7664374Slars break; 7674374Slars 7684374Slars case 'q': 76928597Speter quiet = 1; 7704374Slars break; 7714374Slars 7724374Slars case 'r': 7734374Slars *s1++ = '\r'; 7744374Slars break; 7754374Slars 7764374Slars case 'n': 7774374Slars *s1++ = '\n'; 7784374Slars break; 7794374Slars 7804374Slars case 's': 7814374Slars *s1++ = ' '; 7824374Slars break; 7834374Slars 7844374Slars case 't': 7854374Slars *s1++ = '\t'; 7864374Slars break; 7874374Slars 7884374Slars case 'N': 7894374Slars if (sending) 7904374Slars { 7914374Slars *s1++ = '\\'; 7924374Slars *s1++ = '\0'; 7934374Slars } 7944374Slars else 79511990Speter { 7964374Slars *s1++ = 'N'; 79711990Speter } 7984374Slars break; 79911990Speter 8004374Slars default: 8014374Slars if (isoctal (cur_chr)) 8024374Slars { 8034374Slars cur_chr &= 0x07; 8044374Slars if (isoctal (*s)) 8054374Slars { 8064374Slars cur_chr <<= 3; 8074374Slars cur_chr |= *s++ - '0'; 8084374Slars if (isoctal (*s)) 8094374Slars { 8104374Slars cur_chr <<= 3; 8114374Slars cur_chr |= *s++ - '0'; 8124374Slars } 8134374Slars } 8144374Slars 8154374Slars if (cur_chr != 0 || sending) 8164374Slars { 8174374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 81811990Speter { 8194374Slars *s1++ = '\\'; 82011990Speter } 8214374Slars *s1++ = cur_chr; 8224374Slars } 8234374Slars break; 8244374Slars } 8254374Slars 8264374Slars if (sending) 82711990Speter { 8284374Slars *s1++ = '\\'; 82911990Speter } 8304374Slars *s1++ = cur_chr; 8314374Slars break; 8324374Slars } 8334374Slars } 8344374Slars 8354374Slars if (add_return) 83611990Speter { 8374374Slars *s1++ = '\r'; 83811990Speter } 8394374Slars 8404374Slars *s1++ = '\0'; /* guarantee closure */ 8414374Slars *s1++ = '\0'; /* terminate the string */ 8424374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 8434374Slars } 8444374Slars 8454374Slars/* 84628597Speter * A modified version of 'strtok'. This version skips \ sequences. 84728597Speter */ 84828597Speter 84928597Speterchar *expect_strtok (s, term) 85028597Speterchar *s, *term; 85128597Speter { 85228597Speter static char *str = ""; 85328597Speter int escape_flag = 0; 85428597Speter char *result; 85528597Speter/* 85628597Speter * If a string was specified then do initial processing. 85728597Speter */ 85828597Speter if (s) 85928597Speter { 86028597Speter str = s; 86128597Speter } 86228597Speter/* 86328597Speter * If this is the escape flag then reset it and ignore the character. 86428597Speter */ 86528597Speter if (*str) 86628597Speter { 86728597Speter result = str; 86828597Speter } 86928597Speter else 87028597Speter { 87128597Speter result = (char *) 0; 87228597Speter } 87328597Speter 87428597Speter while (*str) 87528597Speter { 87628597Speter if (escape_flag) 87728597Speter { 87828597Speter escape_flag = 0; 87928597Speter ++str; 88028597Speter continue; 88128597Speter } 88228597Speter 88328597Speter if (*str == '\\') 88428597Speter { 88528597Speter ++str; 88628597Speter escape_flag = 1; 88728597Speter continue; 88828597Speter } 88928597Speter/* 89028597Speter * If this is not in the termination string, continue. 89128597Speter */ 89228597Speter if (strchr (term, *str) == (char *) 0) 89328597Speter { 89428597Speter ++str; 89528597Speter continue; 89628597Speter } 89728597Speter/* 89828597Speter * This is the terminator. Mark the end of the string and stop. 89928597Speter */ 90028597Speter *str++ = '\0'; 90128597Speter break; 90228597Speter } 90328597Speter return (result); 90428597Speter } 90528597Speter 90628597Speter/* 9074374Slars * Process the expect string 9084374Slars */ 90928597Speter 91028597Spetervoid chat_expect (s) 91128597Speterchar *s; 9124374Slars { 91328597Speter char *expect; 91428597Speter char *reply; 91528597Speter 91628597Speter if (strcmp(s, "HANGUP") == 0) 91728597Speter { 91828597Speter ++hup_next; 91928597Speter return; 92028597Speter } 92128597Speter 9224374Slars if (strcmp(s, "ABORT") == 0) 9234374Slars { 9244374Slars ++abort_next; 9254374Slars return; 9264374Slars } 9274374Slars 92828597Speter if (strcmp(s, "CLR_ABORT") == 0) 92928597Speter { 93028597Speter ++clear_abort_next; 93128597Speter return; 93228597Speter } 93328597Speter 93411990Speter if (strcmp(s, "REPORT") == 0) 93511990Speter { 93611990Speter ++report_next; 93711990Speter return; 93811990Speter } 93911990Speter 94028597Speter if (strcmp(s, "CLR_REPORT") == 0) 94128597Speter { 94228597Speter ++clear_report_next; 94328597Speter return; 94428597Speter } 94528597Speter 9464374Slars if (strcmp(s, "TIMEOUT") == 0) 9474374Slars { 9484374Slars ++timeout_next; 9494374Slars return; 9504374Slars } 9514374Slars 95228597Speter if (strcmp(s, "ECHO") == 0) 9534374Slars { 95428597Speter ++echo_next; 95528597Speter return; 95628597Speter } 95728597Speter if (strcmp(s, "SAY") == 0) 95828597Speter { 95928597Speter ++say_next; 96028597Speter return; 96128597Speter } 96228597Speter/* 96328597Speter * Fetch the expect and reply string. 96428597Speter */ 96528597Speter for (;;) 96628597Speter { 96728597Speter expect = expect_strtok (s, "-"); 96828597Speter s = (char *) 0; 9694374Slars 97028597Speter if (expect == (char *) 0) 97111990Speter { 97228597Speter return; 97311990Speter } 97428597Speter 97528597Speter reply = expect_strtok (s, "-"); 97628597Speter/* 97728597Speter * Handle the expect string. If successful then exit. 97828597Speter */ 97928597Speter if (get_string (expect)) 9804374Slars { 98128597Speter return; 9824374Slars } 98328597Speter/* 98428597Speter * If there is a sub-reply string then send it. Otherwise any condition 98528597Speter * is terminal. 98628597Speter */ 98728597Speter if (reply == (char *) 0 || exit_code != 3) 98811990Speter { 98928597Speter break; 99028597Speter } 9914374Slars 99228597Speter chat_send (reply); 9934374Slars } 99428597Speter/* 99528597Speter * The expectation did not occur. This is terminal. 99628597Speter */ 99728597Speter if (fail_reason) 99828597Speter { 99928597Speter syslog(LOG_INFO, "Failed (%s)", fail_reason); 100028597Speter } 100128597Speter else 100228597Speter { 100328597Speter syslog(LOG_INFO, "Failed"); 100428597Speter } 100528597Speter terminate(exit_code); 10064374Slars } 10074374Slars 100828597Speter/* 100928597Speter * Translate the input character to the appropriate string for printing 101028597Speter * the data. 101128597Speter */ 101228597Speter 10134374Slarschar *character(c) 101411990Speterint c; 10154374Slars { 10164374Slars static char string[10]; 10174374Slars char *meta; 10184374Slars 10194374Slars meta = (c & 0x80) ? "M-" : ""; 10204374Slars c &= 0x7F; 10214374Slars 10224374Slars if (c < 32) 102311990Speter { 10244374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 102511990Speter } 10264374Slars else 102711990Speter { 10284374Slars if (c == 127) 102911990Speter { 10304374Slars sprintf(string, "%s^?", meta); 103111990Speter } 10324374Slars else 103311990Speter { 10344374Slars sprintf(string, "%s%c", meta, c); 103511990Speter } 103611990Speter } 10374374Slars 10384374Slars return (string); 10394374Slars } 10404374Slars 10414374Slars/* 10424374Slars * process the reply string 10434374Slars */ 10444374Slarsvoid chat_send (s) 10454374Slarsregister char *s; 10464374Slars { 104728597Speter if (say_next) 104828597Speter { 104928597Speter say_next = 0; 105028597Speter s = clean(s,0); 105128597Speter write(2, s, strlen(s)); 105228597Speter free(s); 105328597Speter return; 105428597Speter } 105528597Speter if (hup_next) 105628597Speter { 105728597Speter hup_next = 0; 105828597Speter if (strcmp(s, "OFF") == 0) 105928597Speter signal(SIGHUP, SIG_IGN); 106028597Speter else 106128597Speter signal(SIGHUP, sighup); 106228597Speter return; 106328597Speter } 106428597Speter if (echo_next) 106528597Speter { 106628597Speter echo_next = 0; 106728597Speter echo = (strcmp(s, "ON") == 0); 106828597Speter return; 106928597Speter } 10704374Slars if (abort_next) 107111990Speter { 10724374Slars char *s1; 107311990Speter 10744374Slars abort_next = 0; 107511990Speter 10764374Slars if (n_aborts >= MAX_ABORTS) 107711990Speter { 10784374Slars fatal("Too many ABORT strings"); 107911990Speter } 108011990Speter 10814374Slars s1 = clean(s, 0); 108211990Speter 108311990Speter if (strlen(s1) > strlen(s) 108411990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 10854374Slars { 10864374Slars syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 10874374Slars die(); 10884374Slars } 10894374Slars 10904374Slars abort_string[n_aborts++] = s1; 10914374Slars 10924374Slars if (verbose) 10934374Slars { 10944374Slars logf("abort on ("); 10954374Slars 10964374Slars for (s1 = s; *s1; ++s1) 109711990Speter { 10984374Slars logf(character(*s1)); 109911990Speter } 11004374Slars 11014374Slars logf(")\n"); 11024374Slars } 110311990Speter return; 11044374Slars } 110511990Speter 110628597Speter if (clear_abort_next) 110728597Speter { 110828597Speter char *s1; 110928597Speter char *s2 = s; 111028597Speter int i; 111128597Speter int old_max; 111228597Speter int pack = 0; 111328597Speter 111428597Speter clear_abort_next = 0; 111528597Speter 111628597Speter s1 = clean(s, 0); 111728597Speter 111828597Speter if (strlen(s1) > strlen(s) 111928597Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 112028597Speter { 112128597Speter syslog(LOG_WARNING, "Illegal or too-long CLR_ABORT string ('%s')", s); 112228597Speter die(); 112328597Speter } 112428597Speter 112528597Speter old_max = n_aborts; 112628597Speter for (i=0; i < n_aborts; i++) 112728597Speter { 112828597Speter if ( strcmp(s1,abort_string[i]) == 0 ) 112928597Speter { 113028597Speter free(abort_string[i]); 113128597Speter abort_string[i] = NULL; 113228597Speter pack++; 113328597Speter n_aborts--; 113428597Speter if (verbose) 113528597Speter { 113628597Speter logf("clear abort on ("); 113728597Speter 113828597Speter for (s2 = s; *s2; ++s2) 113928597Speter { 114028597Speter logf(character(*s2)); 114128597Speter } 114228597Speter 114328597Speter logf(")\n"); 114428597Speter } 114528597Speter } 114628597Speter } 114728597Speter free(s1); 114828597Speter if (pack) pack_array(abort_string,old_max); 114928597Speter return; 115028597Speter } 115128597Speter 115211990Speter if (report_next) 115311990Speter { 115411990Speter char *s1; 115511990Speter 115611990Speter report_next = 0; 115711990Speter if (n_reports >= MAX_REPORTS) 11584374Slars { 115911990Speter fatal("Too many REPORT strings"); 116011990Speter } 116111990Speter 116211990Speter s1 = clean(s, 0); 116311990Speter 116411990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 116511990Speter { 116611990Speter syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 116711990Speter die(); 116811990Speter } 116911990Speter 117011990Speter report_string[n_reports++] = s1; 117111990Speter 117211990Speter if (verbose) 117311990Speter { 117411990Speter logf("report ("); 117511990Speter s1 = s; 117611990Speter while (*s1) 117711990Speter { 117811990Speter logf(character(*s1)); 117911990Speter ++s1; 118011990Speter } 118111990Speter logf(")\n"); 118211990Speter } 118311990Speter return; 118411990Speter } 11854374Slars 118628597Speter if (clear_report_next) 118728597Speter { 118828597Speter char *s1; 118928597Speter char *s2 = s; 119028597Speter int i; 119128597Speter int old_max; 119228597Speter int pack = 0; 119328597Speter 119428597Speter clear_report_next = 0; 119528597Speter 119628597Speter s1 = clean(s, 0); 119728597Speter 119828597Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 119928597Speter { 120028597Speter syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 120128597Speter die(); 120228597Speter } 120328597Speter 120428597Speter old_max = n_reports; 120528597Speter for (i=0; i < n_reports; i++) 120628597Speter { 120728597Speter if ( strcmp(s1,report_string[i]) == 0 ) 120828597Speter { 120928597Speter free(report_string[i]); 121028597Speter report_string[i] = NULL; 121128597Speter pack++; 121228597Speter n_reports--; 121328597Speter if (verbose) 121428597Speter { 121528597Speter logf("clear report ("); 121628597Speter 121728597Speter for (s2 = s; *s2; ++s2) 121828597Speter { 121928597Speter logf(character(*s2)); 122028597Speter } 122128597Speter 122228597Speter logf(")\n"); 122328597Speter } 122428597Speter } 122528597Speter } 122628597Speter free(s1); 122728597Speter if (pack) pack_array(report_string,old_max); 122828597Speter 122928597Speter return; 123028597Speter } 123128597Speter 123211990Speter if (timeout_next) 123311990Speter { 123411990Speter timeout_next = 0; 123511990Speter timeout = atoi(s); 123611990Speter 123711990Speter if (timeout <= 0) 123811990Speter { 123911990Speter timeout = DEFAULT_CHAT_TIMEOUT; 124011990Speter } 12414374Slars 124211990Speter if (verbose) 124311990Speter { 124411990Speter syslog(LOG_INFO, "timeout set to %d seconds", timeout); 12454374Slars } 124611990Speter return; 124711990Speter } 124811990Speter 124911990Speter if (strcmp(s, "EOT") == 0) 125011990Speter { 125111990Speter s = "^D\\c"; 125211990Speter } 125311990Speter else 125411990Speter { 125511990Speter if (strcmp(s, "BREAK") == 0) 12564374Slars { 125711990Speter s = "\\K\\c"; 12584374Slars } 125911990Speter } 126011990Speter 126111990Speter if (!put_string(s)) 126211990Speter { 126311990Speter syslog(LOG_INFO, "Failed"); 126411990Speter terminate(1); 126511990Speter } 12664374Slars } 12674374Slars 12684374Slarsint get_char() 12694374Slars { 12704374Slars int status; 12714374Slars char c; 12724374Slars 12734374Slars status = read(0, &c, 1); 12744374Slars 12754374Slars switch (status) 127611990Speter { 127711990Speter case 1: 127811990Speter return ((int)c & 0x7F); 12794374Slars 128011990Speter default: 128111990Speter syslog(LOG_WARNING, "warning: read() on stdin returned %d", 128211990Speter status); 12834374Slars 128411990Speter case -1: 128511990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 128611990Speter { 128711990Speter sysfatal("Can't get file mode flags on stdin"); 128811990Speter } 128911990Speter else 129011990Speter { 129111990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 129211990Speter { 129311990Speter sysfatal("Can't set file mode flags on stdin"); 129411990Speter } 129511990Speter } 129611990Speter 129711990Speter return (-1); 129811990Speter } 12994374Slars } 13004374Slars 13014374Slarsint put_char(c) 130211990Speterint c; 13034374Slars { 13044374Slars int status; 130511990Speter char ch = c; 13064374Slars 130711990Speter usleep(10000); /* inter-character typing delay (?) */ 13084374Slars 130911990Speter status = write(1, &ch, 1); 13104374Slars 13114374Slars switch (status) 131211990Speter { 131311990Speter case 1: 131411990Speter return (0); 131511990Speter 131611990Speter default: 131711990Speter syslog(LOG_WARNING, "warning: write() on stdout returned %d", 131811990Speter status); 131911990Speter 132011990Speter case -1: 132111990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 132211990Speter { 132311990Speter sysfatal("Can't get file mode flags on stdin"); 132411990Speter } 132511990Speter else 132611990Speter { 132711990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 132811990Speter { 132911990Speter sysfatal("Can't set file mode flags on stdin"); 133011990Speter } 133111990Speter } 133211990Speter 133311990Speter return (-1); 133411990Speter } 13354374Slars } 13364374Slars 13374374Slarsint write_char (c) 13384374Slarsint c; 13394374Slars { 13404374Slars if (alarmed || put_char(c) < 0) 13414374Slars { 13424374Slars extern int errno; 13434374Slars 134411990Speter alarm(0); 134511990Speter alarmed = 0; 13464374Slars 13474374Slars if (verbose) 13484374Slars { 13494374Slars if (errno == EINTR || errno == EWOULDBLOCK) 135011990Speter { 13514374Slars syslog(LOG_INFO, " -- write timed out"); 135211990Speter } 13534374Slars else 135411990Speter { 13554374Slars syslog(LOG_INFO, " -- write failed: %m"); 135611990Speter } 13574374Slars } 13584374Slars return (0); 13594374Slars } 13604374Slars return (1); 13614374Slars } 13624374Slars 13634374Slarsint put_string (s) 13644374Slarsregister char *s; 13654374Slars { 136628597Speter quiet = 0; 13674374Slars s = clean(s, 1); 13684374Slars 13694374Slars if (verbose) 13704374Slars { 13714374Slars logf("send ("); 13724374Slars 13734374Slars if (quiet) 137411990Speter { 13754374Slars logf("??????"); 137611990Speter } 13774374Slars else 13784374Slars { 13794374Slars register char *s1 = s; 13804374Slars 13814374Slars for (s1 = s; *s1; ++s1) 138211990Speter { 13834374Slars logf(character(*s1)); 138411990Speter } 13854374Slars } 13864374Slars 13874374Slars logf(")\n"); 13884374Slars } 13894374Slars 13904374Slars alarm(timeout); alarmed = 0; 13914374Slars 13924374Slars while (*s) 13934374Slars { 13944374Slars register char c = *s++; 13954374Slars 13964374Slars if (c != '\\') 13974374Slars { 13984374Slars if (!write_char (c)) 139911990Speter { 14004374Slars return 0; 140111990Speter } 14024374Slars continue; 14034374Slars } 14044374Slars 14054374Slars c = *s++; 14064374Slars switch (c) 14074374Slars { 14084374Slars case 'd': 14094374Slars sleep(1); 14104374Slars break; 14114374Slars 14124374Slars case 'K': 14134374Slars break_sequence(); 14144374Slars break; 14154374Slars 14164374Slars case 'p': 141711990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 14184374Slars break; 14194374Slars 14204374Slars default: 14214374Slars if (!write_char (c)) 14224374Slars return 0; 14234374Slars break; 14244374Slars } 14254374Slars } 14264374Slars 14274374Slars alarm(0); 14284374Slars alarmed = 0; 14294374Slars return (1); 14304374Slars } 14314374Slars 14324374Slars/* 143328597Speter * Echo a character to stderr. 143428597Speter * When called with -1, a '\n' character is generated when 143528597Speter * the cursor is not at the beginning of a line. 143628597Speter */ 143728597Spetervoid echo_stderr(n) 143828597Speterint n; 143928597Speter { 144028597Speter static int need_lf; 144128597Speter char *s; 144228597Speter 144328597Speter switch (n) 144428597Speter { 144528597Speter case '\r': /* ignore '\r' */ 144628597Speter break; 144728597Speter case -1: 144828597Speter if (need_lf == 0) 144928597Speter break; 145028597Speter /* fall through */ 145128597Speter case '\n': 145228597Speter write(2, "\n", 1); 145328597Speter need_lf = 0; 145428597Speter break; 145528597Speter default: 145628597Speter s = character(n); 145728597Speter write(2, s, strlen(s)); 145828597Speter need_lf = 1; 145928597Speter break; 146028597Speter } 146128597Speter } 146228597Speter 146328597Speter/* 14644374Slars * 'Wait for' this string to appear on this file descriptor. 14654374Slars */ 14664374Slarsint get_string(string) 14674374Slarsregister char *string; 14684374Slars { 14694374Slars char temp[STR_LEN]; 14704374Slars int c, printed = 0, len, minlen; 14714374Slars register char *s = temp, *end = s + STR_LEN; 14724374Slars 14734374Slars fail_reason = (char *)0; 14744374Slars string = clean(string, 0); 14754374Slars len = strlen(string); 14764374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 14774374Slars 14784374Slars if (verbose) 14794374Slars { 14804374Slars register char *s1; 14814374Slars 14824374Slars logf("expect ("); 14834374Slars 14844374Slars for (s1 = string; *s1; ++s1) 148511990Speter { 14864374Slars logf(character(*s1)); 148711990Speter } 14884374Slars 14894374Slars logf(")\n"); 14904374Slars } 14914374Slars 14924374Slars if (len > STR_LEN) 14934374Slars { 14944374Slars syslog(LOG_INFO, "expect string is too long"); 149511990Speter exit_code = 1; 14964374Slars return 0; 14974374Slars } 14984374Slars 14994374Slars if (len == 0) 15004374Slars { 15014374Slars if (verbose) 15024374Slars { 15034374Slars syslog(LOG_INFO, "got it"); 15044374Slars } 15054374Slars 15064374Slars return (1); 15074374Slars } 15084374Slars 150911990Speter alarm(timeout); 151011990Speter alarmed = 0; 15114374Slars 15124374Slars while ( ! alarmed && (c = get_char()) >= 0) 15134374Slars { 151411990Speter int n, abort_len, report_len; 15154374Slars 151628597Speter if (echo) 151728597Speter { 151828597Speter echo_stderr(c); 151928597Speter } 15204374Slars if (verbose) 15214374Slars { 15224374Slars if (c == '\n') 152311990Speter { 15244374Slars logf("\n"); 152511990Speter } 15264374Slars else 152711990Speter { 15284374Slars logf(character(c)); 152911990Speter } 15304374Slars } 15314374Slars 153228597Speter if (Verbose) { 153328597Speter if (c == '\n') fputc( '\n', stderr ); 153428597Speter else if (c != '\r') fprintf( stderr, "%s", character(c) ); 153528597Speter } 153628597Speter 15374374Slars *s++ = c; 15384374Slars 153911990Speter if (!report_gathering) 154011990Speter { 154111990Speter for (n = 0; n < n_reports; ++n) 154211990Speter { 154311990Speter if ((report_string[n] != (char*) NULL) && 154411990Speter s - temp >= (report_len = strlen(report_string[n])) && 154511990Speter strncmp(s - report_len, report_string[n], report_len) == 0) 154611990Speter { 154711990Speter time_t time_now = time ((time_t*) NULL); 154811990Speter struct tm* tm_now = localtime (&time_now); 154911990Speter 155011990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 155111990Speter strcat (report_buffer, report_string[n]); 155211990Speter 155311990Speter report_string[n] = (char *) NULL; 155411990Speter report_gathering = 1; 155511990Speter break; 155611990Speter } 155711990Speter } 155811990Speter } 155911990Speter else 156011990Speter { 156111990Speter if (!iscntrl (c)) 156211990Speter { 156311990Speter int rep_len = strlen (report_buffer); 156411990Speter report_buffer[rep_len] = c; 156511990Speter report_buffer[rep_len + 1] = '\0'; 156611990Speter } 156711990Speter else 156811990Speter { 156911990Speter report_gathering = 0; 157011990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 157111990Speter } 157211990Speter } 157311990Speter 157428597Speter if (s - temp >= len && 157528597Speter c == string[len - 1] && 157628597Speter strncmp(s - len, string, len) == 0) 157728597Speter { 157828597Speter if (verbose) 157928597Speter { 158028597Speter logf(" -- got it\n"); 158128597Speter } 158228597Speter 158328597Speter alarm(0); 158428597Speter alarmed = 0; 158528597Speter return (1); 158628597Speter } 158728597Speter 158828597Speter for (n = 0; n < n_aborts; ++n) 158928597Speter { 159028597Speter if (s - temp >= (abort_len = strlen(abort_string[n])) && 159128597Speter strncmp(s - abort_len, abort_string[n], abort_len) == 0) 159228597Speter { 159328597Speter if (verbose) 159428597Speter { 159528597Speter logf(" -- failed\n"); 159628597Speter } 159728597Speter 159828597Speter alarm(0); 159928597Speter alarmed = 0; 160028597Speter exit_code = n + 4; 160128597Speter strcpy(fail_reason = fail_buffer, abort_string[n]); 160228597Speter return (0); 160328597Speter } 160428597Speter } 160528597Speter 16064374Slars if (s >= end) 16074374Slars { 160811990Speter strncpy (temp, s - minlen, minlen); 16094374Slars s = temp + minlen; 16104374Slars } 16114374Slars 16124374Slars if (alarmed && verbose) 161311990Speter { 16144374Slars syslog(LOG_WARNING, "warning: alarm synchronization problem"); 161511990Speter } 16164374Slars } 16174374Slars 16184374Slars alarm(0); 161911990Speter 16204374Slars if (verbose && printed) 16214374Slars { 16224374Slars if (alarmed) 162311990Speter { 16244374Slars logf(" -- read timed out\n"); 162511990Speter } 16264374Slars else 16274374Slars { 16284374Slars logflush(); 16294374Slars syslog(LOG_INFO, " -- read failed: %m"); 16304374Slars } 16314374Slars } 16324374Slars 163311990Speter exit_code = 3; 163411990Speter alarmed = 0; 16354374Slars return (0); 16364374Slars } 16374374Slars 163811990Speter#ifdef NO_USLEEP 16394374Slars#include <sys/types.h> 16404374Slars#include <sys/time.h> 16414374Slars 16424374Slars/* 16434374Slars usleep -- support routine for 4.2BSD system call emulations 16444374Slars last edit: 29-Oct-1984 D A Gwyn 16454374Slars */ 16464374Slars 16474374Slarsextern int select(); 16484374Slars 16494374Slarsint 16504374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 16514374Slars long usec; /* delay in microseconds */ 16524374Slars{ 16534374Slars static struct /* `timeval' */ 165411990Speter { 165511990Speter long tv_sec; /* seconds */ 165611990Speter long tv_usec; /* microsecs */ 165711990Speter } delay; /* _select() timeout */ 16584374Slars 165911990Speter delay.tv_sec = usec / 1000000L; 16604374Slars delay.tv_usec = usec % 1000000L; 16614374Slars 16624374Slars return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 16634374Slars} 16644374Slars#endif 166528597Speter 166628597Spetervoid 166728597Speterpack_array (array, end) 166828597Speter char **array; /* The address of the array of string pointers */ 166928597Speter int end; /* The index of the next free entry before CLR_ */ 167028597Speter{ 167128597Speter int i, j; 167228597Speter 167328597Speter for (i = 0; i < end; i++) { 167428597Speter if (array[i] == NULL) { 167528597Speter for (j = i+1; j < end; ++j) 167628597Speter if (array[j] != NULL) 167728597Speter array[i++] = array[j]; 167828597Speter for (; i < end; ++i) 167928597Speter array[i] = NULL; 168028597Speter break; 168128597Speter } 168228597Speter } 168328597Speter} 1684