553 lines
13 KiB
C
553 lines
13 KiB
C
|
/* conn.c
|
|||
|
Connection routines for the Taylor 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 Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
|
|||
|
*/
|
|||
|
|
|||
|
#include "uucp.h"
|
|||
|
|
|||
|
#if USE_RCS_ID
|
|||
|
const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/04 19:30:39 jtc Exp $";
|
|||
|
#endif
|
|||
|
|
|||
|
#include <ctype.h>
|
|||
|
|
|||
|
#include "uudefs.h"
|
|||
|
#include "uuconf.h"
|
|||
|
#include "conn.h"
|
|||
|
|
|||
|
static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf,
|
|||
|
struct uuconf_dialer *qdialer,
|
|||
|
const char *zphone, boolean ftranslate));
|
|||
|
|
|||
|
/* Create a new connection. This relies on system dependent functions
|
|||
|
to set the qcmds and psysdep fields. If qport is NULL, it opens a
|
|||
|
standard input port. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_init (qport, qconn)
|
|||
|
struct uuconf_port *qport;
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
qconn->qport = qport;
|
|||
|
switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype)
|
|||
|
{
|
|||
|
case UUCONF_PORTTYPE_STDIN:
|
|||
|
return fsysdep_stdin_init (qconn);
|
|||
|
case UUCONF_PORTTYPE_MODEM:
|
|||
|
return fsysdep_modem_init (qconn);
|
|||
|
case UUCONF_PORTTYPE_DIRECT:
|
|||
|
return fsysdep_direct_init (qconn);
|
|||
|
#if HAVE_TCP
|
|||
|
case UUCONF_PORTTYPE_TCP:
|
|||
|
return fsysdep_tcp_init (qconn);
|
|||
|
#endif
|
|||
|
#if HAVE_TLI
|
|||
|
case UUCONF_PORTTYPE_TLI:
|
|||
|
return fsysdep_tli_init (qconn);
|
|||
|
#endif
|
|||
|
default:
|
|||
|
ulog (LOG_ERROR, "Unknown port type");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Connection dispatch routines. */
|
|||
|
|
|||
|
/* Free a connection. */
|
|||
|
|
|||
|
void
|
|||
|
uconn_free (qconn)
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
(*qconn->qcmds->pufree) (qconn);
|
|||
|
}
|
|||
|
|
|||
|
/* Lock a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_lock (qconn, fin)
|
|||
|
struct sconnection *qconn;
|
|||
|
boolean fin;
|
|||
|
{
|
|||
|
boolean (*pflock) P((struct sconnection *, boolean));
|
|||
|
|
|||
|
pflock = qconn->qcmds->pflock;
|
|||
|
if (pflock == NULL)
|
|||
|
return TRUE;
|
|||
|
return (*pflock) (qconn, fin);
|
|||
|
}
|
|||
|
|
|||
|
/* Unlock a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_unlock (qconn)
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
boolean (*pfunlock) P((struct sconnection *));
|
|||
|
|
|||
|
pfunlock = qconn->qcmds->pfunlock;
|
|||
|
if (pfunlock == NULL)
|
|||
|
return TRUE;
|
|||
|
return (*pfunlock) (qconn);
|
|||
|
}
|
|||
|
|
|||
|
/* Open a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_open (qconn, ibaud, ihighbaud, fwait)
|
|||
|
struct sconnection *qconn;
|
|||
|
long ibaud;
|
|||
|
long ihighbaud;
|
|||
|
boolean fwait;
|
|||
|
{
|
|||
|
boolean fret;
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_PORT))
|
|||
|
{
|
|||
|
char abspeed[20];
|
|||
|
|
|||
|
if (ibaud == (long) 0)
|
|||
|
strcpy (abspeed, "default speed");
|
|||
|
else
|
|||
|
sprintf (abspeed, "speed %ld", ibaud);
|
|||
|
|
|||
|
if (qconn->qport == NULL)
|
|||
|
ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)",
|
|||
|
abspeed);
|
|||
|
else if (qconn->qport->uuconf_zname == NULL)
|
|||
|
ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)",
|
|||
|
abspeed);
|
|||
|
else
|
|||
|
ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)",
|
|||
|
qconn->qport->uuconf_zname, abspeed);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/* If the system provides a range of baud rates, we select the
|
|||
|
highest baud rate supported by the port. */
|
|||
|
if (ihighbaud != 0 && qconn->qport != NULL)
|
|||
|
{
|
|||
|
struct uuconf_port *qport;
|
|||
|
|
|||
|
qport = qconn->qport;
|
|||
|
ibaud = ihighbaud;
|
|||
|
if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
|
|||
|
{
|
|||
|
if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0)
|
|||
|
{
|
|||
|
if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud)
|
|||
|
ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud;
|
|||
|
}
|
|||
|
else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0)
|
|||
|
ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
|
|||
|
}
|
|||
|
else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
|
|||
|
{
|
|||
|
if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0)
|
|||
|
ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* This will normally be overridden by the port specific open
|
|||
|
routine. */
|
|||
|
if (qconn->qport == NULL)
|
|||
|
ulog_device ("stdin");
|
|||
|
else
|
|||
|
ulog_device (qconn->qport->uuconf_zname);
|
|||
|
|
|||
|
fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait);
|
|||
|
|
|||
|
if (! fret)
|
|||
|
ulog_device ((const char *) NULL);
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|
|||
|
|
|||
|
/* Close a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_close (qconn, puuconf, qdialer, fsuccess)
|
|||
|
struct sconnection *qconn;
|
|||
|
pointer puuconf;
|
|||
|
struct uuconf_dialer *qdialer;
|
|||
|
boolean fsuccess;
|
|||
|
{
|
|||
|
boolean fret;
|
|||
|
|
|||
|
DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection");
|
|||
|
|
|||
|
/* Don't report hangup signals while we're closing. */
|
|||
|
fLog_sighup = FALSE;
|
|||
|
|
|||
|
fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess);
|
|||
|
|
|||
|
/* Make sure any signal reporting has been done before we set
|
|||
|
fLog_sighup back to TRUE. */
|
|||
|
ulog (LOG_ERROR, (const char *) NULL);
|
|||
|
fLog_sighup = TRUE;
|
|||
|
|
|||
|
ulog_device ((const char *) NULL);
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|
|||
|
|
|||
|
/* Reset the connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_reset (qconn)
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection");
|
|||
|
|
|||
|
return (*qconn->qcmds->pfreset) (qconn);
|
|||
|
}
|
|||
|
|
|||
|
/* Dial out on the connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
|
|||
|
struct sconnection *qconn;
|
|||
|
pointer puuconf;
|
|||
|
const struct uuconf_system *qsys;
|
|||
|
const char *zphone;
|
|||
|
struct uuconf_dialer *qdialer;
|
|||
|
enum tdialerfound *ptdialerfound;
|
|||
|
{
|
|||
|
struct uuconf_dialer sdialer;
|
|||
|
enum tdialerfound tfound;
|
|||
|
boolean (*pfdial) P((struct sconnection *, pointer,
|
|||
|
const struct uuconf_system *, const char *,
|
|||
|
struct uuconf_dialer *, enum tdialerfound *));
|
|||
|
|
|||
|
if (qdialer == NULL)
|
|||
|
qdialer = &sdialer;
|
|||
|
if (ptdialerfound == NULL)
|
|||
|
ptdialerfound = &tfound;
|
|||
|
|
|||
|
qdialer->uuconf_zname = NULL;
|
|||
|
*ptdialerfound = DIALERFOUND_FALSE;
|
|||
|
|
|||
|
pfdial = qconn->qcmds->pfdial;
|
|||
|
if (pfdial == NULL)
|
|||
|
return TRUE;
|
|||
|
return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound);
|
|||
|
}
|
|||
|
|
|||
|
/* Read data from the connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
|
|||
|
struct sconnection *qconn;
|
|||
|
char *zbuf;
|
|||
|
size_t *pclen;
|
|||
|
size_t cmin;
|
|||
|
int ctimeout;
|
|||
|
boolean freport;
|
|||
|
{
|
|||
|
boolean fret;
|
|||
|
|
|||
|
fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout,
|
|||
|
freport);
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_INCOMING))
|
|||
|
udebug_buffer ("fconn_read: Read", zbuf, *pclen);
|
|||
|
else if (FDEBUGGING (DEBUG_PORT))
|
|||
|
ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen);
|
|||
|
#endif
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|
|||
|
|
|||
|
/* Write data to the connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_write (qconn, zbuf, clen)
|
|||
|
struct sconnection *qconn;
|
|||
|
const char *zbuf;
|
|||
|
size_t clen;
|
|||
|
{
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_OUTGOING))
|
|||
|
udebug_buffer ("fconn_write: Writing", zbuf, clen);
|
|||
|
else if (FDEBUGGING (DEBUG_PORT))
|
|||
|
ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen);
|
|||
|
#endif
|
|||
|
|
|||
|
return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen);
|
|||
|
}
|
|||
|
|
|||
|
/* Read and write data. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_io (qconn, zwrite, pcwrite, zread, pcread)
|
|||
|
struct sconnection *qconn;
|
|||
|
const char *zwrite;
|
|||
|
size_t *pcwrite;
|
|||
|
char *zread;
|
|||
|
size_t *pcread;
|
|||
|
{
|
|||
|
boolean fret;
|
|||
|
#if DEBUG > 1
|
|||
|
size_t cwrite = *pcwrite;
|
|||
|
size_t cread = *pcread;
|
|||
|
|
|||
|
if (cread == 0 || cwrite == 0)
|
|||
|
ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu",
|
|||
|
(unsigned long) cread, (unsigned long) cwrite);
|
|||
|
#endif
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (FDEBUGGING (DEBUG_OUTGOING))
|
|||
|
udebug_buffer ("fconn_io: Writing", zwrite, cwrite);
|
|||
|
#endif
|
|||
|
|
|||
|
fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread);
|
|||
|
|
|||
|
DEBUG_MESSAGE4 (DEBUG_PORT,
|
|||
|
"fconn_io: Wrote %lu of %lu, read %lu of %lu",
|
|||
|
(unsigned long) *pcwrite, (unsigned long) cwrite,
|
|||
|
(unsigned long) *pcread, (unsigned long) cread);
|
|||
|
|
|||
|
#if DEBUG > 1
|
|||
|
if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
|
|||
|
udebug_buffer ("fconn_io: Read", zread, *pcread);
|
|||
|
#endif
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|
|||
|
|
|||
|
/* Send a break character to a connection. Some port types may not
|
|||
|
support break characters, in which case we just return TRUE. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_break (qconn)
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
boolean (*pfbreak) P((struct sconnection *));
|
|||
|
|
|||
|
pfbreak = *qconn->qcmds->pfbreak;
|
|||
|
if (pfbreak == NULL)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character");
|
|||
|
|
|||
|
return (*pfbreak) (qconn);
|
|||
|
}
|
|||
|
|
|||
|
/* Change the setting of a connection. Some port types may not
|
|||
|
support this, in which case we just return TRUE. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_set (qconn, tparity, tstrip, txonxoff)
|
|||
|
struct sconnection *qconn;
|
|||
|
enum tparitysetting tparity;
|
|||
|
enum tstripsetting tstrip;
|
|||
|
enum txonxoffsetting txonxoff;
|
|||
|
{
|
|||
|
boolean (*pfset) P((struct sconnection *, enum tparitysetting,
|
|||
|
enum tstripsetting, enum txonxoffsetting));
|
|||
|
|
|||
|
pfset = qconn->qcmds->pfset;
|
|||
|
if (pfset == NULL)
|
|||
|
return TRUE;
|
|||
|
|
|||
|
DEBUG_MESSAGE3 (DEBUG_PORT,
|
|||
|
"fconn_set: Changing setting to %d, %d, %d",
|
|||
|
(int) tparity, (int) tstrip, (int) txonxoff);
|
|||
|
|
|||
|
return (*pfset) (qconn, tparity, tstrip, txonxoff);
|
|||
|
}
|
|||
|
|
|||
|
/* Require or ignore carrier on a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_carrier (qconn, fcarrier)
|
|||
|
struct sconnection *qconn;
|
|||
|
boolean fcarrier;
|
|||
|
{
|
|||
|
boolean (*pfcarrier) P((struct sconnection *, boolean));
|
|||
|
|
|||
|
pfcarrier = qconn->qcmds->pfcarrier;
|
|||
|
if (pfcarrier == NULL)
|
|||
|
return TRUE;
|
|||
|
return (*pfcarrier) (qconn, fcarrier);
|
|||
|
}
|
|||
|
|
|||
|
/* Run a chat program on a connection. */
|
|||
|
|
|||
|
boolean
|
|||
|
fconn_run_chat (qconn, pzprog)
|
|||
|
struct sconnection *qconn;
|
|||
|
char **pzprog;
|
|||
|
{
|
|||
|
return (*qconn->qcmds->pfchat) (qconn, pzprog);
|
|||
|
}
|
|||
|
|
|||
|
/* Get the baud rate of a connection. */
|
|||
|
|
|||
|
long
|
|||
|
iconn_baud (qconn)
|
|||
|
struct sconnection *qconn;
|
|||
|
{
|
|||
|
long (*pibaud) P((struct sconnection *));
|
|||
|
|
|||
|
pibaud = qconn->qcmds->pibaud;
|
|||
|
if (pibaud == NULL)
|
|||
|
return 0;
|
|||
|
return (*pibaud) (qconn);
|
|||
|
}
|
|||
|
|
|||
|
/* Modem dialing routines. */
|
|||
|
|
|||
|
/*ARGSUSED*/
|
|||
|
boolean
|
|||
|
fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
|
|||
|
struct sconnection *qconn;
|
|||
|
pointer puuconf;
|
|||
|
const struct uuconf_system *qsys;
|
|||
|
const char *zphone;
|
|||
|
struct uuconf_dialer *qdialer;
|
|||
|
enum tdialerfound *ptdialerfound;
|
|||
|
{
|
|||
|
*ptdialerfound = DIALERFOUND_FALSE;
|
|||
|
|
|||
|
if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
|
|||
|
{
|
|||
|
char **pz;
|
|||
|
boolean ffirst;
|
|||
|
|
|||
|
/* The pzdialer field is a sequence of dialer/token pairs. The
|
|||
|
dialer portion names a dialer to use. The token portion is
|
|||
|
what \D and \T in the chat script expand to. If there is no
|
|||
|
token for the last dialer, the phone number for the system is
|
|||
|
used. */
|
|||
|
ffirst = TRUE;
|
|||
|
pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
|
|||
|
while (*pz != NULL)
|
|||
|
{
|
|||
|
int iuuconf;
|
|||
|
struct uuconf_dialer *q;
|
|||
|
struct uuconf_dialer s;
|
|||
|
const char *ztoken;
|
|||
|
boolean ftranslate;
|
|||
|
|
|||
|
if (! ffirst)
|
|||
|
q = &s;
|
|||
|
else
|
|||
|
q = qdialer;
|
|||
|
|
|||
|
iuuconf = uuconf_dialer_info (puuconf, *pz, q);
|
|||
|
if (iuuconf == UUCONF_NOT_FOUND)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: Dialer not found", *pz);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
else if (iuuconf != UUCONF_SUCCESS)
|
|||
|
{
|
|||
|
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
++pz;
|
|||
|
ztoken = *pz;
|
|||
|
|
|||
|
ftranslate = FALSE;
|
|||
|
if (ztoken == NULL
|
|||
|
|| strcmp (ztoken, "\\D") == 0)
|
|||
|
ztoken = zphone;
|
|||
|
else if (strcmp (ztoken, "\\T") == 0)
|
|||
|
{
|
|||
|
ztoken = zphone;
|
|||
|
ftranslate = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate))
|
|||
|
{
|
|||
|
(void) uuconf_dialer_free (puuconf, q);
|
|||
|
if (! ffirst)
|
|||
|
(void) uuconf_dialer_free (puuconf, qdialer);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (ffirst)
|
|||
|
{
|
|||
|
*ptdialerfound = DIALERFOUND_FREE;
|
|||
|
ffirst = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
(void) uuconf_dialer_free (puuconf, q);
|
|||
|
|
|||
|
if (*pz != NULL)
|
|||
|
++pz;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL)
|
|||
|
{
|
|||
|
struct uuconf_dialer *q;
|
|||
|
|
|||
|
q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
|
|||
|
*qdialer = *q;
|
|||
|
*ptdialerfound = DIALERFOUND_TRUE;
|
|||
|
return fcdo_dial (qconn, puuconf, q, zphone, FALSE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "No dialer information");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Actually use a dialer. We set up the modem (which may include
|
|||
|
opening the dialer device), run the chat script, and finish dealing
|
|||
|
with the modem. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate)
|
|||
|
struct sconnection *qconn;
|
|||
|
pointer puuconf;
|
|||
|
struct uuconf_dialer *qdial;
|
|||
|
const char *zphone;
|
|||
|
boolean ftranslate;
|
|||
|
{
|
|||
|
const char *zname;
|
|||
|
|
|||
|
if (! fsysdep_modem_begin_dial (qconn, qdial))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
if (qconn->qport == NULL)
|
|||
|
zname = NULL;
|
|||
|
else
|
|||
|
zname = qconn->qport->uuconf_zname;
|
|||
|
|
|||
|
if (! fchat (qconn, puuconf, &qdial->uuconf_schat,
|
|||
|
(const struct uuconf_system *) NULL, qdial,
|
|||
|
zphone, ftranslate, zname, iconn_baud (qconn)))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
return fsysdep_modem_end_dial (qconn, qdial);
|
|||
|
}
|