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.
801c855caSPeter Wemm * 2 - error on an I/O operation or fatal error condition.
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 * -----------------
1701c855caSPeter Wemm * added -T and -U option and \T and \U substitution to pass a phone
1801c855caSPeter Wemm * number into chat script. Two are needed for some ISDN TA applications.
1901c855caSPeter Wemm * Keith Dart <kdart@cisco.com>
2001c855caSPeter Wemm *
219b1aec48SLars Fredriksen *
223d793cf1SPeter Wemm * Added SAY keyword to send output to stderr.
233d793cf1SPeter Wemm * This allows to turn ECHO OFF and to output specific, user selected,
243d793cf1SPeter Wemm * text to give progress messages. This best works when stderr
253d793cf1SPeter Wemm * exists (i.e.: pppd in nodetach mode).
263d793cf1SPeter Wemm *
273d793cf1SPeter Wemm * Added HANGUP directives to allow for us to be called
283d793cf1SPeter Wemm * back. When HANGUP is set to NO, chat will not hangup at HUP signal.
293d793cf1SPeter Wemm * We rely on timeouts in that case.
303d793cf1SPeter Wemm *
313d793cf1SPeter Wemm * Added CLR_ABORT to clear previously set ABORT string. This has been
323d793cf1SPeter Wemm * dictated by the HANGUP above as "NO CARRIER" (for example) must be
333d793cf1SPeter Wemm * an ABORT condition until we know the other host is going to close
343d793cf1SPeter Wemm * the connection for call back. As soon as we have completed the
353d793cf1SPeter Wemm * first stage of the call back sequence, "NO CARRIER" is a valid, non
363d793cf1SPeter Wemm * fatal string. As soon as we got called back (probably get "CONNECT"),
373d793cf1SPeter Wemm * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
383d793cf1SPeter Wemm * Note that CLR_ABORT packs the abort_strings[] array so that we do not
393d793cf1SPeter Wemm * have unused entries not being reclaimed.
403d793cf1SPeter Wemm *
413d793cf1SPeter Wemm * In the same vein as above, added CLR_REPORT keyword.
423d793cf1SPeter Wemm *
433d793cf1SPeter Wemm * Allow for comments. Line starting with '#' are comments and are
443d793cf1SPeter Wemm * ignored. If a '#' is to be expected as the first character, the
453d793cf1SPeter Wemm * expect string must be quoted.
463d793cf1SPeter Wemm *
473d793cf1SPeter Wemm *
483d793cf1SPeter Wemm * Francis Demierre <Francis@SwissMail.Com>
493d793cf1SPeter Wemm * Thu May 15 17:15:40 MET DST 1997
503d793cf1SPeter Wemm *
519b1aec48SLars Fredriksen *
529f65f104SPeter Wemm * Added -r "report file" switch & REPORT keyword.
539f65f104SPeter Wemm * Robert Geer <bgeer@xmission.com>
549f65f104SPeter Wemm *
5501c855caSPeter Wemm * Added -s "use stderr" and -S "don't use syslog" switches.
5601c855caSPeter Wemm * June 18, 1997
5701c855caSPeter Wemm * Karl O. Pinc <kop@meme.com>
5801c855caSPeter Wemm *
593d793cf1SPeter Wemm *
603d793cf1SPeter Wemm * Added -e "echo" switch & ECHO keyword
613d793cf1SPeter Wemm * Dick Streefland <dicks@tasking.nl>
623d793cf1SPeter Wemm *
633d793cf1SPeter Wemm *
643d793cf1SPeter Wemm * Considerable updates and modifications by
653d793cf1SPeter Wemm * Al Longyear <longyear@pobox.com>
663d793cf1SPeter Wemm * Paul Mackerras <paulus@cs.anu.edu.au>
673d793cf1SPeter Wemm *
683d793cf1SPeter Wemm *
699b1aec48SLars Fredriksen * The original author is:
709b1aec48SLars Fredriksen *
719b1aec48SLars Fredriksen * Karl Fox <karl@MorningStar.Com>
729b1aec48SLars Fredriksen * Morning Star Technologies, Inc.
739b1aec48SLars Fredriksen * 1760 Zollinger Road
749b1aec48SLars Fredriksen * Columbus, OH 43221
759b1aec48SLars Fredriksen * (614)451-1883
769f65f104SPeter Wemm *
773d793cf1SPeter Wemm *
789b1aec48SLars Fredriksen */
799b1aec48SLars Fredriksen
809b1aec48SLars Fredriksen #include <sys/types.h>
819b1aec48SLars Fredriksen #include <sys/stat.h>
82ee6b974cSMark Murray #include <ctype.h>
83ee6b974cSMark Murray #include <errno.h>
84ee6b974cSMark Murray #include <fcntl.h>
85ee6b974cSMark Murray #include <signal.h>
86ee6b974cSMark Murray #include <stdarg.h>
87ee6b974cSMark Murray #include <stdio.h>
88ee6b974cSMark Murray #include <stdlib.h>
89ee6b974cSMark Murray #include <string.h>
909b1aec48SLars Fredriksen #include <syslog.h>
919b1aec48SLars Fredriksen #include <termios.h>
92ee6b974cSMark Murray #include <time.h>
93ee6b974cSMark Murray #include <unistd.h>
949b1aec48SLars Fredriksen
959b1aec48SLars Fredriksen #define STR_LEN 1024
969b1aec48SLars Fredriksen
979b1aec48SLars Fredriksen #ifndef SIGTYPE
989b1aec48SLars Fredriksen #define SIGTYPE void
999b1aec48SLars Fredriksen #endif
1009b1aec48SLars Fredriksen
1019f65f104SPeter Wemm #ifndef O_NONBLOCK
1029f65f104SPeter Wemm #define O_NONBLOCK O_NDELAY
1039f65f104SPeter Wemm #endif
1049f65f104SPeter Wemm
1059b1aec48SLars Fredriksen #define MAX_ABORTS 50
1069f65f104SPeter Wemm #define MAX_REPORTS 50
1079b1aec48SLars Fredriksen #define DEFAULT_CHAT_TIMEOUT 45
1089b1aec48SLars Fredriksen
109bf70beceSEd Schouten static int echo;
110bf70beceSEd Schouten static int verbose;
111bf70beceSEd Schouten static int to_log;
112bf70beceSEd Schouten static int to_stderr;
113bf70beceSEd Schouten static int Verbose;
114bf70beceSEd Schouten static int quiet;
115bf70beceSEd Schouten static int exit_code;
116bf70beceSEd Schouten static FILE* report_fp;
117bf70beceSEd Schouten static char *report_file;
118bf70beceSEd Schouten static char *chat_file;
119bf70beceSEd Schouten static char *phone_num;
120bf70beceSEd Schouten static char *phone_num2;
121bf70beceSEd Schouten static int timeout = DEFAULT_CHAT_TIMEOUT;
1229b1aec48SLars Fredriksen
123ee6b974cSMark Murray static char blank[] = "";
124ee6b974cSMark Murray
125bf70beceSEd Schouten static int have_tty_parameters;
1269f65f104SPeter Wemm
1279f65f104SPeter Wemm #define term_parms struct termios
1289f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param)
1299f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param)
130bf70beceSEd Schouten static struct termios saved_tty_parameters;
1319b1aec48SLars Fredriksen
132bf70beceSEd Schouten static char *abort_string[MAX_ABORTS], *fail_reason, fail_buffer[50];
133bf70beceSEd Schouten static int n_aborts, abort_next, timeout_next, echo_next;
134bf70beceSEd Schouten static int clear_abort_next;
1359b1aec48SLars Fredriksen
136bf70beceSEd Schouten static char *report_string[MAX_REPORTS];
137bf70beceSEd Schouten static char report_buffer[50];
138bf70beceSEd Schouten static int n_reports, report_next, report_gathering;
139bf70beceSEd Schouten static int clear_report_next;
1403d793cf1SPeter Wemm
141bf70beceSEd Schouten static int say_next, hup_next;
1429f65f104SPeter Wemm
143f1bb2cd2SWarner Losh void *dup_mem(void *b, size_t c);
144f1bb2cd2SWarner Losh void *copy_of(char *s);
145*498a0a9cSAlfonso Gregory static void usage(void) __dead2;
1468491f234STim Kientzle void chat_logf(const char *fmt, ...);
147f1bb2cd2SWarner Losh void fatal(int code, const char *fmt, ...);
148f1bb2cd2SWarner Losh SIGTYPE sigalrm(int signo);
149f1bb2cd2SWarner Losh SIGTYPE sigint(int signo);
150f1bb2cd2SWarner Losh SIGTYPE sigterm(int signo);
151f1bb2cd2SWarner Losh SIGTYPE sighup(int signo);
152f1bb2cd2SWarner Losh void init(void);
153f1bb2cd2SWarner Losh void set_tty_parameters(void);
154f1bb2cd2SWarner Losh void echo_stderr(int);
155f1bb2cd2SWarner Losh void break_sequence(void);
156f1bb2cd2SWarner Losh void terminate(int status);
157ee6b974cSMark Murray void do_file(char *chatfile);
158ee6b974cSMark Murray int get_string(char *string);
159ee6b974cSMark Murray int put_string(char *s);
160f1bb2cd2SWarner Losh int write_char(int c);
161f1bb2cd2SWarner Losh int put_char(int c);
162f1bb2cd2SWarner Losh int get_char(void);
163ee6b974cSMark Murray void chat_send(char *s);
164f1bb2cd2SWarner Losh char *character(int c);
165ee6b974cSMark Murray void chat_expect(char *s);
166ee6b974cSMark Murray char *clean(char *s, int sending);
167f1bb2cd2SWarner Losh void pack_array(char **array, int end);
168ee6b974cSMark Murray char *expect_strtok(char *, const char *);
169f1bb2cd2SWarner Losh int vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */
1703d793cf1SPeter Wemm
171ee6b974cSMark Murray void *
dup_mem(void * b,size_t c)172ee6b974cSMark Murray dup_mem(void *b, size_t c)
1739b1aec48SLars Fredriksen {
1749b1aec48SLars Fredriksen void *ans = malloc (c);
1759b1aec48SLars Fredriksen if (!ans)
17601c855caSPeter Wemm fatal(2, "memory error!");
17701c855caSPeter Wemm
1789b1aec48SLars Fredriksen memcpy (ans, b, c);
1799b1aec48SLars Fredriksen return ans;
1809b1aec48SLars Fredriksen }
1819b1aec48SLars Fredriksen
182ee6b974cSMark Murray void *
copy_of(char * s)183ee6b974cSMark Murray copy_of(char *s)
1849b1aec48SLars Fredriksen {
1859b1aec48SLars Fredriksen return dup_mem (s, strlen (s) + 1);
1869b1aec48SLars Fredriksen }
1879b1aec48SLars Fredriksen
1889b1aec48SLars Fredriksen /*
18918ebe779SXin LI * chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout]
19018ebe779SXin LI * [-T phone-number] [-U phone-number2] [chat-script]
19118ebe779SXin LI * where chat-script has the form:
19218ebe779SXin LI * [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]]
1939b1aec48SLars Fredriksen *
1949b1aec48SLars Fredriksen * Perform a UUCP-dialer-like chat script on stdin and stdout.
1959b1aec48SLars Fredriksen */
1969b1aec48SLars Fredriksen int
main(int argc,char * argv[])197ee6b974cSMark Murray main(int argc, char *argv[])
1989b1aec48SLars Fredriksen {
1999b1aec48SLars Fredriksen int option;
2009b1aec48SLars Fredriksen
2019f65f104SPeter Wemm tzset();
2029b1aec48SLars Fredriksen
20318ebe779SXin LI while ((option = getopt(argc, argv, "ef:r:sSt:T:U:vV")) != -1) {
20401c855caSPeter Wemm switch (option) {
2053d793cf1SPeter Wemm case 'e':
2063d793cf1SPeter Wemm ++echo;
2073d793cf1SPeter Wemm break;
2083d793cf1SPeter Wemm
20918ebe779SXin LI case 'f':
21018ebe779SXin LI if (chat_file != NULL)
21118ebe779SXin LI free(chat_file);
21218ebe779SXin LI chat_file = copy_of(optarg);
2139b1aec48SLars Fredriksen break;
2149b1aec48SLars Fredriksen
21518ebe779SXin LI case 'r':
21618ebe779SXin LI if (report_fp != NULL)
21718ebe779SXin LI fclose(report_fp);
21818ebe779SXin LI if (report_file != NULL)
21918ebe779SXin LI free(report_file);
22018ebe779SXin LI report_file = copy_of(optarg);
22118ebe779SXin LI report_fp = fopen(report_file, "a");
22218ebe779SXin LI if (report_fp != NULL) {
22318ebe779SXin LI if (verbose)
22418ebe779SXin LI fprintf(report_fp, "Opening \"%s\"...\n", report_file);
22518ebe779SXin LI } else
22618ebe779SXin LI fatal(2, "cannot open \"%s\" for appending", report_file);
2273d793cf1SPeter Wemm break;
2283d793cf1SPeter Wemm
22901c855caSPeter Wemm case 's':
23001c855caSPeter Wemm ++to_stderr;
23101c855caSPeter Wemm break;
23201c855caSPeter Wemm
23301c855caSPeter Wemm case 'S':
23401c855caSPeter Wemm to_log = 0;
23501c855caSPeter Wemm break;
23601c855caSPeter Wemm
2379b1aec48SLars Fredriksen case 't':
23818ebe779SXin LI timeout = atoi(optarg);
2399b1aec48SLars Fredriksen break;
2409b1aec48SLars Fredriksen
24101c855caSPeter Wemm case 'T':
24218ebe779SXin LI if (phone_num != NULL)
24318ebe779SXin LI free(phone_num);
24418ebe779SXin LI phone_num = copy_of(optarg);
24501c855caSPeter Wemm break;
24601c855caSPeter Wemm
24701c855caSPeter Wemm case 'U':
24818ebe779SXin LI if (phone_num2 != NULL)
24918ebe779SXin LI free(phone_num2);
25018ebe779SXin LI phone_num2 = copy_of(optarg);
25118ebe779SXin LI break;
25218ebe779SXin LI
25318ebe779SXin LI case 'v':
25418ebe779SXin LI ++verbose;
25518ebe779SXin LI break;
25618ebe779SXin LI
25718ebe779SXin LI case 'V':
25818ebe779SXin LI ++Verbose;
25901c855caSPeter Wemm break;
26001c855caSPeter Wemm
2619b1aec48SLars Fredriksen default:
2629b1aec48SLars Fredriksen usage();
2639f65f104SPeter Wemm break;
2649f65f104SPeter Wemm }
2659f65f104SPeter Wemm }
26618ebe779SXin LI
26718ebe779SXin LI argc -= optind;
26818ebe779SXin LI argv += optind;
26918ebe779SXin LI
2709f65f104SPeter Wemm /*
2719f65f104SPeter Wemm * Default the report file to the stderr location
2729f65f104SPeter Wemm */
2739f65f104SPeter Wemm if (report_fp == NULL)
2749f65f104SPeter Wemm report_fp = stderr;
2759b1aec48SLars Fredriksen
27601c855caSPeter Wemm if (to_log) {
2779b1aec48SLars Fredriksen openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
2789b1aec48SLars Fredriksen
2799f65f104SPeter Wemm if (verbose)
2809b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_INFO));
2819f65f104SPeter Wemm else
2829b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_WARNING));
28301c855caSPeter Wemm }
2849b1aec48SLars Fredriksen
28501c855caSPeter Wemm if (chat_file != NULL) {
28618ebe779SXin LI if (*argv != NULL)
2879b1aec48SLars Fredriksen usage();
28818ebe779SXin LI else {
28918ebe779SXin LI init();
2909b1aec48SLars Fredriksen do_file(chat_file);
29118ebe779SXin LI }
29201c855caSPeter Wemm } else {
29318ebe779SXin LI init();
29418ebe779SXin LI while (*argv != NULL && argc > 0) {
29518ebe779SXin LI chat_expect(*argv);
29618ebe779SXin LI argv++;
29718ebe779SXin LI argc--;
2989b1aec48SLars Fredriksen
29918ebe779SXin LI if (*argv != NULL && argc > 0) {
30018ebe779SXin LI chat_send(*argv);
30118ebe779SXin LI argv++;
30218ebe779SXin LI argc--;
30318ebe779SXin LI }
3049b1aec48SLars Fredriksen }
3059b1aec48SLars Fredriksen }
3069b1aec48SLars Fredriksen
3079b1aec48SLars Fredriksen terminate(0);
3083d793cf1SPeter Wemm return 0;
3099b1aec48SLars Fredriksen }
3109b1aec48SLars Fredriksen
3119b1aec48SLars Fredriksen /*
3129b1aec48SLars Fredriksen * Process a chat script when read from a file.
3139b1aec48SLars Fredriksen */
3149b1aec48SLars Fredriksen
315ee6b974cSMark Murray void
do_file(char * chatfile)316ee6b974cSMark Murray do_file(char *chatfile)
3179b1aec48SLars Fredriksen {
318d7d10053SAlexander Langer int linect, sendflg;
3199b1aec48SLars Fredriksen char *sp, *arg, quote;
3209b1aec48SLars Fredriksen char buf [STR_LEN];
3219b1aec48SLars Fredriksen FILE *cfp;
3229b1aec48SLars Fredriksen
323ee6b974cSMark Murray cfp = fopen (chatfile, "r");
3249f65f104SPeter Wemm if (cfp == NULL)
325ee6b974cSMark Murray fatal(1, "%s -- open failed: %m", chatfile);
3269b1aec48SLars Fredriksen
3279b1aec48SLars Fredriksen linect = 0;
3289b1aec48SLars Fredriksen sendflg = 0;
3299b1aec48SLars Fredriksen
33001c855caSPeter Wemm while (fgets(buf, STR_LEN, cfp) != NULL) {
3319b1aec48SLars Fredriksen sp = strchr (buf, '\n');
3329b1aec48SLars Fredriksen if (sp)
3339b1aec48SLars Fredriksen *sp = '\0';
3349b1aec48SLars Fredriksen
3359b1aec48SLars Fredriksen linect++;
3369b1aec48SLars Fredriksen sp = buf;
3373d793cf1SPeter Wemm
3383d793cf1SPeter Wemm /* lines starting with '#' are comments. If a real '#'
3393d793cf1SPeter Wemm is to be expected, it should be quoted .... */
34001c855caSPeter Wemm if ( *sp == '#' )
34101c855caSPeter Wemm continue;
3423d793cf1SPeter Wemm
34301c855caSPeter Wemm while (*sp != '\0') {
34401c855caSPeter Wemm if (*sp == ' ' || *sp == '\t') {
3459b1aec48SLars Fredriksen ++sp;
3469b1aec48SLars Fredriksen continue;
3479b1aec48SLars Fredriksen }
3489b1aec48SLars Fredriksen
34901c855caSPeter Wemm if (*sp == '"' || *sp == '\'') {
3509b1aec48SLars Fredriksen quote = *sp++;
3519b1aec48SLars Fredriksen arg = sp;
35201c855caSPeter Wemm while (*sp != quote) {
3539b1aec48SLars Fredriksen if (*sp == '\0')
35401c855caSPeter Wemm fatal(1, "unterminated quote (line %d)", linect);
3559b1aec48SLars Fredriksen
35601c855caSPeter Wemm if (*sp++ == '\\') {
3579b1aec48SLars Fredriksen if (*sp != '\0')
3589b1aec48SLars Fredriksen ++sp;
3599b1aec48SLars Fredriksen }
3609b1aec48SLars Fredriksen }
3619f65f104SPeter Wemm }
36201c855caSPeter Wemm else {
3639b1aec48SLars Fredriksen arg = sp;
3649b1aec48SLars Fredriksen while (*sp != '\0' && *sp != ' ' && *sp != '\t')
3659b1aec48SLars Fredriksen ++sp;
3669b1aec48SLars Fredriksen }
3679b1aec48SLars Fredriksen
3689b1aec48SLars Fredriksen if (*sp != '\0')
3699b1aec48SLars Fredriksen *sp++ = '\0';
3709b1aec48SLars Fredriksen
3719b1aec48SLars Fredriksen if (sendflg)
3729b1aec48SLars Fredriksen chat_send (arg);
3739b1aec48SLars Fredriksen else
3749b1aec48SLars Fredriksen chat_expect (arg);
3759b1aec48SLars Fredriksen sendflg = !sendflg;
3769b1aec48SLars Fredriksen }
3779b1aec48SLars Fredriksen }
3789b1aec48SLars Fredriksen fclose (cfp);
3799b1aec48SLars Fredriksen }
3809b1aec48SLars Fredriksen
3819b1aec48SLars Fredriksen /*
3829b1aec48SLars Fredriksen * We got an error parsing the command line.
3839b1aec48SLars Fredriksen */
384afaeb553SPhilippe Charnier static void
usage(void)385ee6b974cSMark Murray usage(void)
3869b1aec48SLars Fredriksen {
38718ebe779SXin LI fprintf(stderr,
38818ebe779SXin LI "Usage: chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout]\n"
38918ebe779SXin LI " [-T phone-number] [-U phone-number2] [chat-script]\n"
39018ebe779SXin LI "where chat-script has the form:\n"
39118ebe779SXin LI " [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]]\n");
3929b1aec48SLars Fredriksen exit(1);
3939b1aec48SLars Fredriksen }
3949b1aec48SLars Fredriksen
3959b1aec48SLars Fredriksen /*
39601c855caSPeter Wemm * Send a message to syslog and/or stderr.
3979b1aec48SLars Fredriksen */
398ee6b974cSMark Murray void
chat_logf(const char * fmt,...)3998491f234STim Kientzle chat_logf(const char *fmt, ...)
4009b1aec48SLars Fredriksen {
401bf70beceSEd Schouten char line[1024];
40201c855caSPeter Wemm va_list args;
40301c855caSPeter Wemm
40401c855caSPeter Wemm va_start(args, fmt);
40501c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args);
406544c5e5bSKevin Lo va_end(args);
40701c855caSPeter Wemm if (to_log)
40801c855caSPeter Wemm syslog(LOG_INFO, "%s", line);
40901c855caSPeter Wemm if (to_stderr)
41001c855caSPeter Wemm fprintf(stderr, "%s\n", line);
4119b1aec48SLars Fredriksen }
4129b1aec48SLars Fredriksen
4139b1aec48SLars Fredriksen /*
4149b1aec48SLars Fredriksen * Print an error message and terminate.
4159b1aec48SLars Fredriksen */
4169b1aec48SLars Fredriksen
417ee6b974cSMark Murray void
fatal(int code,const char * fmt,...)418ee6b974cSMark Murray fatal(int code, const char *fmt, ...)
4199b1aec48SLars Fredriksen {
420bf70beceSEd Schouten char line[1024];
42101c855caSPeter Wemm va_list args;
4229b1aec48SLars Fredriksen
42301c855caSPeter Wemm va_start(args, fmt);
42401c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args);
425544c5e5bSKevin Lo va_end(args);
42601c855caSPeter Wemm if (to_log)
42701c855caSPeter Wemm syslog(LOG_ERR, "%s", line);
42801c855caSPeter Wemm if (to_stderr)
42901c855caSPeter Wemm fprintf(stderr, "%s\n", line);
43001c855caSPeter Wemm terminate(code);
4319b1aec48SLars Fredriksen }
4329b1aec48SLars Fredriksen
433bf70beceSEd Schouten static int alarmed;
4349b1aec48SLars Fredriksen
sigalrm(int signo __unused)435ee6b974cSMark Murray SIGTYPE sigalrm(int signo __unused)
4369b1aec48SLars Fredriksen {
4379b1aec48SLars Fredriksen int flags;
4389b1aec48SLars Fredriksen
4399b1aec48SLars Fredriksen alarm(1);
4409b1aec48SLars Fredriksen alarmed = 1; /* Reset alarm to avoid race window */
4419b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
4429b1aec48SLars Fredriksen
4439b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1)
44401c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m");
44501c855caSPeter Wemm
4469f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
44701c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m");
4489b1aec48SLars Fredriksen
4499b1aec48SLars Fredriksen if (verbose)
4508491f234STim Kientzle chat_logf("alarm");
4519b1aec48SLars Fredriksen }
4529b1aec48SLars Fredriksen
sigint(int signo __unused)453ee6b974cSMark Murray SIGTYPE sigint(int signo __unused)
4549b1aec48SLars Fredriksen {
45501c855caSPeter Wemm fatal(2, "SIGINT");
4569b1aec48SLars Fredriksen }
4579b1aec48SLars Fredriksen
sigterm(int signo __unused)458ee6b974cSMark Murray SIGTYPE sigterm(int signo __unused)
4599b1aec48SLars Fredriksen {
46001c855caSPeter Wemm fatal(2, "SIGTERM");
4619b1aec48SLars Fredriksen }
4629b1aec48SLars Fredriksen
sighup(int signo __unused)463ee6b974cSMark Murray SIGTYPE sighup(int signo __unused)
4649b1aec48SLars Fredriksen {
46501c855caSPeter Wemm fatal(2, "SIGHUP");
4669b1aec48SLars Fredriksen }
4679b1aec48SLars Fredriksen
init(void)468ee6b974cSMark Murray void init(void)
4699b1aec48SLars Fredriksen {
4709b1aec48SLars Fredriksen signal(SIGINT, sigint);
4719b1aec48SLars Fredriksen signal(SIGTERM, sigterm);
4729b1aec48SLars Fredriksen signal(SIGHUP, sighup);
4739b1aec48SLars Fredriksen
4749b1aec48SLars Fredriksen set_tty_parameters();
4759b1aec48SLars Fredriksen signal(SIGALRM, sigalrm);
4769b1aec48SLars Fredriksen alarm(0);
4779b1aec48SLars Fredriksen alarmed = 0;
4789b1aec48SLars Fredriksen }
4799b1aec48SLars Fredriksen
set_tty_parameters(void)480ee6b974cSMark Murray void set_tty_parameters(void)
4819b1aec48SLars Fredriksen {
4829f65f104SPeter Wemm #if defined(get_term_param)
4839f65f104SPeter Wemm term_parms t;
4849b1aec48SLars Fredriksen
4859f65f104SPeter Wemm if (get_term_param (&t) < 0)
48601c855caSPeter Wemm fatal(2, "Can't get terminal parameters: %m");
4879b1aec48SLars Fredriksen
4889b1aec48SLars Fredriksen saved_tty_parameters = t;
4899b1aec48SLars Fredriksen have_tty_parameters = 1;
4909b1aec48SLars Fredriksen
4919b1aec48SLars Fredriksen t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
4929b1aec48SLars Fredriksen t.c_oflag = 0;
4939b1aec48SLars Fredriksen t.c_lflag = 0;
4949f65f104SPeter Wemm t.c_cc[VERASE] =
4959f65f104SPeter Wemm t.c_cc[VKILL] = 0;
4969b1aec48SLars Fredriksen t.c_cc[VMIN] = 1;
4979b1aec48SLars Fredriksen t.c_cc[VTIME] = 0;
4989b1aec48SLars Fredriksen
4999f65f104SPeter Wemm if (set_term_param (&t) < 0)
50001c855caSPeter Wemm fatal(2, "Can't set terminal parameters: %m");
5019b1aec48SLars Fredriksen #endif
5029b1aec48SLars Fredriksen }
5039b1aec48SLars Fredriksen
break_sequence(void)504ee6b974cSMark Murray void break_sequence(void)
5059b1aec48SLars Fredriksen {
5069b1aec48SLars Fredriksen tcsendbreak (0, 0);
5079b1aec48SLars Fredriksen }
5089b1aec48SLars Fredriksen
terminate(int status)509ee6b974cSMark Murray void terminate(int status)
5109b1aec48SLars Fredriksen {
5113d793cf1SPeter Wemm echo_stderr(-1);
51201c855caSPeter Wemm if (report_file != (char *) 0 && report_fp != (FILE *) NULL) {
5133d793cf1SPeter Wemm /*
5143d793cf1SPeter Wemm * Allow the last of the report string to be gathered before we terminate.
5153d793cf1SPeter Wemm */
5163d793cf1SPeter Wemm if (report_gathering) {
517ee6b974cSMark Murray int c;
518ee6b974cSMark Murray size_t rep_len;
5193d793cf1SPeter Wemm
5203d793cf1SPeter Wemm rep_len = strlen(report_buffer);
521d2c82c0cSDon Lewis while (rep_len + 1 < sizeof(report_buffer)) {
5223d793cf1SPeter Wemm alarm(1);
5233d793cf1SPeter Wemm c = get_char();
5243d793cf1SPeter Wemm alarm(0);
5253d793cf1SPeter Wemm if (c < 0 || iscntrl(c))
5263d793cf1SPeter Wemm break;
5273d793cf1SPeter Wemm report_buffer[rep_len] = c;
5283d793cf1SPeter Wemm ++rep_len;
5293d793cf1SPeter Wemm }
5303d793cf1SPeter Wemm report_buffer[rep_len] = 0;
5313d793cf1SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer);
5323d793cf1SPeter Wemm }
5339f65f104SPeter Wemm if (verbose)
5349f65f104SPeter Wemm fprintf (report_fp, "Closing \"%s\".\n", report_file);
5359f65f104SPeter Wemm fclose (report_fp);
5369f65f104SPeter Wemm report_fp = (FILE *) NULL;
5379f65f104SPeter Wemm }
5389f65f104SPeter Wemm
5399f65f104SPeter Wemm #if defined(get_term_param)
54001c855caSPeter Wemm if (have_tty_parameters) {
5419f65f104SPeter Wemm if (set_term_param (&saved_tty_parameters) < 0)
54201c855caSPeter Wemm fatal(2, "Can't restore terminal parameters: %m");
5439f65f104SPeter Wemm }
5449f65f104SPeter Wemm #endif
5459f65f104SPeter Wemm
5469b1aec48SLars Fredriksen exit(status);
5479b1aec48SLars Fredriksen }
5489b1aec48SLars Fredriksen
5499b1aec48SLars Fredriksen /*
5509b1aec48SLars Fredriksen * 'Clean up' this string.
5519b1aec48SLars Fredriksen */
552ee6b974cSMark Murray char *
clean(char * s,int sending)553ee6b974cSMark Murray clean(char *s, int sending)
5549b1aec48SLars Fredriksen {
5559b1aec48SLars Fredriksen char temp[STR_LEN], cur_chr;
556ee6b974cSMark Murray char *s1, *phchar;
5579b1aec48SLars Fredriksen int add_return = sending;
5589b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
5599b1aec48SLars Fredriksen
5609b1aec48SLars Fredriksen s1 = temp;
5614e83a8feSKris Kennaway /* Don't overflow buffer, leave room for chars we append later */
562ee6b974cSMark Murray while (*s && s1 - temp < (off_t)(sizeof(temp) - 2 - add_return)) {
5639b1aec48SLars Fredriksen cur_chr = *s++;
56401c855caSPeter Wemm if (cur_chr == '^') {
5659b1aec48SLars Fredriksen cur_chr = *s++;
56601c855caSPeter Wemm if (cur_chr == '\0') {
5679b1aec48SLars Fredriksen *s1++ = '^';
5689b1aec48SLars Fredriksen break;
5699b1aec48SLars Fredriksen }
5709b1aec48SLars Fredriksen cur_chr &= 0x1F;
57101c855caSPeter Wemm if (cur_chr != 0) {
5729b1aec48SLars Fredriksen *s1++ = cur_chr;
5739f65f104SPeter Wemm }
5749b1aec48SLars Fredriksen continue;
5759b1aec48SLars Fredriksen }
5769b1aec48SLars Fredriksen
57701c855caSPeter Wemm if (cur_chr != '\\') {
5789b1aec48SLars Fredriksen *s1++ = cur_chr;
5799b1aec48SLars Fredriksen continue;
5809b1aec48SLars Fredriksen }
5819b1aec48SLars Fredriksen
5829b1aec48SLars Fredriksen cur_chr = *s++;
58301c855caSPeter Wemm if (cur_chr == '\0') {
58401c855caSPeter Wemm if (sending) {
5859b1aec48SLars Fredriksen *s1++ = '\\';
5869b1aec48SLars Fredriksen *s1++ = '\\';
5879b1aec48SLars Fredriksen }
5889b1aec48SLars Fredriksen break;
5899b1aec48SLars Fredriksen }
5909b1aec48SLars Fredriksen
59101c855caSPeter Wemm switch (cur_chr) {
5929b1aec48SLars Fredriksen case 'b':
5939b1aec48SLars Fredriksen *s1++ = '\b';
5949b1aec48SLars Fredriksen break;
5959b1aec48SLars Fredriksen
5969b1aec48SLars Fredriksen case 'c':
5979b1aec48SLars Fredriksen if (sending && *s == '\0')
5989b1aec48SLars Fredriksen add_return = 0;
5999b1aec48SLars Fredriksen else
6009b1aec48SLars Fredriksen *s1++ = cur_chr;
6019b1aec48SLars Fredriksen break;
6029b1aec48SLars Fredriksen
6039b1aec48SLars Fredriksen case '\\':
6049b1aec48SLars Fredriksen case 'K':
6059b1aec48SLars Fredriksen case 'p':
6069b1aec48SLars Fredriksen case 'd':
6079b1aec48SLars Fredriksen if (sending)
6089b1aec48SLars Fredriksen *s1++ = '\\';
6099b1aec48SLars Fredriksen
6109b1aec48SLars Fredriksen *s1++ = cur_chr;
6119b1aec48SLars Fredriksen break;
6129b1aec48SLars Fredriksen
61301c855caSPeter Wemm case 'T':
61401c855caSPeter Wemm if (sending && phone_num) {
61501c855caSPeter Wemm for ( phchar = phone_num; *phchar != '\0'; phchar++)
61601c855caSPeter Wemm *s1++ = *phchar;
61701c855caSPeter Wemm }
61801c855caSPeter Wemm else {
61901c855caSPeter Wemm *s1++ = '\\';
62001c855caSPeter Wemm *s1++ = 'T';
62101c855caSPeter Wemm }
62201c855caSPeter Wemm break;
62301c855caSPeter Wemm
62401c855caSPeter Wemm case 'U':
62501c855caSPeter Wemm if (sending && phone_num2) {
62601c855caSPeter Wemm for ( phchar = phone_num2; *phchar != '\0'; phchar++)
62701c855caSPeter Wemm *s1++ = *phchar;
62801c855caSPeter Wemm }
62901c855caSPeter Wemm else {
63001c855caSPeter Wemm *s1++ = '\\';
63101c855caSPeter Wemm *s1++ = 'U';
63201c855caSPeter Wemm }
63301c855caSPeter Wemm break;
63401c855caSPeter Wemm
6359b1aec48SLars Fredriksen case 'q':
6363d793cf1SPeter Wemm quiet = 1;
6379b1aec48SLars Fredriksen break;
6389b1aec48SLars Fredriksen
6399b1aec48SLars Fredriksen case 'r':
6409b1aec48SLars Fredriksen *s1++ = '\r';
6419b1aec48SLars Fredriksen break;
6429b1aec48SLars Fredriksen
6439b1aec48SLars Fredriksen case 'n':
6449b1aec48SLars Fredriksen *s1++ = '\n';
6459b1aec48SLars Fredriksen break;
6469b1aec48SLars Fredriksen
6479b1aec48SLars Fredriksen case 's':
6489b1aec48SLars Fredriksen *s1++ = ' ';
6499b1aec48SLars Fredriksen break;
6509b1aec48SLars Fredriksen
6519b1aec48SLars Fredriksen case 't':
6529b1aec48SLars Fredriksen *s1++ = '\t';
6539b1aec48SLars Fredriksen break;
6549b1aec48SLars Fredriksen
6559b1aec48SLars Fredriksen case 'N':
65601c855caSPeter Wemm if (sending) {
6579b1aec48SLars Fredriksen *s1++ = '\\';
6589b1aec48SLars Fredriksen *s1++ = '\0';
6599b1aec48SLars Fredriksen }
6609b1aec48SLars Fredriksen else
6619b1aec48SLars Fredriksen *s1++ = 'N';
6629b1aec48SLars Fredriksen break;
6639b1aec48SLars Fredriksen
6649b1aec48SLars Fredriksen default:
66501c855caSPeter Wemm if (isoctal (cur_chr)) {
6669b1aec48SLars Fredriksen cur_chr &= 0x07;
66701c855caSPeter Wemm if (isoctal (*s)) {
6689b1aec48SLars Fredriksen cur_chr <<= 3;
6699b1aec48SLars Fredriksen cur_chr |= *s++ - '0';
67001c855caSPeter Wemm if (isoctal (*s)) {
6719b1aec48SLars Fredriksen cur_chr <<= 3;
6729b1aec48SLars Fredriksen cur_chr |= *s++ - '0';
6739b1aec48SLars Fredriksen }
6749b1aec48SLars Fredriksen }
6759b1aec48SLars Fredriksen
67601c855caSPeter Wemm if (cur_chr != 0 || sending) {
6779b1aec48SLars Fredriksen if (sending && (cur_chr == '\\' || cur_chr == 0))
6789b1aec48SLars Fredriksen *s1++ = '\\';
6799b1aec48SLars Fredriksen *s1++ = cur_chr;
6809b1aec48SLars Fredriksen }
6819b1aec48SLars Fredriksen break;
6829b1aec48SLars Fredriksen }
6839b1aec48SLars Fredriksen
6849b1aec48SLars Fredriksen if (sending)
6859b1aec48SLars Fredriksen *s1++ = '\\';
6869b1aec48SLars Fredriksen *s1++ = cur_chr;
6879b1aec48SLars Fredriksen break;
6889b1aec48SLars Fredriksen }
6899b1aec48SLars Fredriksen }
6909b1aec48SLars Fredriksen
6919b1aec48SLars Fredriksen if (add_return)
6929b1aec48SLars Fredriksen *s1++ = '\r';
6939b1aec48SLars Fredriksen
6949b1aec48SLars Fredriksen *s1++ = '\0'; /* guarantee closure */
6959b1aec48SLars Fredriksen *s1++ = '\0'; /* terminate the string */
6969b1aec48SLars Fredriksen return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
6979b1aec48SLars Fredriksen }
6989b1aec48SLars Fredriksen
6999b1aec48SLars Fredriksen /*
7003d793cf1SPeter Wemm * A modified version of 'strtok'. This version skips \ sequences.
7013d793cf1SPeter Wemm */
7023d793cf1SPeter Wemm
703ee6b974cSMark Murray char *
expect_strtok(char * s,const char * term)704ee6b974cSMark Murray expect_strtok (char *s, const char *term)
7053d793cf1SPeter Wemm {
706ee6b974cSMark Murray static char *str = blank;
7073d793cf1SPeter Wemm int escape_flag = 0;
7083d793cf1SPeter Wemm char *result;
70901c855caSPeter Wemm
7103d793cf1SPeter Wemm /*
7113d793cf1SPeter Wemm * If a string was specified then do initial processing.
7123d793cf1SPeter Wemm */
7133d793cf1SPeter Wemm if (s)
7143d793cf1SPeter Wemm str = s;
71501c855caSPeter Wemm
7163d793cf1SPeter Wemm /*
7173d793cf1SPeter Wemm * If this is the escape flag then reset it and ignore the character.
7183d793cf1SPeter Wemm */
7193d793cf1SPeter Wemm if (*str)
7203d793cf1SPeter Wemm result = str;
7213d793cf1SPeter Wemm else
7223d793cf1SPeter Wemm result = (char *) 0;
7233d793cf1SPeter Wemm
72401c855caSPeter Wemm while (*str) {
72501c855caSPeter Wemm if (escape_flag) {
7263d793cf1SPeter Wemm escape_flag = 0;
7273d793cf1SPeter Wemm ++str;
7283d793cf1SPeter Wemm continue;
7293d793cf1SPeter Wemm }
7303d793cf1SPeter Wemm
73101c855caSPeter Wemm if (*str == '\\') {
7323d793cf1SPeter Wemm ++str;
7333d793cf1SPeter Wemm escape_flag = 1;
7343d793cf1SPeter Wemm continue;
7353d793cf1SPeter Wemm }
73601c855caSPeter Wemm
7373d793cf1SPeter Wemm /*
7383d793cf1SPeter Wemm * If this is not in the termination string, continue.
7393d793cf1SPeter Wemm */
74001c855caSPeter Wemm if (strchr (term, *str) == (char *) 0) {
7413d793cf1SPeter Wemm ++str;
7423d793cf1SPeter Wemm continue;
7433d793cf1SPeter Wemm }
74401c855caSPeter Wemm
7453d793cf1SPeter Wemm /*
7463d793cf1SPeter Wemm * This is the terminator. Mark the end of the string and stop.
7473d793cf1SPeter Wemm */
7483d793cf1SPeter Wemm *str++ = '\0';
7493d793cf1SPeter Wemm break;
7503d793cf1SPeter Wemm }
7513d793cf1SPeter Wemm return (result);
7523d793cf1SPeter Wemm }
7533d793cf1SPeter Wemm
7543d793cf1SPeter Wemm /*
7559b1aec48SLars Fredriksen * Process the expect string
7569b1aec48SLars Fredriksen */
7573d793cf1SPeter Wemm
758ee6b974cSMark Murray void
chat_expect(char * s)759ee6b974cSMark Murray chat_expect(char *s)
7609b1aec48SLars Fredriksen {
7613d793cf1SPeter Wemm char *expect;
7623d793cf1SPeter Wemm char *reply;
7633d793cf1SPeter Wemm
76401c855caSPeter Wemm if (strcmp(s, "HANGUP") == 0) {
7653d793cf1SPeter Wemm ++hup_next;
7663d793cf1SPeter Wemm return;
7673d793cf1SPeter Wemm }
7683d793cf1SPeter Wemm
76901c855caSPeter Wemm if (strcmp(s, "ABORT") == 0) {
7709b1aec48SLars Fredriksen ++abort_next;
7719b1aec48SLars Fredriksen return;
7729b1aec48SLars Fredriksen }
7739b1aec48SLars Fredriksen
77401c855caSPeter Wemm if (strcmp(s, "CLR_ABORT") == 0) {
7753d793cf1SPeter Wemm ++clear_abort_next;
7763d793cf1SPeter Wemm return;
7773d793cf1SPeter Wemm }
7783d793cf1SPeter Wemm
77901c855caSPeter Wemm if (strcmp(s, "REPORT") == 0) {
7809f65f104SPeter Wemm ++report_next;
7819f65f104SPeter Wemm return;
7829f65f104SPeter Wemm }
7839f65f104SPeter Wemm
78401c855caSPeter Wemm if (strcmp(s, "CLR_REPORT") == 0) {
7853d793cf1SPeter Wemm ++clear_report_next;
7863d793cf1SPeter Wemm return;
7873d793cf1SPeter Wemm }
7883d793cf1SPeter Wemm
78901c855caSPeter Wemm if (strcmp(s, "TIMEOUT") == 0) {
7909b1aec48SLars Fredriksen ++timeout_next;
7919b1aec48SLars Fredriksen return;
7929b1aec48SLars Fredriksen }
7939b1aec48SLars Fredriksen
79401c855caSPeter Wemm if (strcmp(s, "ECHO") == 0) {
7953d793cf1SPeter Wemm ++echo_next;
7963d793cf1SPeter Wemm return;
7973d793cf1SPeter Wemm }
79801c855caSPeter Wemm
79901c855caSPeter Wemm if (strcmp(s, "SAY") == 0) {
8003d793cf1SPeter Wemm ++say_next;
8013d793cf1SPeter Wemm return;
8023d793cf1SPeter Wemm }
80301c855caSPeter Wemm
8043d793cf1SPeter Wemm /*
8053d793cf1SPeter Wemm * Fetch the expect and reply string.
8063d793cf1SPeter Wemm */
80701c855caSPeter Wemm for (;;) {
8083d793cf1SPeter Wemm expect = expect_strtok (s, "-");
8093d793cf1SPeter Wemm s = (char *) 0;
8109b1aec48SLars Fredriksen
8113d793cf1SPeter Wemm if (expect == (char *) 0)
8123d793cf1SPeter Wemm return;
8133d793cf1SPeter Wemm
8143d793cf1SPeter Wemm reply = expect_strtok (s, "-");
81501c855caSPeter Wemm
8163d793cf1SPeter Wemm /*
8173d793cf1SPeter Wemm * Handle the expect string. If successful then exit.
8183d793cf1SPeter Wemm */
8193d793cf1SPeter Wemm if (get_string (expect))
8203d793cf1SPeter Wemm return;
82101c855caSPeter Wemm
8223d793cf1SPeter Wemm /*
8233d793cf1SPeter Wemm * If there is a sub-reply string then send it. Otherwise any condition
8243d793cf1SPeter Wemm * is terminal.
8253d793cf1SPeter Wemm */
8263d793cf1SPeter Wemm if (reply == (char *) 0 || exit_code != 3)
8279b1aec48SLars Fredriksen break;
8289b1aec48SLars Fredriksen
8293d793cf1SPeter Wemm chat_send (reply);
8309f65f104SPeter Wemm }
83101c855caSPeter Wemm
8323d793cf1SPeter Wemm /*
8333d793cf1SPeter Wemm * The expectation did not occur. This is terminal.
8343d793cf1SPeter Wemm */
8359b1aec48SLars Fredriksen if (fail_reason)
8368491f234STim Kientzle chat_logf("Failed (%s)", fail_reason);
8379b1aec48SLars Fredriksen else
8388491f234STim Kientzle chat_logf("Failed");
8399f65f104SPeter Wemm terminate(exit_code);
8409f65f104SPeter Wemm }
8413d793cf1SPeter Wemm
8423d793cf1SPeter Wemm /*
8433d793cf1SPeter Wemm * Translate the input character to the appropriate string for printing
8443d793cf1SPeter Wemm * the data.
8453d793cf1SPeter Wemm */
8469b1aec48SLars Fredriksen
847ee6b974cSMark Murray char *
character(int c)848ee6b974cSMark Murray character(int c)
8499b1aec48SLars Fredriksen {
8509b1aec48SLars Fredriksen static char string[10];
851ee6b974cSMark Murray const char *meta;
8529b1aec48SLars Fredriksen
8539b1aec48SLars Fredriksen meta = (c & 0x80) ? "M-" : "";
8549b1aec48SLars Fredriksen c &= 0x7F;
8559b1aec48SLars Fredriksen
8569b1aec48SLars Fredriksen if (c < 32)
8579b1aec48SLars Fredriksen sprintf(string, "%s^%c", meta, (int)c + '@');
85801c855caSPeter Wemm else if (c == 127)
8599b1aec48SLars Fredriksen sprintf(string, "%s^?", meta);
8609b1aec48SLars Fredriksen else
8619b1aec48SLars Fredriksen sprintf(string, "%s%c", meta, c);
8629b1aec48SLars Fredriksen
8639b1aec48SLars Fredriksen return (string);
8649b1aec48SLars Fredriksen }
8659b1aec48SLars Fredriksen
8669b1aec48SLars Fredriksen /*
8679b1aec48SLars Fredriksen * process the reply string
8689b1aec48SLars Fredriksen */
869ee6b974cSMark Murray void
chat_send(char * s)870ee6b974cSMark Murray chat_send(char *s)
8719b1aec48SLars Fredriksen {
87201c855caSPeter Wemm if (say_next) {
8733d793cf1SPeter Wemm say_next = 0;
8743d793cf1SPeter Wemm s = clean(s,0);
875e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s));
8763d793cf1SPeter Wemm free(s);
8773d793cf1SPeter Wemm return;
8783d793cf1SPeter Wemm }
87901c855caSPeter Wemm
88001c855caSPeter Wemm if (hup_next) {
8813d793cf1SPeter Wemm hup_next = 0;
8823d793cf1SPeter Wemm if (strcmp(s, "OFF") == 0)
8833d793cf1SPeter Wemm signal(SIGHUP, SIG_IGN);
8843d793cf1SPeter Wemm else
8853d793cf1SPeter Wemm signal(SIGHUP, sighup);
8863d793cf1SPeter Wemm return;
8873d793cf1SPeter Wemm }
88801c855caSPeter Wemm
88901c855caSPeter Wemm if (echo_next) {
8903d793cf1SPeter Wemm echo_next = 0;
8913d793cf1SPeter Wemm echo = (strcmp(s, "ON") == 0);
8923d793cf1SPeter Wemm return;
8933d793cf1SPeter Wemm }
89401c855caSPeter Wemm
89501c855caSPeter Wemm if (abort_next) {
8969b1aec48SLars Fredriksen char *s1;
8979b1aec48SLars Fredriksen
8989b1aec48SLars Fredriksen abort_next = 0;
8999b1aec48SLars Fredriksen
9009b1aec48SLars Fredriksen if (n_aborts >= MAX_ABORTS)
90101c855caSPeter Wemm fatal(2, "Too many ABORT strings");
9029b1aec48SLars Fredriksen
9039b1aec48SLars Fredriksen s1 = clean(s, 0);
9049b1aec48SLars Fredriksen
9059f65f104SPeter Wemm if (strlen(s1) > strlen(s)
9069f65f104SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer))
90701c855caSPeter Wemm fatal(1, "Illegal or too-long ABORT string ('%v')", s);
9089b1aec48SLars Fredriksen
9099b1aec48SLars Fredriksen abort_string[n_aborts++] = s1;
9109b1aec48SLars Fredriksen
9119b1aec48SLars Fredriksen if (verbose)
9128491f234STim Kientzle chat_logf("abort on (%v)", s);
9139f65f104SPeter Wemm return;
9149b1aec48SLars Fredriksen }
9159f65f104SPeter Wemm
91601c855caSPeter Wemm if (clear_abort_next) {
9173d793cf1SPeter Wemm char *s1;
9183d793cf1SPeter Wemm int i;
9193d793cf1SPeter Wemm int old_max;
9203d793cf1SPeter Wemm int pack = 0;
9213d793cf1SPeter Wemm
9223d793cf1SPeter Wemm clear_abort_next = 0;
9233d793cf1SPeter Wemm
9243d793cf1SPeter Wemm s1 = clean(s, 0);
9253d793cf1SPeter Wemm
9263d793cf1SPeter Wemm if (strlen(s1) > strlen(s)
9273d793cf1SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer))
92801c855caSPeter Wemm fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
9293d793cf1SPeter Wemm
9303d793cf1SPeter Wemm old_max = n_aborts;
93101c855caSPeter Wemm for (i=0; i < n_aborts; i++) {
93201c855caSPeter Wemm if ( strcmp(s1,abort_string[i]) == 0 ) {
9333d793cf1SPeter Wemm free(abort_string[i]);
9343d793cf1SPeter Wemm abort_string[i] = NULL;
9353d793cf1SPeter Wemm pack++;
9363d793cf1SPeter Wemm n_aborts--;
9373d793cf1SPeter Wemm if (verbose)
9388491f234STim Kientzle chat_logf("clear abort on (%v)", s);
9393d793cf1SPeter Wemm }
9403d793cf1SPeter Wemm }
9413d793cf1SPeter Wemm free(s1);
94201c855caSPeter Wemm if (pack)
94301c855caSPeter Wemm pack_array(abort_string,old_max);
9443d793cf1SPeter Wemm return;
9453d793cf1SPeter Wemm }
9463d793cf1SPeter Wemm
94701c855caSPeter Wemm if (report_next) {
9489f65f104SPeter Wemm char *s1;
9499f65f104SPeter Wemm
9509f65f104SPeter Wemm report_next = 0;
9519f65f104SPeter Wemm if (n_reports >= MAX_REPORTS)
95201c855caSPeter Wemm fatal(2, "Too many REPORT strings");
9539f65f104SPeter Wemm
9549f65f104SPeter Wemm s1 = clean(s, 0);
9559f65f104SPeter Wemm
9569f65f104SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
95701c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s);
9589f65f104SPeter Wemm
9599f65f104SPeter Wemm report_string[n_reports++] = s1;
9609f65f104SPeter Wemm
9619f65f104SPeter Wemm if (verbose)
9628491f234STim Kientzle chat_logf("report (%v)", s);
9639f65f104SPeter Wemm return;
9649f65f104SPeter Wemm }
9659f65f104SPeter Wemm
96601c855caSPeter Wemm if (clear_report_next) {
9673d793cf1SPeter Wemm char *s1;
9683d793cf1SPeter Wemm int i;
9693d793cf1SPeter Wemm int old_max;
9703d793cf1SPeter Wemm int pack = 0;
9713d793cf1SPeter Wemm
9723d793cf1SPeter Wemm clear_report_next = 0;
9733d793cf1SPeter Wemm
9743d793cf1SPeter Wemm s1 = clean(s, 0);
9753d793cf1SPeter Wemm
9763d793cf1SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
97701c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s);
9783d793cf1SPeter Wemm
9793d793cf1SPeter Wemm old_max = n_reports;
98001c855caSPeter Wemm for (i=0; i < n_reports; i++) {
98101c855caSPeter Wemm if ( strcmp(s1,report_string[i]) == 0 ) {
9823d793cf1SPeter Wemm free(report_string[i]);
9833d793cf1SPeter Wemm report_string[i] = NULL;
9843d793cf1SPeter Wemm pack++;
9853d793cf1SPeter Wemm n_reports--;
9863d793cf1SPeter Wemm if (verbose)
9878491f234STim Kientzle chat_logf("clear report (%v)", s);
9883d793cf1SPeter Wemm }
9893d793cf1SPeter Wemm }
9903d793cf1SPeter Wemm free(s1);
99101c855caSPeter Wemm if (pack)
99201c855caSPeter Wemm pack_array(report_string,old_max);
9933d793cf1SPeter Wemm
9943d793cf1SPeter Wemm return;
9953d793cf1SPeter Wemm }
9963d793cf1SPeter Wemm
99701c855caSPeter Wemm if (timeout_next) {
9989b1aec48SLars Fredriksen timeout_next = 0;
9999b1aec48SLars Fredriksen timeout = atoi(s);
10009b1aec48SLars Fredriksen
10019b1aec48SLars Fredriksen if (timeout <= 0)
10029b1aec48SLars Fredriksen timeout = DEFAULT_CHAT_TIMEOUT;
10039b1aec48SLars Fredriksen
10049b1aec48SLars Fredriksen if (verbose)
10058491f234STim Kientzle chat_logf("timeout set to %d seconds", timeout);
100601c855caSPeter Wemm
10079f65f104SPeter Wemm return;
10089f65f104SPeter Wemm }
10099f65f104SPeter Wemm
10109f65f104SPeter Wemm if (strcmp(s, "EOT") == 0)
1011ee6b974cSMark Murray s = strdup("^D\\c");
101201c855caSPeter Wemm else if (strcmp(s, "BREAK") == 0)
1013ee6b974cSMark Murray s = strdup("\\K\\c");
10149f65f104SPeter Wemm
10159b1aec48SLars Fredriksen if (!put_string(s))
101601c855caSPeter Wemm fatal(1, "Failed");
10179b1aec48SLars Fredriksen }
10189b1aec48SLars Fredriksen
1019ee6b974cSMark Murray int
get_char(void)1020ee6b974cSMark Murray get_char(void)
10219b1aec48SLars Fredriksen {
10229b1aec48SLars Fredriksen int status;
10239b1aec48SLars Fredriksen char c;
10249b1aec48SLars Fredriksen
1025e1b4d8d0SSheldon Hearn status = read(STDIN_FILENO, &c, 1);
10269b1aec48SLars Fredriksen
102701c855caSPeter Wemm switch (status) {
10289b1aec48SLars Fredriksen case 1:
10299b1aec48SLars Fredriksen return ((int)c & 0x7F);
10309b1aec48SLars Fredriksen
10319b1aec48SLars Fredriksen default:
10328491f234STim Kientzle chat_logf("warning: read() on stdin returned %d", status);
10339b1aec48SLars Fredriksen
10349b1aec48SLars Fredriksen case -1:
10359b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1)
103601c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m");
103701c855caSPeter Wemm
10389f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
103901c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m");
10409b1aec48SLars Fredriksen
10419b1aec48SLars Fredriksen return (-1);
10429b1aec48SLars Fredriksen }
10439b1aec48SLars Fredriksen }
10449b1aec48SLars Fredriksen
put_char(int c)1045ee6b974cSMark Murray int put_char(int c)
10469b1aec48SLars Fredriksen {
10479b1aec48SLars Fredriksen int status;
10489f65f104SPeter Wemm char ch = c;
10499b1aec48SLars Fredriksen
10509f65f104SPeter Wemm usleep(10000); /* inter-character typing delay (?) */
10519b1aec48SLars Fredriksen
1052e1b4d8d0SSheldon Hearn status = write(STDOUT_FILENO, &ch, 1);
10539b1aec48SLars Fredriksen
105401c855caSPeter Wemm switch (status) {
10559b1aec48SLars Fredriksen case 1:
10569b1aec48SLars Fredriksen return (0);
10579b1aec48SLars Fredriksen
10589b1aec48SLars Fredriksen default:
10598491f234STim Kientzle chat_logf("warning: write() on stdout returned %d", status);
10609b1aec48SLars Fredriksen
10619b1aec48SLars Fredriksen case -1:
10629b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1)
106301c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin, %m");
106401c855caSPeter Wemm
10659f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
106601c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m");
10679b1aec48SLars Fredriksen
10689b1aec48SLars Fredriksen return (-1);
10699b1aec48SLars Fredriksen }
10709b1aec48SLars Fredriksen }
10719b1aec48SLars Fredriksen
1072ee6b974cSMark Murray int
write_char(int c)1073ee6b974cSMark Murray write_char(int c)
10749b1aec48SLars Fredriksen {
107501c855caSPeter Wemm if (alarmed || put_char(c) < 0) {
10769f65f104SPeter Wemm alarm(0);
10779f65f104SPeter Wemm alarmed = 0;
10789b1aec48SLars Fredriksen
107901c855caSPeter Wemm if (verbose) {
10809b1aec48SLars Fredriksen if (errno == EINTR || errno == EWOULDBLOCK)
10818491f234STim Kientzle chat_logf(" -- write timed out");
10829b1aec48SLars Fredriksen else
10838491f234STim Kientzle chat_logf(" -- write failed: %m");
10849f65f104SPeter Wemm }
10859b1aec48SLars Fredriksen return (0);
10869b1aec48SLars Fredriksen }
10879b1aec48SLars Fredriksen return (1);
10889b1aec48SLars Fredriksen }
10899b1aec48SLars Fredriksen
1090ee6b974cSMark Murray int
put_string(char * s)1091ee6b974cSMark Murray put_string(char *s)
10929b1aec48SLars Fredriksen {
10933d793cf1SPeter Wemm quiet = 0;
10949b1aec48SLars Fredriksen s = clean(s, 1);
10959b1aec48SLars Fredriksen
1096ee6b974cSMark Murray if (verbose)
10978491f234STim Kientzle chat_logf("send (%v)", quiet ? "??????" : s);
10989b1aec48SLars Fredriksen
10999b1aec48SLars Fredriksen alarm(timeout); alarmed = 0;
11009b1aec48SLars Fredriksen
110101c855caSPeter Wemm while (*s) {
1102ee6b974cSMark Murray char c = *s++;
11039b1aec48SLars Fredriksen
110401c855caSPeter Wemm if (c != '\\') {
11059b1aec48SLars Fredriksen if (!write_char (c))
11069b1aec48SLars Fredriksen return 0;
11079b1aec48SLars Fredriksen continue;
11089b1aec48SLars Fredriksen }
11099b1aec48SLars Fredriksen
11109b1aec48SLars Fredriksen c = *s++;
111101c855caSPeter Wemm switch (c) {
11129b1aec48SLars Fredriksen case 'd':
11139b1aec48SLars Fredriksen sleep(1);
11149b1aec48SLars Fredriksen break;
11159b1aec48SLars Fredriksen
11169b1aec48SLars Fredriksen case 'K':
11179b1aec48SLars Fredriksen break_sequence();
11189b1aec48SLars Fredriksen break;
11199b1aec48SLars Fredriksen
11209b1aec48SLars Fredriksen case 'p':
11219f65f104SPeter Wemm usleep(10000); /* 1/100th of a second (arg is microseconds) */
11229b1aec48SLars Fredriksen break;
11239b1aec48SLars Fredriksen
11249b1aec48SLars Fredriksen default:
11259b1aec48SLars Fredriksen if (!write_char (c))
11269b1aec48SLars Fredriksen return 0;
11279b1aec48SLars Fredriksen break;
11289b1aec48SLars Fredriksen }
11299b1aec48SLars Fredriksen }
11309b1aec48SLars Fredriksen
11319b1aec48SLars Fredriksen alarm(0);
11329b1aec48SLars Fredriksen alarmed = 0;
11339b1aec48SLars Fredriksen return (1);
11349b1aec48SLars Fredriksen }
11359b1aec48SLars Fredriksen
11369b1aec48SLars Fredriksen /*
11373d793cf1SPeter Wemm * Echo a character to stderr.
11383d793cf1SPeter Wemm * When called with -1, a '\n' character is generated when
11393d793cf1SPeter Wemm * the cursor is not at the beginning of a line.
11403d793cf1SPeter Wemm */
1141ee6b974cSMark Murray void
echo_stderr(int n)1142ee6b974cSMark Murray echo_stderr(int n)
11433d793cf1SPeter Wemm {
11443d793cf1SPeter Wemm static int need_lf;
11453d793cf1SPeter Wemm char *s;
11463d793cf1SPeter Wemm
114701c855caSPeter Wemm switch (n) {
11483d793cf1SPeter Wemm case '\r': /* ignore '\r' */
11493d793cf1SPeter Wemm break;
11503d793cf1SPeter Wemm case -1:
11513d793cf1SPeter Wemm if (need_lf == 0)
11523d793cf1SPeter Wemm break;
115393b0017fSPhilippe Charnier /* FALLTHROUGH */
11543d793cf1SPeter Wemm case '\n':
1155e1b4d8d0SSheldon Hearn write(STDERR_FILENO, "\n", 1);
11563d793cf1SPeter Wemm need_lf = 0;
11573d793cf1SPeter Wemm break;
11583d793cf1SPeter Wemm default:
11593d793cf1SPeter Wemm s = character(n);
1160e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s));
11613d793cf1SPeter Wemm need_lf = 1;
11623d793cf1SPeter Wemm break;
11633d793cf1SPeter Wemm }
11643d793cf1SPeter Wemm }
11653d793cf1SPeter Wemm
11663d793cf1SPeter Wemm /*
11679b1aec48SLars Fredriksen * 'Wait for' this string to appear on this file descriptor.
11689b1aec48SLars Fredriksen */
1169ee6b974cSMark Murray int
get_string(char * string)1170ee6b974cSMark Murray get_string(char *string)
11719b1aec48SLars Fredriksen {
11729b1aec48SLars Fredriksen char temp[STR_LEN];
1173f9fe1649SAlan Somers int c;
1174ee6b974cSMark Murray size_t len, minlen;
1175ee6b974cSMark Murray char *s = temp, *end = s + STR_LEN;
117601c855caSPeter Wemm char *logged = temp;
11779b1aec48SLars Fredriksen
11789b1aec48SLars Fredriksen fail_reason = (char *)0;
11794e83a8feSKris Kennaway
11804e83a8feSKris Kennaway if (strlen(string) > STR_LEN) {
11818491f234STim Kientzle chat_logf("expect string is too long");
11824e83a8feSKris Kennaway exit_code = 1;
11834e83a8feSKris Kennaway return 0;
11844e83a8feSKris Kennaway }
11854e83a8feSKris Kennaway
11869b1aec48SLars Fredriksen string = clean(string, 0);
11879b1aec48SLars Fredriksen len = strlen(string);
11889b1aec48SLars Fredriksen minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
11899b1aec48SLars Fredriksen
11909b1aec48SLars Fredriksen if (verbose)
11918491f234STim Kientzle chat_logf("expect (%v)", string);
11929b1aec48SLars Fredriksen
119301c855caSPeter Wemm if (len == 0) {
11949b1aec48SLars Fredriksen if (verbose)
11958491f234STim Kientzle chat_logf("got it");
11969b1aec48SLars Fredriksen return (1);
11979b1aec48SLars Fredriksen }
11989b1aec48SLars Fredriksen
11999f65f104SPeter Wemm alarm(timeout);
12009f65f104SPeter Wemm alarmed = 0;
12019b1aec48SLars Fredriksen
120201c855caSPeter Wemm while ( ! alarmed && (c = get_char()) >= 0) {
12039f65f104SPeter Wemm int n, abort_len, report_len;
12049b1aec48SLars Fredriksen
12053d793cf1SPeter Wemm if (echo)
12063d793cf1SPeter Wemm echo_stderr(c);
120701c855caSPeter Wemm if (verbose && c == '\n') {
120801c855caSPeter Wemm if (s == logged)
12098491f234STim Kientzle chat_logf(""); /* blank line */
12109b1aec48SLars Fredriksen else
12118491f234STim Kientzle chat_logf("%0.*v", s - logged, logged);
121201c855caSPeter Wemm logged = s + 1;
12133d793cf1SPeter Wemm }
12143d793cf1SPeter Wemm
12159b1aec48SLars Fredriksen *s++ = c;
12169b1aec48SLars Fredriksen
121701c855caSPeter Wemm if (verbose && s >= logged + 80) {
12188491f234STim Kientzle chat_logf("%0.*v", s - logged, logged);
121901c855caSPeter Wemm logged = s;
122001c855caSPeter Wemm }
122101c855caSPeter Wemm
122201c855caSPeter Wemm if (Verbose) {
122301c855caSPeter Wemm if (c == '\n')
122401c855caSPeter Wemm fputc( '\n', stderr );
122501c855caSPeter Wemm else if (c != '\r')
122601c855caSPeter Wemm fprintf( stderr, "%s", character(c) );
122701c855caSPeter Wemm }
122801c855caSPeter Wemm
122901c855caSPeter Wemm if (!report_gathering) {
123001c855caSPeter Wemm for (n = 0; n < n_reports; ++n) {
12319f65f104SPeter Wemm if ((report_string[n] != (char*) NULL) &&
12329f65f104SPeter Wemm s - temp >= (report_len = strlen(report_string[n])) &&
123301c855caSPeter Wemm strncmp(s - report_len, report_string[n], report_len) == 0) {
12349f65f104SPeter Wemm time_t time_now = time ((time_t*) NULL);
12359f65f104SPeter Wemm struct tm* tm_now = localtime (&time_now);
12369f65f104SPeter Wemm
12379f65f104SPeter Wemm strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
12389f65f104SPeter Wemm strcat (report_buffer, report_string[n]);
12399f65f104SPeter Wemm
12409f65f104SPeter Wemm report_string[n] = (char *) NULL;
12419f65f104SPeter Wemm report_gathering = 1;
12429f65f104SPeter Wemm break;
12439f65f104SPeter Wemm }
12449f65f104SPeter Wemm }
12459f65f104SPeter Wemm }
124601c855caSPeter Wemm else {
124701c855caSPeter Wemm if (!iscntrl (c)) {
12489f65f104SPeter Wemm int rep_len = strlen (report_buffer);
12499f65f104SPeter Wemm report_buffer[rep_len] = c;
12509f65f104SPeter Wemm report_buffer[rep_len + 1] = '\0';
12519f65f104SPeter Wemm }
125201c855caSPeter Wemm else {
12539f65f104SPeter Wemm report_gathering = 0;
12549f65f104SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer);
12559f65f104SPeter Wemm }
12569f65f104SPeter Wemm }
12579b1aec48SLars Fredriksen
1258ee6b974cSMark Murray if ((size_t)(s - temp) >= len &&
12593d793cf1SPeter Wemm c == string[len - 1] &&
126001c855caSPeter Wemm strncmp(s - len, string, len) == 0) {
126101c855caSPeter Wemm if (verbose) {
126201c855caSPeter Wemm if (s > logged)
12638491f234STim Kientzle chat_logf("%0.*v", s - logged, logged);
12648491f234STim Kientzle chat_logf(" -- got it\n");
12653d793cf1SPeter Wemm }
12663d793cf1SPeter Wemm
12673d793cf1SPeter Wemm alarm(0);
12683d793cf1SPeter Wemm alarmed = 0;
12693d793cf1SPeter Wemm return (1);
12703d793cf1SPeter Wemm }
12713d793cf1SPeter Wemm
127201c855caSPeter Wemm for (n = 0; n < n_aborts; ++n) {
12733d793cf1SPeter Wemm if (s - temp >= (abort_len = strlen(abort_string[n])) &&
127401c855caSPeter Wemm strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
127501c855caSPeter Wemm if (verbose) {
127601c855caSPeter Wemm if (s > logged)
12778491f234STim Kientzle chat_logf("%0.*v", s - logged, logged);
12788491f234STim Kientzle chat_logf(" -- failed");
12793d793cf1SPeter Wemm }
12803d793cf1SPeter Wemm
12813d793cf1SPeter Wemm alarm(0);
12823d793cf1SPeter Wemm alarmed = 0;
12833d793cf1SPeter Wemm exit_code = n + 4;
12843d793cf1SPeter Wemm strcpy(fail_reason = fail_buffer, abort_string[n]);
12853d793cf1SPeter Wemm return (0);
12863d793cf1SPeter Wemm }
12873d793cf1SPeter Wemm }
12883d793cf1SPeter Wemm
128901c855caSPeter Wemm if (s >= end) {
129001c855caSPeter Wemm if (logged < s - minlen) {
12918491f234STim Kientzle chat_logf("%0.*v", s - logged, logged);
129201c855caSPeter Wemm logged = s;
129301c855caSPeter Wemm }
129401c855caSPeter Wemm s -= minlen;
129501c855caSPeter Wemm memmove(temp, s, minlen);
129601c855caSPeter Wemm logged = temp + (logged - s);
12979b1aec48SLars Fredriksen s = temp + minlen;
12989b1aec48SLars Fredriksen }
12999b1aec48SLars Fredriksen
13009b1aec48SLars Fredriksen if (alarmed && verbose)
13018491f234STim Kientzle chat_logf("warning: alarm synchronization problem");
13029f65f104SPeter Wemm }
13039b1aec48SLars Fredriksen
13049b1aec48SLars Fredriksen alarm(0);
13059b1aec48SLars Fredriksen
13069f65f104SPeter Wemm exit_code = 3;
13079b1aec48SLars Fredriksen alarmed = 0;
13089b1aec48SLars Fredriksen return (0);
13099b1aec48SLars Fredriksen }
13109b1aec48SLars Fredriksen
13113d793cf1SPeter Wemm void
pack_array(char ** array,int end)1312ee6b974cSMark Murray pack_array(char **array, int end)
13133d793cf1SPeter Wemm {
13143d793cf1SPeter Wemm int i, j;
13153d793cf1SPeter Wemm
13163d793cf1SPeter Wemm for (i = 0; i < end; i++) {
13173d793cf1SPeter Wemm if (array[i] == NULL) {
13183d793cf1SPeter Wemm for (j = i+1; j < end; ++j)
13193d793cf1SPeter Wemm if (array[j] != NULL)
13203d793cf1SPeter Wemm array[i++] = array[j];
13213d793cf1SPeter Wemm for (; i < end; ++i)
13223d793cf1SPeter Wemm array[i] = NULL;
13233d793cf1SPeter Wemm break;
13243d793cf1SPeter Wemm }
13253d793cf1SPeter Wemm }
13263d793cf1SPeter Wemm }
132701c855caSPeter Wemm
132801c855caSPeter Wemm /*
132901c855caSPeter Wemm * vfmtmsg - format a message into a buffer. Like vsprintf except we
133001c855caSPeter Wemm * also specify the length of the output buffer, and we handle the
133101c855caSPeter Wemm * %m (error message) format.
133201c855caSPeter Wemm * Doesn't do floating-point formats.
133301c855caSPeter Wemm * Returns the number of chars put into buf.
133401c855caSPeter Wemm */
133501c855caSPeter Wemm #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
133601c855caSPeter Wemm
133701c855caSPeter Wemm int
vfmtmsg(char * buf,int buflen,const char * fmt,va_list args)1338ee6b974cSMark Murray vfmtmsg(char *buf, int buflen, const char *fmt, va_list args)
133901c855caSPeter Wemm {
134001c855caSPeter Wemm int c, i, n;
134101c855caSPeter Wemm int width, prec, fillch;
134201c855caSPeter Wemm int base, len, neg, quoted;
134301c855caSPeter Wemm unsigned long val = 0;
134401c855caSPeter Wemm char *str, *buf0;
134501c855caSPeter Wemm const char *f;
134601c855caSPeter Wemm unsigned char *p;
134701c855caSPeter Wemm char num[32];
134801c855caSPeter Wemm static char hexchars[] = "0123456789abcdef";
134901c855caSPeter Wemm
135001c855caSPeter Wemm buf0 = buf;
135101c855caSPeter Wemm --buflen;
135201c855caSPeter Wemm while (buflen > 0) {
135301c855caSPeter Wemm for (f = fmt; *f != '%' && *f != 0; ++f)
135401c855caSPeter Wemm ;
135501c855caSPeter Wemm if (f > fmt) {
135601c855caSPeter Wemm len = f - fmt;
135701c855caSPeter Wemm if (len > buflen)
135801c855caSPeter Wemm len = buflen;
135901c855caSPeter Wemm memcpy(buf, fmt, len);
136001c855caSPeter Wemm buf += len;
136101c855caSPeter Wemm buflen -= len;
136201c855caSPeter Wemm fmt = f;
136301c855caSPeter Wemm }
136401c855caSPeter Wemm if (*fmt == 0)
136501c855caSPeter Wemm break;
136601c855caSPeter Wemm c = *++fmt;
136701c855caSPeter Wemm width = prec = 0;
136801c855caSPeter Wemm fillch = ' ';
136901c855caSPeter Wemm if (c == '0') {
137001c855caSPeter Wemm fillch = '0';
137101c855caSPeter Wemm c = *++fmt;
137201c855caSPeter Wemm }
137301c855caSPeter Wemm if (c == '*') {
137401c855caSPeter Wemm width = va_arg(args, int);
137501c855caSPeter Wemm c = *++fmt;
137601c855caSPeter Wemm } else {
137701c855caSPeter Wemm while (isdigit(c)) {
137801c855caSPeter Wemm width = width * 10 + c - '0';
137901c855caSPeter Wemm c = *++fmt;
138001c855caSPeter Wemm }
138101c855caSPeter Wemm }
138201c855caSPeter Wemm if (c == '.') {
138301c855caSPeter Wemm c = *++fmt;
138401c855caSPeter Wemm if (c == '*') {
138501c855caSPeter Wemm prec = va_arg(args, int);
138601c855caSPeter Wemm c = *++fmt;
138701c855caSPeter Wemm } else {
138801c855caSPeter Wemm while (isdigit(c)) {
138901c855caSPeter Wemm prec = prec * 10 + c - '0';
139001c855caSPeter Wemm c = *++fmt;
139101c855caSPeter Wemm }
139201c855caSPeter Wemm }
139301c855caSPeter Wemm }
139459009de8SPedro F. Giffuni str = NULL;
139501c855caSPeter Wemm base = 0;
139601c855caSPeter Wemm neg = 0;
139701c855caSPeter Wemm ++fmt;
139801c855caSPeter Wemm switch (c) {
139901c855caSPeter Wemm case 'd':
140001c855caSPeter Wemm i = va_arg(args, int);
140101c855caSPeter Wemm if (i < 0) {
140201c855caSPeter Wemm neg = 1;
140301c855caSPeter Wemm val = -i;
140401c855caSPeter Wemm } else
140501c855caSPeter Wemm val = i;
140601c855caSPeter Wemm base = 10;
140701c855caSPeter Wemm break;
140801c855caSPeter Wemm case 'o':
140901c855caSPeter Wemm val = va_arg(args, unsigned int);
141001c855caSPeter Wemm base = 8;
141101c855caSPeter Wemm break;
141201c855caSPeter Wemm case 'x':
141301c855caSPeter Wemm val = va_arg(args, unsigned int);
141401c855caSPeter Wemm base = 16;
141501c855caSPeter Wemm break;
141601c855caSPeter Wemm case 'p':
141701c855caSPeter Wemm val = (unsigned long) va_arg(args, void *);
141801c855caSPeter Wemm base = 16;
141901c855caSPeter Wemm neg = 2;
142001c855caSPeter Wemm break;
142101c855caSPeter Wemm case 's':
142201c855caSPeter Wemm str = va_arg(args, char *);
142301c855caSPeter Wemm break;
142401c855caSPeter Wemm case 'c':
142501c855caSPeter Wemm num[0] = va_arg(args, int);
142601c855caSPeter Wemm num[1] = 0;
142701c855caSPeter Wemm str = num;
142801c855caSPeter Wemm break;
142901c855caSPeter Wemm case 'm':
143001c855caSPeter Wemm str = strerror(errno);
143101c855caSPeter Wemm break;
143201c855caSPeter Wemm case 'v': /* "visible" string */
143301c855caSPeter Wemm case 'q': /* quoted string */
143401c855caSPeter Wemm quoted = c == 'q';
143501c855caSPeter Wemm p = va_arg(args, unsigned char *);
143601c855caSPeter Wemm if (fillch == '0' && prec > 0) {
143701c855caSPeter Wemm n = prec;
143801c855caSPeter Wemm } else {
143901c855caSPeter Wemm n = strlen((char *)p);
144001c855caSPeter Wemm if (prec > 0 && prec < n)
144101c855caSPeter Wemm n = prec;
144201c855caSPeter Wemm }
144301c855caSPeter Wemm while (n > 0 && buflen > 0) {
144401c855caSPeter Wemm c = *p++;
144501c855caSPeter Wemm --n;
144601c855caSPeter Wemm if (!quoted && c >= 0x80) {
144701c855caSPeter Wemm OUTCHAR('M');
144801c855caSPeter Wemm OUTCHAR('-');
144901c855caSPeter Wemm c -= 0x80;
145001c855caSPeter Wemm }
145101c855caSPeter Wemm if (quoted && (c == '"' || c == '\\'))
145201c855caSPeter Wemm OUTCHAR('\\');
145301c855caSPeter Wemm if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
145401c855caSPeter Wemm if (quoted) {
145501c855caSPeter Wemm OUTCHAR('\\');
145601c855caSPeter Wemm switch (c) {
145701c855caSPeter Wemm case '\t': OUTCHAR('t'); break;
145801c855caSPeter Wemm case '\n': OUTCHAR('n'); break;
145901c855caSPeter Wemm case '\b': OUTCHAR('b'); break;
146001c855caSPeter Wemm case '\f': OUTCHAR('f'); break;
146101c855caSPeter Wemm default:
146201c855caSPeter Wemm OUTCHAR('x');
146301c855caSPeter Wemm OUTCHAR(hexchars[c >> 4]);
146401c855caSPeter Wemm OUTCHAR(hexchars[c & 0xf]);
146501c855caSPeter Wemm }
146601c855caSPeter Wemm } else {
146701c855caSPeter Wemm if (c == '\t')
146801c855caSPeter Wemm OUTCHAR(c);
146901c855caSPeter Wemm else {
147001c855caSPeter Wemm OUTCHAR('^');
147101c855caSPeter Wemm OUTCHAR(c ^ 0x40);
147201c855caSPeter Wemm }
147301c855caSPeter Wemm }
147401c855caSPeter Wemm } else
147501c855caSPeter Wemm OUTCHAR(c);
147601c855caSPeter Wemm }
147701c855caSPeter Wemm continue;
147801c855caSPeter Wemm default:
147901c855caSPeter Wemm *buf++ = '%';
148001c855caSPeter Wemm if (c != '%')
148101c855caSPeter Wemm --fmt; /* so %z outputs %z etc. */
148201c855caSPeter Wemm --buflen;
148301c855caSPeter Wemm continue;
148401c855caSPeter Wemm }
148501c855caSPeter Wemm if (base != 0) {
148601c855caSPeter Wemm str = num + sizeof(num);
148701c855caSPeter Wemm *--str = 0;
148801c855caSPeter Wemm while (str > num + neg) {
148901c855caSPeter Wemm *--str = hexchars[val % base];
149001c855caSPeter Wemm val = val / base;
149101c855caSPeter Wemm if (--prec <= 0 && val == 0)
149201c855caSPeter Wemm break;
149301c855caSPeter Wemm }
149401c855caSPeter Wemm switch (neg) {
149501c855caSPeter Wemm case 1:
149601c855caSPeter Wemm *--str = '-';
149701c855caSPeter Wemm break;
149801c855caSPeter Wemm case 2:
149901c855caSPeter Wemm *--str = 'x';
150001c855caSPeter Wemm *--str = '0';
150101c855caSPeter Wemm break;
150201c855caSPeter Wemm }
150301c855caSPeter Wemm len = num + sizeof(num) - 1 - str;
150401c855caSPeter Wemm } else {
150501c855caSPeter Wemm len = strlen(str);
150601c855caSPeter Wemm if (prec > 0 && len > prec)
150701c855caSPeter Wemm len = prec;
150801c855caSPeter Wemm }
150901c855caSPeter Wemm if (width > 0) {
151001c855caSPeter Wemm if (width > buflen)
151101c855caSPeter Wemm width = buflen;
151201c855caSPeter Wemm if ((n = width - len) > 0) {
151301c855caSPeter Wemm buflen -= n;
151401c855caSPeter Wemm for (; n > 0; --n)
151501c855caSPeter Wemm *buf++ = fillch;
151601c855caSPeter Wemm }
151701c855caSPeter Wemm }
151801c855caSPeter Wemm if (len > buflen)
151901c855caSPeter Wemm len = buflen;
152001c855caSPeter Wemm memcpy(buf, str, len);
152101c855caSPeter Wemm buf += len;
152201c855caSPeter Wemm buflen -= len;
152301c855caSPeter Wemm }
152401c855caSPeter Wemm *buf = 0;
152501c855caSPeter Wemm return buf - buf0;
152601c855caSPeter Wemm }
1527