chat.c revision 41568
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. 834766Speter * 2 - error on an I/O operation or fatal error condition. 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 * ----------------- 1734766Speter * added -T and -U option and \T and \U substitution to pass a phone 1834766Speter * number into chat script. Two are needed for some ISDN TA applications. 1934766Speter * Keith Dart <kdart@cisco.com> 2034766Speter * 214374Slars * 2228597Speter * Added SAY keyword to send output to stderr. 2328597Speter * This allows to turn ECHO OFF and to output specific, user selected, 2428597Speter * text to give progress messages. This best works when stderr 2528597Speter * exists (i.e.: pppd in nodetach mode). 264374Slars * 2728597Speter * Added HANGUP directives to allow for us to be called 2828597Speter * back. When HANGUP is set to NO, chat will not hangup at HUP signal. 2928597Speter * We rely on timeouts in that case. 3028597Speter * 3128597Speter * Added CLR_ABORT to clear previously set ABORT string. This has been 3228597Speter * dictated by the HANGUP above as "NO CARRIER" (for example) must be 3328597Speter * an ABORT condition until we know the other host is going to close 3428597Speter * the connection for call back. As soon as we have completed the 3528597Speter * first stage of the call back sequence, "NO CARRIER" is a valid, non 3628597Speter * fatal string. As soon as we got called back (probably get "CONNECT"), 3728597Speter * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command. 3828597Speter * Note that CLR_ABORT packs the abort_strings[] array so that we do not 3928597Speter * have unused entries not being reclaimed. 4028597Speter * 4128597Speter * In the same vein as above, added CLR_REPORT keyword. 4228597Speter * 4328597Speter * Allow for comments. Line starting with '#' are comments and are 4428597Speter * ignored. If a '#' is to be expected as the first character, the 4528597Speter * expect string must be quoted. 4628597Speter * 4728597Speter * 4828597Speter * Francis Demierre <Francis@SwissMail.Com> 4928597Speter * Thu May 15 17:15:40 MET DST 1997 5028597Speter * 5128597Speter * 5211990Speter * Added -r "report file" switch & REPORT keyword. 5311990Speter * Robert Geer <bgeer@xmission.com> 5411990Speter * 5534766Speter * Added -s "use stderr" and -S "don't use syslog" switches. 5634766Speter * June 18, 1997 5734766Speter * Karl O. Pinc <kop@meme.com> 5828597Speter * 5934766Speter * 6028597Speter * Added -e "echo" switch & ECHO keyword 6128597Speter * Dick Streefland <dicks@tasking.nl> 6228597Speter * 6328597Speter * 6428597Speter * Considerable updates and modifications by 6528597Speter * Al Longyear <longyear@pobox.com> 6628597Speter * Paul Mackerras <paulus@cs.anu.edu.au> 6728597Speter * 6828597Speter * 694374Slars * The original author is: 704374Slars * 714374Slars * Karl Fox <karl@MorningStar.Com> 724374Slars * Morning Star Technologies, Inc. 734374Slars * 1760 Zollinger Road 744374Slars * Columbus, OH 43221 754374Slars * (614)451-1883 7611990Speter * 7728597Speter * 784374Slars */ 794374Slars 8028597Speter#ifndef lint 8141568Sarchiestatic const char rcsid[] = 8241568Sarchie "$Id: chat.c,v 1.12 1998/06/23 21:58:41 peter Exp $"; 8328597Speter#endif 844374Slars 854374Slars#include <stdio.h> 8628597Speter#include <ctype.h> 8711990Speter#include <time.h> 884374Slars#include <fcntl.h> 894374Slars#include <signal.h> 904374Slars#include <errno.h> 914374Slars#include <string.h> 924374Slars#include <stdlib.h> 9328597Speter#include <unistd.h> 944374Slars#include <sys/types.h> 954374Slars#include <sys/stat.h> 964374Slars#include <syslog.h> 974374Slars 984374Slars#ifndef TERMIO 994374Slars#undef TERMIOS 1004374Slars#define TERMIOS 1014374Slars#endif 1024374Slars 1034374Slars#ifdef TERMIO 1044374Slars#include <termio.h> 1054374Slars#endif 1064374Slars#ifdef TERMIOS 1074374Slars#include <termios.h> 1084374Slars#endif 1094374Slars 1104374Slars#define STR_LEN 1024 1114374Slars 1124374Slars#ifndef SIGTYPE 1134374Slars#define SIGTYPE void 1144374Slars#endif 1154374Slars 11634766Speter#undef __P 11734766Speter#undef __V 11834766Speter 1194374Slars#ifdef __STDC__ 12034766Speter#include <stdarg.h> 12134766Speter#define __V(x) x 1224374Slars#define __P(x) x 1234374Slars#else 12434766Speter#include <varargs.h> 12534766Speter#define __V(x) (va_alist) va_dcl 1264374Slars#define __P(x) () 1274374Slars#define const 1284374Slars#endif 1294374Slars 13011990Speter#ifndef O_NONBLOCK 13111990Speter#define O_NONBLOCK O_NDELAY 13211990Speter#endif 13311990Speter 13434766Speter#ifdef SUNOS 13534766Speterextern int sys_nerr; 13634766Speterextern char *sys_errlist[]; 13734766Speter#define memmove(to, from, n) bcopy(from, to, n) 13834766Speter#define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\ 13934766Speter "unknown error") 14034766Speter#endif 14134766Speter 1424374Slars/*************** Micro getopt() *********************************************/ 1434374Slars#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 1444374Slars (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 1454374Slars &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 1464374Slars#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 1474374Slars (_O=4,(char*)0):(char*)0) 1484374Slars#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 1494374Slars#define ARG(c,v) (c?(--c,*v++):(char*)0) 1504374Slars 1514374Slarsstatic int _O = 0; /* Internal state */ 1524374Slars/*************** Micro getopt() *********************************************/ 1534374Slars 1544374Slars#define MAX_ABORTS 50 15511990Speter#define MAX_REPORTS 50 1564374Slars#define DEFAULT_CHAT_TIMEOUT 45 1574374Slars 15828597Speterint echo = 0; 15911990Speterint verbose = 0; 16034766Speterint to_log = 1; 16134766Speterint to_stderr = 0; 16228597Speterint Verbose = 0; 16311990Speterint quiet = 0; 16411990Speterint report = 0; 16511990Speterint exit_code = 0; 16611990SpeterFILE* report_fp = (FILE *) 0; 16711990Speterchar *report_file = (char *) 0; 16811990Speterchar *chat_file = (char *) 0; 16934766Speterchar *phone_num = (char *) 0; 17034766Speterchar *phone_num2 = (char *) 0; 17111990Speterint timeout = DEFAULT_CHAT_TIMEOUT; 1724374Slars 1734374Slarsint have_tty_parameters = 0; 17411990Speter 1754374Slars#ifdef TERMIO 17611990Speter#define term_parms struct termio 17711990Speter#define get_term_param(param) ioctl(0, TCGETA, param) 17811990Speter#define set_term_param(param) ioctl(0, TCSETA, param) 1794374Slarsstruct termio saved_tty_parameters; 1804374Slars#endif 18111990Speter 1824374Slars#ifdef TERMIOS 18311990Speter#define term_parms struct termios 18411990Speter#define get_term_param(param) tcgetattr(0, param) 18511990Speter#define set_term_param(param) tcsetattr(0, TCSANOW, param) 1864374Slarsstruct termios saved_tty_parameters; 1874374Slars#endif 1884374Slars 1894374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1904374Slars fail_buffer[50]; 19128597Speterint n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 19228597Speterint clear_abort_next = 0; 1934374Slars 19411990Speterchar *report_string[MAX_REPORTS] ; 19511990Speterchar report_buffer[50] ; 19611990Speterint n_reports = 0, report_next = 0, report_gathering = 0 ; 19728597Speterint clear_report_next = 0; 19811990Speter 19928597Speterint say_next = 0, hup_next = 0; 20028597Speter 2014374Slarsvoid *dup_mem __P((void *b, size_t c)); 2024374Slarsvoid *copy_of __P((char *s)); 20326880Scharnierstatic void usage __P((void)); 20434766Spetervoid logf __P((const char *fmt, ...)); 20534766Spetervoid fatal __P((int code, const char *fmt, ...)); 2064374SlarsSIGTYPE sigalrm __P((int signo)); 2074374SlarsSIGTYPE sigint __P((int signo)); 2084374SlarsSIGTYPE sigterm __P((int signo)); 2094374SlarsSIGTYPE sighup __P((int signo)); 2104374Slarsvoid unalarm __P((void)); 2114374Slarsvoid init __P((void)); 2124374Slarsvoid set_tty_parameters __P((void)); 21328597Spetervoid echo_stderr __P((int)); 2144374Slarsvoid break_sequence __P((void)); 2154374Slarsvoid terminate __P((int status)); 2164374Slarsvoid do_file __P((char *chat_file)); 2174374Slarsint get_string __P((register char *string)); 2184374Slarsint put_string __P((register char *s)); 2194374Slarsint write_char __P((int c)); 22011990Speterint put_char __P((int c)); 2214374Slarsint get_char __P((void)); 2224374Slarsvoid chat_send __P((register char *s)); 22311990Speterchar *character __P((int c)); 2244374Slarsvoid chat_expect __P((register char *s)); 2254374Slarschar *clean __P((register char *s, int sending)); 2264374Slarsvoid break_sequence __P((void)); 2274374Slarsvoid terminate __P((int status)); 22828597Spetervoid pack_array __P((char **array, int end)); 22928597Speterchar *expect_strtok __P((char *, char *)); 23034766Speterint vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */ 2314374Slars 23228597Speterint main __P((int, char *[])); 23328597Speter 2344374Slarsvoid *dup_mem(b, c) 2354374Slarsvoid *b; 2364374Slarssize_t c; 23734766Speter{ 2384374Slars void *ans = malloc (c); 2394374Slars if (!ans) 24034766Speter fatal(2, "memory error!"); 24134766Speter 2424374Slars memcpy (ans, b, c); 2434374Slars return ans; 24434766Speter} 2454374Slars 2464374Slarsvoid *copy_of (s) 2474374Slarschar *s; 24834766Speter{ 2494374Slars return dup_mem (s, strlen (s) + 1); 25034766Speter} 2514374Slars 2524374Slars/* 25334766Speter * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \ 25434766Speter * [ -r report-file ] \ 2554374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 2564374Slars * 2574374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 2584374Slars */ 2594374Slarsint 2604374Slarsmain(argc, argv) 26134766Speter int argc; 26234766Speter char **argv; 26334766Speter{ 2644374Slars int option; 2654374Slars char *arg; 2664374Slars 26711990Speter tzset(); 2684374Slars 26934766Speter while ((option = OPTION(argc, argv)) != 0) { 27034766Speter switch (option) { 27134766Speter case 'e': 27234766Speter ++echo; 27334766Speter break; 27428597Speter 27534766Speter case 'v': 27634766Speter ++verbose; 27734766Speter break; 2784374Slars 27934766Speter case 'V': 28034766Speter ++Verbose; 28134766Speter break; 28228597Speter 28334766Speter case 's': 28434766Speter ++to_stderr; 28534766Speter break; 28634766Speter 28734766Speter case 'S': 28834766Speter to_log = 0; 28934766Speter break; 29034766Speter 29134766Speter case 'f': 29234766Speter if ((arg = OPTARG(argc, argv)) != NULL) 2934374Slars chat_file = copy_of(arg); 29434766Speter else 29534766Speter usage(); 29634766Speter break; 2974374Slars 29834766Speter case 't': 29934766Speter if ((arg = OPTARG(argc, argv)) != NULL) 30034766Speter timeout = atoi(arg); 30134766Speter else 30234766Speter usage(); 30334766Speter break; 3044374Slars 30534766Speter case 'r': 30634766Speter arg = OPTARG (argc, argv); 30734766Speter if (arg) { 30834766Speter if (report_fp != NULL) 30934766Speter fclose (report_fp); 31034766Speter report_file = copy_of (arg); 31134766Speter report_fp = fopen (report_file, "a"); 31234766Speter if (report_fp != NULL) { 31334766Speter if (verbose) 31434766Speter fprintf (report_fp, "Opening \"%s\"...\n", 31534766Speter report_file); 31634766Speter report = 1; 31734766Speter } 31834766Speter } 31934766Speter break; 3204374Slars 32134766Speter case 'T': 32234766Speter if ((arg = OPTARG(argc, argv)) != NULL) 32334766Speter phone_num = copy_of(arg); 32434766Speter else 3254374Slars usage(); 32634766Speter break; 32734766Speter 32834766Speter case 'U': 32934766Speter if ((arg = OPTARG(argc, argv)) != NULL) 33034766Speter phone_num2 = copy_of(arg); 33134766Speter else 33234766Speter usage(); 33334766Speter break; 33434766Speter 33534766Speter default: 33634766Speter usage(); 33734766Speter break; 33834766Speter } 33934766Speter } 34011990Speter/* 34111990Speter * Default the report file to the stderr location 34211990Speter */ 34311990Speter if (report_fp == NULL) 34411990Speter report_fp = stderr; 3454374Slars 34634766Speter if (to_log) { 3474374Slars#ifdef ultrix 34834766Speter openlog("chat", LOG_PID); 3494374Slars#else 35034766Speter openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 3514374Slars 35234766Speter if (verbose) 35334766Speter setlogmask(LOG_UPTO(LOG_INFO)); 35434766Speter else 35534766Speter setlogmask(LOG_UPTO(LOG_WARNING)); 3564374Slars#endif 35734766Speter } 3584374Slars 3594374Slars init(); 36011990Speter 36134766Speter if (chat_file != NULL) { 3624374Slars arg = ARG(argc, argv); 3634374Slars if (arg != NULL) 3644374Slars usage(); 3654374Slars else 3664374Slars do_file (chat_file); 36734766Speter } else { 36834766Speter while ((arg = ARG(argc, argv)) != NULL) { 3694374Slars chat_expect(arg); 3704374Slars 37128597Speter if ((arg = ARG(argc, argv)) != NULL) 3724374Slars chat_send(arg); 3734374Slars } 37434766Speter } 3754374Slars 3764374Slars terminate(0); 37728597Speter return 0; 37834766Speter} 3794374Slars 3804374Slars/* 3814374Slars * Process a chat script when read from a file. 3824374Slars */ 3834374Slars 3844374Slarsvoid do_file (chat_file) 3854374Slarschar *chat_file; 38634766Speter{ 38732069Salex int linect, sendflg; 3884374Slars char *sp, *arg, quote; 3894374Slars char buf [STR_LEN]; 3904374Slars FILE *cfp; 3914374Slars 39211990Speter cfp = fopen (chat_file, "r"); 39311990Speter if (cfp == NULL) 39434766Speter fatal(1, "%s -- open failed: %m", chat_file); 3954374Slars 3964374Slars linect = 0; 3974374Slars sendflg = 0; 3984374Slars 39934766Speter while (fgets(buf, STR_LEN, cfp) != NULL) { 4004374Slars sp = strchr (buf, '\n'); 4014374Slars if (sp) 4024374Slars *sp = '\0'; 4034374Slars 4044374Slars linect++; 4054374Slars sp = buf; 40628597Speter 40728597Speter /* lines starting with '#' are comments. If a real '#' 40828597Speter is to be expected, it should be quoted .... */ 40934766Speter if ( *sp == '#' ) 41034766Speter continue; 41128597Speter 41234766Speter while (*sp != '\0') { 41334766Speter if (*sp == ' ' || *sp == '\t') { 4144374Slars ++sp; 4154374Slars continue; 41634766Speter } 4174374Slars 41834766Speter if (*sp == '"' || *sp == '\'') { 4194374Slars quote = *sp++; 4204374Slars arg = sp; 42134766Speter while (*sp != quote) { 4224374Slars if (*sp == '\0') 42334766Speter fatal(1, "unterminated quote (line %d)", linect); 42434766Speter 42534766Speter if (*sp++ == '\\') { 4264374Slars if (*sp != '\0') 4274374Slars ++sp; 4284374Slars } 4294374Slars } 43034766Speter } 43134766Speter else { 4324374Slars arg = sp; 4334374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 4344374Slars ++sp; 43534766Speter } 4364374Slars 4374374Slars if (*sp != '\0') 4384374Slars *sp++ = '\0'; 4394374Slars 4404374Slars if (sendflg) 4414374Slars chat_send (arg); 4424374Slars else 4434374Slars chat_expect (arg); 4444374Slars sendflg = !sendflg; 4454374Slars } 44634766Speter } 4474374Slars fclose (cfp); 44834766Speter} 4494374Slars 4504374Slars/* 4514374Slars * We got an error parsing the command line. 4524374Slars */ 45326880Scharnierstatic void 45426880Scharnierusage() 45534766Speter{ 45634766Speter fprintf(stderr, "\ 45734766SpeterUsage: chat [-e] [-v] [-V] [-t timeout] [-r report-file] [-T phone-number]\n\ 45834766Speter [-U phone-number2] {-f chat-file | chat-script}\n"); 4594374Slars exit(1); 46034766Speter} 4614374Slars 46234766Speterchar line[1024]; 4634374Slars 46434766Speter/* 46534766Speter * Send a message to syslog and/or stderr. 46634766Speter */ 46734766Spetervoid logf __V((const char *fmt, ...)) 46828597Speter{ 46934766Speter va_list args; 4704374Slars 47134766Speter#ifdef __STDC__ 47234766Speter va_start(args, fmt); 47334766Speter#else 47434766Speter char *fmt; 47534766Speter va_start(args); 47634766Speter fmt = va_arg(args, char *); 47734766Speter#endif 47834766Speter 47934766Speter vfmtmsg(line, sizeof(line), fmt, args); 48034766Speter if (to_log) 48128597Speter syslog(LOG_INFO, "%s", line); 48234766Speter if (to_stderr) 48334766Speter fprintf(stderr, "%s\n", line); 48428597Speter} 4854374Slars 4864374Slars/* 4874374Slars * Print an error message and terminate. 4884374Slars */ 4894374Slars 49034766Spetervoid fatal __V((int code, const char *fmt, ...)) 49134766Speter{ 49234766Speter va_list args; 4934374Slars 49434766Speter#ifdef __STDC__ 49534766Speter va_start(args, fmt); 49634766Speter#else 49734766Speter int code; 49834766Speter char *fmt; 49934766Speter va_start(args); 50034766Speter code = va_arg(args, int); 50134766Speter fmt = va_arg(args, char *); 50234766Speter#endif 5034374Slars 50434766Speter vfmtmsg(line, sizeof(line), fmt, args); 50534766Speter if (to_log) 50634766Speter syslog(LOG_ERR, "%s", line); 50734766Speter if (to_stderr) 50834766Speter fprintf(stderr, "%s\n", line); 50934766Speter terminate(code); 51034766Speter} 5114374Slars 5124374Slarsint alarmed = 0; 5134374Slars 5144374SlarsSIGTYPE sigalrm(signo) 5154374Slarsint signo; 51634766Speter{ 5174374Slars int flags; 5184374Slars 5194374Slars alarm(1); 5204374Slars alarmed = 1; /* Reset alarm to avoid race window */ 5214374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 5224374Slars 5234374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 52434766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 5254374Slars 52634766Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 52734766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 52834766Speter 5294374Slars if (verbose) 53034766Speter logf("alarm"); 53134766Speter} 5324374Slars 5334374Slarsvoid unalarm() 53434766Speter{ 5354374Slars int flags; 5364374Slars 5374374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 53834766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 5394374Slars 54034766Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 54134766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 54234766Speter} 54334766Speter 5444374SlarsSIGTYPE sigint(signo) 5454374Slarsint signo; 54634766Speter{ 54734766Speter fatal(2, "SIGINT"); 54834766Speter} 5494374Slars 5504374SlarsSIGTYPE sigterm(signo) 5514374Slarsint signo; 55234766Speter{ 55334766Speter fatal(2, "SIGTERM"); 55434766Speter} 5554374Slars 5564374SlarsSIGTYPE sighup(signo) 5574374Slarsint signo; 55834766Speter{ 55934766Speter fatal(2, "SIGHUP"); 56034766Speter} 5614374Slars 5624374Slarsvoid init() 56334766Speter{ 5644374Slars signal(SIGINT, sigint); 5654374Slars signal(SIGTERM, sigterm); 5664374Slars signal(SIGHUP, sighup); 5674374Slars 5684374Slars set_tty_parameters(); 5694374Slars signal(SIGALRM, sigalrm); 5704374Slars alarm(0); 5714374Slars alarmed = 0; 57234766Speter} 5734374Slars 5744374Slarsvoid set_tty_parameters() 57534766Speter{ 57611990Speter#if defined(get_term_param) 57711990Speter term_parms t; 5784374Slars 57911990Speter if (get_term_param (&t) < 0) 58034766Speter fatal(2, "Can't get terminal parameters: %m"); 5814374Slars 5824374Slars saved_tty_parameters = t; 58311990Speter have_tty_parameters = 1; 5844374Slars 58511990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 58611990Speter t.c_oflag = 0; 58711990Speter t.c_lflag = 0; 58811990Speter t.c_cc[VERASE] = 58911990Speter t.c_cc[VKILL] = 0; 59011990Speter t.c_cc[VMIN] = 1; 59111990Speter t.c_cc[VTIME] = 0; 5924374Slars 59311990Speter if (set_term_param (&t) < 0) 59434766Speter fatal(2, "Can't set terminal parameters: %m"); 5954374Slars#endif 59634766Speter} 5974374Slars 5984374Slarsvoid break_sequence() 59934766Speter{ 6004374Slars#ifdef TERMIOS 6014374Slars tcsendbreak (0, 0); 6024374Slars#endif 60334766Speter} 6044374Slars 6054374Slarsvoid terminate(status) 6064374Slarsint status; 60734766Speter{ 60828597Speter echo_stderr(-1); 60934766Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 61028597Speter/* 61128597Speter * Allow the last of the report string to be gathered before we terminate. 61228597Speter */ 61328597Speter if (report_gathering) { 61428597Speter int c, rep_len; 61528597Speter 61628597Speter rep_len = strlen(report_buffer); 61728597Speter while (rep_len + 1 <= sizeof(report_buffer)) { 61828597Speter alarm(1); 61928597Speter c = get_char(); 62028597Speter alarm(0); 62128597Speter if (c < 0 || iscntrl(c)) 62228597Speter break; 62328597Speter report_buffer[rep_len] = c; 62428597Speter ++rep_len; 62528597Speter } 62628597Speter report_buffer[rep_len] = 0; 62728597Speter fprintf (report_fp, "chat: %s\n", report_buffer); 62828597Speter } 62911990Speter if (verbose) 63011990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 63111990Speter fclose (report_fp); 63228597Speter report_fp = (FILE *) NULL; 63334766Speter } 6344374Slars 63511990Speter#if defined(get_term_param) 63634766Speter if (have_tty_parameters) { 63711990Speter if (set_term_param (&saved_tty_parameters) < 0) 63834766Speter fatal(2, "Can't restore terminal parameters: %m"); 63934766Speter } 64011990Speter#endif 6414374Slars 64211990Speter exit(status); 64334766Speter} 6444374Slars 6454374Slars/* 6464374Slars * 'Clean up' this string. 6474374Slars */ 6484374Slarschar *clean(s, sending) 6494374Slarsregister char *s; 65034766Speterint sending; /* set to 1 when sending (putting) this string. */ 65134766Speter{ 6524374Slars char temp[STR_LEN], cur_chr; 65334766Speter register char *s1, *phchar; 6544374Slars int add_return = sending; 6554374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6564374Slars 6574374Slars s1 = temp; 65834766Speter while (*s) { 6594374Slars cur_chr = *s++; 66034766Speter if (cur_chr == '^') { 6614374Slars cur_chr = *s++; 66234766Speter if (cur_chr == '\0') { 6634374Slars *s1++ = '^'; 6644374Slars break; 66534766Speter } 6664374Slars cur_chr &= 0x1F; 66734766Speter if (cur_chr != 0) { 6684374Slars *s1++ = cur_chr; 66934766Speter } 6704374Slars continue; 67134766Speter } 6724374Slars 67334766Speter if (cur_chr != '\\') { 6744374Slars *s1++ = cur_chr; 6754374Slars continue; 67634766Speter } 6774374Slars 6784374Slars cur_chr = *s++; 67934766Speter if (cur_chr == '\0') { 68034766Speter if (sending) { 6814374Slars *s1++ = '\\'; 6824374Slars *s1++ = '\\'; 68334766Speter } 6844374Slars break; 68534766Speter } 6864374Slars 68734766Speter switch (cur_chr) { 6884374Slars case 'b': 6894374Slars *s1++ = '\b'; 6904374Slars break; 6914374Slars 6924374Slars case 'c': 6934374Slars if (sending && *s == '\0') 6944374Slars add_return = 0; 6954374Slars else 6964374Slars *s1++ = cur_chr; 6974374Slars break; 6984374Slars 6994374Slars case '\\': 7004374Slars case 'K': 7014374Slars case 'p': 7024374Slars case 'd': 7034374Slars if (sending) 7044374Slars *s1++ = '\\'; 7054374Slars 7064374Slars *s1++ = cur_chr; 7074374Slars break; 7084374Slars 70934766Speter case 'T': 71034766Speter if (sending && phone_num) { 71134766Speter for ( phchar = phone_num; *phchar != '\0'; phchar++) 71234766Speter *s1++ = *phchar; 71334766Speter } 71434766Speter else { 71534766Speter *s1++ = '\\'; 71634766Speter *s1++ = 'T'; 71734766Speter } 71834766Speter break; 71934766Speter 72034766Speter case 'U': 72134766Speter if (sending && phone_num2) { 72234766Speter for ( phchar = phone_num2; *phchar != '\0'; phchar++) 72334766Speter *s1++ = *phchar; 72434766Speter } 72534766Speter else { 72634766Speter *s1++ = '\\'; 72734766Speter *s1++ = 'U'; 72834766Speter } 72934766Speter break; 73034766Speter 7314374Slars case 'q': 73228597Speter quiet = 1; 7334374Slars break; 7344374Slars 7354374Slars case 'r': 7364374Slars *s1++ = '\r'; 7374374Slars break; 7384374Slars 7394374Slars case 'n': 7404374Slars *s1++ = '\n'; 7414374Slars break; 7424374Slars 7434374Slars case 's': 7444374Slars *s1++ = ' '; 7454374Slars break; 7464374Slars 7474374Slars case 't': 7484374Slars *s1++ = '\t'; 7494374Slars break; 7504374Slars 7514374Slars case 'N': 75234766Speter if (sending) { 7534374Slars *s1++ = '\\'; 7544374Slars *s1++ = '\0'; 75534766Speter } 7564374Slars else 7574374Slars *s1++ = 'N'; 7584374Slars break; 75911990Speter 7604374Slars default: 76134766Speter if (isoctal (cur_chr)) { 7624374Slars cur_chr &= 0x07; 76334766Speter if (isoctal (*s)) { 7644374Slars cur_chr <<= 3; 7654374Slars cur_chr |= *s++ - '0'; 76634766Speter if (isoctal (*s)) { 7674374Slars cur_chr <<= 3; 7684374Slars cur_chr |= *s++ - '0'; 7694374Slars } 77034766Speter } 7714374Slars 77234766Speter if (cur_chr != 0 || sending) { 7734374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 7744374Slars *s1++ = '\\'; 7754374Slars *s1++ = cur_chr; 77634766Speter } 7774374Slars break; 77834766Speter } 7794374Slars 7804374Slars if (sending) 7814374Slars *s1++ = '\\'; 7824374Slars *s1++ = cur_chr; 7834374Slars break; 7844374Slars } 78534766Speter } 7864374Slars 7874374Slars if (add_return) 7884374Slars *s1++ = '\r'; 7894374Slars 7904374Slars *s1++ = '\0'; /* guarantee closure */ 7914374Slars *s1++ = '\0'; /* terminate the string */ 7924374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 79334766Speter} 7944374Slars 7954374Slars/* 79628597Speter * A modified version of 'strtok'. This version skips \ sequences. 79728597Speter */ 79828597Speter 79928597Speterchar *expect_strtok (s, term) 80034766Speter char *s, *term; 80134766Speter{ 80228597Speter static char *str = ""; 80328597Speter int escape_flag = 0; 80428597Speter char *result; 80534766Speter 80628597Speter/* 80728597Speter * If a string was specified then do initial processing. 80828597Speter */ 80928597Speter if (s) 81028597Speter str = s; 81134766Speter 81228597Speter/* 81328597Speter * If this is the escape flag then reset it and ignore the character. 81428597Speter */ 81528597Speter if (*str) 81628597Speter result = str; 81728597Speter else 81828597Speter result = (char *) 0; 81928597Speter 82034766Speter while (*str) { 82134766Speter if (escape_flag) { 82228597Speter escape_flag = 0; 82328597Speter ++str; 82428597Speter continue; 82534766Speter } 82628597Speter 82734766Speter if (*str == '\\') { 82828597Speter ++str; 82928597Speter escape_flag = 1; 83028597Speter continue; 83134766Speter } 83234766Speter 83328597Speter/* 83428597Speter * If this is not in the termination string, continue. 83528597Speter */ 83634766Speter if (strchr (term, *str) == (char *) 0) { 83728597Speter ++str; 83828597Speter continue; 83934766Speter } 84034766Speter 84128597Speter/* 84228597Speter * This is the terminator. Mark the end of the string and stop. 84328597Speter */ 84428597Speter *str++ = '\0'; 84528597Speter break; 84634766Speter } 84728597Speter return (result); 84834766Speter} 84928597Speter 85028597Speter/* 8514374Slars * Process the expect string 8524374Slars */ 85328597Speter 85428597Spetervoid chat_expect (s) 85528597Speterchar *s; 85634766Speter{ 85728597Speter char *expect; 85828597Speter char *reply; 85928597Speter 86034766Speter if (strcmp(s, "HANGUP") == 0) { 86128597Speter ++hup_next; 86228597Speter return; 86334766Speter } 86428597Speter 86534766Speter if (strcmp(s, "ABORT") == 0) { 8664374Slars ++abort_next; 8674374Slars return; 86834766Speter } 8694374Slars 87034766Speter if (strcmp(s, "CLR_ABORT") == 0) { 87128597Speter ++clear_abort_next; 87228597Speter return; 87334766Speter } 87428597Speter 87534766Speter if (strcmp(s, "REPORT") == 0) { 87611990Speter ++report_next; 87711990Speter return; 87834766Speter } 87911990Speter 88034766Speter if (strcmp(s, "CLR_REPORT") == 0) { 88128597Speter ++clear_report_next; 88228597Speter return; 88334766Speter } 88428597Speter 88534766Speter if (strcmp(s, "TIMEOUT") == 0) { 8864374Slars ++timeout_next; 8874374Slars return; 88834766Speter } 8894374Slars 89034766Speter if (strcmp(s, "ECHO") == 0) { 89128597Speter ++echo_next; 89228597Speter return; 89334766Speter } 89434766Speter 89534766Speter if (strcmp(s, "SAY") == 0) { 89628597Speter ++say_next; 89728597Speter return; 89834766Speter } 89934766Speter 90028597Speter/* 90128597Speter * Fetch the expect and reply string. 90228597Speter */ 90334766Speter for (;;) { 90428597Speter expect = expect_strtok (s, "-"); 90528597Speter s = (char *) 0; 9064374Slars 90728597Speter if (expect == (char *) 0) 90828597Speter return; 90928597Speter 91028597Speter reply = expect_strtok (s, "-"); 91134766Speter 91228597Speter/* 91328597Speter * Handle the expect string. If successful then exit. 91428597Speter */ 91528597Speter if (get_string (expect)) 91628597Speter return; 91734766Speter 91828597Speter/* 91928597Speter * If there is a sub-reply string then send it. Otherwise any condition 92028597Speter * is terminal. 92128597Speter */ 92228597Speter if (reply == (char *) 0 || exit_code != 3) 92328597Speter break; 9244374Slars 92528597Speter chat_send (reply); 92634766Speter } 92734766Speter 92828597Speter/* 92928597Speter * The expectation did not occur. This is terminal. 93028597Speter */ 93128597Speter if (fail_reason) 93234766Speter logf("Failed (%s)", fail_reason); 93328597Speter else 93434766Speter logf("Failed"); 93528597Speter terminate(exit_code); 93634766Speter} 9374374Slars 93828597Speter/* 93928597Speter * Translate the input character to the appropriate string for printing 94028597Speter * the data. 94128597Speter */ 94228597Speter 9434374Slarschar *character(c) 94411990Speterint c; 94534766Speter{ 9464374Slars static char string[10]; 9474374Slars char *meta; 9484374Slars 9494374Slars meta = (c & 0x80) ? "M-" : ""; 9504374Slars c &= 0x7F; 9514374Slars 9524374Slars if (c < 32) 9534374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 95434766Speter else if (c == 127) 95534766Speter sprintf(string, "%s^?", meta); 9564374Slars else 95734766Speter sprintf(string, "%s%c", meta, c); 9584374Slars 9594374Slars return (string); 96034766Speter} 9614374Slars 9624374Slars/* 9634374Slars * process the reply string 9644374Slars */ 9654374Slarsvoid chat_send (s) 9664374Slarsregister char *s; 96734766Speter{ 96834766Speter if (say_next) { 96928597Speter say_next = 0; 97028597Speter s = clean(s,0); 97128597Speter write(2, s, strlen(s)); 97228597Speter free(s); 97328597Speter return; 97434766Speter } 97534766Speter 97634766Speter if (hup_next) { 97728597Speter hup_next = 0; 97828597Speter if (strcmp(s, "OFF") == 0) 97928597Speter signal(SIGHUP, SIG_IGN); 98028597Speter else 98128597Speter signal(SIGHUP, sighup); 98228597Speter return; 98334766Speter } 98434766Speter 98534766Speter if (echo_next) { 98628597Speter echo_next = 0; 98728597Speter echo = (strcmp(s, "ON") == 0); 98828597Speter return; 98934766Speter } 99034766Speter 99134766Speter if (abort_next) { 9924374Slars char *s1; 99311990Speter 9944374Slars abort_next = 0; 99511990Speter 9964374Slars if (n_aborts >= MAX_ABORTS) 99734766Speter fatal(2, "Too many ABORT strings"); 99811990Speter 9994374Slars s1 = clean(s, 0); 100011990Speter 100111990Speter if (strlen(s1) > strlen(s) 100211990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 100334766Speter fatal(1, "Illegal or too-long ABORT string ('%v')", s); 10044374Slars 10054374Slars abort_string[n_aborts++] = s1; 10064374Slars 10074374Slars if (verbose) 100834766Speter logf("abort on (%v)", s); 100911990Speter return; 101034766Speter } 101111990Speter 101234766Speter if (clear_abort_next) { 101328597Speter char *s1; 101428597Speter int i; 101528597Speter int old_max; 101628597Speter int pack = 0; 101728597Speter 101828597Speter clear_abort_next = 0; 101928597Speter 102028597Speter s1 = clean(s, 0); 102128597Speter 102228597Speter if (strlen(s1) > strlen(s) 102328597Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 102434766Speter fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 102528597Speter 102628597Speter old_max = n_aborts; 102734766Speter for (i=0; i < n_aborts; i++) { 102834766Speter if ( strcmp(s1,abort_string[i]) == 0 ) { 102934766Speter free(abort_string[i]); 103034766Speter abort_string[i] = NULL; 103134766Speter pack++; 103234766Speter n_aborts--; 103334766Speter if (verbose) 103434766Speter logf("clear abort on (%v)", s); 103528597Speter } 103634766Speter } 103728597Speter free(s1); 103834766Speter if (pack) 103934766Speter pack_array(abort_string,old_max); 104028597Speter return; 104134766Speter } 104228597Speter 104334766Speter if (report_next) { 104411990Speter char *s1; 104511990Speter 104611990Speter report_next = 0; 104711990Speter if (n_reports >= MAX_REPORTS) 104834766Speter fatal(2, "Too many REPORT strings"); 104911990Speter 105011990Speter s1 = clean(s, 0); 105111990Speter 105211990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 105334766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 105411990Speter 105511990Speter report_string[n_reports++] = s1; 105611990Speter 105711990Speter if (verbose) 105834766Speter logf("report (%v)", s); 105911990Speter return; 106034766Speter } 10614374Slars 106234766Speter if (clear_report_next) { 106328597Speter char *s1; 106428597Speter int i; 106528597Speter int old_max; 106628597Speter int pack = 0; 106728597Speter 106828597Speter clear_report_next = 0; 106928597Speter 107028597Speter s1 = clean(s, 0); 107128597Speter 107228597Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 107334766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 107428597Speter 107528597Speter old_max = n_reports; 107634766Speter for (i=0; i < n_reports; i++) { 107734766Speter if ( strcmp(s1,report_string[i]) == 0 ) { 107834766Speter free(report_string[i]); 107934766Speter report_string[i] = NULL; 108034766Speter pack++; 108134766Speter n_reports--; 108234766Speter if (verbose) 108334766Speter logf("clear report (%v)", s); 108428597Speter } 108534766Speter } 108628597Speter free(s1); 108734766Speter if (pack) 108834766Speter pack_array(report_string,old_max); 108928597Speter 109028597Speter return; 109134766Speter } 109228597Speter 109334766Speter if (timeout_next) { 109411990Speter timeout_next = 0; 109511990Speter timeout = atoi(s); 109611990Speter 109711990Speter if (timeout <= 0) 109811990Speter timeout = DEFAULT_CHAT_TIMEOUT; 10994374Slars 110011990Speter if (verbose) 110134766Speter logf("timeout set to %d seconds", timeout); 110234766Speter 110311990Speter return; 110434766Speter } 110511990Speter 110611990Speter if (strcmp(s, "EOT") == 0) 110711990Speter s = "^D\\c"; 110834766Speter else if (strcmp(s, "BREAK") == 0) 110934766Speter s = "\\K\\c"; 111011990Speter 111111990Speter if (!put_string(s)) 111234766Speter fatal(1, "Failed"); 111334766Speter} 11144374Slars 11154374Slarsint get_char() 111634766Speter{ 11174374Slars int status; 11184374Slars char c; 11194374Slars 11204374Slars status = read(0, &c, 1); 11214374Slars 112234766Speter switch (status) { 112311990Speter case 1: 112411990Speter return ((int)c & 0x7F); 11254374Slars 112611990Speter default: 112734766Speter logf("warning: read() on stdin returned %d", status); 11284374Slars 112911990Speter case -1: 113011990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 113134766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 113234766Speter 113334766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113434766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 113511990Speter 113611990Speter return (-1); 11374374Slars } 113834766Speter} 11394374Slars 11404374Slarsint put_char(c) 114111990Speterint c; 114234766Speter{ 11434374Slars int status; 114411990Speter char ch = c; 11454374Slars 114611990Speter usleep(10000); /* inter-character typing delay (?) */ 11474374Slars 114811990Speter status = write(1, &ch, 1); 11494374Slars 115034766Speter switch (status) { 115111990Speter case 1: 115211990Speter return (0); 115311990Speter 115411990Speter default: 115534766Speter logf("warning: write() on stdout returned %d", status); 115611990Speter 115711990Speter case -1: 115811990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 115934766Speter fatal(2, "Can't get file mode flags on stdin, %m"); 116034766Speter 116134766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 116234766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 116311990Speter 116411990Speter return (-1); 11654374Slars } 116634766Speter} 11674374Slars 11684374Slarsint write_char (c) 11694374Slarsint c; 117034766Speter{ 117134766Speter if (alarmed || put_char(c) < 0) { 117211990Speter alarm(0); 117311990Speter alarmed = 0; 11744374Slars 117534766Speter if (verbose) { 11764374Slars if (errno == EINTR || errno == EWOULDBLOCK) 117734766Speter logf(" -- write timed out"); 11784374Slars else 117934766Speter logf(" -- write failed: %m"); 118034766Speter } 11814374Slars return (0); 118234766Speter } 11834374Slars return (1); 118434766Speter} 11854374Slars 11864374Slarsint put_string (s) 11874374Slarsregister char *s; 118834766Speter{ 118928597Speter quiet = 0; 11904374Slars s = clean(s, 1); 11914374Slars 119234766Speter if (verbose) { 11934374Slars if (quiet) 119434766Speter logf("send (??????)"); 11954374Slars else 119634766Speter logf("send (%v)", s); 119734766Speter } 11984374Slars 11994374Slars alarm(timeout); alarmed = 0; 12004374Slars 120134766Speter while (*s) { 12024374Slars register char c = *s++; 12034374Slars 120434766Speter if (c != '\\') { 12054374Slars if (!write_char (c)) 12064374Slars return 0; 12074374Slars continue; 120834766Speter } 12094374Slars 12104374Slars c = *s++; 121134766Speter switch (c) { 12124374Slars case 'd': 12134374Slars sleep(1); 12144374Slars break; 12154374Slars 12164374Slars case 'K': 12174374Slars break_sequence(); 12184374Slars break; 12194374Slars 12204374Slars case 'p': 122111990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 12224374Slars break; 12234374Slars 12244374Slars default: 12254374Slars if (!write_char (c)) 12264374Slars return 0; 12274374Slars break; 12284374Slars } 122934766Speter } 12304374Slars 12314374Slars alarm(0); 12324374Slars alarmed = 0; 12334374Slars return (1); 123434766Speter} 12354374Slars 12364374Slars/* 123728597Speter * Echo a character to stderr. 123828597Speter * When called with -1, a '\n' character is generated when 123928597Speter * the cursor is not at the beginning of a line. 124028597Speter */ 124128597Spetervoid echo_stderr(n) 124228597Speterint n; 124334766Speter{ 124434766Speter static int need_lf; 124534766Speter char *s; 124628597Speter 124734766Speter switch (n) { 124834766Speter case '\r': /* ignore '\r' */ 124934766Speter break; 125034766Speter case -1: 125134766Speter if (need_lf == 0) 125228597Speter break; 125334766Speter /* fall through */ 125434766Speter case '\n': 125534766Speter write(2, "\n", 1); 125634766Speter need_lf = 0; 125734766Speter break; 125834766Speter default: 125934766Speter s = character(n); 126034766Speter write(2, s, strlen(s)); 126134766Speter need_lf = 1; 126234766Speter break; 126328597Speter } 126434766Speter} 126528597Speter 126628597Speter/* 12674374Slars * 'Wait for' this string to appear on this file descriptor. 12684374Slars */ 12694374Slarsint get_string(string) 12704374Slarsregister char *string; 127134766Speter{ 12724374Slars char temp[STR_LEN]; 12734374Slars int c, printed = 0, len, minlen; 12744374Slars register char *s = temp, *end = s + STR_LEN; 127534766Speter char *logged = temp; 12764374Slars 12774374Slars fail_reason = (char *)0; 12784374Slars string = clean(string, 0); 12794374Slars len = strlen(string); 12804374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12814374Slars 12824374Slars if (verbose) 128334766Speter logf("expect (%v)", string); 12844374Slars 128534766Speter if (len > STR_LEN) { 128634766Speter logf("expect string is too long"); 128711990Speter exit_code = 1; 12884374Slars return 0; 128934766Speter } 12904374Slars 129134766Speter if (len == 0) { 12924374Slars if (verbose) 129334766Speter logf("got it"); 12944374Slars return (1); 129534766Speter } 12964374Slars 129711990Speter alarm(timeout); 129811990Speter alarmed = 0; 12994374Slars 130034766Speter while ( ! alarmed && (c = get_char()) >= 0) { 130111990Speter int n, abort_len, report_len; 13024374Slars 130328597Speter if (echo) 130428597Speter echo_stderr(c); 130534766Speter if (verbose && c == '\n') { 130634766Speter if (s == logged) 130734766Speter logf(""); /* blank line */ 13084374Slars else 130934766Speter logf("%0.*v", s - logged, logged); 131034766Speter logged = s + 1; 131134766Speter } 13124374Slars 131334766Speter *s++ = c; 131434766Speter 131534766Speter if (verbose && s >= logged + 80) { 131634766Speter logf("%0.*v", s - logged, logged); 131734766Speter logged = s; 131834766Speter } 131934766Speter 132028597Speter if (Verbose) { 132134766Speter if (c == '\n') 132234766Speter fputc( '\n', stderr ); 132334766Speter else if (c != '\r') 132434766Speter fprintf( stderr, "%s", character(c) ); 132528597Speter } 132628597Speter 132734766Speter if (!report_gathering) { 132834766Speter for (n = 0; n < n_reports; ++n) { 132911990Speter if ((report_string[n] != (char*) NULL) && 133011990Speter s - temp >= (report_len = strlen(report_string[n])) && 133134766Speter strncmp(s - report_len, report_string[n], report_len) == 0) { 133211990Speter time_t time_now = time ((time_t*) NULL); 133311990Speter struct tm* tm_now = localtime (&time_now); 133411990Speter 133511990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 133611990Speter strcat (report_buffer, report_string[n]); 133711990Speter 133811990Speter report_string[n] = (char *) NULL; 133911990Speter report_gathering = 1; 134011990Speter break; 134134766Speter } 134211990Speter } 134334766Speter } 134434766Speter else { 134534766Speter if (!iscntrl (c)) { 134611990Speter int rep_len = strlen (report_buffer); 134711990Speter report_buffer[rep_len] = c; 134811990Speter report_buffer[rep_len + 1] = '\0'; 134934766Speter } 135034766Speter else { 135111990Speter report_gathering = 0; 135211990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 135311990Speter } 135434766Speter } 135511990Speter 135628597Speter if (s - temp >= len && 135728597Speter c == string[len - 1] && 135834766Speter strncmp(s - len, string, len) == 0) { 135934766Speter if (verbose) { 136034766Speter if (s > logged) 136134766Speter logf("%0.*v", s - logged, logged); 136228597Speter logf(" -- got it\n"); 136334766Speter } 136428597Speter 136528597Speter alarm(0); 136628597Speter alarmed = 0; 136728597Speter return (1); 136834766Speter } 136928597Speter 137034766Speter for (n = 0; n < n_aborts; ++n) { 137128597Speter if (s - temp >= (abort_len = strlen(abort_string[n])) && 137234766Speter strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 137334766Speter if (verbose) { 137434766Speter if (s > logged) 137534766Speter logf("%0.*v", s - logged, logged); 137634766Speter logf(" -- failed"); 137734766Speter } 137834766Speter 137928597Speter alarm(0); 138028597Speter alarmed = 0; 138128597Speter exit_code = n + 4; 138228597Speter strcpy(fail_reason = fail_buffer, abort_string[n]); 138328597Speter return (0); 138428597Speter } 138534766Speter } 138628597Speter 138734766Speter if (s >= end) { 138834766Speter if (logged < s - minlen) { 138934766Speter logf("%0.*v", s - logged, logged); 139034766Speter logged = s; 139134766Speter } 139234766Speter s -= minlen; 139334766Speter memmove(temp, s, minlen); 139434766Speter logged = temp + (logged - s); 13954374Slars s = temp + minlen; 139634766Speter } 13974374Slars 13984374Slars if (alarmed && verbose) 139934766Speter logf("warning: alarm synchronization problem"); 140034766Speter } 14014374Slars 14024374Slars alarm(0); 140311990Speter 140434766Speter if (verbose && printed) { 14054374Slars if (alarmed) 140634766Speter logf(" -- read timed out"); 14074374Slars else 140834766Speter logf(" -- read failed: %m"); 140934766Speter } 14104374Slars 141111990Speter exit_code = 3; 141211990Speter alarmed = 0; 14134374Slars return (0); 141434766Speter} 14154374Slars 141637126Speter/* 141737126Speter * Gross kludge to handle Solaris versions >= 2.6 having usleep. 141837126Speter */ 141937126Speter#ifdef SOL2 142037126Speter#include <sys/param.h> 142137126Speter#if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 142237126Speter#undef NO_USLEEP 142337126Speter#endif 142437126Speter#endif /* SOL2 */ 142537126Speter 142611990Speter#ifdef NO_USLEEP 14274374Slars#include <sys/types.h> 14284374Slars#include <sys/time.h> 14294374Slars 14304374Slars/* 14314374Slars usleep -- support routine for 4.2BSD system call emulations 14324374Slars last edit: 29-Oct-1984 D A Gwyn 14334374Slars */ 14344374Slars 14354374Slarsextern int select(); 14364374Slars 14374374Slarsint 14384374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 14394374Slars long usec; /* delay in microseconds */ 14404374Slars{ 144134766Speter static struct { /* `timeval' */ 144211990Speter long tv_sec; /* seconds */ 144311990Speter long tv_usec; /* microsecs */ 144434766Speter } delay; /* _select() timeout */ 14454374Slars 144611990Speter delay.tv_sec = usec / 1000000L; 14474374Slars delay.tv_usec = usec % 1000000L; 14484374Slars 144934766Speter return select(0, (long *)0, (long *)0, (long *)0, &delay); 14504374Slars} 14514374Slars#endif 145228597Speter 145328597Spetervoid 145428597Speterpack_array (array, end) 145528597Speter char **array; /* The address of the array of string pointers */ 145628597Speter int end; /* The index of the next free entry before CLR_ */ 145728597Speter{ 145828597Speter int i, j; 145928597Speter 146028597Speter for (i = 0; i < end; i++) { 146128597Speter if (array[i] == NULL) { 146228597Speter for (j = i+1; j < end; ++j) 146328597Speter if (array[j] != NULL) 146428597Speter array[i++] = array[j]; 146528597Speter for (; i < end; ++i) 146628597Speter array[i] = NULL; 146728597Speter break; 146828597Speter } 146928597Speter } 147028597Speter} 147134766Speter 147234766Speter/* 147334766Speter * vfmtmsg - format a message into a buffer. Like vsprintf except we 147434766Speter * also specify the length of the output buffer, and we handle the 147534766Speter * %m (error message) format. 147634766Speter * Doesn't do floating-point formats. 147734766Speter * Returns the number of chars put into buf. 147834766Speter */ 147934766Speter#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 148034766Speter 148134766Speterint 148234766Spetervfmtmsg(buf, buflen, fmt, args) 148334766Speter char *buf; 148434766Speter int buflen; 148534766Speter const char *fmt; 148634766Speter va_list args; 148734766Speter{ 148834766Speter int c, i, n; 148934766Speter int width, prec, fillch; 149034766Speter int base, len, neg, quoted; 149134766Speter unsigned long val = 0; 149234766Speter char *str, *buf0; 149334766Speter const char *f; 149434766Speter unsigned char *p; 149534766Speter char num[32]; 149634766Speter static char hexchars[] = "0123456789abcdef"; 149734766Speter 149834766Speter buf0 = buf; 149934766Speter --buflen; 150034766Speter while (buflen > 0) { 150134766Speter for (f = fmt; *f != '%' && *f != 0; ++f) 150234766Speter ; 150334766Speter if (f > fmt) { 150434766Speter len = f - fmt; 150534766Speter if (len > buflen) 150634766Speter len = buflen; 150734766Speter memcpy(buf, fmt, len); 150834766Speter buf += len; 150934766Speter buflen -= len; 151034766Speter fmt = f; 151134766Speter } 151234766Speter if (*fmt == 0) 151334766Speter break; 151434766Speter c = *++fmt; 151534766Speter width = prec = 0; 151634766Speter fillch = ' '; 151734766Speter if (c == '0') { 151834766Speter fillch = '0'; 151934766Speter c = *++fmt; 152034766Speter } 152134766Speter if (c == '*') { 152234766Speter width = va_arg(args, int); 152334766Speter c = *++fmt; 152434766Speter } else { 152534766Speter while (isdigit(c)) { 152634766Speter width = width * 10 + c - '0'; 152734766Speter c = *++fmt; 152834766Speter } 152934766Speter } 153034766Speter if (c == '.') { 153134766Speter c = *++fmt; 153234766Speter if (c == '*') { 153334766Speter prec = va_arg(args, int); 153434766Speter c = *++fmt; 153534766Speter } else { 153634766Speter while (isdigit(c)) { 153734766Speter prec = prec * 10 + c - '0'; 153834766Speter c = *++fmt; 153934766Speter } 154034766Speter } 154134766Speter } 154234766Speter str = 0; 154334766Speter base = 0; 154434766Speter neg = 0; 154534766Speter ++fmt; 154634766Speter switch (c) { 154734766Speter case 'd': 154834766Speter i = va_arg(args, int); 154934766Speter if (i < 0) { 155034766Speter neg = 1; 155134766Speter val = -i; 155234766Speter } else 155334766Speter val = i; 155434766Speter base = 10; 155534766Speter break; 155634766Speter case 'o': 155734766Speter val = va_arg(args, unsigned int); 155834766Speter base = 8; 155934766Speter break; 156034766Speter case 'x': 156134766Speter val = va_arg(args, unsigned int); 156234766Speter base = 16; 156334766Speter break; 156434766Speter case 'p': 156534766Speter val = (unsigned long) va_arg(args, void *); 156634766Speter base = 16; 156734766Speter neg = 2; 156834766Speter break; 156934766Speter case 's': 157034766Speter str = va_arg(args, char *); 157134766Speter break; 157234766Speter case 'c': 157334766Speter num[0] = va_arg(args, int); 157434766Speter num[1] = 0; 157534766Speter str = num; 157634766Speter break; 157734766Speter case 'm': 157834766Speter str = strerror(errno); 157934766Speter break; 158034766Speter case 'v': /* "visible" string */ 158134766Speter case 'q': /* quoted string */ 158234766Speter quoted = c == 'q'; 158334766Speter p = va_arg(args, unsigned char *); 158434766Speter if (fillch == '0' && prec > 0) { 158534766Speter n = prec; 158634766Speter } else { 158734766Speter n = strlen((char *)p); 158834766Speter if (prec > 0 && prec < n) 158934766Speter n = prec; 159034766Speter } 159134766Speter while (n > 0 && buflen > 0) { 159234766Speter c = *p++; 159334766Speter --n; 159434766Speter if (!quoted && c >= 0x80) { 159534766Speter OUTCHAR('M'); 159634766Speter OUTCHAR('-'); 159734766Speter c -= 0x80; 159834766Speter } 159934766Speter if (quoted && (c == '"' || c == '\\')) 160034766Speter OUTCHAR('\\'); 160134766Speter if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 160234766Speter if (quoted) { 160334766Speter OUTCHAR('\\'); 160434766Speter switch (c) { 160534766Speter case '\t': OUTCHAR('t'); break; 160634766Speter case '\n': OUTCHAR('n'); break; 160734766Speter case '\b': OUTCHAR('b'); break; 160834766Speter case '\f': OUTCHAR('f'); break; 160934766Speter default: 161034766Speter OUTCHAR('x'); 161134766Speter OUTCHAR(hexchars[c >> 4]); 161234766Speter OUTCHAR(hexchars[c & 0xf]); 161334766Speter } 161434766Speter } else { 161534766Speter if (c == '\t') 161634766Speter OUTCHAR(c); 161734766Speter else { 161834766Speter OUTCHAR('^'); 161934766Speter OUTCHAR(c ^ 0x40); 162034766Speter } 162134766Speter } 162234766Speter } else 162334766Speter OUTCHAR(c); 162434766Speter } 162534766Speter continue; 162634766Speter default: 162734766Speter *buf++ = '%'; 162834766Speter if (c != '%') 162934766Speter --fmt; /* so %z outputs %z etc. */ 163034766Speter --buflen; 163134766Speter continue; 163234766Speter } 163334766Speter if (base != 0) { 163434766Speter str = num + sizeof(num); 163534766Speter *--str = 0; 163634766Speter while (str > num + neg) { 163734766Speter *--str = hexchars[val % base]; 163834766Speter val = val / base; 163934766Speter if (--prec <= 0 && val == 0) 164034766Speter break; 164134766Speter } 164234766Speter switch (neg) { 164334766Speter case 1: 164434766Speter *--str = '-'; 164534766Speter break; 164634766Speter case 2: 164734766Speter *--str = 'x'; 164834766Speter *--str = '0'; 164934766Speter break; 165034766Speter } 165134766Speter len = num + sizeof(num) - 1 - str; 165234766Speter } else { 165334766Speter len = strlen(str); 165434766Speter if (prec > 0 && len > prec) 165534766Speter len = prec; 165634766Speter } 165734766Speter if (width > 0) { 165834766Speter if (width > buflen) 165934766Speter width = buflen; 166034766Speter if ((n = width - len) > 0) { 166134766Speter buflen -= n; 166234766Speter for (; n > 0; --n) 166334766Speter *buf++ = fillch; 166434766Speter } 166534766Speter } 166634766Speter if (len > buflen) 166734766Speter len = buflen; 166834766Speter memcpy(buf, str, len); 166934766Speter buf += len; 167034766Speter buflen -= len; 167134766Speter } 167234766Speter *buf = 0; 167334766Speter return buf - buf0; 167434766Speter} 1675