1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com). 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Chat -- a program for automatic session establishment (i.e. dial 9af57ed9fSAtsushi Murai * the phone and log in). 10af57ed9fSAtsushi Murai * 11af57ed9fSAtsushi Murai * This software is in the public domain. 12af57ed9fSAtsushi Murai * 13af57ed9fSAtsushi Murai * Please send all bug reports, requests for information, etc. to: 14af57ed9fSAtsushi Murai * 15af57ed9fSAtsushi Murai * Karl Fox <karl@MorningStar.Com> 16af57ed9fSAtsushi Murai * Morning Star Technologies, Inc. 17af57ed9fSAtsushi Murai * 1760 Zollinger Road 18af57ed9fSAtsushi Murai * Columbus, OH 43221 19af57ed9fSAtsushi Murai * (614)451-1883 20af57ed9fSAtsushi Murai * 21274e766cSBrian Somers * $Id: chat.c,v 1.23 1997/05/07 23:01:23 brian Exp $ 22af57ed9fSAtsushi Murai * 23af57ed9fSAtsushi Murai * TODO: 24af57ed9fSAtsushi Murai * o Support more UUCP compatible control sequences. 25af57ed9fSAtsushi Murai * o Dialing shoud not block monitor process. 2684b8a6ebSAtsushi Murai * o Reading modem by select should be unified into main.c 27af57ed9fSAtsushi Murai */ 28af57ed9fSAtsushi Murai #include "defs.h" 29af57ed9fSAtsushi Murai #include <ctype.h> 30af57ed9fSAtsushi Murai #include <sys/uio.h> 31af57ed9fSAtsushi Murai #ifndef isblank 32af57ed9fSAtsushi Murai #define isblank(c) ((c) == '\t' || (c) == ' ') 33af57ed9fSAtsushi Murai #endif 34af57ed9fSAtsushi Murai #include <sys/time.h> 35af57ed9fSAtsushi Murai #include <fcntl.h> 3653c9f6c0SAtsushi Murai #include <errno.h> 37c3b6ad66SBrian Somers #include <signal.h> 3853c9f6c0SAtsushi Murai #include <sys/wait.h> 39af57ed9fSAtsushi Murai #include "timeout.h" 40af57ed9fSAtsushi Murai #include "vars.h" 41274e766cSBrian Somers #include "chat.h" 42f5ff0f7cSBrian Somers #include "sig.h" 43e68d210eSBrian Somers #include "chat.h" 44af57ed9fSAtsushi Murai 4553c9f6c0SAtsushi Murai #define IBSIZE 200 4653c9f6c0SAtsushi Murai 47af57ed9fSAtsushi Murai static int TimeoutSec; 48af57ed9fSAtsushi Murai static int abort_next, timeout_next; 49af57ed9fSAtsushi Murai static int numaborts; 50af57ed9fSAtsushi Murai char *AbortStrings[50]; 5181cc95f2SAndrey A. Chernov char inbuff[IBSIZE*2+1]; 52af57ed9fSAtsushi Murai 53af57ed9fSAtsushi Murai extern int ChangeParity(char *); 54af57ed9fSAtsushi Murai 55af57ed9fSAtsushi Murai #define MATCH 1 56af57ed9fSAtsushi Murai #define NOMATCH 0 57af57ed9fSAtsushi Murai #define ABORT -1 58af57ed9fSAtsushi Murai 59af57ed9fSAtsushi Murai static char * 60af57ed9fSAtsushi Murai findblank(p, instring) 61af57ed9fSAtsushi Murai char *p; 62af57ed9fSAtsushi Murai int instring; 63af57ed9fSAtsushi Murai { 64af57ed9fSAtsushi Murai if (instring) { 65af57ed9fSAtsushi Murai while (*p) { 66af57ed9fSAtsushi Murai if (*p == '\\') { 67af57ed9fSAtsushi Murai strcpy(p, p + 1); 68af57ed9fSAtsushi Murai if (!*p) 69af57ed9fSAtsushi Murai break; 70af57ed9fSAtsushi Murai } else if (*p == '"') 71af57ed9fSAtsushi Murai return(p); 72af57ed9fSAtsushi Murai p++; 73af57ed9fSAtsushi Murai } 74af57ed9fSAtsushi Murai } else { 75af57ed9fSAtsushi Murai while (*p) { 76af57ed9fSAtsushi Murai if (isblank(*p)) 77af57ed9fSAtsushi Murai return(p); 78af57ed9fSAtsushi Murai p++; 79af57ed9fSAtsushi Murai } 80af57ed9fSAtsushi Murai } 81af57ed9fSAtsushi Murai return p; 82af57ed9fSAtsushi Murai } 83af57ed9fSAtsushi Murai 84af57ed9fSAtsushi Murai int 85e68d210eSBrian Somers MakeArgs(script, pvect, maxargs) 86af57ed9fSAtsushi Murai char *script; 87af57ed9fSAtsushi Murai char **pvect; 88e68d210eSBrian Somers int maxargs; 89af57ed9fSAtsushi Murai { 90af57ed9fSAtsushi Murai int nargs, nb; 91af57ed9fSAtsushi Murai int instring; 92af57ed9fSAtsushi Murai 93af57ed9fSAtsushi Murai nargs = 0; 94af57ed9fSAtsushi Murai while (*script) { 95af57ed9fSAtsushi Murai nb = strspn(script, " \t"); 96af57ed9fSAtsushi Murai script += nb; 97af57ed9fSAtsushi Murai if (*script) { 98af57ed9fSAtsushi Murai if (*script == '"') { 99af57ed9fSAtsushi Murai instring = 1; 100af57ed9fSAtsushi Murai script++; 101af57ed9fSAtsushi Murai if (*script == '\0') 102e68d210eSBrian Somers break; /* Shouldn't return here. Need to null terminate below */ 103af57ed9fSAtsushi Murai } else 104af57ed9fSAtsushi Murai instring = 0; 105e68d210eSBrian Somers if (nargs >= maxargs-1) 106e68d210eSBrian Somers break; 107af57ed9fSAtsushi Murai *pvect++ = script; 108af57ed9fSAtsushi Murai nargs++; 109af57ed9fSAtsushi Murai script = findblank(script, instring); 110af57ed9fSAtsushi Murai if (*script) 111af57ed9fSAtsushi Murai *script++ = '\0'; 112af57ed9fSAtsushi Murai } 113af57ed9fSAtsushi Murai } 114af57ed9fSAtsushi Murai *pvect = NULL; 115af57ed9fSAtsushi Murai return nargs; 116af57ed9fSAtsushi Murai } 117af57ed9fSAtsushi Murai 118af57ed9fSAtsushi Murai /* 11999c02d39SWarner Losh * \c don't add a cr 12099c02d39SWarner Losh * \d Sleep a little (delay 2 seconds 12199c02d39SWarner Losh * \n Line feed character 12299c02d39SWarner Losh * \P Auth Key password 12399c02d39SWarner Losh * \p pause 0.25 sec 124af57ed9fSAtsushi Murai * \r Carrige return character 125af57ed9fSAtsushi Murai * \s Space character 1261dff3fc5SAndrey A. Chernov * \T Telephone number(s) (defined via `set phone') 127af57ed9fSAtsushi Murai * \t Tab character 12899c02d39SWarner Losh * \U Auth User 129af57ed9fSAtsushi Murai */ 130af57ed9fSAtsushi Murai char * 13199c02d39SWarner Losh ExpandString(str, result, reslen, sendmode) 132af57ed9fSAtsushi Murai char *str; 133af57ed9fSAtsushi Murai char *result; 13499c02d39SWarner Losh int reslen; 135af57ed9fSAtsushi Murai int sendmode; 136af57ed9fSAtsushi Murai { 137af57ed9fSAtsushi Murai int addcr = 0; 1381dff3fc5SAndrey A. Chernov char *phone; 139af57ed9fSAtsushi Murai 14099c02d39SWarner Losh result[--reslen] = '\0'; 141af57ed9fSAtsushi Murai if (sendmode) 142af57ed9fSAtsushi Murai addcr = 1; 14399c02d39SWarner Losh while (*str && reslen > 0) { 144af57ed9fSAtsushi Murai switch (*str) { 145af57ed9fSAtsushi Murai case '\\': 146af57ed9fSAtsushi Murai str++; 147af57ed9fSAtsushi Murai switch (*str) { 148af57ed9fSAtsushi Murai case 'c': 149af57ed9fSAtsushi Murai if (sendmode) 150af57ed9fSAtsushi Murai addcr = 0; 151af57ed9fSAtsushi Murai break; 152af57ed9fSAtsushi Murai case 'd': /* Delay 2 seconds */ 153af57ed9fSAtsushi Murai sleep(2); break; 154af57ed9fSAtsushi Murai case 'p': 155af57ed9fSAtsushi Murai usleep(250000); break; /* Pause 0.25 sec */ 156af57ed9fSAtsushi Murai case 'n': 15799c02d39SWarner Losh *result++ = '\n'; reslen--; break; 158af57ed9fSAtsushi Murai case 'r': 15999c02d39SWarner Losh *result++ = '\r'; reslen--; break; 160af57ed9fSAtsushi Murai case 's': 16199c02d39SWarner Losh *result++ = ' '; reslen--; break; 162af57ed9fSAtsushi Murai case 't': 16399c02d39SWarner Losh *result++ = '\t'; reslen--; break; 164af57ed9fSAtsushi Murai case 'P': 16599c02d39SWarner Losh strncpy(result, VarAuthKey, reslen); 16699c02d39SWarner Losh reslen -= strlen(result); 16799c02d39SWarner Losh result += strlen(result); 168af57ed9fSAtsushi Murai break; 169af57ed9fSAtsushi Murai case 'T': 170a81c9c68SAndrey A. Chernov if (VarNextPhone == NULL) { 171a81c9c68SAndrey A. Chernov strcpy(VarPhoneCopy, VarPhoneList); 172a81c9c68SAndrey A. Chernov VarNextPhone = VarPhoneCopy; 173a81c9c68SAndrey A. Chernov } 1741dff3fc5SAndrey A. Chernov phone = strsep(&VarNextPhone, ":"); 17599c02d39SWarner Losh strncpy(result, phone, reslen); 17699c02d39SWarner Losh reslen -= strlen(result); 17799c02d39SWarner Losh result += strlen(result); 1781dff3fc5SAndrey A. Chernov if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) 1791dff3fc5SAndrey A. Chernov fprintf(stderr, "Phone: %s\n", phone); 1809c749ffbSPoul-Henning Kamp LogPrintf(LOG_PHASE_BIT, "Phone: %s\n", phone); 181af57ed9fSAtsushi Murai break; 182af57ed9fSAtsushi Murai case 'U': 18399c02d39SWarner Losh strncpy(result, VarAuthName, reslen); 18499c02d39SWarner Losh reslen -= strlen(result); 18599c02d39SWarner Losh result += strlen(result); 186af57ed9fSAtsushi Murai break; 187af57ed9fSAtsushi Murai default: 18899c02d39SWarner Losh reslen--; 18999c02d39SWarner Losh *result++ = *str; 19099c02d39SWarner Losh break; 191af57ed9fSAtsushi Murai } 19299c02d39SWarner Losh if (*str) 19399c02d39SWarner Losh str++; 194af57ed9fSAtsushi Murai break; 195af57ed9fSAtsushi Murai case '^': 196af57ed9fSAtsushi Murai str++; 19799c02d39SWarner Losh if (*str) { 198af57ed9fSAtsushi Murai *result++ = *str++ & 0x1f; 19999c02d39SWarner Losh reslen--; 20099c02d39SWarner Losh } 201af57ed9fSAtsushi Murai break; 202af57ed9fSAtsushi Murai default: 203af57ed9fSAtsushi Murai *result++ = *str++; 20499c02d39SWarner Losh reslen--; 205af57ed9fSAtsushi Murai break; 206af57ed9fSAtsushi Murai } 207af57ed9fSAtsushi Murai } 20899c02d39SWarner Losh if (--reslen > 0) { 209af57ed9fSAtsushi Murai if (addcr) 210af57ed9fSAtsushi Murai *result++ = '\r'; 21199c02d39SWarner Losh } 21299c02d39SWarner Losh if (--reslen > 0) 213af57ed9fSAtsushi Murai *result++ = '\0'; 214af57ed9fSAtsushi Murai return(result); 215af57ed9fSAtsushi Murai } 216af57ed9fSAtsushi Murai 2179c749ffbSPoul-Henning Kamp #define MAXLOGBUFF 200 2189c749ffbSPoul-Henning Kamp static char logbuff[MAXLOGBUFF]; 2199c749ffbSPoul-Henning Kamp static int loglen = 0; 2209c749ffbSPoul-Henning Kamp 2219c749ffbSPoul-Henning Kamp static void clear_log() { 2229c749ffbSPoul-Henning Kamp memset(logbuff,0,MAXLOGBUFF); 2239c749ffbSPoul-Henning Kamp loglen = 0; 2249c749ffbSPoul-Henning Kamp } 2259c749ffbSPoul-Henning Kamp 2269c749ffbSPoul-Henning Kamp static void flush_log() { 2279c749ffbSPoul-Henning Kamp if ((loglevel & LOG_CONNECT_BIT) 2289c749ffbSPoul-Henning Kamp || ((loglevel & LOG_CARRIER_BIT) 2299c749ffbSPoul-Henning Kamp && strstr(logbuff,"CARRIER"))) { 2309c749ffbSPoul-Henning Kamp LogPrintf(LOG_CONNECT_BIT|LOG_CARRIER_BIT,"Chat: %s\n",logbuff); 2319c749ffbSPoul-Henning Kamp } 2329c749ffbSPoul-Henning Kamp clear_log(); 2339c749ffbSPoul-Henning Kamp } 2349c749ffbSPoul-Henning Kamp 2359c749ffbSPoul-Henning Kamp static void connect_log(char *str, int single_p) { 2369c749ffbSPoul-Henning Kamp int space = MAXLOGBUFF - loglen - 1; 2379c749ffbSPoul-Henning Kamp 2389c749ffbSPoul-Henning Kamp while (space--) { 2399c749ffbSPoul-Henning Kamp if (*str == '\n') { 2409c749ffbSPoul-Henning Kamp flush_log(); 2419c749ffbSPoul-Henning Kamp } else { 2429c749ffbSPoul-Henning Kamp logbuff[loglen++] = *str; 2439c749ffbSPoul-Henning Kamp } 2449c749ffbSPoul-Henning Kamp if (single_p || !*++str) break; 2459c749ffbSPoul-Henning Kamp } 2469c749ffbSPoul-Henning Kamp if (!space) flush_log(); 2479c749ffbSPoul-Henning Kamp } 2489c749ffbSPoul-Henning Kamp 2499c749ffbSPoul-Henning Kamp 2509c749ffbSPoul-Henning Kamp 251af57ed9fSAtsushi Murai int 252af57ed9fSAtsushi Murai WaitforString(estr) 253af57ed9fSAtsushi Murai char *estr; 254af57ed9fSAtsushi Murai { 255af57ed9fSAtsushi Murai struct timeval timeout; 256af57ed9fSAtsushi Murai char *s, *str, ch; 257af57ed9fSAtsushi Murai char *inp; 258af57ed9fSAtsushi Murai fd_set rfds; 259274e766cSBrian Somers int i, nfds, nb; 260274e766cSBrian Somers char buff[IBSIZE]; 261af57ed9fSAtsushi Murai 2629c749ffbSPoul-Henning Kamp 26353c9f6c0SAtsushi Murai #ifdef SIGALRM 26453c9f6c0SAtsushi Murai int omask; 26553c9f6c0SAtsushi Murai omask = sigblock(sigmask(SIGALRM)); 26653c9f6c0SAtsushi Murai #endif 2679c749ffbSPoul-Henning Kamp clear_log(); 26899c02d39SWarner Losh (void) ExpandString(estr, buff, sizeof(buff), 0); 2699c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff); 270af57ed9fSAtsushi Murai str = buff; 271af57ed9fSAtsushi Murai inp = inbuff; 272af57ed9fSAtsushi Murai 27381cc95f2SAndrey A. Chernov if (strlen(str)>=IBSIZE){ 274274e766cSBrian Somers str[IBSIZE-1]=0; 2759c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "Truncating String to %d character: %s\n", IBSIZE, str); 27681cc95f2SAndrey A. Chernov } 27781cc95f2SAndrey A. Chernov 278af57ed9fSAtsushi Murai nfds = modem + 1; 279af57ed9fSAtsushi Murai s = str; 280af57ed9fSAtsushi Murai for (;;) { 281af57ed9fSAtsushi Murai FD_ZERO(&rfds); 282af57ed9fSAtsushi Murai FD_SET(modem, &rfds); 283af57ed9fSAtsushi Murai /* 284af57ed9fSAtsushi Murai * Because it is not clear whether select() modifies timeout value, 285af57ed9fSAtsushi Murai * it is better to initialize timeout values everytime. 286af57ed9fSAtsushi Murai */ 287af57ed9fSAtsushi Murai timeout.tv_sec = TimeoutSec; 288af57ed9fSAtsushi Murai timeout.tv_usec = 0; 289af57ed9fSAtsushi Murai i = select(nfds, &rfds, NULL, NULL, &timeout); 290af57ed9fSAtsushi Murai #ifdef notdef 291af57ed9fSAtsushi Murai TimerService(); 292af57ed9fSAtsushi Murai #endif 293af57ed9fSAtsushi Murai if (i < 0) { 29453c9f6c0SAtsushi Murai #ifdef SIGALRM 29553c9f6c0SAtsushi Murai if (errno == EINTR) 29653c9f6c0SAtsushi Murai continue; 29753c9f6c0SAtsushi Murai sigsetmask(omask); 29853c9f6c0SAtsushi Murai #endif 299af57ed9fSAtsushi Murai perror("select"); 30053c9f6c0SAtsushi Murai *inp = 0; 301af57ed9fSAtsushi Murai return(NOMATCH); 302af57ed9fSAtsushi Murai } else if (i == 0) { /* Timeout reached! */ 30353c9f6c0SAtsushi Murai *inp = 0; 30453c9f6c0SAtsushi Murai if (inp != inbuff) 3059c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "got: %s\n", inbuff); 3069c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "can't get (%d).\n", timeout.tv_sec); 30753c9f6c0SAtsushi Murai #ifdef SIGALRM 30853c9f6c0SAtsushi Murai sigsetmask(omask); 30953c9f6c0SAtsushi Murai #endif 310af57ed9fSAtsushi Murai return(NOMATCH); 311af57ed9fSAtsushi Murai } 312af57ed9fSAtsushi Murai if (FD_ISSET(modem, &rfds)) { /* got something */ 31353c9f6c0SAtsushi Murai if (DEV_IS_SYNC) { 31481cc95f2SAndrey A. Chernov int length; 31581cc95f2SAndrey A. Chernov if ((length=strlen(inbuff))>IBSIZE){ 31681cc95f2SAndrey A. Chernov bcopy(&(inbuff[IBSIZE]),inbuff,IBSIZE+1); /* shuffle down next part*/ 31781cc95f2SAndrey A. Chernov length=strlen(inbuff); 31881cc95f2SAndrey A. Chernov } 31981cc95f2SAndrey A. Chernov nb = read(modem, &(inbuff[length]), IBSIZE); 32081cc95f2SAndrey A. Chernov inbuff[nb + length] = 0; 3219c749ffbSPoul-Henning Kamp connect_log(inbuff,0); 32253c9f6c0SAtsushi Murai if (strstr(inbuff, str)) { 32353c9f6c0SAtsushi Murai #ifdef SIGALRM 32453c9f6c0SAtsushi Murai sigsetmask(omask); 32553c9f6c0SAtsushi Murai #endif 3269c749ffbSPoul-Henning Kamp flush_log(); 32753c9f6c0SAtsushi Murai return(MATCH); 32853c9f6c0SAtsushi Murai } 32953c9f6c0SAtsushi Murai for (i = 0; i < numaborts; i++) { 33053c9f6c0SAtsushi Murai if (strstr(inbuff, AbortStrings[i])) { 3319c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "Abort: %s\n", AbortStrings[i]); 33253c9f6c0SAtsushi Murai #ifdef SIGALRM 33353c9f6c0SAtsushi Murai sigsetmask(omask); 33453c9f6c0SAtsushi Murai #endif 3359c749ffbSPoul-Henning Kamp flush_log(); 33653c9f6c0SAtsushi Murai return(ABORT); 33753c9f6c0SAtsushi Murai } 33853c9f6c0SAtsushi Murai } 33953c9f6c0SAtsushi Murai } else { 340274e766cSBrian Somers if (read(modem, &ch, 1) < 0) { 341274e766cSBrian Somers perror("read error"); 342274e766cSBrian Somers *inp = '\0'; 343274e766cSBrian Somers return(NOMATCH); 344274e766cSBrian Somers } 3459c749ffbSPoul-Henning Kamp connect_log(&ch,1); 346af57ed9fSAtsushi Murai *inp++ = ch; 347af57ed9fSAtsushi Murai if (ch == *s) { 348af57ed9fSAtsushi Murai s++; 349af57ed9fSAtsushi Murai if (*s == '\0') { 35053c9f6c0SAtsushi Murai #ifdef SIGALRM 35153c9f6c0SAtsushi Murai sigsetmask(omask); 35253c9f6c0SAtsushi Murai #endif 35353c9f6c0SAtsushi Murai *inp = 0; 3549c749ffbSPoul-Henning Kamp flush_log(); 355af57ed9fSAtsushi Murai return(MATCH); 356af57ed9fSAtsushi Murai } 357af57ed9fSAtsushi Murai } else { 358af57ed9fSAtsushi Murai s = str; 359af57ed9fSAtsushi Murai if (inp == inbuff+ IBSIZE) { 360af57ed9fSAtsushi Murai bcopy(inp - 100, inbuff, 100); 361af57ed9fSAtsushi Murai inp = inbuff + 100; 362af57ed9fSAtsushi Murai } 363af57ed9fSAtsushi Murai for (i = 0; i < numaborts; i++) { /* Look for Abort strings */ 364af57ed9fSAtsushi Murai int len; 365af57ed9fSAtsushi Murai char *s1; 366af57ed9fSAtsushi Murai 367af57ed9fSAtsushi Murai s1 = AbortStrings[i]; 368af57ed9fSAtsushi Murai len = strlen(s1); 369af57ed9fSAtsushi Murai if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) { 3709c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "Abort: %s\n", s1); 37153c9f6c0SAtsushi Murai *inp = 0; 37253c9f6c0SAtsushi Murai #ifdef SIGALRM 37353c9f6c0SAtsushi Murai sigsetmask(omask); 37453c9f6c0SAtsushi Murai #endif 3759c749ffbSPoul-Henning Kamp flush_log(); 376af57ed9fSAtsushi Murai return(ABORT); 377af57ed9fSAtsushi Murai } 378af57ed9fSAtsushi Murai } 379af57ed9fSAtsushi Murai } 380af57ed9fSAtsushi Murai } 381af57ed9fSAtsushi Murai } 382af57ed9fSAtsushi Murai } 38353c9f6c0SAtsushi Murai } 38453c9f6c0SAtsushi Murai 38553c9f6c0SAtsushi Murai void 38653c9f6c0SAtsushi Murai ExecStr(command, out) 38753c9f6c0SAtsushi Murai char *command, *out; 38853c9f6c0SAtsushi Murai { 38953c9f6c0SAtsushi Murai int pid; 39053c9f6c0SAtsushi Murai int fids[2]; 39153c9f6c0SAtsushi Murai char *vector[20]; 39253c9f6c0SAtsushi Murai int stat, nb; 39353c9f6c0SAtsushi Murai char *cp; 39453c9f6c0SAtsushi Murai char tmp[300]; 39553c9f6c0SAtsushi Murai extern int errno; 39653c9f6c0SAtsushi Murai 39753c9f6c0SAtsushi Murai cp = inbuff + strlen(inbuff) - 1; 39853c9f6c0SAtsushi Murai while (cp > inbuff) { 39953c9f6c0SAtsushi Murai if (*cp < ' ' && *cp != '\t') { 40053c9f6c0SAtsushi Murai cp++; 40153c9f6c0SAtsushi Murai break; 40253c9f6c0SAtsushi Murai } 40353c9f6c0SAtsushi Murai cp--; 40453c9f6c0SAtsushi Murai } 405274e766cSBrian Somers if (snprintf(tmp, sizeof tmp, "%s %s", command, cp) >= sizeof tmp) { 406274e766cSBrian Somers LogPrintf(LOG_CHAT_BIT, "Too long string to ExecStr: \"%s\"\n", 407274e766cSBrian Somers command); 408274e766cSBrian Somers return; 409274e766cSBrian Somers } 410e68d210eSBrian Somers (void) MakeArgs(tmp, vector, VECSIZE(vector)); 41153c9f6c0SAtsushi Murai 412274e766cSBrian Somers if (pipe(fids) < 0) { 413274e766cSBrian Somers LogPrintf(LOG_CHAT_BIT, "Unable to create pipe in ExecStr: %s\n", 414274e766cSBrian Somers strerror(errno)); 415274e766cSBrian Somers return; 416274e766cSBrian Somers } 417274e766cSBrian Somers 41853c9f6c0SAtsushi Murai pid = fork(); 41953c9f6c0SAtsushi Murai if (pid == 0) { 420f5ff0f7cSBrian Somers TermTimerService(); 42106257ca4SAndrey A. Chernov signal(SIGINT, SIG_DFL); 42206257ca4SAndrey A. Chernov signal(SIGQUIT, SIG_DFL); 42306257ca4SAndrey A. Chernov signal(SIGTERM, SIG_DFL); 4240b6828d1SAndrey A. Chernov signal(SIGHUP, SIG_DFL); 425f5ff0f7cSBrian Somers signal(SIGALRM, SIG_DFL); 42653c9f6c0SAtsushi Murai close(fids[0]); 427274e766cSBrian Somers if (dup2(fids[1], 1) < 0) { 428274e766cSBrian Somers LogPrintf(LOG_CHAT_BIT, "dup2(fids[1], 1) in ExecStr: %s\n", 429274e766cSBrian Somers strerror(errno)); 430274e766cSBrian Somers return; 431274e766cSBrian Somers } 43253c9f6c0SAtsushi Murai close(fids[1]); 43353c9f6c0SAtsushi Murai nb = open("/dev/tty", O_RDWR); 434274e766cSBrian Somers if (dup2(nb, 0) < 0) { 435274e766cSBrian Somers LogPrintf(LOG_CHAT_BIT, "dup2(nb, 0) in ExecStr: %s\n", 436274e766cSBrian Somers strerror(errno)); 437274e766cSBrian Somers return; 438274e766cSBrian Somers } 4399c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "exec: %s\n", command); 440113dea91SAndrey A. Chernov /* switch back to original privileges */ 441113dea91SAndrey A. Chernov if (setgid(getgid()) < 0) { 442113dea91SAndrey A. Chernov LogPrintf(LOG_CHAT_BIT, "setgid: %s\n", strerror(errno)); 443113dea91SAndrey A. Chernov exit(1); 444113dea91SAndrey A. Chernov } 445113dea91SAndrey A. Chernov if (setuid(getuid()) < 0) { 446113dea91SAndrey A. Chernov LogPrintf(LOG_CHAT_BIT, "setuid: %s\n", strerror(errno)); 447113dea91SAndrey A. Chernov exit(1); 448113dea91SAndrey A. Chernov } 44953c9f6c0SAtsushi Murai pid = execvp(command, vector); 4509c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "execvp failed for (%d/%d): %s\n", pid, errno, command); 45153c9f6c0SAtsushi Murai exit(127); 45253c9f6c0SAtsushi Murai } else { 45353c9f6c0SAtsushi Murai close(fids[1]); 45453c9f6c0SAtsushi Murai for (;;) { 45553c9f6c0SAtsushi Murai nb = read(fids[0], out, 1); 45653c9f6c0SAtsushi Murai if (nb <= 0) 45753c9f6c0SAtsushi Murai break; 45853c9f6c0SAtsushi Murai out++; 45953c9f6c0SAtsushi Murai } 46053c9f6c0SAtsushi Murai *out = '\0'; 46153c9f6c0SAtsushi Murai close(fids[0]); 46253c9f6c0SAtsushi Murai close(fids[1]); 46353c9f6c0SAtsushi Murai waitpid(pid, &stat, WNOHANG); 46453c9f6c0SAtsushi Murai } 46553c9f6c0SAtsushi Murai } 466af57ed9fSAtsushi Murai 467af57ed9fSAtsushi Murai void 468af57ed9fSAtsushi Murai SendString(str) 469af57ed9fSAtsushi Murai char *str; 470af57ed9fSAtsushi Murai { 47153c9f6c0SAtsushi Murai char *cp; 472274e766cSBrian Somers int on; 473af57ed9fSAtsushi Murai char buff[200]; 474af57ed9fSAtsushi Murai 475af57ed9fSAtsushi Murai if (abort_next) { 476af57ed9fSAtsushi Murai abort_next = 0; 47799c02d39SWarner Losh ExpandString(str, buff, sizeof(buff), 0); 478af57ed9fSAtsushi Murai AbortStrings[numaborts++] = strdup(buff); 479af57ed9fSAtsushi Murai } else if (timeout_next) { 480af57ed9fSAtsushi Murai timeout_next = 0; 481af57ed9fSAtsushi Murai TimeoutSec = atoi(str); 482af57ed9fSAtsushi Murai if (TimeoutSec <= 0) 483af57ed9fSAtsushi Murai TimeoutSec = 30; 484af57ed9fSAtsushi Murai } else { 48553c9f6c0SAtsushi Murai if (*str == '!') { 48699c02d39SWarner Losh (void) ExpandString(str+1, buff+2, sizeof(buff)-2, 0); 48753c9f6c0SAtsushi Murai ExecStr(buff + 2, buff + 2); 48853c9f6c0SAtsushi Murai } else { 48999c02d39SWarner Losh (void) ExpandString(str, buff+2, sizeof(buff)-2, 1); 49053c9f6c0SAtsushi Murai } 491c3899f8dSAtsushi Murai if (strstr(str, "\\P")) { /* Do not log the password itself. */ 4929c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "sending: %s\n", str); 493c3899f8dSAtsushi Murai } else { 4949c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "sending: %s\n", buff+2); 495c3899f8dSAtsushi Murai } 49653c9f6c0SAtsushi Murai cp = buff; 49753c9f6c0SAtsushi Murai if (DEV_IS_SYNC) 49853c9f6c0SAtsushi Murai bcopy("\377\003", buff, 2); /* Prepend HDLC header */ 49953c9f6c0SAtsushi Murai else 50053c9f6c0SAtsushi Murai cp += 2; 50153c9f6c0SAtsushi Murai on = strlen(cp); 502274e766cSBrian Somers write(modem, cp, on); 503af57ed9fSAtsushi Murai } 504af57ed9fSAtsushi Murai } 505af57ed9fSAtsushi Murai 506af57ed9fSAtsushi Murai int 507af57ed9fSAtsushi Murai ExpectString(str) 508af57ed9fSAtsushi Murai char *str; 509af57ed9fSAtsushi Murai { 510af57ed9fSAtsushi Murai char *minus; 511af57ed9fSAtsushi Murai int state; 512af57ed9fSAtsushi Murai 513af57ed9fSAtsushi Murai if (strcmp(str, "ABORT") == 0) { 514af57ed9fSAtsushi Murai ++abort_next; 515af57ed9fSAtsushi Murai return(MATCH); 516af57ed9fSAtsushi Murai } 517af57ed9fSAtsushi Murai if (strcmp(str, "TIMEOUT") == 0) { 518af57ed9fSAtsushi Murai ++timeout_next; 519af57ed9fSAtsushi Murai return(MATCH); 520af57ed9fSAtsushi Murai } 5219c749ffbSPoul-Henning Kamp LogPrintf(LOG_CHAT_BIT, "Expecting %s\n", str); 522af57ed9fSAtsushi Murai while (*str) { 523af57ed9fSAtsushi Murai /* 524af57ed9fSAtsushi Murai * Check whether if string contains sub-send-expect. 525af57ed9fSAtsushi Murai */ 526af57ed9fSAtsushi Murai for (minus = str; *minus; minus++) { 527af57ed9fSAtsushi Murai if (*minus == '-') { 528af57ed9fSAtsushi Murai if (minus == str || minus[-1] != '\\') 529af57ed9fSAtsushi Murai break; 530af57ed9fSAtsushi Murai } 531af57ed9fSAtsushi Murai } 532af57ed9fSAtsushi Murai if (*minus == '-') { /* We have sub-send-expect. */ 533af57ed9fSAtsushi Murai *minus++ = '\0'; 534af57ed9fSAtsushi Murai state = WaitforString(str); 535af57ed9fSAtsushi Murai if (state != NOMATCH) 536af57ed9fSAtsushi Murai return(state); 537af57ed9fSAtsushi Murai /* 538af57ed9fSAtsushi Murai * Can't get expect string. Sendout send part. 539af57ed9fSAtsushi Murai */ 540af57ed9fSAtsushi Murai str = minus; 541af57ed9fSAtsushi Murai for (minus = str; *minus; minus++) { 542af57ed9fSAtsushi Murai if (*minus == '-') { 543af57ed9fSAtsushi Murai if (minus == str || minus[-1] != '\\') 544af57ed9fSAtsushi Murai break; 545af57ed9fSAtsushi Murai } 546af57ed9fSAtsushi Murai } 547af57ed9fSAtsushi Murai if (*minus == '-') { 548af57ed9fSAtsushi Murai *minus++ = '\0'; 549af57ed9fSAtsushi Murai SendString(str); 550af57ed9fSAtsushi Murai str = minus; 551af57ed9fSAtsushi Murai } else { 552af57ed9fSAtsushi Murai SendString(str); 553af57ed9fSAtsushi Murai return(MATCH); 554af57ed9fSAtsushi Murai } 555af57ed9fSAtsushi Murai } else { 556af57ed9fSAtsushi Murai /* 557af57ed9fSAtsushi Murai * Simple case. Wait for string. 558af57ed9fSAtsushi Murai */ 559af57ed9fSAtsushi Murai return(WaitforString(str)); 560af57ed9fSAtsushi Murai } 561af57ed9fSAtsushi Murai } 562af57ed9fSAtsushi Murai return(MATCH); 563af57ed9fSAtsushi Murai } 564af57ed9fSAtsushi Murai 565af57ed9fSAtsushi Murai int 566af57ed9fSAtsushi Murai DoChat(script) 567af57ed9fSAtsushi Murai char *script; 568af57ed9fSAtsushi Murai { 569e68d210eSBrian Somers char *vector[40]; 570af57ed9fSAtsushi Murai char **argv; 571af57ed9fSAtsushi Murai int argc, n, state; 572af57ed9fSAtsushi Murai #ifdef DEBUG 573af57ed9fSAtsushi Murai int i; 574af57ed9fSAtsushi Murai #endif 575af57ed9fSAtsushi Murai 576af57ed9fSAtsushi Murai timeout_next = abort_next = 0; 577af57ed9fSAtsushi Murai for (n = 0; AbortStrings[n]; n++) { 578af57ed9fSAtsushi Murai free(AbortStrings[n]); 579af57ed9fSAtsushi Murai AbortStrings[n] = NULL; 580af57ed9fSAtsushi Murai } 581af57ed9fSAtsushi Murai numaborts = 0; 582af57ed9fSAtsushi Murai 583af57ed9fSAtsushi Murai bzero(vector, sizeof(vector)); 584e68d210eSBrian Somers n = MakeArgs(script, vector, VECSIZE(vector)); 585af57ed9fSAtsushi Murai #ifdef DEBUG 586af57ed9fSAtsushi Murai logprintf("n = %d\n", n); 587af57ed9fSAtsushi Murai for (i = 0; i < n; i++) 588af57ed9fSAtsushi Murai logprintf(" %s\n", vector[i]); 589af57ed9fSAtsushi Murai #endif 590af57ed9fSAtsushi Murai argc = n; 591af57ed9fSAtsushi Murai argv = vector; 592af57ed9fSAtsushi Murai TimeoutSec = 30; 593af57ed9fSAtsushi Murai while (*argv) { 594af57ed9fSAtsushi Murai if (strcmp(*argv, "P_ZERO") == 0 || 595af57ed9fSAtsushi Murai strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) { 596af57ed9fSAtsushi Murai ChangeParity(*argv++); 597af57ed9fSAtsushi Murai continue; 598af57ed9fSAtsushi Murai } 599af57ed9fSAtsushi Murai state = ExpectString(*argv++); 600af57ed9fSAtsushi Murai switch (state) { 601af57ed9fSAtsushi Murai case MATCH: 602af57ed9fSAtsushi Murai if (*argv) 603af57ed9fSAtsushi Murai SendString(*argv++); 604af57ed9fSAtsushi Murai break; 605af57ed9fSAtsushi Murai case ABORT: 606af57ed9fSAtsushi Murai #ifdef notdef 607af57ed9fSAtsushi Murai HangupModem(); 608af57ed9fSAtsushi Murai #endif 609af57ed9fSAtsushi Murai case NOMATCH: 610af57ed9fSAtsushi Murai return(NOMATCH); 611af57ed9fSAtsushi Murai } 612af57ed9fSAtsushi Murai } 613af57ed9fSAtsushi Murai return(MATCH); 614af57ed9fSAtsushi Murai } 615