Home | History | Annotate | Line # | Download | only in chat
chat.c revision 1.3.8.2
      1  1.3.8.2  tls /*
      2  1.3.8.2  tls  *	Chat -- a program for automatic session establishment (i.e. dial
      3  1.3.8.2  tls  *		the phone and log in).
      4  1.3.8.2  tls  *
      5  1.3.8.2  tls  * Standard termination codes:
      6  1.3.8.2  tls  *  0 - successful completion of the script
      7  1.3.8.2  tls  *  1 - invalid argument, expect string too large, etc.
      8  1.3.8.2  tls  *  2 - error on an I/O operation or fatal error condition.
      9  1.3.8.2  tls  *  3 - timeout waiting for a simple string.
     10  1.3.8.2  tls  *  4 - the first string declared as "ABORT"
     11  1.3.8.2  tls  *  5 - the second string declared as "ABORT"
     12  1.3.8.2  tls  *  6 - ... and so on for successive ABORT strings.
     13  1.3.8.2  tls  *
     14  1.3.8.2  tls  *	This software is in the public domain.
     15  1.3.8.2  tls  *
     16  1.3.8.2  tls  * -----------------
     17  1.3.8.2  tls  *	22-May-99 added environment substitutuion, enabled with -E switch.
     18  1.3.8.2  tls  *	Andreas Arens <andras (at) cityweb.de>.
     19  1.3.8.2  tls  *
     20  1.3.8.2  tls  *	12-May-99 added a feature to read data to be sent from a file,
     21  1.3.8.2  tls  *	if the send string starts with @.  Idea from gpk <gpk (at) onramp.net>.
     22  1.3.8.2  tls  *
     23  1.3.8.2  tls  *	added -T and -U option and \T and \U substitution to pass a phone
     24  1.3.8.2  tls  *	number into chat script. Two are needed for some ISDN TA applications.
     25  1.3.8.2  tls  *	Keith Dart <kdart (at) cisco.com>
     26  1.3.8.2  tls  *
     27  1.3.8.2  tls  *
     28  1.3.8.2  tls  *	Added SAY keyword to send output to stderr.
     29  1.3.8.2  tls  *      This allows to turn ECHO OFF and to output specific, user selected,
     30  1.3.8.2  tls  *      text to give progress messages. This best works when stderr
     31  1.3.8.2  tls  *      exists (i.e.: pppd in nodetach mode).
     32  1.3.8.2  tls  *
     33  1.3.8.2  tls  * 	Added HANGUP directives to allow for us to be called
     34  1.3.8.2  tls  *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
     35  1.3.8.2  tls  *      We rely on timeouts in that case.
     36  1.3.8.2  tls  *
     37  1.3.8.2  tls  *      Added CLR_ABORT to clear previously set ABORT string. This has been
     38  1.3.8.2  tls  *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
     39  1.3.8.2  tls  *      an ABORT condition until we know the other host is going to close
     40  1.3.8.2  tls  *      the connection for call back. As soon as we have completed the
     41  1.3.8.2  tls  *      first stage of the call back sequence, "NO CARRIER" is a valid, non
     42  1.3.8.2  tls  *      fatal string. As soon as we got called back (probably get "CONNECT"),
     43  1.3.8.2  tls  *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
     44  1.3.8.2  tls  *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
     45  1.3.8.2  tls  *      have unused entries not being reclaimed.
     46  1.3.8.2  tls  *
     47  1.3.8.2  tls  *      In the same vein as above, added CLR_REPORT keyword.
     48  1.3.8.2  tls  *
     49  1.3.8.2  tls  *      Allow for comments. Line starting with '#' are comments and are
     50  1.3.8.2  tls  *      ignored. If a '#' is to be expected as the first character, the
     51  1.3.8.2  tls  *      expect string must be quoted.
     52  1.3.8.2  tls  *
     53  1.3.8.2  tls  *
     54  1.3.8.2  tls  *		Francis Demierre <Francis (at) SwissMail.Com>
     55  1.3.8.2  tls  * 		Thu May 15 17:15:40 MET DST 1997
     56  1.3.8.2  tls  *
     57  1.3.8.2  tls  *
     58  1.3.8.2  tls  *      Added -r "report file" switch & REPORT keyword.
     59  1.3.8.2  tls  *              Robert Geer <bgeer (at) xmission.com>
     60  1.3.8.2  tls  *
     61  1.3.8.2  tls  *      Added -s "use stderr" and -S "don't use syslog" switches.
     62  1.3.8.2  tls  *              June 18, 1997
     63  1.3.8.2  tls  *              Karl O. Pinc <kop (at) meme.com>
     64  1.3.8.2  tls  *
     65  1.3.8.2  tls  *
     66  1.3.8.2  tls  *	Added -e "echo" switch & ECHO keyword
     67  1.3.8.2  tls  *		Dick Streefland <dicks (at) tasking.nl>
     68  1.3.8.2  tls  *
     69  1.3.8.2  tls  *
     70  1.3.8.2  tls  *	Considerable updates and modifications by
     71  1.3.8.2  tls  *		Al Longyear <longyear (at) pobox.com>
     72  1.3.8.2  tls  *		Paul Mackerras <paulus (at) cs.anu.edu.au>
     73  1.3.8.2  tls  *
     74  1.3.8.2  tls  *
     75  1.3.8.2  tls  *	The original author is:
     76  1.3.8.2  tls  *
     77  1.3.8.2  tls  *		Karl Fox <karl (at) MorningStar.Com>
     78  1.3.8.2  tls  *		Morning Star Technologies, Inc.
     79  1.3.8.2  tls  *		1760 Zollinger Road
     80  1.3.8.2  tls  *		Columbus, OH  43221
     81  1.3.8.2  tls  *		(614)451-1883
     82  1.3.8.2  tls  *
     83  1.3.8.2  tls  */
     84  1.3.8.2  tls 
     85  1.3.8.2  tls #ifndef __STDC__
     86  1.3.8.2  tls #define const
     87  1.3.8.2  tls #endif
     88  1.3.8.2  tls #include <sys/cdefs.h>
     89  1.3.8.2  tls #if 0
     90  1.3.8.2  tls #ifndef lint
     91  1.3.8.2  tls static const char rcsid[] = "Id: chat.c,v 1.30 2004/01/17 05:47:55 carlsonj Exp ";
     92  1.3.8.2  tls #endif
     93  1.3.8.2  tls #else
     94  1.3.8.2  tls __RCSID("$NetBSD: chat.c,v 1.3.8.2 2014/08/19 23:52:11 tls Exp $");
     95  1.3.8.2  tls #endif
     96  1.3.8.2  tls 
     97  1.3.8.2  tls #include <stdio.h>
     98  1.3.8.2  tls #include <ctype.h>
     99  1.3.8.2  tls #include <time.h>
    100  1.3.8.2  tls #include <fcntl.h>
    101  1.3.8.2  tls #include <signal.h>
    102  1.3.8.2  tls #include <errno.h>
    103  1.3.8.2  tls #include <string.h>
    104  1.3.8.2  tls #include <stdlib.h>
    105  1.3.8.2  tls #include <unistd.h>
    106  1.3.8.2  tls #include <sys/types.h>
    107  1.3.8.2  tls #include <sys/stat.h>
    108  1.3.8.2  tls #include <syslog.h>
    109  1.3.8.2  tls 
    110  1.3.8.2  tls #ifndef TERMIO
    111  1.3.8.2  tls #undef	TERMIOS
    112  1.3.8.2  tls #define TERMIOS
    113  1.3.8.2  tls #endif
    114  1.3.8.2  tls 
    115  1.3.8.2  tls #ifdef TERMIO
    116  1.3.8.2  tls #include <termio.h>
    117  1.3.8.2  tls #endif
    118  1.3.8.2  tls #ifdef TERMIOS
    119  1.3.8.2  tls #include <termios.h>
    120  1.3.8.2  tls #endif
    121  1.3.8.2  tls 
    122  1.3.8.2  tls #define	STR_LEN	1024
    123  1.3.8.2  tls 
    124  1.3.8.2  tls #ifndef SIGTYPE
    125  1.3.8.2  tls #define SIGTYPE void
    126  1.3.8.2  tls #endif
    127  1.3.8.2  tls 
    128  1.3.8.2  tls #undef __P
    129  1.3.8.2  tls #undef __V
    130  1.3.8.2  tls 
    131  1.3.8.2  tls #ifdef __STDC__
    132  1.3.8.2  tls #include <stdarg.h>
    133  1.3.8.2  tls #define __V(x)	x
    134  1.3.8.2  tls #define __P(x)	x
    135  1.3.8.2  tls #else
    136  1.3.8.2  tls #include <varargs.h>
    137  1.3.8.2  tls #define __V(x)	(va_alist) va_dcl
    138  1.3.8.2  tls #define __P(x)	()
    139  1.3.8.2  tls #define const
    140  1.3.8.2  tls #endif
    141  1.3.8.2  tls 
    142  1.3.8.2  tls #ifndef O_NONBLOCK
    143  1.3.8.2  tls #define O_NONBLOCK	O_NDELAY
    144  1.3.8.2  tls #endif
    145  1.3.8.2  tls 
    146  1.3.8.2  tls #ifdef SUNOS
    147  1.3.8.2  tls extern int sys_nerr;
    148  1.3.8.2  tls extern char *sys_errlist[];
    149  1.3.8.2  tls #define memmove(to, from, n)	bcopy(from, to, n)
    150  1.3.8.2  tls #define strerror(n)		((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\
    151  1.3.8.2  tls 				 "unknown error")
    152  1.3.8.2  tls #endif
    153  1.3.8.2  tls 
    154  1.3.8.2  tls char *program_name;
    155  1.3.8.2  tls 
    156  1.3.8.2  tls #define	BUFFER_SIZE		256
    157  1.3.8.2  tls #define	MAX_ABORTS		50
    158  1.3.8.2  tls #define	MAX_REPORTS		50
    159  1.3.8.2  tls #define	DEFAULT_CHAT_TIMEOUT	45
    160  1.3.8.2  tls 
    161  1.3.8.2  tls int echo          = 0;
    162  1.3.8.2  tls int verbose       = 0;
    163  1.3.8.2  tls int to_log        = 1;
    164  1.3.8.2  tls int to_stderr     = 0;
    165  1.3.8.2  tls int Verbose       = 0;
    166  1.3.8.2  tls int quiet         = 0;
    167  1.3.8.2  tls int report        = 0;
    168  1.3.8.2  tls int use_env       = 0;
    169  1.3.8.2  tls int exit_code     = 0;
    170  1.3.8.2  tls FILE* report_fp   = (FILE *) 0;
    171  1.3.8.2  tls char *report_file = (char *) 0;
    172  1.3.8.2  tls char *chat_file   = (char *) 0;
    173  1.3.8.2  tls char *phone_num   = (char *) 0;
    174  1.3.8.2  tls char *phone_num2  = (char *) 0;
    175  1.3.8.2  tls int timeout       = DEFAULT_CHAT_TIMEOUT;
    176  1.3.8.2  tls 
    177  1.3.8.2  tls int have_tty_parameters = 0;
    178  1.3.8.2  tls 
    179  1.3.8.2  tls #ifdef TERMIO
    180  1.3.8.2  tls #define term_parms struct termio
    181  1.3.8.2  tls #define get_term_param(param) ioctl(0, TCGETA, param)
    182  1.3.8.2  tls #define set_term_param(param) ioctl(0, TCSETA, param)
    183  1.3.8.2  tls struct termio saved_tty_parameters;
    184  1.3.8.2  tls #endif
    185  1.3.8.2  tls 
    186  1.3.8.2  tls #ifdef TERMIOS
    187  1.3.8.2  tls #define term_parms struct termios
    188  1.3.8.2  tls #define get_term_param(param) tcgetattr(0, param)
    189  1.3.8.2  tls #define set_term_param(param) tcsetattr(0, TCSANOW, param)
    190  1.3.8.2  tls struct termios saved_tty_parameters;
    191  1.3.8.2  tls #endif
    192  1.3.8.2  tls 
    193  1.3.8.2  tls char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
    194  1.3.8.2  tls 	fail_buffer[BUFFER_SIZE];
    195  1.3.8.2  tls int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
    196  1.3.8.2  tls int clear_abort_next = 0;
    197  1.3.8.2  tls 
    198  1.3.8.2  tls char *report_string[MAX_REPORTS] ;
    199  1.3.8.2  tls char  report_buffer[BUFFER_SIZE] ;
    200  1.3.8.2  tls int n_reports = 0, report_next = 0, report_gathering = 0 ;
    201  1.3.8.2  tls int clear_report_next = 0;
    202  1.3.8.2  tls 
    203  1.3.8.2  tls int say_next = 0, hup_next = 0;
    204  1.3.8.2  tls 
    205  1.3.8.2  tls void *dup_mem __P((void *b, size_t c));
    206  1.3.8.2  tls void *copy_of __P((char *s));
    207  1.3.8.2  tls char *grow __P((char *s, char **p, size_t len));
    208  1.3.8.2  tls void usage __P((void));
    209  1.3.8.2  tls void msgf __P((const char *fmt, ...));
    210  1.3.8.2  tls void fatal __P((int code, const char *fmt, ...));
    211  1.3.8.2  tls SIGTYPE sigalrm __P((int signo));
    212  1.3.8.2  tls SIGTYPE sigint __P((int signo));
    213  1.3.8.2  tls SIGTYPE sigterm __P((int signo));
    214  1.3.8.2  tls SIGTYPE sighup __P((int signo));
    215  1.3.8.2  tls void unalarm __P((void));
    216  1.3.8.2  tls void init __P((void));
    217  1.3.8.2  tls void set_tty_parameters __P((void));
    218  1.3.8.2  tls void echo_stderr __P((int));
    219  1.3.8.2  tls void break_sequence __P((void));
    220  1.3.8.2  tls void terminate __P((int status));
    221  1.3.8.2  tls void do_file __P((char *chat_file));
    222  1.3.8.2  tls int  get_string __P((char *string));
    223  1.3.8.2  tls int  put_string __P((char *s));
    224  1.3.8.2  tls int  write_char __P((int c));
    225  1.3.8.2  tls int  put_char __P((int c));
    226  1.3.8.2  tls int  get_char __P((void));
    227  1.3.8.2  tls void chat_send __P((char *s));
    228  1.3.8.2  tls char *character __P((int c));
    229  1.3.8.2  tls void chat_expect __P((char *s));
    230  1.3.8.2  tls char *clean __P((char *s, int sending));
    231  1.3.8.2  tls void break_sequence __P((void));
    232  1.3.8.2  tls void terminate __P((int status));
    233  1.3.8.2  tls void pack_array __P((char **array, int end));
    234  1.3.8.2  tls char *expect_strtok __P((char *, char *));
    235  1.3.8.2  tls int vfmtmsg __P((char *, int, const char *, va_list));	/* vsprintf++ */
    236  1.3.8.2  tls 
    237  1.3.8.2  tls int main __P((int, char *[]));
    238  1.3.8.2  tls 
    239  1.3.8.2  tls void *dup_mem(b, c)
    240  1.3.8.2  tls void *b;
    241  1.3.8.2  tls size_t c;
    242  1.3.8.2  tls {
    243  1.3.8.2  tls     void *ans = malloc (c);
    244  1.3.8.2  tls     if (!ans)
    245  1.3.8.2  tls 	fatal(2, "memory error!");
    246  1.3.8.2  tls 
    247  1.3.8.2  tls     memcpy (ans, b, c);
    248  1.3.8.2  tls     return ans;
    249  1.3.8.2  tls }
    250  1.3.8.2  tls 
    251  1.3.8.2  tls void *copy_of (s)
    252  1.3.8.2  tls char *s;
    253  1.3.8.2  tls {
    254  1.3.8.2  tls     return dup_mem (s, strlen (s) + 1);
    255  1.3.8.2  tls }
    256  1.3.8.2  tls 
    257  1.3.8.2  tls /* grow a char buffer and keep a pointer offset */
    258  1.3.8.2  tls char *grow(s, p, len)
    259  1.3.8.2  tls char *s;
    260  1.3.8.2  tls char **p;
    261  1.3.8.2  tls size_t len;
    262  1.3.8.2  tls {
    263  1.3.8.2  tls     size_t l = *p - s;		/* save p as distance into s */
    264  1.3.8.2  tls 
    265  1.3.8.2  tls     s = realloc(s, len);
    266  1.3.8.2  tls     if (!s)
    267  1.3.8.2  tls 	fatal(2, "memory error!");
    268  1.3.8.2  tls     *p = s + l;			/* restore p */
    269  1.3.8.2  tls     return s;
    270  1.3.8.2  tls }
    271  1.3.8.2  tls 
    272  1.3.8.2  tls /*
    273  1.3.8.2  tls  * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \
    274  1.3.8.2  tls  * [ -r report-file ] \
    275  1.3.8.2  tls  *		[...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
    276  1.3.8.2  tls  *
    277  1.3.8.2  tls  *	Perform a UUCP-dialer-like chat script on stdin and stdout.
    278  1.3.8.2  tls  */
    279  1.3.8.2  tls int
    280  1.3.8.2  tls main(argc, argv)
    281  1.3.8.2  tls      int argc;
    282  1.3.8.2  tls      char **argv;
    283  1.3.8.2  tls {
    284  1.3.8.2  tls     int option;
    285  1.3.8.2  tls     int i;
    286  1.3.8.2  tls 
    287  1.3.8.2  tls     program_name = *argv;
    288  1.3.8.2  tls     tzset();
    289  1.3.8.2  tls 
    290  1.3.8.2  tls     while ((option = getopt(argc, argv, ":eEvVf:t:r:sST:U:")) != -1) {
    291  1.3.8.2  tls 	switch (option) {
    292  1.3.8.2  tls 	case 'e':
    293  1.3.8.2  tls 	    ++echo;
    294  1.3.8.2  tls 	    break;
    295  1.3.8.2  tls 
    296  1.3.8.2  tls 	case 'E':
    297  1.3.8.2  tls 	    ++use_env;
    298  1.3.8.2  tls 	    break;
    299  1.3.8.2  tls 
    300  1.3.8.2  tls 	case 'v':
    301  1.3.8.2  tls 	    ++verbose;
    302  1.3.8.2  tls 	    break;
    303  1.3.8.2  tls 
    304  1.3.8.2  tls 	case 'V':
    305  1.3.8.2  tls 	    ++Verbose;
    306  1.3.8.2  tls 	    break;
    307  1.3.8.2  tls 
    308  1.3.8.2  tls 	case 's':
    309  1.3.8.2  tls 	    ++to_stderr;
    310  1.3.8.2  tls 	    break;
    311  1.3.8.2  tls 
    312  1.3.8.2  tls 	case 'S':
    313  1.3.8.2  tls 	    to_log = 0;
    314  1.3.8.2  tls 	    break;
    315  1.3.8.2  tls 
    316  1.3.8.2  tls 	case 'f':
    317  1.3.8.2  tls 	    if (optarg != NULL)
    318  1.3.8.2  tls 		    chat_file = copy_of(optarg);
    319  1.3.8.2  tls 	    else
    320  1.3.8.2  tls 		usage();
    321  1.3.8.2  tls 	    break;
    322  1.3.8.2  tls 
    323  1.3.8.2  tls 	case 't':
    324  1.3.8.2  tls 	    if (optarg != NULL)
    325  1.3.8.2  tls 		timeout = atoi(optarg);
    326  1.3.8.2  tls 	    else
    327  1.3.8.2  tls 		usage();
    328  1.3.8.2  tls 	    break;
    329  1.3.8.2  tls 
    330  1.3.8.2  tls 	case 'r':
    331  1.3.8.2  tls 	    if (optarg) {
    332  1.3.8.2  tls 		if (report_fp != NULL)
    333  1.3.8.2  tls 		    fclose (report_fp);
    334  1.3.8.2  tls 		report_file = copy_of (optarg);
    335  1.3.8.2  tls 		report_fp   = fopen (report_file, "a");
    336  1.3.8.2  tls 		if (report_fp != NULL) {
    337  1.3.8.2  tls 		    if (verbose)
    338  1.3.8.2  tls 			fprintf (report_fp, "Opening \"%s\"...\n",
    339  1.3.8.2  tls 				 report_file);
    340  1.3.8.2  tls 		    report = 1;
    341  1.3.8.2  tls 		}
    342  1.3.8.2  tls 	    }
    343  1.3.8.2  tls 	    break;
    344  1.3.8.2  tls 
    345  1.3.8.2  tls 	case 'T':
    346  1.3.8.2  tls 	    if (optarg != NULL)
    347  1.3.8.2  tls 		phone_num = copy_of(optarg);
    348  1.3.8.2  tls 	    else
    349  1.3.8.2  tls 		usage();
    350  1.3.8.2  tls 	    break;
    351  1.3.8.2  tls 
    352  1.3.8.2  tls 	case 'U':
    353  1.3.8.2  tls 	    if (optarg != NULL)
    354  1.3.8.2  tls 		phone_num2 = copy_of(optarg);
    355  1.3.8.2  tls 	    else
    356  1.3.8.2  tls 		usage();
    357  1.3.8.2  tls 	    break;
    358  1.3.8.2  tls 
    359  1.3.8.2  tls 	default:
    360  1.3.8.2  tls 	    usage();
    361  1.3.8.2  tls 	    break;
    362  1.3.8.2  tls 	}
    363  1.3.8.2  tls     }
    364  1.3.8.2  tls     argc -= optind;
    365  1.3.8.2  tls     argv += optind;
    366  1.3.8.2  tls /*
    367  1.3.8.2  tls  * Default the report file to the stderr location
    368  1.3.8.2  tls  */
    369  1.3.8.2  tls     if (report_fp == NULL)
    370  1.3.8.2  tls 	report_fp = stderr;
    371  1.3.8.2  tls 
    372  1.3.8.2  tls     if (to_log) {
    373  1.3.8.2  tls #ifdef ultrix
    374  1.3.8.2  tls 	openlog("chat", LOG_PID);
    375  1.3.8.2  tls #else
    376  1.3.8.2  tls 	openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
    377  1.3.8.2  tls 
    378  1.3.8.2  tls 	if (verbose)
    379  1.3.8.2  tls 	    setlogmask(LOG_UPTO(LOG_INFO));
    380  1.3.8.2  tls 	else
    381  1.3.8.2  tls 	    setlogmask(LOG_UPTO(LOG_WARNING));
    382  1.3.8.2  tls #endif
    383  1.3.8.2  tls     }
    384  1.3.8.2  tls 
    385  1.3.8.2  tls     init();
    386  1.3.8.2  tls 
    387  1.3.8.2  tls     if (chat_file != NULL) {
    388  1.3.8.2  tls 	if (argc)
    389  1.3.8.2  tls 	    usage();
    390  1.3.8.2  tls 	else
    391  1.3.8.2  tls 	    do_file (chat_file);
    392  1.3.8.2  tls     } else {
    393  1.3.8.2  tls 	for (i = 0; i < argc; i++) {
    394  1.3.8.2  tls 	    chat_expect(argv[i]);
    395  1.3.8.2  tls 	    if (++i < argc)
    396  1.3.8.2  tls 		chat_send(argv[i]);
    397  1.3.8.2  tls 	}
    398  1.3.8.2  tls     }
    399  1.3.8.2  tls 
    400  1.3.8.2  tls     terminate(0);
    401  1.3.8.2  tls     return 0;
    402  1.3.8.2  tls }
    403  1.3.8.2  tls 
    404  1.3.8.2  tls /*
    405  1.3.8.2  tls  *  Process a chat script when read from a file.
    406  1.3.8.2  tls  */
    407  1.3.8.2  tls 
    408  1.3.8.2  tls void do_file (chat_file)
    409  1.3.8.2  tls char *chat_file;
    410  1.3.8.2  tls {
    411  1.3.8.2  tls     int linect, sendflg;
    412  1.3.8.2  tls     char *sp, *arg, quote;
    413  1.3.8.2  tls     char buf [STR_LEN];
    414  1.3.8.2  tls     FILE *cfp;
    415  1.3.8.2  tls 
    416  1.3.8.2  tls     cfp = fopen (chat_file, "r");
    417  1.3.8.2  tls     if (cfp == NULL)
    418  1.3.8.2  tls 	fatal(1, "%s -- open failed: %m", chat_file);
    419  1.3.8.2  tls 
    420  1.3.8.2  tls     linect = 0;
    421  1.3.8.2  tls     sendflg = 0;
    422  1.3.8.2  tls 
    423  1.3.8.2  tls     while (fgets(buf, STR_LEN, cfp) != NULL) {
    424  1.3.8.2  tls 	sp = strchr (buf, '\n');
    425  1.3.8.2  tls 	if (sp)
    426  1.3.8.2  tls 	    *sp = '\0';
    427  1.3.8.2  tls 
    428  1.3.8.2  tls 	linect++;
    429  1.3.8.2  tls 	sp = buf;
    430  1.3.8.2  tls 
    431  1.3.8.2  tls         /* lines starting with '#' are comments. If a real '#'
    432  1.3.8.2  tls            is to be expected, it should be quoted .... */
    433  1.3.8.2  tls         if ( *sp == '#' )
    434  1.3.8.2  tls 	    continue;
    435  1.3.8.2  tls 
    436  1.3.8.2  tls 	while (*sp != '\0') {
    437  1.3.8.2  tls 	    if (*sp == ' ' || *sp == '\t') {
    438  1.3.8.2  tls 		++sp;
    439  1.3.8.2  tls 		continue;
    440  1.3.8.2  tls 	    }
    441  1.3.8.2  tls 
    442  1.3.8.2  tls 	    if (*sp == '"' || *sp == '\'') {
    443  1.3.8.2  tls 		quote = *sp++;
    444  1.3.8.2  tls 		arg = sp;
    445  1.3.8.2  tls 		while (*sp != quote) {
    446  1.3.8.2  tls 		    if (*sp == '\0')
    447  1.3.8.2  tls 			fatal(1, "unterminated quote (line %d)", linect);
    448  1.3.8.2  tls 
    449  1.3.8.2  tls 		    if (*sp++ == '\\') {
    450  1.3.8.2  tls 			if (*sp != '\0')
    451  1.3.8.2  tls 			    ++sp;
    452  1.3.8.2  tls 		    }
    453  1.3.8.2  tls 		}
    454  1.3.8.2  tls 	    }
    455  1.3.8.2  tls 	    else {
    456  1.3.8.2  tls 		arg = sp;
    457  1.3.8.2  tls 		while (*sp != '\0' && *sp != ' ' && *sp != '\t')
    458  1.3.8.2  tls 		    ++sp;
    459  1.3.8.2  tls 	    }
    460  1.3.8.2  tls 
    461  1.3.8.2  tls 	    if (*sp != '\0')
    462  1.3.8.2  tls 		*sp++ = '\0';
    463  1.3.8.2  tls 
    464  1.3.8.2  tls 	    if (sendflg)
    465  1.3.8.2  tls 		chat_send (arg);
    466  1.3.8.2  tls 	    else
    467  1.3.8.2  tls 		chat_expect (arg);
    468  1.3.8.2  tls 	    sendflg = !sendflg;
    469  1.3.8.2  tls 	}
    470  1.3.8.2  tls     }
    471  1.3.8.2  tls     fclose (cfp);
    472  1.3.8.2  tls }
    473  1.3.8.2  tls 
    474  1.3.8.2  tls /*
    475  1.3.8.2  tls  *	We got an error parsing the command line.
    476  1.3.8.2  tls  */
    477  1.3.8.2  tls void usage()
    478  1.3.8.2  tls {
    479  1.3.8.2  tls     fprintf(stderr, "\
    480  1.3.8.2  tls Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\
    481  1.3.8.2  tls      [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name);
    482  1.3.8.2  tls     exit(1);
    483  1.3.8.2  tls }
    484  1.3.8.2  tls 
    485  1.3.8.2  tls char line[1024];
    486  1.3.8.2  tls 
    487  1.3.8.2  tls /*
    488  1.3.8.2  tls  * Send a message to syslog and/or stderr.
    489  1.3.8.2  tls  */
    490  1.3.8.2  tls void msgf __V((const char *fmt, ...))
    491  1.3.8.2  tls {
    492  1.3.8.2  tls     va_list args;
    493  1.3.8.2  tls 
    494  1.3.8.2  tls #ifdef __STDC__
    495  1.3.8.2  tls     va_start(args, fmt);
    496  1.3.8.2  tls #else
    497  1.3.8.2  tls     char *fmt;
    498  1.3.8.2  tls     va_start(args);
    499  1.3.8.2  tls     fmt = va_arg(args, char *);
    500  1.3.8.2  tls #endif
    501  1.3.8.2  tls 
    502  1.3.8.2  tls     vfmtmsg(line, sizeof(line), fmt, args);
    503  1.3.8.2  tls     va_end(args);
    504  1.3.8.2  tls     if (to_log)
    505  1.3.8.2  tls 	syslog(LOG_INFO, "%s", line);
    506  1.3.8.2  tls     if (to_stderr)
    507  1.3.8.2  tls 	fprintf(stderr, "%s\n", line);
    508  1.3.8.2  tls }
    509  1.3.8.2  tls 
    510  1.3.8.2  tls /*
    511  1.3.8.2  tls  *	Print an error message and terminate.
    512  1.3.8.2  tls  */
    513  1.3.8.2  tls 
    514  1.3.8.2  tls void fatal __V((int code, const char *fmt, ...))
    515  1.3.8.2  tls {
    516  1.3.8.2  tls     va_list args;
    517  1.3.8.2  tls 
    518  1.3.8.2  tls #ifdef __STDC__
    519  1.3.8.2  tls     va_start(args, fmt);
    520  1.3.8.2  tls #else
    521  1.3.8.2  tls     int code;
    522  1.3.8.2  tls     char *fmt;
    523  1.3.8.2  tls     va_start(args);
    524  1.3.8.2  tls     code = va_arg(args, int);
    525  1.3.8.2  tls     fmt = va_arg(args, char *);
    526  1.3.8.2  tls #endif
    527  1.3.8.2  tls 
    528  1.3.8.2  tls     vfmtmsg(line, sizeof(line), fmt, args);
    529  1.3.8.2  tls     va_end(args);
    530  1.3.8.2  tls     if (to_log)
    531  1.3.8.2  tls 	syslog(LOG_ERR, "%s", line);
    532  1.3.8.2  tls     if (to_stderr)
    533  1.3.8.2  tls 	fprintf(stderr, "%s\n", line);
    534  1.3.8.2  tls     terminate(code);
    535  1.3.8.2  tls }
    536  1.3.8.2  tls 
    537  1.3.8.2  tls int alarmed = 0;
    538  1.3.8.2  tls 
    539  1.3.8.2  tls SIGTYPE sigalrm(signo)
    540  1.3.8.2  tls int signo;
    541  1.3.8.2  tls {
    542  1.3.8.2  tls     int flags;
    543  1.3.8.2  tls 
    544  1.3.8.2  tls     alarm(1);
    545  1.3.8.2  tls     alarmed = 1;		/* Reset alarm to avoid race window */
    546  1.3.8.2  tls     signal(SIGALRM, sigalrm);	/* that can cause hanging in read() */
    547  1.3.8.2  tls 
    548  1.3.8.2  tls     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
    549  1.3.8.2  tls 	fatal(2, "Can't get file mode flags on stdin: %m");
    550  1.3.8.2  tls 
    551  1.3.8.2  tls     if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
    552  1.3.8.2  tls 	fatal(2, "Can't set file mode flags on stdin: %m");
    553  1.3.8.2  tls 
    554  1.3.8.2  tls     if (verbose)
    555  1.3.8.2  tls 	msgf("alarm");
    556  1.3.8.2  tls }
    557  1.3.8.2  tls 
    558  1.3.8.2  tls void unalarm()
    559  1.3.8.2  tls {
    560  1.3.8.2  tls     int flags;
    561  1.3.8.2  tls 
    562  1.3.8.2  tls     if ((flags = fcntl(0, F_GETFL, 0)) == -1)
    563  1.3.8.2  tls 	fatal(2, "Can't get file mode flags on stdin: %m");
    564  1.3.8.2  tls 
    565  1.3.8.2  tls     if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
    566  1.3.8.2  tls 	fatal(2, "Can't set file mode flags on stdin: %m");
    567  1.3.8.2  tls }
    568  1.3.8.2  tls 
    569  1.3.8.2  tls SIGTYPE sigint(signo)
    570  1.3.8.2  tls int signo;
    571  1.3.8.2  tls {
    572  1.3.8.2  tls     fatal(2, "SIGINT");
    573  1.3.8.2  tls }
    574  1.3.8.2  tls 
    575  1.3.8.2  tls SIGTYPE sigterm(signo)
    576  1.3.8.2  tls int signo;
    577  1.3.8.2  tls {
    578  1.3.8.2  tls     fatal(2, "SIGTERM");
    579  1.3.8.2  tls }
    580  1.3.8.2  tls 
    581  1.3.8.2  tls SIGTYPE sighup(signo)
    582  1.3.8.2  tls int signo;
    583  1.3.8.2  tls {
    584  1.3.8.2  tls     fatal(2, "SIGHUP");
    585  1.3.8.2  tls }
    586  1.3.8.2  tls 
    587  1.3.8.2  tls void init()
    588  1.3.8.2  tls {
    589  1.3.8.2  tls     signal(SIGINT, sigint);
    590  1.3.8.2  tls     signal(SIGTERM, sigterm);
    591  1.3.8.2  tls     signal(SIGHUP, sighup);
    592  1.3.8.2  tls 
    593  1.3.8.2  tls     set_tty_parameters();
    594  1.3.8.2  tls     signal(SIGALRM, sigalrm);
    595  1.3.8.2  tls     alarm(0);
    596  1.3.8.2  tls     alarmed = 0;
    597  1.3.8.2  tls }
    598  1.3.8.2  tls 
    599  1.3.8.2  tls void set_tty_parameters()
    600  1.3.8.2  tls {
    601  1.3.8.2  tls #if defined(get_term_param)
    602  1.3.8.2  tls     term_parms t;
    603  1.3.8.2  tls 
    604  1.3.8.2  tls     if (get_term_param (&t) < 0)
    605  1.3.8.2  tls 	fatal(2, "Can't get terminal parameters: %m");
    606  1.3.8.2  tls 
    607  1.3.8.2  tls     saved_tty_parameters = t;
    608  1.3.8.2  tls     have_tty_parameters  = 1;
    609  1.3.8.2  tls 
    610  1.3.8.2  tls     t.c_iflag     |= IGNBRK | ISTRIP | IGNPAR;
    611  1.3.8.2  tls     t.c_oflag     |= OPOST | ONLCR;
    612  1.3.8.2  tls     t.c_lflag      = 0;
    613  1.3.8.2  tls     t.c_cc[VERASE] =
    614  1.3.8.2  tls     t.c_cc[VKILL]  = 0;
    615  1.3.8.2  tls     t.c_cc[VMIN]   = 1;
    616  1.3.8.2  tls     t.c_cc[VTIME]  = 0;
    617  1.3.8.2  tls 
    618  1.3.8.2  tls     if (set_term_param (&t) < 0)
    619  1.3.8.2  tls 	fatal(2, "Can't set terminal parameters: %m");
    620  1.3.8.2  tls #endif
    621  1.3.8.2  tls }
    622  1.3.8.2  tls 
    623  1.3.8.2  tls void break_sequence()
    624  1.3.8.2  tls {
    625  1.3.8.2  tls #ifdef TERMIOS
    626  1.3.8.2  tls     tcsendbreak (0, 0);
    627  1.3.8.2  tls #endif
    628  1.3.8.2  tls }
    629  1.3.8.2  tls 
    630  1.3.8.2  tls void terminate(status)
    631  1.3.8.2  tls int status;
    632  1.3.8.2  tls {
    633  1.3.8.2  tls     static int terminating = 0;
    634  1.3.8.2  tls 
    635  1.3.8.2  tls     if (terminating)
    636  1.3.8.2  tls 	exit(status);
    637  1.3.8.2  tls     terminating = 1;
    638  1.3.8.2  tls     echo_stderr(-1);
    639  1.3.8.2  tls /*
    640  1.3.8.2  tls  * Allow the last of the report string to be gathered before we terminate.
    641  1.3.8.2  tls  */
    642  1.3.8.2  tls     if (report_gathering) {
    643  1.3.8.2  tls 	int c, rep_len;
    644  1.3.8.2  tls 
    645  1.3.8.2  tls 	rep_len = strlen(report_buffer);
    646  1.3.8.2  tls 	while (rep_len < sizeof(report_buffer) - 1) {
    647  1.3.8.2  tls 	    alarm(1);
    648  1.3.8.2  tls 	    c = get_char();
    649  1.3.8.2  tls 	    alarm(0);
    650  1.3.8.2  tls 	    if (c < 0 || iscntrl(c))
    651  1.3.8.2  tls 		break;
    652  1.3.8.2  tls 	    report_buffer[rep_len] = c;
    653  1.3.8.2  tls 	    ++rep_len;
    654  1.3.8.2  tls 	}
    655  1.3.8.2  tls 	report_buffer[rep_len] = 0;
    656  1.3.8.2  tls 	fprintf (report_fp, "chat:  %s\n", report_buffer);
    657  1.3.8.2  tls     }
    658  1.3.8.2  tls     if (report_file != (char *) 0 && report_fp != (FILE *) NULL) {
    659  1.3.8.2  tls 	if (verbose)
    660  1.3.8.2  tls 	    fprintf (report_fp, "Closing \"%s\".\n", report_file);
    661  1.3.8.2  tls 	fclose (report_fp);
    662  1.3.8.2  tls 	report_fp = (FILE *) NULL;
    663  1.3.8.2  tls     }
    664  1.3.8.2  tls 
    665  1.3.8.2  tls #if defined(get_term_param)
    666  1.3.8.2  tls     if (have_tty_parameters) {
    667  1.3.8.2  tls 	if (set_term_param (&saved_tty_parameters) < 0)
    668  1.3.8.2  tls 	    fatal(2, "Can't restore terminal parameters: %m");
    669  1.3.8.2  tls     }
    670  1.3.8.2  tls #endif
    671  1.3.8.2  tls 
    672  1.3.8.2  tls     exit(status);
    673  1.3.8.2  tls }
    674  1.3.8.2  tls 
    675  1.3.8.2  tls /*
    676  1.3.8.2  tls  *	'Clean up' this string.
    677  1.3.8.2  tls  */
    678  1.3.8.2  tls char *clean(s, sending)
    679  1.3.8.2  tls char *s;
    680  1.3.8.2  tls int sending;  /* set to 1 when sending (putting) this string. */
    681  1.3.8.2  tls {
    682  1.3.8.2  tls     char cur_chr;
    683  1.3.8.2  tls     char *s1, *p, *phchar;
    684  1.3.8.2  tls     int add_return = sending;
    685  1.3.8.2  tls     size_t len = strlen(s) + 3;		/* see len comments below */
    686  1.3.8.2  tls 
    687  1.3.8.2  tls #define isoctal(chr)	(((chr) >= '0') && ((chr) <= '7'))
    688  1.3.8.2  tls #define isalnumx(chr)	((((chr) >= '0') && ((chr) <= '9')) \
    689  1.3.8.2  tls 			 || (((chr) >= 'a') && ((chr) <= 'z')) \
    690  1.3.8.2  tls 			 || (((chr) >= 'A') && ((chr) <= 'Z')) \
    691  1.3.8.2  tls 			 || (chr) == '_')
    692  1.3.8.2  tls 
    693  1.3.8.2  tls     p = s1 = malloc(len);
    694  1.3.8.2  tls     if (!p)
    695  1.3.8.2  tls 	fatal(2, "memory error!");
    696  1.3.8.2  tls     while (*s) {
    697  1.3.8.2  tls 	cur_chr = *s++;
    698  1.3.8.2  tls 	if (cur_chr == '^') {
    699  1.3.8.2  tls 	    cur_chr = *s++;
    700  1.3.8.2  tls 	    if (cur_chr == '\0') {
    701  1.3.8.2  tls 		*p++ = '^';
    702  1.3.8.2  tls 		break;
    703  1.3.8.2  tls 	    }
    704  1.3.8.2  tls 	    cur_chr &= 0x1F;
    705  1.3.8.2  tls 	    if (cur_chr != 0) {
    706  1.3.8.2  tls 		*p++ = cur_chr;
    707  1.3.8.2  tls 	    }
    708  1.3.8.2  tls 	    continue;
    709  1.3.8.2  tls 	}
    710  1.3.8.2  tls 
    711  1.3.8.2  tls 	if (use_env && cur_chr == '$') {		/* ARI */
    712  1.3.8.2  tls 	    char c;
    713  1.3.8.2  tls 
    714  1.3.8.2  tls 	    phchar = s;
    715  1.3.8.2  tls 	    while (isalnumx(*s))
    716  1.3.8.2  tls 		s++;
    717  1.3.8.2  tls 	    c = *s;		/* save */
    718  1.3.8.2  tls 	    *s = '\0';
    719  1.3.8.2  tls 	    phchar = getenv(phchar);
    720  1.3.8.2  tls 	    *s = c;		/* restore */
    721  1.3.8.2  tls 	    if (phchar) {
    722  1.3.8.2  tls 		len += strlen(phchar);
    723  1.3.8.2  tls 		s1 = grow(s1, &p, len);
    724  1.3.8.2  tls 		while (*phchar)
    725  1.3.8.2  tls 		    *p++ = *phchar++;
    726  1.3.8.2  tls 	    }
    727  1.3.8.2  tls 	    continue;
    728  1.3.8.2  tls 	}
    729  1.3.8.2  tls 
    730  1.3.8.2  tls 	if (cur_chr != '\\') {
    731  1.3.8.2  tls 	    *p++ = cur_chr;
    732  1.3.8.2  tls 	    continue;
    733  1.3.8.2  tls 	}
    734  1.3.8.2  tls 
    735  1.3.8.2  tls 	cur_chr = *s++;
    736  1.3.8.2  tls 	if (cur_chr == '\0') {
    737  1.3.8.2  tls 	    if (sending) {
    738  1.3.8.2  tls 		*p++ = '\\';
    739  1.3.8.2  tls 		*p++ = '\\';	/* +1 for len */
    740  1.3.8.2  tls 	    }
    741  1.3.8.2  tls 	    break;
    742  1.3.8.2  tls 	}
    743  1.3.8.2  tls 
    744  1.3.8.2  tls 	switch (cur_chr) {
    745  1.3.8.2  tls 	case 'b':
    746  1.3.8.2  tls 	    *p++ = '\b';
    747  1.3.8.2  tls 	    break;
    748  1.3.8.2  tls 
    749  1.3.8.2  tls 	case 'c':
    750  1.3.8.2  tls 	    if (sending && *s == '\0')
    751  1.3.8.2  tls 		add_return = 0;
    752  1.3.8.2  tls 	    else
    753  1.3.8.2  tls 		*p++ = cur_chr;
    754  1.3.8.2  tls 	    break;
    755  1.3.8.2  tls 
    756  1.3.8.2  tls 	case '\\':
    757  1.3.8.2  tls 	case 'K':
    758  1.3.8.2  tls 	case 'p':
    759  1.3.8.2  tls 	case 'd':
    760  1.3.8.2  tls 	    if (sending)
    761  1.3.8.2  tls 		*p++ = '\\';
    762  1.3.8.2  tls 	    *p++ = cur_chr;
    763  1.3.8.2  tls 	    break;
    764  1.3.8.2  tls 
    765  1.3.8.2  tls 	case 'T':
    766  1.3.8.2  tls 	    if (sending && phone_num) {
    767  1.3.8.2  tls 		len += strlen(phone_num);
    768  1.3.8.2  tls 		s1 = grow(s1, &p, len);
    769  1.3.8.2  tls 		for (phchar = phone_num; *phchar != '\0'; phchar++)
    770  1.3.8.2  tls 		    *p++ = *phchar;
    771  1.3.8.2  tls 	    }
    772  1.3.8.2  tls 	    else {
    773  1.3.8.2  tls 		*p++ = '\\';
    774  1.3.8.2  tls 		*p++ = 'T';
    775  1.3.8.2  tls 	    }
    776  1.3.8.2  tls 	    break;
    777  1.3.8.2  tls 
    778  1.3.8.2  tls 	case 'U':
    779  1.3.8.2  tls 	    if (sending && phone_num2) {
    780  1.3.8.2  tls 		len += strlen(phone_num2);
    781  1.3.8.2  tls 		s1 = grow(s1, &p, len);
    782  1.3.8.2  tls 		for (phchar = phone_num2; *phchar != '\0'; phchar++)
    783  1.3.8.2  tls 		    *p++ = *phchar;
    784  1.3.8.2  tls 	    }
    785  1.3.8.2  tls 	    else {
    786  1.3.8.2  tls 		*p++ = '\\';
    787  1.3.8.2  tls 		*p++ = 'U';
    788  1.3.8.2  tls 	    }
    789  1.3.8.2  tls 	    break;
    790  1.3.8.2  tls 
    791  1.3.8.2  tls 	case 'q':
    792  1.3.8.2  tls 	    quiet = 1;
    793  1.3.8.2  tls 	    break;
    794  1.3.8.2  tls 
    795  1.3.8.2  tls 	case 'r':
    796  1.3.8.2  tls 	    *p++ = '\r';
    797  1.3.8.2  tls 	    break;
    798  1.3.8.2  tls 
    799  1.3.8.2  tls 	case 'n':
    800  1.3.8.2  tls 	    *p++ = '\n';
    801  1.3.8.2  tls 	    break;
    802  1.3.8.2  tls 
    803  1.3.8.2  tls 	case 's':
    804  1.3.8.2  tls 	    *p++ = ' ';
    805  1.3.8.2  tls 	    break;
    806  1.3.8.2  tls 
    807  1.3.8.2  tls 	case 't':
    808  1.3.8.2  tls 	    *p++ = '\t';
    809  1.3.8.2  tls 	    break;
    810  1.3.8.2  tls 
    811  1.3.8.2  tls 	case 'N':
    812  1.3.8.2  tls 	    if (sending) {
    813  1.3.8.2  tls 		*p++ = '\\';
    814  1.3.8.2  tls 		*p++ = '\0';
    815  1.3.8.2  tls 	    }
    816  1.3.8.2  tls 	    else
    817  1.3.8.2  tls 		*p++ = 'N';
    818  1.3.8.2  tls 	    break;
    819  1.3.8.2  tls 
    820  1.3.8.2  tls 	case '$':			/* ARI */
    821  1.3.8.2  tls 	    if (use_env) {
    822  1.3.8.2  tls 		*p++ = cur_chr;
    823  1.3.8.2  tls 		break;
    824  1.3.8.2  tls 	    }
    825  1.3.8.2  tls 	    /* FALL THROUGH */
    826  1.3.8.2  tls 
    827  1.3.8.2  tls 	default:
    828  1.3.8.2  tls 	    if (isoctal (cur_chr)) {
    829  1.3.8.2  tls 		cur_chr &= 0x07;
    830  1.3.8.2  tls 		if (isoctal (*s)) {
    831  1.3.8.2  tls 		    cur_chr <<= 3;
    832  1.3.8.2  tls 		    cur_chr |= *s++ - '0';
    833  1.3.8.2  tls 		    if (isoctal (*s)) {
    834  1.3.8.2  tls 			cur_chr <<= 3;
    835  1.3.8.2  tls 			cur_chr |= *s++ - '0';
    836  1.3.8.2  tls 		    }
    837  1.3.8.2  tls 		}
    838  1.3.8.2  tls 
    839  1.3.8.2  tls 		if (cur_chr != 0 || sending) {
    840  1.3.8.2  tls 		    if (sending && (cur_chr == '\\' || cur_chr == 0))
    841  1.3.8.2  tls 			*p++ = '\\';
    842  1.3.8.2  tls 		    *p++ = cur_chr;
    843  1.3.8.2  tls 		}
    844  1.3.8.2  tls 		break;
    845  1.3.8.2  tls 	    }
    846  1.3.8.2  tls 
    847  1.3.8.2  tls 	    if (sending)
    848  1.3.8.2  tls 		*p++ = '\\';
    849  1.3.8.2  tls 	    *p++ = cur_chr;
    850  1.3.8.2  tls 	    break;
    851  1.3.8.2  tls 	}
    852  1.3.8.2  tls     }
    853  1.3.8.2  tls 
    854  1.3.8.2  tls     if (add_return)
    855  1.3.8.2  tls 	*p++ = '\r';	/* +2 for len */
    856  1.3.8.2  tls 
    857  1.3.8.2  tls     *p = '\0';		/* +3 for len */
    858  1.3.8.2  tls     return s1;
    859  1.3.8.2  tls }
    860  1.3.8.2  tls 
    861  1.3.8.2  tls /*
    862  1.3.8.2  tls  * A modified version of 'strtok'. This version skips \ sequences.
    863  1.3.8.2  tls  */
    864  1.3.8.2  tls 
    865  1.3.8.2  tls char *expect_strtok (s, term)
    866  1.3.8.2  tls      char *s, *term;
    867  1.3.8.2  tls {
    868  1.3.8.2  tls     static  char *str   = "";
    869  1.3.8.2  tls     int	    escape_flag = 0;
    870  1.3.8.2  tls     char   *result;
    871  1.3.8.2  tls 
    872  1.3.8.2  tls /*
    873  1.3.8.2  tls  * If a string was specified then do initial processing.
    874  1.3.8.2  tls  */
    875  1.3.8.2  tls     if (s)
    876  1.3.8.2  tls 	str = s;
    877  1.3.8.2  tls 
    878  1.3.8.2  tls /*
    879  1.3.8.2  tls  * If this is the escape flag then reset it and ignore the character.
    880  1.3.8.2  tls  */
    881  1.3.8.2  tls     if (*str)
    882  1.3.8.2  tls 	result = str;
    883  1.3.8.2  tls     else
    884  1.3.8.2  tls 	result = (char *) 0;
    885  1.3.8.2  tls 
    886  1.3.8.2  tls     while (*str) {
    887  1.3.8.2  tls 	if (escape_flag) {
    888  1.3.8.2  tls 	    escape_flag = 0;
    889  1.3.8.2  tls 	    ++str;
    890  1.3.8.2  tls 	    continue;
    891  1.3.8.2  tls 	}
    892  1.3.8.2  tls 
    893  1.3.8.2  tls 	if (*str == '\\') {
    894  1.3.8.2  tls 	    ++str;
    895  1.3.8.2  tls 	    escape_flag = 1;
    896  1.3.8.2  tls 	    continue;
    897  1.3.8.2  tls 	}
    898  1.3.8.2  tls 
    899  1.3.8.2  tls /*
    900  1.3.8.2  tls  * If this is not in the termination string, continue.
    901  1.3.8.2  tls  */
    902  1.3.8.2  tls 	if (strchr (term, *str) == (char *) 0) {
    903  1.3.8.2  tls 	    ++str;
    904  1.3.8.2  tls 	    continue;
    905  1.3.8.2  tls 	}
    906  1.3.8.2  tls 
    907  1.3.8.2  tls /*
    908  1.3.8.2  tls  * This is the terminator. Mark the end of the string and stop.
    909  1.3.8.2  tls  */
    910  1.3.8.2  tls 	*str++ = '\0';
    911  1.3.8.2  tls 	break;
    912  1.3.8.2  tls     }
    913  1.3.8.2  tls     return (result);
    914  1.3.8.2  tls }
    915  1.3.8.2  tls 
    916  1.3.8.2  tls /*
    917  1.3.8.2  tls  * Process the expect string
    918  1.3.8.2  tls  */
    919  1.3.8.2  tls 
    920  1.3.8.2  tls void chat_expect (s)
    921  1.3.8.2  tls char *s;
    922  1.3.8.2  tls {
    923  1.3.8.2  tls     char *expect;
    924  1.3.8.2  tls     char *reply;
    925  1.3.8.2  tls 
    926  1.3.8.2  tls     if (strcmp(s, "HANGUP") == 0) {
    927  1.3.8.2  tls 	++hup_next;
    928  1.3.8.2  tls         return;
    929  1.3.8.2  tls     }
    930  1.3.8.2  tls 
    931  1.3.8.2  tls     if (strcmp(s, "ABORT") == 0) {
    932  1.3.8.2  tls 	++abort_next;
    933  1.3.8.2  tls 	return;
    934  1.3.8.2  tls     }
    935  1.3.8.2  tls 
    936  1.3.8.2  tls     if (strcmp(s, "CLR_ABORT") == 0) {
    937  1.3.8.2  tls 	++clear_abort_next;
    938  1.3.8.2  tls 	return;
    939  1.3.8.2  tls     }
    940  1.3.8.2  tls 
    941  1.3.8.2  tls     if (strcmp(s, "REPORT") == 0) {
    942  1.3.8.2  tls 	++report_next;
    943  1.3.8.2  tls 	return;
    944  1.3.8.2  tls     }
    945  1.3.8.2  tls 
    946  1.3.8.2  tls     if (strcmp(s, "CLR_REPORT") == 0) {
    947  1.3.8.2  tls 	++clear_report_next;
    948  1.3.8.2  tls 	return;
    949  1.3.8.2  tls     }
    950  1.3.8.2  tls 
    951  1.3.8.2  tls     if (strcmp(s, "TIMEOUT") == 0) {
    952  1.3.8.2  tls 	++timeout_next;
    953  1.3.8.2  tls 	return;
    954  1.3.8.2  tls     }
    955  1.3.8.2  tls 
    956  1.3.8.2  tls     if (strcmp(s, "ECHO") == 0) {
    957  1.3.8.2  tls 	++echo_next;
    958  1.3.8.2  tls 	return;
    959  1.3.8.2  tls     }
    960  1.3.8.2  tls 
    961  1.3.8.2  tls     if (strcmp(s, "SAY") == 0) {
    962  1.3.8.2  tls 	++say_next;
    963  1.3.8.2  tls 	return;
    964  1.3.8.2  tls     }
    965  1.3.8.2  tls 
    966  1.3.8.2  tls /*
    967  1.3.8.2  tls  * Fetch the expect and reply string.
    968  1.3.8.2  tls  */
    969  1.3.8.2  tls     for (;;) {
    970  1.3.8.2  tls 	expect = expect_strtok (s, "-");
    971  1.3.8.2  tls 	s      = (char *) 0;
    972  1.3.8.2  tls 
    973  1.3.8.2  tls 	if (expect == (char *) 0)
    974  1.3.8.2  tls 	    return;
    975  1.3.8.2  tls 
    976  1.3.8.2  tls 	reply = expect_strtok (s, "-");
    977  1.3.8.2  tls 
    978  1.3.8.2  tls /*
    979  1.3.8.2  tls  * Handle the expect string. If successful then exit.
    980  1.3.8.2  tls  */
    981  1.3.8.2  tls 	if (get_string (expect))
    982  1.3.8.2  tls 	    return;
    983  1.3.8.2  tls 
    984  1.3.8.2  tls /*
    985  1.3.8.2  tls  * If there is a sub-reply string then send it. Otherwise any condition
    986  1.3.8.2  tls  * is terminal.
    987  1.3.8.2  tls  */
    988  1.3.8.2  tls 	if (reply == (char *) 0 || exit_code != 3)
    989  1.3.8.2  tls 	    break;
    990  1.3.8.2  tls 
    991  1.3.8.2  tls 	chat_send (reply);
    992  1.3.8.2  tls     }
    993  1.3.8.2  tls 
    994  1.3.8.2  tls /*
    995  1.3.8.2  tls  * The expectation did not occur. This is terminal.
    996  1.3.8.2  tls  */
    997  1.3.8.2  tls     if (fail_reason)
    998  1.3.8.2  tls 	msgf("Failed (%s)", fail_reason);
    999  1.3.8.2  tls     else
   1000  1.3.8.2  tls 	msgf("Failed");
   1001  1.3.8.2  tls     terminate(exit_code);
   1002  1.3.8.2  tls }
   1003  1.3.8.2  tls 
   1004  1.3.8.2  tls /*
   1005  1.3.8.2  tls  * Translate the input character to the appropriate string for printing
   1006  1.3.8.2  tls  * the data.
   1007  1.3.8.2  tls  */
   1008  1.3.8.2  tls 
   1009  1.3.8.2  tls char *character(c)
   1010  1.3.8.2  tls int c;
   1011  1.3.8.2  tls {
   1012  1.3.8.2  tls     static char string[10];
   1013  1.3.8.2  tls     char *meta;
   1014  1.3.8.2  tls 
   1015  1.3.8.2  tls     meta = (c & 0x80) ? "M-" : "";
   1016  1.3.8.2  tls     c &= 0x7F;
   1017  1.3.8.2  tls 
   1018  1.3.8.2  tls     if (c < 32)
   1019  1.3.8.2  tls 	snprintf(string, sizeof(string), "%s^%c", meta, (int)c + '@');
   1020  1.3.8.2  tls     else if (c == 127)
   1021  1.3.8.2  tls 	snprintf(string, sizeof(string), "%s^?", meta);
   1022  1.3.8.2  tls     else
   1023  1.3.8.2  tls 	snprintf(string, sizeof(string), "%s%c", meta, c);
   1024  1.3.8.2  tls 
   1025  1.3.8.2  tls     return (string);
   1026  1.3.8.2  tls }
   1027  1.3.8.2  tls 
   1028  1.3.8.2  tls /*
   1029  1.3.8.2  tls  *  process the reply string
   1030  1.3.8.2  tls  */
   1031  1.3.8.2  tls void chat_send (s)
   1032  1.3.8.2  tls char *s;
   1033  1.3.8.2  tls {
   1034  1.3.8.2  tls     char file_data[STR_LEN];
   1035  1.3.8.2  tls 
   1036  1.3.8.2  tls     if (say_next) {
   1037  1.3.8.2  tls 	say_next = 0;
   1038  1.3.8.2  tls 	s = clean(s, 1);
   1039  1.3.8.2  tls 	write(2, s, strlen(s));
   1040  1.3.8.2  tls         free(s);
   1041  1.3.8.2  tls 	return;
   1042  1.3.8.2  tls     }
   1043  1.3.8.2  tls 
   1044  1.3.8.2  tls     if (hup_next) {
   1045  1.3.8.2  tls         hup_next = 0;
   1046  1.3.8.2  tls 	if (strcmp(s, "OFF") == 0)
   1047  1.3.8.2  tls            signal(SIGHUP, SIG_IGN);
   1048  1.3.8.2  tls         else
   1049  1.3.8.2  tls            signal(SIGHUP, sighup);
   1050  1.3.8.2  tls         return;
   1051  1.3.8.2  tls     }
   1052  1.3.8.2  tls 
   1053  1.3.8.2  tls     if (echo_next) {
   1054  1.3.8.2  tls 	echo_next = 0;
   1055  1.3.8.2  tls 	echo = (strcmp(s, "ON") == 0);
   1056  1.3.8.2  tls 	return;
   1057  1.3.8.2  tls     }
   1058  1.3.8.2  tls 
   1059  1.3.8.2  tls     if (abort_next) {
   1060  1.3.8.2  tls 	char *s1;
   1061  1.3.8.2  tls 
   1062  1.3.8.2  tls 	abort_next = 0;
   1063  1.3.8.2  tls 
   1064  1.3.8.2  tls 	if (n_aborts >= MAX_ABORTS)
   1065  1.3.8.2  tls 	    fatal(2, "Too many ABORT strings");
   1066  1.3.8.2  tls 
   1067  1.3.8.2  tls 	s1 = clean(s, 0);
   1068  1.3.8.2  tls 
   1069  1.3.8.2  tls 	if (strlen(s1) > strlen(s)
   1070  1.3.8.2  tls 	    || strlen(s1) + 1 > sizeof(fail_buffer))
   1071  1.3.8.2  tls 	    fatal(1, "Illegal or too-long ABORT string ('%v')", s);
   1072  1.3.8.2  tls 
   1073  1.3.8.2  tls 	abort_string[n_aborts++] = s1;
   1074  1.3.8.2  tls 
   1075  1.3.8.2  tls 	if (verbose)
   1076  1.3.8.2  tls 	    msgf("abort on (%v)", s);
   1077  1.3.8.2  tls 	return;
   1078  1.3.8.2  tls     }
   1079  1.3.8.2  tls 
   1080  1.3.8.2  tls     if (clear_abort_next) {
   1081  1.3.8.2  tls 	char *s1;
   1082  1.3.8.2  tls 	int   i;
   1083  1.3.8.2  tls         int   old_max;
   1084  1.3.8.2  tls 	int   pack = 0;
   1085  1.3.8.2  tls 
   1086  1.3.8.2  tls 	clear_abort_next = 0;
   1087  1.3.8.2  tls 
   1088  1.3.8.2  tls 	s1 = clean(s, 0);
   1089  1.3.8.2  tls 
   1090  1.3.8.2  tls 	if (strlen(s1) > strlen(s)
   1091  1.3.8.2  tls 	    || strlen(s1) + 1 > sizeof(fail_buffer))
   1092  1.3.8.2  tls 	    fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
   1093  1.3.8.2  tls 
   1094  1.3.8.2  tls         old_max = n_aborts;
   1095  1.3.8.2  tls 	for (i=0; i < n_aborts; i++) {
   1096  1.3.8.2  tls 	    if ( strcmp(s1,abort_string[i]) == 0 ) {
   1097  1.3.8.2  tls 		free(abort_string[i]);
   1098  1.3.8.2  tls 		abort_string[i] = NULL;
   1099  1.3.8.2  tls 		pack++;
   1100  1.3.8.2  tls 		n_aborts--;
   1101  1.3.8.2  tls 		if (verbose)
   1102  1.3.8.2  tls 		    msgf("clear abort on (%v)", s);
   1103  1.3.8.2  tls 	    }
   1104  1.3.8.2  tls 	}
   1105  1.3.8.2  tls         free(s1);
   1106  1.3.8.2  tls 	if (pack)
   1107  1.3.8.2  tls 	    pack_array(abort_string,old_max);
   1108  1.3.8.2  tls 	return;
   1109  1.3.8.2  tls     }
   1110  1.3.8.2  tls 
   1111  1.3.8.2  tls     if (report_next) {
   1112  1.3.8.2  tls 	char *s1;
   1113  1.3.8.2  tls 
   1114  1.3.8.2  tls 	report_next = 0;
   1115  1.3.8.2  tls 	if (n_reports >= MAX_REPORTS)
   1116  1.3.8.2  tls 	    fatal(2, "Too many REPORT strings");
   1117  1.3.8.2  tls 
   1118  1.3.8.2  tls 	s1 = clean(s, 0);
   1119  1.3.8.2  tls 	if (strlen(s1) > strlen(s)
   1120  1.3.8.2  tls 	    || strlen(s1) + 1 > sizeof(fail_buffer))
   1121  1.3.8.2  tls 	    fatal(1, "Illegal or too-long REPORT string ('%v')", s);
   1122  1.3.8.2  tls 
   1123  1.3.8.2  tls 	report_string[n_reports++] = s1;
   1124  1.3.8.2  tls 
   1125  1.3.8.2  tls 	if (verbose)
   1126  1.3.8.2  tls 	    msgf("report (%v)", s);
   1127  1.3.8.2  tls 	return;
   1128  1.3.8.2  tls     }
   1129  1.3.8.2  tls 
   1130  1.3.8.2  tls     if (clear_report_next) {
   1131  1.3.8.2  tls 	char *s1;
   1132  1.3.8.2  tls 	int   i;
   1133  1.3.8.2  tls 	int   old_max;
   1134  1.3.8.2  tls 	int   pack = 0;
   1135  1.3.8.2  tls 
   1136  1.3.8.2  tls 	clear_report_next = 0;
   1137  1.3.8.2  tls 
   1138  1.3.8.2  tls 	s1 = clean(s, 0);
   1139  1.3.8.2  tls 
   1140  1.3.8.2  tls 	if (strlen(s1) > strlen(s)
   1141  1.3.8.2  tls 	    || strlen(s1) + 1 > sizeof(fail_buffer))
   1142  1.3.8.2  tls 	    fatal(1, "Illegal or too-long REPORT string ('%v')", s);
   1143  1.3.8.2  tls 
   1144  1.3.8.2  tls 	old_max = n_reports;
   1145  1.3.8.2  tls 	for (i=0; i < n_reports; i++) {
   1146  1.3.8.2  tls 	    if ( strcmp(s1,report_string[i]) == 0 ) {
   1147  1.3.8.2  tls 		free(report_string[i]);
   1148  1.3.8.2  tls 		report_string[i] = NULL;
   1149  1.3.8.2  tls 		pack++;
   1150  1.3.8.2  tls 		n_reports--;
   1151  1.3.8.2  tls 		if (verbose)
   1152  1.3.8.2  tls 		    msgf("clear report (%v)", s);
   1153  1.3.8.2  tls 	    }
   1154  1.3.8.2  tls 	}
   1155  1.3.8.2  tls         free(s1);
   1156  1.3.8.2  tls         if (pack)
   1157  1.3.8.2  tls 	    pack_array(report_string,old_max);
   1158  1.3.8.2  tls 
   1159  1.3.8.2  tls 	return;
   1160  1.3.8.2  tls     }
   1161  1.3.8.2  tls 
   1162  1.3.8.2  tls     if (timeout_next) {
   1163  1.3.8.2  tls 	timeout_next = 0;
   1164  1.3.8.2  tls 	s = clean(s, 0);
   1165  1.3.8.2  tls 	timeout = atoi(s);
   1166  1.3.8.2  tls 	free(s);
   1167  1.3.8.2  tls 
   1168  1.3.8.2  tls 	if (timeout <= 0)
   1169  1.3.8.2  tls 	    timeout = DEFAULT_CHAT_TIMEOUT;
   1170  1.3.8.2  tls 
   1171  1.3.8.2  tls 	if (verbose)
   1172  1.3.8.2  tls 	    msgf("timeout set to %d seconds", timeout);
   1173  1.3.8.2  tls 
   1174  1.3.8.2  tls 	return;
   1175  1.3.8.2  tls     }
   1176  1.3.8.2  tls 
   1177  1.3.8.2  tls     /*
   1178  1.3.8.2  tls      * The syntax @filename means read the string to send from the
   1179  1.3.8.2  tls      * file `filename'.
   1180  1.3.8.2  tls      */
   1181  1.3.8.2  tls     if (s[0] == '@') {
   1182  1.3.8.2  tls 	/* skip the @ and any following white-space */
   1183  1.3.8.2  tls 	char *fn = s;
   1184  1.3.8.2  tls 	while (*++fn == ' ' || *fn == '\t')
   1185  1.3.8.2  tls 	    ;
   1186  1.3.8.2  tls 
   1187  1.3.8.2  tls 	if (*fn != 0) {
   1188  1.3.8.2  tls 	    FILE *f;
   1189  1.3.8.2  tls 	    int n = 0;
   1190  1.3.8.2  tls 
   1191  1.3.8.2  tls 	    /* open the file and read until STR_LEN-1 bytes or end-of-file */
   1192  1.3.8.2  tls 	    f = fopen(fn, "r");
   1193  1.3.8.2  tls 	    if (f == NULL)
   1194  1.3.8.2  tls 		fatal(1, "%s -- open failed: %m", fn);
   1195  1.3.8.2  tls 	    while (n < STR_LEN - 1) {
   1196  1.3.8.2  tls 		int nr = fread(&file_data[n], 1, STR_LEN - 1 - n, f);
   1197  1.3.8.2  tls 		if (nr < 0)
   1198  1.3.8.2  tls 		    fatal(1, "%s -- read error", fn);
   1199  1.3.8.2  tls 		if (nr == 0)
   1200  1.3.8.2  tls 		    break;
   1201  1.3.8.2  tls 		n += nr;
   1202  1.3.8.2  tls 	    }
   1203  1.3.8.2  tls 	    fclose(f);
   1204  1.3.8.2  tls 
   1205  1.3.8.2  tls 	    /* use the string we got as the string to send,
   1206  1.3.8.2  tls 	       but trim off the final newline if any. */
   1207  1.3.8.2  tls 	    if (n > 0 && file_data[n-1] == '\n')
   1208  1.3.8.2  tls 		--n;
   1209  1.3.8.2  tls 	    file_data[n] = 0;
   1210  1.3.8.2  tls 	    s = file_data;
   1211  1.3.8.2  tls 	}
   1212  1.3.8.2  tls     }
   1213  1.3.8.2  tls 
   1214  1.3.8.2  tls     if (strcmp(s, "EOT") == 0)
   1215  1.3.8.2  tls 	s = "^D\\c";
   1216  1.3.8.2  tls     else if (strcmp(s, "BREAK") == 0)
   1217  1.3.8.2  tls 	s = "\\K\\c";
   1218  1.3.8.2  tls 
   1219  1.3.8.2  tls     if (!put_string(s))
   1220  1.3.8.2  tls 	fatal(1, "Failed");
   1221  1.3.8.2  tls }
   1222  1.3.8.2  tls 
   1223  1.3.8.2  tls int get_char()
   1224  1.3.8.2  tls {
   1225  1.3.8.2  tls     int status;
   1226  1.3.8.2  tls     char c;
   1227  1.3.8.2  tls 
   1228  1.3.8.2  tls     status = read(0, &c, 1);
   1229  1.3.8.2  tls 
   1230  1.3.8.2  tls     switch (status) {
   1231  1.3.8.2  tls     case 1:
   1232  1.3.8.2  tls 	return ((int)c & 0x7F);
   1233  1.3.8.2  tls 
   1234  1.3.8.2  tls     default:
   1235  1.3.8.2  tls 	msgf("warning: read() on stdin returned %d", status);
   1236  1.3.8.2  tls 
   1237  1.3.8.2  tls     case -1:
   1238  1.3.8.2  tls 	if ((status = fcntl(0, F_GETFL, 0)) == -1)
   1239  1.3.8.2  tls 	    fatal(2, "Can't get file mode flags on stdin: %m");
   1240  1.3.8.2  tls 
   1241  1.3.8.2  tls 	if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
   1242  1.3.8.2  tls 	    fatal(2, "Can't set file mode flags on stdin: %m");
   1243  1.3.8.2  tls 
   1244  1.3.8.2  tls 	return (-1);
   1245  1.3.8.2  tls     }
   1246  1.3.8.2  tls }
   1247  1.3.8.2  tls 
   1248  1.3.8.2  tls int put_char(c)
   1249  1.3.8.2  tls int c;
   1250  1.3.8.2  tls {
   1251  1.3.8.2  tls     int status;
   1252  1.3.8.2  tls     char ch = c;
   1253  1.3.8.2  tls 
   1254  1.3.8.2  tls     usleep(10000);		/* inter-character typing delay (?) */
   1255  1.3.8.2  tls 
   1256  1.3.8.2  tls     status = write(1, &ch, 1);
   1257  1.3.8.2  tls 
   1258  1.3.8.2  tls     switch (status) {
   1259  1.3.8.2  tls     case 1:
   1260  1.3.8.2  tls 	return (0);
   1261  1.3.8.2  tls 
   1262  1.3.8.2  tls     default:
   1263  1.3.8.2  tls 	msgf("warning: write() on stdout returned %d", status);
   1264  1.3.8.2  tls 
   1265  1.3.8.2  tls     case -1:
   1266  1.3.8.2  tls 	if ((status = fcntl(0, F_GETFL, 0)) == -1)
   1267  1.3.8.2  tls 	    fatal(2, "Can't get file mode flags on stdin, %m");
   1268  1.3.8.2  tls 
   1269  1.3.8.2  tls 	if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
   1270  1.3.8.2  tls 	    fatal(2, "Can't set file mode flags on stdin: %m");
   1271  1.3.8.2  tls 
   1272  1.3.8.2  tls 	return (-1);
   1273  1.3.8.2  tls     }
   1274  1.3.8.2  tls }
   1275  1.3.8.2  tls 
   1276  1.3.8.2  tls int write_char (c)
   1277  1.3.8.2  tls int c;
   1278  1.3.8.2  tls {
   1279  1.3.8.2  tls     if (alarmed || put_char(c) < 0) {
   1280  1.3.8.2  tls 	alarm(0);
   1281  1.3.8.2  tls 	alarmed = 0;
   1282  1.3.8.2  tls 
   1283  1.3.8.2  tls 	if (verbose) {
   1284  1.3.8.2  tls 	    if (errno == EINTR || errno == EWOULDBLOCK)
   1285  1.3.8.2  tls 		msgf(" -- write timed out");
   1286  1.3.8.2  tls 	    else
   1287  1.3.8.2  tls 		msgf(" -- write failed: %m");
   1288  1.3.8.2  tls 	}
   1289  1.3.8.2  tls 	return (0);
   1290  1.3.8.2  tls     }
   1291  1.3.8.2  tls     return (1);
   1292  1.3.8.2  tls }
   1293  1.3.8.2  tls 
   1294  1.3.8.2  tls int put_string (s)
   1295  1.3.8.2  tls char *s;
   1296  1.3.8.2  tls {
   1297  1.3.8.2  tls 	char *ss;
   1298  1.3.8.2  tls     quiet = 0;
   1299  1.3.8.2  tls     s = ss = clean(s, 1);
   1300  1.3.8.2  tls 
   1301  1.3.8.2  tls     if (verbose) {
   1302  1.3.8.2  tls 	if (quiet)
   1303  1.3.8.2  tls 	    msgf("send (?????\?)");
   1304  1.3.8.2  tls 	else
   1305  1.3.8.2  tls 	    msgf("send (%v)", s);
   1306  1.3.8.2  tls     }
   1307  1.3.8.2  tls 
   1308  1.3.8.2  tls     alarm(timeout); alarmed = 0;
   1309  1.3.8.2  tls 
   1310  1.3.8.2  tls     while (*s) {
   1311  1.3.8.2  tls 	char c = *s++;
   1312  1.3.8.2  tls 
   1313  1.3.8.2  tls 	if (c != '\\') {
   1314  1.3.8.2  tls 	    if (!write_char (c)) {
   1315  1.3.8.2  tls 		free(ss);
   1316  1.3.8.2  tls 		return 0;
   1317  1.3.8.2  tls 	    }
   1318  1.3.8.2  tls 	    continue;
   1319  1.3.8.2  tls 	}
   1320  1.3.8.2  tls 
   1321  1.3.8.2  tls 	c = *s++;
   1322  1.3.8.2  tls 	switch (c) {
   1323  1.3.8.2  tls 	case 'd':
   1324  1.3.8.2  tls 	    sleep(1);
   1325  1.3.8.2  tls 	    break;
   1326  1.3.8.2  tls 
   1327  1.3.8.2  tls 	case 'K':
   1328  1.3.8.2  tls 	    break_sequence();
   1329  1.3.8.2  tls 	    break;
   1330  1.3.8.2  tls 
   1331  1.3.8.2  tls 	case 'p':
   1332  1.3.8.2  tls 	    usleep(10000); 	/* 1/100th of a second (arg is microseconds) */
   1333  1.3.8.2  tls 	    break;
   1334  1.3.8.2  tls 
   1335  1.3.8.2  tls 	default:
   1336  1.3.8.2  tls 	    if (!write_char (c)) {
   1337  1.3.8.2  tls 		free(ss);
   1338  1.3.8.2  tls 		return 0;
   1339  1.3.8.2  tls 	    }
   1340  1.3.8.2  tls 	    break;
   1341  1.3.8.2  tls 	}
   1342  1.3.8.2  tls     }
   1343  1.3.8.2  tls 
   1344  1.3.8.2  tls     alarm(0);
   1345  1.3.8.2  tls     alarmed = 0;
   1346  1.3.8.2  tls     free(ss);
   1347  1.3.8.2  tls     return (1);
   1348  1.3.8.2  tls }
   1349  1.3.8.2  tls 
   1350  1.3.8.2  tls /*
   1351  1.3.8.2  tls  *	Echo a character to stderr.
   1352  1.3.8.2  tls  *	When called with -1, a '\n' character is generated when
   1353  1.3.8.2  tls  *	the cursor is not at the beginning of a line.
   1354  1.3.8.2  tls  */
   1355  1.3.8.2  tls void echo_stderr(n)
   1356  1.3.8.2  tls int n;
   1357  1.3.8.2  tls {
   1358  1.3.8.2  tls     static int need_lf;
   1359  1.3.8.2  tls     char *s;
   1360  1.3.8.2  tls 
   1361  1.3.8.2  tls     switch (n) {
   1362  1.3.8.2  tls     case '\r':		/* ignore '\r' */
   1363  1.3.8.2  tls 	break;
   1364  1.3.8.2  tls     case -1:
   1365  1.3.8.2  tls 	if (need_lf == 0)
   1366  1.3.8.2  tls 	    break;
   1367  1.3.8.2  tls 	/* fall through */
   1368  1.3.8.2  tls     case '\n':
   1369  1.3.8.2  tls 	write(2, "\n", 1);
   1370  1.3.8.2  tls 	need_lf = 0;
   1371  1.3.8.2  tls 	break;
   1372  1.3.8.2  tls     default:
   1373  1.3.8.2  tls 	s = character(n);
   1374  1.3.8.2  tls 	write(2, s, strlen(s));
   1375  1.3.8.2  tls 	need_lf = 1;
   1376  1.3.8.2  tls 	break;
   1377  1.3.8.2  tls     }
   1378  1.3.8.2  tls }
   1379  1.3.8.2  tls 
   1380  1.3.8.2  tls /*
   1381  1.3.8.2  tls  *	'Wait for' this string to appear on this file descriptor.
   1382  1.3.8.2  tls  */
   1383  1.3.8.2  tls int get_string(string)
   1384  1.3.8.2  tls char *string;
   1385  1.3.8.2  tls {
   1386  1.3.8.2  tls     char temp[STR_LEN];
   1387  1.3.8.2  tls     int c, len, minlen;
   1388  1.3.8.2  tls     char *s = temp, *end = s + STR_LEN;
   1389  1.3.8.2  tls     char *logged = temp;
   1390  1.3.8.2  tls 
   1391  1.3.8.2  tls     fail_reason = (char *)0;
   1392  1.3.8.2  tls     string = clean(string, 0);
   1393  1.3.8.2  tls     len = strlen(string);
   1394  1.3.8.2  tls     minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
   1395  1.3.8.2  tls 
   1396  1.3.8.2  tls     if (verbose)
   1397  1.3.8.2  tls 	msgf("expect (%v)", string);
   1398  1.3.8.2  tls 
   1399  1.3.8.2  tls     if (len > STR_LEN) {
   1400  1.3.8.2  tls 	msgf("expect string is too long");
   1401  1.3.8.2  tls 	exit_code = 1;
   1402  1.3.8.2  tls 	free(string);
   1403  1.3.8.2  tls 	return 0;
   1404  1.3.8.2  tls     }
   1405  1.3.8.2  tls 
   1406  1.3.8.2  tls     if (len == 0) {
   1407  1.3.8.2  tls 	if (verbose)
   1408  1.3.8.2  tls 	    msgf("got it");
   1409  1.3.8.2  tls 	free(string);
   1410  1.3.8.2  tls 	return (1);
   1411  1.3.8.2  tls     }
   1412  1.3.8.2  tls 
   1413  1.3.8.2  tls     alarm(timeout);
   1414  1.3.8.2  tls     alarmed = 0;
   1415  1.3.8.2  tls 
   1416  1.3.8.2  tls     while ( ! alarmed && (c = get_char()) >= 0) {
   1417  1.3.8.2  tls 	int n, abort_len, report_len;
   1418  1.3.8.2  tls 
   1419  1.3.8.2  tls 	if (echo)
   1420  1.3.8.2  tls 	    echo_stderr(c);
   1421  1.3.8.2  tls 	if (verbose && c == '\n') {
   1422  1.3.8.2  tls 	    if (s == logged)
   1423  1.3.8.2  tls 		msgf("");	/* blank line */
   1424  1.3.8.2  tls 	    else
   1425  1.3.8.2  tls 		msgf("%0.*v", s - logged, logged);
   1426  1.3.8.2  tls 	    logged = s + 1;
   1427  1.3.8.2  tls 	}
   1428  1.3.8.2  tls 
   1429  1.3.8.2  tls 	*s++ = c;
   1430  1.3.8.2  tls 
   1431  1.3.8.2  tls 	if (verbose && s >= logged + 80) {
   1432  1.3.8.2  tls 	    msgf("%0.*v", s - logged, logged);
   1433  1.3.8.2  tls 	    logged = s;
   1434  1.3.8.2  tls 	}
   1435  1.3.8.2  tls 
   1436  1.3.8.2  tls 	if (Verbose) {
   1437  1.3.8.2  tls 	   if (c == '\n')
   1438  1.3.8.2  tls 	       fputc( '\n', stderr );
   1439  1.3.8.2  tls 	   else if (c != '\r')
   1440  1.3.8.2  tls 	       fprintf( stderr, "%s", character(c) );
   1441  1.3.8.2  tls 	}
   1442  1.3.8.2  tls 
   1443  1.3.8.2  tls 	if (!report_gathering) {
   1444  1.3.8.2  tls 	    for (n = 0; n < n_reports; ++n) {
   1445  1.3.8.2  tls 		if ((report_string[n] != (char*) NULL) &&
   1446  1.3.8.2  tls 		    s - temp >= (report_len = strlen(report_string[n])) &&
   1447  1.3.8.2  tls 		    strncmp(s - report_len, report_string[n], report_len) == 0) {
   1448  1.3.8.2  tls 		    time_t time_now   = time ((time_t*) NULL);
   1449  1.3.8.2  tls 		    struct tm* tm_now = localtime (&time_now);
   1450  1.3.8.2  tls 
   1451  1.3.8.2  tls 		    strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
   1452  1.3.8.2  tls 		    strcat (report_buffer, report_string[n]);
   1453  1.3.8.2  tls 		    strlcat(report_buffer, report_string[n],
   1454  1.3.8.2  tls 		      sizeof(report_buffer));
   1455  1.3.8.2  tls 
   1456  1.3.8.2  tls 		    report_string[n] = (char *) NULL;
   1457  1.3.8.2  tls 		    report_gathering = 1;
   1458  1.3.8.2  tls 		    break;
   1459  1.3.8.2  tls 		}
   1460  1.3.8.2  tls 	    }
   1461  1.3.8.2  tls 	}
   1462  1.3.8.2  tls 	else {
   1463  1.3.8.2  tls 	    if (!iscntrl (c)) {
   1464  1.3.8.2  tls 		int rep_len = strlen (report_buffer);
   1465  1.3.8.2  tls 		report_buffer[rep_len]     = c;
   1466  1.3.8.2  tls 		report_buffer[rep_len + 1] = '\0';
   1467  1.3.8.2  tls 	    }
   1468  1.3.8.2  tls 	    else {
   1469  1.3.8.2  tls 		report_gathering = 0;
   1470  1.3.8.2  tls 		fprintf (report_fp, "chat:  %s\n", report_buffer);
   1471  1.3.8.2  tls 	    }
   1472  1.3.8.2  tls 	}
   1473  1.3.8.2  tls 
   1474  1.3.8.2  tls 	if (s - temp >= len &&
   1475  1.3.8.2  tls 	    c == string[len - 1] &&
   1476  1.3.8.2  tls 	    strncmp(s - len, string, len) == 0) {
   1477  1.3.8.2  tls 	    if (verbose) {
   1478  1.3.8.2  tls 		if (s > logged)
   1479  1.3.8.2  tls 		    msgf("%0.*v", s - logged, logged);
   1480  1.3.8.2  tls 		msgf(" -- got it\n");
   1481  1.3.8.2  tls 	    }
   1482  1.3.8.2  tls 
   1483  1.3.8.2  tls 	    alarm(0);
   1484  1.3.8.2  tls 	    alarmed = 0;
   1485  1.3.8.2  tls 	    free(string);
   1486  1.3.8.2  tls 	    return (1);
   1487  1.3.8.2  tls 	}
   1488  1.3.8.2  tls 
   1489  1.3.8.2  tls 	for (n = 0; n < n_aborts; ++n) {
   1490  1.3.8.2  tls 	    if (s - temp >= (abort_len = strlen(abort_string[n])) &&
   1491  1.3.8.2  tls 		strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
   1492  1.3.8.2  tls 		if (verbose) {
   1493  1.3.8.2  tls 		    if (s > logged)
   1494  1.3.8.2  tls 			msgf("%0.*v", s - logged, logged);
   1495  1.3.8.2  tls 		    msgf(" -- failed");
   1496  1.3.8.2  tls 		}
   1497  1.3.8.2  tls 
   1498  1.3.8.2  tls 		alarm(0);
   1499  1.3.8.2  tls 		alarmed = 0;
   1500  1.3.8.2  tls 		exit_code = n + 4;
   1501  1.3.8.2  tls 		strlcpy(fail_buffer, abort_string[n], sizeof(fail_buffer));
   1502  1.3.8.2  tls 		fail_reason = fail_buffer;
   1503  1.3.8.2  tls 		free(string);
   1504  1.3.8.2  tls 		return (0);
   1505  1.3.8.2  tls 	    }
   1506  1.3.8.2  tls 	}
   1507  1.3.8.2  tls 
   1508  1.3.8.2  tls 	if (s >= end) {
   1509  1.3.8.2  tls 	    if (logged < s - minlen) {
   1510  1.3.8.2  tls 		if (verbose)
   1511  1.3.8.2  tls 		    msgf("%0.*v", s - logged, logged);
   1512  1.3.8.2  tls 		logged = s;
   1513  1.3.8.2  tls 	    }
   1514  1.3.8.2  tls 	    s -= minlen;
   1515  1.3.8.2  tls 	    memmove(temp, s, minlen);
   1516  1.3.8.2  tls 	    logged = temp + (logged - s);
   1517  1.3.8.2  tls 	    s = temp + minlen;
   1518  1.3.8.2  tls 	}
   1519  1.3.8.2  tls 
   1520  1.3.8.2  tls 	if (alarmed && verbose)
   1521  1.3.8.2  tls 	    msgf("warning: alarm synchronization problem");
   1522  1.3.8.2  tls     }
   1523  1.3.8.2  tls 
   1524  1.3.8.2  tls     alarm(0);
   1525  1.3.8.2  tls 
   1526  1.3.8.2  tls     exit_code = 3;
   1527  1.3.8.2  tls     alarmed   = 0;
   1528  1.3.8.2  tls     free(string);
   1529  1.3.8.2  tls     return (0);
   1530  1.3.8.2  tls }
   1531  1.3.8.2  tls 
   1532  1.3.8.2  tls /*
   1533  1.3.8.2  tls  * Gross kludge to handle Solaris versions >= 2.6 having usleep.
   1534  1.3.8.2  tls  */
   1535  1.3.8.2  tls #ifdef SOL2
   1536  1.3.8.2  tls #include <sys/param.h>
   1537  1.3.8.2  tls #if MAXUID > 65536		/* then this is Solaris 2.6 or later */
   1538  1.3.8.2  tls #undef NO_USLEEP
   1539  1.3.8.2  tls #endif
   1540  1.3.8.2  tls #endif /* SOL2 */
   1541  1.3.8.2  tls 
   1542  1.3.8.2  tls #ifdef NO_USLEEP
   1543  1.3.8.2  tls #include <sys/types.h>
   1544  1.3.8.2  tls #include <sys/time.h>
   1545  1.3.8.2  tls 
   1546  1.3.8.2  tls /*
   1547  1.3.8.2  tls   usleep -- support routine for 4.2BSD system call emulations
   1548  1.3.8.2  tls   last edit:  29-Oct-1984     D A Gwyn
   1549  1.3.8.2  tls   */
   1550  1.3.8.2  tls 
   1551  1.3.8.2  tls extern int	  select();
   1552  1.3.8.2  tls 
   1553  1.3.8.2  tls int
   1554  1.3.8.2  tls usleep( usec )				  /* returns 0 if ok, else -1 */
   1555  1.3.8.2  tls     long		usec;		/* delay in microseconds */
   1556  1.3.8.2  tls {
   1557  1.3.8.2  tls     static struct {		/* `timeval' */
   1558  1.3.8.2  tls 	long	tv_sec;		/* seconds */
   1559  1.3.8.2  tls 	long	tv_usec;	/* microsecs */
   1560  1.3.8.2  tls     } delay;	    		/* _select() timeout */
   1561  1.3.8.2  tls 
   1562  1.3.8.2  tls     delay.tv_sec  = usec / 1000000L;
   1563  1.3.8.2  tls     delay.tv_usec = usec % 1000000L;
   1564  1.3.8.2  tls 
   1565  1.3.8.2  tls     return select(0, (long *)0, (long *)0, (long *)0, &delay);
   1566  1.3.8.2  tls }
   1567  1.3.8.2  tls #endif
   1568  1.3.8.2  tls 
   1569  1.3.8.2  tls void
   1570  1.3.8.2  tls pack_array (array, end)
   1571  1.3.8.2  tls     char **array; /* The address of the array of string pointers */
   1572  1.3.8.2  tls     int    end;   /* The index of the next free entry before CLR_ */
   1573  1.3.8.2  tls {
   1574  1.3.8.2  tls     int i, j;
   1575  1.3.8.2  tls 
   1576  1.3.8.2  tls     for (i = 0; i < end; i++) {
   1577  1.3.8.2  tls 	if (array[i] == NULL) {
   1578  1.3.8.2  tls 	    for (j = i+1; j < end; ++j)
   1579  1.3.8.2  tls 		if (array[j] != NULL)
   1580  1.3.8.2  tls 		    array[i++] = array[j];
   1581  1.3.8.2  tls 	    for (; i < end; ++i)
   1582  1.3.8.2  tls 		array[i] = NULL;
   1583  1.3.8.2  tls 	    break;
   1584  1.3.8.2  tls 	}
   1585  1.3.8.2  tls     }
   1586  1.3.8.2  tls }
   1587  1.3.8.2  tls 
   1588  1.3.8.2  tls /*
   1589  1.3.8.2  tls  * vfmtmsg - format a message into a buffer.  Like vsprintf except we
   1590  1.3.8.2  tls  * also specify the length of the output buffer, and we handle the
   1591  1.3.8.2  tls  * %m (error message) format.
   1592  1.3.8.2  tls  * Doesn't do floating-point formats.
   1593  1.3.8.2  tls  * Returns the number of chars put into buf.
   1594  1.3.8.2  tls  */
   1595  1.3.8.2  tls #define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
   1596  1.3.8.2  tls 
   1597  1.3.8.2  tls int
   1598  1.3.8.2  tls vfmtmsg(buf, buflen, fmt, args)
   1599  1.3.8.2  tls     char *buf;
   1600  1.3.8.2  tls     int buflen;
   1601  1.3.8.2  tls     const char *fmt;
   1602  1.3.8.2  tls     va_list args;
   1603  1.3.8.2  tls {
   1604  1.3.8.2  tls     int c, i, n;
   1605  1.3.8.2  tls     int width, prec, fillch;
   1606  1.3.8.2  tls     int base, len, neg, quoted;
   1607  1.3.8.2  tls     unsigned long val = 0;
   1608  1.3.8.2  tls     char *str, *buf0;
   1609  1.3.8.2  tls     const char *f;
   1610  1.3.8.2  tls     unsigned char *p;
   1611  1.3.8.2  tls     char num[32];
   1612  1.3.8.2  tls     static char hexchars[] = "0123456789abcdef";
   1613  1.3.8.2  tls 
   1614  1.3.8.2  tls     buf0 = buf;
   1615  1.3.8.2  tls     --buflen;
   1616  1.3.8.2  tls     while (buflen > 0) {
   1617  1.3.8.2  tls 	for (f = fmt; *f != '%' && *f != 0; ++f)
   1618  1.3.8.2  tls 	    ;
   1619  1.3.8.2  tls 	if (f > fmt) {
   1620  1.3.8.2  tls 	    len = f - fmt;
   1621  1.3.8.2  tls 	    if (len > buflen)
   1622  1.3.8.2  tls 		len = buflen;
   1623  1.3.8.2  tls 	    memcpy(buf, fmt, len);
   1624  1.3.8.2  tls 	    buf += len;
   1625  1.3.8.2  tls 	    buflen -= len;
   1626  1.3.8.2  tls 	    fmt = f;
   1627  1.3.8.2  tls 	}
   1628  1.3.8.2  tls 	if (*fmt == 0)
   1629  1.3.8.2  tls 	    break;
   1630  1.3.8.2  tls 	c = *++fmt;
   1631  1.3.8.2  tls 	width = prec = 0;
   1632  1.3.8.2  tls 	fillch = ' ';
   1633  1.3.8.2  tls 	if (c == '0') {
   1634  1.3.8.2  tls 	    fillch = '0';
   1635  1.3.8.2  tls 	    c = *++fmt;
   1636  1.3.8.2  tls 	}
   1637  1.3.8.2  tls 	if (c == '*') {
   1638  1.3.8.2  tls 	    width = va_arg(args, int);
   1639  1.3.8.2  tls 	    c = *++fmt;
   1640  1.3.8.2  tls 	} else {
   1641  1.3.8.2  tls 	    while (isdigit(c)) {
   1642  1.3.8.2  tls 		width = width * 10 + c - '0';
   1643  1.3.8.2  tls 		c = *++fmt;
   1644  1.3.8.2  tls 	    }
   1645  1.3.8.2  tls 	}
   1646  1.3.8.2  tls 	if (c == '.') {
   1647  1.3.8.2  tls 	    c = *++fmt;
   1648  1.3.8.2  tls 	    if (c == '*') {
   1649  1.3.8.2  tls 		prec = va_arg(args, int);
   1650  1.3.8.2  tls 		c = *++fmt;
   1651  1.3.8.2  tls 	    } else {
   1652  1.3.8.2  tls 		while (isdigit(c)) {
   1653  1.3.8.2  tls 		    prec = prec * 10 + c - '0';
   1654  1.3.8.2  tls 		    c = *++fmt;
   1655  1.3.8.2  tls 		}
   1656  1.3.8.2  tls 	    }
   1657  1.3.8.2  tls 	}
   1658  1.3.8.2  tls 	str = 0;
   1659  1.3.8.2  tls 	base = 0;
   1660  1.3.8.2  tls 	neg = 0;
   1661  1.3.8.2  tls 	++fmt;
   1662  1.3.8.2  tls 	switch (c) {
   1663  1.3.8.2  tls 	case 'd':
   1664  1.3.8.2  tls 	    i = va_arg(args, int);
   1665  1.3.8.2  tls 	    if (i < 0) {
   1666  1.3.8.2  tls 		neg = 1;
   1667  1.3.8.2  tls 		val = -i;
   1668  1.3.8.2  tls 	    } else
   1669  1.3.8.2  tls 		val = i;
   1670  1.3.8.2  tls 	    base = 10;
   1671  1.3.8.2  tls 	    break;
   1672  1.3.8.2  tls 	case 'o':
   1673  1.3.8.2  tls 	    val = va_arg(args, unsigned int);
   1674  1.3.8.2  tls 	    base = 8;
   1675  1.3.8.2  tls 	    break;
   1676  1.3.8.2  tls 	case 'x':
   1677  1.3.8.2  tls 	    val = va_arg(args, unsigned int);
   1678  1.3.8.2  tls 	    base = 16;
   1679  1.3.8.2  tls 	    break;
   1680  1.3.8.2  tls 	case 'p':
   1681  1.3.8.2  tls 	    val = (unsigned long) va_arg(args, void *);
   1682  1.3.8.2  tls 	    base = 16;
   1683  1.3.8.2  tls 	    neg = 2;
   1684  1.3.8.2  tls 	    break;
   1685  1.3.8.2  tls 	case 's':
   1686  1.3.8.2  tls 	    str = va_arg(args, char *);
   1687  1.3.8.2  tls 	    break;
   1688  1.3.8.2  tls 	case 'c':
   1689  1.3.8.2  tls 	    num[0] = va_arg(args, int);
   1690  1.3.8.2  tls 	    num[1] = 0;
   1691  1.3.8.2  tls 	    str = num;
   1692  1.3.8.2  tls 	    break;
   1693  1.3.8.2  tls 	case 'm':
   1694  1.3.8.2  tls 	    str = strerror(errno);
   1695  1.3.8.2  tls 	    break;
   1696  1.3.8.2  tls 	case 'v':		/* "visible" string */
   1697  1.3.8.2  tls 	case 'q':		/* quoted string */
   1698  1.3.8.2  tls 	    quoted = c == 'q';
   1699  1.3.8.2  tls 	    p = va_arg(args, unsigned char *);
   1700  1.3.8.2  tls 	    if (fillch == '0' && prec > 0) {
   1701  1.3.8.2  tls 		n = prec;
   1702  1.3.8.2  tls 	    } else {
   1703  1.3.8.2  tls 		n = strlen((char *)p);
   1704  1.3.8.2  tls 		if (prec > 0 && prec < n)
   1705  1.3.8.2  tls 		    n = prec;
   1706  1.3.8.2  tls 	    }
   1707  1.3.8.2  tls 	    while (n > 0 && buflen > 0) {
   1708  1.3.8.2  tls 		c = *p++;
   1709  1.3.8.2  tls 		--n;
   1710  1.3.8.2  tls 		if (!quoted && c >= 0x80) {
   1711  1.3.8.2  tls 		    OUTCHAR('M');
   1712  1.3.8.2  tls 		    OUTCHAR('-');
   1713  1.3.8.2  tls 		    c -= 0x80;
   1714  1.3.8.2  tls 		}
   1715  1.3.8.2  tls 		if (quoted && (c == '"' || c == '\\'))
   1716  1.3.8.2  tls 		    OUTCHAR('\\');
   1717  1.3.8.2  tls 		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
   1718  1.3.8.2  tls 		    if (quoted) {
   1719  1.3.8.2  tls 			OUTCHAR('\\');
   1720  1.3.8.2  tls 			switch (c) {
   1721  1.3.8.2  tls 			case '\t':	OUTCHAR('t');	break;
   1722  1.3.8.2  tls 			case '\n':	OUTCHAR('n');	break;
   1723  1.3.8.2  tls 			case '\b':	OUTCHAR('b');	break;
   1724  1.3.8.2  tls 			case '\f':	OUTCHAR('f');	break;
   1725  1.3.8.2  tls 			default:
   1726  1.3.8.2  tls 			    OUTCHAR('x');
   1727  1.3.8.2  tls 			    OUTCHAR(hexchars[c >> 4]);
   1728  1.3.8.2  tls 			    OUTCHAR(hexchars[c & 0xf]);
   1729  1.3.8.2  tls 			}
   1730  1.3.8.2  tls 		    } else {
   1731  1.3.8.2  tls 			if (c == '\t')
   1732  1.3.8.2  tls 			    OUTCHAR(c);
   1733  1.3.8.2  tls 			else {
   1734  1.3.8.2  tls 			    OUTCHAR('^');
   1735  1.3.8.2  tls 			    OUTCHAR(c ^ 0x40);
   1736  1.3.8.2  tls 			}
   1737  1.3.8.2  tls 		    }
   1738  1.3.8.2  tls 		} else
   1739  1.3.8.2  tls 		    OUTCHAR(c);
   1740  1.3.8.2  tls 	    }
   1741  1.3.8.2  tls 	    continue;
   1742  1.3.8.2  tls 	default:
   1743  1.3.8.2  tls 	    *buf++ = '%';
   1744  1.3.8.2  tls 	    if (c != '%')
   1745  1.3.8.2  tls 		--fmt;		/* so %z outputs %z etc. */
   1746  1.3.8.2  tls 	    --buflen;
   1747  1.3.8.2  tls 	    continue;
   1748  1.3.8.2  tls 	}
   1749  1.3.8.2  tls 	if (base != 0) {
   1750  1.3.8.2  tls 	    str = num + sizeof(num);
   1751  1.3.8.2  tls 	    *--str = 0;
   1752  1.3.8.2  tls 	    while (str > num + neg) {
   1753  1.3.8.2  tls 		*--str = hexchars[val % base];
   1754  1.3.8.2  tls 		val = val / base;
   1755  1.3.8.2  tls 		if (--prec <= 0 && val == 0)
   1756  1.3.8.2  tls 		    break;
   1757  1.3.8.2  tls 	    }
   1758  1.3.8.2  tls 	    switch (neg) {
   1759  1.3.8.2  tls 	    case 1:
   1760  1.3.8.2  tls 		*--str = '-';
   1761  1.3.8.2  tls 		break;
   1762  1.3.8.2  tls 	    case 2:
   1763  1.3.8.2  tls 		*--str = 'x';
   1764  1.3.8.2  tls 		*--str = '0';
   1765  1.3.8.2  tls 		break;
   1766  1.3.8.2  tls 	    }
   1767  1.3.8.2  tls 	    len = num + sizeof(num) - 1 - str;
   1768  1.3.8.2  tls 	} else {
   1769  1.3.8.2  tls 	    len = strlen(str);
   1770  1.3.8.2  tls 	    if (prec > 0 && len > prec)
   1771  1.3.8.2  tls 		len = prec;
   1772  1.3.8.2  tls 	}
   1773  1.3.8.2  tls 	if (width > 0) {
   1774  1.3.8.2  tls 	    if (width > buflen)
   1775  1.3.8.2  tls 		width = buflen;
   1776  1.3.8.2  tls 	    if ((n = width - len) > 0) {
   1777  1.3.8.2  tls 		buflen -= n;
   1778  1.3.8.2  tls 		for (; n > 0; --n)
   1779  1.3.8.2  tls 		    *buf++ = fillch;
   1780  1.3.8.2  tls 	    }
   1781  1.3.8.2  tls 	}
   1782  1.3.8.2  tls 	if (len > buflen)
   1783  1.3.8.2  tls 	    len = buflen;
   1784  1.3.8.2  tls 	memcpy(buf, str, len);
   1785  1.3.8.2  tls 	buf += len;
   1786  1.3.8.2  tls 	buflen -= len;
   1787  1.3.8.2  tls     }
   1788  1.3.8.2  tls     *buf = 0;
   1789  1.3.8.2  tls     return buf - buf0;
   1790  1.3.8.2  tls }
   1791