chat.c revision 80381
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[] = 8250477Speter "$FreeBSD: head/usr.bin/chat/chat.c 80381 2001-07-26 11:02:39Z sheldonh $"; 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; 65853686Skris /* Don't overflow buffer, leave room for chars we append later */ 65953686Skris while (*s && s1 - temp < sizeof(temp) - 2 - add_return) { 6604374Slars cur_chr = *s++; 66134766Speter if (cur_chr == '^') { 6624374Slars cur_chr = *s++; 66334766Speter if (cur_chr == '\0') { 6644374Slars *s1++ = '^'; 6654374Slars break; 66634766Speter } 6674374Slars cur_chr &= 0x1F; 66834766Speter if (cur_chr != 0) { 6694374Slars *s1++ = cur_chr; 67034766Speter } 6714374Slars continue; 67234766Speter } 6734374Slars 67434766Speter if (cur_chr != '\\') { 6754374Slars *s1++ = cur_chr; 6764374Slars continue; 67734766Speter } 6784374Slars 6794374Slars cur_chr = *s++; 68034766Speter if (cur_chr == '\0') { 68134766Speter if (sending) { 6824374Slars *s1++ = '\\'; 6834374Slars *s1++ = '\\'; 68434766Speter } 6854374Slars break; 68634766Speter } 6874374Slars 68834766Speter switch (cur_chr) { 6894374Slars case 'b': 6904374Slars *s1++ = '\b'; 6914374Slars break; 6924374Slars 6934374Slars case 'c': 6944374Slars if (sending && *s == '\0') 6954374Slars add_return = 0; 6964374Slars else 6974374Slars *s1++ = cur_chr; 6984374Slars break; 6994374Slars 7004374Slars case '\\': 7014374Slars case 'K': 7024374Slars case 'p': 7034374Slars case 'd': 7044374Slars if (sending) 7054374Slars *s1++ = '\\'; 7064374Slars 7074374Slars *s1++ = cur_chr; 7084374Slars break; 7094374Slars 71034766Speter case 'T': 71134766Speter if (sending && phone_num) { 71234766Speter for ( phchar = phone_num; *phchar != '\0'; phchar++) 71334766Speter *s1++ = *phchar; 71434766Speter } 71534766Speter else { 71634766Speter *s1++ = '\\'; 71734766Speter *s1++ = 'T'; 71834766Speter } 71934766Speter break; 72034766Speter 72134766Speter case 'U': 72234766Speter if (sending && phone_num2) { 72334766Speter for ( phchar = phone_num2; *phchar != '\0'; phchar++) 72434766Speter *s1++ = *phchar; 72534766Speter } 72634766Speter else { 72734766Speter *s1++ = '\\'; 72834766Speter *s1++ = 'U'; 72934766Speter } 73034766Speter break; 73134766Speter 7324374Slars case 'q': 73328597Speter quiet = 1; 7344374Slars break; 7354374Slars 7364374Slars case 'r': 7374374Slars *s1++ = '\r'; 7384374Slars break; 7394374Slars 7404374Slars case 'n': 7414374Slars *s1++ = '\n'; 7424374Slars break; 7434374Slars 7444374Slars case 's': 7454374Slars *s1++ = ' '; 7464374Slars break; 7474374Slars 7484374Slars case 't': 7494374Slars *s1++ = '\t'; 7504374Slars break; 7514374Slars 7524374Slars case 'N': 75334766Speter if (sending) { 7544374Slars *s1++ = '\\'; 7554374Slars *s1++ = '\0'; 75634766Speter } 7574374Slars else 7584374Slars *s1++ = 'N'; 7594374Slars break; 76011990Speter 7614374Slars default: 76234766Speter if (isoctal (cur_chr)) { 7634374Slars cur_chr &= 0x07; 76434766Speter if (isoctal (*s)) { 7654374Slars cur_chr <<= 3; 7664374Slars cur_chr |= *s++ - '0'; 76734766Speter if (isoctal (*s)) { 7684374Slars cur_chr <<= 3; 7694374Slars cur_chr |= *s++ - '0'; 7704374Slars } 77134766Speter } 7724374Slars 77334766Speter if (cur_chr != 0 || sending) { 7744374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 7754374Slars *s1++ = '\\'; 7764374Slars *s1++ = cur_chr; 77734766Speter } 7784374Slars break; 77934766Speter } 7804374Slars 7814374Slars if (sending) 7824374Slars *s1++ = '\\'; 7834374Slars *s1++ = cur_chr; 7844374Slars break; 7854374Slars } 78634766Speter } 7874374Slars 7884374Slars if (add_return) 7894374Slars *s1++ = '\r'; 7904374Slars 7914374Slars *s1++ = '\0'; /* guarantee closure */ 7924374Slars *s1++ = '\0'; /* terminate the string */ 7934374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 79434766Speter} 7954374Slars 7964374Slars/* 79728597Speter * A modified version of 'strtok'. This version skips \ sequences. 79828597Speter */ 79928597Speter 80028597Speterchar *expect_strtok (s, term) 80134766Speter char *s, *term; 80234766Speter{ 80328597Speter static char *str = ""; 80428597Speter int escape_flag = 0; 80528597Speter char *result; 80634766Speter 80728597Speter/* 80828597Speter * If a string was specified then do initial processing. 80928597Speter */ 81028597Speter if (s) 81128597Speter str = s; 81234766Speter 81328597Speter/* 81428597Speter * If this is the escape flag then reset it and ignore the character. 81528597Speter */ 81628597Speter if (*str) 81728597Speter result = str; 81828597Speter else 81928597Speter result = (char *) 0; 82028597Speter 82134766Speter while (*str) { 82234766Speter if (escape_flag) { 82328597Speter escape_flag = 0; 82428597Speter ++str; 82528597Speter continue; 82634766Speter } 82728597Speter 82834766Speter if (*str == '\\') { 82928597Speter ++str; 83028597Speter escape_flag = 1; 83128597Speter continue; 83234766Speter } 83334766Speter 83428597Speter/* 83528597Speter * If this is not in the termination string, continue. 83628597Speter */ 83734766Speter if (strchr (term, *str) == (char *) 0) { 83828597Speter ++str; 83928597Speter continue; 84034766Speter } 84134766Speter 84228597Speter/* 84328597Speter * This is the terminator. Mark the end of the string and stop. 84428597Speter */ 84528597Speter *str++ = '\0'; 84628597Speter break; 84734766Speter } 84828597Speter return (result); 84934766Speter} 85028597Speter 85128597Speter/* 8524374Slars * Process the expect string 8534374Slars */ 85428597Speter 85528597Spetervoid chat_expect (s) 85628597Speterchar *s; 85734766Speter{ 85828597Speter char *expect; 85928597Speter char *reply; 86028597Speter 86134766Speter if (strcmp(s, "HANGUP") == 0) { 86228597Speter ++hup_next; 86328597Speter return; 86434766Speter } 86528597Speter 86634766Speter if (strcmp(s, "ABORT") == 0) { 8674374Slars ++abort_next; 8684374Slars return; 86934766Speter } 8704374Slars 87134766Speter if (strcmp(s, "CLR_ABORT") == 0) { 87228597Speter ++clear_abort_next; 87328597Speter return; 87434766Speter } 87528597Speter 87634766Speter if (strcmp(s, "REPORT") == 0) { 87711990Speter ++report_next; 87811990Speter return; 87934766Speter } 88011990Speter 88134766Speter if (strcmp(s, "CLR_REPORT") == 0) { 88228597Speter ++clear_report_next; 88328597Speter return; 88434766Speter } 88528597Speter 88634766Speter if (strcmp(s, "TIMEOUT") == 0) { 8874374Slars ++timeout_next; 8884374Slars return; 88934766Speter } 8904374Slars 89134766Speter if (strcmp(s, "ECHO") == 0) { 89228597Speter ++echo_next; 89328597Speter return; 89434766Speter } 89534766Speter 89634766Speter if (strcmp(s, "SAY") == 0) { 89728597Speter ++say_next; 89828597Speter return; 89934766Speter } 90034766Speter 90128597Speter/* 90228597Speter * Fetch the expect and reply string. 90328597Speter */ 90434766Speter for (;;) { 90528597Speter expect = expect_strtok (s, "-"); 90628597Speter s = (char *) 0; 9074374Slars 90828597Speter if (expect == (char *) 0) 90928597Speter return; 91028597Speter 91128597Speter reply = expect_strtok (s, "-"); 91234766Speter 91328597Speter/* 91428597Speter * Handle the expect string. If successful then exit. 91528597Speter */ 91628597Speter if (get_string (expect)) 91728597Speter return; 91834766Speter 91928597Speter/* 92028597Speter * If there is a sub-reply string then send it. Otherwise any condition 92128597Speter * is terminal. 92228597Speter */ 92328597Speter if (reply == (char *) 0 || exit_code != 3) 92428597Speter break; 9254374Slars 92628597Speter chat_send (reply); 92734766Speter } 92834766Speter 92928597Speter/* 93028597Speter * The expectation did not occur. This is terminal. 93128597Speter */ 93228597Speter if (fail_reason) 93334766Speter logf("Failed (%s)", fail_reason); 93428597Speter else 93534766Speter logf("Failed"); 93628597Speter terminate(exit_code); 93734766Speter} 9384374Slars 93928597Speter/* 94028597Speter * Translate the input character to the appropriate string for printing 94128597Speter * the data. 94228597Speter */ 94328597Speter 9444374Slarschar *character(c) 94511990Speterint c; 94634766Speter{ 9474374Slars static char string[10]; 9484374Slars char *meta; 9494374Slars 9504374Slars meta = (c & 0x80) ? "M-" : ""; 9514374Slars c &= 0x7F; 9524374Slars 9534374Slars if (c < 32) 9544374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 95534766Speter else if (c == 127) 95634766Speter sprintf(string, "%s^?", meta); 9574374Slars else 95834766Speter sprintf(string, "%s%c", meta, c); 9594374Slars 9604374Slars return (string); 96134766Speter} 9624374Slars 9634374Slars/* 9644374Slars * process the reply string 9654374Slars */ 9664374Slarsvoid chat_send (s) 9674374Slarsregister char *s; 96834766Speter{ 96934766Speter if (say_next) { 97028597Speter say_next = 0; 97128597Speter s = clean(s,0); 97280381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 97328597Speter free(s); 97428597Speter return; 97534766Speter } 97634766Speter 97734766Speter if (hup_next) { 97828597Speter hup_next = 0; 97928597Speter if (strcmp(s, "OFF") == 0) 98028597Speter signal(SIGHUP, SIG_IGN); 98128597Speter else 98228597Speter signal(SIGHUP, sighup); 98328597Speter return; 98434766Speter } 98534766Speter 98634766Speter if (echo_next) { 98728597Speter echo_next = 0; 98828597Speter echo = (strcmp(s, "ON") == 0); 98928597Speter return; 99034766Speter } 99134766Speter 99234766Speter if (abort_next) { 9934374Slars char *s1; 99411990Speter 9954374Slars abort_next = 0; 99611990Speter 9974374Slars if (n_aborts >= MAX_ABORTS) 99834766Speter fatal(2, "Too many ABORT strings"); 99911990Speter 10004374Slars s1 = clean(s, 0); 100111990Speter 100211990Speter if (strlen(s1) > strlen(s) 100311990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 100434766Speter fatal(1, "Illegal or too-long ABORT string ('%v')", s); 10054374Slars 10064374Slars abort_string[n_aborts++] = s1; 10074374Slars 10084374Slars if (verbose) 100934766Speter logf("abort on (%v)", s); 101011990Speter return; 101134766Speter } 101211990Speter 101334766Speter if (clear_abort_next) { 101428597Speter char *s1; 101528597Speter int i; 101628597Speter int old_max; 101728597Speter int pack = 0; 101828597Speter 101928597Speter clear_abort_next = 0; 102028597Speter 102128597Speter s1 = clean(s, 0); 102228597Speter 102328597Speter if (strlen(s1) > strlen(s) 102428597Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 102534766Speter fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 102628597Speter 102728597Speter old_max = n_aborts; 102834766Speter for (i=0; i < n_aborts; i++) { 102934766Speter if ( strcmp(s1,abort_string[i]) == 0 ) { 103034766Speter free(abort_string[i]); 103134766Speter abort_string[i] = NULL; 103234766Speter pack++; 103334766Speter n_aborts--; 103434766Speter if (verbose) 103534766Speter logf("clear abort on (%v)", s); 103628597Speter } 103734766Speter } 103828597Speter free(s1); 103934766Speter if (pack) 104034766Speter pack_array(abort_string,old_max); 104128597Speter return; 104234766Speter } 104328597Speter 104434766Speter if (report_next) { 104511990Speter char *s1; 104611990Speter 104711990Speter report_next = 0; 104811990Speter if (n_reports >= MAX_REPORTS) 104934766Speter fatal(2, "Too many REPORT strings"); 105011990Speter 105111990Speter s1 = clean(s, 0); 105211990Speter 105311990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 105434766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 105511990Speter 105611990Speter report_string[n_reports++] = s1; 105711990Speter 105811990Speter if (verbose) 105934766Speter logf("report (%v)", s); 106011990Speter return; 106134766Speter } 10624374Slars 106334766Speter if (clear_report_next) { 106428597Speter char *s1; 106528597Speter int i; 106628597Speter int old_max; 106728597Speter int pack = 0; 106828597Speter 106928597Speter clear_report_next = 0; 107028597Speter 107128597Speter s1 = clean(s, 0); 107228597Speter 107328597Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 107434766Speter fatal(1, "Illegal or too-long REPORT string ('%v')", s); 107528597Speter 107628597Speter old_max = n_reports; 107734766Speter for (i=0; i < n_reports; i++) { 107834766Speter if ( strcmp(s1,report_string[i]) == 0 ) { 107934766Speter free(report_string[i]); 108034766Speter report_string[i] = NULL; 108134766Speter pack++; 108234766Speter n_reports--; 108334766Speter if (verbose) 108434766Speter logf("clear report (%v)", s); 108528597Speter } 108634766Speter } 108728597Speter free(s1); 108834766Speter if (pack) 108934766Speter pack_array(report_string,old_max); 109028597Speter 109128597Speter return; 109234766Speter } 109328597Speter 109434766Speter if (timeout_next) { 109511990Speter timeout_next = 0; 109611990Speter timeout = atoi(s); 109711990Speter 109811990Speter if (timeout <= 0) 109911990Speter timeout = DEFAULT_CHAT_TIMEOUT; 11004374Slars 110111990Speter if (verbose) 110234766Speter logf("timeout set to %d seconds", timeout); 110334766Speter 110411990Speter return; 110534766Speter } 110611990Speter 110711990Speter if (strcmp(s, "EOT") == 0) 110811990Speter s = "^D\\c"; 110934766Speter else if (strcmp(s, "BREAK") == 0) 111034766Speter s = "\\K\\c"; 111111990Speter 111211990Speter if (!put_string(s)) 111334766Speter fatal(1, "Failed"); 111434766Speter} 11154374Slars 11164374Slarsint get_char() 111734766Speter{ 11184374Slars int status; 11194374Slars char c; 11204374Slars 112180381Ssheldonh status = read(STDIN_FILENO, &c, 1); 11224374Slars 112334766Speter switch (status) { 112411990Speter case 1: 112511990Speter return ((int)c & 0x7F); 11264374Slars 112711990Speter default: 112834766Speter logf("warning: read() on stdin returned %d", status); 11294374Slars 113011990Speter case -1: 113111990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 113234766Speter fatal(2, "Can't get file mode flags on stdin: %m"); 113334766Speter 113434766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 113534766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 113611990Speter 113711990Speter return (-1); 11384374Slars } 113934766Speter} 11404374Slars 11414374Slarsint put_char(c) 114211990Speterint c; 114334766Speter{ 11444374Slars int status; 114511990Speter char ch = c; 11464374Slars 114711990Speter usleep(10000); /* inter-character typing delay (?) */ 11484374Slars 114980381Ssheldonh status = write(STDOUT_FILENO, &ch, 1); 11504374Slars 115134766Speter switch (status) { 115211990Speter case 1: 115311990Speter return (0); 115411990Speter 115511990Speter default: 115634766Speter logf("warning: write() on stdout returned %d", status); 115711990Speter 115811990Speter case -1: 115911990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 116034766Speter fatal(2, "Can't get file mode flags on stdin, %m"); 116134766Speter 116234766Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 116334766Speter fatal(2, "Can't set file mode flags on stdin: %m"); 116411990Speter 116511990Speter return (-1); 11664374Slars } 116734766Speter} 11684374Slars 11694374Slarsint write_char (c) 11704374Slarsint c; 117134766Speter{ 117234766Speter if (alarmed || put_char(c) < 0) { 117311990Speter alarm(0); 117411990Speter alarmed = 0; 11754374Slars 117634766Speter if (verbose) { 11774374Slars if (errno == EINTR || errno == EWOULDBLOCK) 117834766Speter logf(" -- write timed out"); 11794374Slars else 118034766Speter logf(" -- write failed: %m"); 118134766Speter } 11824374Slars return (0); 118334766Speter } 11844374Slars return (1); 118534766Speter} 11864374Slars 11874374Slarsint put_string (s) 11884374Slarsregister char *s; 118934766Speter{ 119028597Speter quiet = 0; 11914374Slars s = clean(s, 1); 11924374Slars 119334766Speter if (verbose) { 11944374Slars if (quiet) 119534766Speter logf("send (??????)"); 11964374Slars else 119734766Speter logf("send (%v)", s); 119834766Speter } 11994374Slars 12004374Slars alarm(timeout); alarmed = 0; 12014374Slars 120234766Speter while (*s) { 12034374Slars register char c = *s++; 12044374Slars 120534766Speter if (c != '\\') { 12064374Slars if (!write_char (c)) 12074374Slars return 0; 12084374Slars continue; 120934766Speter } 12104374Slars 12114374Slars c = *s++; 121234766Speter switch (c) { 12134374Slars case 'd': 12144374Slars sleep(1); 12154374Slars break; 12164374Slars 12174374Slars case 'K': 12184374Slars break_sequence(); 12194374Slars break; 12204374Slars 12214374Slars case 'p': 122211990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 12234374Slars break; 12244374Slars 12254374Slars default: 12264374Slars if (!write_char (c)) 12274374Slars return 0; 12284374Slars break; 12294374Slars } 123034766Speter } 12314374Slars 12324374Slars alarm(0); 12334374Slars alarmed = 0; 12344374Slars return (1); 123534766Speter} 12364374Slars 12374374Slars/* 123828597Speter * Echo a character to stderr. 123928597Speter * When called with -1, a '\n' character is generated when 124028597Speter * the cursor is not at the beginning of a line. 124128597Speter */ 124228597Spetervoid echo_stderr(n) 124328597Speterint n; 124434766Speter{ 124534766Speter static int need_lf; 124634766Speter char *s; 124728597Speter 124834766Speter switch (n) { 124934766Speter case '\r': /* ignore '\r' */ 125034766Speter break; 125134766Speter case -1: 125234766Speter if (need_lf == 0) 125328597Speter break; 125434766Speter /* fall through */ 125534766Speter case '\n': 125680381Ssheldonh write(STDERR_FILENO, "\n", 1); 125734766Speter need_lf = 0; 125834766Speter break; 125934766Speter default: 126034766Speter s = character(n); 126180381Ssheldonh write(STDERR_FILENO, s, strlen(s)); 126234766Speter need_lf = 1; 126334766Speter break; 126428597Speter } 126534766Speter} 126628597Speter 126728597Speter/* 12684374Slars * 'Wait for' this string to appear on this file descriptor. 12694374Slars */ 12704374Slarsint get_string(string) 12714374Slarsregister char *string; 127234766Speter{ 12734374Slars char temp[STR_LEN]; 12744374Slars int c, printed = 0, len, minlen; 12754374Slars register char *s = temp, *end = s + STR_LEN; 127634766Speter char *logged = temp; 12774374Slars 12784374Slars fail_reason = (char *)0; 127953686Skris 128053686Skris if (strlen(string) > STR_LEN) { 128153686Skris logf("expect string is too long"); 128253686Skris exit_code = 1; 128353686Skris return 0; 128453686Skris } 128553686Skris 12864374Slars string = clean(string, 0); 12874374Slars len = strlen(string); 12884374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 12894374Slars 12904374Slars if (verbose) 129134766Speter logf("expect (%v)", string); 12924374Slars 129334766Speter if (len == 0) { 12944374Slars if (verbose) 129534766Speter logf("got it"); 12964374Slars return (1); 129734766Speter } 12984374Slars 129911990Speter alarm(timeout); 130011990Speter alarmed = 0; 13014374Slars 130234766Speter while ( ! alarmed && (c = get_char()) >= 0) { 130311990Speter int n, abort_len, report_len; 13044374Slars 130528597Speter if (echo) 130628597Speter echo_stderr(c); 130734766Speter if (verbose && c == '\n') { 130834766Speter if (s == logged) 130934766Speter logf(""); /* blank line */ 13104374Slars else 131134766Speter logf("%0.*v", s - logged, logged); 131234766Speter logged = s + 1; 131334766Speter } 13144374Slars 131534766Speter *s++ = c; 131634766Speter 131734766Speter if (verbose && s >= logged + 80) { 131834766Speter logf("%0.*v", s - logged, logged); 131934766Speter logged = s; 132034766Speter } 132134766Speter 132228597Speter if (Verbose) { 132334766Speter if (c == '\n') 132434766Speter fputc( '\n', stderr ); 132534766Speter else if (c != '\r') 132634766Speter fprintf( stderr, "%s", character(c) ); 132728597Speter } 132828597Speter 132934766Speter if (!report_gathering) { 133034766Speter for (n = 0; n < n_reports; ++n) { 133111990Speter if ((report_string[n] != (char*) NULL) && 133211990Speter s - temp >= (report_len = strlen(report_string[n])) && 133334766Speter strncmp(s - report_len, report_string[n], report_len) == 0) { 133411990Speter time_t time_now = time ((time_t*) NULL); 133511990Speter struct tm* tm_now = localtime (&time_now); 133611990Speter 133711990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 133811990Speter strcat (report_buffer, report_string[n]); 133911990Speter 134011990Speter report_string[n] = (char *) NULL; 134111990Speter report_gathering = 1; 134211990Speter break; 134334766Speter } 134411990Speter } 134534766Speter } 134634766Speter else { 134734766Speter if (!iscntrl (c)) { 134811990Speter int rep_len = strlen (report_buffer); 134911990Speter report_buffer[rep_len] = c; 135011990Speter report_buffer[rep_len + 1] = '\0'; 135134766Speter } 135234766Speter else { 135311990Speter report_gathering = 0; 135411990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 135511990Speter } 135634766Speter } 135711990Speter 135828597Speter if (s - temp >= len && 135928597Speter c == string[len - 1] && 136034766Speter strncmp(s - len, string, len) == 0) { 136134766Speter if (verbose) { 136234766Speter if (s > logged) 136334766Speter logf("%0.*v", s - logged, logged); 136428597Speter logf(" -- got it\n"); 136534766Speter } 136628597Speter 136728597Speter alarm(0); 136828597Speter alarmed = 0; 136928597Speter return (1); 137034766Speter } 137128597Speter 137234766Speter for (n = 0; n < n_aborts; ++n) { 137328597Speter if (s - temp >= (abort_len = strlen(abort_string[n])) && 137434766Speter strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 137534766Speter if (verbose) { 137634766Speter if (s > logged) 137734766Speter logf("%0.*v", s - logged, logged); 137834766Speter logf(" -- failed"); 137934766Speter } 138034766Speter 138128597Speter alarm(0); 138228597Speter alarmed = 0; 138328597Speter exit_code = n + 4; 138428597Speter strcpy(fail_reason = fail_buffer, abort_string[n]); 138528597Speter return (0); 138628597Speter } 138734766Speter } 138828597Speter 138934766Speter if (s >= end) { 139034766Speter if (logged < s - minlen) { 139134766Speter logf("%0.*v", s - logged, logged); 139234766Speter logged = s; 139334766Speter } 139434766Speter s -= minlen; 139534766Speter memmove(temp, s, minlen); 139634766Speter logged = temp + (logged - s); 13974374Slars s = temp + minlen; 139834766Speter } 13994374Slars 14004374Slars if (alarmed && verbose) 140134766Speter logf("warning: alarm synchronization problem"); 140234766Speter } 14034374Slars 14044374Slars alarm(0); 140511990Speter 140634766Speter if (verbose && printed) { 14074374Slars if (alarmed) 140834766Speter logf(" -- read timed out"); 14094374Slars else 141034766Speter logf(" -- read failed: %m"); 141134766Speter } 14124374Slars 141311990Speter exit_code = 3; 141411990Speter alarmed = 0; 14154374Slars return (0); 141634766Speter} 14174374Slars 141837126Speter/* 141937126Speter * Gross kludge to handle Solaris versions >= 2.6 having usleep. 142037126Speter */ 142137126Speter#ifdef SOL2 142237126Speter#include <sys/param.h> 142337126Speter#if MAXUID > 65536 /* then this is Solaris 2.6 or later */ 142437126Speter#undef NO_USLEEP 142537126Speter#endif 142637126Speter#endif /* SOL2 */ 142737126Speter 142811990Speter#ifdef NO_USLEEP 14294374Slars#include <sys/types.h> 14304374Slars#include <sys/time.h> 14314374Slars 14324374Slars/* 14334374Slars usleep -- support routine for 4.2BSD system call emulations 14344374Slars last edit: 29-Oct-1984 D A Gwyn 14354374Slars */ 14364374Slars 14374374Slarsextern int select(); 14384374Slars 14394374Slarsint 14404374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 14414374Slars long usec; /* delay in microseconds */ 14424374Slars{ 144334766Speter static struct { /* `timeval' */ 144411990Speter long tv_sec; /* seconds */ 144511990Speter long tv_usec; /* microsecs */ 144634766Speter } delay; /* _select() timeout */ 14474374Slars 144811990Speter delay.tv_sec = usec / 1000000L; 14494374Slars delay.tv_usec = usec % 1000000L; 14504374Slars 145134766Speter return select(0, (long *)0, (long *)0, (long *)0, &delay); 14524374Slars} 14534374Slars#endif 145428597Speter 145528597Spetervoid 145628597Speterpack_array (array, end) 145728597Speter char **array; /* The address of the array of string pointers */ 145828597Speter int end; /* The index of the next free entry before CLR_ */ 145928597Speter{ 146028597Speter int i, j; 146128597Speter 146228597Speter for (i = 0; i < end; i++) { 146328597Speter if (array[i] == NULL) { 146428597Speter for (j = i+1; j < end; ++j) 146528597Speter if (array[j] != NULL) 146628597Speter array[i++] = array[j]; 146728597Speter for (; i < end; ++i) 146828597Speter array[i] = NULL; 146928597Speter break; 147028597Speter } 147128597Speter } 147228597Speter} 147334766Speter 147434766Speter/* 147534766Speter * vfmtmsg - format a message into a buffer. Like vsprintf except we 147634766Speter * also specify the length of the output buffer, and we handle the 147734766Speter * %m (error message) format. 147834766Speter * Doesn't do floating-point formats. 147934766Speter * Returns the number of chars put into buf. 148034766Speter */ 148134766Speter#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 148234766Speter 148334766Speterint 148434766Spetervfmtmsg(buf, buflen, fmt, args) 148534766Speter char *buf; 148634766Speter int buflen; 148734766Speter const char *fmt; 148834766Speter va_list args; 148934766Speter{ 149034766Speter int c, i, n; 149134766Speter int width, prec, fillch; 149234766Speter int base, len, neg, quoted; 149334766Speter unsigned long val = 0; 149434766Speter char *str, *buf0; 149534766Speter const char *f; 149634766Speter unsigned char *p; 149734766Speter char num[32]; 149834766Speter static char hexchars[] = "0123456789abcdef"; 149934766Speter 150034766Speter buf0 = buf; 150134766Speter --buflen; 150234766Speter while (buflen > 0) { 150334766Speter for (f = fmt; *f != '%' && *f != 0; ++f) 150434766Speter ; 150534766Speter if (f > fmt) { 150634766Speter len = f - fmt; 150734766Speter if (len > buflen) 150834766Speter len = buflen; 150934766Speter memcpy(buf, fmt, len); 151034766Speter buf += len; 151134766Speter buflen -= len; 151234766Speter fmt = f; 151334766Speter } 151434766Speter if (*fmt == 0) 151534766Speter break; 151634766Speter c = *++fmt; 151734766Speter width = prec = 0; 151834766Speter fillch = ' '; 151934766Speter if (c == '0') { 152034766Speter fillch = '0'; 152134766Speter c = *++fmt; 152234766Speter } 152334766Speter if (c == '*') { 152434766Speter width = va_arg(args, int); 152534766Speter c = *++fmt; 152634766Speter } else { 152734766Speter while (isdigit(c)) { 152834766Speter width = width * 10 + c - '0'; 152934766Speter c = *++fmt; 153034766Speter } 153134766Speter } 153234766Speter if (c == '.') { 153334766Speter c = *++fmt; 153434766Speter if (c == '*') { 153534766Speter prec = va_arg(args, int); 153634766Speter c = *++fmt; 153734766Speter } else { 153834766Speter while (isdigit(c)) { 153934766Speter prec = prec * 10 + c - '0'; 154034766Speter c = *++fmt; 154134766Speter } 154234766Speter } 154334766Speter } 154434766Speter str = 0; 154534766Speter base = 0; 154634766Speter neg = 0; 154734766Speter ++fmt; 154834766Speter switch (c) { 154934766Speter case 'd': 155034766Speter i = va_arg(args, int); 155134766Speter if (i < 0) { 155234766Speter neg = 1; 155334766Speter val = -i; 155434766Speter } else 155534766Speter val = i; 155634766Speter base = 10; 155734766Speter break; 155834766Speter case 'o': 155934766Speter val = va_arg(args, unsigned int); 156034766Speter base = 8; 156134766Speter break; 156234766Speter case 'x': 156334766Speter val = va_arg(args, unsigned int); 156434766Speter base = 16; 156534766Speter break; 156634766Speter case 'p': 156734766Speter val = (unsigned long) va_arg(args, void *); 156834766Speter base = 16; 156934766Speter neg = 2; 157034766Speter break; 157134766Speter case 's': 157234766Speter str = va_arg(args, char *); 157334766Speter break; 157434766Speter case 'c': 157534766Speter num[0] = va_arg(args, int); 157634766Speter num[1] = 0; 157734766Speter str = num; 157834766Speter break; 157934766Speter case 'm': 158034766Speter str = strerror(errno); 158134766Speter break; 158234766Speter case 'v': /* "visible" string */ 158334766Speter case 'q': /* quoted string */ 158434766Speter quoted = c == 'q'; 158534766Speter p = va_arg(args, unsigned char *); 158634766Speter if (fillch == '0' && prec > 0) { 158734766Speter n = prec; 158834766Speter } else { 158934766Speter n = strlen((char *)p); 159034766Speter if (prec > 0 && prec < n) 159134766Speter n = prec; 159234766Speter } 159334766Speter while (n > 0 && buflen > 0) { 159434766Speter c = *p++; 159534766Speter --n; 159634766Speter if (!quoted && c >= 0x80) { 159734766Speter OUTCHAR('M'); 159834766Speter OUTCHAR('-'); 159934766Speter c -= 0x80; 160034766Speter } 160134766Speter if (quoted && (c == '"' || c == '\\')) 160234766Speter OUTCHAR('\\'); 160334766Speter if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 160434766Speter if (quoted) { 160534766Speter OUTCHAR('\\'); 160634766Speter switch (c) { 160734766Speter case '\t': OUTCHAR('t'); break; 160834766Speter case '\n': OUTCHAR('n'); break; 160934766Speter case '\b': OUTCHAR('b'); break; 161034766Speter case '\f': OUTCHAR('f'); break; 161134766Speter default: 161234766Speter OUTCHAR('x'); 161334766Speter OUTCHAR(hexchars[c >> 4]); 161434766Speter OUTCHAR(hexchars[c & 0xf]); 161534766Speter } 161634766Speter } else { 161734766Speter if (c == '\t') 161834766Speter OUTCHAR(c); 161934766Speter else { 162034766Speter OUTCHAR('^'); 162134766Speter OUTCHAR(c ^ 0x40); 162234766Speter } 162334766Speter } 162434766Speter } else 162534766Speter OUTCHAR(c); 162634766Speter } 162734766Speter continue; 162834766Speter default: 162934766Speter *buf++ = '%'; 163034766Speter if (c != '%') 163134766Speter --fmt; /* so %z outputs %z etc. */ 163234766Speter --buflen; 163334766Speter continue; 163434766Speter } 163534766Speter if (base != 0) { 163634766Speter str = num + sizeof(num); 163734766Speter *--str = 0; 163834766Speter while (str > num + neg) { 163934766Speter *--str = hexchars[val % base]; 164034766Speter val = val / base; 164134766Speter if (--prec <= 0 && val == 0) 164234766Speter break; 164334766Speter } 164434766Speter switch (neg) { 164534766Speter case 1: 164634766Speter *--str = '-'; 164734766Speter break; 164834766Speter case 2: 164934766Speter *--str = 'x'; 165034766Speter *--str = '0'; 165134766Speter break; 165234766Speter } 165334766Speter len = num + sizeof(num) - 1 - str; 165434766Speter } else { 165534766Speter len = strlen(str); 165634766Speter if (prec > 0 && len > prec) 165734766Speter len = prec; 165834766Speter } 165934766Speter if (width > 0) { 166034766Speter if (width > buflen) 166134766Speter width = buflen; 166234766Speter if ((n = width - len) > 0) { 166334766Speter buflen -= n; 166434766Speter for (; n > 0; --n) 166534766Speter *buf++ = fillch; 166634766Speter } 166734766Speter } 166834766Speter if (len > buflen) 166934766Speter len = buflen; 167034766Speter memcpy(buf, str, len); 167134766Speter buf += len; 167234766Speter buflen -= len; 167334766Speter } 167434766Speter *buf = 0; 167534766Speter return buf - buf0; 167634766Speter} 1677