home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
old
/
ckermit70
/
ck9con.c
< prev
next >
Wrap
C/C++ Source or Header
|
2020-01-01
|
45KB
|
1,212 lines
#include "ckcsym.h"
#ifdef NOLOCAL
char *connv = "";
#else
char *connv = "OS-9 Connect Command, 7.0.015, 1 Jan 2000";
/* C K 9 C O N -- Dumb terminal connection to remote system, for OS-9 */
/*
Modified from ckucon.c by Bob Larson (blarson@ecla.usc.edu)
Edition: 5A(01)
by Chris Hemsing, Aachen, W Germany (chris@lfm.rwth-aachen.de):
More efficient using sigmask, added character set translation
Edition: 5A(02)
07/25/91 Chris Hemsing minor bug fixes, changes for gnu (ansi) C
flow control on both sides
Edition: 5A(03)
03/04/92 Chris Hemsing Kanji bug fix
Edition: 5A(04)
08/20/92 Chris Hemsing flow control bug fix on return from local shell
Edition: 5A(05)
10/01/92 Chris Hemsing added sending xon via escape character
Edition: 5A(06)
10/09/92 Chris Hemsing escape back to local even on receive burst
Edition: 5A(07)
12/22/94 Ulli Schlueter improved overall performance (system load is
reduced about 80%, see ck9tio.c),
brought it near to the unix version that
means: added APC and ansi escape sequence
recognition, text session logging, support of
SET TERM CR-DISPLAY, support of SET TERM NEWLINE,
debug session, keyboard macros and some escape
character features
Edition: 5A(08)
01/26/95 Ulli Schlueter added network support
Edition: 5A(09)
03/13/95 Ulli Schlueter i/o buffers dynamic
Edition: 5A(10)
04/19/95 Ulli Schlueter Changed handling of CR from keyboard. Added
handling of telnet binary mode.
Edition: 5A(11)
04/21/95 Ulli Schlueter Incoming telnet CR/NUL is handled. Made debugging
display prettier.
Edition: 5A(12)
04/25/95 Ulli Schlueter Keyboard i/o buffered.
Edition: 7.0.15
1 Jan 2000 S Rance, F. da Cruz: Adapt to C-Kermit 7.0 and Ultra C.
Author: Frank da Cruz <fdc@columbia.edu>
Columbia University Center for Computing Activities, January 1985.
Copyright (C) 1985, 2000,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
*/
#include "ckcdeb.h"
#include "ckucmd.h"
#include "ckcker.h"
#include "ckcasc.h"
#ifndef NOCSETS
#include "ckcxla.h" /* Character set translation */
#endif /* NOCSETS */
#include "ckcnet.h"
#include <errno.h>
#include <sgstat.h> /* Set/Get tty modes */
#ifndef EOS_NOTRDY
#ifdef E_NOTRDY
#define EOS_NOTRDY E_NOTRDY
#endif /* E_NOTRDY */
#endif /* EOS_NOTRDY */
_PROTOTYP( VOID doesc, (char) );
_PROTOTYP( static VOID logchar, (char) );
_PROTOTYP( int hconne, (void) );
extern int local, escape, duplex, parity, flow, seslog, sessft, debses, nopush,
mdmtyp, ttnproto, cmask, cmdmsk, network, nettype, deblog, sosi, tnlm,
xitsta, what, ttyfd, quiet, backgrd, pflag, tt_crd/*, ttfdflg*/;
#ifdef TCPSOCKET
extern int tn_nlm, tn_b_nlm, tn_binary;
#endif /* TCPSOCKET */
extern long speed;
extern char ttname[], sesfil[], myhost[], *ccntab[];
/* from ck9tio.c . . . */
/* console/tty signal flags (incremented by catch) */
extern int csigflg, tsigflg;
#ifdef CK_APC
extern int apcactive; /* Application Program Command (APC) */
extern int apcstatus; /* items ... */
static int apclength = 0;
#ifdef DCMDBUF
extern char *apcbuf;
#else
extern char apcbuf[];
#endif /* DCMDBUF */
static int apcbuflen = APCBUFLEN - 2;
#endif /* CK_APC */
/* Character-set items */
#ifndef NOCSETS
#ifdef CK_ANSIC /* ANSI C prototypes... */
extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
static CHAR (*sxo)(CHAR); /* Local translation functions */
static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */
static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */
static CHAR (*rxi)(CHAR);
#else /* Not ANSI C... */
extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
static CHAR (*sxo)(); /* Local translation functions */
static CHAR (*rxo)(); /* for output (sending) terminal chars */
static CHAR (*sxi)(); /* and for input (receiving) terminal chars. */
static CHAR (*rxi)();
#endif /* CK_ANSIC */
extern int language; /* Current language. */
extern struct csinfo fcsinfo[]; /* File character set info. */
extern int tcsr, tcsl; /* Terminal character sets, remote & local. */
#endif /* NOCSETS */
/*
We do not need to parse and recognize escape sequences if we are being built
without character-set support AND without APC support.
*/
#ifdef NOCSETS /* No character sets */
#ifndef CK_APC /* No APC */
#ifndef NOESCSEQ
#define NOESCSEQ /* So no escape sequence recognizer */
#endif /* NOESCSEQ */
#endif /* CK_APC */
#endif /* NOCSETS */
#ifndef NOSETKEY /* Keyboard mapping */
extern KEY *keymap; /* Single-character key map */
extern MACRO *macrotab; /* Key macro pointer table */
#endif /* NOSETKEY */
#ifdef NOESCSEQ
#define chkaes(x, y)
#else
/*
As of edit 178, the CONNECT command will skip past ANSI escape sequences
to avoid translating the characters within them. This allows the CONNECT
command to work correctly when connected to a remote host that uses a
7-bit ISO 646 national character set, in which characters like '[' would
normally be translated into accented characters, ruining the terminal's
interpretation (and generation) of escape sequences.
As of edit 190, the CONNECT command responds to APC escape sequences
(ESC _ text ESC \) if the user SETs TERMINAL APC ON or UNCHECKED, and the
program was built with CK_APC defined.
Non-ANSI/ISO-compliant escape sequences are not handled.
*/
/*
States for the escape-sequence recognizer.
*/
#define ES_NORMAL 0 /* Normal, not in an escape sequence */
#define ES_GOTESC 1 /* Current character is ESC */
#define ES_ESCSEQ 2 /* Inside an escape sequence */
#define ES_GOTCSI 3 /* Inside a control sequence */
#define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */
#define ES_TERMIN 5 /* 1st char of string terminator */
static CHAR escseq; /* 1 = Recognizer is active */
static struct _escinf {
char
inesc, /* State of sequence recognizer */
oldesc; /* Previous state of recognizer */
} escinf[2];
/*
ANSI escape sequence handling. Only the 7-bit form is treated, because
translation is not a problem in the 8-bit environment, in which all GL
characters are ASCII and no translation takes place. So we don't check
for the 8-bit single-character versions of CSI, DCS, OSC, APC, or ST.
Here is the ANSI sequence recognizer state table, followed by the code
that implements it.
Definitions:
CAN = Cancel 01/08 Ctrl-X
SUB = Substitute 01/10 Ctrl-Z
DCS = Device Control Sequence 01/11 05/00 ESC P
CSI = Control Sequence Introducer 01/11 05/11 ESC [
ST = String Terminator 01/11 05/12 ESC \
OSC = Operating System Command 01/11 05/13 ESC ]
PM = Privacy Message 01/11 05/14 ESC ^
APC = Application Program Command 01/11 05/15 ESC _
ANSI escape sequence recognizer:
State Input New State ; Commentary
NORMAL (start) ; Start in NORMAL state
(any) CAN NORMAL ; ^X cancels
(any) SUB NORMAL ; ^Z cancels
NORMAL ESC GOTESC ; Begin escape sequence
NORMAL other ; NORMAL control or graphic character
GOTESC ESC ; Start again
GOTESC [ GOTCSI ; CSI
GOTESC P STRING ; DCS introducer, consume through ST
GOTESC ] STRING ; OSC introducer, consume through ST
GOTESC ^ STRING ; PM introducer, consume through ST
GOTESC _ STRING ; APC introducer, consume through ST
GOTESC 0..~ NORMAL ; 03/00 through 17/14 = Final character
GOTESC other ESCSEQ ; Intermediate or ignored control character
ESCSEQ ESC GOTESC ; Start again
ESCSEQ 0..~ NORMAL ; 03/00 through 17/14 = Final character
ESCSEQ other ; Intermediate or ignored control character
GOTCSI ESC GOTESC ; Start again
GOTCSI @..~ NORMAL ; 04/00 through 17/14 = Final character
GOTCSI other ; Intermediate char or ignored control char
STRING ESC TERMIN ; Maybe have ST
STRING other ; Consume all else
TERMIN \ NORMAL ; End of string
TERMIN other STRING ; Still in string
*/
/*
chkaes() -- Check ANSI Escape Sequence.
Call with EACH character in input stream.
Sets global inesc variable according to escape sequence state.
Returns 0 normally, 1 if an APC sequence is to be executed.
*/
int
#ifdef CK_ANSIC
chkaes(char c, struct _escinf *inf)
#else
chkaes(c, inf) char c; struct _escinf *inf;
#endif /* CK_ANSIC */
/* chkaes */ {
inf->oldesc = inf->inesc; /* Remember previous state */
if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */
inf->inesc = ES_NORMAL;
else /* Otherwise */
switch (inf->inesc) { /* enter state switcher */
case ES_NORMAL: /* NORMAL state */
if (c == ESC) /* Got an ESC */
inf->inesc = ES_GOTESC; /* Change state to GOTESC */
break; /* Otherwise stay in NORMAL state */
case ES_GOTESC: /* GOTESC state */
if (c == '[') /* Left bracket after ESC is CSI */
inf->inesc = ES_GOTCSI; /* Change to GOTCSI state */
else if (c == 'P' || (c > 0134 && c < 0140)) { /* P, [, ^, or _ */
inf->inesc = ES_STRING; /* Switch to STRING-absorption state */
#ifdef CK_APC
/* APC handled in child only */
if (c == '_' && inf == &escinf[1] &&
apcstatus != APC_OFF) {
debug(F100,"APC begin","",0);
apcactive = 1; /* Set APC-Active flag */
apclength = 0; /* and reset APC buffer pointer */
}
#endif /* CK_APC */
} else if (c > 057 && c < 0177) /* Final character '0' thru '~' */
inf->inesc = ES_NORMAL; /* Back to normal */
else if (c != ESC) /* ESC in an escape sequence... */
inf->inesc = ES_ESCSEQ; /* starts a new escape sequence */
break; /* Intermediate or ignored ctrl char */
case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */
if (c > 057 && c < 0177) /* Final character '0' thru '~' */
inf->inesc = ES_NORMAL; /* Return to NORMAL state. */
else if (c == ESC) /* ESC ... */
inf->inesc = ES_GOTESC; /* starts a new escape sequence */
break; /* Intermediate or ignored ctrl char */
case ES_GOTCSI: /* GOTCSI -- In a control sequence */
if (c > 077 && c < 0177) /* Final character '@' thru '~' */
inf->inesc = ES_NORMAL; /* Return to NORMAL. */
else if (c == ESC) /* ESC ... */
inf->inesc = ES_GOTESC; /* starts over. */
break; /* Intermediate or ignored ctrl char */
case ES_STRING: /* Inside a string */
if (c == ESC) /* ESC may be 1st char of terminator */
inf->inesc = ES_TERMIN; /* Go see. */
#ifdef CK_APC
else if (apcactive && (apclength < apcbuflen)) /* If in APC, */
apcbuf[apclength++] = c; /* deposit this character. */
else { /* Buffer overrun */
apcactive = 0; /* Discard what we got */
apclength = 0; /* and go back to normal. */
apcbuf[0] = 0; /* Not pretty, but what else */
inf->inesc = ES_NORMAL; /* can we do? (ST might not come) */
}
#endif /* CK_APC */
break; /* Absorb all other characters. */
case ES_TERMIN: /* May have a string terminator */
if (c == '\\') { /* which must be backslash */
inf->inesc = ES_NORMAL; /* If so, back to NORMAL */
#ifdef CK_APC
if (apcactive) { /* If it was an APC string, */
debug(F101,"APC terminated","",c);
apcbuf[apclength] = NUL; /* terminate it and then ... */
return(1);
}
#endif /* CK_APC */
} else { /* Otherwise */
inf->inesc = ES_STRING; /* Back to string absorption. */
#ifdef CK_APC
if (apcactive && (apclength+1 < apcbuflen)) { /* In APC string */
apcbuf[apclength++] = ESC; /* deposit the Esc character */
apcbuf[apclength++] = c; /* and this character too */
}
#endif /* CK_APC */
}
}
return(0);
}
#endif /* NOESCSEQ */
static CHAR active, /* Variables global to this module */
quitnow,
#ifdef NETCONN
telnet_cnct, /* 1 if telnet connection */
#endif /* NETCONN */
#ifdef TNCODE
c_ttprv, /* Previous character from comm line */
#endif /* TNCODE */
c_slprv, /* Previous session log character */
inshift, outshift, /* SO/SI shift state */
dohangup; /* 2 = user requested hangup, 1 = hangup due to error */
#define LIBUFL 200 /* Line buffer */
#define LOBUFL (2*LIBUFL) /* for cr/lf display */
#ifdef DYNAMIC
static CHAR *libuf;
static CHAR *lobuf;
#else
static CHAR libuf[LIBUFL];
static CHAR lobuf[LOBUFL];
#endif /* DYNAMIC */
static int ibc;
static CHAR *ibp;
#define KIBUFL 80
#define KOBUFL (3*KIBUFL)
#ifdef DYNAMIC
static CHAR *kibuf, *kobuf;
#else
static CHAR kibuf[KIBUFL];
static CHAR kobuf[KOBUFL];
#endif /* DYNAMIC */
static CHAR *kibp, *kobp;
static int kibc, kobc;
static struct sgbuf opt; /* sgtty info... */
/* C K C G E T C -- C-Kermit CONNECT Get Character */
/*
Semi buffered read from communication device.
On error, returns ttinc's return code (see ttinc() description).
Dummy argument for compatible calling conventions with ttinc().
NOTE: We don't have a macro for this because we have to pass
a pointer to this function as an argument to tn_doop().
*/
int
ckcgetc(dummy) int dummy; {
if (ibc > 0) {
ibc -= 1;
return *ibp++;
}
else return ttinc(0);
}
/* K B G E T C -- Get one character from keyboard (semi buffered). */
static int
kbgetc () {
if (kibc > 0) {
kibc -= 1;
return *kibp++;
}
return coninc(0);
}
/* K B P U T C -- Send one character from keyboard (buffered) */
/*
Using write() and not ttol() because less overhead. When an error occurrs,
ttol() will call ttclos() on network connections where as ttoc(), which was
used for output in the unbuffered version, will not (ckutio.c: why that?).
The first arg of ttol() schould (must) be a null terminated string!?
*/
static int
kbputc (c) int c; {
if (c < 0 || kobc >= KOBUFL) {
if (write(ttyfd, kobuf, kobc) < 0) {
debug(F101, "conect kbputc errno", NULL, errno);
return -1;
}
kobp = kobuf;
kobc = 0;
}
if (!(c < 0)) {
*kobp++ = dopar(c);
kobc += 1;
}
return 0;
}
/* C O N E C T -- Perform terminal connection */
conect() {
register int c; /* c is a character, but must be signed
integer to pass thru -1, which is the
modem disconnection signal, and is
different from the character 0377 */
register int csave; /* Another copy of c */
register int n;
char temp[80];
int we_have_data;
#ifndef NOESCSEQ
int apcrc = 0; /* APC recognized flag */
#endif /* NOESCSEQ */
#ifndef NOCSETS
int langsv; /* For remembering language setting. */
int tcs; /* Intermediate ("transfer") character set. */
#endif /* NOCSETS */
#ifndef NOSETKEY
MACRO kmptr = NULL; /* Pointer to current key macro */
#endif /* NOSETKEY */
if (!local) {
#ifdef NETCONN
printf("Sorry, you must SET LINE or SET HOST first\n");
#else
printf("Sorry, you must SET LINE first\n");
#endif /* !NETCONN */
return(0);
}
if (speed < 0 && network == 0 /*&& ttfdflg == 0*/) {
printf("Sorry, you must SET SPEED first\n");
return(0);
}
#ifdef COMMENT
/* This is handled by SET ESCAPE */
if ((escape < 0) || (escape > 0177)) {
printf("Your escape character is not ASCII - %d\n",escape);
return(0);
}
#endif /* COMMENT */
#ifdef DYNAMIC
if (libuf == NULL) {
/* Allocate input/output buffers */
n = LIBUFL + LOBUFL + KIBUFL + KOBUFL;
if ((libuf = (CHAR *)malloc(n)) == NULL) {
printf("Sorry, CONNECT i/o buffers can't be allocated\n");
return 0;
}
lobuf = libuf + LIBUFL;
kibuf = lobuf + LOBUFL;
kobuf = kibuf + KIBUFL;
}
#endif /* DYNAMIC */
if (ttopen(ttname,&local,
#ifdef NETCONN
network ? -nettype : mdmtyp,
#else
mdmtyp,
#endif /* NETCONN */
0) < 0) {
sprintf(temp,"Sorry, can't open %s",ttname);
perror(temp);
return(0);
}
dohangup = 0; /* Hangup not requested yet */
if (!quiet
#ifdef CK_APC
&& !apcactive
#endif /* CK_APC */
) {
#ifdef NETCONN
printf("Connecting %s %s", network ? "to host" : "through", ttname);
if (!network && speed >= 0L) printf(", speed %d", speed);
#else
printf("Connecting thru %s, speed %d",ttname,speed);
#endif /* NETCONN */
printf(".\nThe escape character is Ctrl-%c (ASCII %d, %s)\n",
ctl(escape), escape, escape == 127 ? "DEL" : ccntab[escape]);
printf("Type the escape character followed by C to get back,\n");
printf("or followed by ? to see other options.\n");
if (seslog) printf("(Session logged to %s, %s)\n",sesfil,
sessft ? "binary" : "text");
if (debses) printf("(Debugging Display...)\n");
}
/* Condition console terminal and communication line */
if (conbin(escape) < 0) {
printf("Sorry, can't condition console terminal\n");
return(0);
}
if (flow==1) { /*if xon/xoff you should have it running on both*/
if (_gs_opt(0,&opt) <0) /* Structure for restoring */
{
printf("Sorry, can't condition console terminal\n");
return(0);
}
opt.sg_xon = 0x11;
opt.sg_xoff = 0x13;
_ss_opt(0,&opt);
_ss_opt(1,&opt); /* set new modes . */
}
if (ttvt(speed,flow) < 0) {
conres();
printf("Sorry, Can't condition communication line\n");
return(0);
}
#ifdef NETCONN
telnet_cnct = network && ttnproto == NP_TELNET;
#endif /* NETCONN */
#ifndef NOCSETS
/* Set up character set translations */
tcs = gettcs(tcsr, tcsl); /* Get intermediate set */
if (tcsr == tcsl) { /* Remote and local sets the same? */
sxo = rxo = NULL; /* If so, no translation. */
sxi = rxi = NULL;
} else { /* Otherwise, set up */
sxo = xls[tcs][tcsl]; /* translation function */
rxo = xlr[tcs][tcsr]; /* pointers for output functions */
sxi = xls[tcs][tcsr]; /* and for input functions. */
rxi = xlr[tcs][tcsl];
}
/*
This is to prevent use of zmstuff() and zdstuff() by translation functions.
They only work with disk i/o, not with communication i/o. Luckily Russian
translation functions don't do any stuffing...
*/
langsv = language;
#ifndef NOCYRIL
if (language != L_RUSSIAN)
#endif /* NOCYRIL */
language = L_USASCII;
#ifndef NOESCSEQ
/*
We need to activate the escape-sequence recognition feature when:
(a) translation is elected, AND
(b) the local and/or remote set is a 7-bit set other than US ASCII.
Or:
SET TERMINAL APC is not OFF (handled in the next statement).
*/
escseq = (tcs != TC_TRANSP) && /* Not transparent */
(fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */
(fcsinfo[tcsl].code != FC_USASCII); /* But not ASCII */
#endif /* NOESCSEQ */
#endif /* NOCSETS */
#ifndef NOESCSEQ
#ifdef CK_APC
escseq = escseq || (apcstatus != APC_OFF);
apcactive = 0; /* An APC command is not active */
apclength = 0; /* ... */
#endif /* CK_APC */
escinf[0].oldesc =
escinf[1].oldesc = -1;
escinf[0].inesc =
escinf[1].inesc = ES_NORMAL; /* Initial state of recognizer */
debug(F101,"escseq","",escseq);
#endif /* NOESCSEQ */
inshift = outshift = 0; /* Initial shift state. */
/*
Main loop. The treatment of the 8th bit of keyboard characters
is governed by SET COMMAND BYTESIZE (cmdmsk). The treatment of the 8th bit
of characters sent to the remote is governed by SET TERMINAL BYTESIZE
(cmask). This distinction was introduced in edit C-Kermit 5A(164).
*/
what = W_CONNECT; /* Keep track of what we're doing */
active = 1;
csigflg = tsigflg = 1; /* force signal setup */
while (active) {
/*
Increment signal mask, signals must be masked between _ss_ssig and sleep
*/
if (ibc <= 0) {
sigmask(1);
if (csigflg) {
csigflg = 0;
_ss_ssig(0, SIGARB);
}
#ifdef NETCONN
if (!network) {
#endif /* NETCONN */
if (tsigflg) {
tsigflg = 0;
_ss_ssig(ttyfd, SIGARB+1);
}
sleep(0); /* signal mask is cleared */
#ifdef NETCONN
} else {
extern int ttevid;
/*
Note: We're going to wait for an event with the signal mask set. That's ok,
because only then the event wait routine recognizes signals that arrived
between the above call of sigmask and the entry of event wait! The effect is
that an arriving signal will put us in the active queue, but the intercept
routine is not executed. That is ok too, because after the execution of the
below sigmask call the signal mask is clear and the os9call exception handler
checks for pending signals - then the intercept routine is executed.
*/
_ev_wait(ttevid, 1, 0x7fff);
sigmask(0);
}
#endif /* NETCONN */
}
/*
Avoid this expensive system call, cause it's unnecessary: we're calling
read only if there's data available, then no signal is pending anymore.
*/
#ifdef COMMENT
_ss_rel(0);
_ss_rel(ttyfd);
#endif /* COMMENT */
/*
Loop while data on keybord or remote port. Do check console to get
characters through even if communication line receives a burst.
*/
do {
we_have_data = 0;
if ((n = _gs_rdy(0)) > 0
/*
Using read because missing conxin() - see the discussion of ckucon.c:kbget().
*/
? (n = read(0, kibp = kibuf, n > KIBUFL ? KIBUFL : n)) > 0
: (n = errno != EOS_NOTRDY ? -1 : 0, 0))
{
/*
Wait some arbitrary time for buffer fill to reduce system load and to avoid
sending small packets over the network.
*/
if (n < 10) tsleep(2);
we_have_data = 1;
kibc = n;
/* kobc = 0; */
kobp = kobuf;
do { /* while (kibc || kmptr) */
#ifndef NOSETKEY
if (kmptr) {
if ((c = (CHAR)*kmptr++) == NUL) {
kmptr = NULL;
continue; /* get next character from kb or break */
}
} else
#endif /* NOSETKEY */
c = kbgetc(); /* Get character from keyboard */
c &= cmdmsk;
#ifndef NOSETKEY
/*
Note: kmptr is NULL if we got character c from the keyboard, and it is
not NULL if it came from a macro. In the latter case, we must avoid
expanding it again.
*/
if (!kmptr && macrotab[c]) { /* Macro definition for c? */
kmptr = macrotab[c]; /* Yes, set up macro pointer */
continue; /* and restart the loop */
} else c = keymap[c]; /* else use single-char keymap */
#endif /* NOSETKEY */
if (
#ifndef NOSETKEY
!kmptr &&
#endif /* NOSETKEY */
(c & 0177) == escape)
{ /* Look for escape char */
if (kobc) kbputc(-1); /* Flush kb output buffer */
c = kbgetc() & 0177; /* Got esc, get its arg */
doesc(c); /* And process it */
if (!active) break; /* immediately leave we_have_data
loop to avoid burst receive */
}
else
{ /* Ordinary character */
csave = c; /* Save it before translation for local echo */
#ifndef NOCSETS
#ifndef NOESCSEQ
if (escinf[0].inesc == ES_NORMAL)
#endif /* NOESCSEQ */
{
/* Translate character sets */
if (sxo) c = (*sxo)(c); /* Local to intermediate. */
if (rxo) c = (*rxo)(c); /* Intermediate to remote. */
}
if (escseq) chkaes((char)c, &escinf[0]);
#endif /* NOCSETS */
/*
If Shift-In/Shift-Out selected and we have a 7-bit connection,
handle shifting here.
*/
if (sosi) { /* Shift-In/Out selected? */
if (cmask == 0177) { /* In 7-bit environment? */
if (c & 0200) { /* 8-bit character? */
if (outshift == 0) { /* If not shifted, */
kbputc(SO); /* shift. */
outshift = 1;
}
} else {
if (outshift == 1) { /* 7-bit character */
kbputc(SI); /* If shifted, */
outshift = 0; /* unshift. */
}
}
}
if (c == SO) outshift = 1; /* User typed SO */
if (c == SI) outshift = 0; /* User typed SI */
}
c &= cmask; /* Apply Kermit-to-host mask now. */
kbputc(c);
if (c == CR) { /* Carriage Return */
#ifdef TNCODE /* Handle TELNET NEWLINE ON/OFF/RAW */
if (telnet_cnct) {
switch (!TELOPT_ME(TELOPT_BINARY) ?
tn_nlm : tn_b_nlm) {
case TNL_CRLF: /* Send CR/LF */
kbputc(LF);
break;
case TNL_CRNUL: /* Send CR/NUL */
kbputc(NUL);
break;
}
}
#endif /* TNCODE */
if (tnlm) /* TERMINAL NEWLINE ON */
kbputc(LF); /* Send CR/LF */
}
#ifdef TNCODE
/* If user types the 0xff character (TELNET IAC), it must be doubled. */
else /* Not CR */
if ((dopar((CHAR) c) == IAC) && /* IAC (0xff) */
telnet_cnct) {
kbputc(IAC); /* double it */
}
#endif /* TNCODE */
while (1) { /* Handle local echo */
if (duplex) { /* Half duplex? */
if (debses) {
conol(dbchr(csave)); /* the original char */
if (csave == LF) conoll("");
} else
conoc(csave); /* Yes, also echo it. */
if (seslog) /* And maybe log it. */
logchar(
/* sessft == 0 && csave == '\l' ? '\n' : */
csave
);
if (csave == CR && tt_crd) { /* TERM CR-DISPLAY */
csave = LF;
continue; /* Output LF and leave loop */
}
}
break; /* Leave pseudo loop */
}
} /* end if ((c & 0177) == escape) */
} while (kibc
#ifndef NOSETKEY
|| kmptr
#endif /* NOSETKEY */
);
if (kobc) { /* Flush kb output buffer */
if (kbputc(-1) < 0) {
perror("\r\012Can't send character\012");
active = 0;
}
}
} /* end if data on console */
else if (n < 0) {
debug(F101,"conect console errno", NULL, errno);
active = 0;
}
if (active == 0) break; /* Leave we-have-data loop */
/*
Get characters from the communication line and put to the
console.
*/
if ((n = ibc) > 0 || ((n = ttchk()) > 0
? (n = ttxin(n > LIBUFL ? LIBUFL : n, ibp = libuf)) > 0
: (n = errno != EOS_NOTRDY ? -1 : 0, 0)))
{
register CHAR *pi = ibp;
register CHAR *po = lobuf;
we_have_data = 1;
do {
c = *pi++;
#ifdef TNCODE
if (c == NUL && telnet_cnct &&
!TELOPT_U(TELOPT_BINARY) && c_ttprv == CR) {
c_ttprv = c;
continue; /* get next character */
}
c_ttprv = c;
/* Handle TELNET negotiations... */
if (c == IAC && telnet_cnct) {
register int tx;
debug(F100,"CONNECT got IAC","",0);
if (po - lobuf > 0) { /* Dump screen-output buffer */
conxo(po - lobuf, (char *)lobuf);
po = lobuf;
}
ibc = n - 1; /* save for ckcgetc */
ibp = pi;
tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc);
n = ibc + 1;
pi = ibp;
if ((tx) == 0) {
continue; /* get next character */
} else if (tx == -1) { /* I/O error */
if (!quiet)
printf("\n\012Communications disconnect ");
#ifdef NOSETBUF
fflush(stdout);
#endif /* NOSETBUF */
ttclos(0); /* close network connection */
dohangup = 1;
active = 0;
break; /* Leave comm-data loop */
/* NOTREACHED */
} else if ((tx == 1) && (!duplex)) { /* ECHO change */
duplex = 1; /* Turn on local echo */
debug(F101,"CONNECT TELNET duplex change","",duplex);
continue; /* get next character */
} else if ((tx == 2) && (duplex)) { /* ECHO change */
duplex = 0;
debug(F101,"CONNECT TELNET duplex change","",duplex);
continue; /* get next character */
} else if (tx == 3) { /* Quoted IAC */
c = IAC;
} else continue; /* Negotiation OK, get next char. */
}
#endif /* TNCODE */
if (debses) {
while (1) {
conol(dbchr(c));
if (c == LF) conoll("");
if (seslog) logchar(c);
if (c == CR && tt_crd) { /* TERM CR-DISPLAY */
c = LF;
continue; /* Output LF and leave loop */
}
break; /* Leave pseudo loop */
}
} else {
c &= cmask;
if (sosi) {
if (c == SO) {
inshift = 1;
continue; /* get next character */
} else if (c == SI) {
inshift = 0;
continue; /* get next character */
}
if (inshift) c |= 0200;
}
#ifndef NOCSETS
#ifndef NOESCSEQ
/* If not in an esc sequ. */
if (escinf[1].inesc == ES_NORMAL)
#endif /* NOESCSEQ */
{
/* Translate character sets */
if (sxi) c = (*sxi)(c);
if (rxi) c = (*rxi)(c);
}
#endif /* NOCSETS */
#ifndef NOESCSEQ
if (escseq) /* If handling escape sequences */
/* update our state */
apcrc = chkaes((char)c, &escinf[1]);
#ifdef CK_APC
/*
If we are handling APCs, we have several possibilities at this point:
1. Ordinary character to be written to the screen.
2. An Esc; we can't write it because it might be the beginning of an APC.
3. The character following an Esc, in which case we write Esc, then char,
but only if we have not just entered an APC sequence.
*/
if (escseq && apcstatus != APC_OFF) {
if (escinf[1].inesc == ES_GOTESC)
/* Don't write ESC yet */
continue; /* Handle next character */
else if (escinf[1].oldesc == ES_GOTESC
&& !apcactive) {
*po++ = ESC; /* Write saved ESC */
if (seslog) logchar((char)ESC);
} else if (apcrc) { /* We have an APC */
debug(F111,"APC complete",apcbuf,apclength);
active = 0;
n--; /* uncount character */
break; /* Force screen update */
}
}
#endif /* CK_APC */
#endif /* NOESCSEQ */
#ifdef CK_APC
if (!apcactive) /* Ignore when in APC sequence */
#endif /* CK_APC */
{
c &= cmdmsk; /* Apply command mask. */
if (c == CR && tt_crd) { /* SET TER CR-DISP CRLF */
*po++ = c;
if (seslog) logchar(c);
c = LF;
}
*po++ = c;
}
if (seslog) logchar(c); /* Handle session log */
} /* end no debug session */
} while (--n > 0);
ibc = n; /* save remaining input count */
ibp = pi; /* save input buffer position */
if (po - lobuf > 0)
conxo(po - lobuf,(char *)lobuf); /* Output whole buffer */
} /* end data on communications line */
else if (n < 0) {
debug(F101, "conect comm errno", NULL, errno);
if (!quiet)
printf("\n\lCommunications disconnect ");
if (network) ttclos(0);
dohangup = 1;
active = 0;
}
} while (we_have_data && active); /* end while(we_have_data) */
} /* end while(active) */
_ss_rel(0);
if (!network) _ss_rel(ttyfd);
conres(); /* Reset the console. */
if (dohangup > 0) { /* If hangup requested, do that. */
#ifndef NODIAL
if (dohangup > 1) /* User asked for it */
if (mdmhup() < 1) /* Maybe hang up via modem */
#endif /* NODIAL */
tthang(); /* And make sure we don't hang up */
dohangup = 0; /* again unless requested again. */
}
if (quitnow) doexit(GOOD_EXIT, xitsta); /* Exit now if requested. */
if (!quiet
#ifdef CK_APC
&& !apcactive
#endif /* CK_APC */
)
printf("[Back at %s]", *myhost ? myhost : "local system");
#ifdef CK_APC
if (!apcactive)
#endif /* CK_APC */
printf("\n");
what = W_NOTHING; /* So console modes are set right. */
#ifndef NOCSETS
language = langsv; /* Restore language */
#endif /* NOCSETS */
return(1);
}
/* H C O N N E -- Give help message for connect. */
int
#ifdef CK_ANSIC
hconne(void)
#else
hconne()
#endif /* CK_ANSIC */
{
int c;
static char *hlpmsg[] = {"\
\r\012C to close the connection, or:\r",
" 0 (zero) to send a null\r",
" B to send a BREAK\r",
#ifdef NETCONN
" I to send a network interrupt packet\r",
#ifdef TCPSOCKET
" A to send Are You There?\r",
#endif /* TCPSOCKET */
#endif /* NETCONN */
" U to hangup and close connection\r",
" Q to hangup and quit Kermit\r",
" S for status\r",
" X to send an XON\r",
#ifndef NOPUSH
" ! to push to local shell\r",
#endif /* NOPUSH */
" ? for help\r",
" \\ backslash code:\r",
" \\nnn decimal character code\r",
" \\Onnn octal character code\r",
" \\Xhh hexadecimal character code\r",
" terminate with carriage return.\r",
" escape character twice to send the escape character.\r\012\r\012\r",
""};
conola(hlpmsg); /* Print the help message. */
conol("Command>"); /* Prompt for command. */
c = kbgetc() & 0177; /* Get character, strip any parity. */
conoc(c); /* Echo it. */
if (c != CMDQ)
conoll("");
return(c); /* Return it. */
}
/* D O E S C -- Process an escape character argument */
VOID
#ifdef CK_ANSIC
doesc(char c)
#else
doesc(c) char c;
#endif /* CK_ANSIC */
{
CHAR d;
char temp[80];
while (1) {
if (c == escape) { /* Send escape character */
d = dopar(c); ttoc(d); return;
} else /* Or else look it up below. */
if (isupper(c)) c = tolower(c);
switch (c) {
#ifdef NETCONN
case 'i': /* Send Interrupt */
case '\011':
#ifdef TCPSOCKET
#ifndef IP
#define IP 244
#endif /* IP */
if (telnet_cnct) { /* TELNET */
temp[0] = (CHAR) IAC; /* I Am a Command */
temp[1] = (CHAR) IP; /* Interrupt Process */
temp[2] = NUL; /* For ttol debug call */
ttol((CHAR *)temp,2);
} else
#endif /* TCPSOCKET */
conoc(BEL);
return;
#ifdef TCPSOCKET
case 'a': /* "Are You There?" */
case '\01':
#ifndef AYT
#define AYT 246
#endif /* AYT */
if (telnet_cnct) {
temp[0] = (CHAR) IAC; /* I Am a Command */
temp[1] = (CHAR) AYT; /* Are You There? */
temp[2] = NUL; /* For ttol debug call */
ttol((CHAR *)temp,2);
} else conoc(BEL);
return;
#endif /* TCPSOCKET */
#endif /* NETCONN */
case 'c': /* Close connection */
case '\03':
active = 0; conol("\r\012"); return;
case 'b': /* Send a BREAK signal */
case '\02':
if (ttsndb()<0) conol("\r\nCan't send break\r\012");
return;
case 'u': /* Hangup */
case '\010':
dohangup = 2; active = 0; conol("\r\012"); return;
case 'q':
dohangup = 2; quitnow = 1; active = 0; conol("\r\012"); return;
case '!':
#ifndef NOPUSH
if (!nopush) {
conres();
zshcmd("");
if (conbin(escape) < 0) {
printf("Error returning to remote session\n");
active = 0;
}
/*if xon/xoff you should have it running on both*/
if (flow == 1) {
if ((_ss_opt(0,&opt) < 0)||(_ss_opt(1,&opt) < 0)) {
printf("Error returning to remote session\n");
active = 0;
}
}
} else
conoc(BEL);
#else
conoc(BEL);
#endif /* NOPUSH */
return;
case 's': /* Status */
sprintf(temp,
"\015\012Connected %s %s",
network ? "to" : "through", ttname);
conol(temp);
if (speed >= 0L) {
sprintf(temp,", speed %ld", speed);
conoll(temp);
} else conoll("");
sprintf(temp,
"Terminal bytesize: %d, Command bytesize: %d, Parity: ",
(cmask == 0177) ? 7 : 8,
(cmdmsk == 0177) ? 7 : 8 );
conol(temp);
switch (parity) {
case 0: conoll("none"); break;
case 'e': conoll("even"); break;
case 'o': conoll("odd"); break;
case 's': conoll("space"); break;
case 'm': conoll("mark"); break;
}
sprintf(temp,"Terminal echo: %s", duplex ? "local" : "remote");
conoll(temp);
if (seslog) {
conol("Logging to: "); conoll(sesfil);
}
if (!network) shomdm();
#ifdef OSK
conoll("");
#endif /* OSK */
return;
case 'h': /* Help */
case '?': /* Help */
c = hconne(); continue;
case 'x': /* send xon */
ttoc(dopar(XON)); return;
case '0': /* Send a null */
c = '\0'; d = dopar(c); ttoc(d); return;
case SP: /* Space, ignore */
return;
default: /* Other */
if (c == CMDQ) { /* Backslash escape */
int x = 1;
char *ecbp = temp;
*ecbp++ = c;
while (((c = (kbgetc() & cmdmsk)) != '\012') && (c != '\n')
&& ++x < sizeof temp)
*ecbp++ = c;
*ecbp = NUL; ecbp = temp;
do {
x = xxesc(&ecbp); /* Interpret it */
if (x >= 0) { /* No key mapping here */
ttoc(dopar(x));
} else { /* Invalid backslash code. */
conoc(BEL);
break;
}
} while (*ecbp != NUL);
return;
}
conoc(BEL); return; /* Invalid esc arg, beep */
}
}
}
static
VOID
#ifdef CK_ANSIC
logchar(char c)
#else
logchar(c) char c;
#endif /* CK_ANSIC */
/* logchar */ { /* Log character c to session log */
/*if (seslog) */
if ((sessft != 0) ||
((c == '\012' || c == '\n') ? c_slprv != '\n' :
c != '\0' &&
c != XON &&
c != XOFF))
if (zchout(ZSFILE,c) < 0) {
conoll("");
conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
seslog = 0;
}
c_slprv = c;
}
#endif /* !NOLOCAL */