xref: /freebsd/usr.bin/chat/chat.c (revision d7d1005304be06c8b9e61169e0fc5e43e1cee133)
19b1aec48SLars Fredriksen /*
29b1aec48SLars Fredriksen  *	Chat -- a program for automatic session establishment (i.e. dial
39b1aec48SLars Fredriksen  *		the phone and log in).
49b1aec48SLars Fredriksen  *
59f65f104SPeter Wemm  * Standard termination codes:
69f65f104SPeter Wemm  *  0 - successful completion of the script
79f65f104SPeter Wemm  *  1 - invalid argument, expect string too large, etc.
89f65f104SPeter Wemm  *  2 - error on an I/O operation or fatal error condtion.
99f65f104SPeter Wemm  *  3 - timeout waiting for a simple string.
109f65f104SPeter Wemm  *  4 - the first string declared as "ABORT"
119f65f104SPeter Wemm  *  5 - the second string declared as "ABORT"
129f65f104SPeter Wemm  *  6 - ... and so on for successive ABORT strings.
139f65f104SPeter Wemm  *
149b1aec48SLars Fredriksen  *	This software is in the public domain.
159b1aec48SLars Fredriksen  *
163d793cf1SPeter Wemm  * -----------------
179b1aec48SLars Fredriksen  *
183d793cf1SPeter Wemm  *	Added SAY keyword to send output to stderr.
193d793cf1SPeter Wemm  *      This allows to turn ECHO OFF and to output specific, user selected,
203d793cf1SPeter Wemm  *      text to give progress messages. This best works when stderr
213d793cf1SPeter Wemm  *      exists (i.e.: pppd in nodetach mode).
223d793cf1SPeter Wemm  *
233d793cf1SPeter Wemm  * 	Added HANGUP directives to allow for us to be called
243d793cf1SPeter Wemm  *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
253d793cf1SPeter Wemm  *      We rely on timeouts in that case.
263d793cf1SPeter Wemm  *
273d793cf1SPeter Wemm  *      Added CLR_ABORT to clear previously set ABORT string. This has been
283d793cf1SPeter Wemm  *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
293d793cf1SPeter Wemm  *      an ABORT condition until we know the other host is going to close
303d793cf1SPeter Wemm  *      the connection for call back. As soon as we have completed the
313d793cf1SPeter Wemm  *      first stage of the call back sequence, "NO CARRIER" is a valid, non
323d793cf1SPeter Wemm  *      fatal string. As soon as we got called back (probably get "CONNECT"),
333d793cf1SPeter Wemm  *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
343d793cf1SPeter Wemm  *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
353d793cf1SPeter Wemm  *      have unused entries not being reclaimed.
363d793cf1SPeter Wemm  *
373d793cf1SPeter Wemm  *      In the same vein as above, added CLR_REPORT keyword.
383d793cf1SPeter Wemm  *
393d793cf1SPeter Wemm  *      Allow for comments. Line starting with '#' are comments and are
403d793cf1SPeter Wemm  *      ignored. If a '#' is to be expected as the first character, the
413d793cf1SPeter Wemm  *      expect string must be quoted.
423d793cf1SPeter Wemm  *
433d793cf1SPeter Wemm  *
443d793cf1SPeter Wemm  *		Francis Demierre <Francis@SwissMail.Com>
453d793cf1SPeter Wemm  * 		Thu May 15 17:15:40 MET DST 1997
463d793cf1SPeter Wemm  *
479b1aec48SLars Fredriksen  *
489f65f104SPeter Wemm  *      Added -r "report file" switch & REPORT keyword.
499f65f104SPeter Wemm  *              Robert Geer <bgeer@xmission.com>
509f65f104SPeter Wemm  *
513d793cf1SPeter Wemm  *
523d793cf1SPeter Wemm  *	Added -e "echo" switch & ECHO keyword
533d793cf1SPeter Wemm  *		Dick Streefland <dicks@tasking.nl>
543d793cf1SPeter Wemm  *
553d793cf1SPeter Wemm  *
563d793cf1SPeter Wemm  *	Considerable updates and modifications by
573d793cf1SPeter Wemm  *		Al Longyear <longyear@pobox.com>
583d793cf1SPeter Wemm  *		Paul Mackerras <paulus@cs.anu.edu.au>
593d793cf1SPeter Wemm  *
603d793cf1SPeter Wemm  *
619b1aec48SLars Fredriksen  *	The original author is:
629b1aec48SLars Fredriksen  *
639b1aec48SLars Fredriksen  *		Karl Fox <karl@MorningStar.Com>
649b1aec48SLars Fredriksen  *		Morning Star Technologies, Inc.
659b1aec48SLars Fredriksen  *		1760 Zollinger Road
669b1aec48SLars Fredriksen  *		Columbus, OH  43221
679b1aec48SLars Fredriksen  *		(614)451-1883
689f65f104SPeter Wemm  *
693d793cf1SPeter Wemm  *
709b1aec48SLars Fredriksen  */
719b1aec48SLars Fredriksen 
723d793cf1SPeter Wemm #ifndef lint
73d7d10053SAlexander Langer static char rcsid[] = "$Id: chat.c,v 1.9 1997/08/22 15:24:36 peter Exp $";
743d793cf1SPeter Wemm #endif
759b1aec48SLars Fredriksen 
769b1aec48SLars Fredriksen #include <stdio.h>
773d793cf1SPeter Wemm #include <ctype.h>
789f65f104SPeter Wemm #include <time.h>
799b1aec48SLars Fredriksen #include <fcntl.h>
809b1aec48SLars Fredriksen #include <signal.h>
819b1aec48SLars Fredriksen #include <errno.h>
829b1aec48SLars Fredriksen #include <string.h>
839b1aec48SLars Fredriksen #include <stdlib.h>
843d793cf1SPeter Wemm #include <unistd.h>
859b1aec48SLars Fredriksen #include <sys/types.h>
869b1aec48SLars Fredriksen #include <sys/stat.h>
879b1aec48SLars Fredriksen #include <syslog.h>
889b1aec48SLars Fredriksen 
899b1aec48SLars Fredriksen #ifndef TERMIO
909b1aec48SLars Fredriksen #undef	TERMIOS
919b1aec48SLars Fredriksen #define TERMIOS
929b1aec48SLars Fredriksen #endif
939b1aec48SLars Fredriksen 
949b1aec48SLars Fredriksen #ifdef TERMIO
959b1aec48SLars Fredriksen #include <termio.h>
969b1aec48SLars Fredriksen #endif
979b1aec48SLars Fredriksen #ifdef TERMIOS
989b1aec48SLars Fredriksen #include <termios.h>
999b1aec48SLars Fredriksen #endif
1009b1aec48SLars Fredriksen 
1019b1aec48SLars Fredriksen #define	STR_LEN	1024
1029b1aec48SLars Fredriksen 
1039b1aec48SLars Fredriksen #ifndef SIGTYPE
1049b1aec48SLars Fredriksen #define SIGTYPE void
1059b1aec48SLars Fredriksen #endif
1069b1aec48SLars Fredriksen 
1079b1aec48SLars Fredriksen #ifdef __STDC__
1089b1aec48SLars Fredriksen #undef __P
1099b1aec48SLars Fredriksen #define __P(x)	x
1109b1aec48SLars Fredriksen #else
1119b1aec48SLars Fredriksen #define __P(x)	()
1129b1aec48SLars Fredriksen #define const
1139b1aec48SLars Fredriksen #endif
1149b1aec48SLars Fredriksen 
1159f65f104SPeter Wemm #ifndef O_NONBLOCK
1169f65f104SPeter Wemm #define O_NONBLOCK	O_NDELAY
1179f65f104SPeter Wemm #endif
1189f65f104SPeter Wemm 
1199b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/
1209b1aec48SLars Fredriksen #define	OPTION(c,v)	(_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
1219b1aec48SLars Fredriksen 				(--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
1229b1aec48SLars Fredriksen 				&&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
1239b1aec48SLars Fredriksen #define	OPTARG(c,v)	(_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
1249b1aec48SLars Fredriksen 				(_O=4,(char*)0):(char*)0)
1259b1aec48SLars Fredriksen #define	OPTONLYARG(c,v)	(_O&2&&**v?(_O=1,--c,*v++):(char*)0)
1269b1aec48SLars Fredriksen #define	ARG(c,v)	(c?(--c,*v++):(char*)0)
1279b1aec48SLars Fredriksen 
1289b1aec48SLars Fredriksen static int _O = 0;		/* Internal state */
1299b1aec48SLars Fredriksen /*************** Micro getopt() *********************************************/
1309b1aec48SLars Fredriksen 
1319b1aec48SLars Fredriksen #define	MAX_ABORTS		50
1329f65f104SPeter Wemm #define	MAX_REPORTS		50
1339b1aec48SLars Fredriksen #define	DEFAULT_CHAT_TIMEOUT	45
1349b1aec48SLars Fredriksen 
1353d793cf1SPeter Wemm int echo          = 0;
1369b1aec48SLars Fredriksen int verbose       = 0;
1373d793cf1SPeter Wemm int Verbose       = 0;
1389b1aec48SLars Fredriksen int quiet         = 0;
1399f65f104SPeter Wemm int report        = 0;
1409f65f104SPeter Wemm int exit_code     = 0;
1419f65f104SPeter Wemm FILE* report_fp   = (FILE *) 0;
1429f65f104SPeter Wemm char *report_file = (char *) 0;
1439b1aec48SLars Fredriksen char *chat_file   = (char *) 0;
1449b1aec48SLars Fredriksen int timeout       = DEFAULT_CHAT_TIMEOUT;
1459b1aec48SLars Fredriksen 
1469b1aec48SLars Fredriksen int have_tty_parameters = 0;
1479f65f104SPeter Wemm 
1489b1aec48SLars Fredriksen #ifdef TERMIO
1499f65f104SPeter Wemm #define term_parms struct termio
1509f65f104SPeter Wemm #define get_term_param(param) ioctl(0, TCGETA, param)
1519f65f104SPeter Wemm #define set_term_param(param) ioctl(0, TCSETA, param)
1529b1aec48SLars Fredriksen struct termio saved_tty_parameters;
1539b1aec48SLars Fredriksen #endif
1549f65f104SPeter Wemm 
1559b1aec48SLars Fredriksen #ifdef TERMIOS
1569f65f104SPeter Wemm #define term_parms struct termios
1579f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param)
1589f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param)
1599b1aec48SLars Fredriksen struct termios saved_tty_parameters;
1609b1aec48SLars Fredriksen #endif
1619b1aec48SLars Fredriksen 
1629b1aec48SLars Fredriksen char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
1639b1aec48SLars Fredriksen 	fail_buffer[50];
1643d793cf1SPeter Wemm int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
1653d793cf1SPeter Wemm int clear_abort_next = 0;
1669b1aec48SLars Fredriksen 
1679f65f104SPeter Wemm char *report_string[MAX_REPORTS] ;
1689f65f104SPeter Wemm char  report_buffer[50] ;
1699f65f104SPeter Wemm int n_reports = 0, report_next = 0, report_gathering = 0 ;
1703d793cf1SPeter Wemm int clear_report_next = 0;
1713d793cf1SPeter Wemm 
1723d793cf1SPeter Wemm int say_next = 0, hup_next = 0;
1739f65f104SPeter Wemm 
1749b1aec48SLars Fredriksen void *dup_mem __P((void *b, size_t c));
1759b1aec48SLars Fredriksen void *copy_of __P((char *s));
176afaeb553SPhilippe Charnier static void usage __P((void));
1779b1aec48SLars Fredriksen void logf __P((const char *str));
1789b1aec48SLars Fredriksen void logflush __P((void));
1799b1aec48SLars Fredriksen void fatal __P((const char *msg));
1809b1aec48SLars Fredriksen void sysfatal __P((const char *msg));
1819b1aec48SLars Fredriksen SIGTYPE sigalrm __P((int signo));
1829b1aec48SLars Fredriksen SIGTYPE sigint __P((int signo));
1839b1aec48SLars Fredriksen SIGTYPE sigterm __P((int signo));
1849b1aec48SLars Fredriksen SIGTYPE sighup __P((int signo));
1859b1aec48SLars Fredriksen void unalarm __P((void));
1869b1aec48SLars Fredriksen void init __P((void));
1879b1aec48SLars Fredriksen void set_tty_parameters __P((void));
1883d793cf1SPeter Wemm void echo_stderr __P((int));
1899b1aec48SLars Fredriksen void break_sequence __P((void));
1909b1aec48SLars Fredriksen void terminate __P((int status));
1919b1aec48SLars Fredriksen void do_file __P((char *chat_file));
1929b1aec48SLars Fredriksen int  get_string __P((register char *string));
1939b1aec48SLars Fredriksen int  put_string __P((register char *s));
1949b1aec48SLars Fredriksen int  write_char __P((int c));
1959f65f104SPeter Wemm int  put_char __P((int c));
1969b1aec48SLars Fredriksen int  get_char __P((void));
1979b1aec48SLars Fredriksen void chat_send __P((register char *s));
1989f65f104SPeter Wemm char *character __P((int c));
1999b1aec48SLars Fredriksen void chat_expect __P((register char *s));
2009b1aec48SLars Fredriksen char *clean __P((register char *s, int sending));
2019b1aec48SLars Fredriksen void break_sequence __P((void));
2029b1aec48SLars Fredriksen void terminate __P((int status));
2039b1aec48SLars Fredriksen void die __P((void));
2043d793cf1SPeter Wemm void pack_array __P((char **array, int end));
2053d793cf1SPeter Wemm char *expect_strtok __P((char *, char *));
2063d793cf1SPeter Wemm 
2073d793cf1SPeter Wemm int main __P((int, char *[]));
2089b1aec48SLars Fredriksen 
2099b1aec48SLars Fredriksen void *dup_mem(b, c)
2109b1aec48SLars Fredriksen void *b;
2119b1aec48SLars Fredriksen size_t c;
2129b1aec48SLars Fredriksen     {
2139b1aec48SLars Fredriksen     void *ans = malloc (c);
2149b1aec48SLars Fredriksen     if (!ans)
2159f65f104SPeter Wemm         {
2169b1aec48SLars Fredriksen 	fatal ("memory error!\n");
2179f65f104SPeter Wemm         }
2189b1aec48SLars Fredriksen     memcpy (ans, b, c);
2199b1aec48SLars Fredriksen     return ans;
2209b1aec48SLars Fredriksen     }
2219b1aec48SLars Fredriksen 
2229b1aec48SLars Fredriksen void *copy_of (s)
2239b1aec48SLars Fredriksen char *s;
2249b1aec48SLars Fredriksen     {
2259b1aec48SLars Fredriksen     return dup_mem (s, strlen (s) + 1);
2269b1aec48SLars Fredriksen     }
2279b1aec48SLars Fredriksen 
2289b1aec48SLars Fredriksen /*
2299f65f104SPeter Wemm  *	chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \
2309b1aec48SLars Fredriksen  *		[...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
2319b1aec48SLars Fredriksen  *
2329b1aec48SLars Fredriksen  *	Perform a UUCP-dialer-like chat script on stdin and stdout.
2339b1aec48SLars Fredriksen  */
2349b1aec48SLars Fredriksen int
2359b1aec48SLars Fredriksen main(argc, argv)
2369b1aec48SLars Fredriksen int argc;
2379b1aec48SLars Fredriksen char **argv;
2389b1aec48SLars Fredriksen     {
2399b1aec48SLars Fredriksen     int option;
2409b1aec48SLars Fredriksen     char *arg;
2419b1aec48SLars Fredriksen 
2429f65f104SPeter Wemm     tzset();
2439b1aec48SLars Fredriksen 
2443d793cf1SPeter Wemm     while ((option = OPTION(argc, argv)) != 0)
2459f65f104SPeter Wemm         {
2469b1aec48SLars Fredriksen 	switch (option)
2479b1aec48SLars Fredriksen 	    {
2483d793cf1SPeter Wemm 	    case 'e':
2493d793cf1SPeter Wemm 		++echo;
2503d793cf1SPeter Wemm 		break;
2513d793cf1SPeter Wemm 
2529b1aec48SLars Fredriksen 	    case 'v':
2539b1aec48SLars Fredriksen 		++verbose;
2549b1aec48SLars Fredriksen 		break;
2559b1aec48SLars Fredriksen 
2563d793cf1SPeter Wemm 	    case 'V':
2573d793cf1SPeter Wemm 	        ++Verbose;
2583d793cf1SPeter Wemm 		break;
2593d793cf1SPeter Wemm 
2609b1aec48SLars Fredriksen 	    case 'f':
2613d793cf1SPeter Wemm 		if ((arg = OPTARG(argc, argv)) != NULL)
2629f65f104SPeter Wemm 		    {
2639b1aec48SLars Fredriksen 		    chat_file = copy_of(arg);
2649f65f104SPeter Wemm 		    }
2659b1aec48SLars Fredriksen 		else
2669f65f104SPeter Wemm 		    {
2679b1aec48SLars Fredriksen 		    usage();
2689f65f104SPeter Wemm 		    }
2699b1aec48SLars Fredriksen 		break;
2709b1aec48SLars Fredriksen 
2719b1aec48SLars Fredriksen 	    case 't':
2723d793cf1SPeter Wemm 		if ((arg = OPTARG(argc, argv)) != NULL)
2739f65f104SPeter Wemm 		    {
2749b1aec48SLars Fredriksen 		    timeout = atoi(arg);
2759f65f104SPeter Wemm 		    }
2769b1aec48SLars Fredriksen 		else
2779f65f104SPeter Wemm 		    {
2789b1aec48SLars Fredriksen 		    usage();
2799f65f104SPeter Wemm 		    }
2809f65f104SPeter Wemm 		break;
2819b1aec48SLars Fredriksen 
2829f65f104SPeter Wemm 	    case 'r':
2839f65f104SPeter Wemm 		arg = OPTARG (argc, argv);
2849f65f104SPeter Wemm 		if (arg)
2859f65f104SPeter Wemm 		    {
2869f65f104SPeter Wemm 		    if (report_fp != NULL)
2879f65f104SPeter Wemm 		        {
2889f65f104SPeter Wemm 			fclose (report_fp);
2899f65f104SPeter Wemm 		        }
2909f65f104SPeter Wemm 		    report_file = copy_of (arg);
2919f65f104SPeter Wemm 		    report_fp   = fopen (report_file, "a");
2929f65f104SPeter Wemm 		    if (report_fp != NULL)
2939f65f104SPeter Wemm 		        {
2949f65f104SPeter Wemm 			if (verbose)
2959f65f104SPeter Wemm 			    {
2969f65f104SPeter Wemm 			    fprintf (report_fp, "Opening \"%s\"...\n",
2979f65f104SPeter Wemm 				     report_file);
2989f65f104SPeter Wemm 			    }
2999f65f104SPeter Wemm 			report = 1;
3009f65f104SPeter Wemm 		        }
3019f65f104SPeter Wemm 		    }
3029b1aec48SLars Fredriksen 		break;
3039b1aec48SLars Fredriksen 
3049b1aec48SLars Fredriksen 	    default:
3059b1aec48SLars Fredriksen 		usage();
3069f65f104SPeter Wemm 		break;
3079f65f104SPeter Wemm 	    }
3089f65f104SPeter Wemm       }
3099f65f104SPeter Wemm /*
3109f65f104SPeter Wemm  * Default the report file to the stderr location
3119f65f104SPeter Wemm  */
3129f65f104SPeter Wemm     if (report_fp == NULL)
3139f65f104SPeter Wemm         {
3149f65f104SPeter Wemm 	report_fp = stderr;
3159b1aec48SLars Fredriksen         }
3169b1aec48SLars Fredriksen 
3179b1aec48SLars Fredriksen #ifdef ultrix
3189b1aec48SLars Fredriksen     openlog("chat", LOG_PID);
3199b1aec48SLars Fredriksen #else
3209b1aec48SLars Fredriksen     openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
3219b1aec48SLars Fredriksen 
3229f65f104SPeter Wemm     if (verbose)
3239f65f104SPeter Wemm         {
3249b1aec48SLars Fredriksen 	setlogmask(LOG_UPTO(LOG_INFO));
3259f65f104SPeter Wemm         }
3269f65f104SPeter Wemm     else
3279f65f104SPeter Wemm         {
3289b1aec48SLars Fredriksen 	setlogmask(LOG_UPTO(LOG_WARNING));
3299b1aec48SLars Fredriksen         }
3309b1aec48SLars Fredriksen #endif
3319b1aec48SLars Fredriksen 
3329b1aec48SLars Fredriksen     init();
3339b1aec48SLars Fredriksen 
3349b1aec48SLars Fredriksen     if (chat_file != NULL)
3359b1aec48SLars Fredriksen 	{
3369b1aec48SLars Fredriksen 	arg = ARG(argc, argv);
3379b1aec48SLars Fredriksen 	if (arg != NULL)
3389f65f104SPeter Wemm 	    {
3399b1aec48SLars Fredriksen 	    usage();
3409f65f104SPeter Wemm 	    }
3419b1aec48SLars Fredriksen 	else
3429f65f104SPeter Wemm 	    {
3439b1aec48SLars Fredriksen 	    do_file (chat_file);
3449b1aec48SLars Fredriksen 	    }
3459f65f104SPeter Wemm 	}
3469b1aec48SLars Fredriksen     else
3479b1aec48SLars Fredriksen 	{
3483d793cf1SPeter Wemm 	while ((arg = ARG(argc, argv)) != NULL)
3499b1aec48SLars Fredriksen 	    {
3509b1aec48SLars Fredriksen 	    chat_expect(arg);
3519b1aec48SLars Fredriksen 
3523d793cf1SPeter Wemm 	    if ((arg = ARG(argc, argv)) != NULL)
3539f65f104SPeter Wemm 	        {
3549b1aec48SLars Fredriksen 		chat_send(arg);
3559b1aec48SLars Fredriksen 	        }
3569b1aec48SLars Fredriksen 	    }
3579f65f104SPeter Wemm 	}
3589b1aec48SLars Fredriksen 
3599b1aec48SLars Fredriksen     terminate(0);
3603d793cf1SPeter Wemm     return 0;
3619b1aec48SLars Fredriksen     }
3629b1aec48SLars Fredriksen 
3639b1aec48SLars Fredriksen /*
3649b1aec48SLars Fredriksen  *  Process a chat script when read from a file.
3659b1aec48SLars Fredriksen  */
3669b1aec48SLars Fredriksen 
3679b1aec48SLars Fredriksen void do_file (chat_file)
3689b1aec48SLars Fredriksen char *chat_file;
3699b1aec48SLars Fredriksen     {
370d7d10053SAlexander Langer     int linect, sendflg;
3719b1aec48SLars Fredriksen     char *sp, *arg, quote;
3729b1aec48SLars Fredriksen     char buf [STR_LEN];
3739b1aec48SLars Fredriksen     FILE *cfp;
3749b1aec48SLars Fredriksen 
3759f65f104SPeter Wemm     cfp = fopen (chat_file, "r");
3769f65f104SPeter Wemm     if (cfp == NULL)
3779b1aec48SLars Fredriksen 	{
3789b1aec48SLars Fredriksen 	syslog (LOG_ERR, "%s -- open failed: %m", chat_file);
3799b1aec48SLars Fredriksen 	terminate (1);
3809b1aec48SLars Fredriksen 	}
3819b1aec48SLars Fredriksen 
3829b1aec48SLars Fredriksen     linect = 0;
3839b1aec48SLars Fredriksen     sendflg = 0;
3849b1aec48SLars Fredriksen 
3859b1aec48SLars Fredriksen     while (fgets(buf, STR_LEN, cfp) != NULL)
3869b1aec48SLars Fredriksen 	{
3879b1aec48SLars Fredriksen 	sp = strchr (buf, '\n');
3889b1aec48SLars Fredriksen 	if (sp)
3899f65f104SPeter Wemm 	    {
3909b1aec48SLars Fredriksen 	    *sp = '\0';
3919f65f104SPeter Wemm 	    }
3929b1aec48SLars Fredriksen 
3939b1aec48SLars Fredriksen 	linect++;
3949b1aec48SLars Fredriksen 	sp = buf;
3953d793cf1SPeter Wemm 
3963d793cf1SPeter Wemm         /* lines starting with '#' are comments. If a real '#'
3973d793cf1SPeter Wemm            is to be expected, it should be quoted .... */
3983d793cf1SPeter Wemm         if ( *sp == '#' ) continue;
3993d793cf1SPeter Wemm 
4009b1aec48SLars Fredriksen 	while (*sp != '\0')
4019b1aec48SLars Fredriksen 	    {
4029b1aec48SLars Fredriksen 	    if (*sp == ' ' || *sp == '\t')
4039b1aec48SLars Fredriksen 		{
4049b1aec48SLars Fredriksen 		++sp;
4059b1aec48SLars Fredriksen 		continue;
4069b1aec48SLars Fredriksen 		}
4079b1aec48SLars Fredriksen 
4089b1aec48SLars Fredriksen 	    if (*sp == '"' || *sp == '\'')
4099b1aec48SLars Fredriksen 		{
4109b1aec48SLars Fredriksen 		quote = *sp++;
4119b1aec48SLars Fredriksen 		arg = sp;
4129b1aec48SLars Fredriksen 		while (*sp != quote)
4139b1aec48SLars Fredriksen 		    {
4149b1aec48SLars Fredriksen 		    if (*sp == '\0')
4159b1aec48SLars Fredriksen 			{
4169b1aec48SLars Fredriksen 			syslog (LOG_ERR, "unterminated quote (line %d)",
4179b1aec48SLars Fredriksen 				linect);
4189b1aec48SLars Fredriksen 			terminate (1);
4199b1aec48SLars Fredriksen 			}
4209b1aec48SLars Fredriksen 
4219b1aec48SLars Fredriksen 		    if (*sp++ == '\\')
4229f65f104SPeter Wemm 		        {
4239b1aec48SLars Fredriksen 			if (*sp != '\0')
4249f65f104SPeter Wemm 			    {
4259b1aec48SLars Fredriksen 			    ++sp;
4269b1aec48SLars Fredriksen 			    }
4279b1aec48SLars Fredriksen 		        }
4289f65f104SPeter Wemm 		    }
4299f65f104SPeter Wemm 		}
4309b1aec48SLars Fredriksen 	    else
4319b1aec48SLars Fredriksen 		{
4329b1aec48SLars Fredriksen 		arg = sp;
4339b1aec48SLars Fredriksen 		while (*sp != '\0' && *sp != ' ' && *sp != '\t')
4349f65f104SPeter Wemm 		    {
4359b1aec48SLars Fredriksen 		    ++sp;
4369b1aec48SLars Fredriksen 		    }
4379f65f104SPeter Wemm 		}
4389b1aec48SLars Fredriksen 
4399b1aec48SLars Fredriksen 	    if (*sp != '\0')
4409f65f104SPeter Wemm 	        {
4419b1aec48SLars Fredriksen 		*sp++ = '\0';
4429f65f104SPeter Wemm 	        }
4439b1aec48SLars Fredriksen 
4449b1aec48SLars Fredriksen 	    if (sendflg)
4459b1aec48SLars Fredriksen 		{
4469b1aec48SLars Fredriksen 		chat_send (arg);
4479b1aec48SLars Fredriksen 		}
4489b1aec48SLars Fredriksen 	    else
4499b1aec48SLars Fredriksen 		{
4509b1aec48SLars Fredriksen 		chat_expect (arg);
4519b1aec48SLars Fredriksen 		}
4529b1aec48SLars Fredriksen 	    sendflg = !sendflg;
4539b1aec48SLars Fredriksen 	    }
4549b1aec48SLars Fredriksen 	}
4559b1aec48SLars Fredriksen     fclose (cfp);
4569b1aec48SLars Fredriksen     }
4579b1aec48SLars Fredriksen 
4589b1aec48SLars Fredriksen /*
4599b1aec48SLars Fredriksen  *	We got an error parsing the command line.
4609b1aec48SLars Fredriksen  */
461afaeb553SPhilippe Charnier static void
462afaeb553SPhilippe Charnier usage()
4639b1aec48SLars Fredriksen     {
464afaeb553SPhilippe Charnier     fprintf(stderr, "%s %s\n",
4653d793cf1SPeter Wemm 		"usage: chat [-e] [-v] [-V] [-t timeout] [-r report-file]",
466afaeb553SPhilippe Charnier 		"{-f chat-file | chat-script}");
4679b1aec48SLars Fredriksen     exit(1);
4689b1aec48SLars Fredriksen     }
4699b1aec48SLars Fredriksen 
4709b1aec48SLars Fredriksen char line[256];
4719b1aec48SLars Fredriksen char *p;
4729b1aec48SLars Fredriksen 
4739b1aec48SLars Fredriksen void logf (str)
4749b1aec48SLars Fredriksen const char *str;
4759b1aec48SLars Fredriksen {
4763d793cf1SPeter Wemm     int l = strlen(line);
4779b1aec48SLars Fredriksen 
4783d793cf1SPeter Wemm     if (l + strlen(str) >= sizeof(line)) {
4793d793cf1SPeter Wemm 	syslog(LOG_INFO, "%s", line);
4803d793cf1SPeter Wemm 	l = 0;
4813d793cf1SPeter Wemm     }
4823d793cf1SPeter Wemm     strcpy(line + l, str);
4833d793cf1SPeter Wemm 
4843d793cf1SPeter Wemm     if (str[strlen(str)-1] == '\n') {
4859b1aec48SLars Fredriksen 	syslog (LOG_INFO, "%s", line);
4869b1aec48SLars Fredriksen 	line[0] = 0;
4879b1aec48SLars Fredriksen     }
4889b1aec48SLars Fredriksen }
4899b1aec48SLars Fredriksen 
4909b1aec48SLars Fredriksen void logflush()
4919b1aec48SLars Fredriksen     {
4929b1aec48SLars Fredriksen     if (line[0] != 0)
4939b1aec48SLars Fredriksen 	{
4949b1aec48SLars Fredriksen 	syslog(LOG_INFO, "%s", line);
4959b1aec48SLars Fredriksen 	line[0] = 0;
4969b1aec48SLars Fredriksen         }
4979b1aec48SLars Fredriksen     }
4989b1aec48SLars Fredriksen 
4999b1aec48SLars Fredriksen /*
5009f65f104SPeter Wemm  *	Terminate with an error.
5019b1aec48SLars Fredriksen  */
5029b1aec48SLars Fredriksen void die()
5039b1aec48SLars Fredriksen     {
5049b1aec48SLars Fredriksen     terminate(1);
5059b1aec48SLars Fredriksen     }
5069b1aec48SLars Fredriksen 
5079b1aec48SLars Fredriksen /*
5089b1aec48SLars Fredriksen  *	Print an error message and terminate.
5099b1aec48SLars Fredriksen  */
5109b1aec48SLars Fredriksen 
5119b1aec48SLars Fredriksen void fatal (msg)
5129b1aec48SLars Fredriksen const char *msg;
5139b1aec48SLars Fredriksen     {
5149b1aec48SLars Fredriksen     syslog(LOG_ERR, "%s", msg);
5159f65f104SPeter Wemm     terminate(2);
5169b1aec48SLars Fredriksen     }
5179b1aec48SLars Fredriksen 
5189b1aec48SLars Fredriksen /*
5199b1aec48SLars Fredriksen  *	Print an error message along with the system error message and
5209b1aec48SLars Fredriksen  *	terminate.
5219b1aec48SLars Fredriksen  */
5229b1aec48SLars Fredriksen 
5239b1aec48SLars Fredriksen void sysfatal (msg)
5249b1aec48SLars Fredriksen const char *msg;
5259b1aec48SLars Fredriksen     {
5269b1aec48SLars Fredriksen     syslog(LOG_ERR, "%s: %m", msg);
5279f65f104SPeter Wemm     terminate(2);
5289b1aec48SLars Fredriksen     }
5299b1aec48SLars Fredriksen 
5309b1aec48SLars Fredriksen int alarmed = 0;
5319b1aec48SLars Fredriksen 
5329b1aec48SLars Fredriksen SIGTYPE sigalrm(signo)
5339b1aec48SLars Fredriksen int signo;
5349b1aec48SLars Fredriksen     {
5359b1aec48SLars Fredriksen     int flags;
5369b1aec48SLars Fredriksen 
5379b1aec48SLars Fredriksen     alarm(1);
5389b1aec48SLars Fredriksen     alarmed = 1;		/* Reset alarm to avoid race window */
5399b1aec48SLars Fredriksen     signal(SIGALRM, sigalrm);	/* that can cause hanging in read() */
5409b1aec48SLars Fredriksen 
5419b1aec48SLars Fredriksen     logflush();
5429b1aec48SLars Fredriksen     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
5439f65f104SPeter Wemm         {
5449b1aec48SLars Fredriksen 	sysfatal("Can't get file mode flags on stdin");
5459f65f104SPeter Wemm         }
5469b1aec48SLars Fredriksen     else
5479f65f104SPeter Wemm         {
5489f65f104SPeter Wemm 	if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
5499f65f104SPeter Wemm 	    {
5509b1aec48SLars Fredriksen 	    sysfatal("Can't set file mode flags on stdin");
5519f65f104SPeter Wemm 	    }
5529f65f104SPeter Wemm         }
5539b1aec48SLars Fredriksen 
5549b1aec48SLars Fredriksen     if (verbose)
5559b1aec48SLars Fredriksen 	{
5569b1aec48SLars Fredriksen 	syslog(LOG_INFO, "alarm");
5579b1aec48SLars Fredriksen 	}
5589b1aec48SLars Fredriksen     }
5599b1aec48SLars Fredriksen 
5609b1aec48SLars Fredriksen void unalarm()
5619b1aec48SLars Fredriksen     {
5629b1aec48SLars Fredriksen     int flags;
5639b1aec48SLars Fredriksen 
5649b1aec48SLars Fredriksen     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
5659f65f104SPeter Wemm         {
5669b1aec48SLars Fredriksen 	sysfatal("Can't get file mode flags on stdin");
5679f65f104SPeter Wemm         }
5689b1aec48SLars Fredriksen     else
5699f65f104SPeter Wemm         {
5709f65f104SPeter Wemm 	if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
5719f65f104SPeter Wemm 	    {
5729b1aec48SLars Fredriksen 	    sysfatal("Can't set file mode flags on stdin");
5739b1aec48SLars Fredriksen 	    }
5749f65f104SPeter Wemm         }
5759f65f104SPeter Wemm     }
5769b1aec48SLars Fredriksen 
5779b1aec48SLars Fredriksen SIGTYPE sigint(signo)
5789b1aec48SLars Fredriksen int signo;
5799b1aec48SLars Fredriksen     {
5809b1aec48SLars Fredriksen     fatal("SIGINT");
5819b1aec48SLars Fredriksen     }
5829b1aec48SLars Fredriksen 
5839b1aec48SLars Fredriksen SIGTYPE sigterm(signo)
5849b1aec48SLars Fredriksen int signo;
5859b1aec48SLars Fredriksen     {
5869b1aec48SLars Fredriksen     fatal("SIGTERM");
5879b1aec48SLars Fredriksen     }
5889b1aec48SLars Fredriksen 
5899b1aec48SLars Fredriksen SIGTYPE sighup(signo)
5909b1aec48SLars Fredriksen int signo;
5919b1aec48SLars Fredriksen     {
5929b1aec48SLars Fredriksen     fatal("SIGHUP");
5939b1aec48SLars Fredriksen     }
5949b1aec48SLars Fredriksen 
5959b1aec48SLars Fredriksen void init()
5969b1aec48SLars Fredriksen     {
5979b1aec48SLars Fredriksen     signal(SIGINT, sigint);
5989b1aec48SLars Fredriksen     signal(SIGTERM, sigterm);
5999b1aec48SLars Fredriksen     signal(SIGHUP, sighup);
6009b1aec48SLars Fredriksen 
6019b1aec48SLars Fredriksen     set_tty_parameters();
6029b1aec48SLars Fredriksen     signal(SIGALRM, sigalrm);
6039b1aec48SLars Fredriksen     alarm(0);
6049b1aec48SLars Fredriksen     alarmed = 0;
6059b1aec48SLars Fredriksen     }
6069b1aec48SLars Fredriksen 
6079b1aec48SLars Fredriksen void set_tty_parameters()
6089b1aec48SLars Fredriksen     {
6099f65f104SPeter Wemm #if defined(get_term_param)
6109f65f104SPeter Wemm     term_parms t;
6119b1aec48SLars Fredriksen 
6129f65f104SPeter Wemm     if (get_term_param (&t) < 0)
6139f65f104SPeter Wemm         {
61439746e46SJohn-Mark Gurney 	have_tty_parameters = 0;
61539746e46SJohn-Mark Gurney 	return;
6169f65f104SPeter Wemm         }
6179b1aec48SLars Fredriksen 
6189b1aec48SLars Fredriksen     saved_tty_parameters = t;
6199b1aec48SLars Fredriksen     have_tty_parameters  = 1;
6209b1aec48SLars Fredriksen 
6219b1aec48SLars Fredriksen     t.c_iflag     |= IGNBRK | ISTRIP | IGNPAR;
6229b1aec48SLars Fredriksen     t.c_oflag      = 0;
6239b1aec48SLars Fredriksen     t.c_lflag      = 0;
6249f65f104SPeter Wemm     t.c_cc[VERASE] =
6259f65f104SPeter Wemm     t.c_cc[VKILL]  = 0;
6269b1aec48SLars Fredriksen     t.c_cc[VMIN]   = 1;
6279b1aec48SLars Fredriksen     t.c_cc[VTIME]  = 0;
6289b1aec48SLars Fredriksen 
6299f65f104SPeter Wemm     if (set_term_param (&t) < 0)
6309f65f104SPeter Wemm         {
6319b1aec48SLars Fredriksen 	sysfatal("Can't set terminal parameters");
6329f65f104SPeter Wemm         }
6339b1aec48SLars Fredriksen #endif
6349b1aec48SLars Fredriksen     }
6359b1aec48SLars Fredriksen 
6369b1aec48SLars Fredriksen void break_sequence()
6379b1aec48SLars Fredriksen     {
6389b1aec48SLars Fredriksen #ifdef TERMIOS
6399b1aec48SLars Fredriksen     tcsendbreak (0, 0);
6409b1aec48SLars Fredriksen #endif
6419b1aec48SLars Fredriksen     }
6429b1aec48SLars Fredriksen 
6439b1aec48SLars Fredriksen void terminate(status)
6449b1aec48SLars Fredriksen int status;
6459b1aec48SLars Fredriksen     {
6463d793cf1SPeter Wemm     echo_stderr(-1);
6479f65f104SPeter Wemm     if (report_file != (char *) 0 && report_fp != (FILE *) NULL)
6489f65f104SPeter Wemm 	{
6493d793cf1SPeter Wemm /*
6503d793cf1SPeter Wemm  * Allow the last of the report string to be gathered before we terminate.
6513d793cf1SPeter Wemm  */
6523d793cf1SPeter Wemm 	if (report_gathering) {
6533d793cf1SPeter Wemm 	    int c, rep_len;
6543d793cf1SPeter Wemm 
6553d793cf1SPeter Wemm 	    rep_len = strlen(report_buffer);
6563d793cf1SPeter Wemm 	    while (rep_len + 1 <= sizeof(report_buffer)) {
6573d793cf1SPeter Wemm 		alarm(1);
6583d793cf1SPeter Wemm 		c = get_char();
6593d793cf1SPeter Wemm 		alarm(0);
6603d793cf1SPeter Wemm 		if (c < 0 || iscntrl(c))
6613d793cf1SPeter Wemm 		    break;
6623d793cf1SPeter Wemm 		report_buffer[rep_len] = c;
6633d793cf1SPeter Wemm 		++rep_len;
6643d793cf1SPeter Wemm 	    }
6653d793cf1SPeter Wemm 	    report_buffer[rep_len] = 0;
6663d793cf1SPeter Wemm 	    fprintf (report_fp, "chat:  %s\n", report_buffer);
6673d793cf1SPeter Wemm 	}
6689f65f104SPeter Wemm 	if (verbose)
6699f65f104SPeter Wemm 	    {
6709f65f104SPeter Wemm 	    fprintf (report_fp, "Closing \"%s\".\n", report_file);
6719f65f104SPeter Wemm 	    }
6729f65f104SPeter Wemm 	fclose (report_fp);
6739f65f104SPeter Wemm 	report_fp = (FILE *) NULL;
6749f65f104SPeter Wemm         }
6759f65f104SPeter Wemm 
6769f65f104SPeter Wemm #if defined(get_term_param)
6779f65f104SPeter Wemm     if (have_tty_parameters)
6789f65f104SPeter Wemm         {
6799f65f104SPeter Wemm 	if (set_term_param (&saved_tty_parameters) < 0)
6809f65f104SPeter Wemm 	    {
6819b1aec48SLars Fredriksen 	    syslog(LOG_ERR, "Can't restore terminal parameters: %m");
6829b1aec48SLars Fredriksen 	    exit(1);
6839b1aec48SLars Fredriksen 	    }
6849f65f104SPeter Wemm         }
6859f65f104SPeter Wemm #endif
6869f65f104SPeter Wemm 
6879b1aec48SLars Fredriksen     exit(status);
6889b1aec48SLars Fredriksen     }
6899b1aec48SLars Fredriksen 
6909b1aec48SLars Fredriksen /*
6919b1aec48SLars Fredriksen  *	'Clean up' this string.
6929b1aec48SLars Fredriksen  */
6939b1aec48SLars Fredriksen char *clean(s, sending)
6949b1aec48SLars Fredriksen register char *s;
6959b1aec48SLars Fredriksen int sending;
6969b1aec48SLars Fredriksen     {
6979b1aec48SLars Fredriksen     char temp[STR_LEN], cur_chr;
6989b1aec48SLars Fredriksen     register char *s1;
6999b1aec48SLars Fredriksen     int add_return = sending;
7009b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
7019b1aec48SLars Fredriksen 
7029b1aec48SLars Fredriksen     s1 = temp;
7039b1aec48SLars Fredriksen     while (*s)
7049b1aec48SLars Fredriksen 	{
7059b1aec48SLars Fredriksen 	cur_chr = *s++;
7069b1aec48SLars Fredriksen 	if (cur_chr == '^')
7079b1aec48SLars Fredriksen 	    {
7089b1aec48SLars Fredriksen 	    cur_chr = *s++;
7099b1aec48SLars Fredriksen 	    if (cur_chr == '\0')
7109b1aec48SLars Fredriksen 		{
7119b1aec48SLars Fredriksen 		*s1++ = '^';
7129b1aec48SLars Fredriksen 		break;
7139b1aec48SLars Fredriksen 		}
7149b1aec48SLars Fredriksen 	    cur_chr &= 0x1F;
7159b1aec48SLars Fredriksen 	    if (cur_chr != 0)
7169f65f104SPeter Wemm 	        {
7179b1aec48SLars Fredriksen 		*s1++ = cur_chr;
7189f65f104SPeter Wemm 	        }
7199b1aec48SLars Fredriksen 	    continue;
7209b1aec48SLars Fredriksen 	    }
7219b1aec48SLars Fredriksen 
7229b1aec48SLars Fredriksen 	if (cur_chr != '\\')
7239b1aec48SLars Fredriksen 	    {
7249b1aec48SLars Fredriksen 	    *s1++ = cur_chr;
7259b1aec48SLars Fredriksen 	    continue;
7269b1aec48SLars Fredriksen 	    }
7279b1aec48SLars Fredriksen 
7289b1aec48SLars Fredriksen 	cur_chr = *s++;
7299b1aec48SLars Fredriksen 	if (cur_chr == '\0')
7309b1aec48SLars Fredriksen 	    {
7319b1aec48SLars Fredriksen 	    if (sending)
7329b1aec48SLars Fredriksen 		{
7339b1aec48SLars Fredriksen 		*s1++ = '\\';
7349b1aec48SLars Fredriksen 		*s1++ = '\\';
7359b1aec48SLars Fredriksen 		}
7369b1aec48SLars Fredriksen 	    break;
7379b1aec48SLars Fredriksen 	    }
7389b1aec48SLars Fredriksen 
7399b1aec48SLars Fredriksen 	switch (cur_chr)
7409b1aec48SLars Fredriksen 	    {
7419b1aec48SLars Fredriksen 	case 'b':
7429b1aec48SLars Fredriksen 	    *s1++ = '\b';
7439b1aec48SLars Fredriksen 	    break;
7449b1aec48SLars Fredriksen 
7459b1aec48SLars Fredriksen 	case 'c':
7469b1aec48SLars Fredriksen 	    if (sending && *s == '\0')
7479f65f104SPeter Wemm 	        {
7489b1aec48SLars Fredriksen 		add_return = 0;
7499f65f104SPeter Wemm 	        }
7509b1aec48SLars Fredriksen 	    else
7519f65f104SPeter Wemm 	        {
7529b1aec48SLars Fredriksen 		*s1++ = cur_chr;
7539f65f104SPeter Wemm 	        }
7549b1aec48SLars Fredriksen 	    break;
7559b1aec48SLars Fredriksen 
7569b1aec48SLars Fredriksen 	case '\\':
7579b1aec48SLars Fredriksen 	case 'K':
7589b1aec48SLars Fredriksen 	case 'p':
7599b1aec48SLars Fredriksen 	case 'd':
7609b1aec48SLars Fredriksen 	    if (sending)
7619f65f104SPeter Wemm 	        {
7629b1aec48SLars Fredriksen 		*s1++ = '\\';
7639f65f104SPeter Wemm 	        }
7649b1aec48SLars Fredriksen 
7659b1aec48SLars Fredriksen 	    *s1++ = cur_chr;
7669b1aec48SLars Fredriksen 	    break;
7679b1aec48SLars Fredriksen 
7689b1aec48SLars Fredriksen 	case 'q':
7693d793cf1SPeter Wemm 	    quiet = 1;
7709b1aec48SLars Fredriksen 	    break;
7719b1aec48SLars Fredriksen 
7729b1aec48SLars Fredriksen 	case 'r':
7739b1aec48SLars Fredriksen 	    *s1++ = '\r';
7749b1aec48SLars Fredriksen 	    break;
7759b1aec48SLars Fredriksen 
7769b1aec48SLars Fredriksen 	case 'n':
7779b1aec48SLars Fredriksen 	    *s1++ = '\n';
7789b1aec48SLars Fredriksen 	    break;
7799b1aec48SLars Fredriksen 
7809b1aec48SLars Fredriksen 	case 's':
7819b1aec48SLars Fredriksen 	    *s1++ = ' ';
7829b1aec48SLars Fredriksen 	    break;
7839b1aec48SLars Fredriksen 
7849b1aec48SLars Fredriksen 	case 't':
7859b1aec48SLars Fredriksen 	    *s1++ = '\t';
7869b1aec48SLars Fredriksen 	    break;
7879b1aec48SLars Fredriksen 
7889b1aec48SLars Fredriksen 	case 'N':
7899b1aec48SLars Fredriksen 	    if (sending)
7909b1aec48SLars Fredriksen 		{
7919b1aec48SLars Fredriksen 		*s1++ = '\\';
7929b1aec48SLars Fredriksen 		*s1++ = '\0';
7939b1aec48SLars Fredriksen 		}
7949b1aec48SLars Fredriksen 	    else
7959f65f104SPeter Wemm 	        {
7969b1aec48SLars Fredriksen 		*s1++ = 'N';
7979f65f104SPeter Wemm 	        }
7989b1aec48SLars Fredriksen 	    break;
7999b1aec48SLars Fredriksen 
8009b1aec48SLars Fredriksen 	default:
8019b1aec48SLars Fredriksen 	    if (isoctal (cur_chr))
8029b1aec48SLars Fredriksen 		{
8039b1aec48SLars Fredriksen 		cur_chr &= 0x07;
8049b1aec48SLars Fredriksen 		if (isoctal (*s))
8059b1aec48SLars Fredriksen 		    {
8069b1aec48SLars Fredriksen 		    cur_chr <<= 3;
8079b1aec48SLars Fredriksen 		    cur_chr |= *s++ - '0';
8089b1aec48SLars Fredriksen 		    if (isoctal (*s))
8099b1aec48SLars Fredriksen 			{
8109b1aec48SLars Fredriksen 			cur_chr <<= 3;
8119b1aec48SLars Fredriksen 			cur_chr |= *s++ - '0';
8129b1aec48SLars Fredriksen 			}
8139b1aec48SLars Fredriksen 		    }
8149b1aec48SLars Fredriksen 
8159b1aec48SLars Fredriksen 		if (cur_chr != 0 || sending)
8169b1aec48SLars Fredriksen 		    {
8179b1aec48SLars Fredriksen 		    if (sending && (cur_chr == '\\' || cur_chr == 0))
8189f65f104SPeter Wemm 		        {
8199b1aec48SLars Fredriksen 			*s1++ = '\\';
8209f65f104SPeter Wemm 		        }
8219b1aec48SLars Fredriksen 		    *s1++ = cur_chr;
8229b1aec48SLars Fredriksen 		    }
8239b1aec48SLars Fredriksen 		break;
8249b1aec48SLars Fredriksen 		}
8259b1aec48SLars Fredriksen 
8269b1aec48SLars Fredriksen 	    if (sending)
8279f65f104SPeter Wemm 	        {
8289b1aec48SLars Fredriksen 		*s1++ = '\\';
8299f65f104SPeter Wemm 	        }
8309b1aec48SLars Fredriksen 	    *s1++ = cur_chr;
8319b1aec48SLars Fredriksen 	    break;
8329b1aec48SLars Fredriksen 	    }
8339b1aec48SLars Fredriksen 	}
8349b1aec48SLars Fredriksen 
8359b1aec48SLars Fredriksen     if (add_return)
8369f65f104SPeter Wemm         {
8379b1aec48SLars Fredriksen 	*s1++ = '\r';
8389f65f104SPeter Wemm         }
8399b1aec48SLars Fredriksen 
8409b1aec48SLars Fredriksen     *s1++ = '\0'; /* guarantee closure */
8419b1aec48SLars Fredriksen     *s1++ = '\0'; /* terminate the string */
8429b1aec48SLars Fredriksen     return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
8439b1aec48SLars Fredriksen     }
8449b1aec48SLars Fredriksen 
8459b1aec48SLars Fredriksen /*
8463d793cf1SPeter Wemm  * A modified version of 'strtok'. This version skips \ sequences.
8473d793cf1SPeter Wemm  */
8483d793cf1SPeter Wemm 
8493d793cf1SPeter Wemm char *expect_strtok (s, term)
8503d793cf1SPeter Wemm char *s, *term;
8513d793cf1SPeter Wemm     {
8523d793cf1SPeter Wemm     static  char *str   = "";
8533d793cf1SPeter Wemm     int	    escape_flag = 0;
8543d793cf1SPeter Wemm     char   *result;
8553d793cf1SPeter Wemm /*
8563d793cf1SPeter Wemm  * If a string was specified then do initial processing.
8573d793cf1SPeter Wemm  */
8583d793cf1SPeter Wemm     if (s)
8593d793cf1SPeter Wemm 	{
8603d793cf1SPeter Wemm 	str = s;
8613d793cf1SPeter Wemm 	}
8623d793cf1SPeter Wemm /*
8633d793cf1SPeter Wemm  * If this is the escape flag then reset it and ignore the character.
8643d793cf1SPeter Wemm  */
8653d793cf1SPeter Wemm     if (*str)
8663d793cf1SPeter Wemm         {
8673d793cf1SPeter Wemm 	result = str;
8683d793cf1SPeter Wemm         }
8693d793cf1SPeter Wemm     else
8703d793cf1SPeter Wemm         {
8713d793cf1SPeter Wemm 	result = (char *) 0;
8723d793cf1SPeter Wemm         }
8733d793cf1SPeter Wemm 
8743d793cf1SPeter Wemm     while (*str)
8753d793cf1SPeter Wemm 	{
8763d793cf1SPeter Wemm 	if (escape_flag)
8773d793cf1SPeter Wemm 	    {
8783d793cf1SPeter Wemm 	    escape_flag = 0;
8793d793cf1SPeter Wemm 	    ++str;
8803d793cf1SPeter Wemm 	    continue;
8813d793cf1SPeter Wemm 	    }
8823d793cf1SPeter Wemm 
8833d793cf1SPeter Wemm 	if (*str == '\\')
8843d793cf1SPeter Wemm 	    {
8853d793cf1SPeter Wemm 	    ++str;
8863d793cf1SPeter Wemm 	    escape_flag = 1;
8873d793cf1SPeter Wemm 	    continue;
8883d793cf1SPeter Wemm 	    }
8893d793cf1SPeter Wemm /*
8903d793cf1SPeter Wemm  * If this is not in the termination string, continue.
8913d793cf1SPeter Wemm  */
8923d793cf1SPeter Wemm 	if (strchr (term, *str) == (char *) 0)
8933d793cf1SPeter Wemm 	    {
8943d793cf1SPeter Wemm 	    ++str;
8953d793cf1SPeter Wemm 	    continue;
8963d793cf1SPeter Wemm 	    }
8973d793cf1SPeter Wemm /*
8983d793cf1SPeter Wemm  * This is the terminator. Mark the end of the string and stop.
8993d793cf1SPeter Wemm  */
9003d793cf1SPeter Wemm 	*str++ = '\0';
9013d793cf1SPeter Wemm 	break;
9023d793cf1SPeter Wemm 	}
9033d793cf1SPeter Wemm     return (result);
9043d793cf1SPeter Wemm     }
9053d793cf1SPeter Wemm 
9063d793cf1SPeter Wemm /*
9079b1aec48SLars Fredriksen  * Process the expect string
9089b1aec48SLars Fredriksen  */
9093d793cf1SPeter Wemm 
9109b1aec48SLars Fredriksen void chat_expect (s)
9113d793cf1SPeter Wemm char *s;
9129b1aec48SLars Fredriksen     {
9133d793cf1SPeter Wemm     char *expect;
9143d793cf1SPeter Wemm     char *reply;
9153d793cf1SPeter Wemm 
9163d793cf1SPeter Wemm     if (strcmp(s, "HANGUP") == 0)
9173d793cf1SPeter Wemm         {
9183d793cf1SPeter Wemm 	++hup_next;
9193d793cf1SPeter Wemm         return;
9203d793cf1SPeter Wemm         }
9213d793cf1SPeter Wemm 
9229b1aec48SLars Fredriksen     if (strcmp(s, "ABORT") == 0)
9239b1aec48SLars Fredriksen 	{
9249b1aec48SLars Fredriksen 	++abort_next;
9259b1aec48SLars Fredriksen 	return;
9269b1aec48SLars Fredriksen 	}
9279b1aec48SLars Fredriksen 
9283d793cf1SPeter Wemm     if (strcmp(s, "CLR_ABORT") == 0)
9293d793cf1SPeter Wemm 	{
9303d793cf1SPeter Wemm 	++clear_abort_next;
9313d793cf1SPeter Wemm 	return;
9323d793cf1SPeter Wemm 	}
9333d793cf1SPeter Wemm 
9349f65f104SPeter Wemm     if (strcmp(s, "REPORT") == 0)
9359f65f104SPeter Wemm 	{
9369f65f104SPeter Wemm 	++report_next;
9379f65f104SPeter Wemm 	return;
9389f65f104SPeter Wemm 	}
9399f65f104SPeter Wemm 
9403d793cf1SPeter Wemm     if (strcmp(s, "CLR_REPORT") == 0)
9413d793cf1SPeter Wemm 	{
9423d793cf1SPeter Wemm 	++clear_report_next;
9433d793cf1SPeter Wemm 	return;
9443d793cf1SPeter Wemm 	}
9453d793cf1SPeter Wemm 
9469b1aec48SLars Fredriksen     if (strcmp(s, "TIMEOUT") == 0)
9479b1aec48SLars Fredriksen 	{
9489b1aec48SLars Fredriksen 	++timeout_next;
9499b1aec48SLars Fredriksen 	return;
9509b1aec48SLars Fredriksen 	}
9519b1aec48SLars Fredriksen 
9523d793cf1SPeter Wemm     if (strcmp(s, "ECHO") == 0)
9539b1aec48SLars Fredriksen 	{
9543d793cf1SPeter Wemm 	++echo_next;
9553d793cf1SPeter Wemm 	return;
9563d793cf1SPeter Wemm 	}
9573d793cf1SPeter Wemm     if (strcmp(s, "SAY") == 0)
9583d793cf1SPeter Wemm 	{
9593d793cf1SPeter Wemm 	++say_next;
9603d793cf1SPeter Wemm 	return;
9613d793cf1SPeter Wemm 	}
9623d793cf1SPeter Wemm /*
9633d793cf1SPeter Wemm  * Fetch the expect and reply string.
9643d793cf1SPeter Wemm  */
9653d793cf1SPeter Wemm     for (;;)
9663d793cf1SPeter Wemm 	{
9673d793cf1SPeter Wemm 	expect = expect_strtok (s, "-");
9683d793cf1SPeter Wemm 	s      = (char *) 0;
9699b1aec48SLars Fredriksen 
9703d793cf1SPeter Wemm 	if (expect == (char *) 0)
9719f65f104SPeter Wemm 	    {
9723d793cf1SPeter Wemm 	    return;
9733d793cf1SPeter Wemm 	    }
9743d793cf1SPeter Wemm 
9753d793cf1SPeter Wemm 	reply = expect_strtok (s, "-");
9763d793cf1SPeter Wemm /*
9773d793cf1SPeter Wemm  * Handle the expect string. If successful then exit.
9783d793cf1SPeter Wemm  */
9793d793cf1SPeter Wemm 	if (get_string (expect))
9809f65f104SPeter Wemm 	    {
9813d793cf1SPeter Wemm 	    return;
9823d793cf1SPeter Wemm 	    }
9833d793cf1SPeter Wemm /*
9843d793cf1SPeter Wemm  * If there is a sub-reply string then send it. Otherwise any condition
9853d793cf1SPeter Wemm  * is terminal.
9863d793cf1SPeter Wemm  */
9873d793cf1SPeter Wemm 	if (reply == (char *) 0 || exit_code != 3)
9889f65f104SPeter Wemm 	    {
9899b1aec48SLars Fredriksen 	    break;
9909f65f104SPeter Wemm 	    }
9919b1aec48SLars Fredriksen 
9923d793cf1SPeter Wemm 	chat_send (reply);
9939f65f104SPeter Wemm 	}
9943d793cf1SPeter Wemm /*
9953d793cf1SPeter Wemm  * The expectation did not occur. This is terminal.
9963d793cf1SPeter Wemm  */
9979b1aec48SLars Fredriksen     if (fail_reason)
9989f65f104SPeter Wemm 	{
9999b1aec48SLars Fredriksen 	syslog(LOG_INFO, "Failed (%s)", fail_reason);
10009f65f104SPeter Wemm 	}
10019b1aec48SLars Fredriksen     else
10029f65f104SPeter Wemm 	{
10039b1aec48SLars Fredriksen 	syslog(LOG_INFO, "Failed");
10049f65f104SPeter Wemm 	}
10059f65f104SPeter Wemm     terminate(exit_code);
10069f65f104SPeter Wemm     }
10073d793cf1SPeter Wemm 
10083d793cf1SPeter Wemm /*
10093d793cf1SPeter Wemm  * Translate the input character to the appropriate string for printing
10103d793cf1SPeter Wemm  * the data.
10113d793cf1SPeter Wemm  */
10129b1aec48SLars Fredriksen 
10139b1aec48SLars Fredriksen char *character(c)
10149f65f104SPeter Wemm int c;
10159b1aec48SLars Fredriksen     {
10169b1aec48SLars Fredriksen     static char string[10];
10179b1aec48SLars Fredriksen     char *meta;
10189b1aec48SLars Fredriksen 
10199b1aec48SLars Fredriksen     meta = (c & 0x80) ? "M-" : "";
10209b1aec48SLars Fredriksen     c &= 0x7F;
10219b1aec48SLars Fredriksen 
10229b1aec48SLars Fredriksen     if (c < 32)
10239f65f104SPeter Wemm         {
10249b1aec48SLars Fredriksen 	sprintf(string, "%s^%c", meta, (int)c + '@');
10259f65f104SPeter Wemm         }
10269b1aec48SLars Fredriksen     else
10279f65f104SPeter Wemm         {
10289b1aec48SLars Fredriksen 	if (c == 127)
10299f65f104SPeter Wemm 	    {
10309b1aec48SLars Fredriksen 	    sprintf(string, "%s^?", meta);
10319f65f104SPeter Wemm 	    }
10329b1aec48SLars Fredriksen 	else
10339f65f104SPeter Wemm 	    {
10349b1aec48SLars Fredriksen 	    sprintf(string, "%s%c", meta, c);
10359f65f104SPeter Wemm 	    }
10369f65f104SPeter Wemm         }
10379b1aec48SLars Fredriksen 
10389b1aec48SLars Fredriksen     return (string);
10399b1aec48SLars Fredriksen     }
10409b1aec48SLars Fredriksen 
10419b1aec48SLars Fredriksen /*
10429b1aec48SLars Fredriksen  *  process the reply string
10439b1aec48SLars Fredriksen  */
10449b1aec48SLars Fredriksen void chat_send (s)
10459b1aec48SLars Fredriksen register char *s;
10469b1aec48SLars Fredriksen     {
10473d793cf1SPeter Wemm     if (say_next)
10483d793cf1SPeter Wemm 	{
10493d793cf1SPeter Wemm 	say_next = 0;
10503d793cf1SPeter Wemm 	s = clean(s,0);
10513d793cf1SPeter Wemm 	write(2, s, strlen(s));
10523d793cf1SPeter Wemm         free(s);
10533d793cf1SPeter Wemm 	return;
10543d793cf1SPeter Wemm 	}
10553d793cf1SPeter Wemm     if (hup_next)
10563d793cf1SPeter Wemm         {
10573d793cf1SPeter Wemm         hup_next = 0;
10583d793cf1SPeter Wemm 	if (strcmp(s, "OFF") == 0)
10593d793cf1SPeter Wemm            signal(SIGHUP, SIG_IGN);
10603d793cf1SPeter Wemm         else
10613d793cf1SPeter Wemm            signal(SIGHUP, sighup);
10623d793cf1SPeter Wemm         return;
10633d793cf1SPeter Wemm         }
10643d793cf1SPeter Wemm     if (echo_next)
10653d793cf1SPeter Wemm 	{
10663d793cf1SPeter Wemm 	echo_next = 0;
10673d793cf1SPeter Wemm 	echo = (strcmp(s, "ON") == 0);
10683d793cf1SPeter Wemm 	return;
10693d793cf1SPeter Wemm 	}
10709b1aec48SLars Fredriksen     if (abort_next)
10719b1aec48SLars Fredriksen         {
10729b1aec48SLars Fredriksen 	char *s1;
10739b1aec48SLars Fredriksen 
10749b1aec48SLars Fredriksen 	abort_next = 0;
10759b1aec48SLars Fredriksen 
10769b1aec48SLars Fredriksen 	if (n_aborts >= MAX_ABORTS)
10779f65f104SPeter Wemm 	    {
10789b1aec48SLars Fredriksen 	    fatal("Too many ABORT strings");
10799f65f104SPeter Wemm 	    }
10809b1aec48SLars Fredriksen 
10819b1aec48SLars Fredriksen 	s1 = clean(s, 0);
10829b1aec48SLars Fredriksen 
10839f65f104SPeter Wemm 	if (strlen(s1) > strlen(s)
10849f65f104SPeter Wemm 	    || strlen(s1) + 1 > sizeof(fail_buffer))
10859b1aec48SLars Fredriksen 	    {
10869b1aec48SLars Fredriksen 	    syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s);
10879b1aec48SLars Fredriksen 	    die();
10889b1aec48SLars Fredriksen 	    }
10899b1aec48SLars Fredriksen 
10909b1aec48SLars Fredriksen 	abort_string[n_aborts++] = s1;
10919b1aec48SLars Fredriksen 
10929b1aec48SLars Fredriksen 	if (verbose)
10939b1aec48SLars Fredriksen 	    {
10949b1aec48SLars Fredriksen 	    logf("abort on (");
10959b1aec48SLars Fredriksen 
10969b1aec48SLars Fredriksen 	    for (s1 = s; *s1; ++s1)
10979f65f104SPeter Wemm 	        {
10989b1aec48SLars Fredriksen 		logf(character(*s1));
10999f65f104SPeter Wemm 	        }
11009b1aec48SLars Fredriksen 
11019b1aec48SLars Fredriksen 	    logf(")\n");
11029b1aec48SLars Fredriksen 	    }
11039f65f104SPeter Wemm 	return;
11049b1aec48SLars Fredriksen 	}
11059f65f104SPeter Wemm 
11063d793cf1SPeter Wemm     if (clear_abort_next)
11073d793cf1SPeter Wemm         {
11083d793cf1SPeter Wemm 	char *s1;
11093d793cf1SPeter Wemm 	char *s2 = s;
11103d793cf1SPeter Wemm 	int   i;
11113d793cf1SPeter Wemm         int   old_max;
11123d793cf1SPeter Wemm 	int   pack = 0;
11133d793cf1SPeter Wemm 
11143d793cf1SPeter Wemm 	clear_abort_next = 0;
11153d793cf1SPeter Wemm 
11163d793cf1SPeter Wemm 	s1 = clean(s, 0);
11173d793cf1SPeter Wemm 
11183d793cf1SPeter Wemm 	if (strlen(s1) > strlen(s)
11193d793cf1SPeter Wemm 	    || strlen(s1) + 1 > sizeof(fail_buffer))
11203d793cf1SPeter Wemm 	    {
11213d793cf1SPeter Wemm 	    syslog(LOG_WARNING, "Illegal or too-long CLR_ABORT string ('%s')", s);
11223d793cf1SPeter Wemm 	    die();
11233d793cf1SPeter Wemm 	    }
11243d793cf1SPeter Wemm 
11253d793cf1SPeter Wemm         old_max = n_aborts;
11263d793cf1SPeter Wemm 	for (i=0; i < n_aborts; i++)
11273d793cf1SPeter Wemm 	    {
11283d793cf1SPeter Wemm 		if ( strcmp(s1,abort_string[i]) == 0 )
11293d793cf1SPeter Wemm 		    {
11303d793cf1SPeter Wemm                         free(abort_string[i]);
11313d793cf1SPeter Wemm 			abort_string[i] = NULL;
11323d793cf1SPeter Wemm 			pack++;
11333d793cf1SPeter Wemm                         n_aborts--;
11343d793cf1SPeter Wemm 			if (verbose)
11353d793cf1SPeter Wemm 	    		{
11363d793cf1SPeter Wemm 	    		logf("clear abort on (");
11373d793cf1SPeter Wemm 
11383d793cf1SPeter Wemm 	    		for (s2 = s; *s2; ++s2)
11393d793cf1SPeter Wemm 	        		{
11403d793cf1SPeter Wemm 				logf(character(*s2));
11413d793cf1SPeter Wemm 	        		}
11423d793cf1SPeter Wemm 
11433d793cf1SPeter Wemm 	    		logf(")\n");
11443d793cf1SPeter Wemm 	    		}
11453d793cf1SPeter Wemm 	    	    }
11463d793cf1SPeter Wemm 	    }
11473d793cf1SPeter Wemm         free(s1);
11483d793cf1SPeter Wemm 	if (pack) pack_array(abort_string,old_max);
11493d793cf1SPeter Wemm 	return;
11503d793cf1SPeter Wemm 	}
11513d793cf1SPeter Wemm 
11529f65f104SPeter Wemm     if (report_next)
11539f65f104SPeter Wemm         {
11549f65f104SPeter Wemm 	char *s1;
11559f65f104SPeter Wemm 
11569f65f104SPeter Wemm 	report_next = 0;
11579f65f104SPeter Wemm 	if (n_reports >= MAX_REPORTS)
11589f65f104SPeter Wemm 	    {
11599f65f104SPeter Wemm 	    fatal("Too many REPORT strings");
11609f65f104SPeter Wemm 	    }
11619f65f104SPeter Wemm 
11629f65f104SPeter Wemm 	s1 = clean(s, 0);
11639f65f104SPeter Wemm 
11649f65f104SPeter Wemm 	if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
11659f65f104SPeter Wemm 	    {
11669f65f104SPeter Wemm 	    syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s);
11679f65f104SPeter Wemm 	    die();
11689f65f104SPeter Wemm 	    }
11699f65f104SPeter Wemm 
11709f65f104SPeter Wemm 	report_string[n_reports++] = s1;
11719f65f104SPeter Wemm 
11729f65f104SPeter Wemm 	if (verbose)
11739f65f104SPeter Wemm 	    {
11749f65f104SPeter Wemm 	    logf("report (");
11759f65f104SPeter Wemm 	    s1 = s;
11769f65f104SPeter Wemm 	    while (*s1)
11779f65f104SPeter Wemm 	        {
11789f65f104SPeter Wemm 		logf(character(*s1));
11799f65f104SPeter Wemm 		++s1;
11809f65f104SPeter Wemm 	        }
11819f65f104SPeter Wemm 	    logf(")\n");
11829f65f104SPeter Wemm 	    }
11839f65f104SPeter Wemm 	return;
11849f65f104SPeter Wemm         }
11859f65f104SPeter Wemm 
11863d793cf1SPeter Wemm     if (clear_report_next)
11873d793cf1SPeter Wemm         {
11883d793cf1SPeter Wemm 	char *s1;
11893d793cf1SPeter Wemm         char *s2 = s;
11903d793cf1SPeter Wemm 	int   i;
11913d793cf1SPeter Wemm 	int   old_max;
11923d793cf1SPeter Wemm 	int   pack = 0;
11933d793cf1SPeter Wemm 
11943d793cf1SPeter Wemm 	clear_report_next = 0;
11953d793cf1SPeter Wemm 
11963d793cf1SPeter Wemm 	s1 = clean(s, 0);
11973d793cf1SPeter Wemm 
11983d793cf1SPeter Wemm 	if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
11993d793cf1SPeter Wemm 	    {
12003d793cf1SPeter Wemm 	    syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s);
12013d793cf1SPeter Wemm 	    die();
12023d793cf1SPeter Wemm 	    }
12033d793cf1SPeter Wemm 
12043d793cf1SPeter Wemm 	old_max = n_reports;
12053d793cf1SPeter Wemm 	for (i=0; i < n_reports; i++)
12063d793cf1SPeter Wemm 	    {
12073d793cf1SPeter Wemm 		if ( strcmp(s1,report_string[i]) == 0 )
12083d793cf1SPeter Wemm 		    {
12093d793cf1SPeter Wemm 			free(report_string[i]);
12103d793cf1SPeter Wemm 			report_string[i] = NULL;
12113d793cf1SPeter Wemm 			pack++;
12123d793cf1SPeter Wemm 			n_reports--;
12133d793cf1SPeter Wemm 			if (verbose)
12143d793cf1SPeter Wemm 	    		{
12153d793cf1SPeter Wemm 	    		logf("clear report (");
12163d793cf1SPeter Wemm 
12173d793cf1SPeter Wemm 	    		for (s2 = s; *s2; ++s2)
12183d793cf1SPeter Wemm 	        		{
12193d793cf1SPeter Wemm 				logf(character(*s2));
12203d793cf1SPeter Wemm 	        		}
12213d793cf1SPeter Wemm 
12223d793cf1SPeter Wemm 	    		logf(")\n");
12233d793cf1SPeter Wemm 	    		}
12243d793cf1SPeter Wemm 	    	    }
12253d793cf1SPeter Wemm 	    }
12263d793cf1SPeter Wemm         free(s1);
12273d793cf1SPeter Wemm         if (pack) pack_array(report_string,old_max);
12283d793cf1SPeter Wemm 
12293d793cf1SPeter Wemm 	return;
12303d793cf1SPeter Wemm         }
12313d793cf1SPeter Wemm 
12329b1aec48SLars Fredriksen     if (timeout_next)
12339b1aec48SLars Fredriksen         {
12349b1aec48SLars Fredriksen 	timeout_next = 0;
12359b1aec48SLars Fredriksen 	timeout = atoi(s);
12369b1aec48SLars Fredriksen 
12379b1aec48SLars Fredriksen 	if (timeout <= 0)
12389f65f104SPeter Wemm 	    {
12399b1aec48SLars Fredriksen 	    timeout = DEFAULT_CHAT_TIMEOUT;
12409f65f104SPeter Wemm 	    }
12419b1aec48SLars Fredriksen 
12429b1aec48SLars Fredriksen 	if (verbose)
12439b1aec48SLars Fredriksen 	    {
12449b1aec48SLars Fredriksen 	    syslog(LOG_INFO, "timeout set to %d seconds", timeout);
12459b1aec48SLars Fredriksen 	    }
12469f65f104SPeter Wemm 	return;
12479f65f104SPeter Wemm         }
12489f65f104SPeter Wemm 
12499f65f104SPeter Wemm     if (strcmp(s, "EOT") == 0)
12509f65f104SPeter Wemm         {
12519f65f104SPeter Wemm 	s = "^D\\c";
12529b1aec48SLars Fredriksen         }
12539b1aec48SLars Fredriksen     else
12549b1aec48SLars Fredriksen         {
12559b1aec48SLars Fredriksen 	if (strcmp(s, "BREAK") == 0)
12569f65f104SPeter Wemm 	    {
12579b1aec48SLars Fredriksen 	    s = "\\K\\c";
12589f65f104SPeter Wemm 	    }
12599f65f104SPeter Wemm         }
12609f65f104SPeter Wemm 
12619b1aec48SLars Fredriksen     if (!put_string(s))
12629b1aec48SLars Fredriksen         {
12639b1aec48SLars Fredriksen 	syslog(LOG_INFO, "Failed");
12649b1aec48SLars Fredriksen 	terminate(1);
12659b1aec48SLars Fredriksen         }
12669b1aec48SLars Fredriksen     }
12679b1aec48SLars Fredriksen 
12689b1aec48SLars Fredriksen int get_char()
12699b1aec48SLars Fredriksen     {
12709b1aec48SLars Fredriksen     int status;
12719b1aec48SLars Fredriksen     char c;
12729b1aec48SLars Fredriksen 
12739b1aec48SLars Fredriksen     status = read(0, &c, 1);
12749b1aec48SLars Fredriksen 
12759b1aec48SLars Fredriksen     switch (status)
12769b1aec48SLars Fredriksen         {
12779b1aec48SLars Fredriksen     case 1:
12789b1aec48SLars Fredriksen 	return ((int)c & 0x7F);
12799b1aec48SLars Fredriksen 
12809b1aec48SLars Fredriksen     default:
12819b1aec48SLars Fredriksen 	syslog(LOG_WARNING, "warning: read() on stdin returned %d",
12829b1aec48SLars Fredriksen 	       status);
12839b1aec48SLars Fredriksen 
12849b1aec48SLars Fredriksen     case -1:
12859b1aec48SLars Fredriksen 	if ((status = fcntl(0, F_GETFL, 0)) == -1)
12869f65f104SPeter Wemm 	    {
12879b1aec48SLars Fredriksen 	    sysfatal("Can't get file mode flags on stdin");
12889f65f104SPeter Wemm 	    }
12899b1aec48SLars Fredriksen 	else
12909f65f104SPeter Wemm 	    {
12919f65f104SPeter Wemm 	    if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
12929f65f104SPeter Wemm 	        {
12939b1aec48SLars Fredriksen 		sysfatal("Can't set file mode flags on stdin");
12949f65f104SPeter Wemm 	        }
12959f65f104SPeter Wemm 	    }
12969b1aec48SLars Fredriksen 
12979b1aec48SLars Fredriksen 	return (-1);
12989b1aec48SLars Fredriksen         }
12999b1aec48SLars Fredriksen     }
13009b1aec48SLars Fredriksen 
13019b1aec48SLars Fredriksen int put_char(c)
13029f65f104SPeter Wemm int c;
13039b1aec48SLars Fredriksen     {
13049b1aec48SLars Fredriksen     int status;
13059f65f104SPeter Wemm     char ch = c;
13069b1aec48SLars Fredriksen 
13079f65f104SPeter Wemm     usleep(10000);		/* inter-character typing delay (?) */
13089b1aec48SLars Fredriksen 
13099f65f104SPeter Wemm     status = write(1, &ch, 1);
13109b1aec48SLars Fredriksen 
13119b1aec48SLars Fredriksen     switch (status)
13129b1aec48SLars Fredriksen         {
13139b1aec48SLars Fredriksen     case 1:
13149b1aec48SLars Fredriksen 	return (0);
13159b1aec48SLars Fredriksen 
13169b1aec48SLars Fredriksen     default:
13179b1aec48SLars Fredriksen 	syslog(LOG_WARNING, "warning: write() on stdout returned %d",
13189b1aec48SLars Fredriksen 	       status);
13199b1aec48SLars Fredriksen 
13209b1aec48SLars Fredriksen     case -1:
13219b1aec48SLars Fredriksen 	if ((status = fcntl(0, F_GETFL, 0)) == -1)
13229f65f104SPeter Wemm 	    {
13239b1aec48SLars Fredriksen 	    sysfatal("Can't get file mode flags on stdin");
13249f65f104SPeter Wemm 	    }
13259b1aec48SLars Fredriksen 	else
13269f65f104SPeter Wemm 	    {
13279f65f104SPeter Wemm 	    if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
13289f65f104SPeter Wemm 	        {
13299b1aec48SLars Fredriksen 		sysfatal("Can't set file mode flags on stdin");
13309f65f104SPeter Wemm 	        }
13319f65f104SPeter Wemm 	    }
13329b1aec48SLars Fredriksen 
13339b1aec48SLars Fredriksen 	return (-1);
13349b1aec48SLars Fredriksen         }
13359b1aec48SLars Fredriksen     }
13369b1aec48SLars Fredriksen 
13379b1aec48SLars Fredriksen int write_char (c)
13389b1aec48SLars Fredriksen int c;
13399b1aec48SLars Fredriksen     {
13409b1aec48SLars Fredriksen     if (alarmed || put_char(c) < 0)
13419b1aec48SLars Fredriksen 	{
13429b1aec48SLars Fredriksen 	extern int errno;
13439b1aec48SLars Fredriksen 
13449f65f104SPeter Wemm 	alarm(0);
13459f65f104SPeter Wemm 	alarmed = 0;
13469b1aec48SLars Fredriksen 
13479b1aec48SLars Fredriksen 	if (verbose)
13489b1aec48SLars Fredriksen 	    {
13499b1aec48SLars Fredriksen 	    if (errno == EINTR || errno == EWOULDBLOCK)
13509f65f104SPeter Wemm 	        {
13519b1aec48SLars Fredriksen 		syslog(LOG_INFO, " -- write timed out");
13529f65f104SPeter Wemm 	        }
13539b1aec48SLars Fredriksen 	    else
13549f65f104SPeter Wemm 	        {
13559b1aec48SLars Fredriksen 		syslog(LOG_INFO, " -- write failed: %m");
13569b1aec48SLars Fredriksen 	        }
13579f65f104SPeter Wemm 	    }
13589b1aec48SLars Fredriksen 	return (0);
13599b1aec48SLars Fredriksen 	}
13609b1aec48SLars Fredriksen     return (1);
13619b1aec48SLars Fredriksen     }
13629b1aec48SLars Fredriksen 
13639b1aec48SLars Fredriksen int put_string (s)
13649b1aec48SLars Fredriksen register char *s;
13659b1aec48SLars Fredriksen     {
13663d793cf1SPeter Wemm     quiet = 0;
13679b1aec48SLars Fredriksen     s = clean(s, 1);
13689b1aec48SLars Fredriksen 
13699b1aec48SLars Fredriksen     if (verbose)
13709b1aec48SLars Fredriksen 	{
13719b1aec48SLars Fredriksen 	logf("send (");
13729b1aec48SLars Fredriksen 
13739b1aec48SLars Fredriksen 	if (quiet)
13749f65f104SPeter Wemm 	    {
13759b1aec48SLars Fredriksen 	    logf("??????");
13769f65f104SPeter Wemm 	    }
13779b1aec48SLars Fredriksen 	else
13789b1aec48SLars Fredriksen 	    {
13799b1aec48SLars Fredriksen 	    register char *s1 = s;
13809b1aec48SLars Fredriksen 
13819b1aec48SLars Fredriksen 	    for (s1 = s; *s1; ++s1)
13829f65f104SPeter Wemm 	        {
13839b1aec48SLars Fredriksen 		logf(character(*s1));
13849b1aec48SLars Fredriksen 	        }
13859f65f104SPeter Wemm 	    }
13869b1aec48SLars Fredriksen 
13879b1aec48SLars Fredriksen 	logf(")\n");
13889b1aec48SLars Fredriksen 	}
13899b1aec48SLars Fredriksen 
13909b1aec48SLars Fredriksen     alarm(timeout); alarmed = 0;
13919b1aec48SLars Fredriksen 
13929b1aec48SLars Fredriksen     while (*s)
13939b1aec48SLars Fredriksen 	{
13949b1aec48SLars Fredriksen 	register char c = *s++;
13959b1aec48SLars Fredriksen 
13969b1aec48SLars Fredriksen 	if (c != '\\')
13979b1aec48SLars Fredriksen 	    {
13989b1aec48SLars Fredriksen 	    if (!write_char (c))
13999f65f104SPeter Wemm 	        {
14009b1aec48SLars Fredriksen 		return 0;
14019f65f104SPeter Wemm 	        }
14029b1aec48SLars Fredriksen 	    continue;
14039b1aec48SLars Fredriksen 	    }
14049b1aec48SLars Fredriksen 
14059b1aec48SLars Fredriksen 	c = *s++;
14069b1aec48SLars Fredriksen 	switch (c)
14079b1aec48SLars Fredriksen 	    {
14089b1aec48SLars Fredriksen 	case 'd':
14099b1aec48SLars Fredriksen 	    sleep(1);
14109b1aec48SLars Fredriksen 	    break;
14119b1aec48SLars Fredriksen 
14129b1aec48SLars Fredriksen 	case 'K':
14139b1aec48SLars Fredriksen 	    break_sequence();
14149b1aec48SLars Fredriksen 	    break;
14159b1aec48SLars Fredriksen 
14169b1aec48SLars Fredriksen 	case 'p':
14179f65f104SPeter Wemm 	    usleep(10000); 	/* 1/100th of a second (arg is microseconds) */
14189b1aec48SLars Fredriksen 	    break;
14199b1aec48SLars Fredriksen 
14209b1aec48SLars Fredriksen 	default:
14219b1aec48SLars Fredriksen 	    if (!write_char (c))
14229b1aec48SLars Fredriksen 		return 0;
14239b1aec48SLars Fredriksen 	    break;
14249b1aec48SLars Fredriksen 	    }
14259b1aec48SLars Fredriksen 	}
14269b1aec48SLars Fredriksen 
14279b1aec48SLars Fredriksen     alarm(0);
14289b1aec48SLars Fredriksen     alarmed = 0;
14299b1aec48SLars Fredriksen     return (1);
14309b1aec48SLars Fredriksen     }
14319b1aec48SLars Fredriksen 
14329b1aec48SLars Fredriksen /*
14333d793cf1SPeter Wemm  *	Echo a character to stderr.
14343d793cf1SPeter Wemm  *	When called with -1, a '\n' character is generated when
14353d793cf1SPeter Wemm  *	the cursor is not at the beginning of a line.
14363d793cf1SPeter Wemm  */
14373d793cf1SPeter Wemm void echo_stderr(n)
14383d793cf1SPeter Wemm int n;
14393d793cf1SPeter Wemm     {
14403d793cf1SPeter Wemm 	static int need_lf;
14413d793cf1SPeter Wemm 	char *s;
14423d793cf1SPeter Wemm 
14433d793cf1SPeter Wemm 	switch (n)
14443d793cf1SPeter Wemm 	    {
14453d793cf1SPeter Wemm 	case '\r':		/* ignore '\r' */
14463d793cf1SPeter Wemm 	    break;
14473d793cf1SPeter Wemm 	case -1:
14483d793cf1SPeter Wemm 	    if (need_lf == 0)
14493d793cf1SPeter Wemm 		break;
14503d793cf1SPeter Wemm 	    /* fall through */
14513d793cf1SPeter Wemm 	case '\n':
14523d793cf1SPeter Wemm 	    write(2, "\n", 1);
14533d793cf1SPeter Wemm 	    need_lf = 0;
14543d793cf1SPeter Wemm 	    break;
14553d793cf1SPeter Wemm 	default:
14563d793cf1SPeter Wemm 	    s = character(n);
14573d793cf1SPeter Wemm 	    write(2, s, strlen(s));
14583d793cf1SPeter Wemm 	    need_lf = 1;
14593d793cf1SPeter Wemm 	    break;
14603d793cf1SPeter Wemm 	    }
14613d793cf1SPeter Wemm     }
14623d793cf1SPeter Wemm 
14633d793cf1SPeter Wemm /*
14649b1aec48SLars Fredriksen  *	'Wait for' this string to appear on this file descriptor.
14659b1aec48SLars Fredriksen  */
14669b1aec48SLars Fredriksen int get_string(string)
14679b1aec48SLars Fredriksen register char *string;
14689b1aec48SLars Fredriksen     {
14699b1aec48SLars Fredriksen     char temp[STR_LEN];
14709b1aec48SLars Fredriksen     int c, printed = 0, len, minlen;
14719b1aec48SLars Fredriksen     register char *s = temp, *end = s + STR_LEN;
14729b1aec48SLars Fredriksen 
14739b1aec48SLars Fredriksen     fail_reason = (char *)0;
14749b1aec48SLars Fredriksen     string = clean(string, 0);
14759b1aec48SLars Fredriksen     len = strlen(string);
14769b1aec48SLars Fredriksen     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
14779b1aec48SLars Fredriksen 
14789b1aec48SLars Fredriksen     if (verbose)
14799b1aec48SLars Fredriksen 	{
14809b1aec48SLars Fredriksen 	register char *s1;
14819b1aec48SLars Fredriksen 
14829b1aec48SLars Fredriksen 	logf("expect (");
14839b1aec48SLars Fredriksen 
14849b1aec48SLars Fredriksen 	for (s1 = string; *s1; ++s1)
14859f65f104SPeter Wemm 	    {
14869b1aec48SLars Fredriksen 	    logf(character(*s1));
14879f65f104SPeter Wemm 	    }
14889b1aec48SLars Fredriksen 
14899b1aec48SLars Fredriksen 	logf(")\n");
14909b1aec48SLars Fredriksen 	}
14919b1aec48SLars Fredriksen 
14929b1aec48SLars Fredriksen     if (len > STR_LEN)
14939b1aec48SLars Fredriksen 	{
14949b1aec48SLars Fredriksen 	syslog(LOG_INFO, "expect string is too long");
14959f65f104SPeter Wemm 	exit_code = 1;
14969b1aec48SLars Fredriksen 	return 0;
14979b1aec48SLars Fredriksen 	}
14989b1aec48SLars Fredriksen 
14999b1aec48SLars Fredriksen     if (len == 0)
15009b1aec48SLars Fredriksen 	{
15019b1aec48SLars Fredriksen 	if (verbose)
15029b1aec48SLars Fredriksen 	    {
15039b1aec48SLars Fredriksen 	    syslog(LOG_INFO, "got it");
15049b1aec48SLars Fredriksen 	    }
15059b1aec48SLars Fredriksen 
15069b1aec48SLars Fredriksen 	return (1);
15079b1aec48SLars Fredriksen 	}
15089b1aec48SLars Fredriksen 
15099f65f104SPeter Wemm     alarm(timeout);
15109f65f104SPeter Wemm     alarmed = 0;
15119b1aec48SLars Fredriksen 
15129b1aec48SLars Fredriksen     while ( ! alarmed && (c = get_char()) >= 0)
15139b1aec48SLars Fredriksen 	{
15149f65f104SPeter Wemm 	int n, abort_len, report_len;
15159b1aec48SLars Fredriksen 
15163d793cf1SPeter Wemm 	if (echo)
15173d793cf1SPeter Wemm 	    {
15183d793cf1SPeter Wemm 	    echo_stderr(c);
15193d793cf1SPeter Wemm 	    }
15209b1aec48SLars Fredriksen 	if (verbose)
15219b1aec48SLars Fredriksen 	    {
15229b1aec48SLars Fredriksen 	    if (c == '\n')
15239f65f104SPeter Wemm 	        {
15249b1aec48SLars Fredriksen 		logf("\n");
15259f65f104SPeter Wemm 	        }
15269b1aec48SLars Fredriksen 	    else
15279f65f104SPeter Wemm 	        {
15289b1aec48SLars Fredriksen 		logf(character(c));
15299b1aec48SLars Fredriksen 	        }
15309f65f104SPeter Wemm 	    }
15319b1aec48SLars Fredriksen 
15323d793cf1SPeter Wemm 	if (Verbose) {
15333d793cf1SPeter Wemm 	   if (c == '\n')      fputc( '\n', stderr );
15343d793cf1SPeter Wemm 	   else if (c != '\r') fprintf( stderr, "%s", character(c) );
15353d793cf1SPeter Wemm 	}
15363d793cf1SPeter Wemm 
15379b1aec48SLars Fredriksen 	*s++ = c;
15389b1aec48SLars Fredriksen 
15399f65f104SPeter Wemm 	if (!report_gathering)
15409f65f104SPeter Wemm 	    {
15419f65f104SPeter Wemm 	    for (n = 0; n < n_reports; ++n)
15429f65f104SPeter Wemm 	        {
15439f65f104SPeter Wemm 		if ((report_string[n] != (char*) NULL) &&
15449f65f104SPeter Wemm 		    s - temp >= (report_len = strlen(report_string[n])) &&
15459f65f104SPeter Wemm 		    strncmp(s - report_len, report_string[n], report_len) == 0)
15469f65f104SPeter Wemm 		    {
15479f65f104SPeter Wemm 		    time_t time_now   = time ((time_t*) NULL);
15489f65f104SPeter Wemm 		    struct tm* tm_now = localtime (&time_now);
15499f65f104SPeter Wemm 
15509f65f104SPeter Wemm 		    strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
15519f65f104SPeter Wemm 		    strcat (report_buffer, report_string[n]);
15529f65f104SPeter Wemm 
15539f65f104SPeter Wemm 		    report_string[n] = (char *) NULL;
15549f65f104SPeter Wemm 		    report_gathering = 1;
15559f65f104SPeter Wemm 		    break;
15569f65f104SPeter Wemm 		    }
15579f65f104SPeter Wemm 	        }
15589f65f104SPeter Wemm 	    }
15599f65f104SPeter Wemm 	else
15609f65f104SPeter Wemm 	    {
15619f65f104SPeter Wemm 	    if (!iscntrl (c))
15629f65f104SPeter Wemm 	        {
15639f65f104SPeter Wemm 		int rep_len = strlen (report_buffer);
15649f65f104SPeter Wemm 		report_buffer[rep_len]     = c;
15659f65f104SPeter Wemm 		report_buffer[rep_len + 1] = '\0';
15669f65f104SPeter Wemm 	        }
15679f65f104SPeter Wemm 	    else
15689f65f104SPeter Wemm 	        {
15699f65f104SPeter Wemm 		report_gathering = 0;
15709f65f104SPeter Wemm 		fprintf (report_fp, "chat:  %s\n", report_buffer);
15719f65f104SPeter Wemm 	        }
15729f65f104SPeter Wemm 	    }
15739b1aec48SLars Fredriksen 
15743d793cf1SPeter Wemm 	if (s - temp >= len &&
15753d793cf1SPeter Wemm 	    c == string[len - 1] &&
15763d793cf1SPeter Wemm 	    strncmp(s - len, string, len) == 0)
15773d793cf1SPeter Wemm 	    {
15783d793cf1SPeter Wemm 	    if (verbose)
15793d793cf1SPeter Wemm 		{
15803d793cf1SPeter Wemm 		logf(" -- got it\n");
15813d793cf1SPeter Wemm 		}
15823d793cf1SPeter Wemm 
15833d793cf1SPeter Wemm 	    alarm(0);
15843d793cf1SPeter Wemm 	    alarmed = 0;
15853d793cf1SPeter Wemm 	    return (1);
15863d793cf1SPeter Wemm 	    }
15873d793cf1SPeter Wemm 
15883d793cf1SPeter Wemm 	for (n = 0; n < n_aborts; ++n)
15893d793cf1SPeter Wemm 	    {
15903d793cf1SPeter Wemm 	    if (s - temp >= (abort_len = strlen(abort_string[n])) &&
15913d793cf1SPeter Wemm 		strncmp(s - abort_len, abort_string[n], abort_len) == 0)
15923d793cf1SPeter Wemm 	        {
15933d793cf1SPeter Wemm 		if (verbose)
15943d793cf1SPeter Wemm 		    {
15953d793cf1SPeter Wemm 		    logf(" -- failed\n");
15963d793cf1SPeter Wemm 		    }
15973d793cf1SPeter Wemm 
15983d793cf1SPeter Wemm 		alarm(0);
15993d793cf1SPeter Wemm 		alarmed = 0;
16003d793cf1SPeter Wemm 		exit_code = n + 4;
16013d793cf1SPeter Wemm 		strcpy(fail_reason = fail_buffer, abort_string[n]);
16023d793cf1SPeter Wemm 		return (0);
16033d793cf1SPeter Wemm 	        }
16043d793cf1SPeter Wemm 	    }
16053d793cf1SPeter Wemm 
16069b1aec48SLars Fredriksen 	if (s >= end)
16079b1aec48SLars Fredriksen 	    {
16089b1aec48SLars Fredriksen 	    strncpy (temp, s - minlen, minlen);
16099b1aec48SLars Fredriksen 	    s = temp + minlen;
16109b1aec48SLars Fredriksen 	    }
16119b1aec48SLars Fredriksen 
16129b1aec48SLars Fredriksen 	if (alarmed && verbose)
16139f65f104SPeter Wemm 	    {
16149b1aec48SLars Fredriksen 	    syslog(LOG_WARNING, "warning: alarm synchronization problem");
16159b1aec48SLars Fredriksen 	    }
16169f65f104SPeter Wemm 	}
16179b1aec48SLars Fredriksen 
16189b1aec48SLars Fredriksen     alarm(0);
16199b1aec48SLars Fredriksen 
16209b1aec48SLars Fredriksen     if (verbose && printed)
16219b1aec48SLars Fredriksen 	{
16229b1aec48SLars Fredriksen 	if (alarmed)
16239f65f104SPeter Wemm 	    {
16249b1aec48SLars Fredriksen 	    logf(" -- read timed out\n");
16259f65f104SPeter Wemm 	    }
16269b1aec48SLars Fredriksen 	else
16279b1aec48SLars Fredriksen 	    {
16289b1aec48SLars Fredriksen 	    logflush();
16299b1aec48SLars Fredriksen 	    syslog(LOG_INFO, " -- read failed: %m");
16309b1aec48SLars Fredriksen 	    }
16319b1aec48SLars Fredriksen 	}
16329b1aec48SLars Fredriksen 
16339f65f104SPeter Wemm     exit_code = 3;
16349b1aec48SLars Fredriksen     alarmed   = 0;
16359b1aec48SLars Fredriksen     return (0);
16369b1aec48SLars Fredriksen     }
16379b1aec48SLars Fredriksen 
16389f65f104SPeter Wemm #ifdef NO_USLEEP
16399b1aec48SLars Fredriksen #include <sys/types.h>
16409b1aec48SLars Fredriksen #include <sys/time.h>
16419b1aec48SLars Fredriksen 
16429b1aec48SLars Fredriksen /*
16439b1aec48SLars Fredriksen   usleep -- support routine for 4.2BSD system call emulations
16449b1aec48SLars Fredriksen   last edit:  29-Oct-1984     D A Gwyn
16459b1aec48SLars Fredriksen   */
16469b1aec48SLars Fredriksen 
16479b1aec48SLars Fredriksen extern int	  select();
16489b1aec48SLars Fredriksen 
16499b1aec48SLars Fredriksen int
16509b1aec48SLars Fredriksen usleep( usec )				  /* returns 0 if ok, else -1 */
16519b1aec48SLars Fredriksen     long		usec;		/* delay in microseconds */
16529b1aec48SLars Fredriksen {
16539b1aec48SLars Fredriksen     static struct			/* `timeval' */
16549b1aec48SLars Fredriksen         {
16559b1aec48SLars Fredriksen 	long	tv_sec;		/* seconds */
16569b1aec48SLars Fredriksen 	long	tv_usec;	/* microsecs */
16579b1aec48SLars Fredriksen         } delay;	    /* _select() timeout */
16589b1aec48SLars Fredriksen 
16599b1aec48SLars Fredriksen     delay.tv_sec  = usec / 1000000L;
16609b1aec48SLars Fredriksen     delay.tv_usec = usec % 1000000L;
16619b1aec48SLars Fredriksen 
16629b1aec48SLars Fredriksen     return select( 0, (long *)0, (long *)0, (long *)0, &delay );
16639b1aec48SLars Fredriksen }
16649b1aec48SLars Fredriksen #endif
16653d793cf1SPeter Wemm 
16663d793cf1SPeter Wemm void
16673d793cf1SPeter Wemm pack_array (array, end)
16683d793cf1SPeter Wemm     char **array; /* The address of the array of string pointers */
16693d793cf1SPeter Wemm     int    end;   /* The index of the next free entry before CLR_ */
16703d793cf1SPeter Wemm {
16713d793cf1SPeter Wemm     int i, j;
16723d793cf1SPeter Wemm 
16733d793cf1SPeter Wemm     for (i = 0; i < end; i++) {
16743d793cf1SPeter Wemm 	if (array[i] == NULL) {
16753d793cf1SPeter Wemm 	    for (j = i+1; j < end; ++j)
16763d793cf1SPeter Wemm 		if (array[j] != NULL)
16773d793cf1SPeter Wemm 		    array[i++] = array[j];
16783d793cf1SPeter Wemm 	    for (; i < end; ++i)
16793d793cf1SPeter Wemm 		array[i] = NULL;
16803d793cf1SPeter Wemm 	    break;
16813d793cf1SPeter Wemm 	}
16823d793cf1SPeter Wemm     }
16833d793cf1SPeter Wemm }
1684