NetBSD/gnu/libexec/uucp/port.c

603 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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);
}