1431 lines
32 KiB
C
1431 lines
32 KiB
C
|
/* chat.c
|
|||
|
Chat routine for the UUCP package.
|
|||
|
|
|||
|
Copyright (C) 1991, 1992 Ian Lance Taylor
|
|||
|
|
|||
|
This file is part of the Taylor UUCP package.
|
|||
|
|
|||
|
This program is free software; you can redistribute it and/or
|
|||
|
modify it under the terms of the GNU General Public License as
|
|||
|
published by the Free Software Foundation; either version 2 of the
|
|||
|
License, or (at your option) any later version.
|
|||
|
|
|||
|
This program is distributed in the hope that it will be useful, but
|
|||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
General Public License for more details.
|
|||
|
|
|||
|
You should have received a copy of the GNU General Public License
|
|||
|
along with this program; if not, write to the Free Software
|
|||
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|||
|
|
|||
|
The author of the program may be contacted at ian@airs.com or
|
|||
|
c/o AIRS, P.O. Box 520, Waltham, MA 02254.
|
|||
|
|
|||
|
$Log: chat.c,v $
|
|||
|
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
|||
|
initial import of 386bsd-0.1 sources
|
|||
|
|
|||
|
Revision 1.26 1992/04/03 05:37:11 ian
|
|||
|
Minor cleanups for gcc 2.1
|
|||
|
|
|||
|
Revision 1.25 1992/03/28 21:47:55 ian
|
|||
|
David J. MacKenzie: allow backslash to quote newline in config files
|
|||
|
|
|||
|
Revision 1.24 1992/03/28 21:28:00 ian
|
|||
|
David J. MacKenzie: handle empty subexpect strings correctly
|
|||
|
|
|||
|
Revision 1.23 1992/03/28 19:57:22 ian
|
|||
|
David J. MacKenzie: send port device for /Y rather than port name
|
|||
|
|
|||
|
Revision 1.22 1992/03/17 01:03:03 ian
|
|||
|
Miscellaneous cleanup
|
|||
|
|
|||
|
Revision 1.21 1992/03/16 21:21:59 ian
|
|||
|
Scott Ballantyne: go ahead and send an illegal send script character
|
|||
|
|
|||
|
Revision 1.20 1992/03/16 00:47:15 ian
|
|||
|
Turn off DEBUG_PORT for chat script debugging
|
|||
|
|
|||
|
Revision 1.19 1992/03/12 19:56:10 ian
|
|||
|
Debugging based on types rather than number
|
|||
|
|
|||
|
Revision 1.18 1992/03/11 19:53:55 ian
|
|||
|
Improved chat script debugging
|
|||
|
|
|||
|
Revision 1.17 1992/03/04 00:36:44 ian
|
|||
|
Michael Richardson: better chat script debugging
|
|||
|
|
|||
|
Revision 1.16 1992/03/03 06:06:48 ian
|
|||
|
T. William Wells: don't complain about missing configuration files
|
|||
|
|
|||
|
Revision 1.15 1992/02/19 19:36:07 ian
|
|||
|
Rearranged time functions
|
|||
|
|
|||
|
Revision 1.14 1992/02/19 05:24:07 ian
|
|||
|
Bob Denny: if no trailing send string, don't send a carriage return
|
|||
|
|
|||
|
Revision 1.13 1992/02/08 03:54:18 ian
|
|||
|
Include <string.h> only in <uucp.h>, added 1992 copyright
|
|||
|
|
|||
|
Revision 1.12 1992/02/02 06:38:22 ian
|
|||
|
Michael Nolan: chat script strings might be separated by more than just ' '
|
|||
|
|
|||
|
Revision 1.11 1992/01/05 03:11:06 ian
|
|||
|
Made fcsend static
|
|||
|
|
|||
|
Revision 1.10 1991/12/28 03:49:23 ian
|
|||
|
Added HAVE_MEMFNS and HAVE_BFNS; changed uses of memset to bzero
|
|||
|
|
|||
|
Revision 1.9 1991/12/17 23:14:08 ian
|
|||
|
T. William Wells: allow dialer complete and abort to be chat scripts
|
|||
|
|
|||
|
Revision 1.8 1991/12/15 04:17:11 ian
|
|||
|
Added chat-seven-bit command to control parity bit stripping
|
|||
|
|
|||
|
Revision 1.7 1991/12/15 03:42:33 ian
|
|||
|
Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
|
|||
|
|
|||
|
Revision 1.6 1991/12/13 04:27:33 ian
|
|||
|
Franc,ois Pinard: add some chat script debugging messages
|
|||
|
|
|||
|
Revision 1.5 1991/12/07 17:58:38 ian
|
|||
|
Handle a chat script with nothing but a send string
|
|||
|
|
|||
|
Revision 1.4 1991/12/06 21:10:27 ian
|
|||
|
Franc,ois Pinard: ccescape should never return a negative number
|
|||
|
|
|||
|
Revision 1.3 1991/11/11 23:47:24 ian
|
|||
|
Added chat-program to run a program to do a chat script
|
|||
|
|
|||
|
Revision 1.2 1991/11/11 19:32:03 ian
|
|||
|
Added breceive_char to read characters through protocol buffering
|
|||
|
|
|||
|
Revision 1.1 1991/09/10 19:38:16 ian
|
|||
|
Initial revision
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include "uucp.h"
|
|||
|
|
|||
|
#if USE_RCS_ID
|
|||
|
char chat_rcsid[] = "$Id: chat.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
|||
|
#endif
|
|||
|
|
|||
|
#include <ctype.h>
|
|||
|
#include <errno.h>
|
|||
|
|
|||
|
#include "port.h"
|
|||
|
#include "system.h"
|
|||
|
|
|||
|
/* Local functions. */
|
|||
|
|
|||
|
static int ccescape P((char *zbuf));
|
|||
|
static int icexpect P((int cstrings, char **azstrings, int *aclens,
|
|||
|
int ctimeout, boolean fstrip));
|
|||
|
static boolean fcsend P((const char *zsend,
|
|||
|
const struct ssysteminfo *qsys,
|
|||
|
const struct sdialer *qdial,
|
|||
|
const char *zphone,
|
|||
|
boolean ftranslate));
|
|||
|
static boolean fcecho_send P((const char *z, int clen));
|
|||
|
static boolean fcphone P((const struct sdialer *qdial, const char *zphone,
|
|||
|
boolean (*pfwrite) P((const char *zwrite,
|
|||
|
int cwrite)),
|
|||
|
boolean ftranslate, boolean *pfquote));
|
|||
|
static boolean fctranslate P((const char *zphone, const char **pzprefix,
|
|||
|
const char **pzsuffix));
|
|||
|
static boolean fcprogram P((const char *zprogram,
|
|||
|
const struct ssysteminfo *qsys,
|
|||
|
const struct sdialer *qdial,
|
|||
|
const char *zphone, const char *zport,
|
|||
|
long ibaud));
|
|||
|
|
|||
|
/* Run a chat script with the other system. The chat script is a
|
|||
|
series of expect send pairs. We wait for the expect string to show
|
|||
|
up, and then we send the send string. The chat string for a system
|
|||
|
holds the expect and send strings separated by a single space. */
|
|||
|
|
|||
|
boolean
|
|||
|
fchat (qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
|
|||
|
const struct schat_info *qchat;
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
const struct sdialer *qdial;
|
|||
|
const char *zphone;
|
|||
|
boolean ftranslate;
|
|||
|
const char *zport;
|
|||
|
long ibaud;
|
|||
|
{
|
|||
|
const char *zchat;
|
|||
|
int cstrings;
|
|||
|
char **azstrings;
|
|||
|
int *aclens;
|
|||
|
char *zbuf;
|
|||
|
|
|||
|
/* First run the program, if any. */
|
|||
|
if (qchat->zprogram != NULL)
|
|||
|
{
|
|||
|
if (! fcprogram (qchat->zprogram, qsys, qdial, zphone, zport, ibaud))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
/* If there's no chat script, we're done. */
|
|||
|
if (qchat->zchat == NULL)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
zchat = qchat->zchat;
|
|||
|
|
|||
|
if (qchat->zfail == NULL)
|
|||
|
{
|
|||
|
cstrings = 1;
|
|||
|
azstrings = (char **) alloca (sizeof (char *));
|
|||
|
aclens = (int *) alloca (sizeof (int));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
const char *zlook;
|
|||
|
char *zcopy, *z;
|
|||
|
|
|||
|
/* We leave string number 0 for the chat script; after that
|
|||
|
we want 1 more than the number of spaces in the chat_fail
|
|||
|
string (the fencepost problem). */
|
|||
|
cstrings = 2;
|
|||
|
for (zlook = qchat->zfail; *zlook != '\0'; zlook++)
|
|||
|
if (*zlook == ' ')
|
|||
|
++cstrings;
|
|||
|
|
|||
|
azstrings = (char **) alloca (cstrings * sizeof (char *));
|
|||
|
aclens = (int *) alloca (cstrings * sizeof (int));
|
|||
|
|
|||
|
zcopy = (char *) alloca (strlen (qchat->zfail) + 1);
|
|||
|
strcpy (zcopy, qchat->zfail);
|
|||
|
|
|||
|
/* Get the strings into the array, and handle all the escape
|
|||
|
characters. */
|
|||
|
cstrings = 1;
|
|||
|
azstrings[1] = zcopy;
|
|||
|
for (z = zcopy; *z != '\0'; z++)
|
|||
|
{
|
|||
|
if (*z == ' ')
|
|||
|
{
|
|||
|
*z++ = '\0';
|
|||
|
aclens[cstrings] = ccescape (azstrings[cstrings]);
|
|||
|
++cstrings;
|
|||
|
azstrings[cstrings] = z;
|
|||
|
}
|
|||
|
}
|
|||
|
aclens[cstrings] = ccescape (azstrings[cstrings]);
|
|||
|
++cstrings;
|
|||
|
}
|
|||
|
|
|||
|
zbuf = (char *) alloca (strlen (zchat) + 1);
|
|||
|
|
|||
|
while (*zchat != '\0')
|
|||
|
{
|
|||
|
int cchatlen;
|
|||
|
char *znext;
|
|||
|
|
|||
|
/* Get this expect string into zbuf. */
|
|||
|
cchatlen = strcspn (zchat, " \t");
|
|||
|
strncpy (zbuf, zchat, cchatlen);
|
|||
|
zbuf[cchatlen] = '\0';
|
|||
|
zchat += cchatlen;
|
|||
|
zchat += strspn (zchat, " \t");
|
|||
|
|
|||
|
/* Separate out the first subexpect string. */
|
|||
|
azstrings[0] = zbuf;
|
|||
|
znext = strchr (zbuf, '-');
|
|||
|
if (znext != NULL)
|
|||
|
*znext = '\0';
|
|||
|
aclens[0] = ccescape (azstrings[0]);
|
|||
|
|
|||
|
/* Loop over subexpects and subsends. */
|
|||
|
while (TRUE)
|
|||
|
{
|
|||
|
char *zsub;
|
|||
|
|
|||
|
if (aclens[0] == 0
|
|||
|
|| (aclens[0] == 2
|
|||
|
&& strcmp (azstrings[0], "\"\"") == 0))
|
|||
|
{
|
|||
|
/* There is no subexpect sequence. If there is a
|
|||
|
subsend sequence we move on to it. Otherwise we let
|
|||
|
this expect succeed. This is somewhat inconsistent,
|
|||
|
but it seems to be the traditional approach. */
|
|||
|
if (znext == NULL)
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int istr;
|
|||
|
|
|||
|
istr = icexpect (cstrings, azstrings, aclens,
|
|||
|
qchat->ctimeout, qchat->fstrip);
|
|||
|
|
|||
|
/* If we found the string, break out of the
|
|||
|
subexpect/subsend loop. */
|
|||
|
if (istr == 0)
|
|||
|
break;
|
|||
|
|
|||
|
/* If we got an error, return FALSE. */
|
|||
|
if (istr < -1)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
/* If we found a failure string, log it and get out. */
|
|||
|
if (istr > 0)
|
|||
|
{
|
|||
|
const char *zfail;
|
|||
|
int clen;
|
|||
|
char *zcopy;
|
|||
|
|
|||
|
zfail = qchat->zfail;
|
|||
|
for (--istr; istr > 0; --istr)
|
|||
|
zfail = strchr (zfail, ' ') + 1;
|
|||
|
clen = strcspn (zfail, " ");
|
|||
|
zcopy = (char *) alloca (clen + 1);
|
|||
|
strncpy (zcopy, zfail, clen);
|
|||
|
zcopy[clen] = '\0';
|
|||
|
ulog (LOG_ERROR, "Chat script failed: Got \"%s\"",
|
|||
|
zcopy);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
/* We timed out; look for a send subsequence. If none,
|
|||
|
the chat script has failed. */
|
|||
|
if (znext == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "Timed out in chat script");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Send the send subsequence. A \"\" will send nothing. An
|
|||
|
empty string will send a carriage return. */
|
|||
|
++znext;
|
|||
|
zsub = znext;
|
|||
|
znext = strchr (zsub, '-');
|
|||
|
if (znext != NULL)
|
|||
|
*znext = '\0';
|
|||
|
if (! fcsend (zsub, qsys, qdial, zphone, ftranslate))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
/* If there is no expect subsequence, we are done. */
|
|||
|
if (znext == NULL)
|
|||
|
break;
|
|||
|
|
|||
|
/* Move on to next expect subsequence. */
|
|||
|
++znext;
|
|||
|
azstrings[0] = znext;
|
|||
|
znext = strchr (azstrings[0], '-');
|
|||
|
if (znext != NULL)
|
|||
|
*znext = '\0';
|
|||
|
aclens[0] = ccescape (azstrings[0]);
|
|||
|
}
|
|||
|
|
|||
|
/* We matched the expect string. */
|
|||
|
if (*zchat == '\0')
|
|||
|
return TRUE;
|
|||
|
|
|||
|
/* Copy the send string into zbuf. */
|
|||
|
cchatlen = strcspn (zchat, " \t");
|
|||
|
strncpy (zbuf, zchat, cchatlen);
|
|||
|
zbuf[cchatlen] = '\0';
|
|||
|
zchat += cchatlen;
|
|||
|
zchat += strspn (zchat, " \t");
|
|||
|
|
|||
|
if (*zbuf != '\0')
|
|||
|
{
|
|||
|
if (! fcsend (zbuf, qsys, qdial, zphone, ftranslate))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* The chat sequence has been completed. */
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Translate escape sequences within an expect string. */
|
|||
|
|
|||
|
static int
|
|||
|
ccescape (z)
|
|||
|
char *z;
|
|||
|
{
|
|||
|
char *zto, *zfrom;
|
|||
|
|
|||
|
zto = z;
|
|||
|
zfrom = z;
|
|||
|
while (*zfrom != '\0')
|
|||
|
{
|
|||
|
if (*zfrom != '\\')
|
|||
|
{
|
|||
|
*zto++ = *zfrom++;
|
|||
|
continue;
|
|||
|
}
|
|||
|
++zfrom;
|
|||
|
switch (*zfrom)
|
|||
|
{
|
|||
|
case 'b':
|
|||
|
*zto++ = '\b';
|
|||
|
break;
|
|||
|
case 'n':
|
|||
|
*zto++ = '\n';
|
|||
|
break;
|
|||
|
case 'N':
|
|||
|
*zto++ = '\0';
|
|||
|
break;
|
|||
|
case 'r':
|
|||
|
*zto++ = '\r';
|
|||
|
break;
|
|||
|
case 's':
|
|||
|
*zto++ = ' ';
|
|||
|
break;
|
|||
|
case 't':
|
|||
|
*zto++ = '\t';
|
|||
|
break;
|
|||
|
case '\0':
|
|||
|
--zfrom;
|
|||
|
/* Fall through. */
|
|||
|
case '\\':
|
|||
|
*zto++ = '\\';
|
|||
|
break;
|
|||
|
case '0': case '1': case '2': case '3': case '4':
|
|||
|
case '5': case '6': case '7': case '8': case '9':
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
i = *zfrom - '0';
|
|||
|
if (zfrom[1] >= '0' && zfrom[1] <= '7')
|
|||
|
i = 8 * i + *++zfrom - '0';
|
|||
|
if (zfrom[1] >= '0' && zfrom[1] <= '7')
|
|||
|
i = 8 * i + *++zfrom - '0';
|
|||
|
*zto++ = (char) i;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'x':
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
i = 0;
|
|||
|
while (isxdigit (BUCHAR (zfrom[1])))
|
|||
|
{
|
|||
|
if (isdigit (BUCHAR (zfrom[1])))
|
|||
|
i = 16 * i + *++zfrom - '0';
|
|||
|
else if (isupper (BUCHAR (zfrom[1])))
|
|||
|
i = 16 * i + *++zfrom - 'A';
|
|||
|
else
|
|||
|
i = 16 * i + *++zfrom - 'a';
|
|||
|
}
|
|||
|
*zto++ = (char) i;
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
ulog (LOG_ERROR,
|
|||
|
"Unrecognized escape sequence \\%c in expect string",
|
|||
|
*zfrom);
|
|||
|
*zto++ = *zfrom;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
++zfrom;
|
|||
|
}
|
|||
|
|
|||
|
*zto = '\0';
|
|||
|
|
|||
|
return zto - z;
|
|||
|
}
|
|||
|
|
|||
|
/* Read characters and wait for one of a set of memory strings to come
|
|||
|
in. This returns the index into the array of the string that
|
|||
|
arrives, or -1 on timeout, or -2 on error. */
|
|||
|
|
|||
|
static int
|
|||
|
icexpect (cstrings, azstrings, aclens, ctimeout, fstrip)
|
|||
|
int cstrings;
|
|||
|
char **azstrings;
|
|||
|
int *aclens;
|
|||
|
int ctimeout;
|
|||
|
boolean fstrip;
|
|||
|
{
|
|||
|
int i;
|
|||
|
int cmin, cmax;
|
|||
|
char *zhave;
|
|||
|
int chave;
|
|||
|
long iendtime;
|
|||
|
#if DEBUG > 1
|
|||
|
int cchars;
|
|||
|
int iolddebug;
|
|||
|
#endif
|
|||
|
|
|||
|
cmax = cmin = aclens[0];
|
|||
|
for (i = 1; i < cstrings; i++)
|
|||
|
{
|
|||
|
if (cmax < aclens[i])
|
|||
|
cmax = aclens[i];
|
|||
|
if (cmin > aclens[i])
|
|||
|
cmin = aclens[i];
|
|||
|
}
|
|||
|
|
|||
|
zhave = (char *) alloca (cmax);
|
|||
|
chave = 0;
|
|||
|
|
|||
|
iendtime = isysdep_time ((long *) NULL) + ctimeout;
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
cchars = 0;
|
|||
|
iolddebug = iDebug;
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
udebug_buffer ("icexpect: Looking for", azstrings[0],
|
|||
|
aclens[0]);
|
|||
|
ulog (LOG_DEBUG_START, "icexpect: Got \"");
|
|||
|
iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
while (TRUE)
|
|||
|
{
|
|||
|
int bchar;
|
|||
|
|
|||
|
/* If we have no more time, get out. */
|
|||
|
if (ctimeout <= 0)
|
|||
|
{
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_END, "\" (timed out)");
|
|||
|
iDebug = iolddebug;
|
|||
|
}
|
|||
|
#endif
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
/* Read one character at a time. We could use a more complex
|
|||
|
algorithm to read in larger batches, but it's probably not
|
|||
|
worth it. If the buffer is full, shift it left; we already
|
|||
|
know that no string matches, and the buffer holds the largest
|
|||
|
string, so this can't lose a match. */
|
|||
|
if (chave >= cmax)
|
|||
|
{
|
|||
|
xmemmove (zhave, zhave + 1, cmax - 1);
|
|||
|
--chave;
|
|||
|
}
|
|||
|
|
|||
|
/* The timeout/error return values from breceive_char are the
|
|||
|
same as for this function. */
|
|||
|
bchar = breceive_char (ctimeout, TRUE);
|
|||
|
if (bchar < 0)
|
|||
|
{
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
/* If there was an error, it will probably be logged in
|
|||
|
the middle of our string, but this is only debugging
|
|||
|
so it's not a big deal. */
|
|||
|
ulog (LOG_DEBUG_END, "\" (%s)",
|
|||
|
bchar == -1 ? "timed out" : "error");
|
|||
|
iDebug = iolddebug;
|
|||
|
}
|
|||
|
#endif
|
|||
|
return bchar;
|
|||
|
}
|
|||
|
|
|||
|
/* Strip the parity bit if desired. */
|
|||
|
if (fstrip)
|
|||
|
bchar &= 0x7f;
|
|||
|
|
|||
|
zhave[chave] = (char) bchar;
|
|||
|
++chave;
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
char ab[5];
|
|||
|
|
|||
|
++cchars;
|
|||
|
if (cchars > 60)
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_END, "\"");
|
|||
|
ulog (LOG_DEBUG_START, "icexpect: Got \"");
|
|||
|
cchars = 0;
|
|||
|
}
|
|||
|
(void) cdebug_char (ab, bchar);
|
|||
|
ulog (LOG_DEBUG_CONTINUE, "%s", ab);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/* See if any of the strings can be found in the buffer. Since
|
|||
|
we read one character at a time, the string can only be found
|
|||
|
at the end of the buffer. */
|
|||
|
for (i = 0; i < cstrings; i++)
|
|||
|
{
|
|||
|
if (aclens[i] <= chave
|
|||
|
&& memcmp (zhave + chave - aclens[i], azstrings[i],
|
|||
|
aclens[i]) == 0)
|
|||
|
{
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
if (i == 0)
|
|||
|
ulog (LOG_DEBUG_END, "\" (found it)");
|
|||
|
else
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_END, "\"");
|
|||
|
udebug_buffer ("icexpect: Found", azstrings[i],
|
|||
|
aclens[i]);
|
|||
|
}
|
|||
|
iDebug = iolddebug;
|
|||
|
}
|
|||
|
#endif
|
|||
|
return i;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ctimeout = (int) (iendtime - isysdep_time ((long *) NULL));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
|
|||
|
/* Debugging function for fcsend. This takes the fquote variable, the
|
|||
|
length of the string (0 if this an informational string which can
|
|||
|
be printed directly) and the string itself. It returns the new
|
|||
|
value for fquote. The fquote variable is TRUE if the debugging
|
|||
|
output is in the middle of a quoted string. */
|
|||
|
|
|||
|
static int cCsend_chars;
|
|||
|
static int iColddebug;
|
|||
|
|
|||
|
static boolean fcsend_debug P((boolean, int, const char *));
|
|||
|
|
|||
|
static boolean
|
|||
|
fcsend_debug (fquote, clen, zbuf)
|
|||
|
boolean fquote;
|
|||
|
int clen;
|
|||
|
const char *zbuf;
|
|||
|
{
|
|||
|
int cwas;
|
|||
|
|
|||
|
if (! FDEBUGGING (DEBUG_CHAT))
|
|||
|
return TRUE;
|
|||
|
|
|||
|
cwas = cCsend_chars;
|
|||
|
if (clen > 0)
|
|||
|
cCsend_chars += clen;
|
|||
|
else
|
|||
|
cCsend_chars += strlen (zbuf);
|
|||
|
if (cCsend_chars > 60 && cwas > 10)
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : "");
|
|||
|
fquote = FALSE;
|
|||
|
ulog (LOG_DEBUG_START, "fcsend: Writing");
|
|||
|
cCsend_chars = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (clen == 0)
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
if (! fquote)
|
|||
|
ulog (LOG_DEBUG_CONTINUE, " \"");
|
|||
|
for (i = 0; i < clen; i++)
|
|||
|
{
|
|||
|
char ab[5];
|
|||
|
|
|||
|
(void) cdebug_char (ab, zbuf[i]);
|
|||
|
ulog (LOG_DEBUG_CONTINUE, "%s", ab);
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Finish up the debugging information for fcsend. */
|
|||
|
|
|||
|
static void ucsend_debug_end P((boolean, boolean));
|
|||
|
|
|||
|
static void
|
|||
|
ucsend_debug_end (fquote, ferr)
|
|||
|
boolean fquote;
|
|||
|
boolean ferr;
|
|||
|
{
|
|||
|
if (! FDEBUGGING (DEBUG_CHAT))
|
|||
|
return;
|
|||
|
|
|||
|
if (fquote)
|
|||
|
ulog (LOG_DEBUG_CONTINUE, "\"");
|
|||
|
|
|||
|
if (ferr)
|
|||
|
ulog (LOG_DEBUG_CONTINUE, " (error)");
|
|||
|
|
|||
|
ulog (LOG_DEBUG_END, "%s", "");
|
|||
|
|
|||
|
iDebug = iColddebug;
|
|||
|
}
|
|||
|
|
|||
|
#else /* DEBUG <= 1 */
|
|||
|
|
|||
|
/* Use macro definitions to make fcsend look neater. */
|
|||
|
|
|||
|
#define fcsend_debug(fquote, clen, zbuf) TRUE
|
|||
|
|
|||
|
#define ucsend_debug_end(fquote, ferror)
|
|||
|
|
|||
|
#endif /* DEBUG <= 1 */
|
|||
|
|
|||
|
/* Send a string out. This has to parse escape sequences as it goes.
|
|||
|
Note that it handles the dialer escape sequences (\e, \E, \D, \T)
|
|||
|
although they make no sense for chatting with a system. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fcsend (z, qsys, qdial, zphone, ftranslate)
|
|||
|
const char *z;
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
const struct sdialer *qdial;
|
|||
|
const char *zphone;
|
|||
|
boolean ftranslate;
|
|||
|
{
|
|||
|
boolean fnocr;
|
|||
|
boolean (*pfwrite) P((const char *, int));
|
|||
|
char *zcallout_login;
|
|||
|
char *zcallout_pass;
|
|||
|
boolean fquote;
|
|||
|
|
|||
|
if (strcmp (z, "\"\"") == 0)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
fnocr = FALSE;
|
|||
|
pfwrite = fport_write;
|
|||
|
zcallout_login = NULL;
|
|||
|
zcallout_pass = NULL;
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_CHAT))
|
|||
|
{
|
|||
|
ulog (LOG_DEBUG_START, "fcsend: Writing");
|
|||
|
fquote = FALSE;
|
|||
|
cCsend_chars = 0;
|
|||
|
iColddebug = iDebug;
|
|||
|
iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
while (*z != '\0')
|
|||
|
{
|
|||
|
const char *zlook;
|
|||
|
boolean fsend;
|
|||
|
char bsend;
|
|||
|
|
|||
|
zlook = z + strcspn (z, "\\BE");
|
|||
|
|
|||
|
if (zlook > z)
|
|||
|
{
|
|||
|
fquote = fcsend_debug (fquote, zlook - z, z);
|
|||
|
if (! (*pfwrite) (z, zlook - z))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (*zlook == '\0')
|
|||
|
break;
|
|||
|
|
|||
|
z = zlook;
|
|||
|
|
|||
|
fsend = FALSE;
|
|||
|
switch (*z)
|
|||
|
{
|
|||
|
case 'B':
|
|||
|
if (strncmp (z, "BREAK", 5) == 0)
|
|||
|
{
|
|||
|
fquote = fcsend_debug (fquote, 0, "break");
|
|||
|
if (! fport_break ())
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
z += 5;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fsend = TRUE;
|
|||
|
bsend = 'B';
|
|||
|
++z;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'E':
|
|||
|
if (strncmp (z, "EOT", 3) == 0)
|
|||
|
{
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\004';
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fsend = TRUE;
|
|||
|
bsend = 'E';
|
|||
|
++z;
|
|||
|
}
|
|||
|
break;
|
|||
|
case '\\':
|
|||
|
++z;
|
|||
|
switch (*z)
|
|||
|
{
|
|||
|
case 'b':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\b';
|
|||
|
break;
|
|||
|
case 'c':
|
|||
|
fnocr = TRUE;
|
|||
|
break;
|
|||
|
case 'd':
|
|||
|
fquote = fcsend_debug (fquote, 0, "sleep");
|
|||
|
usysdep_sleep (1);
|
|||
|
break;
|
|||
|
case 'e':
|
|||
|
fquote = fcsend_debug (fquote, 0, "echo-check-off");
|
|||
|
pfwrite = fport_write;
|
|||
|
break;
|
|||
|
case 'E':
|
|||
|
fquote = fcsend_debug (fquote, 0, "echo-check-on");
|
|||
|
pfwrite = fcecho_send;
|
|||
|
break;
|
|||
|
case 'K':
|
|||
|
fquote = fcsend_debug (fquote, 0, "break");
|
|||
|
if (! fport_break ())
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'n':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\n';
|
|||
|
break;
|
|||
|
case 'N':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\0';
|
|||
|
break;
|
|||
|
case 'p':
|
|||
|
fquote = fcsend_debug (fquote, 0, "pause");
|
|||
|
usysdep_pause ();
|
|||
|
break;
|
|||
|
case 'r':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\r';
|
|||
|
break;
|
|||
|
case 's':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = ' ';
|
|||
|
break;
|
|||
|
case 't':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\t';
|
|||
|
break;
|
|||
|
case '\0':
|
|||
|
--z;
|
|||
|
/* Fall through. */
|
|||
|
case '\\':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = '\\';
|
|||
|
break;
|
|||
|
case '0': case '1': case '2': case '3': case '4':
|
|||
|
case '5': case '6': case '7': case '8': case '9':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = *z - '0';
|
|||
|
if (z[1] >= '0' && z[1] <= '7')
|
|||
|
bsend = (char) (8 * bsend + *++z - '0');
|
|||
|
if (z[1] >= '0' && z[1] <= '7')
|
|||
|
bsend = (char) (8 * bsend + *++z - '0');
|
|||
|
break;
|
|||
|
case 'x':
|
|||
|
fsend = TRUE;
|
|||
|
bsend = 0;
|
|||
|
while (isxdigit (BUCHAR (z[1])))
|
|||
|
{
|
|||
|
if (isdigit (BUCHAR (z[1])))
|
|||
|
bsend = (char) (16 * bsend + *++z - '0');
|
|||
|
else if (isupper (BUCHAR (z[1])))
|
|||
|
bsend = (char) (16 * bsend + *++z - 'A');
|
|||
|
else
|
|||
|
bsend = (char) (16 * bsend + *++z - 'a');
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'L':
|
|||
|
{
|
|||
|
const char *zlog;
|
|||
|
|
|||
|
if (qsys == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\L");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zlog = qsys->zcall_login;
|
|||
|
if (zlog == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "No login defined");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (zlog[0] == '*' && zlog[1] == '\0')
|
|||
|
{
|
|||
|
if (zcallout_login == NULL
|
|||
|
&& ! fcallout_login (qsys, &zcallout_login,
|
|||
|
&zcallout_pass))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zlog = zcallout_login;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "login");
|
|||
|
fquote = fcsend_debug (fquote, strlen (zlog), zlog);
|
|||
|
if (! (*pfwrite) (zlog, strlen (zlog)))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'P':
|
|||
|
{
|
|||
|
const char *zpass;
|
|||
|
|
|||
|
if (qsys == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\P");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zpass = qsys->zcall_password;
|
|||
|
if (zpass == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "No password defined");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (zpass[0] == '*' && zpass[1] == '\0')
|
|||
|
{
|
|||
|
if (zcallout_pass == NULL
|
|||
|
&& ! fcallout_login (qsys, &zcallout_login,
|
|||
|
&zcallout_pass))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zpass = zcallout_pass;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "password");
|
|||
|
fquote = fcsend_debug (fquote, strlen (zpass), zpass);
|
|||
|
if (! (*pfwrite) (zpass, strlen (zpass)))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'D':
|
|||
|
if (qdial == NULL || zphone == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\D");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "\\D");
|
|||
|
if (! fcphone (qdial, zphone, pfwrite, ftranslate, &fquote))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'T':
|
|||
|
if (qdial == NULL || zphone == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\T");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "\\T");
|
|||
|
if (! fcphone (qdial, zphone, pfwrite, TRUE, &fquote))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'M':
|
|||
|
if (qdial == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\M");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "ignore-carrier");
|
|||
|
if (! fport_no_carrier ())
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'm':
|
|||
|
if (qdial == NULL)
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
ulog (LOG_ERROR, "Illegal use of \\m");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
fquote = fcsend_debug (fquote, 0, "need-carrier");
|
|||
|
if (! fport_need_carrier ())
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
/* This error message will screw up any debugging
|
|||
|
information, but it's easily avoidable. */
|
|||
|
ulog (LOG_ERROR,
|
|||
|
"Unrecognized escape sequence \\%c in send string",
|
|||
|
*z);
|
|||
|
fsend = TRUE;
|
|||
|
bsend = *z;
|
|||
|
break;
|
|||
|
}
|
|||
|
++z;
|
|||
|
break;
|
|||
|
#if DEBUG > 0
|
|||
|
default:
|
|||
|
ulog (LOG_FATAL, "fcsend: Can't happen");
|
|||
|
break;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
if (fsend)
|
|||
|
{
|
|||
|
fquote = fcsend_debug (fquote, 1, &bsend);
|
|||
|
if (! (*pfwrite) (&bsend, 1))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Clobber and free the login and password names that came from
|
|||
|
the call out file. We probably shouldn't even keep them around
|
|||
|
this long. */
|
|||
|
|
|||
|
if (zcallout_login != NULL)
|
|||
|
{
|
|||
|
bzero (zcallout_login, strlen (zcallout_login));
|
|||
|
xfree ((pointer) zcallout_login);
|
|||
|
}
|
|||
|
if (zcallout_pass != NULL)
|
|||
|
{
|
|||
|
bzero (zcallout_pass, strlen (zcallout_pass));
|
|||
|
xfree ((pointer) zcallout_pass);
|
|||
|
}
|
|||
|
|
|||
|
/* Output a final carriage return, unless there was a \c. Don't
|
|||
|
bother to check for an echo. */
|
|||
|
if (! fnocr)
|
|||
|
{
|
|||
|
char b;
|
|||
|
|
|||
|
b = '\r';
|
|||
|
fquote = fcsend_debug (fquote, 1, &b);
|
|||
|
if (! fport_write (&b, 1))
|
|||
|
{
|
|||
|
ucsend_debug_end (fquote, TRUE);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ucsend_debug_end (fquote, FALSE);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Write out a phone number with optional dialcode translation. The
|
|||
|
pfquote argument is only used for debugging. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fcphone (qdial, zphone, pfwrite, ftranslate, pfquote)
|
|||
|
const struct sdialer *qdial;
|
|||
|
const char *zphone;
|
|||
|
boolean (*pfwrite) P((const char *zwrite, int cwrite));
|
|||
|
boolean ftranslate;
|
|||
|
boolean *pfquote;
|
|||
|
{
|
|||
|
const char *zprefix, *zsuffix;
|
|||
|
|
|||
|
if (ftranslate)
|
|||
|
{
|
|||
|
if (! fctranslate (zphone, &zprefix, &zsuffix))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
zprefix = zphone;
|
|||
|
zsuffix = NULL;
|
|||
|
}
|
|||
|
|
|||
|
while (zprefix != NULL)
|
|||
|
{
|
|||
|
while (TRUE)
|
|||
|
{
|
|||
|
const char *z;
|
|||
|
const char *zstr;
|
|||
|
|
|||
|
z = zprefix + strcspn (zprefix, "=-");
|
|||
|
if (z > zprefix)
|
|||
|
{
|
|||
|
*pfquote = fcsend_debug (*pfquote, z - zprefix, zprefix);
|
|||
|
if (! (*pfwrite) (zprefix, z - zprefix))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (*z == '=')
|
|||
|
zstr = qdial->zdialtone;
|
|||
|
else if (*z == '-')
|
|||
|
zstr = qdial->zpause;
|
|||
|
else /* *z == '\0' */
|
|||
|
break;
|
|||
|
|
|||
|
if (zstr != NULL)
|
|||
|
{
|
|||
|
*pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr);
|
|||
|
if (! (*pfwrite) (zstr, strlen (zstr)))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
zprefix = z + 1;
|
|||
|
}
|
|||
|
|
|||
|
zprefix = zsuffix;
|
|||
|
zsuffix = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Given a phone number, run it through dial code translation
|
|||
|
returning two strings. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fctranslate (zphone, pzprefix, pzsuffix)
|
|||
|
const char *zphone;
|
|||
|
const char **pzprefix;
|
|||
|
const char **pzsuffix;
|
|||
|
{
|
|||
|
char *zdialcode, *zto;
|
|||
|
const char *zfrom;
|
|||
|
|
|||
|
*pzprefix = zphone;
|
|||
|
*pzsuffix = NULL;
|
|||
|
|
|||
|
if (zDialcodefile == NULL)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
zdialcode = (char *) alloca (strlen (zphone) + 1);
|
|||
|
zfrom = zphone;
|
|||
|
zto = zdialcode;
|
|||
|
while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom)))
|
|||
|
*zto++ = *zfrom++;
|
|||
|
*zto = '\0';
|
|||
|
|
|||
|
if (*zdialcode != '\0')
|
|||
|
{
|
|||
|
struct smulti_file *qmulti;
|
|||
|
struct scmdtab as[2];
|
|||
|
char *zpre;
|
|||
|
|
|||
|
qmulti = qmulti_open (zDialcodefile);
|
|||
|
if (qmulti == NULL)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
as[0].zcmd = zdialcode;
|
|||
|
as[0].itype = CMDTABTYPE_STRING;
|
|||
|
as[0].pvar = (pointer) &zpre;
|
|||
|
as[0].ptfn = NULL;
|
|||
|
as[1].zcmd = NULL;
|
|||
|
|
|||
|
zpre = NULL;
|
|||
|
|
|||
|
uprocesscmds ((FILE *) NULL, qmulti, as, (const char *) NULL,
|
|||
|
CMDFLAG_BACKSLASH);
|
|||
|
|
|||
|
(void) fmulti_close (qmulti);
|
|||
|
|
|||
|
if (zpre == NULL)
|
|||
|
ulog (LOG_ERROR, "Unknown dial code %s", zdialcode);
|
|||
|
else
|
|||
|
{
|
|||
|
*pzprefix = zpre;
|
|||
|
*pzsuffix = zfrom;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Write out a string making sure the each character is echoed back. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fcecho_send (zwrite, cwrite)
|
|||
|
const char *zwrite;
|
|||
|
int cwrite;
|
|||
|
{
|
|||
|
const char *zend;
|
|||
|
|
|||
|
zend = zwrite + cwrite;
|
|||
|
|
|||
|
for (; zwrite < zend; zwrite++)
|
|||
|
{
|
|||
|
int b;
|
|||
|
|
|||
|
if (! fport_write (zwrite, 1))
|
|||
|
return FALSE;
|
|||
|
do
|
|||
|
{
|
|||
|
/* We arbitrarily wait five seconds for the echo. */
|
|||
|
b = breceive_char (5, TRUE);
|
|||
|
/* Now b == -1 on timeout, -2 on error. */
|
|||
|
if (b < 0)
|
|||
|
{
|
|||
|
if (b == -1)
|
|||
|
ulog (LOG_ERROR, "Character not echoed");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
while (b != BUCHAR (*zwrite));
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/* Run a chat program. Expand any escape sequences and call a system
|
|||
|
dependent program to run it. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fcprogram (zprogram, qsys, qdial, zphone, zport, ibaud)
|
|||
|
const char *zprogram;
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
const struct sdialer *qdial;
|
|||
|
const char *zphone;
|
|||
|
const char *zport;
|
|||
|
long ibaud;
|
|||
|
{
|
|||
|
char *zbuf;
|
|||
|
int calc, clen;
|
|||
|
char *zto;
|
|||
|
const char *zfrom;
|
|||
|
char *zcallout_login;
|
|||
|
char *zcallout_pass;
|
|||
|
boolean fret;
|
|||
|
|
|||
|
zcallout_login = NULL;
|
|||
|
zcallout_pass = NULL;
|
|||
|
|
|||
|
/* Copy the string into memory expanding escape sequences. */
|
|||
|
|
|||
|
zbuf = (char *) xmalloc (1);
|
|||
|
calc = 1;
|
|||
|
clen = 0;
|
|||
|
zto = zbuf;
|
|||
|
for (zfrom = zprogram; *zfrom != '\0'; zfrom++)
|
|||
|
{
|
|||
|
const char *zadd;
|
|||
|
int cadd;
|
|||
|
|
|||
|
if (*zfrom != '\\')
|
|||
|
{
|
|||
|
if (clen + 2 > calc)
|
|||
|
{
|
|||
|
calc = clen + 80;
|
|||
|
zbuf = (char *) xrealloc ((pointer) zbuf, calc);
|
|||
|
zto = zbuf + clen;
|
|||
|
}
|
|||
|
*zto++ = *zfrom;
|
|||
|
++clen;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
++zfrom;
|
|||
|
switch (*zfrom)
|
|||
|
{
|
|||
|
case '\0':
|
|||
|
--zfrom;
|
|||
|
/* Fall through. */
|
|||
|
case '\\':
|
|||
|
zadd = "\\";
|
|||
|
break;
|
|||
|
case 'L':
|
|||
|
{
|
|||
|
const char *zlog;
|
|||
|
|
|||
|
if (qsys == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\L");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zlog = qsys->zcall_login;
|
|||
|
if (zlog == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: No login defined");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (zlog[0] == '*' && zlog[1] == '\0')
|
|||
|
{
|
|||
|
if (zcallout_login == NULL
|
|||
|
&& ! fcallout_login (qsys, &zcallout_login,
|
|||
|
&zcallout_pass))
|
|||
|
return FALSE;
|
|||
|
zlog = zcallout_login;
|
|||
|
}
|
|||
|
zadd = zlog;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'P':
|
|||
|
{
|
|||
|
const char *zpass;
|
|||
|
|
|||
|
if (qsys == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\P");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zpass = qsys->zcall_password;
|
|||
|
if (zpass == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: No password defined");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (zpass[0] == '*' && zpass[1] == '\0')
|
|||
|
{
|
|||
|
if (zcallout_pass == NULL
|
|||
|
&& ! fcallout_login (qsys, &zcallout_login,
|
|||
|
&zcallout_pass))
|
|||
|
return FALSE;
|
|||
|
zpass = zcallout_pass;
|
|||
|
}
|
|||
|
zadd = zpass;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'D':
|
|||
|
if (qdial == NULL || zphone == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\D");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zadd = zphone;
|
|||
|
break;
|
|||
|
case 'T':
|
|||
|
{
|
|||
|
const char *zprefix, *zsuffix;
|
|||
|
|
|||
|
if (qdial == NULL || zphone == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\T");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (! fctranslate (zphone, &zprefix, &zsuffix))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (zsuffix == NULL)
|
|||
|
zadd = zprefix;
|
|||
|
else
|
|||
|
{
|
|||
|
int cprefix;
|
|||
|
|
|||
|
cprefix = strlen (zprefix);
|
|||
|
if (clen + cprefix + 1 > calc)
|
|||
|
{
|
|||
|
calc = clen + cprefix + 20;
|
|||
|
zbuf = (char *) xrealloc ((pointer) zbuf, calc);
|
|||
|
zto = zbuf + clen;
|
|||
|
}
|
|||
|
strcpy (zto, zprefix);
|
|||
|
zto += cprefix;
|
|||
|
clen += cprefix;
|
|||
|
zadd = zsuffix;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'Y':
|
|||
|
if (zLdevice == NULL && zport == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\Y");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
/* zLdevice will generally make more sense than zport, but
|
|||
|
it might not be set yet. */
|
|||
|
zadd = zLdevice;
|
|||
|
if (zadd == NULL)
|
|||
|
zadd = zport;
|
|||
|
break;
|
|||
|
case 'Z':
|
|||
|
if (qsys == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\Z");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zadd = qsys->zname;
|
|||
|
break;
|
|||
|
case 'S':
|
|||
|
{
|
|||
|
char *zalc;
|
|||
|
|
|||
|
if (ibaud == 0)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "chat-program: Illegal use of \\S");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
zalc = (char *) alloca (15);
|
|||
|
sprintf (zalc, "%ld", ibaud);
|
|||
|
zadd = zalc;
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
{
|
|||
|
char *zset;
|
|||
|
|
|||
|
ulog (LOG_ERROR,
|
|||
|
"chat-program: Unrecognized escape sequence \\%c",
|
|||
|
*zfrom);
|
|||
|
zset = (char *) alloca (2);
|
|||
|
zset[0] = *zfrom;
|
|||
|
zset[1] = '\0';
|
|||
|
zadd = zset;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
cadd = strlen (zadd);
|
|||
|
if (clen + cadd + 1 > calc)
|
|||
|
{
|
|||
|
calc = clen + cadd + 20;
|
|||
|
zbuf = (char *) xrealloc ((pointer) zbuf, calc);
|
|||
|
zto = zbuf + clen;
|
|||
|
}
|
|||
|
strcpy (zto, zadd);
|
|||
|
zto += cadd;
|
|||
|
clen += cadd;
|
|||
|
}
|
|||
|
|
|||
|
*zto = '\0';
|
|||
|
|
|||
|
/* Invoke the program. */
|
|||
|
|
|||
|
fret = fport_run_chat (zbuf);
|
|||
|
|
|||
|
xfree ((pointer) zbuf);
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|