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