chat.c revision 26880
14374Slars/* 24374Slars * Chat -- a program for automatic session establishment (i.e. dial 34374Slars * the phone and log in). 44374Slars * 511990Speter * Standard termination codes: 611990Speter * 0 - successful completion of the script 711990Speter * 1 - invalid argument, expect string too large, etc. 811990Speter * 2 - error on an I/O operation or fatal error condtion. 911990Speter * 3 - timeout waiting for a simple string. 1011990Speter * 4 - the first string declared as "ABORT" 1111990Speter * 5 - the second string declared as "ABORT" 1211990Speter * 6 - ... and so on for successive ABORT strings. 1311990Speter * 144374Slars * This software is in the public domain. 154374Slars * 164374Slars * Please send all bug reports, requests for information, etc. to: 174374Slars * 184374Slars * Al Longyear (longyear@netcom.com) 194374Slars * (I was the last person to change this code.) 204374Slars * 2111990Speter * Added -r "report file" switch & REPORT keyword. 2211990Speter * Robert Geer <bgeer@xmission.com> 2311990Speter * 244374Slars * The original author is: 254374Slars * 264374Slars * Karl Fox <karl@MorningStar.Com> 274374Slars * Morning Star Technologies, Inc. 284374Slars * 1760 Zollinger Road 294374Slars * Columbus, OH 43221 304374Slars * (614)451-1883 3111990Speter * 324374Slars */ 334374Slars 3426880Scharnierstatic char rcsid[] = "$Id: chat.c,v 1.7 1997/04/02 09:55:26 jmg Exp $"; 354374Slars 364374Slars#include <stdio.h> 3711990Speter#include <time.h> 384374Slars#include <fcntl.h> 394374Slars#include <signal.h> 404374Slars#include <errno.h> 414374Slars#include <string.h> 424374Slars#include <stdlib.h> 434374Slars#include <sys/types.h> 444374Slars#include <sys/stat.h> 454374Slars#include <syslog.h> 464374Slars 474374Slars#ifndef TERMIO 484374Slars#undef TERMIOS 494374Slars#define TERMIOS 504374Slars#endif 514374Slars 524374Slars#ifdef TERMIO 534374Slars#include <termio.h> 544374Slars#endif 554374Slars#ifdef TERMIOS 564374Slars#include <termios.h> 574374Slars#endif 584374Slars 594374Slars#define STR_LEN 1024 604374Slars 614374Slars#ifndef SIGTYPE 624374Slars#define SIGTYPE void 634374Slars#endif 644374Slars 654374Slars#ifdef __STDC__ 664374Slars#undef __P 674374Slars#define __P(x) x 684374Slars#else 694374Slars#define __P(x) () 704374Slars#define const 714374Slars#endif 724374Slars 7311990Speter#ifndef O_NONBLOCK 7411990Speter#define O_NONBLOCK O_NDELAY 7511990Speter#endif 7611990Speter 774374Slars/*************** Micro getopt() *********************************************/ 784374Slars#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 794374Slars (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 804374Slars &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 814374Slars#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 824374Slars (_O=4,(char*)0):(char*)0) 834374Slars#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 844374Slars#define ARG(c,v) (c?(--c,*v++):(char*)0) 854374Slars 864374Slarsstatic int _O = 0; /* Internal state */ 874374Slars/*************** Micro getopt() *********************************************/ 884374Slars 894374Slars#define MAX_ABORTS 50 9011990Speter#define MAX_REPORTS 50 914374Slars#define DEFAULT_CHAT_TIMEOUT 45 924374Slars 9311990Speterint verbose = 0; 9411990Speterint quiet = 0; 9511990Speterint report = 0; 9611990Speterint exit_code = 0; 9711990SpeterFILE* report_fp = (FILE *) 0; 9811990Speterchar *report_file = (char *) 0; 9911990Speterchar *chat_file = (char *) 0; 10011990Speterint timeout = DEFAULT_CHAT_TIMEOUT; 1014374Slars 1024374Slarsint have_tty_parameters = 0; 10311990Speter 1044374Slars#ifdef TERMIO 10511990Speter#define term_parms struct termio 10611990Speter#define get_term_param(param) ioctl(0, TCGETA, param) 10711990Speter#define set_term_param(param) ioctl(0, TCSETA, param) 1084374Slarsstruct termio saved_tty_parameters; 1094374Slars#endif 11011990Speter 1114374Slars#ifdef TERMIOS 11211990Speter#define term_parms struct termios 11311990Speter#define get_term_param(param) tcgetattr(0, param) 11411990Speter#define set_term_param(param) tcsetattr(0, TCSANOW, param) 1154374Slarsstruct termios saved_tty_parameters; 1164374Slars#endif 1174374Slars 1184374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1194374Slars fail_buffer[50]; 1204374Slarsint n_aborts = 0, abort_next = 0, timeout_next = 0; 1214374Slars 12211990Speterchar *report_string[MAX_REPORTS] ; 12311990Speterchar report_buffer[50] ; 12411990Speterint n_reports = 0, report_next = 0, report_gathering = 0 ; 12511990Speter 1264374Slarsvoid *dup_mem __P((void *b, size_t c)); 1274374Slarsvoid *copy_of __P((char *s)); 12826880Scharnierstatic void usage __P((void)); 1294374Slarsvoid logf __P((const char *str)); 1304374Slarsvoid logflush __P((void)); 1314374Slarsvoid fatal __P((const char *msg)); 1324374Slarsvoid sysfatal __P((const char *msg)); 1334374SlarsSIGTYPE sigalrm __P((int signo)); 1344374SlarsSIGTYPE sigint __P((int signo)); 1354374SlarsSIGTYPE sigterm __P((int signo)); 1364374SlarsSIGTYPE sighup __P((int signo)); 1374374Slarsvoid unalarm __P((void)); 1384374Slarsvoid init __P((void)); 1394374Slarsvoid set_tty_parameters __P((void)); 1404374Slarsvoid break_sequence __P((void)); 1414374Slarsvoid terminate __P((int status)); 1424374Slarsvoid do_file __P((char *chat_file)); 1434374Slarsint get_string __P((register char *string)); 1444374Slarsint put_string __P((register char *s)); 1454374Slarsint write_char __P((int c)); 14611990Speterint put_char __P((int c)); 1474374Slarsint get_char __P((void)); 1484374Slarsvoid chat_send __P((register char *s)); 14911990Speterchar *character __P((int c)); 1504374Slarsvoid chat_expect __P((register char *s)); 1514374Slarschar *clean __P((register char *s, int sending)); 1524374Slarsvoid break_sequence __P((void)); 1534374Slarsvoid terminate __P((int status)); 1544374Slarsvoid die __P((void)); 1554374Slars 1564374Slarsvoid *dup_mem(b, c) 1574374Slarsvoid *b; 1584374Slarssize_t c; 1594374Slars { 1604374Slars void *ans = malloc (c); 1614374Slars if (!ans) 16211990Speter { 1634374Slars fatal ("memory error!\n"); 16411990Speter } 1654374Slars memcpy (ans, b, c); 1664374Slars return ans; 1674374Slars } 1684374Slars 1694374Slarsvoid *copy_of (s) 1704374Slarschar *s; 1714374Slars { 1724374Slars return dup_mem (s, strlen (s) + 1); 1734374Slars } 1744374Slars 1754374Slars/* 17611990Speter * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \ 1774374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 1784374Slars * 1794374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 1804374Slars */ 1814374Slarsint 1824374Slarsmain(argc, argv) 1834374Slarsint argc; 1844374Slarschar **argv; 1854374Slars { 1864374Slars int option; 1874374Slars char *arg; 1884374Slars 18911990Speter tzset(); 1904374Slars 1914374Slars while (option = OPTION(argc, argv)) 19211990Speter { 1934374Slars switch (option) 1944374Slars { 1954374Slars case 'v': 1964374Slars ++verbose; 1974374Slars break; 1984374Slars 1994374Slars case 'f': 2004374Slars if (arg = OPTARG(argc, argv)) 20111990Speter { 2024374Slars chat_file = copy_of(arg); 20311990Speter } 2044374Slars else 20511990Speter { 2064374Slars usage(); 20711990Speter } 2084374Slars break; 2094374Slars 2104374Slars case 't': 2114374Slars if (arg = OPTARG(argc, argv)) 21211990Speter { 2134374Slars timeout = atoi(arg); 21411990Speter } 2154374Slars else 21611990Speter { 2174374Slars usage(); 21811990Speter } 21911990Speter break; 2204374Slars 22111990Speter case 'r': 22211990Speter arg = OPTARG (argc, argv); 22311990Speter if (arg) 22411990Speter { 22511990Speter if (report_fp != NULL) 22611990Speter { 22711990Speter fclose (report_fp); 22811990Speter } 22911990Speter report_file = copy_of (arg); 23011990Speter report_fp = fopen (report_file, "a"); 23111990Speter if (report_fp != NULL) 23211990Speter { 23311990Speter if (verbose) 23411990Speter { 23511990Speter fprintf (report_fp, "Opening \"%s\"...\n", 23611990Speter report_file); 23711990Speter } 23811990Speter report = 1; 23911990Speter } 24011990Speter } 2414374Slars break; 2424374Slars 2434374Slars default: 2444374Slars usage(); 24511990Speter break; 2464374Slars } 24711990Speter } 24811990Speter/* 24911990Speter * Default the report file to the stderr location 25011990Speter */ 25111990Speter if (report_fp == NULL) 25211990Speter { 25311990Speter report_fp = stderr; 25411990Speter } 2554374Slars 2564374Slars#ifdef ultrix 2574374Slars openlog("chat", LOG_PID); 2584374Slars#else 2594374Slars openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 2604374Slars 26111990Speter if (verbose) 26211990Speter { 2634374Slars setlogmask(LOG_UPTO(LOG_INFO)); 26411990Speter } 26511990Speter else 26611990Speter { 2674374Slars setlogmask(LOG_UPTO(LOG_WARNING)); 26811990Speter } 2694374Slars#endif 2704374Slars 2714374Slars init(); 27211990Speter 2734374Slars if (chat_file != NULL) 2744374Slars { 2754374Slars arg = ARG(argc, argv); 2764374Slars if (arg != NULL) 27711990Speter { 2784374Slars usage(); 27911990Speter } 2804374Slars else 28111990Speter { 2824374Slars do_file (chat_file); 28311990Speter } 2844374Slars } 2854374Slars else 2864374Slars { 2874374Slars while (arg = ARG(argc, argv)) 2884374Slars { 2894374Slars chat_expect(arg); 2904374Slars 2914374Slars if (arg = ARG(argc, argv)) 29211990Speter { 2934374Slars chat_send(arg); 29411990Speter } 2954374Slars } 2964374Slars } 2974374Slars 2984374Slars terminate(0); 2994374Slars } 3004374Slars 3014374Slars/* 3024374Slars * Process a chat script when read from a file. 3034374Slars */ 3044374Slars 3054374Slarsvoid do_file (chat_file) 3064374Slarschar *chat_file; 3074374Slars { 3084374Slars int linect, len, sendflg; 3094374Slars char *sp, *arg, quote; 3104374Slars char buf [STR_LEN]; 3114374Slars FILE *cfp; 3124374Slars 31311990Speter cfp = fopen (chat_file, "r"); 31411990Speter if (cfp == NULL) 3154374Slars { 3164374Slars syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 3174374Slars terminate (1); 3184374Slars } 3194374Slars 3204374Slars linect = 0; 3214374Slars sendflg = 0; 3224374Slars 3234374Slars while (fgets(buf, STR_LEN, cfp) != NULL) 3244374Slars { 3254374Slars sp = strchr (buf, '\n'); 3264374Slars if (sp) 32711990Speter { 3284374Slars *sp = '\0'; 32911990Speter } 3304374Slars 3314374Slars linect++; 3324374Slars sp = buf; 3334374Slars while (*sp != '\0') 3344374Slars { 3354374Slars if (*sp == ' ' || *sp == '\t') 3364374Slars { 3374374Slars ++sp; 3384374Slars continue; 3394374Slars } 3404374Slars 3414374Slars if (*sp == '"' || *sp == '\'') 3424374Slars { 3434374Slars quote = *sp++; 3444374Slars arg = sp; 3454374Slars while (*sp != quote) 3464374Slars { 3474374Slars if (*sp == '\0') 3484374Slars { 3494374Slars syslog (LOG_ERR, "unterminated quote (line %d)", 3504374Slars linect); 3514374Slars terminate (1); 3524374Slars } 35311990Speter 3544374Slars if (*sp++ == '\\') 35511990Speter { 3564374Slars if (*sp != '\0') 35711990Speter { 3584374Slars ++sp; 35911990Speter } 36011990Speter } 3614374Slars } 3624374Slars } 3634374Slars else 3644374Slars { 3654374Slars arg = sp; 3664374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 36711990Speter { 3684374Slars ++sp; 36911990Speter } 3704374Slars } 3714374Slars 3724374Slars if (*sp != '\0') 37311990Speter { 3744374Slars *sp++ = '\0'; 37511990Speter } 3764374Slars 3774374Slars if (sendflg) 3784374Slars { 3794374Slars chat_send (arg); 3804374Slars } 3814374Slars else 3824374Slars { 3834374Slars chat_expect (arg); 3844374Slars } 3854374Slars sendflg = !sendflg; 3864374Slars } 3874374Slars } 3884374Slars fclose (cfp); 3894374Slars } 3904374Slars 3914374Slars/* 3924374Slars * We got an error parsing the command line. 3934374Slars */ 39426880Scharnierstatic void 39526880Scharnierusage() 3964374Slars { 39726880Scharnier fprintf(stderr, "%s %s\n", 39826880Scharnier "usage: chat [-v] [-t timeout] [-r report-file]", 39926880Scharnier "{-f chat-file | chat-script}"); 4004374Slars exit(1); 4014374Slars } 4024374Slars 4034374Slarschar line[256]; 4044374Slarschar *p; 4054374Slars 4064374Slarsvoid logf (str) 4074374Slarsconst char *str; 4084374Slars { 4094374Slars p = line + strlen(line); 4104374Slars strcat (p, str); 4114374Slars 4124374Slars if (str[strlen(str)-1] == '\n') 4134374Slars { 4144374Slars syslog (LOG_INFO, "%s", line); 4154374Slars line[0] = 0; 4164374Slars } 4174374Slars } 4184374Slars 4194374Slarsvoid logflush() 4204374Slars { 4214374Slars if (line[0] != 0) 4224374Slars { 4234374Slars syslog(LOG_INFO, "%s", line); 4244374Slars line[0] = 0; 4254374Slars } 4264374Slars } 4274374Slars 4284374Slars/* 42911990Speter * Terminate with an error. 4304374Slars */ 4314374Slarsvoid die() 4324374Slars { 4334374Slars terminate(1); 4344374Slars } 4354374Slars 4364374Slars/* 4374374Slars * Print an error message and terminate. 4384374Slars */ 4394374Slars 4404374Slarsvoid fatal (msg) 4414374Slarsconst char *msg; 4424374Slars { 4434374Slars syslog(LOG_ERR, "%s", msg); 44411990Speter terminate(2); 4454374Slars } 4464374Slars 4474374Slars/* 4484374Slars * Print an error message along with the system error message and 4494374Slars * terminate. 4504374Slars */ 4514374Slars 4524374Slarsvoid sysfatal (msg) 4534374Slarsconst char *msg; 4544374Slars { 4554374Slars syslog(LOG_ERR, "%s: %m", msg); 45611990Speter terminate(2); 4574374Slars } 4584374Slars 4594374Slarsint alarmed = 0; 4604374Slars 4614374SlarsSIGTYPE sigalrm(signo) 4624374Slarsint signo; 4634374Slars { 4644374Slars int flags; 4654374Slars 4664374Slars alarm(1); 4674374Slars alarmed = 1; /* Reset alarm to avoid race window */ 4684374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4694374Slars 4704374Slars logflush(); 4714374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 47211990Speter { 4734374Slars sysfatal("Can't get file mode flags on stdin"); 47411990Speter } 4754374Slars else 47611990Speter { 47711990Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 47811990Speter { 4794374Slars sysfatal("Can't set file mode flags on stdin"); 48011990Speter } 48111990Speter } 4824374Slars 4834374Slars if (verbose) 4844374Slars { 4854374Slars syslog(LOG_INFO, "alarm"); 4864374Slars } 4874374Slars } 4884374Slars 4894374Slarsvoid unalarm() 4904374Slars { 4914374Slars int flags; 4924374Slars 4934374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 49411990Speter { 4954374Slars sysfatal("Can't get file mode flags on stdin"); 49611990Speter } 4974374Slars else 49811990Speter { 49911990Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 50011990Speter { 5014374Slars sysfatal("Can't set file mode flags on stdin"); 50211990Speter } 50311990Speter } 5044374Slars } 5054374Slars 5064374SlarsSIGTYPE sigint(signo) 5074374Slarsint signo; 5084374Slars { 5094374Slars fatal("SIGINT"); 5104374Slars } 5114374Slars 5124374SlarsSIGTYPE sigterm(signo) 5134374Slarsint signo; 5144374Slars { 5154374Slars fatal("SIGTERM"); 5164374Slars } 5174374Slars 5184374SlarsSIGTYPE sighup(signo) 5194374Slarsint signo; 5204374Slars { 5214374Slars fatal("SIGHUP"); 5224374Slars } 5234374Slars 5244374Slarsvoid init() 5254374Slars { 5264374Slars signal(SIGINT, sigint); 5274374Slars signal(SIGTERM, sigterm); 5284374Slars signal(SIGHUP, sighup); 5294374Slars 5304374Slars set_tty_parameters(); 5314374Slars signal(SIGALRM, sigalrm); 5324374Slars alarm(0); 5334374Slars alarmed = 0; 5344374Slars } 5354374Slars 5364374Slarsvoid set_tty_parameters() 5374374Slars { 53811990Speter#if defined(get_term_param) 53911990Speter term_parms t; 5404374Slars 54111990Speter if (get_term_param (&t) < 0) 54211990Speter { 54324541Sjmg have_tty_parameters = 0; 54424541Sjmg return; 54511990Speter } 5464374Slars 5474374Slars saved_tty_parameters = t; 54811990Speter have_tty_parameters = 1; 5494374Slars 55011990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 55111990Speter t.c_oflag = 0; 55211990Speter t.c_lflag = 0; 55311990Speter t.c_cc[VERASE] = 55411990Speter t.c_cc[VKILL] = 0; 55511990Speter t.c_cc[VMIN] = 1; 55611990Speter t.c_cc[VTIME] = 0; 5574374Slars 55811990Speter if (set_term_param (&t) < 0) 55911990Speter { 5604374Slars sysfatal("Can't set terminal parameters"); 56111990Speter } 5624374Slars#endif 5634374Slars } 5644374Slars 5654374Slarsvoid break_sequence() 5664374Slars { 5674374Slars#ifdef TERMIOS 5684374Slars tcsendbreak (0, 0); 5694374Slars#endif 5704374Slars } 5714374Slars 5724374Slarsvoid terminate(status) 5734374Slarsint status; 5744374Slars { 57511990Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 57611990Speter { 57711990Speter if (verbose) 57811990Speter { 57911990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 58011990Speter } 58111990Speter fclose (report_fp); 58211990Speter report_fp = (FILE*) NULL; 5834374Slars } 5844374Slars 58511990Speter#if defined(get_term_param) 58611990Speter if (have_tty_parameters) 58711990Speter { 58811990Speter if (set_term_param (&saved_tty_parameters) < 0) 58911990Speter { 59011990Speter syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 59111990Speter exit(1); 59211990Speter } 59311990Speter } 59411990Speter#endif 5954374Slars 59611990Speter exit(status); 5974374Slars } 5984374Slars 5994374Slars/* 6004374Slars * 'Clean up' this string. 6014374Slars */ 6024374Slarschar *clean(s, sending) 6034374Slarsregister char *s; 6044374Slarsint sending; 6054374Slars { 6064374Slars char temp[STR_LEN], cur_chr; 6074374Slars register char *s1; 6084374Slars int add_return = sending; 6094374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6104374Slars 6114374Slars s1 = temp; 6124374Slars while (*s) 6134374Slars { 6144374Slars cur_chr = *s++; 6154374Slars if (cur_chr == '^') 6164374Slars { 6174374Slars cur_chr = *s++; 6184374Slars if (cur_chr == '\0') 6194374Slars { 6204374Slars *s1++ = '^'; 6214374Slars break; 6224374Slars } 6234374Slars cur_chr &= 0x1F; 6244374Slars if (cur_chr != 0) 62511990Speter { 6264374Slars *s1++ = cur_chr; 62711990Speter } 6284374Slars continue; 6294374Slars } 6304374Slars 6314374Slars if (cur_chr != '\\') 6324374Slars { 6334374Slars *s1++ = cur_chr; 6344374Slars continue; 6354374Slars } 6364374Slars 6374374Slars cur_chr = *s++; 6384374Slars if (cur_chr == '\0') 6394374Slars { 6404374Slars if (sending) 6414374Slars { 6424374Slars *s1++ = '\\'; 6434374Slars *s1++ = '\\'; 6444374Slars } 6454374Slars break; 6464374Slars } 6474374Slars 6484374Slars switch (cur_chr) 6494374Slars { 6504374Slars case 'b': 6514374Slars *s1++ = '\b'; 6524374Slars break; 6534374Slars 6544374Slars case 'c': 6554374Slars if (sending && *s == '\0') 65611990Speter { 6574374Slars add_return = 0; 65811990Speter } 6594374Slars else 66011990Speter { 6614374Slars *s1++ = cur_chr; 66211990Speter } 6634374Slars break; 6644374Slars 6654374Slars case '\\': 6664374Slars case 'K': 6674374Slars case 'p': 6684374Slars case 'd': 6694374Slars if (sending) 67011990Speter { 6714374Slars *s1++ = '\\'; 67211990Speter } 6734374Slars 6744374Slars *s1++ = cur_chr; 6754374Slars break; 6764374Slars 6774374Slars case 'q': 6784374Slars quiet = ! quiet; 6794374Slars break; 6804374Slars 6814374Slars case 'r': 6824374Slars *s1++ = '\r'; 6834374Slars break; 6844374Slars 6854374Slars case 'n': 6864374Slars *s1++ = '\n'; 6874374Slars break; 6884374Slars 6894374Slars case 's': 6904374Slars *s1++ = ' '; 6914374Slars break; 6924374Slars 6934374Slars case 't': 6944374Slars *s1++ = '\t'; 6954374Slars break; 6964374Slars 6974374Slars case 'N': 6984374Slars if (sending) 6994374Slars { 7004374Slars *s1++ = '\\'; 7014374Slars *s1++ = '\0'; 7024374Slars } 7034374Slars else 70411990Speter { 7054374Slars *s1++ = 'N'; 70611990Speter } 7074374Slars break; 70811990Speter 7094374Slars default: 7104374Slars if (isoctal (cur_chr)) 7114374Slars { 7124374Slars cur_chr &= 0x07; 7134374Slars if (isoctal (*s)) 7144374Slars { 7154374Slars cur_chr <<= 3; 7164374Slars cur_chr |= *s++ - '0'; 7174374Slars if (isoctal (*s)) 7184374Slars { 7194374Slars cur_chr <<= 3; 7204374Slars cur_chr |= *s++ - '0'; 7214374Slars } 7224374Slars } 7234374Slars 7244374Slars if (cur_chr != 0 || sending) 7254374Slars { 7264374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 72711990Speter { 7284374Slars *s1++ = '\\'; 72911990Speter } 7304374Slars *s1++ = cur_chr; 7314374Slars } 7324374Slars break; 7334374Slars } 7344374Slars 7354374Slars if (sending) 73611990Speter { 7374374Slars *s1++ = '\\'; 73811990Speter } 7394374Slars *s1++ = cur_chr; 7404374Slars break; 7414374Slars } 7424374Slars } 7434374Slars 7444374Slars if (add_return) 74511990Speter { 7464374Slars *s1++ = '\r'; 74711990Speter } 7484374Slars 7494374Slars *s1++ = '\0'; /* guarantee closure */ 7504374Slars *s1++ = '\0'; /* terminate the string */ 7514374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7524374Slars } 7534374Slars 7544374Slars/* 7554374Slars * Process the expect string 7564374Slars */ 7574374Slarsvoid chat_expect(s) 7584374Slarsregister char *s; 7594374Slars { 7604374Slars if (strcmp(s, "ABORT") == 0) 7614374Slars { 7624374Slars ++abort_next; 7634374Slars return; 7644374Slars } 7654374Slars 76611990Speter if (strcmp(s, "REPORT") == 0) 76711990Speter { 76811990Speter ++report_next; 76911990Speter return; 77011990Speter } 77111990Speter 7724374Slars if (strcmp(s, "TIMEOUT") == 0) 7734374Slars { 7744374Slars ++timeout_next; 7754374Slars return; 7764374Slars } 7774374Slars 7784374Slars while (*s) 7794374Slars { 7804374Slars register char *hyphen; 7814374Slars 7824374Slars for (hyphen = s; *hyphen; ++hyphen) 78311990Speter { 7844374Slars if (*hyphen == '-') 78511990Speter { 7864374Slars if (hyphen == s || hyphen[-1] != '\\') 78711990Speter { 7884374Slars break; 78911990Speter } 79011990Speter } 79111990Speter } 79211990Speter 7934374Slars if (*hyphen == '-') 7944374Slars { 7954374Slars *hyphen = '\0'; 7964374Slars 7974374Slars if (get_string(s)) 79811990Speter { 7994374Slars return; 80011990Speter } 8014374Slars else 8024374Slars { 8034374Slars s = hyphen + 1; 8044374Slars 8054374Slars for (hyphen = s; *hyphen; ++hyphen) 80611990Speter { 8074374Slars if (*hyphen == '-') 80811990Speter { 8094374Slars if (hyphen == s || hyphen[-1] != '\\') 81011990Speter { 8114374Slars break; 81211990Speter } 81311990Speter } 81411990Speter } 8154374Slars 8164374Slars if (*hyphen == '-') 8174374Slars { 8184374Slars *hyphen = '\0'; 8194374Slars 8204374Slars chat_send(s); 8214374Slars s = hyphen + 1; 8224374Slars } 8234374Slars else 8244374Slars { 8254374Slars chat_send(s); 8264374Slars return; 8274374Slars } 8284374Slars } 8294374Slars } 8304374Slars else 83111990Speter { 8324374Slars if (get_string(s)) 83311990Speter { 8344374Slars return; 83511990Speter } 8364374Slars else 8374374Slars { 8384374Slars if (fail_reason) 83911990Speter { 8404374Slars syslog(LOG_INFO, "Failed (%s)", fail_reason); 84111990Speter } 8424374Slars else 84311990Speter { 8444374Slars syslog(LOG_INFO, "Failed"); 84511990Speter } 8464374Slars 84711990Speter terminate(exit_code); 8484374Slars } 84911990Speter } 8504374Slars } 8514374Slars } 8524374Slars 8534374Slarschar *character(c) 85411990Speterint c; 8554374Slars { 8564374Slars static char string[10]; 8574374Slars char *meta; 8584374Slars 8594374Slars meta = (c & 0x80) ? "M-" : ""; 8604374Slars c &= 0x7F; 8614374Slars 8624374Slars if (c < 32) 86311990Speter { 8644374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 86511990Speter } 8664374Slars else 86711990Speter { 8684374Slars if (c == 127) 86911990Speter { 8704374Slars sprintf(string, "%s^?", meta); 87111990Speter } 8724374Slars else 87311990Speter { 8744374Slars sprintf(string, "%s%c", meta, c); 87511990Speter } 87611990Speter } 8774374Slars 8784374Slars return (string); 8794374Slars } 8804374Slars 8814374Slars/* 8824374Slars * process the reply string 8834374Slars */ 8844374Slarsvoid chat_send (s) 8854374Slarsregister char *s; 8864374Slars { 8874374Slars if (abort_next) 88811990Speter { 8894374Slars char *s1; 89011990Speter 8914374Slars abort_next = 0; 89211990Speter 8934374Slars if (n_aborts >= MAX_ABORTS) 89411990Speter { 8954374Slars fatal("Too many ABORT strings"); 89611990Speter } 89711990Speter 8984374Slars s1 = clean(s, 0); 89911990Speter 90011990Speter if (strlen(s1) > strlen(s) 90111990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 9024374Slars { 9034374Slars syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 9044374Slars die(); 9054374Slars } 9064374Slars 9074374Slars abort_string[n_aborts++] = s1; 9084374Slars 9094374Slars if (verbose) 9104374Slars { 9114374Slars logf("abort on ("); 9124374Slars 9134374Slars for (s1 = s; *s1; ++s1) 91411990Speter { 9154374Slars logf(character(*s1)); 91611990Speter } 9174374Slars 9184374Slars logf(")\n"); 9194374Slars } 92011990Speter return; 9214374Slars } 92211990Speter 92311990Speter if (report_next) 92411990Speter { 92511990Speter char *s1; 92611990Speter 92711990Speter report_next = 0; 92811990Speter if (n_reports >= MAX_REPORTS) 9294374Slars { 93011990Speter fatal("Too many REPORT strings"); 93111990Speter } 93211990Speter 93311990Speter s1 = clean(s, 0); 93411990Speter 93511990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 93611990Speter { 93711990Speter syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 93811990Speter die(); 93911990Speter } 94011990Speter 94111990Speter report_string[n_reports++] = s1; 94211990Speter 94311990Speter if (verbose) 94411990Speter { 94511990Speter logf("report ("); 94611990Speter s1 = s; 94711990Speter while (*s1) 94811990Speter { 94911990Speter logf(character(*s1)); 95011990Speter ++s1; 95111990Speter } 95211990Speter logf(")\n"); 95311990Speter } 95411990Speter return; 95511990Speter } 9564374Slars 95711990Speter if (timeout_next) 95811990Speter { 95911990Speter timeout_next = 0; 96011990Speter timeout = atoi(s); 96111990Speter 96211990Speter if (timeout <= 0) 96311990Speter { 96411990Speter timeout = DEFAULT_CHAT_TIMEOUT; 96511990Speter } 9664374Slars 96711990Speter if (verbose) 96811990Speter { 96911990Speter syslog(LOG_INFO, "timeout set to %d seconds", timeout); 9704374Slars } 97111990Speter return; 97211990Speter } 97311990Speter 97411990Speter if (strcmp(s, "EOT") == 0) 97511990Speter { 97611990Speter s = "^D\\c"; 97711990Speter } 97811990Speter else 97911990Speter { 98011990Speter if (strcmp(s, "BREAK") == 0) 9814374Slars { 98211990Speter s = "\\K\\c"; 9834374Slars } 98411990Speter } 98511990Speter 98611990Speter if (!put_string(s)) 98711990Speter { 98811990Speter syslog(LOG_INFO, "Failed"); 98911990Speter terminate(1); 99011990Speter } 9914374Slars } 9924374Slars 9934374Slarsint get_char() 9944374Slars { 9954374Slars int status; 9964374Slars char c; 9974374Slars 9984374Slars status = read(0, &c, 1); 9994374Slars 10004374Slars switch (status) 100111990Speter { 100211990Speter case 1: 100311990Speter return ((int)c & 0x7F); 10044374Slars 100511990Speter default: 100611990Speter syslog(LOG_WARNING, "warning: read() on stdin returned %d", 100711990Speter status); 10084374Slars 100911990Speter case -1: 101011990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 101111990Speter { 101211990Speter sysfatal("Can't get file mode flags on stdin"); 101311990Speter } 101411990Speter else 101511990Speter { 101611990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 101711990Speter { 101811990Speter sysfatal("Can't set file mode flags on stdin"); 101911990Speter } 102011990Speter } 102111990Speter 102211990Speter return (-1); 102311990Speter } 10244374Slars } 10254374Slars 10264374Slarsint put_char(c) 102711990Speterint c; 10284374Slars { 10294374Slars int status; 103011990Speter char ch = c; 10314374Slars 103211990Speter usleep(10000); /* inter-character typing delay (?) */ 10334374Slars 103411990Speter status = write(1, &ch, 1); 10354374Slars 10364374Slars switch (status) 103711990Speter { 103811990Speter case 1: 103911990Speter return (0); 104011990Speter 104111990Speter default: 104211990Speter syslog(LOG_WARNING, "warning: write() on stdout returned %d", 104311990Speter status); 104411990Speter 104511990Speter case -1: 104611990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 104711990Speter { 104811990Speter sysfatal("Can't get file mode flags on stdin"); 104911990Speter } 105011990Speter else 105111990Speter { 105211990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 105311990Speter { 105411990Speter sysfatal("Can't set file mode flags on stdin"); 105511990Speter } 105611990Speter } 105711990Speter 105811990Speter return (-1); 105911990Speter } 10604374Slars } 10614374Slars 10624374Slarsint write_char (c) 10634374Slarsint c; 10644374Slars { 10654374Slars if (alarmed || put_char(c) < 0) 10664374Slars { 10674374Slars extern int errno; 10684374Slars 106911990Speter alarm(0); 107011990Speter alarmed = 0; 10714374Slars 10724374Slars if (verbose) 10734374Slars { 10744374Slars if (errno == EINTR || errno == EWOULDBLOCK) 107511990Speter { 10764374Slars syslog(LOG_INFO, " -- write timed out"); 107711990Speter } 10784374Slars else 107911990Speter { 10804374Slars syslog(LOG_INFO, " -- write failed: %m"); 108111990Speter } 10824374Slars } 10834374Slars return (0); 10844374Slars } 10854374Slars return (1); 10864374Slars } 10874374Slars 10884374Slarsint put_string (s) 10894374Slarsregister char *s; 10904374Slars { 10914374Slars s = clean(s, 1); 10924374Slars 10934374Slars if (verbose) 10944374Slars { 10954374Slars logf("send ("); 10964374Slars 10974374Slars if (quiet) 109811990Speter { 10994374Slars logf("??????"); 110011990Speter } 11014374Slars else 11024374Slars { 11034374Slars register char *s1 = s; 11044374Slars 11054374Slars for (s1 = s; *s1; ++s1) 110611990Speter { 11074374Slars logf(character(*s1)); 110811990Speter } 11094374Slars } 11104374Slars 11114374Slars logf(")\n"); 11124374Slars } 11134374Slars 11144374Slars alarm(timeout); alarmed = 0; 11154374Slars 11164374Slars while (*s) 11174374Slars { 11184374Slars register char c = *s++; 11194374Slars 11204374Slars if (c != '\\') 11214374Slars { 11224374Slars if (!write_char (c)) 112311990Speter { 11244374Slars return 0; 112511990Speter } 11264374Slars continue; 11274374Slars } 11284374Slars 11294374Slars c = *s++; 11304374Slars switch (c) 11314374Slars { 11324374Slars case 'd': 11334374Slars sleep(1); 11344374Slars break; 11354374Slars 11364374Slars case 'K': 11374374Slars break_sequence(); 11384374Slars break; 11394374Slars 11404374Slars case 'p': 114111990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11424374Slars break; 11434374Slars 11444374Slars default: 11454374Slars if (!write_char (c)) 11464374Slars return 0; 11474374Slars break; 11484374Slars } 11494374Slars } 11504374Slars 11514374Slars alarm(0); 11524374Slars alarmed = 0; 11534374Slars return (1); 11544374Slars } 11554374Slars 11564374Slars/* 11574374Slars * 'Wait for' this string to appear on this file descriptor. 11584374Slars */ 11594374Slarsint get_string(string) 11604374Slarsregister char *string; 11614374Slars { 11624374Slars char temp[STR_LEN]; 11634374Slars int c, printed = 0, len, minlen; 11644374Slars register char *s = temp, *end = s + STR_LEN; 11654374Slars 11664374Slars fail_reason = (char *)0; 11674374Slars string = clean(string, 0); 11684374Slars len = strlen(string); 11694374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 11704374Slars 11714374Slars if (verbose) 11724374Slars { 11734374Slars register char *s1; 11744374Slars 11754374Slars logf("expect ("); 11764374Slars 11774374Slars for (s1 = string; *s1; ++s1) 117811990Speter { 11794374Slars logf(character(*s1)); 118011990Speter } 11814374Slars 11824374Slars logf(")\n"); 11834374Slars } 11844374Slars 11854374Slars if (len > STR_LEN) 11864374Slars { 11874374Slars syslog(LOG_INFO, "expect string is too long"); 118811990Speter exit_code = 1; 11894374Slars return 0; 11904374Slars } 11914374Slars 11924374Slars if (len == 0) 11934374Slars { 11944374Slars if (verbose) 11954374Slars { 11964374Slars syslog(LOG_INFO, "got it"); 11974374Slars } 11984374Slars 11994374Slars return (1); 12004374Slars } 12014374Slars 120211990Speter alarm(timeout); 120311990Speter alarmed = 0; 12044374Slars 12054374Slars while ( ! alarmed && (c = get_char()) >= 0) 12064374Slars { 120711990Speter int n, abort_len, report_len; 12084374Slars 12094374Slars if (verbose) 12104374Slars { 12114374Slars if (c == '\n') 121211990Speter { 12134374Slars logf("\n"); 121411990Speter } 12154374Slars else 121611990Speter { 12174374Slars logf(character(c)); 121811990Speter } 12194374Slars } 12204374Slars 12214374Slars *s++ = c; 12224374Slars 12234374Slars if (s - temp >= len && 12244374Slars c == string[len - 1] && 12254374Slars strncmp(s - len, string, len) == 0) 12264374Slars { 12274374Slars if (verbose) 12284374Slars { 12294374Slars logf(" -- got it\n"); 12304374Slars } 12314374Slars 123211990Speter alarm(0); 123311990Speter alarmed = 0; 12344374Slars return (1); 12354374Slars } 12364374Slars 12374374Slars for (n = 0; n < n_aborts; ++n) 123811990Speter { 12394374Slars if (s - temp >= (abort_len = strlen(abort_string[n])) && 12404374Slars strncmp(s - abort_len, abort_string[n], abort_len) == 0) 124111990Speter { 12424374Slars if (verbose) 12434374Slars { 12444374Slars logf(" -- failed\n"); 12454374Slars } 124611990Speter 124711990Speter alarm(0); 124811990Speter alarmed = 0; 124911990Speter exit_code = n + 4; 12504374Slars strcpy(fail_reason = fail_buffer, abort_string[n]); 12514374Slars return (0); 125211990Speter } 125311990Speter } 12544374Slars 125511990Speter if (!report_gathering) 125611990Speter { 125711990Speter for (n = 0; n < n_reports; ++n) 125811990Speter { 125911990Speter if ((report_string[n] != (char*) NULL) && 126011990Speter s - temp >= (report_len = strlen(report_string[n])) && 126111990Speter strncmp(s - report_len, report_string[n], report_len) == 0) 126211990Speter { 126311990Speter time_t time_now = time ((time_t*) NULL); 126411990Speter struct tm* tm_now = localtime (&time_now); 126511990Speter 126611990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 126711990Speter strcat (report_buffer, report_string[n]); 126811990Speter 126911990Speter report_string[n] = (char *) NULL; 127011990Speter report_gathering = 1; 127111990Speter break; 127211990Speter } 127311990Speter } 127411990Speter } 127511990Speter else 127611990Speter { 127711990Speter if (!iscntrl (c)) 127811990Speter { 127911990Speter int rep_len = strlen (report_buffer); 128011990Speter report_buffer[rep_len] = c; 128111990Speter report_buffer[rep_len + 1] = '\0'; 128211990Speter } 128311990Speter else 128411990Speter { 128511990Speter report_gathering = 0; 128611990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 128711990Speter } 128811990Speter } 128911990Speter 12904374Slars if (s >= end) 12914374Slars { 129211990Speter strncpy (temp, s - minlen, minlen); 12934374Slars s = temp + minlen; 12944374Slars } 12954374Slars 12964374Slars if (alarmed && verbose) 129711990Speter { 12984374Slars syslog(LOG_WARNING, "warning: alarm synchronization problem"); 129911990Speter } 13004374Slars } 13014374Slars 13024374Slars alarm(0); 130311990Speter 13044374Slars if (verbose && printed) 13054374Slars { 13064374Slars if (alarmed) 130711990Speter { 13084374Slars logf(" -- read timed out\n"); 130911990Speter } 13104374Slars else 13114374Slars { 13124374Slars logflush(); 13134374Slars syslog(LOG_INFO, " -- read failed: %m"); 13144374Slars } 13154374Slars } 13164374Slars 131711990Speter exit_code = 3; 131811990Speter alarmed = 0; 13194374Slars return (0); 13204374Slars } 13214374Slars 132211990Speter#ifdef NO_USLEEP 13234374Slars#include <sys/types.h> 13244374Slars#include <sys/time.h> 13254374Slars 13264374Slars/* 13274374Slars usleep -- support routine for 4.2BSD system call emulations 13284374Slars last edit: 29-Oct-1984 D A Gwyn 13294374Slars */ 13304374Slars 13314374Slarsextern int select(); 13324374Slars 13334374Slarsint 13344374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 13354374Slars long usec; /* delay in microseconds */ 13364374Slars{ 13374374Slars static struct /* `timeval' */ 133811990Speter { 133911990Speter long tv_sec; /* seconds */ 134011990Speter long tv_usec; /* microsecs */ 134111990Speter } delay; /* _select() timeout */ 13424374Slars 134311990Speter delay.tv_sec = usec / 1000000L; 13444374Slars delay.tv_usec = usec % 1000000L; 13454374Slars 13464374Slars return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 13474374Slars} 13484374Slars#endif 1349