chat.c revision 4374
14374Slars/* 24374Slars * Chat -- a program for automatic session establishment (i.e. dial 34374Slars * the phone and log in). 44374Slars * 54374Slars * This software is in the public domain. 64374Slars * 74374Slars * Please send all bug reports, requests for information, etc. to: 84374Slars * 94374Slars * Al Longyear (longyear@netcom.com) 104374Slars * (I was the last person to change this code.) 114374Slars * 124374Slars * The original author is: 134374Slars * 144374Slars * Karl Fox <karl@MorningStar.Com> 154374Slars * Morning Star Technologies, Inc. 164374Slars * 1760 Zollinger Road 174374Slars * Columbus, OH 43221 184374Slars * (614)451-1883 194374Slars */ 204374Slars 214374Slarsstatic char rcsid[] = "$Id: chat.c,v 1.4 1994/05/30 00:30:37 paulus Exp $"; 224374Slars 234374Slars#include <stdio.h> 244374Slars#include <fcntl.h> 254374Slars#include <signal.h> 264374Slars#include <errno.h> 274374Slars#include <string.h> 284374Slars#include <stdlib.h> 294374Slars#include <sys/types.h> 304374Slars#include <sys/stat.h> 314374Slars#include <syslog.h> 324374Slars 334374Slars#ifndef TERMIO 344374Slars#undef TERMIOS 354374Slars#define TERMIOS 364374Slars#endif 374374Slars 384374Slars#ifdef sun 394374Slars# if defined(SUNOS) && SUNOS >= 41 404374Slars# ifndef HDB 414374Slars# define HDB 424374Slars# endif 434374Slars# endif 444374Slars#endif 454374Slars 464374Slars#ifdef TERMIO 474374Slars#include <termio.h> 484374Slars#endif 494374Slars#ifdef TERMIOS 504374Slars#include <termios.h> 514374Slars#endif 524374Slars 534374Slars#define STR_LEN 1024 544374Slars 554374Slars#ifndef SIGTYPE 564374Slars#define SIGTYPE void 574374Slars#endif 584374Slars 594374Slars#ifdef __STDC__ 604374Slars#undef __P 614374Slars#define __P(x) x 624374Slars#else 634374Slars#define __P(x) () 644374Slars#define const 654374Slars#endif 664374Slars 674374Slars/*************** Micro getopt() *********************************************/ 684374Slars#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ 694374Slars (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ 704374Slars &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) 714374Slars#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ 724374Slars (_O=4,(char*)0):(char*)0) 734374Slars#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) 744374Slars#define ARG(c,v) (c?(--c,*v++):(char*)0) 754374Slars 764374Slarsstatic int _O = 0; /* Internal state */ 774374Slars/*************** Micro getopt() *********************************************/ 784374Slars 794374Slarschar *program_name; 804374Slars 814374Slars#ifndef LOCK_DIR 824374Slars# ifdef __NetBSD__ 834374Slars# define PIDSTRING 844374Slars# define LOCK_DIR "/var/spool/lock" 854374Slars# else 864374Slars# ifdef HDB 874374Slars# define PIDSTRING 884374Slars# define LOCK_DIR "/usr/spool/locks" 894374Slars# else /* HDB */ 904374Slars# define LOCK_DIR "/usr/spool/uucp" 914374Slars# endif /* HDB */ 924374Slars# endif 934374Slars#endif /* LOCK_DIR */ 944374Slars 954374Slars#define MAX_ABORTS 50 964374Slars#define DEFAULT_CHAT_TIMEOUT 45 974374Slars 984374Slarsint verbose = 0; 994374Slarsint quiet = 0; 1004374Slarschar *lock_file = (char *)0; 1014374Slarschar *chat_file = (char *)0; 1024374Slarsint timeout = DEFAULT_CHAT_TIMEOUT; 1034374Slars 1044374Slarsint have_tty_parameters = 0; 1054374Slars#ifdef TERMIO 1064374Slarsstruct termio saved_tty_parameters; 1074374Slars#endif 1084374Slars#ifdef TERMIOS 1094374Slarsstruct termios saved_tty_parameters; 1104374Slars#endif 1114374Slars 1124374Slarschar *abort_string[MAX_ABORTS], *fail_reason = (char *)0, 1134374Slars fail_buffer[50]; 1144374Slarsint n_aborts = 0, abort_next = 0, timeout_next = 0; 1154374Slars 1164374Slarsvoid *dup_mem __P((void *b, size_t c)); 1174374Slarsvoid *copy_of __P((char *s)); 1184374Slarsvoid usage __P((void)); 1194374Slarsvoid logf __P((const char *str)); 1204374Slarsvoid logflush __P((void)); 1214374Slarsvoid fatal __P((const char *msg)); 1224374Slarsvoid sysfatal __P((const char *msg)); 1234374SlarsSIGTYPE sigalrm __P((int signo)); 1244374SlarsSIGTYPE sigint __P((int signo)); 1254374SlarsSIGTYPE sigterm __P((int signo)); 1264374SlarsSIGTYPE sighup __P((int signo)); 1274374Slarsvoid unalarm __P((void)); 1284374Slarsvoid init __P((void)); 1294374Slarsvoid set_tty_parameters __P((void)); 1304374Slarsvoid break_sequence __P((void)); 1314374Slarsvoid terminate __P((int status)); 1324374Slarsvoid do_file __P((char *chat_file)); 1334374Slarsvoid lock __P((void)); 1344374Slarsvoid delay __P((void)); 1354374Slarsint get_string __P((register char *string)); 1364374Slarsint put_string __P((register char *s)); 1374374Slarsint write_char __P((int c)); 1384374Slarsint put_char __P((char c)); 1394374Slarsint get_char __P((void)); 1404374Slarsvoid chat_send __P((register char *s)); 1414374Slarschar *character __P((char c)); 1424374Slarsvoid chat_expect __P((register char *s)); 1434374Slarschar *clean __P((register char *s, int sending)); 1444374Slarsvoid unlock __P((void)); 1454374Slarsvoid lock __P((void)); 1464374Slarsvoid break_sequence __P((void)); 1474374Slarsvoid terminate __P((int status)); 1484374Slarsvoid die __P((void)); 1494374Slars 1504374Slarsvoid *dup_mem(b, c) 1514374Slarsvoid *b; 1524374Slarssize_t c; 1534374Slars { 1544374Slars void *ans = malloc (c); 1554374Slars if (!ans) 1564374Slars fatal ("memory error!\n"); 1574374Slars memcpy (ans, b, c); 1584374Slars return ans; 1594374Slars } 1604374Slars 1614374Slarsvoid *copy_of (s) 1624374Slarschar *s; 1634374Slars { 1644374Slars return dup_mem (s, strlen (s) + 1); 1654374Slars } 1664374Slars 1674374Slars/* 1684374Slars * chat [ -v ] [ -t timeout ] [ -l lock-file ] [ -f chat-file ] \ 1694374Slars * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] 1704374Slars * 1714374Slars * Perform a UUCP-dialer-like chat script on stdin and stdout. 1724374Slars */ 1734374Slarsint 1744374Slarsmain(argc, argv) 1754374Slarsint argc; 1764374Slarschar **argv; 1774374Slars { 1784374Slars int option; 1794374Slars char *arg; 1804374Slars 1814374Slars program_name = *argv; 1824374Slars 1834374Slars while (option = OPTION(argc, argv)) 1844374Slars switch (option) 1854374Slars { 1864374Slars case 'v': 1874374Slars ++verbose; 1884374Slars break; 1894374Slars 1904374Slars case 'f': 1914374Slars if (arg = OPTARG(argc, argv)) 1924374Slars chat_file = copy_of(arg); 1934374Slars else 1944374Slars usage(); 1954374Slars 1964374Slars break; 1974374Slars 1984374Slars case 'l': 1994374Slars if (arg = OPTARG(argc, argv)) 2004374Slars lock_file = copy_of(arg); 2014374Slars else 2024374Slars usage(); 2034374Slars 2044374Slars break; 2054374Slars 2064374Slars case 't': 2074374Slars if (arg = OPTARG(argc, argv)) 2084374Slars timeout = atoi(arg); 2094374Slars else 2104374Slars usage(); 2114374Slars 2124374Slars break; 2134374Slars 2144374Slars default: 2154374Slars usage(); 2164374Slars } 2174374Slars 2184374Slars#ifdef ultrix 2194374Slars openlog("chat", LOG_PID); 2204374Slars#else 2214374Slars openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); 2224374Slars 2234374Slars if (verbose) { 2244374Slars setlogmask(LOG_UPTO(LOG_INFO)); 2254374Slars } else { 2264374Slars setlogmask(LOG_UPTO(LOG_WARNING)); 2274374Slars } 2284374Slars#endif 2294374Slars 2304374Slars init(); 2314374Slars 2324374Slars if (chat_file != NULL) 2334374Slars { 2344374Slars arg = ARG(argc, argv); 2354374Slars if (arg != NULL) 2364374Slars usage(); 2374374Slars else 2384374Slars do_file (chat_file); 2394374Slars } 2404374Slars else 2414374Slars { 2424374Slars while (arg = ARG(argc, argv)) 2434374Slars { 2444374Slars chat_expect(arg); 2454374Slars 2464374Slars if (arg = ARG(argc, argv)) 2474374Slars chat_send(arg); 2484374Slars } 2494374Slars } 2504374Slars 2514374Slars terminate(0); 2524374Slars } 2534374Slars 2544374Slars/* 2554374Slars * Process a chat script when read from a file. 2564374Slars */ 2574374Slars 2584374Slarsvoid do_file (chat_file) 2594374Slarschar *chat_file; 2604374Slars { 2614374Slars int linect, len, sendflg; 2624374Slars char *sp, *arg, quote; 2634374Slars char buf [STR_LEN]; 2644374Slars FILE *cfp; 2654374Slars 2664374Slars if ((cfp = fopen (chat_file, "r")) == NULL) 2674374Slars { 2684374Slars syslog (LOG_ERR, "%s -- open failed: %m", chat_file); 2694374Slars terminate (1); 2704374Slars } 2714374Slars 2724374Slars linect = 0; 2734374Slars sendflg = 0; 2744374Slars 2754374Slars while (fgets(buf, STR_LEN, cfp) != NULL) 2764374Slars { 2774374Slars sp = strchr (buf, '\n'); 2784374Slars if (sp) 2794374Slars *sp = '\0'; 2804374Slars 2814374Slars linect++; 2824374Slars sp = buf; 2834374Slars while (*sp != '\0') 2844374Slars { 2854374Slars if (*sp == ' ' || *sp == '\t') 2864374Slars { 2874374Slars ++sp; 2884374Slars continue; 2894374Slars } 2904374Slars 2914374Slars if (*sp == '"' || *sp == '\'') 2924374Slars { 2934374Slars quote = *sp++; 2944374Slars arg = sp; 2954374Slars while (*sp != quote) 2964374Slars { 2974374Slars if (*sp == '\0') 2984374Slars { 2994374Slars syslog (LOG_ERR, "unterminated quote (line %d)", 3004374Slars linect); 3014374Slars terminate (1); 3024374Slars } 3034374Slars 3044374Slars if (*sp++ == '\\') 3054374Slars if (*sp != '\0') 3064374Slars ++sp; 3074374Slars } 3084374Slars } 3094374Slars else 3104374Slars { 3114374Slars arg = sp; 3124374Slars while (*sp != '\0' && *sp != ' ' && *sp != '\t') 3134374Slars ++sp; 3144374Slars } 3154374Slars 3164374Slars if (*sp != '\0') 3174374Slars *sp++ = '\0'; 3184374Slars 3194374Slars if (sendflg) 3204374Slars { 3214374Slars chat_send (arg); 3224374Slars } 3234374Slars else 3244374Slars { 3254374Slars chat_expect (arg); 3264374Slars } 3274374Slars sendflg = !sendflg; 3284374Slars } 3294374Slars } 3304374Slars fclose (cfp); 3314374Slars } 3324374Slars 3334374Slars/* 3344374Slars * We got an error parsing the command line. 3354374Slars */ 3364374Slarsvoid usage() 3374374Slars { 3384374Slars fprintf(stderr, "\ 3394374SlarsUsage: %s [-v] [-l lock-file] [-t timeout] {-f chat-file || chat-script}\n", 3404374Slars program_name); 3414374Slars exit(1); 3424374Slars } 3434374Slars 3444374Slarschar line[256]; 3454374Slarschar *p; 3464374Slars 3474374Slarsvoid logf (str) 3484374Slarsconst char *str; 3494374Slars { 3504374Slars p = line + strlen(line); 3514374Slars strcat (p, str); 3524374Slars 3534374Slars if (str[strlen(str)-1] == '\n') 3544374Slars { 3554374Slars syslog (LOG_INFO, "%s", line); 3564374Slars line[0] = 0; 3574374Slars } 3584374Slars } 3594374Slars 3604374Slarsvoid logflush() 3614374Slars { 3624374Slars if (line[0] != 0) 3634374Slars { 3644374Slars syslog(LOG_INFO, "%s", line); 3654374Slars line[0] = 0; 3664374Slars } 3674374Slars } 3684374Slars 3694374Slars/* 3704374Slars * Unlock and terminate with an error. 3714374Slars */ 3724374Slarsvoid die() 3734374Slars { 3744374Slars unlock(); 3754374Slars terminate(1); 3764374Slars } 3774374Slars 3784374Slars/* 3794374Slars * Print an error message and terminate. 3804374Slars */ 3814374Slars 3824374Slarsvoid fatal (msg) 3834374Slarsconst char *msg; 3844374Slars { 3854374Slars syslog(LOG_ERR, "%s", msg); 3864374Slars unlock(); 3874374Slars terminate(1); 3884374Slars } 3894374Slars 3904374Slars/* 3914374Slars * Print an error message along with the system error message and 3924374Slars * terminate. 3934374Slars */ 3944374Slars 3954374Slarsvoid sysfatal (msg) 3964374Slarsconst char *msg; 3974374Slars { 3984374Slars syslog(LOG_ERR, "%s: %m", msg); 3994374Slars unlock(); 4004374Slars terminate(1); 4014374Slars } 4024374Slars 4034374Slarsint alarmed = 0; 4044374Slars 4054374SlarsSIGTYPE sigalrm(signo) 4064374Slarsint signo; 4074374Slars { 4084374Slars int flags; 4094374Slars 4104374Slars alarm(1); 4114374Slars alarmed = 1; /* Reset alarm to avoid race window */ 4124374Slars signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ 4134374Slars 4144374Slars logflush(); 4154374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 4164374Slars sysfatal("Can't get file mode flags on stdin"); 4174374Slars else 4184374Slars if (fcntl(0, F_SETFL, flags | FNDELAY) == -1) 4194374Slars sysfatal("Can't set file mode flags on stdin"); 4204374Slars 4214374Slars if (verbose) 4224374Slars { 4234374Slars syslog(LOG_INFO, "alarm"); 4244374Slars } 4254374Slars } 4264374Slars 4274374Slarsvoid unalarm() 4284374Slars { 4294374Slars int flags; 4304374Slars 4314374Slars if ((flags = fcntl(0, F_GETFL, 0)) == -1) 4324374Slars sysfatal("Can't get file mode flags on stdin"); 4334374Slars else 4344374Slars if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1) 4354374Slars sysfatal("Can't set file mode flags on stdin"); 4364374Slars } 4374374Slars 4384374SlarsSIGTYPE sigint(signo) 4394374Slarsint signo; 4404374Slars { 4414374Slars fatal("SIGINT"); 4424374Slars } 4434374Slars 4444374SlarsSIGTYPE sigterm(signo) 4454374Slarsint signo; 4464374Slars { 4474374Slars fatal("SIGTERM"); 4484374Slars } 4494374Slars 4504374SlarsSIGTYPE sighup(signo) 4514374Slarsint signo; 4524374Slars { 4534374Slars fatal("SIGHUP"); 4544374Slars } 4554374Slars 4564374Slarsvoid init() 4574374Slars { 4584374Slars signal(SIGINT, sigint); 4594374Slars signal(SIGTERM, sigterm); 4604374Slars signal(SIGHUP, sighup); 4614374Slars 4624374Slars if (lock_file) 4634374Slars lock(); 4644374Slars 4654374Slars set_tty_parameters(); 4664374Slars signal(SIGALRM, sigalrm); 4674374Slars alarm(0); 4684374Slars alarmed = 0; 4694374Slars } 4704374Slars 4714374Slarsvoid set_tty_parameters() 4724374Slars { 4734374Slars#ifdef TERMIO 4744374Slars struct termio t; 4754374Slars 4764374Slars if (ioctl(0, TCGETA, &t) < 0) 4774374Slars sysfatal("Can't get terminal parameters"); 4784374Slars#endif 4794374Slars#ifdef TERMIOS 4804374Slars struct termios t; 4814374Slars 4824374Slars if (tcgetattr(0, &t) < 0) 4834374Slars sysfatal("Can't get terminal parameters"); 4844374Slars#endif 4854374Slars 4864374Slars saved_tty_parameters = t; 4874374Slars have_tty_parameters = 1; 4884374Slars 4894374Slars t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; 4904374Slars t.c_oflag = 0; 4914374Slars t.c_lflag = 0; 4924374Slars t.c_cc[VERASE] = t.c_cc[VKILL] = 0; 4934374Slars t.c_cc[VMIN] = 1; 4944374Slars t.c_cc[VTIME] = 0; 4954374Slars 4964374Slars#ifdef TERMIO 4974374Slars if (ioctl(0, TCSETA, &t) < 0) 4984374Slars sysfatal("Can't set terminal parameters"); 4994374Slars#endif 5004374Slars#ifdef TERMIOS 5014374Slars if (tcsetattr(0, TCSANOW, &t) < 0) 5024374Slars sysfatal("Can't set terminal parameters"); 5034374Slars#endif 5044374Slars } 5054374Slars 5064374Slarsvoid break_sequence() 5074374Slars { 5084374Slars#ifdef TERMIOS 5094374Slars tcsendbreak (0, 0); 5104374Slars#endif 5114374Slars } 5124374Slars 5134374Slarsvoid terminate(status) 5144374Slarsint status; 5154374Slars { 5164374Slars if (have_tty_parameters && 5174374Slars#ifdef TERMIO 5184374Slars ioctl(0, TCSETA, &saved_tty_parameters) < 0 5194374Slars#endif 5204374Slars#ifdef TERMIOS 5214374Slars tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0 5224374Slars#endif 5234374Slars ) { 5244374Slars syslog(LOG_ERR, "Can't restore terminal parameters: %m"); 5254374Slars unlock(); 5264374Slars exit(1); 5274374Slars } 5284374Slars exit(status); 5294374Slars } 5304374Slars 5314374Slars/* 5324374Slars * Create a lock file for the named lock device 5334374Slars */ 5344374Slarsvoid lock() 5354374Slars { 5364374Slars int fd, pid; 5374374Slars# ifdef PIDSTRING 5384374Slars char hdb_lock_buffer[12]; 5394374Slars# endif 5404374Slars 5414374Slars lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR) 5424374Slars + 1 + strlen(lock_file) + 1), 5434374Slars LOCK_DIR), "/"), lock_file); 5444374Slars 5454374Slars if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) 5464374Slars { 5474374Slars char *s = lock_file; 5484374Slars lock_file = (char *)0; /* Don't remove someone else's lock file! */ 5494374Slars syslog(LOG_ERR, "Can't get lock file '%s': %m", s); 5504374Slars die(); 5514374Slars } 5524374Slars 5534374Slars# ifdef PIDSTRING 5544374Slars sprintf(hdb_lock_buffer, "%10d\n", getpid()); 5554374Slars write(fd, hdb_lock_buffer, 11); 5564374Slars# else 5574374Slars pid = getpid(); 5584374Slars write(fd, &pid, sizeof pid); 5594374Slars# endif 5604374Slars 5614374Slars close(fd); 5624374Slars } 5634374Slars 5644374Slars/* 5654374Slars * Remove our lockfile 5664374Slars */ 5674374Slarsvoid unlock() 5684374Slars { 5694374Slars if (lock_file) 5704374Slars { 5714374Slars unlink(lock_file); 5724374Slars lock_file = (char *)0; 5734374Slars } 5744374Slars } 5754374Slars 5764374Slars/* 5774374Slars * 'Clean up' this string. 5784374Slars */ 5794374Slarschar *clean(s, sending) 5804374Slarsregister char *s; 5814374Slarsint sending; 5824374Slars { 5834374Slars char temp[STR_LEN], cur_chr; 5844374Slars register char *s1; 5854374Slars int add_return = sending; 5864374Slars#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) 5874374Slars 5884374Slars s1 = temp; 5894374Slars while (*s) 5904374Slars { 5914374Slars cur_chr = *s++; 5924374Slars if (cur_chr == '^') 5934374Slars { 5944374Slars cur_chr = *s++; 5954374Slars if (cur_chr == '\0') 5964374Slars { 5974374Slars *s1++ = '^'; 5984374Slars break; 5994374Slars } 6004374Slars cur_chr &= 0x1F; 6014374Slars if (cur_chr != 0) 6024374Slars *s1++ = cur_chr; 6034374Slars continue; 6044374Slars } 6054374Slars 6064374Slars if (cur_chr != '\\') 6074374Slars { 6084374Slars *s1++ = cur_chr; 6094374Slars continue; 6104374Slars } 6114374Slars 6124374Slars cur_chr = *s++; 6134374Slars if (cur_chr == '\0') 6144374Slars { 6154374Slars if (sending) 6164374Slars { 6174374Slars *s1++ = '\\'; 6184374Slars *s1++ = '\\'; 6194374Slars } 6204374Slars break; 6214374Slars } 6224374Slars 6234374Slars switch (cur_chr) 6244374Slars { 6254374Slars case 'b': 6264374Slars *s1++ = '\b'; 6274374Slars break; 6284374Slars 6294374Slars case 'c': 6304374Slars if (sending && *s == '\0') 6314374Slars add_return = 0; 6324374Slars else 6334374Slars *s1++ = cur_chr; 6344374Slars break; 6354374Slars 6364374Slars case '\\': 6374374Slars case 'K': 6384374Slars case 'p': 6394374Slars case 'd': 6404374Slars if (sending) 6414374Slars *s1++ = '\\'; 6424374Slars 6434374Slars *s1++ = cur_chr; 6444374Slars break; 6454374Slars 6464374Slars case 'q': 6474374Slars quiet = ! quiet; 6484374Slars break; 6494374Slars 6504374Slars case 'r': 6514374Slars *s1++ = '\r'; 6524374Slars break; 6534374Slars 6544374Slars case 'n': 6554374Slars *s1++ = '\n'; 6564374Slars break; 6574374Slars 6584374Slars case 's': 6594374Slars *s1++ = ' '; 6604374Slars break; 6614374Slars 6624374Slars case 't': 6634374Slars *s1++ = '\t'; 6644374Slars break; 6654374Slars 6664374Slars case 'N': 6674374Slars if (sending) 6684374Slars { 6694374Slars *s1++ = '\\'; 6704374Slars *s1++ = '\0'; 6714374Slars } 6724374Slars else 6734374Slars *s1++ = 'N'; 6744374Slars break; 6754374Slars 6764374Slars default: 6774374Slars if (isoctal (cur_chr)) 6784374Slars { 6794374Slars cur_chr &= 0x07; 6804374Slars if (isoctal (*s)) 6814374Slars { 6824374Slars cur_chr <<= 3; 6834374Slars cur_chr |= *s++ - '0'; 6844374Slars if (isoctal (*s)) 6854374Slars { 6864374Slars cur_chr <<= 3; 6874374Slars cur_chr |= *s++ - '0'; 6884374Slars } 6894374Slars } 6904374Slars 6914374Slars if (cur_chr != 0 || sending) 6924374Slars { 6934374Slars if (sending && (cur_chr == '\\' || cur_chr == 0)) 6944374Slars *s1++ = '\\'; 6954374Slars *s1++ = cur_chr; 6964374Slars } 6974374Slars break; 6984374Slars } 6994374Slars 7004374Slars if (sending) 7014374Slars *s1++ = '\\'; 7024374Slars *s1++ = cur_chr; 7034374Slars break; 7044374Slars } 7054374Slars } 7064374Slars 7074374Slars if (add_return) 7084374Slars *s1++ = '\r'; 7094374Slars 7104374Slars *s1++ = '\0'; /* guarantee closure */ 7114374Slars *s1++ = '\0'; /* terminate the string */ 7124374Slars return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ 7134374Slars } 7144374Slars 7154374Slars/* 7164374Slars * Process the expect string 7174374Slars */ 7184374Slarsvoid chat_expect(s) 7194374Slarsregister char *s; 7204374Slars { 7214374Slars if (strcmp(s, "ABORT") == 0) 7224374Slars { 7234374Slars ++abort_next; 7244374Slars return; 7254374Slars } 7264374Slars 7274374Slars if (strcmp(s, "TIMEOUT") == 0) 7284374Slars { 7294374Slars ++timeout_next; 7304374Slars return; 7314374Slars } 7324374Slars 7334374Slars while (*s) 7344374Slars { 7354374Slars register char *hyphen; 7364374Slars 7374374Slars for (hyphen = s; *hyphen; ++hyphen) 7384374Slars if (*hyphen == '-') 7394374Slars if (hyphen == s || hyphen[-1] != '\\') 7404374Slars break; 7414374Slars 7424374Slars if (*hyphen == '-') 7434374Slars { 7444374Slars *hyphen = '\0'; 7454374Slars 7464374Slars if (get_string(s)) 7474374Slars return; 7484374Slars else 7494374Slars { 7504374Slars s = hyphen + 1; 7514374Slars 7524374Slars for (hyphen = s; *hyphen; ++hyphen) 7534374Slars if (*hyphen == '-') 7544374Slars if (hyphen == s || hyphen[-1] != '\\') 7554374Slars break; 7564374Slars 7574374Slars if (*hyphen == '-') 7584374Slars { 7594374Slars *hyphen = '\0'; 7604374Slars 7614374Slars chat_send(s); 7624374Slars s = hyphen + 1; 7634374Slars } 7644374Slars else 7654374Slars { 7664374Slars chat_send(s); 7674374Slars return; 7684374Slars } 7694374Slars } 7704374Slars } 7714374Slars else 7724374Slars if (get_string(s)) 7734374Slars return; 7744374Slars else 7754374Slars { 7764374Slars if (fail_reason) 7774374Slars syslog(LOG_INFO, "Failed (%s)", fail_reason); 7784374Slars else 7794374Slars syslog(LOG_INFO, "Failed"); 7804374Slars 7814374Slars unlock(); 7824374Slars terminate(1); 7834374Slars } 7844374Slars } 7854374Slars } 7864374Slars 7874374Slarschar *character(c) 7884374Slarschar c; 7894374Slars { 7904374Slars static char string[10]; 7914374Slars char *meta; 7924374Slars 7934374Slars meta = (c & 0x80) ? "M-" : ""; 7944374Slars c &= 0x7F; 7954374Slars 7964374Slars if (c < 32) 7974374Slars sprintf(string, "%s^%c", meta, (int)c + '@'); 7984374Slars else 7994374Slars if (c == 127) 8004374Slars sprintf(string, "%s^?", meta); 8014374Slars else 8024374Slars sprintf(string, "%s%c", meta, c); 8034374Slars 8044374Slars return (string); 8054374Slars } 8064374Slars 8074374Slars/* 8084374Slars * process the reply string 8094374Slars */ 8104374Slarsvoid chat_send (s) 8114374Slarsregister char *s; 8124374Slars { 8134374Slars if (abort_next) 8144374Slars { 8154374Slars char *s1; 8164374Slars 8174374Slars abort_next = 0; 8184374Slars 8194374Slars if (n_aborts >= MAX_ABORTS) 8204374Slars fatal("Too many ABORT strings"); 8214374Slars 8224374Slars s1 = clean(s, 0); 8234374Slars 8244374Slars if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) 8254374Slars { 8264374Slars syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); 8274374Slars die(); 8284374Slars } 8294374Slars 8304374Slars abort_string[n_aborts++] = s1; 8314374Slars 8324374Slars if (verbose) 8334374Slars { 8344374Slars logf("abort on ("); 8354374Slars 8364374Slars for (s1 = s; *s1; ++s1) 8374374Slars logf(character(*s1)); 8384374Slars 8394374Slars logf(")\n"); 8404374Slars } 8414374Slars } 8424374Slars else 8434374Slars if (timeout_next) 8444374Slars { 8454374Slars timeout_next = 0; 8464374Slars timeout = atoi(s); 8474374Slars 8484374Slars if (timeout <= 0) 8494374Slars timeout = DEFAULT_CHAT_TIMEOUT; 8504374Slars 8514374Slars if (verbose) 8524374Slars { 8534374Slars syslog(LOG_INFO, "timeout set to %d seconds", timeout); 8544374Slars } 8554374Slars } 8564374Slars else 8574374Slars { 8584374Slars if (strcmp(s, "EOT") == 0) 8594374Slars s = "^D\\c"; 8604374Slars else 8614374Slars if (strcmp(s, "BREAK") == 0) 8624374Slars s = "\\K\\c"; 8634374Slars if ( ! put_string(s)) 8644374Slars { 8654374Slars syslog(LOG_INFO, "Failed"); 8664374Slars unlock(); 8674374Slars terminate(1); 8684374Slars } 8694374Slars } 8704374Slars } 8714374Slars 8724374Slarsint get_char() 8734374Slars { 8744374Slars int status; 8754374Slars char c; 8764374Slars 8774374Slars status = read(0, &c, 1); 8784374Slars 8794374Slars switch (status) 8804374Slars { 8814374Slars case 1: 8824374Slars return ((int)c & 0x7F); 8834374Slars 8844374Slars default: 8854374Slars syslog(LOG_WARNING, "warning: read() on stdin returned %d", 8864374Slars status); 8874374Slars 8884374Slars case -1: 8894374Slars if ((status = fcntl(0, F_GETFL, 0)) == -1) 8904374Slars sysfatal("Can't get file mode flags on stdin"); 8914374Slars else 8924374Slars if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) 8934374Slars sysfatal("Can't set file mode flags on stdin"); 8944374Slars 8954374Slars return (-1); 8964374Slars } 8974374Slars } 8984374Slars 8994374Slarsint put_char(c) 9004374Slarschar c; 9014374Slars { 9024374Slars int status; 9034374Slars 9044374Slars delay(); 9054374Slars 9064374Slars status = write(1, &c, 1); 9074374Slars 9084374Slars switch (status) 9094374Slars { 9104374Slars case 1: 9114374Slars return (0); 9124374Slars 9134374Slars default: 9144374Slars syslog(LOG_WARNING, "warning: write() on stdout returned %d", 9154374Slars status); 9164374Slars 9174374Slars case -1: 9184374Slars if ((status = fcntl(0, F_GETFL, 0)) == -1) 9194374Slars sysfatal("Can't get file mode flags on stdin"); 9204374Slars else 9214374Slars if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) 9224374Slars sysfatal("Can't set file mode flags on stdin"); 9234374Slars 9244374Slars return (-1); 9254374Slars } 9264374Slars } 9274374Slars 9284374Slarsint write_char (c) 9294374Slarsint c; 9304374Slars { 9314374Slars if (alarmed || put_char(c) < 0) 9324374Slars { 9334374Slars extern int errno; 9344374Slars 9354374Slars alarm(0); alarmed = 0; 9364374Slars 9374374Slars if (verbose) 9384374Slars { 9394374Slars if (errno == EINTR || errno == EWOULDBLOCK) 9404374Slars syslog(LOG_INFO, " -- write timed out"); 9414374Slars else 9424374Slars syslog(LOG_INFO, " -- write failed: %m"); 9434374Slars } 9444374Slars return (0); 9454374Slars } 9464374Slars return (1); 9474374Slars } 9484374Slars 9494374Slarsint put_string (s) 9504374Slarsregister char *s; 9514374Slars { 9524374Slars s = clean(s, 1); 9534374Slars 9544374Slars if (verbose) 9554374Slars { 9564374Slars logf("send ("); 9574374Slars 9584374Slars if (quiet) 9594374Slars logf("??????"); 9604374Slars else 9614374Slars { 9624374Slars register char *s1 = s; 9634374Slars 9644374Slars for (s1 = s; *s1; ++s1) 9654374Slars logf(character(*s1)); 9664374Slars } 9674374Slars 9684374Slars logf(")\n"); 9694374Slars } 9704374Slars 9714374Slars alarm(timeout); alarmed = 0; 9724374Slars 9734374Slars while (*s) 9744374Slars { 9754374Slars register char c = *s++; 9764374Slars 9774374Slars if (c != '\\') 9784374Slars { 9794374Slars if (!write_char (c)) 9804374Slars return 0; 9814374Slars continue; 9824374Slars } 9834374Slars 9844374Slars c = *s++; 9854374Slars switch (c) 9864374Slars { 9874374Slars case 'd': 9884374Slars sleep(1); 9894374Slars break; 9904374Slars 9914374Slars case 'K': 9924374Slars break_sequence(); 9934374Slars break; 9944374Slars 9954374Slars case 'p': 9964374Slars usleep(10000); /* 1/100th of a second. */ 9974374Slars break; 9984374Slars 9994374Slars default: 10004374Slars if (!write_char (c)) 10014374Slars return 0; 10024374Slars break; 10034374Slars } 10044374Slars } 10054374Slars 10064374Slars alarm(0); 10074374Slars alarmed = 0; 10084374Slars return (1); 10094374Slars } 10104374Slars 10114374Slars/* 10124374Slars * 'Wait for' this string to appear on this file descriptor. 10134374Slars */ 10144374Slarsint get_string(string) 10154374Slarsregister char *string; 10164374Slars { 10174374Slars char temp[STR_LEN]; 10184374Slars int c, printed = 0, len, minlen; 10194374Slars register char *s = temp, *end = s + STR_LEN; 10204374Slars 10214374Slars fail_reason = (char *)0; 10224374Slars string = clean(string, 0); 10234374Slars len = strlen(string); 10244374Slars minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; 10254374Slars 10264374Slars if (verbose) 10274374Slars { 10284374Slars register char *s1; 10294374Slars 10304374Slars logf("expect ("); 10314374Slars 10324374Slars for (s1 = string; *s1; ++s1) 10334374Slars logf(character(*s1)); 10344374Slars 10354374Slars logf(")\n"); 10364374Slars } 10374374Slars 10384374Slars if (len > STR_LEN) 10394374Slars { 10404374Slars syslog(LOG_INFO, "expect string is too long"); 10414374Slars return 0; 10424374Slars } 10434374Slars 10444374Slars if (len == 0) 10454374Slars { 10464374Slars if (verbose) 10474374Slars { 10484374Slars syslog(LOG_INFO, "got it"); 10494374Slars } 10504374Slars 10514374Slars return (1); 10524374Slars } 10534374Slars 10544374Slars alarm(timeout); alarmed = 0; 10554374Slars 10564374Slars while ( ! alarmed && (c = get_char()) >= 0) 10574374Slars { 10584374Slars int n, abort_len; 10594374Slars 10604374Slars if (verbose) 10614374Slars { 10624374Slars if (c == '\n') 10634374Slars logf("\n"); 10644374Slars else 10654374Slars logf(character(c)); 10664374Slars } 10674374Slars 10684374Slars *s++ = c; 10694374Slars 10704374Slars if (s - temp >= len && 10714374Slars c == string[len - 1] && 10724374Slars strncmp(s - len, string, len) == 0) 10734374Slars { 10744374Slars if (verbose) 10754374Slars { 10764374Slars logf(" -- got it\n"); 10774374Slars } 10784374Slars 10794374Slars alarm(0); alarmed = 0; 10804374Slars return (1); 10814374Slars } 10824374Slars 10834374Slars for (n = 0; n < n_aborts; ++n) 10844374Slars if (s - temp >= (abort_len = strlen(abort_string[n])) && 10854374Slars strncmp(s - abort_len, abort_string[n], abort_len) == 0) 10864374Slars { 10874374Slars if (verbose) 10884374Slars { 10894374Slars logf(" -- failed\n"); 10904374Slars } 10914374Slars 10924374Slars alarm(0); alarmed = 0; 10934374Slars strcpy(fail_reason = fail_buffer, abort_string[n]); 10944374Slars return (0); 10954374Slars } 10964374Slars 10974374Slars if (s >= end) 10984374Slars { 10994374Slars strncpy(temp, s - minlen, minlen); 11004374Slars s = temp + minlen; 11014374Slars } 11024374Slars 11034374Slars if (alarmed && verbose) 11044374Slars syslog(LOG_WARNING, "warning: alarm synchronization problem"); 11054374Slars } 11064374Slars 11074374Slars alarm(0); 11084374Slars 11094374Slars if (verbose && printed) 11104374Slars { 11114374Slars if (alarmed) 11124374Slars logf(" -- read timed out\n"); 11134374Slars else 11144374Slars { 11154374Slars logflush(); 11164374Slars syslog(LOG_INFO, " -- read failed: %m"); 11174374Slars } 11184374Slars } 11194374Slars 11204374Slars alarmed = 0; 11214374Slars return (0); 11224374Slars } 11234374Slars 11244374Slars#ifdef ultrix 11254374Slars#undef NO_USLEEP 11264374Slars#include <sys/types.h> 11274374Slars#include <sys/time.h> 11284374Slars 11294374Slars/* 11304374Slars usleep -- support routine for 4.2BSD system call emulations 11314374Slars last edit: 29-Oct-1984 D A Gwyn 11324374Slars */ 11334374Slars 11344374Slarsextern int select(); 11354374Slars 11364374Slarsint 11374374Slarsusleep( usec ) /* returns 0 if ok, else -1 */ 11384374Slars long usec; /* delay in microseconds */ 11394374Slars{ 11404374Slars static struct /* `timeval' */ 11414374Slars { 11424374Slars long tv_sec; /* seconds */ 11434374Slars long tv_usec; /* microsecs */ 11444374Slars } delay; /* _select() timeout */ 11454374Slars 11464374Slars delay.tv_sec = usec / 1000000L; 11474374Slars delay.tv_usec = usec % 1000000L; 11484374Slars 11494374Slars return select( 0, (long *)0, (long *)0, (long *)0, &delay ); 11504374Slars} 11514374Slars#endif 11524374Slars 11534374Slars/* 11544374Slars * Delay an amount appropriate for between typed characters. 11554374Slars */ 11564374Slarsvoid delay() 11574374Slars { 11584374Slars# ifdef NO_USLEEP 11594374Slars register int i; 11604374Slars 11614374Slars for (i = 0; i < 30000; ++i) /* ... did we just say appropriate? */ 11624374Slars ; 11634374Slars# else /* NO_USLEEP */ 11644374Slars usleep(100); 11654374Slars# endif /* NO_USLEEP */ 11664374Slars } 1167