11ae349f5Scvs2svn /* 21ae349f5Scvs2svn * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 31ae349f5Scvs2svn * 41ae349f5Scvs2svn * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 51ae349f5Scvs2svn * 61ae349f5Scvs2svn * Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com). 71ae349f5Scvs2svn * 81ae349f5Scvs2svn * Chat -- a program for automatic session establishment (i.e. dial 91ae349f5Scvs2svn * the phone and log in). 101ae349f5Scvs2svn * 111ae349f5Scvs2svn * This software is in the public domain. 121ae349f5Scvs2svn * 131ae349f5Scvs2svn * Please send all bug reports, requests for information, etc. to: 141ae349f5Scvs2svn * 151ae349f5Scvs2svn * Karl Fox <karl@MorningStar.Com> 161ae349f5Scvs2svn * Morning Star Technologies, Inc. 171ae349f5Scvs2svn * 1760 Zollinger Road 181ae349f5Scvs2svn * Columbus, OH 43221 191ae349f5Scvs2svn * (614)451-1883 201ae349f5Scvs2svn * 2142d4d396SBrian Somers * $Id: chat.c,v 1.44.2.4 1998/02/06 02:23:30 brian Exp $ 221ae349f5Scvs2svn * 231ae349f5Scvs2svn * TODO: 241ae349f5Scvs2svn * o Support more UUCP compatible control sequences. 251ae349f5Scvs2svn * o Dialing shoud not block monitor process. 261ae349f5Scvs2svn * o Reading modem by select should be unified into main.c 271ae349f5Scvs2svn */ 281ae349f5Scvs2svn #include <sys/param.h> 291ae349f5Scvs2svn #include <netinet/in.h> 301ae349f5Scvs2svn 311ae349f5Scvs2svn #include <ctype.h> 321ae349f5Scvs2svn #include <errno.h> 331ae349f5Scvs2svn #include <fcntl.h> 341ae349f5Scvs2svn #include <setjmp.h> 351ae349f5Scvs2svn #include <signal.h> 361ae349f5Scvs2svn #include <stdio.h> 371ae349f5Scvs2svn #include <stdlib.h> 381ae349f5Scvs2svn #include <string.h> 391ae349f5Scvs2svn #include <sys/time.h> 401ae349f5Scvs2svn #include <sys/wait.h> 411ae349f5Scvs2svn #include <termios.h> 421ae349f5Scvs2svn #include <unistd.h> 431ae349f5Scvs2svn 441ae349f5Scvs2svn #include "command.h" 451ae349f5Scvs2svn #include "mbuf.h" 461ae349f5Scvs2svn #include "log.h" 471ae349f5Scvs2svn #include "defs.h" 481ae349f5Scvs2svn #include "timer.h" 491ae349f5Scvs2svn #include "loadalias.h" 501ae349f5Scvs2svn #include "vars.h" 511ae349f5Scvs2svn #include "modem.h" 526140ba11SBrian Somers #include "hdlc.h" 536140ba11SBrian Somers #include "throughput.h" 546140ba11SBrian Somers #include "fsm.h" 556140ba11SBrian Somers #include "lcp.h" 566140ba11SBrian Somers #include "link.h" 576140ba11SBrian Somers #include "async.h" 5842d4d396SBrian Somers #include "descriptor.h" 5963b73463SBrian Somers #include "physical.h" 602289f246SBrian Somers #include "chat.h" 611ae349f5Scvs2svn 621ae349f5Scvs2svn #ifndef isblank 631ae349f5Scvs2svn #define isblank(c) ((c) == '\t' || (c) == ' ') 641ae349f5Scvs2svn #endif 651ae349f5Scvs2svn 661ae349f5Scvs2svn 671ae349f5Scvs2svn #define IBSIZE LINE_LEN 681ae349f5Scvs2svn 691ae349f5Scvs2svn static int TimeoutSec; 701ae349f5Scvs2svn static int abort_next, timeout_next; 711ae349f5Scvs2svn static int numaborts; 721ae349f5Scvs2svn static char *AbortStrings[50]; 731ae349f5Scvs2svn static char inbuff[IBSIZE * 2 + 1]; 741ae349f5Scvs2svn static jmp_buf ChatEnv; 751ae349f5Scvs2svn 761ae349f5Scvs2svn #define MATCH 1 771ae349f5Scvs2svn #define NOMATCH 0 781ae349f5Scvs2svn #define ABORT -1 791ae349f5Scvs2svn 801ae349f5Scvs2svn static char * 811ae349f5Scvs2svn findblank(char *p, int instring) 821ae349f5Scvs2svn { 831ae349f5Scvs2svn if (instring) { 841ae349f5Scvs2svn while (*p) { 851ae349f5Scvs2svn if (*p == '\\') { 861ae349f5Scvs2svn strcpy(p, p + 1); 871ae349f5Scvs2svn if (!*p) 881ae349f5Scvs2svn break; 891ae349f5Scvs2svn } else if (*p == '"') 901ae349f5Scvs2svn return (p); 911ae349f5Scvs2svn p++; 921ae349f5Scvs2svn } 931ae349f5Scvs2svn } else { 941ae349f5Scvs2svn while (*p) { 951ae349f5Scvs2svn if (isblank(*p)) 961ae349f5Scvs2svn return (p); 971ae349f5Scvs2svn p++; 981ae349f5Scvs2svn } 991ae349f5Scvs2svn } 1001ae349f5Scvs2svn return p; 1011ae349f5Scvs2svn } 1021ae349f5Scvs2svn 1031ae349f5Scvs2svn int 1041ae349f5Scvs2svn MakeArgs(char *script, char **pvect, int maxargs) 1051ae349f5Scvs2svn { 1061ae349f5Scvs2svn int nargs, nb; 1071ae349f5Scvs2svn int instring; 1081ae349f5Scvs2svn 1091ae349f5Scvs2svn nargs = 0; 1101ae349f5Scvs2svn while (*script) { 1111ae349f5Scvs2svn nb = strspn(script, " \t"); 1121ae349f5Scvs2svn script += nb; 1131ae349f5Scvs2svn if (*script) { 1141ae349f5Scvs2svn if (*script == '"') { 1151ae349f5Scvs2svn instring = 1; 1161ae349f5Scvs2svn script++; 1171ae349f5Scvs2svn if (*script == '\0') 1181ae349f5Scvs2svn break; /* Shouldn't return here. Need to null 1191ae349f5Scvs2svn * terminate below */ 1201ae349f5Scvs2svn } else 1211ae349f5Scvs2svn instring = 0; 1221ae349f5Scvs2svn if (nargs >= maxargs - 1) 1231ae349f5Scvs2svn break; 1241ae349f5Scvs2svn *pvect++ = script; 1251ae349f5Scvs2svn nargs++; 1261ae349f5Scvs2svn script = findblank(script, instring); 1271ae349f5Scvs2svn if (*script) 1281ae349f5Scvs2svn *script++ = '\0'; 1291ae349f5Scvs2svn } 1301ae349f5Scvs2svn } 1311ae349f5Scvs2svn *pvect = NULL; 1321ae349f5Scvs2svn return nargs; 1331ae349f5Scvs2svn } 1341ae349f5Scvs2svn 1351ae349f5Scvs2svn /* 1361ae349f5Scvs2svn * \c don't add a cr 1371ae349f5Scvs2svn * \d Sleep a little (delay 2 seconds 1381ae349f5Scvs2svn * \n Line feed character 1391ae349f5Scvs2svn * \P Auth Key password 1401ae349f5Scvs2svn * \p pause 0.25 sec 1411ae349f5Scvs2svn * \r Carrige return character 1421ae349f5Scvs2svn * \s Space character 1431ae349f5Scvs2svn * \T Telephone number(s) (defined via `set phone') 1441ae349f5Scvs2svn * \t Tab character 1451ae349f5Scvs2svn * \U Auth User 1461ae349f5Scvs2svn */ 1471ae349f5Scvs2svn char * 1481ae349f5Scvs2svn ExpandString(const char *str, char *result, int reslen, int sendmode) 1491ae349f5Scvs2svn { 1501ae349f5Scvs2svn int addcr = 0; 1511ae349f5Scvs2svn char *phone; 1521ae349f5Scvs2svn 1531ae349f5Scvs2svn result[--reslen] = '\0'; 1541ae349f5Scvs2svn if (sendmode) 1551ae349f5Scvs2svn addcr = 1; 1561ae349f5Scvs2svn while (*str && reslen > 0) { 1571ae349f5Scvs2svn switch (*str) { 1581ae349f5Scvs2svn case '\\': 1591ae349f5Scvs2svn str++; 1601ae349f5Scvs2svn switch (*str) { 1611ae349f5Scvs2svn case 'c': 1621ae349f5Scvs2svn if (sendmode) 1631ae349f5Scvs2svn addcr = 0; 1641ae349f5Scvs2svn break; 1651ae349f5Scvs2svn case 'd': /* Delay 2 seconds */ 1661ae349f5Scvs2svn nointr_sleep(2); 1671ae349f5Scvs2svn break; 1681ae349f5Scvs2svn case 'p': 1691ae349f5Scvs2svn nointr_usleep(250000); 1701ae349f5Scvs2svn break; /* Pause 0.25 sec */ 1711ae349f5Scvs2svn case 'n': 1721ae349f5Scvs2svn *result++ = '\n'; 1731ae349f5Scvs2svn reslen--; 1741ae349f5Scvs2svn break; 1751ae349f5Scvs2svn case 'r': 1761ae349f5Scvs2svn *result++ = '\r'; 1771ae349f5Scvs2svn reslen--; 1781ae349f5Scvs2svn break; 1791ae349f5Scvs2svn case 's': 1801ae349f5Scvs2svn *result++ = ' '; 1811ae349f5Scvs2svn reslen--; 1821ae349f5Scvs2svn break; 1831ae349f5Scvs2svn case 't': 1841ae349f5Scvs2svn *result++ = '\t'; 1851ae349f5Scvs2svn reslen--; 1861ae349f5Scvs2svn break; 1871ae349f5Scvs2svn case 'P': 1881ae349f5Scvs2svn strncpy(result, VarAuthKey, reslen); 1891ae349f5Scvs2svn reslen -= strlen(result); 1901ae349f5Scvs2svn result += strlen(result); 1911ae349f5Scvs2svn break; 1921ae349f5Scvs2svn case 'T': 1931ae349f5Scvs2svn if (VarAltPhone == NULL) { 1941ae349f5Scvs2svn if (VarNextPhone == NULL) { 1951ae349f5Scvs2svn strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1); 1961ae349f5Scvs2svn VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0'; 1971ae349f5Scvs2svn VarNextPhone = VarPhoneCopy; 1981ae349f5Scvs2svn } 1991ae349f5Scvs2svn VarAltPhone = strsep(&VarNextPhone, ":"); 2001ae349f5Scvs2svn } 2011ae349f5Scvs2svn phone = strsep(&VarAltPhone, "|"); 2021ae349f5Scvs2svn strncpy(result, phone, reslen); 2031ae349f5Scvs2svn reslen -= strlen(result); 2041ae349f5Scvs2svn result += strlen(result); 2051ae349f5Scvs2svn if (VarTerm) 2061ae349f5Scvs2svn fprintf(VarTerm, "Phone: %s\n", phone); 2071ae349f5Scvs2svn LogPrintf(LogPHASE, "Phone: %s\n", phone); 2081ae349f5Scvs2svn break; 2091ae349f5Scvs2svn case 'U': 2101ae349f5Scvs2svn strncpy(result, VarAuthName, reslen); 2111ae349f5Scvs2svn reslen -= strlen(result); 2121ae349f5Scvs2svn result += strlen(result); 2131ae349f5Scvs2svn break; 2141ae349f5Scvs2svn default: 2151ae349f5Scvs2svn reslen--; 2161ae349f5Scvs2svn *result++ = *str; 2171ae349f5Scvs2svn break; 2181ae349f5Scvs2svn } 2191ae349f5Scvs2svn if (*str) 2201ae349f5Scvs2svn str++; 2211ae349f5Scvs2svn break; 2221ae349f5Scvs2svn case '^': 2231ae349f5Scvs2svn str++; 2241ae349f5Scvs2svn if (*str) { 2251ae349f5Scvs2svn *result++ = *str++ & 0x1f; 2261ae349f5Scvs2svn reslen--; 2271ae349f5Scvs2svn } 2281ae349f5Scvs2svn break; 2291ae349f5Scvs2svn default: 2301ae349f5Scvs2svn *result++ = *str++; 2311ae349f5Scvs2svn reslen--; 2321ae349f5Scvs2svn break; 2331ae349f5Scvs2svn } 2341ae349f5Scvs2svn } 2351ae349f5Scvs2svn if (--reslen > 0) { 2361ae349f5Scvs2svn if (addcr) 2371ae349f5Scvs2svn *result++ = '\r'; 2381ae349f5Scvs2svn } 2391ae349f5Scvs2svn if (--reslen > 0) 2401ae349f5Scvs2svn *result++ = '\0'; 2411ae349f5Scvs2svn return (result); 2421ae349f5Scvs2svn } 2431ae349f5Scvs2svn 2441ae349f5Scvs2svn #define MAXLOGBUFF LINE_LEN 2451ae349f5Scvs2svn static char logbuff[MAXLOGBUFF]; 2461ae349f5Scvs2svn static int loglen = 0; 2471ae349f5Scvs2svn 2481ae349f5Scvs2svn static void 2491ae349f5Scvs2svn clear_log(void) 2501ae349f5Scvs2svn { 2511ae349f5Scvs2svn memset(logbuff, 0, MAXLOGBUFF); 2521ae349f5Scvs2svn loglen = 0; 2531ae349f5Scvs2svn } 2541ae349f5Scvs2svn 2551ae349f5Scvs2svn static void 2561ae349f5Scvs2svn flush_log(void) 2571ae349f5Scvs2svn { 2581ae349f5Scvs2svn if (LogIsKept(LogCONNECT)) 2591ae349f5Scvs2svn LogPrintf(LogCONNECT, "%s\n", logbuff); 2601ae349f5Scvs2svn else if (LogIsKept(LogCARRIER) && strstr(logbuff, "CARRIER")) 2611ae349f5Scvs2svn LogPrintf(LogCARRIER, "%s\n", logbuff); 2621ae349f5Scvs2svn 2631ae349f5Scvs2svn clear_log(); 2641ae349f5Scvs2svn } 2651ae349f5Scvs2svn 2661ae349f5Scvs2svn static void 2671ae349f5Scvs2svn connect_log(const char *str, int single_p) 2681ae349f5Scvs2svn { 2691ae349f5Scvs2svn int space = MAXLOGBUFF - loglen - 1; 2701ae349f5Scvs2svn 2711ae349f5Scvs2svn while (space--) { 2721ae349f5Scvs2svn if (*str == '\n') { 2731ae349f5Scvs2svn flush_log(); 2741ae349f5Scvs2svn } else { 2751ae349f5Scvs2svn logbuff[loglen++] = *str; 2761ae349f5Scvs2svn } 2771ae349f5Scvs2svn if (single_p || !*++str) 2781ae349f5Scvs2svn break; 2791ae349f5Scvs2svn } 2801ae349f5Scvs2svn if (!space) 2811ae349f5Scvs2svn flush_log(); 2821ae349f5Scvs2svn } 2831ae349f5Scvs2svn 2841ae349f5Scvs2svn static void 28563b73463SBrian Somers ExecStr(struct physical *physical, char *command, char *out, int olen) 2861ae349f5Scvs2svn { 2871ae349f5Scvs2svn pid_t pid; 2881ae349f5Scvs2svn int fids[2]; 2891ae349f5Scvs2svn char *vector[MAXARGS], *startout, *endout; 2901ae349f5Scvs2svn int stat, nb; 2911ae349f5Scvs2svn 2921ae349f5Scvs2svn LogPrintf(LogCHAT, "Exec: %s\n", command); 2931ae349f5Scvs2svn MakeArgs(command, vector, VECSIZE(vector)); 2941ae349f5Scvs2svn 2951ae349f5Scvs2svn if (pipe(fids) < 0) { 2961ae349f5Scvs2svn LogPrintf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", 2971ae349f5Scvs2svn strerror(errno)); 2981ae349f5Scvs2svn longjmp(ChatEnv, 2); 2991ae349f5Scvs2svn } 3001ae349f5Scvs2svn if ((pid = fork()) == 0) { 3011ae349f5Scvs2svn TermTimerService(); 3021ae349f5Scvs2svn signal(SIGINT, SIG_DFL); 3031ae349f5Scvs2svn signal(SIGQUIT, SIG_DFL); 3041ae349f5Scvs2svn signal(SIGTERM, SIG_DFL); 3051ae349f5Scvs2svn signal(SIGHUP, SIG_DFL); 3061ae349f5Scvs2svn signal(SIGALRM, SIG_DFL); 30763b73463SBrian Somers /* XXX-ML This looks like it might need more encapsulation. */ 30863b73463SBrian Somers if (Physical_GetFD(physical) == 2) { 30963b73463SBrian Somers Physical_DupAndClose(physical); 3101ae349f5Scvs2svn } 3111ae349f5Scvs2svn close(fids[0]); 3121ae349f5Scvs2svn dup2(fids[1], 2); 3131ae349f5Scvs2svn close(fids[1]); 31463b73463SBrian Somers dup2(Physical_GetFD(physical), 0); 31563b73463SBrian Somers dup2(Physical_GetFD(physical), 1); 3161ae349f5Scvs2svn if ((nb = open("/dev/tty", O_RDWR)) > 3) { 3171ae349f5Scvs2svn dup2(nb, 3); 3181ae349f5Scvs2svn close(nb); 3191ae349f5Scvs2svn } 3201ae349f5Scvs2svn setuid(geteuid()); 3211ae349f5Scvs2svn execvp(vector[0], vector); 3221ae349f5Scvs2svn fprintf(stderr, "execvp failed: %s: %s\n", vector[0], strerror(errno)); 3231ae349f5Scvs2svn exit(127); 3241ae349f5Scvs2svn } else { 3251ae349f5Scvs2svn char *name = strdup(vector[0]); 3261ae349f5Scvs2svn 3271ae349f5Scvs2svn close(fids[1]); 3281ae349f5Scvs2svn endout = out + olen - 1; 3291ae349f5Scvs2svn startout = out; 3301ae349f5Scvs2svn while (out < endout) { 3311ae349f5Scvs2svn nb = read(fids[0], out, 1); 3321ae349f5Scvs2svn if (nb <= 0) 3331ae349f5Scvs2svn break; 3341ae349f5Scvs2svn out++; 3351ae349f5Scvs2svn } 3361ae349f5Scvs2svn *out = '\0'; 3371ae349f5Scvs2svn close(fids[0]); 3381ae349f5Scvs2svn close(fids[1]); 3391ae349f5Scvs2svn waitpid(pid, &stat, WNOHANG); 3401ae349f5Scvs2svn if (WIFSIGNALED(stat)) { 3411ae349f5Scvs2svn LogPrintf(LogWARN, "%s: signal %d\n", name, WTERMSIG(stat)); 3421ae349f5Scvs2svn free(name); 3431ae349f5Scvs2svn longjmp(ChatEnv, 3); 3441ae349f5Scvs2svn } else if (WIFEXITED(stat)) { 3451ae349f5Scvs2svn switch (WEXITSTATUS(stat)) { 3461ae349f5Scvs2svn case 0: 3471ae349f5Scvs2svn free(name); 3481ae349f5Scvs2svn break; 3491ae349f5Scvs2svn case 127: 3501ae349f5Scvs2svn LogPrintf(LogWARN, "%s: %s\n", name, startout); 3511ae349f5Scvs2svn free(name); 3521ae349f5Scvs2svn longjmp(ChatEnv, 4); 3531ae349f5Scvs2svn break; 3541ae349f5Scvs2svn default: 3551ae349f5Scvs2svn LogPrintf(LogWARN, "%s: exit %d\n", name, WEXITSTATUS(stat)); 3561ae349f5Scvs2svn free(name); 3571ae349f5Scvs2svn longjmp(ChatEnv, 5); 3581ae349f5Scvs2svn break; 3591ae349f5Scvs2svn } 3601ae349f5Scvs2svn } else { 3611ae349f5Scvs2svn LogPrintf(LogWARN, "%s: Unexpected exit result\n", name); 3621ae349f5Scvs2svn free(name); 3631ae349f5Scvs2svn longjmp(ChatEnv, 6); 3641ae349f5Scvs2svn } 3651ae349f5Scvs2svn } 3661ae349f5Scvs2svn } 3671ae349f5Scvs2svn 3681ae349f5Scvs2svn static int 36963b73463SBrian Somers WaitforString(struct physical *physical, const char *estr) 3701ae349f5Scvs2svn { 3711ae349f5Scvs2svn struct timeval timeout; 3721ae349f5Scvs2svn char *s, *str, ch; 3731ae349f5Scvs2svn char *inp; 3741ae349f5Scvs2svn fd_set rfds; 3751ae349f5Scvs2svn int i, nfds, nb; 3761ae349f5Scvs2svn char buff[IBSIZE]; 3771ae349f5Scvs2svn #ifdef SIGALRM 3781ae349f5Scvs2svn int omask; 3791ae349f5Scvs2svn 3801ae349f5Scvs2svn omask = sigblock(sigmask(SIGALRM)); 3811ae349f5Scvs2svn #endif 3821ae349f5Scvs2svn clear_log(); 3831ae349f5Scvs2svn if (*estr == '!') { 3841ae349f5Scvs2svn ExpandString(estr + 1, buff, sizeof buff, 0); 38563b73463SBrian Somers ExecStr(physical, buff, buff, sizeof buff); 3861ae349f5Scvs2svn } else { 3871ae349f5Scvs2svn ExpandString(estr, buff, sizeof buff, 0); 3881ae349f5Scvs2svn } 3891ae349f5Scvs2svn if (LogIsKept(LogCHAT)) { 3901ae349f5Scvs2svn s = buff + strlen(buff) - 1; 3911ae349f5Scvs2svn while (s >= buff && *s == '\n') 3921ae349f5Scvs2svn s--; 3931ae349f5Scvs2svn if (!strcmp(estr, buff)) 3941ae349f5Scvs2svn LogPrintf(LogCHAT, "Wait for (%d): %.*s\n", 3951ae349f5Scvs2svn TimeoutSec, s - buff + 1, buff); 3961ae349f5Scvs2svn else 3971ae349f5Scvs2svn LogPrintf(LogCHAT, "Wait for (%d): %s --> %.*s\n", 3981ae349f5Scvs2svn TimeoutSec, estr, s - buff + 1, buff); 3991ae349f5Scvs2svn } 4001ae349f5Scvs2svn 4011ae349f5Scvs2svn if (buff[0] == '\0') 4021ae349f5Scvs2svn return (MATCH); 4031ae349f5Scvs2svn 4041ae349f5Scvs2svn str = buff; 4051ae349f5Scvs2svn inp = inbuff; 4061ae349f5Scvs2svn 4071ae349f5Scvs2svn if (strlen(str) >= IBSIZE) { 4081ae349f5Scvs2svn str[IBSIZE - 1] = 0; 4091ae349f5Scvs2svn LogPrintf(LogCHAT, "Truncating String to %d character: %s\n", IBSIZE, str); 4101ae349f5Scvs2svn } 41163b73463SBrian Somers /* XXX-ML - this look REALLY fishy. */ 41263b73463SBrian Somers nfds = Physical_GetFD(physical) + 1; 4131ae349f5Scvs2svn s = str; 4141ae349f5Scvs2svn for (;;) { 4151ae349f5Scvs2svn FD_ZERO(&rfds); 41663b73463SBrian Somers FD_SET(Physical_GetFD(physical), &rfds); 4171ae349f5Scvs2svn 4181ae349f5Scvs2svn /* 4191ae349f5Scvs2svn * Because it is not clear whether select() modifies timeout value, it is 4201ae349f5Scvs2svn * better to initialize timeout values everytime. 4211ae349f5Scvs2svn */ 4221ae349f5Scvs2svn timeout.tv_sec = TimeoutSec; 4231ae349f5Scvs2svn timeout.tv_usec = 0; 4241ae349f5Scvs2svn i = select(nfds, &rfds, NULL, NULL, &timeout); 4251ae349f5Scvs2svn #ifdef notdef 4261ae349f5Scvs2svn TimerService(); 4271ae349f5Scvs2svn #endif 4281ae349f5Scvs2svn if (i < 0) { 4291ae349f5Scvs2svn #ifdef SIGALRM 4301ae349f5Scvs2svn if (errno == EINTR) 4311ae349f5Scvs2svn continue; 4321ae349f5Scvs2svn sigsetmask(omask); 4331ae349f5Scvs2svn #endif 4341ae349f5Scvs2svn LogPrintf(LogERROR, "WaitForString: select(): %s\n", strerror(errno)); 4351ae349f5Scvs2svn *inp = 0; 4361ae349f5Scvs2svn return (NOMATCH); 4371ae349f5Scvs2svn } else if (i == 0) { /* Timeout reached! */ 4381ae349f5Scvs2svn *inp = 0; 4391ae349f5Scvs2svn if (inp != inbuff) 4401ae349f5Scvs2svn LogPrintf(LogCHAT, "Got: %s\n", inbuff); 4411ae349f5Scvs2svn LogPrintf(LogCHAT, "Can't get (%d).\n", timeout.tv_sec); 4421ae349f5Scvs2svn #ifdef SIGALRM 4431ae349f5Scvs2svn sigsetmask(omask); 4441ae349f5Scvs2svn #endif 4451ae349f5Scvs2svn return (NOMATCH); 4461ae349f5Scvs2svn } 44763b73463SBrian Somers if (Physical_FD_ISSET(physical, &rfds)) { /* got something */ 44863b73463SBrian Somers if (Physical_IsSync(physical)) { 4491ae349f5Scvs2svn int length; 4501ae349f5Scvs2svn 4511ae349f5Scvs2svn if ((length = strlen(inbuff)) > IBSIZE) { 4521ae349f5Scvs2svn /* shuffle down next part */ 4531ae349f5Scvs2svn memcpy(inbuff, &(inbuff[IBSIZE]), IBSIZE + 1); 4541ae349f5Scvs2svn length = strlen(inbuff); 4551ae349f5Scvs2svn } 45663b73463SBrian Somers if (length + IBSIZE > sizeof(inbuff)) 45763b73463SBrian Somers abort(); /* Bug & security problem */ 45863b73463SBrian Somers nb = Physical_Read(physical, &(inbuff[length]), IBSIZE); 4591ae349f5Scvs2svn inbuff[nb + length] = 0; 4601ae349f5Scvs2svn connect_log(inbuff, 0); 4611ae349f5Scvs2svn if (strstr(inbuff, str)) { 4621ae349f5Scvs2svn #ifdef SIGALRM 4631ae349f5Scvs2svn sigsetmask(omask); 4641ae349f5Scvs2svn #endif 4651ae349f5Scvs2svn flush_log(); 4661ae349f5Scvs2svn return (MATCH); 4671ae349f5Scvs2svn } 4681ae349f5Scvs2svn for (i = 0; i < numaborts; i++) { 4691ae349f5Scvs2svn if (strstr(inbuff, AbortStrings[i])) { 4701ae349f5Scvs2svn LogPrintf(LogCHAT, "Abort: %s\n", AbortStrings[i]); 4711ae349f5Scvs2svn #ifdef SIGALRM 4721ae349f5Scvs2svn sigsetmask(omask); 4731ae349f5Scvs2svn #endif 4741ae349f5Scvs2svn flush_log(); 4751ae349f5Scvs2svn return (ABORT); 4761ae349f5Scvs2svn } 4771ae349f5Scvs2svn } 4781ae349f5Scvs2svn } else { 47963b73463SBrian Somers if (Physical_Read(physical, &ch, 1) < 0) { 4801ae349f5Scvs2svn LogPrintf(LogERROR, "read error: %s\n", strerror(errno)); 4811ae349f5Scvs2svn *inp = '\0'; 4821ae349f5Scvs2svn return (NOMATCH); 4831ae349f5Scvs2svn } 4841ae349f5Scvs2svn connect_log(&ch, 1); 4851ae349f5Scvs2svn *inp++ = ch; 4861ae349f5Scvs2svn if (ch == *s) { 4871ae349f5Scvs2svn s++; 4881ae349f5Scvs2svn if (*s == '\0') { 4891ae349f5Scvs2svn #ifdef SIGALRM 4901ae349f5Scvs2svn sigsetmask(omask); 4911ae349f5Scvs2svn #endif 4921ae349f5Scvs2svn *inp = 0; 4931ae349f5Scvs2svn flush_log(); 4941ae349f5Scvs2svn return (MATCH); 4951ae349f5Scvs2svn } 4961ae349f5Scvs2svn } else 4971ae349f5Scvs2svn s = str; 4981ae349f5Scvs2svn if (inp == inbuff + IBSIZE) { 4991ae349f5Scvs2svn memcpy(inbuff, inp - 100, 100); 5001ae349f5Scvs2svn inp = inbuff + 100; 5011ae349f5Scvs2svn } 5021ae349f5Scvs2svn if (s == str) { 5031ae349f5Scvs2svn for (i = 0; i < numaborts; i++) { /* Look for Abort strings */ 5041ae349f5Scvs2svn int len; 5051ae349f5Scvs2svn char *s1; 5061ae349f5Scvs2svn 5071ae349f5Scvs2svn s1 = AbortStrings[i]; 5081ae349f5Scvs2svn len = strlen(s1); 5091ae349f5Scvs2svn if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) { 5101ae349f5Scvs2svn LogPrintf(LogCHAT, "Abort: %s\n", s1); 5111ae349f5Scvs2svn *inp = 0; 5121ae349f5Scvs2svn #ifdef SIGALRM 5131ae349f5Scvs2svn sigsetmask(omask); 5141ae349f5Scvs2svn #endif 5151ae349f5Scvs2svn flush_log(); 5161ae349f5Scvs2svn return (ABORT); 5171ae349f5Scvs2svn } 5181ae349f5Scvs2svn } 5191ae349f5Scvs2svn } 5201ae349f5Scvs2svn } 5211ae349f5Scvs2svn } 5221ae349f5Scvs2svn } 5231ae349f5Scvs2svn } 5241ae349f5Scvs2svn 5251ae349f5Scvs2svn static void 52663b73463SBrian Somers SendString(struct physical *physical, const char *str) 5271ae349f5Scvs2svn { 5281ae349f5Scvs2svn char *cp; 5291ae349f5Scvs2svn int on; 5301ae349f5Scvs2svn char buff[LINE_LEN]; 5311ae349f5Scvs2svn 5321ae349f5Scvs2svn if (abort_next) { 5331ae349f5Scvs2svn abort_next = 0; 5341ae349f5Scvs2svn ExpandString(str, buff, sizeof buff, 0); 5351ae349f5Scvs2svn AbortStrings[numaborts++] = strdup(buff); 5361ae349f5Scvs2svn } else if (timeout_next) { 5371ae349f5Scvs2svn timeout_next = 0; 5381ae349f5Scvs2svn TimeoutSec = atoi(str); 5391ae349f5Scvs2svn if (TimeoutSec <= 0) 5401ae349f5Scvs2svn TimeoutSec = 30; 5411ae349f5Scvs2svn } else { 5421ae349f5Scvs2svn if (*str == '!') { 5431ae349f5Scvs2svn ExpandString(str + 1, buff + 2, sizeof buff - 2, 0); 54463b73463SBrian Somers ExecStr(physical, buff + 2, buff + 2, sizeof buff - 2); 5451ae349f5Scvs2svn } else { 5461ae349f5Scvs2svn ExpandString(str, buff + 2, sizeof buff - 2, 1); 5471ae349f5Scvs2svn } 5481ae349f5Scvs2svn if (strstr(str, "\\P")) /* Do not log the password itself. */ 5491ae349f5Scvs2svn LogPrintf(LogCHAT, "Sending: %s", str); 5501ae349f5Scvs2svn else { 5511ae349f5Scvs2svn cp = buff + strlen(buff + 2) + 1; 5521ae349f5Scvs2svn while (cp >= buff + 2 && *cp == '\n') 5531ae349f5Scvs2svn cp--; 5541ae349f5Scvs2svn LogPrintf(LogCHAT, "Sending: %.*s\n", cp - buff - 1, buff + 2); 5551ae349f5Scvs2svn } 5561ae349f5Scvs2svn cp = buff; 55763b73463SBrian Somers if (Physical_IsSync(physical)) 5581ae349f5Scvs2svn memcpy(buff, "\377\003", 2); /* Prepend HDLC header */ 5591ae349f5Scvs2svn else 5601ae349f5Scvs2svn cp += 2; 5611ae349f5Scvs2svn on = strlen(cp); 56263b73463SBrian Somers /* XXX - missing return value check */ 56363b73463SBrian Somers Physical_Write(physical, cp, on); 5641ae349f5Scvs2svn } 5651ae349f5Scvs2svn } 5661ae349f5Scvs2svn 5671ae349f5Scvs2svn static int 56863b73463SBrian Somers ExpectString(struct physical *physical, char *str) 5691ae349f5Scvs2svn { 5701ae349f5Scvs2svn char *minus; 5711ae349f5Scvs2svn int state; 5721ae349f5Scvs2svn 5731ae349f5Scvs2svn if (strcmp(str, "ABORT") == 0) { 5741ae349f5Scvs2svn ++abort_next; 5751ae349f5Scvs2svn return (MATCH); 5761ae349f5Scvs2svn } 5771ae349f5Scvs2svn if (strcmp(str, "TIMEOUT") == 0) { 5781ae349f5Scvs2svn ++timeout_next; 5791ae349f5Scvs2svn return (MATCH); 5801ae349f5Scvs2svn } 5811ae349f5Scvs2svn LogPrintf(LogCHAT, "Expecting: %s\n", str); 5821ae349f5Scvs2svn while (*str) { 5831ae349f5Scvs2svn /* 5841ae349f5Scvs2svn * Check whether if string contains sub-send-expect. 5851ae349f5Scvs2svn */ 5861ae349f5Scvs2svn for (minus = str; *minus; minus++) { 5871ae349f5Scvs2svn if (*minus == '-') { 5881ae349f5Scvs2svn if (minus == str || minus[-1] != '\\') 5891ae349f5Scvs2svn break; 5901ae349f5Scvs2svn } 5911ae349f5Scvs2svn } 5921ae349f5Scvs2svn if (*minus == '-') { /* We have sub-send-expect. */ 5931ae349f5Scvs2svn *minus = '\0'; /* XXX: Cheat with the const string */ 59463b73463SBrian Somers state = WaitforString(physical, str); 5951ae349f5Scvs2svn *minus = '-'; /* XXX: Cheat with the const string */ 5961ae349f5Scvs2svn minus++; 5971ae349f5Scvs2svn if (state != NOMATCH) 5981ae349f5Scvs2svn return (state); 5991ae349f5Scvs2svn 6001ae349f5Scvs2svn /* 6011ae349f5Scvs2svn * Can't get expect string. Sendout send part. 6021ae349f5Scvs2svn */ 6031ae349f5Scvs2svn str = minus; 6041ae349f5Scvs2svn for (minus = str; *minus; minus++) { 6051ae349f5Scvs2svn if (*minus == '-') { 6061ae349f5Scvs2svn if (minus == str || minus[-1] != '\\') 6071ae349f5Scvs2svn break; 6081ae349f5Scvs2svn } 6091ae349f5Scvs2svn } 6101ae349f5Scvs2svn if (*minus == '-') { 6111ae349f5Scvs2svn *minus = '\0'; /* XXX: Cheat with the const string */ 61263b73463SBrian Somers SendString(physical, str); 6131ae349f5Scvs2svn *minus = '-'; /* XXX: Cheat with the const string */ 6141ae349f5Scvs2svn str = ++minus; 6151ae349f5Scvs2svn } else { 61663b73463SBrian Somers SendString(physical, str); 6171ae349f5Scvs2svn return (MATCH); 6181ae349f5Scvs2svn } 6191ae349f5Scvs2svn } else { 6201ae349f5Scvs2svn /* 6211ae349f5Scvs2svn * Simple case. Wait for string. 6221ae349f5Scvs2svn */ 62363b73463SBrian Somers return (WaitforString(physical, str)); 6241ae349f5Scvs2svn } 6251ae349f5Scvs2svn } 6261ae349f5Scvs2svn return (MATCH); 6271ae349f5Scvs2svn } 6281ae349f5Scvs2svn 6291ae349f5Scvs2svn static void (*oint) (int); 6301ae349f5Scvs2svn 6311ae349f5Scvs2svn static void 6321ae349f5Scvs2svn StopDial(int sig) 6331ae349f5Scvs2svn { 6341ae349f5Scvs2svn LogPrintf(LogPHASE, "DoChat: Caught signal %d, abort connect\n", sig); 6351ae349f5Scvs2svn longjmp(ChatEnv, 1); 6361ae349f5Scvs2svn } 6371ae349f5Scvs2svn 6381ae349f5Scvs2svn int 63963b73463SBrian Somers DoChat(struct physical *physical, char *script) 6401ae349f5Scvs2svn { 6411ae349f5Scvs2svn char *vector[MAXARGS]; 6421ae349f5Scvs2svn char *const *argv; 6431ae349f5Scvs2svn int argc, n, state, err; 6441ae349f5Scvs2svn 6451ae349f5Scvs2svn if (!script || !*script) 6461ae349f5Scvs2svn return MATCH; 6471ae349f5Scvs2svn 6481ae349f5Scvs2svn if ((err = setjmp(ChatEnv))) { 6491ae349f5Scvs2svn signal(SIGINT, oint); 6501ae349f5Scvs2svn if (err == 1) 6511ae349f5Scvs2svn /* Caught a SIGINT during chat */ 6521ae349f5Scvs2svn return (-1); 6531ae349f5Scvs2svn return (NOMATCH); 6541ae349f5Scvs2svn } 6551ae349f5Scvs2svn oint = signal(SIGINT, StopDial); 6561ae349f5Scvs2svn 6571ae349f5Scvs2svn timeout_next = abort_next = 0; 6581ae349f5Scvs2svn for (n = 0; AbortStrings[n]; n++) { 6591ae349f5Scvs2svn free(AbortStrings[n]); 6601ae349f5Scvs2svn AbortStrings[n] = NULL; 6611ae349f5Scvs2svn } 6621ae349f5Scvs2svn numaborts = 0; 6631ae349f5Scvs2svn 6641ae349f5Scvs2svn memset(vector, '\0', sizeof vector); 6651ae349f5Scvs2svn argc = MakeArgs(script, vector, VECSIZE(vector)); 6661ae349f5Scvs2svn argv = vector; 6671ae349f5Scvs2svn TimeoutSec = 30; 6681ae349f5Scvs2svn while (*argv) { 6691ae349f5Scvs2svn if (strcmp(*argv, "P_ZERO") == 0 || 6701ae349f5Scvs2svn strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) { 671ecd5172aSBrian Somers modem_SetParity(physical, *argv++); 6721ae349f5Scvs2svn continue; 6731ae349f5Scvs2svn } 67463b73463SBrian Somers state = ExpectString(physical, *argv++); 6751ae349f5Scvs2svn switch (state) { 6761ae349f5Scvs2svn case MATCH: 6771ae349f5Scvs2svn if (*argv) 67863b73463SBrian Somers SendString(physical, *argv++); 6791ae349f5Scvs2svn break; 6801ae349f5Scvs2svn case ABORT: 6811ae349f5Scvs2svn case NOMATCH: 6821ae349f5Scvs2svn signal(SIGINT, oint); 6831ae349f5Scvs2svn return (NOMATCH); 6841ae349f5Scvs2svn } 6851ae349f5Scvs2svn } 6861ae349f5Scvs2svn signal(SIGINT, oint); 6871ae349f5Scvs2svn return (MATCH); 6881ae349f5Scvs2svn } 689