xref: /freebsd/usr.sbin/ppp/chat.c (revision 63b7346316afa0c20b6cf22506bcc53abc9f08f8)
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