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 * 2163b73463SBrian Somers * $Id: chat.c,v 1.44 1998/01/21 02:15:13 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 "chat.h" 521ae349f5Scvs2svn #include "modem.h" 5363b73463SBrian Somers #include "physical.h" 541ae349f5Scvs2svn 551ae349f5Scvs2svn #ifndef isblank 561ae349f5Scvs2svn #define isblank(c) ((c) == '\t' || (c) == ' ') 571ae349f5Scvs2svn #endif 581ae349f5Scvs2svn 591ae349f5Scvs2svn 601ae349f5Scvs2svn #define IBSIZE LINE_LEN 611ae349f5Scvs2svn 621ae349f5Scvs2svn static int TimeoutSec; 631ae349f5Scvs2svn static int abort_next, timeout_next; 641ae349f5Scvs2svn static int numaborts; 651ae349f5Scvs2svn static char *AbortStrings[50]; 661ae349f5Scvs2svn static char inbuff[IBSIZE * 2 + 1]; 671ae349f5Scvs2svn static jmp_buf ChatEnv; 681ae349f5Scvs2svn 691ae349f5Scvs2svn #define MATCH 1 701ae349f5Scvs2svn #define NOMATCH 0 711ae349f5Scvs2svn #define ABORT -1 721ae349f5Scvs2svn 731ae349f5Scvs2svn static char * 741ae349f5Scvs2svn findblank(char *p, int instring) 751ae349f5Scvs2svn { 761ae349f5Scvs2svn if (instring) { 771ae349f5Scvs2svn while (*p) { 781ae349f5Scvs2svn if (*p == '\\') { 791ae349f5Scvs2svn strcpy(p, p + 1); 801ae349f5Scvs2svn if (!*p) 811ae349f5Scvs2svn break; 821ae349f5Scvs2svn } else if (*p == '"') 831ae349f5Scvs2svn return (p); 841ae349f5Scvs2svn p++; 851ae349f5Scvs2svn } 861ae349f5Scvs2svn } else { 871ae349f5Scvs2svn while (*p) { 881ae349f5Scvs2svn if (isblank(*p)) 891ae349f5Scvs2svn return (p); 901ae349f5Scvs2svn p++; 911ae349f5Scvs2svn } 921ae349f5Scvs2svn } 931ae349f5Scvs2svn return p; 941ae349f5Scvs2svn } 951ae349f5Scvs2svn 961ae349f5Scvs2svn int 971ae349f5Scvs2svn MakeArgs(char *script, char **pvect, int maxargs) 981ae349f5Scvs2svn { 991ae349f5Scvs2svn int nargs, nb; 1001ae349f5Scvs2svn int instring; 1011ae349f5Scvs2svn 1021ae349f5Scvs2svn nargs = 0; 1031ae349f5Scvs2svn while (*script) { 1041ae349f5Scvs2svn nb = strspn(script, " \t"); 1051ae349f5Scvs2svn script += nb; 1061ae349f5Scvs2svn if (*script) { 1071ae349f5Scvs2svn if (*script == '"') { 1081ae349f5Scvs2svn instring = 1; 1091ae349f5Scvs2svn script++; 1101ae349f5Scvs2svn if (*script == '\0') 1111ae349f5Scvs2svn break; /* Shouldn't return here. Need to null 1121ae349f5Scvs2svn * terminate below */ 1131ae349f5Scvs2svn } else 1141ae349f5Scvs2svn instring = 0; 1151ae349f5Scvs2svn if (nargs >= maxargs - 1) 1161ae349f5Scvs2svn break; 1171ae349f5Scvs2svn *pvect++ = script; 1181ae349f5Scvs2svn nargs++; 1191ae349f5Scvs2svn script = findblank(script, instring); 1201ae349f5Scvs2svn if (*script) 1211ae349f5Scvs2svn *script++ = '\0'; 1221ae349f5Scvs2svn } 1231ae349f5Scvs2svn } 1241ae349f5Scvs2svn *pvect = NULL; 1251ae349f5Scvs2svn return nargs; 1261ae349f5Scvs2svn } 1271ae349f5Scvs2svn 1281ae349f5Scvs2svn /* 1291ae349f5Scvs2svn * \c don't add a cr 1301ae349f5Scvs2svn * \d Sleep a little (delay 2 seconds 1311ae349f5Scvs2svn * \n Line feed character 1321ae349f5Scvs2svn * \P Auth Key password 1331ae349f5Scvs2svn * \p pause 0.25 sec 1341ae349f5Scvs2svn * \r Carrige return character 1351ae349f5Scvs2svn * \s Space character 1361ae349f5Scvs2svn * \T Telephone number(s) (defined via `set phone') 1371ae349f5Scvs2svn * \t Tab character 1381ae349f5Scvs2svn * \U Auth User 1391ae349f5Scvs2svn */ 1401ae349f5Scvs2svn char * 1411ae349f5Scvs2svn ExpandString(const char *str, char *result, int reslen, int sendmode) 1421ae349f5Scvs2svn { 1431ae349f5Scvs2svn int addcr = 0; 1441ae349f5Scvs2svn char *phone; 1451ae349f5Scvs2svn 1461ae349f5Scvs2svn result[--reslen] = '\0'; 1471ae349f5Scvs2svn if (sendmode) 1481ae349f5Scvs2svn addcr = 1; 1491ae349f5Scvs2svn while (*str && reslen > 0) { 1501ae349f5Scvs2svn switch (*str) { 1511ae349f5Scvs2svn case '\\': 1521ae349f5Scvs2svn str++; 1531ae349f5Scvs2svn switch (*str) { 1541ae349f5Scvs2svn case 'c': 1551ae349f5Scvs2svn if (sendmode) 1561ae349f5Scvs2svn addcr = 0; 1571ae349f5Scvs2svn break; 1581ae349f5Scvs2svn case 'd': /* Delay 2 seconds */ 1591ae349f5Scvs2svn nointr_sleep(2); 1601ae349f5Scvs2svn break; 1611ae349f5Scvs2svn case 'p': 1621ae349f5Scvs2svn nointr_usleep(250000); 1631ae349f5Scvs2svn break; /* Pause 0.25 sec */ 1641ae349f5Scvs2svn case 'n': 1651ae349f5Scvs2svn *result++ = '\n'; 1661ae349f5Scvs2svn reslen--; 1671ae349f5Scvs2svn break; 1681ae349f5Scvs2svn case 'r': 1691ae349f5Scvs2svn *result++ = '\r'; 1701ae349f5Scvs2svn reslen--; 1711ae349f5Scvs2svn break; 1721ae349f5Scvs2svn case 's': 1731ae349f5Scvs2svn *result++ = ' '; 1741ae349f5Scvs2svn reslen--; 1751ae349f5Scvs2svn break; 1761ae349f5Scvs2svn case 't': 1771ae349f5Scvs2svn *result++ = '\t'; 1781ae349f5Scvs2svn reslen--; 1791ae349f5Scvs2svn break; 1801ae349f5Scvs2svn case 'P': 1811ae349f5Scvs2svn strncpy(result, VarAuthKey, reslen); 1821ae349f5Scvs2svn reslen -= strlen(result); 1831ae349f5Scvs2svn result += strlen(result); 1841ae349f5Scvs2svn break; 1851ae349f5Scvs2svn case 'T': 1861ae349f5Scvs2svn if (VarAltPhone == NULL) { 1871ae349f5Scvs2svn if (VarNextPhone == NULL) { 1881ae349f5Scvs2svn strncpy(VarPhoneCopy, VarPhoneList, sizeof VarPhoneCopy - 1); 1891ae349f5Scvs2svn VarPhoneCopy[sizeof VarPhoneCopy - 1] = '\0'; 1901ae349f5Scvs2svn VarNextPhone = VarPhoneCopy; 1911ae349f5Scvs2svn } 1921ae349f5Scvs2svn VarAltPhone = strsep(&VarNextPhone, ":"); 1931ae349f5Scvs2svn } 1941ae349f5Scvs2svn phone = strsep(&VarAltPhone, "|"); 1951ae349f5Scvs2svn strncpy(result, phone, reslen); 1961ae349f5Scvs2svn reslen -= strlen(result); 1971ae349f5Scvs2svn result += strlen(result); 1981ae349f5Scvs2svn if (VarTerm) 1991ae349f5Scvs2svn fprintf(VarTerm, "Phone: %s\n", phone); 2001ae349f5Scvs2svn LogPrintf(LogPHASE, "Phone: %s\n", phone); 2011ae349f5Scvs2svn break; 2021ae349f5Scvs2svn case 'U': 2031ae349f5Scvs2svn strncpy(result, VarAuthName, reslen); 2041ae349f5Scvs2svn reslen -= strlen(result); 2051ae349f5Scvs2svn result += strlen(result); 2061ae349f5Scvs2svn break; 2071ae349f5Scvs2svn default: 2081ae349f5Scvs2svn reslen--; 2091ae349f5Scvs2svn *result++ = *str; 2101ae349f5Scvs2svn break; 2111ae349f5Scvs2svn } 2121ae349f5Scvs2svn if (*str) 2131ae349f5Scvs2svn str++; 2141ae349f5Scvs2svn break; 2151ae349f5Scvs2svn case '^': 2161ae349f5Scvs2svn str++; 2171ae349f5Scvs2svn if (*str) { 2181ae349f5Scvs2svn *result++ = *str++ & 0x1f; 2191ae349f5Scvs2svn reslen--; 2201ae349f5Scvs2svn } 2211ae349f5Scvs2svn break; 2221ae349f5Scvs2svn default: 2231ae349f5Scvs2svn *result++ = *str++; 2241ae349f5Scvs2svn reslen--; 2251ae349f5Scvs2svn break; 2261ae349f5Scvs2svn } 2271ae349f5Scvs2svn } 2281ae349f5Scvs2svn if (--reslen > 0) { 2291ae349f5Scvs2svn if (addcr) 2301ae349f5Scvs2svn *result++ = '\r'; 2311ae349f5Scvs2svn } 2321ae349f5Scvs2svn if (--reslen > 0) 2331ae349f5Scvs2svn *result++ = '\0'; 2341ae349f5Scvs2svn return (result); 2351ae349f5Scvs2svn } 2361ae349f5Scvs2svn 2371ae349f5Scvs2svn #define MAXLOGBUFF LINE_LEN 2381ae349f5Scvs2svn static char logbuff[MAXLOGBUFF]; 2391ae349f5Scvs2svn static int loglen = 0; 2401ae349f5Scvs2svn 2411ae349f5Scvs2svn static void 2421ae349f5Scvs2svn clear_log(void) 2431ae349f5Scvs2svn { 2441ae349f5Scvs2svn memset(logbuff, 0, MAXLOGBUFF); 2451ae349f5Scvs2svn loglen = 0; 2461ae349f5Scvs2svn } 2471ae349f5Scvs2svn 2481ae349f5Scvs2svn static void 2491ae349f5Scvs2svn flush_log(void) 2501ae349f5Scvs2svn { 2511ae349f5Scvs2svn if (LogIsKept(LogCONNECT)) 2521ae349f5Scvs2svn LogPrintf(LogCONNECT, "%s\n", logbuff); 2531ae349f5Scvs2svn else if (LogIsKept(LogCARRIER) && strstr(logbuff, "CARRIER")) 2541ae349f5Scvs2svn LogPrintf(LogCARRIER, "%s\n", logbuff); 2551ae349f5Scvs2svn 2561ae349f5Scvs2svn clear_log(); 2571ae349f5Scvs2svn } 2581ae349f5Scvs2svn 2591ae349f5Scvs2svn static void 2601ae349f5Scvs2svn connect_log(const char *str, int single_p) 2611ae349f5Scvs2svn { 2621ae349f5Scvs2svn int space = MAXLOGBUFF - loglen - 1; 2631ae349f5Scvs2svn 2641ae349f5Scvs2svn while (space--) { 2651ae349f5Scvs2svn if (*str == '\n') { 2661ae349f5Scvs2svn flush_log(); 2671ae349f5Scvs2svn } else { 2681ae349f5Scvs2svn logbuff[loglen++] = *str; 2691ae349f5Scvs2svn } 2701ae349f5Scvs2svn if (single_p || !*++str) 2711ae349f5Scvs2svn break; 2721ae349f5Scvs2svn } 2731ae349f5Scvs2svn if (!space) 2741ae349f5Scvs2svn flush_log(); 2751ae349f5Scvs2svn } 2761ae349f5Scvs2svn 2771ae349f5Scvs2svn static void 27863b73463SBrian Somers ExecStr(struct physical *physical, char *command, char *out, int olen) 2791ae349f5Scvs2svn { 2801ae349f5Scvs2svn pid_t pid; 2811ae349f5Scvs2svn int fids[2]; 2821ae349f5Scvs2svn char *vector[MAXARGS], *startout, *endout; 2831ae349f5Scvs2svn int stat, nb; 2841ae349f5Scvs2svn 2851ae349f5Scvs2svn LogPrintf(LogCHAT, "Exec: %s\n", command); 2861ae349f5Scvs2svn MakeArgs(command, vector, VECSIZE(vector)); 2871ae349f5Scvs2svn 2881ae349f5Scvs2svn if (pipe(fids) < 0) { 2891ae349f5Scvs2svn LogPrintf(LogCHAT, "Unable to create pipe in ExecStr: %s\n", 2901ae349f5Scvs2svn strerror(errno)); 2911ae349f5Scvs2svn longjmp(ChatEnv, 2); 2921ae349f5Scvs2svn } 2931ae349f5Scvs2svn if ((pid = fork()) == 0) { 2941ae349f5Scvs2svn TermTimerService(); 2951ae349f5Scvs2svn signal(SIGINT, SIG_DFL); 2961ae349f5Scvs2svn signal(SIGQUIT, SIG_DFL); 2971ae349f5Scvs2svn signal(SIGTERM, SIG_DFL); 2981ae349f5Scvs2svn signal(SIGHUP, SIG_DFL); 2991ae349f5Scvs2svn signal(SIGALRM, SIG_DFL); 30063b73463SBrian Somers /* XXX-ML This looks like it might need more encapsulation. */ 30163b73463SBrian Somers if (Physical_GetFD(physical) == 2) { 30263b73463SBrian Somers Physical_DupAndClose(physical); 3031ae349f5Scvs2svn } 3041ae349f5Scvs2svn close(fids[0]); 3051ae349f5Scvs2svn dup2(fids[1], 2); 3061ae349f5Scvs2svn close(fids[1]); 30763b73463SBrian Somers dup2(Physical_GetFD(physical), 0); 30863b73463SBrian Somers dup2(Physical_GetFD(physical), 1); 3091ae349f5Scvs2svn if ((nb = open("/dev/tty", O_RDWR)) > 3) { 3101ae349f5Scvs2svn dup2(nb, 3); 3111ae349f5Scvs2svn close(nb); 3121ae349f5Scvs2svn } 3131ae349f5Scvs2svn setuid(geteuid()); 3141ae349f5Scvs2svn execvp(vector[0], vector); 3151ae349f5Scvs2svn fprintf(stderr, "execvp failed: %s: %s\n", vector[0], strerror(errno)); 3161ae349f5Scvs2svn exit(127); 3171ae349f5Scvs2svn } else { 3181ae349f5Scvs2svn char *name = strdup(vector[0]); 3191ae349f5Scvs2svn 3201ae349f5Scvs2svn close(fids[1]); 3211ae349f5Scvs2svn endout = out + olen - 1; 3221ae349f5Scvs2svn startout = out; 3231ae349f5Scvs2svn while (out < endout) { 3241ae349f5Scvs2svn nb = read(fids[0], out, 1); 3251ae349f5Scvs2svn if (nb <= 0) 3261ae349f5Scvs2svn break; 3271ae349f5Scvs2svn out++; 3281ae349f5Scvs2svn } 3291ae349f5Scvs2svn *out = '\0'; 3301ae349f5Scvs2svn close(fids[0]); 3311ae349f5Scvs2svn close(fids[1]); 3321ae349f5Scvs2svn waitpid(pid, &stat, WNOHANG); 3331ae349f5Scvs2svn if (WIFSIGNALED(stat)) { 3341ae349f5Scvs2svn LogPrintf(LogWARN, "%s: signal %d\n", name, WTERMSIG(stat)); 3351ae349f5Scvs2svn free(name); 3361ae349f5Scvs2svn longjmp(ChatEnv, 3); 3371ae349f5Scvs2svn } else if (WIFEXITED(stat)) { 3381ae349f5Scvs2svn switch (WEXITSTATUS(stat)) { 3391ae349f5Scvs2svn case 0: 3401ae349f5Scvs2svn free(name); 3411ae349f5Scvs2svn break; 3421ae349f5Scvs2svn case 127: 3431ae349f5Scvs2svn LogPrintf(LogWARN, "%s: %s\n", name, startout); 3441ae349f5Scvs2svn free(name); 3451ae349f5Scvs2svn longjmp(ChatEnv, 4); 3461ae349f5Scvs2svn break; 3471ae349f5Scvs2svn default: 3481ae349f5Scvs2svn LogPrintf(LogWARN, "%s: exit %d\n", name, WEXITSTATUS(stat)); 3491ae349f5Scvs2svn free(name); 3501ae349f5Scvs2svn longjmp(ChatEnv, 5); 3511ae349f5Scvs2svn break; 3521ae349f5Scvs2svn } 3531ae349f5Scvs2svn } else { 3541ae349f5Scvs2svn LogPrintf(LogWARN, "%s: Unexpected exit result\n", name); 3551ae349f5Scvs2svn free(name); 3561ae349f5Scvs2svn longjmp(ChatEnv, 6); 3571ae349f5Scvs2svn } 3581ae349f5Scvs2svn } 3591ae349f5Scvs2svn } 3601ae349f5Scvs2svn 3611ae349f5Scvs2svn static int 36263b73463SBrian Somers WaitforString(struct physical *physical, const char *estr) 3631ae349f5Scvs2svn { 3641ae349f5Scvs2svn struct timeval timeout; 3651ae349f5Scvs2svn char *s, *str, ch; 3661ae349f5Scvs2svn char *inp; 3671ae349f5Scvs2svn fd_set rfds; 3681ae349f5Scvs2svn int i, nfds, nb; 3691ae349f5Scvs2svn char buff[IBSIZE]; 3701ae349f5Scvs2svn #ifdef SIGALRM 3711ae349f5Scvs2svn int omask; 3721ae349f5Scvs2svn 3731ae349f5Scvs2svn omask = sigblock(sigmask(SIGALRM)); 3741ae349f5Scvs2svn #endif 3751ae349f5Scvs2svn clear_log(); 3761ae349f5Scvs2svn if (*estr == '!') { 3771ae349f5Scvs2svn ExpandString(estr + 1, buff, sizeof buff, 0); 37863b73463SBrian Somers ExecStr(physical, buff, buff, sizeof buff); 3791ae349f5Scvs2svn } else { 3801ae349f5Scvs2svn ExpandString(estr, buff, sizeof buff, 0); 3811ae349f5Scvs2svn } 3821ae349f5Scvs2svn if (LogIsKept(LogCHAT)) { 3831ae349f5Scvs2svn s = buff + strlen(buff) - 1; 3841ae349f5Scvs2svn while (s >= buff && *s == '\n') 3851ae349f5Scvs2svn s--; 3861ae349f5Scvs2svn if (!strcmp(estr, buff)) 3871ae349f5Scvs2svn LogPrintf(LogCHAT, "Wait for (%d): %.*s\n", 3881ae349f5Scvs2svn TimeoutSec, s - buff + 1, buff); 3891ae349f5Scvs2svn else 3901ae349f5Scvs2svn LogPrintf(LogCHAT, "Wait for (%d): %s --> %.*s\n", 3911ae349f5Scvs2svn TimeoutSec, estr, s - buff + 1, buff); 3921ae349f5Scvs2svn } 3931ae349f5Scvs2svn 3941ae349f5Scvs2svn if (buff[0] == '\0') 3951ae349f5Scvs2svn return (MATCH); 3961ae349f5Scvs2svn 3971ae349f5Scvs2svn str = buff; 3981ae349f5Scvs2svn inp = inbuff; 3991ae349f5Scvs2svn 4001ae349f5Scvs2svn if (strlen(str) >= IBSIZE) { 4011ae349f5Scvs2svn str[IBSIZE - 1] = 0; 4021ae349f5Scvs2svn LogPrintf(LogCHAT, "Truncating String to %d character: %s\n", IBSIZE, str); 4031ae349f5Scvs2svn } 40463b73463SBrian Somers /* XXX-ML - this look REALLY fishy. */ 40563b73463SBrian Somers nfds = Physical_GetFD(physical) + 1; 4061ae349f5Scvs2svn s = str; 4071ae349f5Scvs2svn for (;;) { 4081ae349f5Scvs2svn FD_ZERO(&rfds); 40963b73463SBrian Somers FD_SET(Physical_GetFD(physical), &rfds); 4101ae349f5Scvs2svn 4111ae349f5Scvs2svn /* 4121ae349f5Scvs2svn * Because it is not clear whether select() modifies timeout value, it is 4131ae349f5Scvs2svn * better to initialize timeout values everytime. 4141ae349f5Scvs2svn */ 4151ae349f5Scvs2svn timeout.tv_sec = TimeoutSec; 4161ae349f5Scvs2svn timeout.tv_usec = 0; 4171ae349f5Scvs2svn i = select(nfds, &rfds, NULL, NULL, &timeout); 4181ae349f5Scvs2svn #ifdef notdef 4191ae349f5Scvs2svn TimerService(); 4201ae349f5Scvs2svn #endif 4211ae349f5Scvs2svn if (i < 0) { 4221ae349f5Scvs2svn #ifdef SIGALRM 4231ae349f5Scvs2svn if (errno == EINTR) 4241ae349f5Scvs2svn continue; 4251ae349f5Scvs2svn sigsetmask(omask); 4261ae349f5Scvs2svn #endif 4271ae349f5Scvs2svn LogPrintf(LogERROR, "WaitForString: select(): %s\n", strerror(errno)); 4281ae349f5Scvs2svn *inp = 0; 4291ae349f5Scvs2svn return (NOMATCH); 4301ae349f5Scvs2svn } else if (i == 0) { /* Timeout reached! */ 4311ae349f5Scvs2svn *inp = 0; 4321ae349f5Scvs2svn if (inp != inbuff) 4331ae349f5Scvs2svn LogPrintf(LogCHAT, "Got: %s\n", inbuff); 4341ae349f5Scvs2svn LogPrintf(LogCHAT, "Can't get (%d).\n", timeout.tv_sec); 4351ae349f5Scvs2svn #ifdef SIGALRM 4361ae349f5Scvs2svn sigsetmask(omask); 4371ae349f5Scvs2svn #endif 4381ae349f5Scvs2svn return (NOMATCH); 4391ae349f5Scvs2svn } 44063b73463SBrian Somers if (Physical_FD_ISSET(physical, &rfds)) { /* got something */ 44163b73463SBrian Somers if (Physical_IsSync(physical)) { 4421ae349f5Scvs2svn int length; 4431ae349f5Scvs2svn 4441ae349f5Scvs2svn if ((length = strlen(inbuff)) > IBSIZE) { 4451ae349f5Scvs2svn /* shuffle down next part */ 4461ae349f5Scvs2svn memcpy(inbuff, &(inbuff[IBSIZE]), IBSIZE + 1); 4471ae349f5Scvs2svn length = strlen(inbuff); 4481ae349f5Scvs2svn } 44963b73463SBrian Somers if (length + IBSIZE > sizeof(inbuff)) 45063b73463SBrian Somers abort(); /* Bug & security problem */ 45163b73463SBrian Somers nb = Physical_Read(physical, &(inbuff[length]), IBSIZE); 4521ae349f5Scvs2svn inbuff[nb + length] = 0; 4531ae349f5Scvs2svn connect_log(inbuff, 0); 4541ae349f5Scvs2svn if (strstr(inbuff, str)) { 4551ae349f5Scvs2svn #ifdef SIGALRM 4561ae349f5Scvs2svn sigsetmask(omask); 4571ae349f5Scvs2svn #endif 4581ae349f5Scvs2svn flush_log(); 4591ae349f5Scvs2svn return (MATCH); 4601ae349f5Scvs2svn } 4611ae349f5Scvs2svn for (i = 0; i < numaborts; i++) { 4621ae349f5Scvs2svn if (strstr(inbuff, AbortStrings[i])) { 4631ae349f5Scvs2svn LogPrintf(LogCHAT, "Abort: %s\n", AbortStrings[i]); 4641ae349f5Scvs2svn #ifdef SIGALRM 4651ae349f5Scvs2svn sigsetmask(omask); 4661ae349f5Scvs2svn #endif 4671ae349f5Scvs2svn flush_log(); 4681ae349f5Scvs2svn return (ABORT); 4691ae349f5Scvs2svn } 4701ae349f5Scvs2svn } 4711ae349f5Scvs2svn } else { 47263b73463SBrian Somers if (Physical_Read(physical, &ch, 1) < 0) { 4731ae349f5Scvs2svn LogPrintf(LogERROR, "read error: %s\n", strerror(errno)); 4741ae349f5Scvs2svn *inp = '\0'; 4751ae349f5Scvs2svn return (NOMATCH); 4761ae349f5Scvs2svn } 4771ae349f5Scvs2svn connect_log(&ch, 1); 4781ae349f5Scvs2svn *inp++ = ch; 4791ae349f5Scvs2svn if (ch == *s) { 4801ae349f5Scvs2svn s++; 4811ae349f5Scvs2svn if (*s == '\0') { 4821ae349f5Scvs2svn #ifdef SIGALRM 4831ae349f5Scvs2svn sigsetmask(omask); 4841ae349f5Scvs2svn #endif 4851ae349f5Scvs2svn *inp = 0; 4861ae349f5Scvs2svn flush_log(); 4871ae349f5Scvs2svn return (MATCH); 4881ae349f5Scvs2svn } 4891ae349f5Scvs2svn } else 4901ae349f5Scvs2svn s = str; 4911ae349f5Scvs2svn if (inp == inbuff + IBSIZE) { 4921ae349f5Scvs2svn memcpy(inbuff, inp - 100, 100); 4931ae349f5Scvs2svn inp = inbuff + 100; 4941ae349f5Scvs2svn } 4951ae349f5Scvs2svn if (s == str) { 4961ae349f5Scvs2svn for (i = 0; i < numaborts; i++) { /* Look for Abort strings */ 4971ae349f5Scvs2svn int len; 4981ae349f5Scvs2svn char *s1; 4991ae349f5Scvs2svn 5001ae349f5Scvs2svn s1 = AbortStrings[i]; 5011ae349f5Scvs2svn len = strlen(s1); 5021ae349f5Scvs2svn if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) { 5031ae349f5Scvs2svn LogPrintf(LogCHAT, "Abort: %s\n", s1); 5041ae349f5Scvs2svn *inp = 0; 5051ae349f5Scvs2svn #ifdef SIGALRM 5061ae349f5Scvs2svn sigsetmask(omask); 5071ae349f5Scvs2svn #endif 5081ae349f5Scvs2svn flush_log(); 5091ae349f5Scvs2svn return (ABORT); 5101ae349f5Scvs2svn } 5111ae349f5Scvs2svn } 5121ae349f5Scvs2svn } 5131ae349f5Scvs2svn } 5141ae349f5Scvs2svn } 5151ae349f5Scvs2svn } 5161ae349f5Scvs2svn } 5171ae349f5Scvs2svn 5181ae349f5Scvs2svn static void 51963b73463SBrian Somers SendString(struct physical *physical, const char *str) 5201ae349f5Scvs2svn { 5211ae349f5Scvs2svn char *cp; 5221ae349f5Scvs2svn int on; 5231ae349f5Scvs2svn char buff[LINE_LEN]; 5241ae349f5Scvs2svn 5251ae349f5Scvs2svn if (abort_next) { 5261ae349f5Scvs2svn abort_next = 0; 5271ae349f5Scvs2svn ExpandString(str, buff, sizeof buff, 0); 5281ae349f5Scvs2svn AbortStrings[numaborts++] = strdup(buff); 5291ae349f5Scvs2svn } else if (timeout_next) { 5301ae349f5Scvs2svn timeout_next = 0; 5311ae349f5Scvs2svn TimeoutSec = atoi(str); 5321ae349f5Scvs2svn if (TimeoutSec <= 0) 5331ae349f5Scvs2svn TimeoutSec = 30; 5341ae349f5Scvs2svn } else { 5351ae349f5Scvs2svn if (*str == '!') { 5361ae349f5Scvs2svn ExpandString(str + 1, buff + 2, sizeof buff - 2, 0); 53763b73463SBrian Somers ExecStr(physical, buff + 2, buff + 2, sizeof buff - 2); 5381ae349f5Scvs2svn } else { 5391ae349f5Scvs2svn ExpandString(str, buff + 2, sizeof buff - 2, 1); 5401ae349f5Scvs2svn } 5411ae349f5Scvs2svn if (strstr(str, "\\P")) /* Do not log the password itself. */ 5421ae349f5Scvs2svn LogPrintf(LogCHAT, "Sending: %s", str); 5431ae349f5Scvs2svn else { 5441ae349f5Scvs2svn cp = buff + strlen(buff + 2) + 1; 5451ae349f5Scvs2svn while (cp >= buff + 2 && *cp == '\n') 5461ae349f5Scvs2svn cp--; 5471ae349f5Scvs2svn LogPrintf(LogCHAT, "Sending: %.*s\n", cp - buff - 1, buff + 2); 5481ae349f5Scvs2svn } 5491ae349f5Scvs2svn cp = buff; 55063b73463SBrian Somers if (Physical_IsSync(physical)) 5511ae349f5Scvs2svn memcpy(buff, "\377\003", 2); /* Prepend HDLC header */ 5521ae349f5Scvs2svn else 5531ae349f5Scvs2svn cp += 2; 5541ae349f5Scvs2svn on = strlen(cp); 55563b73463SBrian Somers /* XXX - missing return value check */ 55663b73463SBrian Somers Physical_Write(physical, cp, on); 5571ae349f5Scvs2svn } 5581ae349f5Scvs2svn } 5591ae349f5Scvs2svn 5601ae349f5Scvs2svn static int 56163b73463SBrian Somers ExpectString(struct physical *physical, char *str) 5621ae349f5Scvs2svn { 5631ae349f5Scvs2svn char *minus; 5641ae349f5Scvs2svn int state; 5651ae349f5Scvs2svn 5661ae349f5Scvs2svn if (strcmp(str, "ABORT") == 0) { 5671ae349f5Scvs2svn ++abort_next; 5681ae349f5Scvs2svn return (MATCH); 5691ae349f5Scvs2svn } 5701ae349f5Scvs2svn if (strcmp(str, "TIMEOUT") == 0) { 5711ae349f5Scvs2svn ++timeout_next; 5721ae349f5Scvs2svn return (MATCH); 5731ae349f5Scvs2svn } 5741ae349f5Scvs2svn LogPrintf(LogCHAT, "Expecting: %s\n", str); 5751ae349f5Scvs2svn while (*str) { 5761ae349f5Scvs2svn /* 5771ae349f5Scvs2svn * Check whether if string contains sub-send-expect. 5781ae349f5Scvs2svn */ 5791ae349f5Scvs2svn for (minus = str; *minus; minus++) { 5801ae349f5Scvs2svn if (*minus == '-') { 5811ae349f5Scvs2svn if (minus == str || minus[-1] != '\\') 5821ae349f5Scvs2svn break; 5831ae349f5Scvs2svn } 5841ae349f5Scvs2svn } 5851ae349f5Scvs2svn if (*minus == '-') { /* We have sub-send-expect. */ 5861ae349f5Scvs2svn *minus = '\0'; /* XXX: Cheat with the const string */ 58763b73463SBrian Somers state = WaitforString(physical, str); 5881ae349f5Scvs2svn *minus = '-'; /* XXX: Cheat with the const string */ 5891ae349f5Scvs2svn minus++; 5901ae349f5Scvs2svn if (state != NOMATCH) 5911ae349f5Scvs2svn return (state); 5921ae349f5Scvs2svn 5931ae349f5Scvs2svn /* 5941ae349f5Scvs2svn * Can't get expect string. Sendout send part. 5951ae349f5Scvs2svn */ 5961ae349f5Scvs2svn str = minus; 5971ae349f5Scvs2svn for (minus = str; *minus; minus++) { 5981ae349f5Scvs2svn if (*minus == '-') { 5991ae349f5Scvs2svn if (minus == str || minus[-1] != '\\') 6001ae349f5Scvs2svn break; 6011ae349f5Scvs2svn } 6021ae349f5Scvs2svn } 6031ae349f5Scvs2svn if (*minus == '-') { 6041ae349f5Scvs2svn *minus = '\0'; /* XXX: Cheat with the const string */ 60563b73463SBrian Somers SendString(physical, str); 6061ae349f5Scvs2svn *minus = '-'; /* XXX: Cheat with the const string */ 6071ae349f5Scvs2svn str = ++minus; 6081ae349f5Scvs2svn } else { 60963b73463SBrian Somers SendString(physical, str); 6101ae349f5Scvs2svn return (MATCH); 6111ae349f5Scvs2svn } 6121ae349f5Scvs2svn } else { 6131ae349f5Scvs2svn /* 6141ae349f5Scvs2svn * Simple case. Wait for string. 6151ae349f5Scvs2svn */ 61663b73463SBrian Somers return (WaitforString(physical, str)); 6171ae349f5Scvs2svn } 6181ae349f5Scvs2svn } 6191ae349f5Scvs2svn return (MATCH); 6201ae349f5Scvs2svn } 6211ae349f5Scvs2svn 6221ae349f5Scvs2svn static void (*oint) (int); 6231ae349f5Scvs2svn 6241ae349f5Scvs2svn static void 6251ae349f5Scvs2svn StopDial(int sig) 6261ae349f5Scvs2svn { 6271ae349f5Scvs2svn LogPrintf(LogPHASE, "DoChat: Caught signal %d, abort connect\n", sig); 6281ae349f5Scvs2svn longjmp(ChatEnv, 1); 6291ae349f5Scvs2svn } 6301ae349f5Scvs2svn 6311ae349f5Scvs2svn int 63263b73463SBrian Somers DoChat(struct physical *physical, char *script) 6331ae349f5Scvs2svn { 6341ae349f5Scvs2svn char *vector[MAXARGS]; 6351ae349f5Scvs2svn char *const *argv; 6361ae349f5Scvs2svn int argc, n, state, err; 6371ae349f5Scvs2svn 6381ae349f5Scvs2svn if (!script || !*script) 6391ae349f5Scvs2svn return MATCH; 6401ae349f5Scvs2svn 6411ae349f5Scvs2svn if ((err = setjmp(ChatEnv))) { 6421ae349f5Scvs2svn signal(SIGINT, oint); 6431ae349f5Scvs2svn if (err == 1) 6441ae349f5Scvs2svn /* Caught a SIGINT during chat */ 6451ae349f5Scvs2svn return (-1); 6461ae349f5Scvs2svn return (NOMATCH); 6471ae349f5Scvs2svn } 6481ae349f5Scvs2svn oint = signal(SIGINT, StopDial); 6491ae349f5Scvs2svn 6501ae349f5Scvs2svn timeout_next = abort_next = 0; 6511ae349f5Scvs2svn for (n = 0; AbortStrings[n]; n++) { 6521ae349f5Scvs2svn free(AbortStrings[n]); 6531ae349f5Scvs2svn AbortStrings[n] = NULL; 6541ae349f5Scvs2svn } 6551ae349f5Scvs2svn numaborts = 0; 6561ae349f5Scvs2svn 6571ae349f5Scvs2svn memset(vector, '\0', sizeof vector); 6581ae349f5Scvs2svn argc = MakeArgs(script, vector, VECSIZE(vector)); 6591ae349f5Scvs2svn argv = vector; 6601ae349f5Scvs2svn TimeoutSec = 30; 6611ae349f5Scvs2svn while (*argv) { 6621ae349f5Scvs2svn if (strcmp(*argv, "P_ZERO") == 0 || 6631ae349f5Scvs2svn strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) { 66463b73463SBrian Somers ChangeParity(physical, *argv++); 6651ae349f5Scvs2svn continue; 6661ae349f5Scvs2svn } 66763b73463SBrian Somers state = ExpectString(physical, *argv++); 6681ae349f5Scvs2svn switch (state) { 6691ae349f5Scvs2svn case MATCH: 6701ae349f5Scvs2svn if (*argv) 67163b73463SBrian Somers SendString(physical, *argv++); 6721ae349f5Scvs2svn break; 6731ae349f5Scvs2svn case ABORT: 6741ae349f5Scvs2svn case NOMATCH: 6751ae349f5Scvs2svn signal(SIGINT, oint); 6761ae349f5Scvs2svn return (NOMATCH); 6771ae349f5Scvs2svn } 6781ae349f5Scvs2svn } 6791ae349f5Scvs2svn signal(SIGINT, oint); 6801ae349f5Scvs2svn return (MATCH); 6811ae349f5Scvs2svn } 682