603 lines
14 KiB
C
603 lines
14 KiB
C
/* port.c
|
||
Port manipulation 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 AIRS, P.O. Box 520, Waltham, MA 02254.
|
||
|
||
$Log: port.c,v $
|
||
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
||
initial import of 386bsd-0.1 sources
|
||
|
||
Revision 1.17 1992/04/01 22:31:05 ian
|
||
Initialize stdin port
|
||
|
||
Revision 1.16 1992/03/28 19:57:22 ian
|
||
David J. MacKenzie: send port device for /Y rather than port name
|
||
|
||
Revision 1.15 1992/03/17 01:03:03 ian
|
||
Miscellaneous cleanup
|
||
|
||
Revision 1.14 1992/03/15 06:58:12 ian
|
||
Show fport_read and fport_write calls under DEBUG_PORT
|
||
|
||
Revision 1.13 1992/03/12 19:54:43 ian
|
||
Debugging based on types rather than number
|
||
|
||
Revision 1.12 1992/03/04 00:36:44 ian
|
||
Michael Richardson: better chat script debugging
|
||
|
||
Revision 1.11 1992/02/08 19:34:07 ian
|
||
Cast result of alloca
|
||
|
||
Revision 1.10 1992/02/08 03:54:18 ian
|
||
Include <string.h> only in <uucp.h>, added 1992 copyright
|
||
|
||
Revision 1.9 1991/12/28 04:20:36 ian
|
||
Cleaned up debugging code
|
||
|
||
Revision 1.8 1991/12/20 02:18:35 ian
|
||
Complete diagnostics for fport_io
|
||
|
||
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/10 19:45:05 ian
|
||
Added ulog_device to record device name for log file
|
||
|
||
Revision 1.5 1991/11/14 03:20:13 ian
|
||
Added seven-bit and reliable commands to help when selecting protocols
|
||
|
||
Revision 1.4 1991/11/13 20:38:00 ian
|
||
Added TCP port type for connections over TCP
|
||
|
||
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 00:39:45 ian
|
||
Open port in seven bit mode, added fport_set to change to eight bit
|
||
|
||
Revision 1.1 1991/09/10 19:40:31 ian
|
||
Initial revision
|
||
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#if USE_RCS_ID
|
||
char port_rcsid[] = "$Id: port.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
||
#endif
|
||
|
||
#include <ctype.h>
|
||
|
||
#include "port.h"
|
||
|
||
#if DEBUG > 1
|
||
|
||
/* A debugging routine used when displaying buffers. */
|
||
|
||
int
|
||
cdebug_char (z, ichar)
|
||
char *z;
|
||
int ichar;
|
||
{
|
||
char b;
|
||
|
||
if (isprint (BUCHAR (ichar))
|
||
&& ichar != '\"'
|
||
&& ichar != '\\')
|
||
{
|
||
*z++ = (char) ichar;
|
||
*z = '\0';
|
||
return 1;
|
||
}
|
||
|
||
*z++ = '\\';
|
||
|
||
switch (ichar)
|
||
{
|
||
case '\n':
|
||
b = 'n';
|
||
break;
|
||
case '\r':
|
||
b = 'r';
|
||
break;
|
||
case '\"':
|
||
b = '\"';
|
||
break;
|
||
case '\\':
|
||
b = '\\';
|
||
break;
|
||
default:
|
||
sprintf (z, "%03o", (unsigned int) BUCHAR (ichar));
|
||
return strlen (z) + 1;
|
||
}
|
||
|
||
*z++ = b;
|
||
*z = '\0';
|
||
return 2;
|
||
}
|
||
|
||
/* Display a buffer when debugging. */
|
||
|
||
void
|
||
udebug_buffer (zhdr, zbuf, clen)
|
||
const char *zhdr;
|
||
const char *zbuf;
|
||
int clen;
|
||
{
|
||
char *z, *zalc;
|
||
int i;
|
||
|
||
z = zalc = (char *) xmalloc (clen * 4 + 1);
|
||
for (i = 0; i < clen && i < 80; i++)
|
||
z += cdebug_char (z, zbuf[i]);
|
||
if (i < clen)
|
||
{
|
||
*z++ = '.';
|
||
*z++ = '.';
|
||
*z++ = '.';
|
||
}
|
||
*z = '\0';
|
||
|
||
ulog (LOG_DEBUG, "%s %d \"%s\"", zhdr, clen, zalc);
|
||
xfree ((pointer) zalc);
|
||
}
|
||
|
||
#endif /* DEBUG > 1 */
|
||
|
||
/* The open port. */
|
||
|
||
struct sport *qPort;
|
||
|
||
/* The port dispatch table. The order of entries in this table must
|
||
be the same as the tporttype enumeration. */
|
||
|
||
const struct sportcmds asPortcmds[] =
|
||
{
|
||
{ fsysdep_stdin_lock, fsysdep_stdin_open, fsysdep_stdin_close,
|
||
fsysdep_stdin_reset, NULL, fsysdep_stdin_read,
|
||
fsysdep_stdin_write, fsysdep_stdin_io, fsysdep_stdin_break,
|
||
fsysdep_stdin_set, fsysdep_stdin_chat, isysdep_stdin_baud },
|
||
{ fsysdep_modem_lock, fsysdep_modem_open, fsysdep_modem_close,
|
||
fsysdep_modem_reset, fmodem_dial, fsysdep_modem_read,
|
||
fsysdep_modem_write, fsysdep_modem_io, fsysdep_modem_break,
|
||
fsysdep_modem_set, fsysdep_modem_chat, isysdep_modem_baud },
|
||
{ fsysdep_direct_lock, fsysdep_direct_open, fsysdep_direct_close,
|
||
fsysdep_direct_reset, NULL, fsysdep_direct_read,
|
||
fsysdep_direct_write, fsysdep_direct_io, fsysdep_direct_break,
|
||
fsysdep_direct_set, fsysdep_direct_chat, isysdep_direct_baud },
|
||
#if HAVE_TCP
|
||
{ ftcp_lock, ftcp_open, ftcp_close,
|
||
ftcp_reset, ftcp_dial, fsysdep_tcp_read,
|
||
fsysdep_tcp_write, fsysdep_tcp_io, NULL,
|
||
NULL, fsysdep_tcp_chat, itcp_baud },
|
||
#endif /* HAVE_TCP */
|
||
};
|
||
|
||
/* Port dispatch routines. These could probably become macros,
|
||
although the port argument would have to be evaluated twice. */
|
||
|
||
/* Lock a port. */
|
||
|
||
boolean
|
||
fport_lock (qport, fin)
|
||
struct sport *qport;
|
||
boolean fin;
|
||
{
|
||
return (*asPortcmds[(int) qport->ttype].pflock) (qport, fin);
|
||
}
|
||
|
||
/* The port structure we use when opening standard input as a port. */
|
||
|
||
static struct sport sPstdin =
|
||
{
|
||
"stdin",
|
||
PORTTYPE_STDIN,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NULL
|
||
};
|
||
|
||
/* Open a port. */
|
||
|
||
boolean
|
||
fport_open (qport, ibaud, ihighbaud, fwait)
|
||
struct sport *qport;
|
||
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 (qport == NULL)
|
||
ulog (LOG_DEBUG, "fport_open: Opening stdin port (%s)",
|
||
abspeed);
|
||
else if (qport->zname == NULL)
|
||
ulog (LOG_DEBUG, "fport_open: Opening unnamed port (%s)",
|
||
abspeed);
|
||
else
|
||
ulog (LOG_DEBUG, "fport_open: Opening port %s (%s)",
|
||
qport->zname, abspeed);
|
||
}
|
||
#endif
|
||
|
||
if (qport == NULL)
|
||
{
|
||
qport = &sPstdin;
|
||
SYSDEP_STDIN_INIT (&qport->u.sstdin.s);
|
||
}
|
||
qPort = NULL;
|
||
|
||
/* If the system provides a range of baud rates, we select the
|
||
highest baud rate supported by the port. */
|
||
if (ihighbaud != 0)
|
||
{
|
||
ibaud = ihighbaud;
|
||
if (qport->ttype == PORTTYPE_MODEM)
|
||
{
|
||
if (qport->u.smodem.ihighbaud != 0)
|
||
{
|
||
if (qport->u.smodem.ihighbaud < ihighbaud)
|
||
ibaud = qport->u.smodem.ihighbaud;
|
||
}
|
||
else if (qport->u.smodem.ibaud != 0)
|
||
ibaud = qport->u.smodem.ibaud;
|
||
}
|
||
else if (qport->ttype == PORTTYPE_DIRECT)
|
||
{
|
||
if (qport->u.sdirect.ibaud != 0)
|
||
ibaud = qport->u.sdirect.ibaud;
|
||
}
|
||
}
|
||
|
||
/* This will normally be overridden by the port specific open
|
||
routine. */
|
||
ulog_device (qport->zname);
|
||
|
||
fret = (*asPortcmds[(int) qport->ttype].pfopen) (qport, ibaud, fwait);
|
||
if (fret)
|
||
qPort = qport;
|
||
else
|
||
ulog_device ((const char *) NULL);
|
||
return fret;
|
||
}
|
||
|
||
/* Close and unlock the port. */
|
||
|
||
boolean
|
||
fport_close (fsuccess)
|
||
boolean fsuccess;
|
||
{
|
||
boolean fret;
|
||
|
||
if (qPort == NULL)
|
||
return TRUE;
|
||
|
||
DEBUG_MESSAGE0 (DEBUG_PORT, "fport_close: Closing port");
|
||
|
||
fret = (*asPortcmds[(int) qPort->ttype].pfclose) (qPort, fsuccess);
|
||
qPort = NULL;
|
||
ulog_device ((const char *) NULL);
|
||
return fret;
|
||
}
|
||
|
||
/* Reset the port. */
|
||
|
||
boolean
|
||
fport_reset ()
|
||
{
|
||
DEBUG_MESSAGE0 (DEBUG_PORT, "fport_reset: Resetting port");
|
||
|
||
return (*asPortcmds[(int) qPort->ttype].pfreset) (qPort);
|
||
}
|
||
|
||
/* Dial out on the port. */
|
||
|
||
boolean
|
||
fport_dial (qsys, pcproto_params, pqproto_params, pireliable)
|
||
const struct ssysteminfo *qsys;
|
||
int *pcproto_params;
|
||
struct sproto_param **pqproto_params;
|
||
int *pireliable;
|
||
{
|
||
boolean (*pfdial) P((struct sport *, const struct ssysteminfo *,
|
||
int *, struct sproto_param **, int *));
|
||
|
||
pfdial = asPortcmds[(int) qPort->ttype].pfdial;
|
||
if (pfdial == NULL)
|
||
{
|
||
*pcproto_params = 0;
|
||
*pqproto_params = NULL;
|
||
*pireliable = 0;
|
||
return TRUE;
|
||
}
|
||
return (*pfdial) (qPort, qsys, pcproto_params, pqproto_params,
|
||
pireliable);
|
||
}
|
||
|
||
/* Read data from the port. */
|
||
|
||
boolean
|
||
fport_read (zbuf, pclen, cmin, ctimeout, freport)
|
||
char *zbuf;
|
||
int *pclen;
|
||
int cmin;
|
||
int ctimeout;
|
||
boolean freport;
|
||
{
|
||
boolean fret;
|
||
|
||
fret = (*asPortcmds[(int) qPort->ttype].pfread) (qPort, zbuf, pclen,
|
||
cmin, ctimeout,
|
||
freport);
|
||
#if DEBUG > 1
|
||
if (FDEBUGGING (DEBUG_INCOMING))
|
||
udebug_buffer ("fport_read: Read", zbuf, *pclen);
|
||
else if (FDEBUGGING (DEBUG_PORT))
|
||
ulog (LOG_DEBUG, "fport_read: Read %d", *pclen);
|
||
#endif
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Write data to the port. */
|
||
|
||
boolean
|
||
fport_write (zbuf, clen)
|
||
const char *zbuf;
|
||
int clen;
|
||
{
|
||
#if DEBUG > 1
|
||
if (FDEBUGGING (DEBUG_OUTGOING))
|
||
udebug_buffer ("fport_write: Writing", zbuf, clen);
|
||
else if (FDEBUGGING (DEBUG_PORT))
|
||
ulog (LOG_DEBUG, "fport_write: Writing %d", clen);
|
||
#endif
|
||
|
||
return (*asPortcmds[(int) qPort->ttype].pfwrite) (qPort, zbuf, clen);
|
||
}
|
||
|
||
/* Read and write data. */
|
||
|
||
boolean
|
||
fport_io (zwrite, pcwrite, zread, pcread)
|
||
const char *zwrite;
|
||
int *pcwrite;
|
||
char *zread;
|
||
int *pcread;
|
||
{
|
||
boolean fret;
|
||
#if DEBUG > 1
|
||
int cwrite = *pcwrite;
|
||
int cread = *pcread;
|
||
|
||
if (cread <= 0 || cwrite <= 0)
|
||
ulog (LOG_FATAL, "fport_io: cread %d; cwrite %d", cread, cwrite);
|
||
#endif
|
||
|
||
#if DEBUG > 1
|
||
if (FDEBUGGING (DEBUG_OUTGOING))
|
||
udebug_buffer ("fport_io: Writing", zwrite, cwrite);
|
||
#endif
|
||
|
||
fret = (*asPortcmds[(int) qPort->ttype].pfio) (qPort, zwrite, pcwrite,
|
||
zread, pcread);
|
||
|
||
DEBUG_MESSAGE4 (DEBUG_PORT,
|
||
"fport_io: Wrote %d of %d, read %d of %d",
|
||
*pcwrite, cwrite, *pcread, cread);
|
||
|
||
#if DEBUG > 1
|
||
if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
|
||
udebug_buffer ("fport_io: Read", zread, *pcread);
|
||
#endif
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Send a break character to a port. Some port types may not support
|
||
break characters, in which case we just return TRUE. */
|
||
|
||
boolean
|
||
fport_break ()
|
||
{
|
||
boolean (*pfbreak) P((struct sport *));
|
||
|
||
DEBUG_MESSAGE0 (DEBUG_PORT, "fport_break: Sending break character");
|
||
|
||
pfbreak = asPortcmds[(int) qPort->ttype].pfbreak;
|
||
if (pfbreak == NULL)
|
||
return TRUE;
|
||
return (*pfbreak) (qPort);
|
||
}
|
||
|
||
/* Change the setting of a port. Some port types may not support
|
||
this, in which case we just return TRUE. */
|
||
|
||
boolean
|
||
fport_set (tset)
|
||
enum tportsetting tset;
|
||
{
|
||
boolean (*pfset) P((struct sport *, enum tportsetting));
|
||
|
||
DEBUG_MESSAGE1 (DEBUG_PORT,
|
||
"fport_set: Changing setting to %d", (int) tset);
|
||
|
||
pfset = asPortcmds[(int) qPort->ttype].pfset;
|
||
if (pfset == NULL)
|
||
return TRUE;
|
||
return (*pfset) (qPort, tset);
|
||
}
|
||
|
||
/* Run a chat program on a port. */
|
||
|
||
boolean
|
||
fport_run_chat (zprog)
|
||
const char *zprog;
|
||
{
|
||
return (*asPortcmds[(int) qPort->ttype].pfchat) (qPort, zprog);
|
||
}
|
||
|
||
/* Get the baud rate of a port. */
|
||
|
||
long
|
||
iport_baud ()
|
||
{
|
||
return (*asPortcmds[(int) qPort->ttype].pibaud) (qPort);
|
||
}
|
||
|
||
/* Modem dialing routines. */
|
||
|
||
static boolean fpdo_dial P((struct sdialer *qdial, const char *zphone,
|
||
boolean ftranslate));
|
||
|
||
boolean
|
||
fmodem_dial (qport, qsys, pcproto_params, pqproto_params, pireliable)
|
||
struct sport *qport;
|
||
const struct ssysteminfo *qsys;
|
||
int *pcproto_params;
|
||
struct sproto_param **pqproto_params;
|
||
int *pireliable;
|
||
{
|
||
if (qport->u.smodem.zdialer != NULL)
|
||
{
|
||
char *zcopy, *zdialer;
|
||
boolean ffirst;
|
||
|
||
/* The zdialer string 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;
|
||
*pcproto_params = 0;
|
||
*pqproto_params = NULL;
|
||
*pireliable = 0;
|
||
|
||
zcopy = (char *) alloca (strlen (qport->u.smodem.zdialer) + 1);
|
||
strcpy (zcopy, qport->u.smodem.zdialer);
|
||
|
||
zdialer = strtok (zcopy, " \t");
|
||
while (zdialer != NULL)
|
||
{
|
||
struct sdialer s;
|
||
char *ztoken;
|
||
boolean ftranslate, ftoken;
|
||
|
||
if (! fread_dialer_info (zdialer, &s))
|
||
return FALSE;
|
||
|
||
ztoken = strtok ((char *) NULL, " \t");
|
||
ftoken = ztoken != NULL;
|
||
|
||
ftranslate = FALSE;
|
||
if (ztoken == NULL
|
||
|| strcmp (ztoken, "\\D") == 0)
|
||
ztoken = qsys->zphone;
|
||
else if (strcmp (ztoken, "\\T") == 0)
|
||
{
|
||
ztoken = qsys->zphone;
|
||
ftranslate = TRUE;
|
||
}
|
||
|
||
/* Perhaps we should accumulate the protocol parameters. */
|
||
if (ffirst)
|
||
{
|
||
*pcproto_params = s.cproto_params;
|
||
*pqproto_params = s.qproto_params;
|
||
*pireliable = s.ireliable;
|
||
ffirst = FALSE;
|
||
}
|
||
|
||
if (! fpdo_dial (&s, ztoken, ftranslate))
|
||
return FALSE;
|
||
|
||
if (! ftoken)
|
||
zdialer = NULL;
|
||
else
|
||
zdialer = strtok ((char *) NULL, " \t");
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
else if (qport->u.smodem.qdialer != NULL)
|
||
{
|
||
*pcproto_params = qport->u.smodem.qdialer->cproto_params;
|
||
*pqproto_params = qport->u.smodem.qdialer->qproto_params;
|
||
*pireliable = qport->u.smodem.qdialer->ireliable;
|
||
return fpdo_dial (qport->u.smodem.qdialer, qsys->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
|
||
fpdo_dial (qdial, zphone, ftranslate)
|
||
struct sdialer *qdial;
|
||
const char *zphone;
|
||
boolean ftranslate;
|
||
{
|
||
if (! fsysdep_modem_begin_dial (qPort, qdial))
|
||
return FALSE;
|
||
|
||
if (! fchat (&qdial->schat, (const struct ssysteminfo *) NULL, qdial,
|
||
zphone, ftranslate, qPort->zname, iport_baud ()))
|
||
return FALSE;
|
||
|
||
return fsysdep_modem_end_dial (qPort, qdial);
|
||
}
|
||
|
||
/* Permit no carrier from a port. */
|
||
|
||
boolean
|
||
fport_no_carrier ()
|
||
{
|
||
return fsysdep_modem_no_carrier (qPort);
|
||
}
|
||
|
||
/* Require carrier from a port. */
|
||
|
||
boolean
|
||
fport_need_carrier ()
|
||
{
|
||
return fsysdep_modem_need_carrier (qPort);
|
||
}
|