chat.c revision 11990
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 3411990Speterstatic char rcsid[] = "$Id: chat.c,v 1.1.1.1 1994/11/12 05:25:32 lars 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 { 5454374Slars sysfatal("Can't get terminal parameters"); 54611990Speter } 5474374Slars 5484374Slars saved_tty_parameters = t; 54911990Speter have_tty_parameters = 1; 5504374Slars 55111990Speter t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 55211990Speter t.c_oflag = 0; 55311990Speter t.c_lflag = 0; 55411990Speter t.c_cc[VERASE] = 55511990Speter t.c_cc[VKILL] = 0; 55611990Speter t.c_cc[VMIN] = 1; 55711990Speter t.c_cc[VTIME] = 0; 5584374Slars 55911990Speter if (set_term_param (&t) < 0) 56011990Speter { 5614374Slars sysfatal("Can't set terminal parameters"); 56211990Speter } 5634374Slars#endif 5644374Slars } 5654374Slars 5664374Slarsvoid break_sequence() 5674374Slars { 5684374Slars#ifdef TERMIOS 5694374Slars tcsendbreak (0, 0); 5704374Slars#endif 5714374Slars } 5724374Slars 5734374Slarsvoid terminate(status) 5744374Slarsint status; 5754374Slars { 57611990Speter if (report_file != (char *) 0 && report_fp != (FILE *) NULL) 57711990Speter { 57811990Speter if (verbose) 57911990Speter { 58011990Speter fprintf (report_fp, "Closing \"%s\".\n", report_file); 58111990Speter } 58211990Speter fclose (report_fp); 58311990Speter report_fp = (FILE*) NULL; 5844374Slars } 5854374Slars 58611990Speter#if defined(get_term_param) 58711990Speter if (have_tty_parameters) 58811990Speter { 58911990Speter if (set_term_param (&saved_tty_parameters) < 0) 59011990Speter { 59111990Speter syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 59211990Speter exit(1); 59311990Speter } 59411990Speter } 59511990Speter#endif 5964374Slars 59711990Speter exit(status); 5984374Slars } 5994374Slars 6004374Slars/* 6014374Slars * 'Clean up' this string. 6024374Slars */ 6034374Slarschar *clean(s, sending) 6044374Slarsregister char *s; 6054374Slarsint sending; 6064374Slars { 6074374Slars char temp[STR_LEN], cur_chr; 6084374Slars register char *s1; 6094374Slars int add_return = sending; 6104374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 6114374Slars 6124374Slars s1 = temp; 6134374Slars while (*s) 6144374Slars { 6154374Slars cur_chr = *s++; 6164374Slars if (cur_chr == '^') 6174374Slars { 6184374Slars cur_chr = *s++; 6194374Slars if (cur_chr == '\0') 6204374Slars { 6214374Slars *s1++ = '^'; 6224374Slars break; 6234374Slars } 6244374Slars cur_chr &= 0x1F; 6254374Slars if (cur_chr != 0) 62611990Speter { 6274374Slars *s1++ = cur_chr; 62811990Speter } 6294374Slars continue; 6304374Slars } 6314374Slars 6324374Slars if (cur_chr != '\\') 6334374Slars { 6344374Slars *s1++ = cur_chr; 6354374Slars continue; 6364374Slars } 6374374Slars 6384374Slars cur_chr = *s++; 6394374Slars if (cur_chr == '\0') 6404374Slars { 6414374Slars if (sending) 6424374Slars { 6434374Slars *s1++ = '\\'; 6444374Slars *s1++ = '\\'; 6454374Slars } 6464374Slars break; 6474374Slars } 6484374Slars 6494374Slars switch (cur_chr) 6504374Slars { 6514374Slars case 'b': 6524374Slars *s1++ = '\b'; 6534374Slars break; 6544374Slars 6554374Slars case 'c': 6564374Slars if (sending && *s == '\0') 65711990Speter { 6584374Slars add_return = 0; 65911990Speter } 6604374Slars else 66111990Speter { 6624374Slars *s1++ = cur_chr; 66311990Speter } 6644374Slars break; 6654374Slars 6664374Slars case '\\': 6674374Slars case 'K': 6684374Slars case 'p': 6694374Slars case 'd': 6704374Slars if (sending) 67111990Speter { 6724374Slars *s1++ = '\\'; 67311990Speter } 6744374Slars 6754374Slars *s1++ = cur_chr; 6764374Slars break; 6774374Slars 6784374Slars case 'q': 6794374Slars quiet = ! quiet; 6804374Slars break; 6814374Slars 6824374Slars case 'r': 6834374Slars *s1++ = '\r'; 6844374Slars break; 6854374Slars 6864374Slars case 'n': 6874374Slars *s1++ = '\n'; 6884374Slars break; 6894374Slars 6904374Slars case 's': 6914374Slars *s1++ = ' '; 6924374Slars break; 6934374Slars 6944374Slars case 't': 6954374Slars *s1++ = '\t'; 6964374Slars break; 6974374Slars 6984374Slars case 'N': 6994374Slars if (sending) 7004374Slars { 7014374Slars *s1++ = '\\'; 7024374Slars *s1++ = '\0'; 7034374Slars } 7044374Slars else 70511990Speter { 7064374Slars *s1++ = 'N'; 70711990Speter } 7084374Slars break; 70911990Speter 7104374Slars default: 7114374Slars if (isoctal (cur_chr)) 7124374Slars { 7134374Slars cur_chr &= 0x07; 7144374Slars if (isoctal (*s)) 7154374Slars { 7164374Slars cur_chr <<= 3; 7174374Slars cur_chr |= *s++ - '0'; 7184374Slars if (isoctal (*s)) 7194374Slars { 7204374Slars cur_chr <<= 3; 7214374Slars cur_chr |= *s++ - '0'; 7224374Slars } 7234374Slars } 7244374Slars 7254374Slars if (cur_chr != 0 || sending) 7264374Slars { 7274374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 72811990Speter { 7294374Slars *s1++ = '\\'; 73011990Speter } 7314374Slars *s1++ = cur_chr; 7324374Slars } 7334374Slars break; 7344374Slars } 7354374Slars 7364374Slars if (sending) 73711990Speter { 7384374Slars *s1++ = '\\'; 73911990Speter } 7404374Slars *s1++ = cur_chr; 7414374Slars break; 7424374Slars } 7434374Slars } 7444374Slars 7454374Slars if (add_return) 74611990Speter { 7474374Slars *s1++ = '\r'; 74811990Speter } 7494374Slars 7504374Slars *s1++ = '\0'; /* guarantee closure */ 7514374Slars *s1++ = '\0'; /* terminate the string */ 7524374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7534374Slars } 7544374Slars 7554374Slars/* 7564374Slars * Process the expect string 7574374Slars */ 7584374Slarsvoid chat_expect(s) 7594374Slarsregister char *s; 7604374Slars { 7614374Slars if (strcmp(s, "ABORT") == 0) 7624374Slars { 7634374Slars ++abort_next; 7644374Slars return; 7654374Slars } 7664374Slars 76711990Speter if (strcmp(s, "REPORT") == 0) 76811990Speter { 76911990Speter ++report_next; 77011990Speter return; 77111990Speter } 77211990Speter 7734374Slars if (strcmp(s, "TIMEOUT") == 0) 7744374Slars { 7754374Slars ++timeout_next; 7764374Slars return; 7774374Slars } 7784374Slars 7794374Slars while (*s) 7804374Slars { 7814374Slars register char *hyphen; 7824374Slars 7834374Slars for (hyphen = s; *hyphen; ++hyphen) 78411990Speter { 7854374Slars if (*hyphen == '-') 78611990Speter { 7874374Slars if (hyphen == s || hyphen[-1] != '\\') 78811990Speter { 7894374Slars break; 79011990Speter } 79111990Speter } 79211990Speter } 79311990Speter 7944374Slars if (*hyphen == '-') 7954374Slars { 7964374Slars *hyphen = '\0'; 7974374Slars 7984374Slars if (get_string(s)) 79911990Speter { 8004374Slars return; 80111990Speter } 8024374Slars else 8034374Slars { 8044374Slars s = hyphen + 1; 8054374Slars 8064374Slars for (hyphen = s; *hyphen; ++hyphen) 80711990Speter { 8084374Slars if (*hyphen == '-') 80911990Speter { 8104374Slars if (hyphen == s || hyphen[-1] != '\\') 81111990Speter { 8124374Slars break; 81311990Speter } 81411990Speter } 81511990Speter } 8164374Slars 8174374Slars if (*hyphen == '-') 8184374Slars { 8194374Slars *hyphen = '\0'; 8204374Slars 8214374Slars chat_send(s); 8224374Slars s = hyphen + 1; 8234374Slars } 8244374Slars else 8254374Slars { 8264374Slars chat_send(s); 8274374Slars return; 8284374Slars } 8294374Slars } 8304374Slars } 8314374Slars else 83211990Speter { 8334374Slars if (get_string(s)) 83411990Speter { 8354374Slars return; 83611990Speter } 8374374Slars else 8384374Slars { 8394374Slars if (fail_reason) 84011990Speter { 8414374Slars syslog(LOG_INFO, "Failed (%s)", fail_reason); 84211990Speter } 8434374Slars else 84411990Speter { 8454374Slars syslog(LOG_INFO, "Failed"); 84611990Speter } 8474374Slars 84811990Speter terminate(exit_code); 8494374Slars } 85011990Speter } 8514374Slars } 8524374Slars } 8534374Slars 8544374Slarschar *character(c) 85511990Speterint c; 8564374Slars { 8574374Slars static char string[10]; 8584374Slars char *meta; 8594374Slars 8604374Slars meta = (c & 0x80) ? "M-" : ""; 8614374Slars c &= 0x7F; 8624374Slars 8634374Slars if (c < 32) 86411990Speter { 8654374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 86611990Speter } 8674374Slars else 86811990Speter { 8694374Slars if (c == 127) 87011990Speter { 8714374Slars sprintf(string, "%s^?", meta); 87211990Speter } 8734374Slars else 87411990Speter { 8754374Slars sprintf(string, "%s%c", meta, c); 87611990Speter } 87711990Speter } 8784374Slars 8794374Slars return (string); 8804374Slars } 8814374Slars 8824374Slars/* 8834374Slars * process the reply string 8844374Slars */ 8854374Slarsvoid chat_send (s) 8864374Slarsregister char *s; 8874374Slars { 8884374Slars if (abort_next) 88911990Speter { 8904374Slars char *s1; 89111990Speter 8924374Slars abort_next = 0; 89311990Speter 8944374Slars if (n_aborts >= MAX_ABORTS) 89511990Speter { 8964374Slars fatal("Too many ABORT strings"); 89711990Speter } 89811990Speter 8994374Slars s1 = clean(s, 0); 90011990Speter 90111990Speter if (strlen(s1) > strlen(s) 90211990Speter || strlen(s1) + 1 > sizeof(fail_buffer)) 9034374Slars { 9044374Slars syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 9054374Slars die(); 9064374Slars } 9074374Slars 9084374Slars abort_string[n_aborts++] = s1; 9094374Slars 9104374Slars if (verbose) 9114374Slars { 9124374Slars logf("abort on ("); 9134374Slars 9144374Slars for (s1 = s; *s1; ++s1) 91511990Speter { 9164374Slars logf(character(*s1)); 91711990Speter } 9184374Slars 9194374Slars logf(")\n"); 9204374Slars } 92111990Speter return; 9224374Slars } 92311990Speter 92411990Speter if (report_next) 92511990Speter { 92611990Speter char *s1; 92711990Speter 92811990Speter report_next = 0; 92911990Speter if (n_reports >= MAX_REPORTS) 9304374Slars { 93111990Speter fatal("Too many REPORT strings"); 93211990Speter } 93311990Speter 93411990Speter s1 = clean(s, 0); 93511990Speter 93611990Speter if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 93711990Speter { 93811990Speter syslog(LOG_WARNING, "Illegal or too-long REPORT string ('%s')", s); 93911990Speter die(); 94011990Speter } 94111990Speter 94211990Speter report_string[n_reports++] = s1; 94311990Speter 94411990Speter if (verbose) 94511990Speter { 94611990Speter logf("report ("); 94711990Speter s1 = s; 94811990Speter while (*s1) 94911990Speter { 95011990Speter logf(character(*s1)); 95111990Speter ++s1; 95211990Speter } 95311990Speter logf(")\n"); 95411990Speter } 95511990Speter return; 95611990Speter } 9574374Slars 95811990Speter if (timeout_next) 95911990Speter { 96011990Speter timeout_next = 0; 96111990Speter timeout = atoi(s); 96211990Speter 96311990Speter if (timeout <= 0) 96411990Speter { 96511990Speter timeout = DEFAULT_CHAT_TIMEOUT; 96611990Speter } 9674374Slars 96811990Speter if (verbose) 96911990Speter { 97011990Speter syslog(LOG_INFO, "timeout set to %d seconds", timeout); 9714374Slars } 97211990Speter return; 97311990Speter } 97411990Speter 97511990Speter if (strcmp(s, "EOT") == 0) 97611990Speter { 97711990Speter s = "^D\\c"; 97811990Speter } 97911990Speter else 98011990Speter { 98111990Speter if (strcmp(s, "BREAK") == 0) 9824374Slars { 98311990Speter s = "\\K\\c"; 9844374Slars } 98511990Speter } 98611990Speter 98711990Speter if (!put_string(s)) 98811990Speter { 98911990Speter syslog(LOG_INFO, "Failed"); 99011990Speter terminate(1); 99111990Speter } 9924374Slars } 9934374Slars 9944374Slarsint get_char() 9954374Slars { 9964374Slars int status; 9974374Slars char c; 9984374Slars 9994374Slars status = read(0, &c, 1); 10004374Slars 10014374Slars switch (status) 100211990Speter { 100311990Speter case 1: 100411990Speter return ((int)c & 0x7F); 10054374Slars 100611990Speter default: 100711990Speter syslog(LOG_WARNING, "warning: read() on stdin returned %d", 100811990Speter status); 10094374Slars 101011990Speter case -1: 101111990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 101211990Speter { 101311990Speter sysfatal("Can't get file mode flags on stdin"); 101411990Speter } 101511990Speter else 101611990Speter { 101711990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 101811990Speter { 101911990Speter sysfatal("Can't set file mode flags on stdin"); 102011990Speter } 102111990Speter } 102211990Speter 102311990Speter return (-1); 102411990Speter } 10254374Slars } 10264374Slars 10274374Slarsint put_char(c) 102811990Speterint c; 10294374Slars { 10304374Slars int status; 103111990Speter char ch = c; 10324374Slars 103311990Speter usleep(10000); /* inter-character typing delay (?) */ 10344374Slars 103511990Speter status = write(1, &ch, 1); 10364374Slars 10374374Slars switch (status) 103811990Speter { 103911990Speter case 1: 104011990Speter return (0); 104111990Speter 104211990Speter default: 104311990Speter syslog(LOG_WARNING, "warning: write() on stdout returned %d", 104411990Speter status); 104511990Speter 104611990Speter case -1: 104711990Speter if ((status = fcntl(0, F_GETFL, 0)) == -1) 104811990Speter { 104911990Speter sysfatal("Can't get file mode flags on stdin"); 105011990Speter } 105111990Speter else 105211990Speter { 105311990Speter if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1) 105411990Speter { 105511990Speter sysfatal("Can't set file mode flags on stdin"); 105611990Speter } 105711990Speter } 105811990Speter 105911990Speter return (-1); 106011990Speter } 10614374Slars } 10624374Slars 10634374Slarsint write_char (c) 10644374Slarsint c; 10654374Slars { 10664374Slars if (alarmed || put_char(c) < 0) 10674374Slars { 10684374Slars extern int errno; 10694374Slars 107011990Speter alarm(0); 107111990Speter alarmed = 0; 10724374Slars 10734374Slars if (verbose) 10744374Slars { 10754374Slars if (errno == EINTR || errno == EWOULDBLOCK) 107611990Speter { 10774374Slars syslog(LOG_INFO, " -- write timed out"); 107811990Speter } 10794374Slars else 108011990Speter { 10814374Slars syslog(LOG_INFO, " -- write failed: %m"); 108211990Speter } 10834374Slars } 10844374Slars return (0); 10854374Slars } 10864374Slars return (1); 10874374Slars } 10884374Slars 10894374Slarsint put_string (s) 10904374Slarsregister char *s; 10914374Slars { 10924374Slars s = clean(s, 1); 10934374Slars 10944374Slars if (verbose) 10954374Slars { 10964374Slars logf("send ("); 10974374Slars 10984374Slars if (quiet) 109911990Speter { 11004374Slars logf("??????"); 110111990Speter } 11024374Slars else 11034374Slars { 11044374Slars register char *s1 = s; 11054374Slars 11064374Slars for (s1 = s; *s1; ++s1) 110711990Speter { 11084374Slars logf(character(*s1)); 110911990Speter } 11104374Slars } 11114374Slars 11124374Slars logf(")\n"); 11134374Slars } 11144374Slars 11154374Slars alarm(timeout); alarmed = 0; 11164374Slars 11174374Slars while (*s) 11184374Slars { 11194374Slars register char c = *s++; 11204374Slars 11214374Slars if (c != '\\') 11224374Slars { 11234374Slars if (!write_char (c)) 112411990Speter { 11254374Slars return 0; 112611990Speter } 11274374Slars continue; 11284374Slars } 11294374Slars 11304374Slars c = *s++; 11314374Slars switch (c) 11324374Slars { 11334374Slars case 'd': 11344374Slars sleep(1); 11354374Slars break; 11364374Slars 11374374Slars case 'K': 11384374Slars break_sequence(); 11394374Slars break; 11404374Slars 11414374Slars case 'p': 114211990Speter usleep(10000); /* 1/100th of a second (arg is microseconds) */ 11434374Slars break; 11444374Slars 11454374Slars default: 11464374Slars if (!write_char (c)) 11474374Slars return 0; 11484374Slars break; 11494374Slars } 11504374Slars } 11514374Slars 11524374Slars alarm(0); 11534374Slars alarmed = 0; 11544374Slars return (1); 11554374Slars } 11564374Slars 11574374Slars/* 11584374Slars * 'Wait for' this string to appear on this file descriptor. 11594374Slars */ 11604374Slarsint get_string(string) 11614374Slarsregister char *string; 11624374Slars { 11634374Slars char temp[STR_LEN]; 11644374Slars int c, printed = 0, len, minlen; 11654374Slars register char *s = temp, *end = s + STR_LEN; 11664374Slars 11674374Slars fail_reason = (char *)0; 11684374Slars string = clean(string, 0); 11694374Slars len = strlen(string); 11704374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 11714374Slars 11724374Slars if (verbose) 11734374Slars { 11744374Slars register char *s1; 11754374Slars 11764374Slars logf("expect ("); 11774374Slars 11784374Slars for (s1 = string; *s1; ++s1) 117911990Speter { 11804374Slars logf(character(*s1)); 118111990Speter } 11824374Slars 11834374Slars logf(")\n"); 11844374Slars } 11854374Slars 11864374Slars if (len > STR_LEN) 11874374Slars { 11884374Slars syslog(LOG_INFO, "expect string is too long"); 118911990Speter exit_code = 1; 11904374Slars return 0; 11914374Slars } 11924374Slars 11934374Slars if (len == 0) 11944374Slars { 11954374Slars if (verbose) 11964374Slars { 11974374Slars syslog(LOG_INFO, "got it"); 11984374Slars } 11994374Slars 12004374Slars return (1); 12014374Slars } 12024374Slars 120311990Speter alarm(timeout); 120411990Speter alarmed = 0; 12054374Slars 12064374Slars while ( ! alarmed && (c = get_char()) >= 0) 12074374Slars { 120811990Speter int n, abort_len, report_len; 12094374Slars 12104374Slars if (verbose) 12114374Slars { 12124374Slars if (c == '\n') 121311990Speter { 12144374Slars logf("\n"); 121511990Speter } 12164374Slars else 121711990Speter { 12184374Slars logf(character(c)); 121911990Speter } 12204374Slars } 12214374Slars 12224374Slars *s++ = c; 12234374Slars 12244374Slars if (s - temp >= len && 12254374Slars c == string[len - 1] && 12264374Slars strncmp(s - len, string, len) == 0) 12274374Slars { 12284374Slars if (verbose) 12294374Slars { 12304374Slars logf(" -- got it\n"); 12314374Slars } 12324374Slars 123311990Speter alarm(0); 123411990Speter alarmed = 0; 12354374Slars return (1); 12364374Slars } 12374374Slars 12384374Slars for (n = 0; n < n_aborts; ++n) 123911990Speter { 12404374Slars if (s - temp >= (abort_len = strlen(abort_string[n])) && 12414374Slars strncmp(s - abort_len, abort_string[n], abort_len) == 0) 124211990Speter { 12434374Slars if (verbose) 12444374Slars { 12454374Slars logf(" -- failed\n"); 12464374Slars } 124711990Speter 124811990Speter alarm(0); 124911990Speter alarmed = 0; 125011990Speter exit_code = n + 4; 12514374Slars strcpy(fail_reason = fail_buffer, abort_string[n]); 12524374Slars return (0); 125311990Speter } 125411990Speter } 12554374Slars 125611990Speter if (!report_gathering) 125711990Speter { 125811990Speter for (n = 0; n < n_reports; ++n) 125911990Speter { 126011990Speter if ((report_string[n] != (char*) NULL) && 126111990Speter s - temp >= (report_len = strlen(report_string[n])) && 126211990Speter strncmp(s - report_len, report_string[n], report_len) == 0) 126311990Speter { 126411990Speter time_t time_now = time ((time_t*) NULL); 126511990Speter struct tm* tm_now = localtime (&time_now); 126611990Speter 126711990Speter strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now); 126811990Speter strcat (report_buffer, report_string[n]); 126911990Speter 127011990Speter report_string[n] = (char *) NULL; 127111990Speter report_gathering = 1; 127211990Speter break; 127311990Speter } 127411990Speter } 127511990Speter } 127611990Speter else 127711990Speter { 127811990Speter if (!iscntrl (c)) 127911990Speter { 128011990Speter int rep_len = strlen (report_buffer); 128111990Speter report_buffer[rep_len] = c; 128211990Speter report_buffer[rep_len + 1] = '\0'; 128311990Speter } 128411990Speter else 128511990Speter { 128611990Speter report_gathering = 0; 128711990Speter fprintf (report_fp, "chat: %s\n", report_buffer); 128811990Speter } 128911990Speter } 129011990Speter 12914374Slars if (s >= end) 12924374Slars { 129311990Speter strncpy (temp, s - minlen, minlen); 12944374Slars s = temp + minlen; 12954374Slars } 12964374Slars 12974374Slars if (alarmed && verbose) 129811990Speter { 12994374Slars syslog(LOG_WARNING, "warning: alarm synchronization problem"); 130011990Speter } 13014374Slars } 13024374Slars 13034374Slars alarm(0); 130411990Speter 13054374Slars if (verbose && printed) 13064374Slars { 13074374Slars if (alarmed) 130811990Speter { 13094374Slars logf(" -- read timed out\n"); 131011990Speter } 13114374Slars else 13124374Slars { 13134374Slars logflush(); 13144374Slars syslog(LOG_INFO, " -- read failed: %m"); 13154374Slars } 13164374Slars } 13174374Slars 131811990Speter exit_code = 3; 131911990Speter alarmed = 0; 13204374Slars return (0); 13214374Slars } 13224374Slars 132311990Speter#ifdef NO_USLEEP 13244374Slars#include <sys/types.h> 13254374Slars#include <sys/time.h> 13264374Slars 13274374Slars/* 13284374Slars usleep -- support routine for 4.2BSD system call emulations 13294374Slars last edit: 29-Oct-1984 D A Gwyn 13304374Slars */ 13314374Slars 13324374Slarsextern int select(); 13334374Slars 13344374Slarsint 13354374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 13364374Slars long usec; /* delay in microseconds */ 13374374Slars{ 13384374Slars static struct /* `timeval' */ 133911990Speter { 134011990Speter long tv_sec; /* seconds */ 134111990Speter long tv_usec; /* microsecs */ 134211990Speter } delay; /* _select() timeout */ 13434374Slars 134411990Speter delay.tv_sec = usec / 1000000L; 13454374Slars delay.tv_usec = usec % 1000000L; 13464374Slars 13474374Slars return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 13484374Slars} 13494374Slars#endif 1350