chat.c revision 24541
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 3424541Sjmgstatic char rcsid[] = "$Id: chat.c,v 1.6 1997/02/22 19:54:23 peter 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 894374Slarschar *program_name; 904374Slars 914374Slars#define MAX_ABORTS 50 9211990Speter#define MAX_REPORTS 50 934374Slars#define DEFAULT_CHAT_TIMEOUT 45 944374Slars 9511990Speterint verbose = 0; 9611990Speterint quiet = 0; 9711990Speterint report = 0; 9811990Speterint exit_code = 0; 9911990SpeterFILE* report_fp = (FILE *) 0; 10011990Speterchar *report_file = (char *) 0; 10111990Speterchar *chat_file = (char *) 0; 10211990Speterint timeout = DEFAULT_CHAT_TIMEOUT; 1034374Slars 1044374Slarsint have_tty_parameters = 0; 10511990Speter 1064374Slars#ifdef TERMIO 10711990Speter#define term_parms struct termio 10811990Speter#define get_term_param(param) ioctl(0, TCGETA, param) 10911990Speter#define set_term_param(param) ioctl(0, TCSETA, param) 1104374Slarsstruct termio saved_tty_parameters; 1114374Slars#endif 11211990Speter 1134374Slars#ifdef TERMIOS 11411990Speter#define term_parms struct termios 11511990Speter#define get_term_param(param) tcgetattr(0, param) 11611990Speter#define set_term_param(param) tcsetattr(0, TCSANOW, param) 1174374Slarsstruct termios saved_tty_parameters; 1184374Slars#endif 1194374Slars 1204374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1214374Slars fail_buffer[50]; 1224374Slarsint n_aborts = 0, abort_next = 0, timeout_next = 0; 1234374Slars 12411990Speterchar *report_string[MAX_REPORTS] ; 12511990Speterchar report_buffer[50] ; 12611990Speterint n_reports = 0, report_next = 0, report_gathering = 0 ; 12711990Speter 1284374Slarsvoid *dup_mem __P((void *b, size_t c)); 1294374Slarsvoid *copy_of __P((char *s)); 1304374Slarsvoid usage __P((void)); 1314374Slarsvoid logf __P((const char *str)); 1324374Slarsvoid logflush __P((void)); 1334374Slarsvoid fatal __P((const char *msg)); 1344374Slarsvoid sysfatal __P((const char *msg)); 1354374SlarsSIGTYPE sigalrm __P((int signo)); 1364374SlarsSIGTYPE sigint __P((int signo)); 1374374SlarsSIGTYPE sigterm __P((int signo)); 1384374SlarsSIGTYPE sighup __P((int signo)); 1394374Slarsvoid unalarm __P((void)); 1404374Slarsvoid init __P((void)); 1414374Slarsvoid set_tty_parameters __P((void)); 1424374Slarsvoid break_sequence __P((void)); 1434374Slarsvoid terminate __P((int status)); 1444374Slarsvoid do_file __P((char *chat_file)); 1454374Slarsint get_string __P((register char *string)); 1464374Slarsint put_string __P((register char *s)); 1474374Slarsint write_char __P((int c)); 14811990Speterint put_char __P((int c)); 1494374Slarsint get_char __P((void)); 1504374Slarsvoid chat_send __P((register char *s)); 15111990Speterchar *character __P((int c)); 1524374Slarsvoid chat_expect __P((register char *s)); 1534374Slarschar *clean __P((register char *s, int sending)); 1544374Slarsvoid break_sequence __P((void)); 1554374Slarsvoid terminate __P((int status)); 1564374Slarsvoid die __P((void)); 1574374Slars 1584374Slarsvoid *dup_mem(b, c) 1594374Slarsvoid *b; 1604374Slarssize_t c; 1614374Slars { 1624374Slars void *ans = malloc (c); 1634374Slars if (!ans) 16411990Speter { 1654374Slars fatal ("memory error!\n"); 16611990Speter } 1674374Slars memcpy (ans, b, c); 1684374Slars return ans; 1694374Slars } 1704374Slars 1714374Slarsvoid *copy_of (s) 1724374Slarschar *s; 1734374Slars { 1744374Slars return dup_mem (s, strlen (s) + 1); 1754374Slars } 1764374Slars 1774374Slars/* 17811990Speter * chat [ -v ] [ -t timeout ] [ -f chat-file ] [ -r report-file ] \ 1794374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 1804374Slars * 1814374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 1824374Slars */ 1834374Slarsint 1844374Slarsmain(argc, argv) 1854374Slarsint argc; 1864374Slarschar **argv; 1874374Slars { 1884374Slars int option; 1894374Slars char *arg; 1904374Slars 1914374Slars program_name = *argv; 19211990Speter tzset(); 1934374Slars 1944374Slars while (option = OPTION(argc, argv)) 19511990Speter { 1964374Slars switch (option) 1974374Slars { 1984374Slars case 'v': 1994374Slars ++verbose; 2004374Slars break; 2014374Slars 2024374Slars case 'f': 2034374Slars if (arg = OPTARG(argc, argv)) 20411990Speter { 2054374Slars chat_file = copy_of(arg); 20611990Speter } 2074374Slars else 20811990Speter { 2094374Slars usage(); 21011990Speter } 2114374Slars break; 2124374Slars 2134374Slars case 't': 2144374Slars if (arg = OPTARG(argc, argv)) 21511990Speter { 2164374Slars timeout = atoi(arg); 21711990Speter } 2184374Slars else 21911990Speter { 2204374Slars usage(); 22111990Speter } 22211990Speter break; 2234374Slars 22411990Speter case 'r': 22511990Speter arg = OPTARG (argc, argv); 22611990Speter if (arg) 22711990Speter { 22811990Speter if (report_fp != NULL) 22911990Speter { 23011990Speter fclose (report_fp); 23111990Speter } 23211990Speter report_file = copy_of (arg); 23311990Speter report_fp = fopen (report_file, "a"); 23411990Speter if (report_fp != NULL) 23511990Speter { 23611990Speter if (verbose) 23711990Speter { 23811990Speter fprintf (report_fp, "Opening \"%s\"...\n", 23911990Speter report_file); 24011990Speter } 24111990Speter report = 1; 24211990Speter } 24311990Speter } 2444374Slars break; 2454374Slars 2464374Slars default: 2474374Slars usage(); 24811990Speter break; 2494374Slars } 25011990Speter } 25111990Speter/* 25211990Speter * Default the report file to the stderr location 25311990Speter */ 25411990Speter if (report_fp == NULL) 25511990Speter { 25611990Speter report_fp = stderr; 25711990Speter } 2584374Slars 2594374Slars#ifdef ultrix 2604374Slars openlog("chat", LOG_PID); 2614374Slars#else 2624374Slars openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 2634374Slars 26411990Speter if (verbose) 26511990Speter { 2664374Slars setlogmask(LOG_UPTO(LOG_INFO)); 26711990Speter } 26811990Speter else 26911990Speter { 2704374Slars setlogmask(LOG_UPTO(LOG_WARNING)); 27111990Speter } 2724374Slars#endif 2734374Slars 2744374Slars init(); 27511990Speter 2764374Slars if (chat_file != NULL) 2774374Slars { 2784374Slars arg = ARG(argc, argv); 2794374Slars if (arg != NULL) 28011990Speter { 2814374Slars usage(); 28211990Speter } 2834374Slars else 28411990Speter { 2854374Slars do_file (chat_file); 28611990Speter } 2874374Slars } 2884374Slars else 2894374Slars { 2904374Slars while (arg = ARG(argc, argv)) 2914374Slars { 2924374Slars chat_expect(arg); 2934374Slars 2944374Slars if (arg = ARG(argc, argv)) 29511990Speter { 2964374Slars chat_send(arg); 29711990Speter } 2984374Slars } 2994374Slars } 3004374Slars 3014374Slars terminate(0); 3024374Slars } 3034374Slars 3044374Slars/* 3054374Slars * Process a chat script when read from a file. 3064374Slars */ 3074374Slars 3084374Slarsvoid do_file (chat_file) 3094374Slarschar *chat_file; 3104374Slars { 3114374Slars int linect, len, sendflg; 3124374Slars char *sp, *arg, quote; 3134374Slars char buf [STR_LEN]; 3144374Slars FILE *cfp; 3154374Slars 31611990Speter cfp = fopen (chat_file, "r"); 31711990Speter if (cfp == NULL) 3184374Slars { 3194374Slars syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 3204374Slars terminate (1); 3214374Slars } 3224374Slars 3234374Slars linect = 0; 3244374Slars sendflg = 0; 3254374Slars 3264374Slars while (fgets(buf, STR_LEN, cfp) != NULL) 3274374Slars { 3284374Slars sp = strchr (buf, '\n'); 3294374Slars if (sp) 33011990Speter { 3314374Slars *sp = '\0'; 33211990Speter } 3334374Slars 3344374Slars linect++; 3354374Slars sp = buf; 3364374Slars while (*sp != '\0') 3374374Slars { 3384374Slars if (*sp == ' ' || *sp == '\t') 3394374Slars { 3404374Slars ++sp; 3414374Slars continue; 3424374Slars } 3434374Slars 3444374Slars if (*sp == '"' || *sp == '\'') 3454374Slars { 3464374Slars quote = *sp++; 3474374Slars arg = sp; 3484374Slars while (*sp != quote) 3494374Slars { 3504374Slars if (*sp == '\0') 3514374Slars { 3524374Slars syslog (LOG_ERR, "unterminated quote (line %d)", 3534374Slars linect); 3544374Slars terminate (1); 3554374Slars } 35611990Speter 3574374Slars if (*sp++ == '\\') 35811990Speter { 3594374Slars if (*sp != '\0') 36011990Speter { 3614374Slars ++sp; 36211990Speter } 36311990Speter } 3644374Slars } 3654374Slars } 3664374Slars else 3674374Slars { 3684374Slars arg = sp; 3694374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 37011990Speter { 3714374Slars ++sp; 37211990Speter } 3734374Slars } 3744374Slars 3754374Slars if (*sp != '\0') 37611990Speter { 3774374Slars *sp++ = '\0'; 37811990Speter } 3794374Slars 3804374Slars if (sendflg) 3814374Slars { 3824374Slars chat_send (arg); 3834374Slars } 3844374Slars else 3854374Slars { 3864374Slars chat_expect (arg); 3874374Slars } 3884374Slars sendflg = !sendflg; 3894374Slars } 3904374Slars } 3914374Slars fclose (cfp); 3924374Slars } 3934374Slars 3944374Slars/* 3954374Slars * We got an error parsing the command line. 3964374Slars */ 3974374Slarsvoid usage() 3984374Slars { 3994374Slars fprintf(stderr, "\ 40011990SpeterUsage: %s [-v] [-t timeout] [-r report-file] {-f chat-file | chat-script}\n", 4014374Slars program_name); 4024374Slars exit(1); 4034374Slars } 4044374Slars 4054374Slarschar line[256]; 4064374Slarschar *p; 4074374Slars 4084374Slarsvoid logf (str) 4094374Slarsconst char *str; 4104374Slars { 4114374Slars p = line + strlen(line); 4124374Slars strcat (p, str); 4134374Slars 4144374Slars if (str[strlen(str)-1] == '\n') 4154374Slars { 4164374Slars syslog (LOG_INFO, "%s", line); 4174374Slars line[0] = 0; 4184374Slars } 4194374Slars } 4204374Slars 4214374Slarsvoid logflush() 4224374Slars { 4234374Slars if (line[0] != 0) 4244374Slars { 4254374Slars syslog(LOG_INFO, "%s", line); 4264374Slars line[0] = 0; 4274374Slars } 4284374Slars } 4294374Slars 4304374Slars/* 43111990Speter * Terminate with an error. 4324374Slars */ 4334374Slarsvoid die() 4344374Slars { 4354374Slars terminate(1); 4364374Slars } 4374374Slars 4384374Slars/* 4394374Slars * Print an error message and terminate. 4404374Slars */ 4414374Slars 4424374Slarsvoid fatal (msg) 4434374Slarsconst char *msg; 4444374Slars { 4454374Slars syslog(LOG_ERR, "%s", msg); 44611990Speter terminate(2); 4474374Slars } 4484374Slars 4494374Slars/* 4504374Slars * Print an error message along with the system error message and 4514374Slars * terminate. 4524374Slars */ 4534374Slars 4544374Slarsvoid sysfatal (msg) 4554374Slarsconst char *msg; 4564374Slars { 4574374Slars syslog(LOG_ERR, "%s: %m", msg); 45811990Speter terminate(2); 4594374Slars } 4604374Slars 4614374Slarsint alarmed = 0; 4624374Slars 4634374SlarsSIGTYPE sigalrm(signo) 4644374Slarsint signo; 4654374Slars { 4664374Slars int flags; 4674374Slars 4684374Slars alarm(1); 4694374Slars alarmed = 1; /* Reset alarm to avoid race window */ 4704374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4714374Slars 4724374Slars logflush(); 4734374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 47411990Speter { 4754374Slars sysfatal("Can't get file mode flags on stdin"); 47611990Speter } 4774374Slars else 47811990Speter { 47911990Speter if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1) 48011990Speter { 4814374Slars sysfatal("Can't set file mode flags on stdin"); 48211990Speter } 48311990Speter } 4844374Slars 4854374Slars if (verbose) 4864374Slars { 4874374Slars syslog(LOG_INFO, "alarm"); 4884374Slars } 4894374Slars } 4904374Slars 4914374Slarsvoid unalarm() 4924374Slars { 4934374Slars int flags; 4944374Slars 4954374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 49611990Speter { 4974374Slars sysfatal("Can't get file mode flags on stdin"); 49811990Speter } 4994374Slars else 50011990Speter { 50111990Speter if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1) 50211990Speter { 5034374Slars sysfatal("Can't set file mode flags on stdin"); 50411990Speter } 50511990Speter } 5064374Slars } 5074374Slars 5084374SlarsSIGTYPE sigint(signo) 5094374Slarsint signo; 5104374Slars { 5114374Slars fatal("SIGINT"); 5124374Slars } 5134374Slars 5144374SlarsSIGTYPE sigterm(signo) 5154374Slarsint signo; 5164374Slars { 5174374Slars fatal("SIGTERM"); 5184374Slars } 5194374Slars 5204374SlarsSIGTYPE sighup(signo) 5214374Slarsint signo; 5224374Slars { 5234374Slars fatal("SIGHUP"); 5244374Slars } 5254374Slars 5264374Slarsvoid init() 5274374Slars { 5284374Slars signal(SIGINT, sigint); 5294374Slars signal(SIGTERM, sigterm); 5304374Slars signal(SIGHUP, sighup); 5314374Slars 5324374Slars set_tty_parameters(); 5334374Slars signal(SIGALRM, sigalrm); 5344374Slars alarm(0); 5354374Slars alarmed = 0; 5364374Slars } 5374374Slars 5384374Slarsvoid set_tty_parameters() 5394374Slars { 54011990Speter#if defined(get_term_param) 54111990Speter term_parms t; 5424374Slars 54311990Speter if (get_term_param (&t) < 0) 54411990Speter { 54524541Sjmg have_tty_parameters = 0; 54624541Sjmg return; 54711990Speter } 5484374Slars 5494374Slars saved_tty_parameters = t; 55011990Speter have_tty_parameters = 1; 5514374Slars 55211990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 55311990Speter t.c_oflag = 0; 55411990Speter t.c_lflag = 0; 55511990Speter t.c_cc[VERASE] = 55611990Speter t.c_cc[VKILL] = 0; 55711990Speter t.c_cc[VMIN] = 1; 55811990Speter t.c_cc[VTIME] = 0; 5594374Slars 56011990Speter if (set_term_param (&t) < 0) 56111990Speter { 5624374Slars sysfatal("Can't set terminal parameters"); 56311990Speter } 5644374Slars#endif 5654374Slars } 5664374Slars 5674374Slarsvoid break_sequence() 5684374Slars { 5694374Slars#ifdef TERMIOS 5704374Slars tcsendbreak (0, 0); 5714374Slars#endif 5724374Slars } 5734374Slars 5744374Slarsvoid terminate(status) 5754374Slarsint status; 5764374Slars { 57711990Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 57811990Speter { 57911990Speter if (verbose) 58011990Speter { 58111990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 58211990Speter } 58311990Speter fclose (report_fp); 58411990Speter report_fp = (FILE*) NULL; 5854374Slars } 5864374Slars 58711990Speter#if defined(get_term_param) 58811990Speter if (have_tty_parameters) 58911990Speter { 59011990Speter if (set_term_param (&saved_tty_parameters) < 0) 59111990Speter { 59211990Speter syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 59311990Speter exit(1); 59411990Speter } 59511990Speter } 59611990Speter#endif 5974374Slars 59811990Speter exit(status); 5994374Slars } 6004374Slars 6014374Slars/* 6024374Slars * 'Clean up' this string. 6034374Slars */ 6044374Slarschar *clean(s, sending) 6054374Slarsregister char *s; 6064374Slarsint sending; 6074374Slars { 6084374Slars char temp[STR_LEN], cur_chr; 6094374Slars register char *s1; 6104374Slars int add_return = sending; 6114374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6124374Slars 6134374Slars s1 = temp; 6144374Slars while (*s) 6154374Slars { 6164374Slars cur_chr = *s++; 6174374Slars if (cur_chr == '^') 6184374Slars { 6194374Slars cur_chr = *s++; 6204374Slars if (cur_chr == '\0') 6214374Slars { 6224374Slars *s1++ = '^'; 6234374Slars break; 6244374Slars } 6254374Slars cur_chr &= 0x1F; 6264374Slars if (cur_chr != 0) 62711990Speter { 6284374Slars *s1++ = cur_chr; 62911990Speter } 6304374Slars continue; 6314374Slars } 6324374Slars 6334374Slars if (cur_chr != '\\') 6344374Slars { 6354374Slars *s1++ = cur_chr; 6364374Slars continue; 6374374Slars } 6384374Slars 6394374Slars cur_chr = *s++; 6404374Slars if (cur_chr == '\0') 6414374Slars { 6424374Slars if (sending) 6434374Slars { 6444374Slars *s1++ = '\\'; 6454374Slars *s1++ = '\\'; 6464374Slars } 6474374Slars break; 6484374Slars } 6494374Slars 6504374Slars switch (cur_chr) 6514374Slars { 6524374Slars case 'b': 6534374Slars *s1++ = '\b'; 6544374Slars break; 6554374Slars 6564374Slars case 'c': 6574374Slars if (sending && *s == '\0') 65811990Speter { 6594374Slars add_return = 0; 66011990Speter } 6614374Slars else 66211990Speter { 6634374Slars *s1++ = cur_chr; 66411990Speter } 6654374Slars break; 6664374Slars 6674374Slars case '\\': 6684374Slars case 'K': 6694374Slars case 'p': 6704374Slars case 'd': 6714374Slars if (sending) 67211990Speter { 6734374Slars *s1++ = '\\'; 67411990Speter } 6754374Slars 6764374Slars *s1++ = cur_chr; 6774374Slars break; 6784374Slars 6794374Slars case 'q': 6804374Slars quiet = ! quiet; 6814374Slars break; 6824374Slars 6834374Slars case 'r': 6844374Slars *s1++ = '\r'; 6854374Slars break; 6864374Slars 6874374Slars case 'n': 6884374Slars *s1++ = '\n'; 6894374Slars break; 6904374Slars 6914374Slars case 's': 6924374Slars *s1++ = ' '; 6934374Slars break; 6944374Slars 6954374Slars case 't': 6964374Slars *s1++ = '\t'; 6974374Slars break; 6984374Slars 6994374Slars case 'N': 7004374Slars if (sending) 7014374Slars { 7024374Slars *s1++ = '\\'; 7034374Slars *s1++ = '\0'; 7044374Slars } 7054374Slars else 70611990Speter { 7074374Slars *s1++ = 'N'; 70811990Speter } 7094374Slars break; 71011990Speter 7114374Slars default: 7124374Slars if (isoctal (cur_chr)) 7134374Slars { 7144374Slars cur_chr &= 0x07; 7154374Slars if (isoctal (*s)) 7164374Slars { 7174374Slars cur_chr <<= 3; 7184374Slars cur_chr |= *s++ - '0'; 7194374Slars if (isoctal (*s)) 7204374Slars { 7214374Slars cur_chr <<= 3; 7224374Slars cur_chr |= *s++ - '0'; 7234374Slars } 7244374Slars } 7254374Slars 7264374Slars if (cur_chr != 0 || sending) 7274374Slars { 7284374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 72911990Speter { 7304374Slars *s1++ = '\\'; 73111990Speter } 7324374Slars *s1++ = cur_chr; 7334374Slars } 7344374Slars break; 7354374Slars } 7364374Slars 7374374Slars if (sending) 73811990Speter { 7394374Slars *s1++ = '\\'; 74011990Speter } 7414374Slars *s1++ = cur_chr; 7424374Slars break; 7434374Slars } 7444374Slars } 7454374Slars 7464374Slars if (add_return) 74711990Speter { 7484374Slars *s1++ = '\r'; 74911990Speter } 7504374Slars 7514374Slars *s1++ = '\0'; /* guarantee closure */ 7524374Slars *s1++ = '\0'; /* terminate the string */ 7534374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7544374Slars } 7554374Slars 7564374Slars/* 7574374Slars * Process the expect string 7584374Slars */ 7594374Slarsvoid chat_expect(s) 7604374Slarsregister char *s; 7614374Slars { 7624374Slars if (strcmp(s, "ABORT") == 0) 7634374Slars { 7644374Slars ++abort_next; 7654374Slars return; 7664374Slars } 7674374Slars 76811990Speter if (strcmp(s, "REPORT") == 0) 76911990Speter { 77011990Speter ++report_next; 77111990Speter return; 77211990Speter } 77311990Speter 7744374Slars if (strcmp(s, "TIMEOUT") == 0) 7754374Slars { 7764374Slars ++timeout_next; 7774374Slars return; 7784374Slars } 7794374Slars 7804374Slars while (*s) 7814374Slars { 7824374Slars register char *hyphen; 7834374Slars 7844374Slars for (hyphen = s; *hyphen; ++hyphen) 78511990Speter { 7864374Slars if (*hyphen == '-') 78711990Speter { 7884374Slars if (hyphen == s || hyphen[-1] != '\\') 78911990Speter { 7904374Slars break; 79111990Speter } 79211990Speter } 79311990Speter } 79411990Speter 7954374Slars if (*hyphen == '-') 7964374Slars { 7974374Slars *hyphen = '\0'; 7984374Slars 7994374Slars if (get_string(s)) 80011990Speter { 8014374Slars return; 80211990Speter } 8034374Slars else 8044374Slars { 8054374Slars s = hyphen + 1; 8064374Slars 8074374Slars for (hyphen = s; *hyphen; ++hyphen) 80811990Speter { 8094374Slars if (*hyphen == '-') 81011990Speter { 8114374Slars if (hyphen == s || hyphen[-1] != '\\') 81211990Speter { 8134374Slars break; 81411990Speter } 81511990Speter } 81611990Speter } 8174374Slars 8184374Slars if (*hyphen == '-') 8194374Slars { 8204374Slars *hyphen = '\0'; 8214374Slars 8224374Slars chat_send(s); 8234374Slars s = hyphen + 1; 8244374Slars } 8254374Slars else 8264374Slars { 8274374Slars chat_send(s); 8284374Slars return; 8294374Slars } 8304374Slars } 8314374Slars } 8324374Slars else 83311990Speter { 8344374Slars if (get_string(s)) 83511990Speter { 8364374Slars return; 83711990Speter } 8384374Slars else 8394374Slars { 8404374Slars if (fail_reason) 84111990Speter { 8424374Slars syslog(LOG_INFO, "Failed (%s)", fail_reason); 84311990Speter } 8444374Slars else 84511990Speter { 8464374Slars syslog(LOG_INFO, "Failed"); 84711990Speter } 8484374Slars 84911990Speter terminate(exit_code); 8504374Slars } 85111990Speter } 8524374Slars } 8534374Slars } 8544374Slars 8554374Slarschar *character(c) 85611990Speterint c; 8574374Slars { 8584374Slars static char string[10]; 8594374Slars char *meta; 8604374Slars 8614374Slars meta = (c & 0x80) ? "M-" : ""; 8624374Slars c &= 0x7F; 8634374Slars 8644374Slars if (c < 32) 86511990Speter { 8664374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 86711990Speter } 8684374Slars else 86911990Speter { 8704374Slars if (c == 127) 87111990Speter { 8724374Slars sprintf(string, "%s^?", meta); 87311990Speter } 8744374Slars else 87511990Speter { 8764374Slars sprintf(string, "%s%c", meta, c); 87711990Speter } 87811990Speter } 8794374Slars 8804374Slars return (string); 8814374Slars } 8824374Slars 8834374Slars/* 8844374Slars * process the reply string 8854374Slars */ 8864374Slarsvoid chat_send (s) 8874374Slarsregister char *s; 8884374Slars { 8894374Slars if (abort_next) 89011990Speter { 8914374Slars char *s1; 89211990Speter 8934374Slars abort_next = 0; 89411990Speter 8954374Slars if (n_aborts >= MAX_ABORTS) 89611990Speter { 8974374Slars fatal("Too many ABORT strings"); 89811990Speter } 89911990Speter 9004374Slars s1 = clean(s, 0); 90111990Speter 90211990Speter if (strlen(s1) > strlen(s) 90311990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 9044374Slars { 9054374Slars syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 9064374Slars die(); 9074374Slars } 9084374Slars 9094374Slars abort_string[n_aborts++] = s1; 9104374Slars 9114374Slars if (verbose) 9124374Slars { 9134374Slars logf("abort on ("); 9144374Slars 9154374Slars for (s1 = s; *s1; ++s1) 91611990Speter { 9174374Slars logf(character(*s1)); 91811990Speter } 9194374Slars 9204374Slars logf(")\n"); 9214374Slars } 92211990Speter return; 9234374Slars } 92411990Speter 92511990Speter if (report_next) 92611990Speter { 92711990Speter char *s1; 92811990Speter 92911990Speter report_next = 0; 93011990Speter if (n_reports >= MAX_REPORTS) 9314374Slars { 93211990Speter fatal("Too many REPORT strings"); 93311990Speter } 93411990Speter 93511990Speter s1 = clean(s, 0); 93611990Speter 93711990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 93811990Speter { 93911990Speter syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 94011990Speter die(); 94111990Speter } 94211990Speter 94311990Speter report_string[n_reports++] = s1; 94411990Speter 94511990Speter if (verbose) 94611990Speter { 94711990Speter logf("report ("); 94811990Speter s1 = s; 94911990Speter while (*s1) 95011990Speter { 95111990Speter logf(character(*s1)); 95211990Speter ++s1; 95311990Speter } 95411990Speter logf(")\n"); 95511990Speter } 95611990Speter return; 95711990Speter } 9584374Slars 95911990Speter if (timeout_next) 96011990Speter { 96111990Speter timeout_next = 0; 96211990Speter timeout = atoi(s); 96311990Speter 96411990Speter if (timeout <= 0) 96511990Speter { 96611990Speter timeout = DEFAULT_CHAT_TIMEOUT; 96711990Speter } 9684374Slars 96911990Speter if (verbose) 97011990Speter { 97111990Speter syslog(LOG_INFO, "timeout set to %d seconds", timeout); 9724374Slars } 97311990Speter return; 97411990Speter } 97511990Speter 97611990Speter if (strcmp(s, "EOT") == 0) 97711990Speter { 97811990Speter s = "^D\\c"; 97911990Speter } 98011990Speter else 98111990Speter { 98211990Speter if (strcmp(s, "BREAK") == 0) 9834374Slars { 98411990Speter s = "\\K\\c"; 9854374Slars } 98611990Speter } 98711990Speter 98811990Speter if (!put_string(s)) 98911990Speter { 99011990Speter syslog(LOG_INFO, "Failed"); 99111990Speter terminate(1); 99211990Speter } 9934374Slars } 9944374Slars 9954374Slarsint get_char() 9964374Slars { 9974374Slars int status; 9984374Slars char c; 9994374Slars 10004374Slars status = read(0, &c, 1); 10014374Slars 10024374Slars switch (status) 100311990Speter { 100411990Speter case 1: 100511990Speter return ((int)c & 0x7F); 10064374Slars 100711990Speter default: 100811990Speter syslog(LOG_WARNING, "warning: read() on stdin returned %d", 100911990Speter status); 10104374Slars 101111990Speter case -1: 101211990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 101311990Speter { 101411990Speter sysfatal("Can't get file mode flags on stdin"); 101511990Speter } 101611990Speter else 101711990Speter { 101811990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 101911990Speter { 102011990Speter sysfatal("Can't set file mode flags on stdin"); 102111990Speter } 102211990Speter } 102311990Speter 102411990Speter return (-1); 102511990Speter } 10264374Slars } 10274374Slars 10284374Slarsint put_char(c) 102911990Speterint c; 10304374Slars { 10314374Slars int status; 103211990Speter char ch = c; 10334374Slars 103411990Speter usleep(10000); /* inter-character typing delay (?) */ 10354374Slars 103611990Speter status = write(1, &ch, 1); 10374374Slars 10384374Slars switch (status) 103911990Speter { 104011990Speter case 1: 104111990Speter return (0); 104211990Speter 104311990Speter default: 104411990Speter syslog(LOG_WARNING, "warning: write() on stdout returned %d", 104511990Speter status); 104611990Speter 104711990Speter case -1: 104811990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 104911990Speter { 105011990Speter sysfatal("Can't get file mode flags on stdin"); 105111990Speter } 105211990Speter else 105311990Speter { 105411990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 105511990Speter { 105611990Speter sysfatal("Can't set file mode flags on stdin"); 105711990Speter } 105811990Speter } 105911990Speter 106011990Speter return (-1); 106111990Speter } 10624374Slars } 10634374Slars 10644374Slarsint write_char (c) 10654374Slarsint c; 10664374Slars { 10674374Slars if (alarmed || put_char(c) < 0) 10684374Slars { 10694374Slars extern int errno; 10704374Slars 107111990Speter alarm(0); 107211990Speter alarmed = 0; 10734374Slars 10744374Slars if (verbose) 10754374Slars { 10764374Slars if (errno == EINTR || errno == EWOULDBLOCK) 107711990Speter { 10784374Slars syslog(LOG_INFO, " -- write timed out"); 107911990Speter } 10804374Slars else 108111990Speter { 10824374Slars syslog(LOG_INFO, " -- write failed: %m"); 108311990Speter } 10844374Slars } 10854374Slars return (0); 10864374Slars } 10874374Slars return (1); 10884374Slars } 10894374Slars 10904374Slarsint put_string (s) 10914374Slarsregister char *s; 10924374Slars { 10934374Slars s = clean(s, 1); 10944374Slars 10954374Slars if (verbose) 10964374Slars { 10974374Slars logf("send ("); 10984374Slars 10994374Slars if (quiet) 110011990Speter { 11014374Slars logf("??????"); 110211990Speter } 11034374Slars else 11044374Slars { 11054374Slars register char *s1 = s; 11064374Slars 11074374Slars for (s1 = s; *s1; ++s1) 110811990Speter { 11094374Slars logf(character(*s1)); 111011990Speter } 11114374Slars } 11124374Slars 11134374Slars logf(")\n"); 11144374Slars } 11154374Slars 11164374Slars alarm(timeout); alarmed = 0; 11174374Slars 11184374Slars while (*s) 11194374Slars { 11204374Slars register char c = *s++; 11214374Slars 11224374Slars if (c != '\\') 11234374Slars { 11244374Slars if (!write_char (c)) 112511990Speter { 11264374Slars return 0; 112711990Speter } 11284374Slars continue; 11294374Slars } 11304374Slars 11314374Slars c = *s++; 11324374Slars switch (c) 11334374Slars { 11344374Slars case 'd': 11354374Slars sleep(1); 11364374Slars break; 11374374Slars 11384374Slars case 'K': 11394374Slars break_sequence(); 11404374Slars break; 11414374Slars 11424374Slars case 'p': 114311990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11444374Slars break; 11454374Slars 11464374Slars default: 11474374Slars if (!write_char (c)) 11484374Slars return 0; 11494374Slars break; 11504374Slars } 11514374Slars } 11524374Slars 11534374Slars alarm(0); 11544374Slars alarmed = 0; 11554374Slars return (1); 11564374Slars } 11574374Slars 11584374Slars/* 11594374Slars * 'Wait for' this string to appear on this file descriptor. 11604374Slars */ 11614374Slarsint get_string(string) 11624374Slarsregister char *string; 11634374Slars { 11644374Slars char temp[STR_LEN]; 11654374Slars int c, printed = 0, len, minlen; 11664374Slars register char *s = temp, *end = s + STR_LEN; 11674374Slars 11684374Slars fail_reason = (char *)0; 11694374Slars string = clean(string, 0); 11704374Slars len = strlen(string); 11714374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 11724374Slars 11734374Slars if (verbose) 11744374Slars { 11754374Slars register char *s1; 11764374Slars 11774374Slars logf("expect ("); 11784374Slars 11794374Slars for (s1 = string; *s1; ++s1) 118011990Speter { 11814374Slars logf(character(*s1)); 118211990Speter } 11834374Slars 11844374Slars logf(")\n"); 11854374Slars } 11864374Slars 11874374Slars if (len > STR_LEN) 11884374Slars { 11894374Slars syslog(LOG_INFO, "expect string is too long"); 119011990Speter exit_code = 1; 11914374Slars return 0; 11924374Slars } 11934374Slars 11944374Slars if (len == 0) 11954374Slars { 11964374Slars if (verbose) 11974374Slars { 11984374Slars syslog(LOG_INFO, "got it"); 11994374Slars } 12004374Slars 12014374Slars return (1); 12024374Slars } 12034374Slars 120411990Speter alarm(timeout); 120511990Speter alarmed = 0; 12064374Slars 12074374Slars while ( ! alarmed && (c = get_char()) >= 0) 12084374Slars { 120911990Speter int n, abort_len, report_len; 12104374Slars 12114374Slars if (verbose) 12124374Slars { 12134374Slars if (c == '\n') 121411990Speter { 12154374Slars logf("\n"); 121611990Speter } 12174374Slars else 121811990Speter { 12194374Slars logf(character(c)); 122011990Speter } 12214374Slars } 12224374Slars 12234374Slars *s++ = c; 12244374Slars 12254374Slars if (s - temp >= len && 12264374Slars c == string[len - 1] && 12274374Slars strncmp(s - len, string, len) == 0) 12284374Slars { 12294374Slars if (verbose) 12304374Slars { 12314374Slars logf(" -- got it\n"); 12324374Slars } 12334374Slars 123411990Speter alarm(0); 123511990Speter alarmed = 0; 12364374Slars return (1); 12374374Slars } 12384374Slars 12394374Slars for (n = 0; n < n_aborts; ++n) 124011990Speter { 12414374Slars if (s - temp >= (abort_len = strlen(abort_string[n])) && 12424374Slars strncmp(s - abort_len, abort_string[n], abort_len) == 0) 124311990Speter { 12444374Slars if (verbose) 12454374Slars { 12464374Slars logf(" -- failed\n"); 12474374Slars } 124811990Speter 124911990Speter alarm(0); 125011990Speter alarmed = 0; 125111990Speter exit_code = n + 4; 12524374Slars strcpy(fail_reason = fail_buffer, abort_string[n]); 12534374Slars return (0); 125411990Speter } 125511990Speter } 12564374Slars 125711990Speter if (!report_gathering) 125811990Speter { 125911990Speter for (n = 0; n < n_reports; ++n) 126011990Speter { 126111990Speter if ((report_string[n] != (char*) NULL) && 126211990Speter s - temp >= (report_len = strlen(report_string[n])) && 126311990Speter strncmp(s - report_len, report_string[n], report_len) == 0) 126411990Speter { 126511990Speter time_t time_now = time ((time_t*) NULL); 126611990Speter struct tm* tm_now = localtime (&time_now); 126711990Speter 126811990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 126911990Speter strcat (report_buffer, report_string[n]); 127011990Speter 127111990Speter report_string[n] = (char *) NULL; 127211990Speter report_gathering = 1; 127311990Speter break; 127411990Speter } 127511990Speter } 127611990Speter } 127711990Speter else 127811990Speter { 127911990Speter if (!iscntrl (c)) 128011990Speter { 128111990Speter int rep_len = strlen (report_buffer); 128211990Speter report_buffer[rep_len] = c; 128311990Speter report_buffer[rep_len + 1] = '\0'; 128411990Speter } 128511990Speter else 128611990Speter { 128711990Speter report_gathering = 0; 128811990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 128911990Speter } 129011990Speter } 129111990Speter 12924374Slars if (s >= end) 12934374Slars { 129411990Speter strncpy (temp, s - minlen, minlen); 12954374Slars s = temp + minlen; 12964374Slars } 12974374Slars 12984374Slars if (alarmed && verbose) 129911990Speter { 13004374Slars syslog(LOG_WARNING, "warning: alarm synchronization problem"); 130111990Speter } 13024374Slars } 13034374Slars 13044374Slars alarm(0); 130511990Speter 13064374Slars if (verbose && printed) 13074374Slars { 13084374Slars if (alarmed) 130911990Speter { 13104374Slars logf(" -- read timed out\n"); 131111990Speter } 13124374Slars else 13134374Slars { 13144374Slars logflush(); 13154374Slars syslog(LOG_INFO, " -- read failed: %m"); 13164374Slars } 13174374Slars } 13184374Slars 131911990Speter exit_code = 3; 132011990Speter alarmed = 0; 13214374Slars return (0); 13224374Slars } 13234374Slars 132411990Speter#ifdef NO_USLEEP 13254374Slars#include <sys/types.h> 13264374Slars#include <sys/time.h> 13274374Slars 13284374Slars/* 13294374Slars usleep -- support routine for 4.2BSD system call emulations 13304374Slars last edit: 29-Oct-1984 D A Gwyn 13314374Slars */ 13324374Slars 13334374Slarsextern int select(); 13344374Slars 13354374Slarsint 13364374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 13374374Slars long usec; /* delay in microseconds */ 13384374Slars{ 13394374Slars static struct /* `timeval' */ 134011990Speter { 134111990Speter long tv_sec; /* seconds */ 134211990Speter long tv_usec; /* microsecs */ 134311990Speter } delay; /* _select() timeout */ 13444374Slars 134511990Speter delay.tv_sec = usec / 1000000L; 13464374Slars delay.tv_usec = usec % 1000000L; 13474374Slars 13484374Slars return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 13494374Slars} 13504374Slars#endif 1351