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 80ee6b974cSMark Murray #include <sys/cdefs.h> 81ee6b974cSMark Murray __FBSDID("$FreeBSD$"); 829b1aec48SLars Fredriksen 839b1aec48SLars Fredriksen #include <sys/types.h> 849b1aec48SLars Fredriksen #include <sys/stat.h> 85ee6b974cSMark Murray #include <ctype.h> 86ee6b974cSMark Murray #include <errno.h> 87ee6b974cSMark Murray #include <fcntl.h> 88ee6b974cSMark Murray #include <signal.h> 89ee6b974cSMark Murray #include <stdarg.h> 90ee6b974cSMark Murray #include <stdio.h> 91ee6b974cSMark Murray #include <stdlib.h> 92ee6b974cSMark Murray #include <string.h> 939b1aec48SLars Fredriksen #include <syslog.h> 949b1aec48SLars Fredriksen #include <termios.h> 95ee6b974cSMark Murray #include <time.h> 96ee6b974cSMark Murray #include <unistd.h> 979b1aec48SLars Fredriksen 989b1aec48SLars Fredriksen #define STR_LEN 1024 999b1aec48SLars Fredriksen 1009b1aec48SLars Fredriksen #ifndef SIGTYPE 1019b1aec48SLars Fredriksen #define SIGTYPE void 1029b1aec48SLars Fredriksen #endif 1039b1aec48SLars Fredriksen 1049f65f104SPeter Wemm #ifndef O_NONBLOCK 1059f65f104SPeter Wemm #define O_NONBLOCK O_NDELAY 1069f65f104SPeter Wemm #endif 1079f65f104SPeter Wemm 1089b1aec48SLars Fredriksen #define MAX_ABORTS 50 1099f65f104SPeter Wemm #define MAX_REPORTS 50 1109b1aec48SLars Fredriksen #define DEFAULT_CHAT_TIMEOUT 45 1119b1aec48SLars Fredriksen 1123d793cf1SPeter Wemm int echo = 0; 1139b1aec48SLars Fredriksen int verbose = 0; 11401c855caSPeter Wemm int to_log = 1; 11501c855caSPeter Wemm int to_stderr = 0; 1163d793cf1SPeter Wemm int Verbose = 0; 1179b1aec48SLars Fredriksen int quiet = 0; 1189f65f104SPeter Wemm int exit_code = 0; 1199f65f104SPeter Wemm FILE* report_fp = (FILE *) 0; 1209f65f104SPeter Wemm char *report_file = (char *) 0; 1219b1aec48SLars Fredriksen char *chat_file = (char *) 0; 12201c855caSPeter Wemm char *phone_num = (char *) 0; 12301c855caSPeter Wemm char *phone_num2 = (char *) 0; 1249b1aec48SLars Fredriksen int timeout = DEFAULT_CHAT_TIMEOUT; 1259b1aec48SLars Fredriksen 126ee6b974cSMark Murray static char blank[] = ""; 127ee6b974cSMark Murray 1289b1aec48SLars Fredriksen int have_tty_parameters = 0; 1299f65f104SPeter Wemm 1309f65f104SPeter Wemm #define term_parms struct termios 1319f65f104SPeter Wemm #define get_term_param(param) tcgetattr(0, param) 1329f65f104SPeter Wemm #define set_term_param(param) tcsetattr(0, TCSANOW, param) 1339b1aec48SLars Fredriksen struct termios saved_tty_parameters; 1349b1aec48SLars Fredriksen 1359b1aec48SLars Fredriksen char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1369b1aec48SLars Fredriksen fail_buffer[50]; 1373d793cf1SPeter Wemm int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0; 1383d793cf1SPeter Wemm int clear_abort_next = 0; 1399b1aec48SLars Fredriksen 1409f65f104SPeter Wemm char *report_string[MAX_REPORTS] ; 1419f65f104SPeter Wemm char report_buffer[50] ; 1429f65f104SPeter Wemm int n_reports = 0, report_next = 0, report_gathering = 0 ; 1433d793cf1SPeter Wemm int clear_report_next = 0; 1443d793cf1SPeter Wemm 1453d793cf1SPeter Wemm int say_next = 0, hup_next = 0; 1469f65f104SPeter Wemm 147f1bb2cd2SWarner Losh void *dup_mem(void *b, size_t c); 148f1bb2cd2SWarner Losh void *copy_of(char *s); 149f1bb2cd2SWarner Losh static void usage(void); 1508491f234STim Kientzle void chat_logf(const char *fmt, ...); 151f1bb2cd2SWarner Losh void fatal(int code, const char *fmt, ...); 152f1bb2cd2SWarner Losh SIGTYPE sigalrm(int signo); 153f1bb2cd2SWarner Losh SIGTYPE sigint(int signo); 154f1bb2cd2SWarner Losh SIGTYPE sigterm(int signo); 155f1bb2cd2SWarner Losh SIGTYPE sighup(int signo); 156f1bb2cd2SWarner Losh void init(void); 157f1bb2cd2SWarner Losh void set_tty_parameters(void); 158f1bb2cd2SWarner Losh void echo_stderr(int); 159f1bb2cd2SWarner Losh void break_sequence(void); 160f1bb2cd2SWarner Losh void terminate(int status); 161ee6b974cSMark Murray void do_file(char *chatfile); 162ee6b974cSMark Murray int get_string(char *string); 163ee6b974cSMark Murray int put_string(char *s); 164f1bb2cd2SWarner Losh int write_char(int c); 165f1bb2cd2SWarner Losh int put_char(int c); 166f1bb2cd2SWarner Losh int get_char(void); 167ee6b974cSMark Murray void chat_send(char *s); 168f1bb2cd2SWarner Losh char *character(int c); 169ee6b974cSMark Murray void chat_expect(char *s); 170ee6b974cSMark Murray char *clean(char *s, int sending); 171f1bb2cd2SWarner Losh void pack_array(char **array, int end); 172ee6b974cSMark Murray char *expect_strtok(char *, const char *); 173f1bb2cd2SWarner Losh int vfmtmsg(char *, int, const char *, va_list); /* vsprintf++ */ 1743d793cf1SPeter Wemm 175ee6b974cSMark Murray void * 176ee6b974cSMark Murray dup_mem(void *b, size_t c) 1779b1aec48SLars Fredriksen { 1789b1aec48SLars Fredriksen void *ans = malloc (c); 1799b1aec48SLars Fredriksen if (!ans) 18001c855caSPeter Wemm fatal(2, "memory error!"); 18101c855caSPeter Wemm 1829b1aec48SLars Fredriksen memcpy (ans, b, c); 1839b1aec48SLars Fredriksen return ans; 1849b1aec48SLars Fredriksen } 1859b1aec48SLars Fredriksen 186ee6b974cSMark Murray void * 187ee6b974cSMark Murray copy_of(char *s) 1889b1aec48SLars Fredriksen { 1899b1aec48SLars Fredriksen return dup_mem (s, strlen (s) + 1); 1909b1aec48SLars Fredriksen } 1919b1aec48SLars Fredriksen 1929b1aec48SLars Fredriksen /* 19318ebe779SXin LI * chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout] 19418ebe779SXin LI * [-T phone-number] [-U phone-number2] [chat-script] 19518ebe779SXin LI * where chat-script has the form: 19618ebe779SXin LI * [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]] 1979b1aec48SLars Fredriksen * 1989b1aec48SLars Fredriksen * Perform a UUCP-dialer-like chat script on stdin and stdout. 1999b1aec48SLars Fredriksen */ 2009b1aec48SLars Fredriksen int 201ee6b974cSMark Murray main(int argc, char *argv[]) 2029b1aec48SLars Fredriksen { 2039b1aec48SLars Fredriksen int option; 2049b1aec48SLars Fredriksen 2059f65f104SPeter Wemm tzset(); 2069b1aec48SLars Fredriksen 20718ebe779SXin LI while ((option = getopt(argc, argv, "ef:r:sSt:T:U:vV")) != -1) { 20801c855caSPeter Wemm switch (option) { 2093d793cf1SPeter Wemm case 'e': 2103d793cf1SPeter Wemm ++echo; 2113d793cf1SPeter Wemm break; 2123d793cf1SPeter Wemm 21318ebe779SXin LI case 'f': 21418ebe779SXin LI if (chat_file != NULL) 21518ebe779SXin LI free(chat_file); 21618ebe779SXin LI chat_file = copy_of(optarg); 2179b1aec48SLars Fredriksen break; 2189b1aec48SLars Fredriksen 21918ebe779SXin LI case 'r': 22018ebe779SXin LI if (report_fp != NULL) 22118ebe779SXin LI fclose(report_fp); 22218ebe779SXin LI if (report_file != NULL) 22318ebe779SXin LI free(report_file); 22418ebe779SXin LI report_file = copy_of(optarg); 22518ebe779SXin LI report_fp = fopen(report_file, "a"); 22618ebe779SXin LI if (report_fp != NULL) { 22718ebe779SXin LI if (verbose) 22818ebe779SXin LI fprintf(report_fp, "Opening \"%s\"...\n", report_file); 22918ebe779SXin LI } else 23018ebe779SXin LI fatal(2, "cannot open \"%s\" for appending", report_file); 2313d793cf1SPeter Wemm break; 2323d793cf1SPeter Wemm 23301c855caSPeter Wemm case 's': 23401c855caSPeter Wemm ++to_stderr; 23501c855caSPeter Wemm break; 23601c855caSPeter Wemm 23701c855caSPeter Wemm case 'S': 23801c855caSPeter Wemm to_log = 0; 23901c855caSPeter Wemm break; 24001c855caSPeter Wemm 2419b1aec48SLars Fredriksen case 't': 24218ebe779SXin LI timeout = atoi(optarg); 2439b1aec48SLars Fredriksen break; 2449b1aec48SLars Fredriksen 24501c855caSPeter Wemm case 'T': 24618ebe779SXin LI if (phone_num != NULL) 24718ebe779SXin LI free(phone_num); 24818ebe779SXin LI phone_num = copy_of(optarg); 24901c855caSPeter Wemm break; 25001c855caSPeter Wemm 25101c855caSPeter Wemm case 'U': 25218ebe779SXin LI if (phone_num2 != NULL) 25318ebe779SXin LI free(phone_num2); 25418ebe779SXin LI phone_num2 = copy_of(optarg); 25518ebe779SXin LI break; 25618ebe779SXin LI 25718ebe779SXin LI case 'v': 25818ebe779SXin LI ++verbose; 25918ebe779SXin LI break; 26018ebe779SXin LI 26118ebe779SXin LI case 'V': 26218ebe779SXin LI ++Verbose; 26301c855caSPeter Wemm break; 26401c855caSPeter Wemm 2659b1aec48SLars Fredriksen default: 2669b1aec48SLars Fredriksen usage(); 2679f65f104SPeter Wemm break; 2689f65f104SPeter Wemm } 2699f65f104SPeter Wemm } 27018ebe779SXin LI 27118ebe779SXin LI argc -= optind; 27218ebe779SXin LI argv += optind; 27318ebe779SXin LI 2749f65f104SPeter Wemm /* 2759f65f104SPeter Wemm * Default the report file to the stderr location 2769f65f104SPeter Wemm */ 2779f65f104SPeter Wemm if (report_fp == NULL) 2789f65f104SPeter Wemm report_fp = stderr; 2799b1aec48SLars Fredriksen 28001c855caSPeter Wemm if (to_log) { 2819b1aec48SLars Fredriksen openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 2829b1aec48SLars Fredriksen 2839f65f104SPeter Wemm if (verbose) 2849b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_INFO)); 2859f65f104SPeter Wemm else 2869b1aec48SLars Fredriksen setlogmask(LOG_UPTO(LOG_WARNING)); 28701c855caSPeter Wemm } 2889b1aec48SLars Fredriksen 28901c855caSPeter Wemm if (chat_file != NULL) { 29018ebe779SXin LI if (*argv != NULL) 2919b1aec48SLars Fredriksen usage(); 29218ebe779SXin LI else { 29318ebe779SXin LI init(); 2949b1aec48SLars Fredriksen do_file(chat_file); 29518ebe779SXin LI } 29601c855caSPeter Wemm } else { 29718ebe779SXin LI init(); 29818ebe779SXin LI while (*argv != NULL && argc > 0) { 29918ebe779SXin LI chat_expect(*argv); 30018ebe779SXin LI argv++; 30118ebe779SXin LI argc--; 3029b1aec48SLars Fredriksen 30318ebe779SXin LI if (*argv != NULL && argc > 0) { 30418ebe779SXin LI chat_send(*argv); 30518ebe779SXin LI argv++; 30618ebe779SXin LI argc--; 30718ebe779SXin LI } 3089b1aec48SLars Fredriksen } 3099b1aec48SLars Fredriksen } 3109b1aec48SLars Fredriksen 3119b1aec48SLars Fredriksen terminate(0); 3123d793cf1SPeter Wemm return 0; 3139b1aec48SLars Fredriksen } 3149b1aec48SLars Fredriksen 3159b1aec48SLars Fredriksen /* 3169b1aec48SLars Fredriksen * Process a chat script when read from a file. 3179b1aec48SLars Fredriksen */ 3189b1aec48SLars Fredriksen 319ee6b974cSMark Murray void 320ee6b974cSMark Murray do_file(char *chatfile) 3219b1aec48SLars Fredriksen { 322d7d10053SAlexander Langer int linect, sendflg; 3239b1aec48SLars Fredriksen char *sp, *arg, quote; 3249b1aec48SLars Fredriksen char buf [STR_LEN]; 3259b1aec48SLars Fredriksen FILE *cfp; 3269b1aec48SLars Fredriksen 327ee6b974cSMark Murray cfp = fopen (chatfile, "r"); 3289f65f104SPeter Wemm if (cfp == NULL) 329ee6b974cSMark Murray fatal(1, "%s -- open failed: %m", chatfile); 3309b1aec48SLars Fredriksen 3319b1aec48SLars Fredriksen linect = 0; 3329b1aec48SLars Fredriksen sendflg = 0; 3339b1aec48SLars Fredriksen 33401c855caSPeter Wemm while (fgets(buf, STR_LEN, cfp) != NULL) { 3359b1aec48SLars Fredriksen sp = strchr (buf, '\n'); 3369b1aec48SLars Fredriksen if (sp) 3379b1aec48SLars Fredriksen *sp = '\0'; 3389b1aec48SLars Fredriksen 3399b1aec48SLars Fredriksen linect++; 3409b1aec48SLars Fredriksen sp = buf; 3413d793cf1SPeter Wemm 3423d793cf1SPeter Wemm /* lines starting with '#' are comments. If a real '#' 3433d793cf1SPeter Wemm is to be expected, it should be quoted .... */ 34401c855caSPeter Wemm if ( *sp == '#' ) 34501c855caSPeter Wemm continue; 3463d793cf1SPeter Wemm 34701c855caSPeter Wemm while (*sp != '\0') { 34801c855caSPeter Wemm if (*sp == ' ' || *sp == '\t') { 3499b1aec48SLars Fredriksen ++sp; 3509b1aec48SLars Fredriksen continue; 3519b1aec48SLars Fredriksen } 3529b1aec48SLars Fredriksen 35301c855caSPeter Wemm if (*sp == '"' || *sp == '\'') { 3549b1aec48SLars Fredriksen quote = *sp++; 3559b1aec48SLars Fredriksen arg = sp; 35601c855caSPeter Wemm while (*sp != quote) { 3579b1aec48SLars Fredriksen if (*sp == '\0') 35801c855caSPeter Wemm fatal(1, "unterminated quote (line %d)", linect); 3599b1aec48SLars Fredriksen 36001c855caSPeter Wemm if (*sp++ == '\\') { 3619b1aec48SLars Fredriksen if (*sp != '\0') 3629b1aec48SLars Fredriksen ++sp; 3639b1aec48SLars Fredriksen } 3649b1aec48SLars Fredriksen } 3659f65f104SPeter Wemm } 36601c855caSPeter Wemm else { 3679b1aec48SLars Fredriksen arg = sp; 3689b1aec48SLars Fredriksen while (*sp != '\0' && *sp != ' ' && *sp != '\t') 3699b1aec48SLars Fredriksen ++sp; 3709b1aec48SLars Fredriksen } 3719b1aec48SLars Fredriksen 3729b1aec48SLars Fredriksen if (*sp != '\0') 3739b1aec48SLars Fredriksen *sp++ = '\0'; 3749b1aec48SLars Fredriksen 3759b1aec48SLars Fredriksen if (sendflg) 3769b1aec48SLars Fredriksen chat_send (arg); 3779b1aec48SLars Fredriksen else 3789b1aec48SLars Fredriksen chat_expect (arg); 3799b1aec48SLars Fredriksen sendflg = !sendflg; 3809b1aec48SLars Fredriksen } 3819b1aec48SLars Fredriksen } 3829b1aec48SLars Fredriksen fclose (cfp); 3839b1aec48SLars Fredriksen } 3849b1aec48SLars Fredriksen 3859b1aec48SLars Fredriksen /* 3869b1aec48SLars Fredriksen * We got an error parsing the command line. 3879b1aec48SLars Fredriksen */ 388afaeb553SPhilippe Charnier static void 389ee6b974cSMark Murray usage(void) 3909b1aec48SLars Fredriksen { 39118ebe779SXin LI fprintf(stderr, 39218ebe779SXin LI "Usage: chat [-esSvV] [-f chat-file] [-r report-file] [-t timeout]\n" 39318ebe779SXin LI " [-T phone-number] [-U phone-number2] [chat-script]\n" 39418ebe779SXin LI "where chat-script has the form:\n" 39518ebe779SXin LI " [...[[expect[-send[-expect...]] send expect[-send[-expect]] ...]]]\n"); 3969b1aec48SLars Fredriksen exit(1); 3979b1aec48SLars Fredriksen } 3989b1aec48SLars Fredriksen 39901c855caSPeter Wemm char line[1024]; 4009b1aec48SLars Fredriksen 4019b1aec48SLars Fredriksen /* 40201c855caSPeter Wemm * Send a message to syslog and/or stderr. 4039b1aec48SLars Fredriksen */ 404ee6b974cSMark Murray void 4058491f234STim Kientzle chat_logf(const char *fmt, ...) 4069b1aec48SLars Fredriksen { 40701c855caSPeter Wemm va_list args; 40801c855caSPeter Wemm 40901c855caSPeter Wemm va_start(args, fmt); 41001c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 411*544c5e5bSKevin Lo va_end(args); 41201c855caSPeter Wemm if (to_log) 41301c855caSPeter Wemm syslog(LOG_INFO, "%s", line); 41401c855caSPeter Wemm if (to_stderr) 41501c855caSPeter Wemm fprintf(stderr, "%s\n", line); 4169b1aec48SLars Fredriksen } 4179b1aec48SLars Fredriksen 4189b1aec48SLars Fredriksen /* 4199b1aec48SLars Fredriksen * Print an error message and terminate. 4209b1aec48SLars Fredriksen */ 4219b1aec48SLars Fredriksen 422ee6b974cSMark Murray void 423ee6b974cSMark Murray fatal(int code, const char *fmt, ...) 4249b1aec48SLars Fredriksen { 42501c855caSPeter Wemm va_list args; 4269b1aec48SLars Fredriksen 42701c855caSPeter Wemm va_start(args, fmt); 42801c855caSPeter Wemm vfmtmsg(line, sizeof(line), fmt, args); 429*544c5e5bSKevin Lo va_end(args); 43001c855caSPeter Wemm if (to_log) 43101c855caSPeter Wemm syslog(LOG_ERR, "%s", line); 43201c855caSPeter Wemm if (to_stderr) 43301c855caSPeter Wemm fprintf(stderr, "%s\n", line); 43401c855caSPeter Wemm terminate(code); 4359b1aec48SLars Fredriksen } 4369b1aec48SLars Fredriksen 4379b1aec48SLars Fredriksen int alarmed = 0; 4389b1aec48SLars Fredriksen 439ee6b974cSMark Murray SIGTYPE sigalrm(int signo __unused) 4409b1aec48SLars Fredriksen { 4419b1aec48SLars Fredriksen int flags; 4429b1aec48SLars Fredriksen 4439b1aec48SLars Fredriksen alarm(1); 4449b1aec48SLars Fredriksen alarmed = 1; /* Reset alarm to avoid race window */ 4459b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4469b1aec48SLars Fredriksen 4479b1aec48SLars Fredriksen if ((flags = fcntl(0, F_GETFL, 0)) == -1) 44801c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 44901c855caSPeter Wemm 4509f65f104SPeter Wemm if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 45101c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 4529b1aec48SLars Fredriksen 4539b1aec48SLars Fredriksen if (verbose) 4548491f234STim Kientzle chat_logf("alarm"); 4559b1aec48SLars Fredriksen } 4569b1aec48SLars Fredriksen 457ee6b974cSMark Murray SIGTYPE sigint(int signo __unused) 4589b1aec48SLars Fredriksen { 45901c855caSPeter Wemm fatal(2, "SIGINT"); 4609b1aec48SLars Fredriksen } 4619b1aec48SLars Fredriksen 462ee6b974cSMark Murray SIGTYPE sigterm(int signo __unused) 4639b1aec48SLars Fredriksen { 46401c855caSPeter Wemm fatal(2, "SIGTERM"); 4659b1aec48SLars Fredriksen } 4669b1aec48SLars Fredriksen 467ee6b974cSMark Murray SIGTYPE sighup(int signo __unused) 4689b1aec48SLars Fredriksen { 46901c855caSPeter Wemm fatal(2, "SIGHUP"); 4709b1aec48SLars Fredriksen } 4719b1aec48SLars Fredriksen 472ee6b974cSMark Murray void init(void) 4739b1aec48SLars Fredriksen { 4749b1aec48SLars Fredriksen signal(SIGINT, sigint); 4759b1aec48SLars Fredriksen signal(SIGTERM, sigterm); 4769b1aec48SLars Fredriksen signal(SIGHUP, sighup); 4779b1aec48SLars Fredriksen 4789b1aec48SLars Fredriksen set_tty_parameters(); 4799b1aec48SLars Fredriksen signal(SIGALRM, sigalrm); 4809b1aec48SLars Fredriksen alarm(0); 4819b1aec48SLars Fredriksen alarmed = 0; 4829b1aec48SLars Fredriksen } 4839b1aec48SLars Fredriksen 484ee6b974cSMark Murray void set_tty_parameters(void) 4859b1aec48SLars Fredriksen { 4869f65f104SPeter Wemm #if defined(get_term_param) 4879f65f104SPeter Wemm term_parms t; 4889b1aec48SLars Fredriksen 4899f65f104SPeter Wemm if (get_term_param (&t) < 0) 49001c855caSPeter Wemm fatal(2, "Can't get terminal parameters: %m"); 4919b1aec48SLars Fredriksen 4929b1aec48SLars Fredriksen saved_tty_parameters = t; 4939b1aec48SLars Fredriksen have_tty_parameters = 1; 4949b1aec48SLars Fredriksen 4959b1aec48SLars Fredriksen t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 4969b1aec48SLars Fredriksen t.c_oflag = 0; 4979b1aec48SLars Fredriksen t.c_lflag = 0; 4989f65f104SPeter Wemm t.c_cc[VERASE] = 4999f65f104SPeter Wemm t.c_cc[VKILL] = 0; 5009b1aec48SLars Fredriksen t.c_cc[VMIN] = 1; 5019b1aec48SLars Fredriksen t.c_cc[VTIME] = 0; 5029b1aec48SLars Fredriksen 5039f65f104SPeter Wemm if (set_term_param (&t) < 0) 50401c855caSPeter Wemm fatal(2, "Can't set terminal parameters: %m"); 5059b1aec48SLars Fredriksen #endif 5069b1aec48SLars Fredriksen } 5079b1aec48SLars Fredriksen 508ee6b974cSMark Murray void break_sequence(void) 5099b1aec48SLars Fredriksen { 5109b1aec48SLars Fredriksen tcsendbreak (0, 0); 5119b1aec48SLars Fredriksen } 5129b1aec48SLars Fredriksen 513ee6b974cSMark Murray void terminate(int status) 5149b1aec48SLars Fredriksen { 5153d793cf1SPeter Wemm echo_stderr(-1); 51601c855caSPeter Wemm if (report_file != (char *) 0 && report_fp != (FILE *) NULL) { 5173d793cf1SPeter Wemm /* 5183d793cf1SPeter Wemm * Allow the last of the report string to be gathered before we terminate. 5193d793cf1SPeter Wemm */ 5203d793cf1SPeter Wemm if (report_gathering) { 521ee6b974cSMark Murray int c; 522ee6b974cSMark Murray size_t rep_len; 5233d793cf1SPeter Wemm 5243d793cf1SPeter Wemm rep_len = strlen(report_buffer); 5253d793cf1SPeter Wemm while (rep_len + 1 <= sizeof(report_buffer)) { 5263d793cf1SPeter Wemm alarm(1); 5273d793cf1SPeter Wemm c = get_char(); 5283d793cf1SPeter Wemm alarm(0); 5293d793cf1SPeter Wemm if (c < 0 || iscntrl(c)) 5303d793cf1SPeter Wemm break; 5313d793cf1SPeter Wemm report_buffer[rep_len] = c; 5323d793cf1SPeter Wemm ++rep_len; 5333d793cf1SPeter Wemm } 5343d793cf1SPeter Wemm report_buffer[rep_len] = 0; 5353d793cf1SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 5363d793cf1SPeter Wemm } 5379f65f104SPeter Wemm if (verbose) 5389f65f104SPeter Wemm fprintf (report_fp, "Closing \"%s\".\n", report_file); 5399f65f104SPeter Wemm fclose (report_fp); 5409f65f104SPeter Wemm report_fp = (FILE *) NULL; 5419f65f104SPeter Wemm } 5429f65f104SPeter Wemm 5439f65f104SPeter Wemm #if defined(get_term_param) 54401c855caSPeter Wemm if (have_tty_parameters) { 5459f65f104SPeter Wemm if (set_term_param (&saved_tty_parameters) < 0) 54601c855caSPeter Wemm fatal(2, "Can't restore terminal parameters: %m"); 5479f65f104SPeter Wemm } 5489f65f104SPeter Wemm #endif 5499f65f104SPeter Wemm 5509b1aec48SLars Fredriksen exit(status); 5519b1aec48SLars Fredriksen } 5529b1aec48SLars Fredriksen 5539b1aec48SLars Fredriksen /* 5549b1aec48SLars Fredriksen * 'Clean up' this string. 5559b1aec48SLars Fredriksen */ 556ee6b974cSMark Murray char * 557ee6b974cSMark Murray clean(char *s, int sending) 5589b1aec48SLars Fredriksen { 5599b1aec48SLars Fredriksen char temp[STR_LEN], cur_chr; 560ee6b974cSMark Murray char *s1, *phchar; 5619b1aec48SLars Fredriksen int add_return = sending; 5629b1aec48SLars Fredriksen #define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 5639b1aec48SLars Fredriksen 5649b1aec48SLars Fredriksen s1 = temp; 5654e83a8feSKris Kennaway /* Don't overflow buffer, leave room for chars we append later */ 566ee6b974cSMark Murray while (*s && s1 - temp < (off_t)(sizeof(temp) - 2 - add_return)) { 5679b1aec48SLars Fredriksen cur_chr = *s++; 56801c855caSPeter Wemm if (cur_chr == '^') { 5699b1aec48SLars Fredriksen cur_chr = *s++; 57001c855caSPeter Wemm if (cur_chr == '\0') { 5719b1aec48SLars Fredriksen *s1++ = '^'; 5729b1aec48SLars Fredriksen break; 5739b1aec48SLars Fredriksen } 5749b1aec48SLars Fredriksen cur_chr &= 0x1F; 57501c855caSPeter Wemm if (cur_chr != 0) { 5769b1aec48SLars Fredriksen *s1++ = cur_chr; 5779f65f104SPeter Wemm } 5789b1aec48SLars Fredriksen continue; 5799b1aec48SLars Fredriksen } 5809b1aec48SLars Fredriksen 58101c855caSPeter Wemm if (cur_chr != '\\') { 5829b1aec48SLars Fredriksen *s1++ = cur_chr; 5839b1aec48SLars Fredriksen continue; 5849b1aec48SLars Fredriksen } 5859b1aec48SLars Fredriksen 5869b1aec48SLars Fredriksen cur_chr = *s++; 58701c855caSPeter Wemm if (cur_chr == '\0') { 58801c855caSPeter Wemm if (sending) { 5899b1aec48SLars Fredriksen *s1++ = '\\'; 5909b1aec48SLars Fredriksen *s1++ = '\\'; 5919b1aec48SLars Fredriksen } 5929b1aec48SLars Fredriksen break; 5939b1aec48SLars Fredriksen } 5949b1aec48SLars Fredriksen 59501c855caSPeter Wemm switch (cur_chr) { 5969b1aec48SLars Fredriksen case 'b': 5979b1aec48SLars Fredriksen *s1++ = '\b'; 5989b1aec48SLars Fredriksen break; 5999b1aec48SLars Fredriksen 6009b1aec48SLars Fredriksen case 'c': 6019b1aec48SLars Fredriksen if (sending && *s == '\0') 6029b1aec48SLars Fredriksen add_return = 0; 6039b1aec48SLars Fredriksen else 6049b1aec48SLars Fredriksen *s1++ = cur_chr; 6059b1aec48SLars Fredriksen break; 6069b1aec48SLars Fredriksen 6079b1aec48SLars Fredriksen case '\\': 6089b1aec48SLars Fredriksen case 'K': 6099b1aec48SLars Fredriksen case 'p': 6109b1aec48SLars Fredriksen case 'd': 6119b1aec48SLars Fredriksen if (sending) 6129b1aec48SLars Fredriksen *s1++ = '\\'; 6139b1aec48SLars Fredriksen 6149b1aec48SLars Fredriksen *s1++ = cur_chr; 6159b1aec48SLars Fredriksen break; 6169b1aec48SLars Fredriksen 61701c855caSPeter Wemm case 'T': 61801c855caSPeter Wemm if (sending && phone_num) { 61901c855caSPeter Wemm for ( phchar = phone_num; *phchar != '\0'; phchar++) 62001c855caSPeter Wemm *s1++ = *phchar; 62101c855caSPeter Wemm } 62201c855caSPeter Wemm else { 62301c855caSPeter Wemm *s1++ = '\\'; 62401c855caSPeter Wemm *s1++ = 'T'; 62501c855caSPeter Wemm } 62601c855caSPeter Wemm break; 62701c855caSPeter Wemm 62801c855caSPeter Wemm case 'U': 62901c855caSPeter Wemm if (sending && phone_num2) { 63001c855caSPeter Wemm for ( phchar = phone_num2; *phchar != '\0'; phchar++) 63101c855caSPeter Wemm *s1++ = *phchar; 63201c855caSPeter Wemm } 63301c855caSPeter Wemm else { 63401c855caSPeter Wemm *s1++ = '\\'; 63501c855caSPeter Wemm *s1++ = 'U'; 63601c855caSPeter Wemm } 63701c855caSPeter Wemm break; 63801c855caSPeter Wemm 6399b1aec48SLars Fredriksen case 'q': 6403d793cf1SPeter Wemm quiet = 1; 6419b1aec48SLars Fredriksen break; 6429b1aec48SLars Fredriksen 6439b1aec48SLars Fredriksen case 'r': 6449b1aec48SLars Fredriksen *s1++ = '\r'; 6459b1aec48SLars Fredriksen break; 6469b1aec48SLars Fredriksen 6479b1aec48SLars Fredriksen case 'n': 6489b1aec48SLars Fredriksen *s1++ = '\n'; 6499b1aec48SLars Fredriksen break; 6509b1aec48SLars Fredriksen 6519b1aec48SLars Fredriksen case 's': 6529b1aec48SLars Fredriksen *s1++ = ' '; 6539b1aec48SLars Fredriksen break; 6549b1aec48SLars Fredriksen 6559b1aec48SLars Fredriksen case 't': 6569b1aec48SLars Fredriksen *s1++ = '\t'; 6579b1aec48SLars Fredriksen break; 6589b1aec48SLars Fredriksen 6599b1aec48SLars Fredriksen case 'N': 66001c855caSPeter Wemm if (sending) { 6619b1aec48SLars Fredriksen *s1++ = '\\'; 6629b1aec48SLars Fredriksen *s1++ = '\0'; 6639b1aec48SLars Fredriksen } 6649b1aec48SLars Fredriksen else 6659b1aec48SLars Fredriksen *s1++ = 'N'; 6669b1aec48SLars Fredriksen break; 6679b1aec48SLars Fredriksen 6689b1aec48SLars Fredriksen default: 66901c855caSPeter Wemm if (isoctal (cur_chr)) { 6709b1aec48SLars Fredriksen cur_chr &= 0x07; 67101c855caSPeter Wemm if (isoctal (*s)) { 6729b1aec48SLars Fredriksen cur_chr <<= 3; 6739b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 67401c855caSPeter Wemm if (isoctal (*s)) { 6759b1aec48SLars Fredriksen cur_chr <<= 3; 6769b1aec48SLars Fredriksen cur_chr |= *s++ - '0'; 6779b1aec48SLars Fredriksen } 6789b1aec48SLars Fredriksen } 6799b1aec48SLars Fredriksen 68001c855caSPeter Wemm if (cur_chr != 0 || sending) { 6819b1aec48SLars Fredriksen if (sending && (cur_chr == '\\' || cur_chr == 0)) 6829b1aec48SLars Fredriksen *s1++ = '\\'; 6839b1aec48SLars Fredriksen *s1++ = cur_chr; 6849b1aec48SLars Fredriksen } 6859b1aec48SLars Fredriksen break; 6869b1aec48SLars Fredriksen } 6879b1aec48SLars Fredriksen 6889b1aec48SLars Fredriksen if (sending) 6899b1aec48SLars Fredriksen *s1++ = '\\'; 6909b1aec48SLars Fredriksen *s1++ = cur_chr; 6919b1aec48SLars Fredriksen break; 6929b1aec48SLars Fredriksen } 6939b1aec48SLars Fredriksen } 6949b1aec48SLars Fredriksen 6959b1aec48SLars Fredriksen if (add_return) 6969b1aec48SLars Fredriksen *s1++ = '\r'; 6979b1aec48SLars Fredriksen 6989b1aec48SLars Fredriksen *s1++ = '\0'; /* guarantee closure */ 6999b1aec48SLars Fredriksen *s1++ = '\0'; /* terminate the string */ 7009b1aec48SLars Fredriksen return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7019b1aec48SLars Fredriksen } 7029b1aec48SLars Fredriksen 7039b1aec48SLars Fredriksen /* 7043d793cf1SPeter Wemm * A modified version of 'strtok'. This version skips \ sequences. 7053d793cf1SPeter Wemm */ 7063d793cf1SPeter Wemm 707ee6b974cSMark Murray char * 708ee6b974cSMark Murray expect_strtok (char *s, const char *term) 7093d793cf1SPeter Wemm { 710ee6b974cSMark Murray static char *str = blank; 7113d793cf1SPeter Wemm int escape_flag = 0; 7123d793cf1SPeter Wemm char *result; 71301c855caSPeter Wemm 7143d793cf1SPeter Wemm /* 7153d793cf1SPeter Wemm * If a string was specified then do initial processing. 7163d793cf1SPeter Wemm */ 7173d793cf1SPeter Wemm if (s) 7183d793cf1SPeter Wemm str = s; 71901c855caSPeter Wemm 7203d793cf1SPeter Wemm /* 7213d793cf1SPeter Wemm * If this is the escape flag then reset it and ignore the character. 7223d793cf1SPeter Wemm */ 7233d793cf1SPeter Wemm if (*str) 7243d793cf1SPeter Wemm result = str; 7253d793cf1SPeter Wemm else 7263d793cf1SPeter Wemm result = (char *) 0; 7273d793cf1SPeter Wemm 72801c855caSPeter Wemm while (*str) { 72901c855caSPeter Wemm if (escape_flag) { 7303d793cf1SPeter Wemm escape_flag = 0; 7313d793cf1SPeter Wemm ++str; 7323d793cf1SPeter Wemm continue; 7333d793cf1SPeter Wemm } 7343d793cf1SPeter Wemm 73501c855caSPeter Wemm if (*str == '\\') { 7363d793cf1SPeter Wemm ++str; 7373d793cf1SPeter Wemm escape_flag = 1; 7383d793cf1SPeter Wemm continue; 7393d793cf1SPeter Wemm } 74001c855caSPeter Wemm 7413d793cf1SPeter Wemm /* 7423d793cf1SPeter Wemm * If this is not in the termination string, continue. 7433d793cf1SPeter Wemm */ 74401c855caSPeter Wemm if (strchr (term, *str) == (char *) 0) { 7453d793cf1SPeter Wemm ++str; 7463d793cf1SPeter Wemm continue; 7473d793cf1SPeter Wemm } 74801c855caSPeter Wemm 7493d793cf1SPeter Wemm /* 7503d793cf1SPeter Wemm * This is the terminator. Mark the end of the string and stop. 7513d793cf1SPeter Wemm */ 7523d793cf1SPeter Wemm *str++ = '\0'; 7533d793cf1SPeter Wemm break; 7543d793cf1SPeter Wemm } 7553d793cf1SPeter Wemm return (result); 7563d793cf1SPeter Wemm } 7573d793cf1SPeter Wemm 7583d793cf1SPeter Wemm /* 7599b1aec48SLars Fredriksen * Process the expect string 7609b1aec48SLars Fredriksen */ 7613d793cf1SPeter Wemm 762ee6b974cSMark Murray void 763ee6b974cSMark Murray chat_expect(char *s) 7649b1aec48SLars Fredriksen { 7653d793cf1SPeter Wemm char *expect; 7663d793cf1SPeter Wemm char *reply; 7673d793cf1SPeter Wemm 76801c855caSPeter Wemm if (strcmp(s, "HANGUP") == 0) { 7693d793cf1SPeter Wemm ++hup_next; 7703d793cf1SPeter Wemm return; 7713d793cf1SPeter Wemm } 7723d793cf1SPeter Wemm 77301c855caSPeter Wemm if (strcmp(s, "ABORT") == 0) { 7749b1aec48SLars Fredriksen ++abort_next; 7759b1aec48SLars Fredriksen return; 7769b1aec48SLars Fredriksen } 7779b1aec48SLars Fredriksen 77801c855caSPeter Wemm if (strcmp(s, "CLR_ABORT") == 0) { 7793d793cf1SPeter Wemm ++clear_abort_next; 7803d793cf1SPeter Wemm return; 7813d793cf1SPeter Wemm } 7823d793cf1SPeter Wemm 78301c855caSPeter Wemm if (strcmp(s, "REPORT") == 0) { 7849f65f104SPeter Wemm ++report_next; 7859f65f104SPeter Wemm return; 7869f65f104SPeter Wemm } 7879f65f104SPeter Wemm 78801c855caSPeter Wemm if (strcmp(s, "CLR_REPORT") == 0) { 7893d793cf1SPeter Wemm ++clear_report_next; 7903d793cf1SPeter Wemm return; 7913d793cf1SPeter Wemm } 7923d793cf1SPeter Wemm 79301c855caSPeter Wemm if (strcmp(s, "TIMEOUT") == 0) { 7949b1aec48SLars Fredriksen ++timeout_next; 7959b1aec48SLars Fredriksen return; 7969b1aec48SLars Fredriksen } 7979b1aec48SLars Fredriksen 79801c855caSPeter Wemm if (strcmp(s, "ECHO") == 0) { 7993d793cf1SPeter Wemm ++echo_next; 8003d793cf1SPeter Wemm return; 8013d793cf1SPeter Wemm } 80201c855caSPeter Wemm 80301c855caSPeter Wemm if (strcmp(s, "SAY") == 0) { 8043d793cf1SPeter Wemm ++say_next; 8053d793cf1SPeter Wemm return; 8063d793cf1SPeter Wemm } 80701c855caSPeter Wemm 8083d793cf1SPeter Wemm /* 8093d793cf1SPeter Wemm * Fetch the expect and reply string. 8103d793cf1SPeter Wemm */ 81101c855caSPeter Wemm for (;;) { 8123d793cf1SPeter Wemm expect = expect_strtok (s, "-"); 8133d793cf1SPeter Wemm s = (char *) 0; 8149b1aec48SLars Fredriksen 8153d793cf1SPeter Wemm if (expect == (char *) 0) 8163d793cf1SPeter Wemm return; 8173d793cf1SPeter Wemm 8183d793cf1SPeter Wemm reply = expect_strtok (s, "-"); 81901c855caSPeter Wemm 8203d793cf1SPeter Wemm /* 8213d793cf1SPeter Wemm * Handle the expect string. If successful then exit. 8223d793cf1SPeter Wemm */ 8233d793cf1SPeter Wemm if (get_string (expect)) 8243d793cf1SPeter Wemm return; 82501c855caSPeter Wemm 8263d793cf1SPeter Wemm /* 8273d793cf1SPeter Wemm * If there is a sub-reply string then send it. Otherwise any condition 8283d793cf1SPeter Wemm * is terminal. 8293d793cf1SPeter Wemm */ 8303d793cf1SPeter Wemm if (reply == (char *) 0 || exit_code != 3) 8319b1aec48SLars Fredriksen break; 8329b1aec48SLars Fredriksen 8333d793cf1SPeter Wemm chat_send (reply); 8349f65f104SPeter Wemm } 83501c855caSPeter Wemm 8363d793cf1SPeter Wemm /* 8373d793cf1SPeter Wemm * The expectation did not occur. This is terminal. 8383d793cf1SPeter Wemm */ 8399b1aec48SLars Fredriksen if (fail_reason) 8408491f234STim Kientzle chat_logf("Failed (%s)", fail_reason); 8419b1aec48SLars Fredriksen else 8428491f234STim Kientzle chat_logf("Failed"); 8439f65f104SPeter Wemm terminate(exit_code); 8449f65f104SPeter Wemm } 8453d793cf1SPeter Wemm 8463d793cf1SPeter Wemm /* 8473d793cf1SPeter Wemm * Translate the input character to the appropriate string for printing 8483d793cf1SPeter Wemm * the data. 8493d793cf1SPeter Wemm */ 8509b1aec48SLars Fredriksen 851ee6b974cSMark Murray char * 852ee6b974cSMark Murray character(int c) 8539b1aec48SLars Fredriksen { 8549b1aec48SLars Fredriksen static char string[10]; 855ee6b974cSMark Murray const char *meta; 8569b1aec48SLars Fredriksen 8579b1aec48SLars Fredriksen meta = (c & 0x80) ? "M-" : ""; 8589b1aec48SLars Fredriksen c &= 0x7F; 8599b1aec48SLars Fredriksen 8609b1aec48SLars Fredriksen if (c < 32) 8619b1aec48SLars Fredriksen sprintf(string, "%s^%c", meta, (int)c + '@'); 86201c855caSPeter Wemm else if (c == 127) 8639b1aec48SLars Fredriksen sprintf(string, "%s^?", meta); 8649b1aec48SLars Fredriksen else 8659b1aec48SLars Fredriksen sprintf(string, "%s%c", meta, c); 8669b1aec48SLars Fredriksen 8679b1aec48SLars Fredriksen return (string); 8689b1aec48SLars Fredriksen } 8699b1aec48SLars Fredriksen 8709b1aec48SLars Fredriksen /* 8719b1aec48SLars Fredriksen * process the reply string 8729b1aec48SLars Fredriksen */ 873ee6b974cSMark Murray void 874ee6b974cSMark Murray chat_send(char *s) 8759b1aec48SLars Fredriksen { 87601c855caSPeter Wemm if (say_next) { 8773d793cf1SPeter Wemm say_next = 0; 8783d793cf1SPeter Wemm s = clean(s,0); 879e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s)); 8803d793cf1SPeter Wemm free(s); 8813d793cf1SPeter Wemm return; 8823d793cf1SPeter Wemm } 88301c855caSPeter Wemm 88401c855caSPeter Wemm if (hup_next) { 8853d793cf1SPeter Wemm hup_next = 0; 8863d793cf1SPeter Wemm if (strcmp(s, "OFF") == 0) 8873d793cf1SPeter Wemm signal(SIGHUP, SIG_IGN); 8883d793cf1SPeter Wemm else 8893d793cf1SPeter Wemm signal(SIGHUP, sighup); 8903d793cf1SPeter Wemm return; 8913d793cf1SPeter Wemm } 89201c855caSPeter Wemm 89301c855caSPeter Wemm if (echo_next) { 8943d793cf1SPeter Wemm echo_next = 0; 8953d793cf1SPeter Wemm echo = (strcmp(s, "ON") == 0); 8963d793cf1SPeter Wemm return; 8973d793cf1SPeter Wemm } 89801c855caSPeter Wemm 89901c855caSPeter Wemm if (abort_next) { 9009b1aec48SLars Fredriksen char *s1; 9019b1aec48SLars Fredriksen 9029b1aec48SLars Fredriksen abort_next = 0; 9039b1aec48SLars Fredriksen 9049b1aec48SLars Fredriksen if (n_aborts >= MAX_ABORTS) 90501c855caSPeter Wemm fatal(2, "Too many ABORT strings"); 9069b1aec48SLars Fredriksen 9079b1aec48SLars Fredriksen s1 = clean(s, 0); 9089b1aec48SLars Fredriksen 9099f65f104SPeter Wemm if (strlen(s1) > strlen(s) 9109f65f104SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 91101c855caSPeter Wemm fatal(1, "Illegal or too-long ABORT string ('%v')", s); 9129b1aec48SLars Fredriksen 9139b1aec48SLars Fredriksen abort_string[n_aborts++] = s1; 9149b1aec48SLars Fredriksen 9159b1aec48SLars Fredriksen if (verbose) 9168491f234STim Kientzle chat_logf("abort on (%v)", s); 9179f65f104SPeter Wemm return; 9189b1aec48SLars Fredriksen } 9199f65f104SPeter Wemm 92001c855caSPeter Wemm if (clear_abort_next) { 9213d793cf1SPeter Wemm char *s1; 9223d793cf1SPeter Wemm int i; 9233d793cf1SPeter Wemm int old_max; 9243d793cf1SPeter Wemm int pack = 0; 9253d793cf1SPeter Wemm 9263d793cf1SPeter Wemm clear_abort_next = 0; 9273d793cf1SPeter Wemm 9283d793cf1SPeter Wemm s1 = clean(s, 0); 9293d793cf1SPeter Wemm 9303d793cf1SPeter Wemm if (strlen(s1) > strlen(s) 9313d793cf1SPeter Wemm || strlen(s1) + 1 > sizeof(fail_buffer)) 93201c855caSPeter Wemm fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s); 9333d793cf1SPeter Wemm 9343d793cf1SPeter Wemm old_max = n_aborts; 93501c855caSPeter Wemm for (i=0; i < n_aborts; i++) { 93601c855caSPeter Wemm if ( strcmp(s1,abort_string[i]) == 0 ) { 9373d793cf1SPeter Wemm free(abort_string[i]); 9383d793cf1SPeter Wemm abort_string[i] = NULL; 9393d793cf1SPeter Wemm pack++; 9403d793cf1SPeter Wemm n_aborts--; 9413d793cf1SPeter Wemm if (verbose) 9428491f234STim Kientzle chat_logf("clear abort on (%v)", s); 9433d793cf1SPeter Wemm } 9443d793cf1SPeter Wemm } 9453d793cf1SPeter Wemm free(s1); 94601c855caSPeter Wemm if (pack) 94701c855caSPeter Wemm pack_array(abort_string,old_max); 9483d793cf1SPeter Wemm return; 9493d793cf1SPeter Wemm } 9503d793cf1SPeter Wemm 95101c855caSPeter Wemm if (report_next) { 9529f65f104SPeter Wemm char *s1; 9539f65f104SPeter Wemm 9549f65f104SPeter Wemm report_next = 0; 9559f65f104SPeter Wemm if (n_reports >= MAX_REPORTS) 95601c855caSPeter Wemm fatal(2, "Too many REPORT strings"); 9579f65f104SPeter Wemm 9589f65f104SPeter Wemm s1 = clean(s, 0); 9599f65f104SPeter Wemm 9609f65f104SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 96101c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 9629f65f104SPeter Wemm 9639f65f104SPeter Wemm report_string[n_reports++] = s1; 9649f65f104SPeter Wemm 9659f65f104SPeter Wemm if (verbose) 9668491f234STim Kientzle chat_logf("report (%v)", s); 9679f65f104SPeter Wemm return; 9689f65f104SPeter Wemm } 9699f65f104SPeter Wemm 97001c855caSPeter Wemm if (clear_report_next) { 9713d793cf1SPeter Wemm char *s1; 9723d793cf1SPeter Wemm int i; 9733d793cf1SPeter Wemm int old_max; 9743d793cf1SPeter Wemm int pack = 0; 9753d793cf1SPeter Wemm 9763d793cf1SPeter Wemm clear_report_next = 0; 9773d793cf1SPeter Wemm 9783d793cf1SPeter Wemm s1 = clean(s, 0); 9793d793cf1SPeter Wemm 9803d793cf1SPeter Wemm if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 98101c855caSPeter Wemm fatal(1, "Illegal or too-long REPORT string ('%v')", s); 9823d793cf1SPeter Wemm 9833d793cf1SPeter Wemm old_max = n_reports; 98401c855caSPeter Wemm for (i=0; i < n_reports; i++) { 98501c855caSPeter Wemm if ( strcmp(s1,report_string[i]) == 0 ) { 9863d793cf1SPeter Wemm free(report_string[i]); 9873d793cf1SPeter Wemm report_string[i] = NULL; 9883d793cf1SPeter Wemm pack++; 9893d793cf1SPeter Wemm n_reports--; 9903d793cf1SPeter Wemm if (verbose) 9918491f234STim Kientzle chat_logf("clear report (%v)", s); 9923d793cf1SPeter Wemm } 9933d793cf1SPeter Wemm } 9943d793cf1SPeter Wemm free(s1); 99501c855caSPeter Wemm if (pack) 99601c855caSPeter Wemm pack_array(report_string,old_max); 9973d793cf1SPeter Wemm 9983d793cf1SPeter Wemm return; 9993d793cf1SPeter Wemm } 10003d793cf1SPeter Wemm 100101c855caSPeter Wemm if (timeout_next) { 10029b1aec48SLars Fredriksen timeout_next = 0; 10039b1aec48SLars Fredriksen timeout = atoi(s); 10049b1aec48SLars Fredriksen 10059b1aec48SLars Fredriksen if (timeout <= 0) 10069b1aec48SLars Fredriksen timeout = DEFAULT_CHAT_TIMEOUT; 10079b1aec48SLars Fredriksen 10089b1aec48SLars Fredriksen if (verbose) 10098491f234STim Kientzle chat_logf("timeout set to %d seconds", timeout); 101001c855caSPeter Wemm 10119f65f104SPeter Wemm return; 10129f65f104SPeter Wemm } 10139f65f104SPeter Wemm 10149f65f104SPeter Wemm if (strcmp(s, "EOT") == 0) 1015ee6b974cSMark Murray s = strdup("^D\\c"); 101601c855caSPeter Wemm else if (strcmp(s, "BREAK") == 0) 1017ee6b974cSMark Murray s = strdup("\\K\\c"); 10189f65f104SPeter Wemm 10199b1aec48SLars Fredriksen if (!put_string(s)) 102001c855caSPeter Wemm fatal(1, "Failed"); 10219b1aec48SLars Fredriksen } 10229b1aec48SLars Fredriksen 1023ee6b974cSMark Murray int 1024ee6b974cSMark Murray get_char(void) 10259b1aec48SLars Fredriksen { 10269b1aec48SLars Fredriksen int status; 10279b1aec48SLars Fredriksen char c; 10289b1aec48SLars Fredriksen 1029e1b4d8d0SSheldon Hearn status = read(STDIN_FILENO, &c, 1); 10309b1aec48SLars Fredriksen 103101c855caSPeter Wemm switch (status) { 10329b1aec48SLars Fredriksen case 1: 10339b1aec48SLars Fredriksen return ((int)c & 0x7F); 10349b1aec48SLars Fredriksen 10359b1aec48SLars Fredriksen default: 10368491f234STim Kientzle chat_logf("warning: read() on stdin returned %d", status); 10379b1aec48SLars Fredriksen 10389b1aec48SLars Fredriksen case -1: 10399b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 104001c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin: %m"); 104101c855caSPeter Wemm 10429f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 104301c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 10449b1aec48SLars Fredriksen 10459b1aec48SLars Fredriksen return (-1); 10469b1aec48SLars Fredriksen } 10479b1aec48SLars Fredriksen } 10489b1aec48SLars Fredriksen 1049ee6b974cSMark Murray int put_char(int c) 10509b1aec48SLars Fredriksen { 10519b1aec48SLars Fredriksen int status; 10529f65f104SPeter Wemm char ch = c; 10539b1aec48SLars Fredriksen 10549f65f104SPeter Wemm usleep(10000); /* inter-character typing delay (?) */ 10559b1aec48SLars Fredriksen 1056e1b4d8d0SSheldon Hearn status = write(STDOUT_FILENO, &ch, 1); 10579b1aec48SLars Fredriksen 105801c855caSPeter Wemm switch (status) { 10599b1aec48SLars Fredriksen case 1: 10609b1aec48SLars Fredriksen return (0); 10619b1aec48SLars Fredriksen 10629b1aec48SLars Fredriksen default: 10638491f234STim Kientzle chat_logf("warning: write() on stdout returned %d", status); 10649b1aec48SLars Fredriksen 10659b1aec48SLars Fredriksen case -1: 10669b1aec48SLars Fredriksen if ((status = fcntl(0, F_GETFL, 0)) == -1) 106701c855caSPeter Wemm fatal(2, "Can't get file mode flags on stdin, %m"); 106801c855caSPeter Wemm 10699f65f104SPeter Wemm if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 107001c855caSPeter Wemm fatal(2, "Can't set file mode flags on stdin: %m"); 10719b1aec48SLars Fredriksen 10729b1aec48SLars Fredriksen return (-1); 10739b1aec48SLars Fredriksen } 10749b1aec48SLars Fredriksen } 10759b1aec48SLars Fredriksen 1076ee6b974cSMark Murray int 1077ee6b974cSMark Murray write_char(int c) 10789b1aec48SLars Fredriksen { 107901c855caSPeter Wemm if (alarmed || put_char(c) < 0) { 10809f65f104SPeter Wemm alarm(0); 10819f65f104SPeter Wemm alarmed = 0; 10829b1aec48SLars Fredriksen 108301c855caSPeter Wemm if (verbose) { 10849b1aec48SLars Fredriksen if (errno == EINTR || errno == EWOULDBLOCK) 10858491f234STim Kientzle chat_logf(" -- write timed out"); 10869b1aec48SLars Fredriksen else 10878491f234STim Kientzle chat_logf(" -- write failed: %m"); 10889f65f104SPeter Wemm } 10899b1aec48SLars Fredriksen return (0); 10909b1aec48SLars Fredriksen } 10919b1aec48SLars Fredriksen return (1); 10929b1aec48SLars Fredriksen } 10939b1aec48SLars Fredriksen 1094ee6b974cSMark Murray int 1095ee6b974cSMark Murray put_string(char *s) 10969b1aec48SLars Fredriksen { 10973d793cf1SPeter Wemm quiet = 0; 10989b1aec48SLars Fredriksen s = clean(s, 1); 10999b1aec48SLars Fredriksen 1100ee6b974cSMark Murray if (verbose) 11018491f234STim Kientzle chat_logf("send (%v)", quiet ? "??????" : s); 11029b1aec48SLars Fredriksen 11039b1aec48SLars Fredriksen alarm(timeout); alarmed = 0; 11049b1aec48SLars Fredriksen 110501c855caSPeter Wemm while (*s) { 1106ee6b974cSMark Murray char c = *s++; 11079b1aec48SLars Fredriksen 110801c855caSPeter Wemm if (c != '\\') { 11099b1aec48SLars Fredriksen if (!write_char (c)) 11109b1aec48SLars Fredriksen return 0; 11119b1aec48SLars Fredriksen continue; 11129b1aec48SLars Fredriksen } 11139b1aec48SLars Fredriksen 11149b1aec48SLars Fredriksen c = *s++; 111501c855caSPeter Wemm switch (c) { 11169b1aec48SLars Fredriksen case 'd': 11179b1aec48SLars Fredriksen sleep(1); 11189b1aec48SLars Fredriksen break; 11199b1aec48SLars Fredriksen 11209b1aec48SLars Fredriksen case 'K': 11219b1aec48SLars Fredriksen break_sequence(); 11229b1aec48SLars Fredriksen break; 11239b1aec48SLars Fredriksen 11249b1aec48SLars Fredriksen case 'p': 11259f65f104SPeter Wemm usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11269b1aec48SLars Fredriksen break; 11279b1aec48SLars Fredriksen 11289b1aec48SLars Fredriksen default: 11299b1aec48SLars Fredriksen if (!write_char (c)) 11309b1aec48SLars Fredriksen return 0; 11319b1aec48SLars Fredriksen break; 11329b1aec48SLars Fredriksen } 11339b1aec48SLars Fredriksen } 11349b1aec48SLars Fredriksen 11359b1aec48SLars Fredriksen alarm(0); 11369b1aec48SLars Fredriksen alarmed = 0; 11379b1aec48SLars Fredriksen return (1); 11389b1aec48SLars Fredriksen } 11399b1aec48SLars Fredriksen 11409b1aec48SLars Fredriksen /* 11413d793cf1SPeter Wemm * Echo a character to stderr. 11423d793cf1SPeter Wemm * When called with -1, a '\n' character is generated when 11433d793cf1SPeter Wemm * the cursor is not at the beginning of a line. 11443d793cf1SPeter Wemm */ 1145ee6b974cSMark Murray void 1146ee6b974cSMark Murray echo_stderr(int n) 11473d793cf1SPeter Wemm { 11483d793cf1SPeter Wemm static int need_lf; 11493d793cf1SPeter Wemm char *s; 11503d793cf1SPeter Wemm 115101c855caSPeter Wemm switch (n) { 11523d793cf1SPeter Wemm case '\r': /* ignore '\r' */ 11533d793cf1SPeter Wemm break; 11543d793cf1SPeter Wemm case -1: 11553d793cf1SPeter Wemm if (need_lf == 0) 11563d793cf1SPeter Wemm break; 115793b0017fSPhilippe Charnier /* FALLTHROUGH */ 11583d793cf1SPeter Wemm case '\n': 1159e1b4d8d0SSheldon Hearn write(STDERR_FILENO, "\n", 1); 11603d793cf1SPeter Wemm need_lf = 0; 11613d793cf1SPeter Wemm break; 11623d793cf1SPeter Wemm default: 11633d793cf1SPeter Wemm s = character(n); 1164e1b4d8d0SSheldon Hearn write(STDERR_FILENO, s, strlen(s)); 11653d793cf1SPeter Wemm need_lf = 1; 11663d793cf1SPeter Wemm break; 11673d793cf1SPeter Wemm } 11683d793cf1SPeter Wemm } 11693d793cf1SPeter Wemm 11703d793cf1SPeter Wemm /* 11719b1aec48SLars Fredriksen * 'Wait for' this string to appear on this file descriptor. 11729b1aec48SLars Fredriksen */ 1173ee6b974cSMark Murray int 1174ee6b974cSMark Murray get_string(char *string) 11759b1aec48SLars Fredriksen { 11769b1aec48SLars Fredriksen char temp[STR_LEN]; 1177ee6b974cSMark Murray int c, printed = 0; 1178ee6b974cSMark Murray size_t len, minlen; 1179ee6b974cSMark Murray char *s = temp, *end = s + STR_LEN; 118001c855caSPeter Wemm char *logged = temp; 11819b1aec48SLars Fredriksen 11829b1aec48SLars Fredriksen fail_reason = (char *)0; 11834e83a8feSKris Kennaway 11844e83a8feSKris Kennaway if (strlen(string) > STR_LEN) { 11858491f234STim Kientzle chat_logf("expect string is too long"); 11864e83a8feSKris Kennaway exit_code = 1; 11874e83a8feSKris Kennaway return 0; 11884e83a8feSKris Kennaway } 11894e83a8feSKris Kennaway 11909b1aec48SLars Fredriksen string = clean(string, 0); 11919b1aec48SLars Fredriksen len = strlen(string); 11929b1aec48SLars Fredriksen minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 11939b1aec48SLars Fredriksen 11949b1aec48SLars Fredriksen if (verbose) 11958491f234STim Kientzle chat_logf("expect (%v)", string); 11969b1aec48SLars Fredriksen 119701c855caSPeter Wemm if (len == 0) { 11989b1aec48SLars Fredriksen if (verbose) 11998491f234STim Kientzle chat_logf("got it"); 12009b1aec48SLars Fredriksen return (1); 12019b1aec48SLars Fredriksen } 12029b1aec48SLars Fredriksen 12039f65f104SPeter Wemm alarm(timeout); 12049f65f104SPeter Wemm alarmed = 0; 12059b1aec48SLars Fredriksen 120601c855caSPeter Wemm while ( ! alarmed && (c = get_char()) >= 0) { 12079f65f104SPeter Wemm int n, abort_len, report_len; 12089b1aec48SLars Fredriksen 12093d793cf1SPeter Wemm if (echo) 12103d793cf1SPeter Wemm echo_stderr(c); 121101c855caSPeter Wemm if (verbose && c == '\n') { 121201c855caSPeter Wemm if (s == logged) 12138491f234STim Kientzle chat_logf(""); /* blank line */ 12149b1aec48SLars Fredriksen else 12158491f234STim Kientzle chat_logf("%0.*v", s - logged, logged); 121601c855caSPeter Wemm logged = s + 1; 12173d793cf1SPeter Wemm } 12183d793cf1SPeter Wemm 12199b1aec48SLars Fredriksen *s++ = c; 12209b1aec48SLars Fredriksen 122101c855caSPeter Wemm if (verbose && s >= logged + 80) { 12228491f234STim Kientzle chat_logf("%0.*v", s - logged, logged); 122301c855caSPeter Wemm logged = s; 122401c855caSPeter Wemm } 122501c855caSPeter Wemm 122601c855caSPeter Wemm if (Verbose) { 122701c855caSPeter Wemm if (c == '\n') 122801c855caSPeter Wemm fputc( '\n', stderr ); 122901c855caSPeter Wemm else if (c != '\r') 123001c855caSPeter Wemm fprintf( stderr, "%s", character(c) ); 123101c855caSPeter Wemm } 123201c855caSPeter Wemm 123301c855caSPeter Wemm if (!report_gathering) { 123401c855caSPeter Wemm for (n = 0; n < n_reports; ++n) { 12359f65f104SPeter Wemm if ((report_string[n] != (char*) NULL) && 12369f65f104SPeter Wemm s - temp >= (report_len = strlen(report_string[n])) && 123701c855caSPeter Wemm strncmp(s - report_len, report_string[n], report_len) == 0) { 12389f65f104SPeter Wemm time_t time_now = time ((time_t*) NULL); 12399f65f104SPeter Wemm struct tm* tm_now = localtime (&time_now); 12409f65f104SPeter Wemm 12419f65f104SPeter Wemm strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 12429f65f104SPeter Wemm strcat (report_buffer, report_string[n]); 12439f65f104SPeter Wemm 12449f65f104SPeter Wemm report_string[n] = (char *) NULL; 12459f65f104SPeter Wemm report_gathering = 1; 12469f65f104SPeter Wemm break; 12479f65f104SPeter Wemm } 12489f65f104SPeter Wemm } 12499f65f104SPeter Wemm } 125001c855caSPeter Wemm else { 125101c855caSPeter Wemm if (!iscntrl (c)) { 12529f65f104SPeter Wemm int rep_len = strlen (report_buffer); 12539f65f104SPeter Wemm report_buffer[rep_len] = c; 12549f65f104SPeter Wemm report_buffer[rep_len + 1] = '\0'; 12559f65f104SPeter Wemm } 125601c855caSPeter Wemm else { 12579f65f104SPeter Wemm report_gathering = 0; 12589f65f104SPeter Wemm fprintf (report_fp, "chat: %s\n", report_buffer); 12599f65f104SPeter Wemm } 12609f65f104SPeter Wemm } 12619b1aec48SLars Fredriksen 1262ee6b974cSMark Murray if ((size_t)(s - temp) >= len && 12633d793cf1SPeter Wemm c == string[len - 1] && 126401c855caSPeter Wemm strncmp(s - len, string, len) == 0) { 126501c855caSPeter Wemm if (verbose) { 126601c855caSPeter Wemm if (s > logged) 12678491f234STim Kientzle chat_logf("%0.*v", s - logged, logged); 12688491f234STim Kientzle chat_logf(" -- got it\n"); 12693d793cf1SPeter Wemm } 12703d793cf1SPeter Wemm 12713d793cf1SPeter Wemm alarm(0); 12723d793cf1SPeter Wemm alarmed = 0; 12733d793cf1SPeter Wemm return (1); 12743d793cf1SPeter Wemm } 12753d793cf1SPeter Wemm 127601c855caSPeter Wemm for (n = 0; n < n_aborts; ++n) { 12773d793cf1SPeter Wemm if (s - temp >= (abort_len = strlen(abort_string[n])) && 127801c855caSPeter Wemm strncmp(s - abort_len, abort_string[n], abort_len) == 0) { 127901c855caSPeter Wemm if (verbose) { 128001c855caSPeter Wemm if (s > logged) 12818491f234STim Kientzle chat_logf("%0.*v", s - logged, logged); 12828491f234STim Kientzle chat_logf(" -- failed"); 12833d793cf1SPeter Wemm } 12843d793cf1SPeter Wemm 12853d793cf1SPeter Wemm alarm(0); 12863d793cf1SPeter Wemm alarmed = 0; 12873d793cf1SPeter Wemm exit_code = n + 4; 12883d793cf1SPeter Wemm strcpy(fail_reason = fail_buffer, abort_string[n]); 12893d793cf1SPeter Wemm return (0); 12903d793cf1SPeter Wemm } 12913d793cf1SPeter Wemm } 12923d793cf1SPeter Wemm 129301c855caSPeter Wemm if (s >= end) { 129401c855caSPeter Wemm if (logged < s - minlen) { 12958491f234STim Kientzle chat_logf("%0.*v", s - logged, logged); 129601c855caSPeter Wemm logged = s; 129701c855caSPeter Wemm } 129801c855caSPeter Wemm s -= minlen; 129901c855caSPeter Wemm memmove(temp, s, minlen); 130001c855caSPeter Wemm logged = temp + (logged - s); 13019b1aec48SLars Fredriksen s = temp + minlen; 13029b1aec48SLars Fredriksen } 13039b1aec48SLars Fredriksen 13049b1aec48SLars Fredriksen if (alarmed && verbose) 13058491f234STim Kientzle chat_logf("warning: alarm synchronization problem"); 13069f65f104SPeter Wemm } 13079b1aec48SLars Fredriksen 13089b1aec48SLars Fredriksen alarm(0); 13099b1aec48SLars Fredriksen 131001c855caSPeter Wemm if (verbose && printed) { 13119b1aec48SLars Fredriksen if (alarmed) 13128491f234STim Kientzle chat_logf(" -- read timed out"); 13139b1aec48SLars Fredriksen else 13148491f234STim Kientzle chat_logf(" -- read failed: %m"); 13159b1aec48SLars Fredriksen } 13169b1aec48SLars Fredriksen 13179f65f104SPeter Wemm exit_code = 3; 13189b1aec48SLars Fredriksen alarmed = 0; 13199b1aec48SLars Fredriksen return (0); 13209b1aec48SLars Fredriksen } 13219b1aec48SLars Fredriksen 13223d793cf1SPeter Wemm void 1323ee6b974cSMark Murray pack_array(char **array, int end) 13243d793cf1SPeter Wemm { 13253d793cf1SPeter Wemm int i, j; 13263d793cf1SPeter Wemm 13273d793cf1SPeter Wemm for (i = 0; i < end; i++) { 13283d793cf1SPeter Wemm if (array[i] == NULL) { 13293d793cf1SPeter Wemm for (j = i+1; j < end; ++j) 13303d793cf1SPeter Wemm if (array[j] != NULL) 13313d793cf1SPeter Wemm array[i++] = array[j]; 13323d793cf1SPeter Wemm for (; i < end; ++i) 13333d793cf1SPeter Wemm array[i] = NULL; 13343d793cf1SPeter Wemm break; 13353d793cf1SPeter Wemm } 13363d793cf1SPeter Wemm } 13373d793cf1SPeter Wemm } 133801c855caSPeter Wemm 133901c855caSPeter Wemm /* 134001c855caSPeter Wemm * vfmtmsg - format a message into a buffer. Like vsprintf except we 134101c855caSPeter Wemm * also specify the length of the output buffer, and we handle the 134201c855caSPeter Wemm * %m (error message) format. 134301c855caSPeter Wemm * Doesn't do floating-point formats. 134401c855caSPeter Wemm * Returns the number of chars put into buf. 134501c855caSPeter Wemm */ 134601c855caSPeter Wemm #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 134701c855caSPeter Wemm 134801c855caSPeter Wemm int 1349ee6b974cSMark Murray vfmtmsg(char *buf, int buflen, const char *fmt, va_list args) 135001c855caSPeter Wemm { 135101c855caSPeter Wemm int c, i, n; 135201c855caSPeter Wemm int width, prec, fillch; 135301c855caSPeter Wemm int base, len, neg, quoted; 135401c855caSPeter Wemm unsigned long val = 0; 135501c855caSPeter Wemm char *str, *buf0; 135601c855caSPeter Wemm const char *f; 135701c855caSPeter Wemm unsigned char *p; 135801c855caSPeter Wemm char num[32]; 135901c855caSPeter Wemm static char hexchars[] = "0123456789abcdef"; 136001c855caSPeter Wemm 136101c855caSPeter Wemm buf0 = buf; 136201c855caSPeter Wemm --buflen; 136301c855caSPeter Wemm while (buflen > 0) { 136401c855caSPeter Wemm for (f = fmt; *f != '%' && *f != 0; ++f) 136501c855caSPeter Wemm ; 136601c855caSPeter Wemm if (f > fmt) { 136701c855caSPeter Wemm len = f - fmt; 136801c855caSPeter Wemm if (len > buflen) 136901c855caSPeter Wemm len = buflen; 137001c855caSPeter Wemm memcpy(buf, fmt, len); 137101c855caSPeter Wemm buf += len; 137201c855caSPeter Wemm buflen -= len; 137301c855caSPeter Wemm fmt = f; 137401c855caSPeter Wemm } 137501c855caSPeter Wemm if (*fmt == 0) 137601c855caSPeter Wemm break; 137701c855caSPeter Wemm c = *++fmt; 137801c855caSPeter Wemm width = prec = 0; 137901c855caSPeter Wemm fillch = ' '; 138001c855caSPeter Wemm if (c == '0') { 138101c855caSPeter Wemm fillch = '0'; 138201c855caSPeter Wemm c = *++fmt; 138301c855caSPeter Wemm } 138401c855caSPeter Wemm if (c == '*') { 138501c855caSPeter Wemm width = va_arg(args, int); 138601c855caSPeter Wemm c = *++fmt; 138701c855caSPeter Wemm } else { 138801c855caSPeter Wemm while (isdigit(c)) { 138901c855caSPeter Wemm width = width * 10 + c - '0'; 139001c855caSPeter Wemm c = *++fmt; 139101c855caSPeter Wemm } 139201c855caSPeter Wemm } 139301c855caSPeter Wemm if (c == '.') { 139401c855caSPeter Wemm c = *++fmt; 139501c855caSPeter Wemm if (c == '*') { 139601c855caSPeter Wemm prec = va_arg(args, int); 139701c855caSPeter Wemm c = *++fmt; 139801c855caSPeter Wemm } else { 139901c855caSPeter Wemm while (isdigit(c)) { 140001c855caSPeter Wemm prec = prec * 10 + c - '0'; 140101c855caSPeter Wemm c = *++fmt; 140201c855caSPeter Wemm } 140301c855caSPeter Wemm } 140401c855caSPeter Wemm } 140501c855caSPeter Wemm str = 0; 140601c855caSPeter Wemm base = 0; 140701c855caSPeter Wemm neg = 0; 140801c855caSPeter Wemm ++fmt; 140901c855caSPeter Wemm switch (c) { 141001c855caSPeter Wemm case 'd': 141101c855caSPeter Wemm i = va_arg(args, int); 141201c855caSPeter Wemm if (i < 0) { 141301c855caSPeter Wemm neg = 1; 141401c855caSPeter Wemm val = -i; 141501c855caSPeter Wemm } else 141601c855caSPeter Wemm val = i; 141701c855caSPeter Wemm base = 10; 141801c855caSPeter Wemm break; 141901c855caSPeter Wemm case 'o': 142001c855caSPeter Wemm val = va_arg(args, unsigned int); 142101c855caSPeter Wemm base = 8; 142201c855caSPeter Wemm break; 142301c855caSPeter Wemm case 'x': 142401c855caSPeter Wemm val = va_arg(args, unsigned int); 142501c855caSPeter Wemm base = 16; 142601c855caSPeter Wemm break; 142701c855caSPeter Wemm case 'p': 142801c855caSPeter Wemm val = (unsigned long) va_arg(args, void *); 142901c855caSPeter Wemm base = 16; 143001c855caSPeter Wemm neg = 2; 143101c855caSPeter Wemm break; 143201c855caSPeter Wemm case 's': 143301c855caSPeter Wemm str = va_arg(args, char *); 143401c855caSPeter Wemm break; 143501c855caSPeter Wemm case 'c': 143601c855caSPeter Wemm num[0] = va_arg(args, int); 143701c855caSPeter Wemm num[1] = 0; 143801c855caSPeter Wemm str = num; 143901c855caSPeter Wemm break; 144001c855caSPeter Wemm case 'm': 144101c855caSPeter Wemm str = strerror(errno); 144201c855caSPeter Wemm break; 144301c855caSPeter Wemm case 'v': /* "visible" string */ 144401c855caSPeter Wemm case 'q': /* quoted string */ 144501c855caSPeter Wemm quoted = c == 'q'; 144601c855caSPeter Wemm p = va_arg(args, unsigned char *); 144701c855caSPeter Wemm if (fillch == '0' && prec > 0) { 144801c855caSPeter Wemm n = prec; 144901c855caSPeter Wemm } else { 145001c855caSPeter Wemm n = strlen((char *)p); 145101c855caSPeter Wemm if (prec > 0 && prec < n) 145201c855caSPeter Wemm n = prec; 145301c855caSPeter Wemm } 145401c855caSPeter Wemm while (n > 0 && buflen > 0) { 145501c855caSPeter Wemm c = *p++; 145601c855caSPeter Wemm --n; 145701c855caSPeter Wemm if (!quoted && c >= 0x80) { 145801c855caSPeter Wemm OUTCHAR('M'); 145901c855caSPeter Wemm OUTCHAR('-'); 146001c855caSPeter Wemm c -= 0x80; 146101c855caSPeter Wemm } 146201c855caSPeter Wemm if (quoted && (c == '"' || c == '\\')) 146301c855caSPeter Wemm OUTCHAR('\\'); 146401c855caSPeter Wemm if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 146501c855caSPeter Wemm if (quoted) { 146601c855caSPeter Wemm OUTCHAR('\\'); 146701c855caSPeter Wemm switch (c) { 146801c855caSPeter Wemm case '\t': OUTCHAR('t'); break; 146901c855caSPeter Wemm case '\n': OUTCHAR('n'); break; 147001c855caSPeter Wemm case '\b': OUTCHAR('b'); break; 147101c855caSPeter Wemm case '\f': OUTCHAR('f'); break; 147201c855caSPeter Wemm default: 147301c855caSPeter Wemm OUTCHAR('x'); 147401c855caSPeter Wemm OUTCHAR(hexchars[c >> 4]); 147501c855caSPeter Wemm OUTCHAR(hexchars[c & 0xf]); 147601c855caSPeter Wemm } 147701c855caSPeter Wemm } else { 147801c855caSPeter Wemm if (c == '\t') 147901c855caSPeter Wemm OUTCHAR(c); 148001c855caSPeter Wemm else { 148101c855caSPeter Wemm OUTCHAR('^'); 148201c855caSPeter Wemm OUTCHAR(c ^ 0x40); 148301c855caSPeter Wemm } 148401c855caSPeter Wemm } 148501c855caSPeter Wemm } else 148601c855caSPeter Wemm OUTCHAR(c); 148701c855caSPeter Wemm } 148801c855caSPeter Wemm continue; 148901c855caSPeter Wemm default: 149001c855caSPeter Wemm *buf++ = '%'; 149101c855caSPeter Wemm if (c != '%') 149201c855caSPeter Wemm --fmt; /* so %z outputs %z etc. */ 149301c855caSPeter Wemm --buflen; 149401c855caSPeter Wemm continue; 149501c855caSPeter Wemm } 149601c855caSPeter Wemm if (base != 0) { 149701c855caSPeter Wemm str = num + sizeof(num); 149801c855caSPeter Wemm *--str = 0; 149901c855caSPeter Wemm while (str > num + neg) { 150001c855caSPeter Wemm *--str = hexchars[val % base]; 150101c855caSPeter Wemm val = val / base; 150201c855caSPeter Wemm if (--prec <= 0 && val == 0) 150301c855caSPeter Wemm break; 150401c855caSPeter Wemm } 150501c855caSPeter Wemm switch (neg) { 150601c855caSPeter Wemm case 1: 150701c855caSPeter Wemm *--str = '-'; 150801c855caSPeter Wemm break; 150901c855caSPeter Wemm case 2: 151001c855caSPeter Wemm *--str = 'x'; 151101c855caSPeter Wemm *--str = '0'; 151201c855caSPeter Wemm break; 151301c855caSPeter Wemm } 151401c855caSPeter Wemm len = num + sizeof(num) - 1 - str; 151501c855caSPeter Wemm } else { 151601c855caSPeter Wemm len = strlen(str); 151701c855caSPeter Wemm if (prec > 0 && len > prec) 151801c855caSPeter Wemm len = prec; 151901c855caSPeter Wemm } 152001c855caSPeter Wemm if (width > 0) { 152101c855caSPeter Wemm if (width > buflen) 152201c855caSPeter Wemm width = buflen; 152301c855caSPeter Wemm if ((n = width - len) > 0) { 152401c855caSPeter Wemm buflen -= n; 152501c855caSPeter Wemm for (; n > 0; --n) 152601c855caSPeter Wemm *buf++ = fillch; 152701c855caSPeter Wemm } 152801c855caSPeter Wemm } 152901c855caSPeter Wemm if (len > buflen) 153001c855caSPeter Wemm len = buflen; 153101c855caSPeter Wemm memcpy(buf, str, len); 153201c855caSPeter Wemm buf += len; 153301c855caSPeter Wemm buflen -= len; 153401c855caSPeter Wemm } 153501c855caSPeter Wemm *buf = 0; 153601c855caSPeter Wemm return buf - buf0; 153701c855caSPeter Wemm } 1538