📄 telnet.c
字号:
}
}
if (count)
ring_consumed(&netiring, count);
return returnValue||count;
}
static int bol = 1, local = 0;
int
rlogin_susp()
{
if (local) {
local = 0;
bol = 1;
command(0, "z\n", 2);
return(1);
}
return(0);
}
static int
telsnd()
{
int tcc;
int count;
int returnValue = 0;
unsigned char *tbp;
tcc = 0;
count = 0;
while (NETROOM() > 2) {
register int sc;
register int c;
if (tcc == 0) {
if (count) {
ring_consumed(&ttyiring, count);
returnValue = 1;
count = 0;
}
tbp = ttyiring.consume;
tcc = ring_full_consecutive(&ttyiring);
if (tcc == 0) {
break;
}
}
c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
if (rlogin != _POSIX_VDISABLE) {
if (bol) {
bol = 0;
if (sc == rlogin) {
local = 1;
continue;
}
} else if (local) {
local = 0;
if (sc == '.' || c == termEofChar) {
bol = 1;
command(0, "close\n", 6);
continue;
}
if (sc == termSuspChar) {
bol = 1;
command(0, "z\n", 2);
continue;
}
if (sc == escape) {
command(0, (char *)tbp, tcc);
bol = 1;
count += tcc;
tcc = 0;
flushline = 1;
break;
}
if (sc != rlogin) {
++tcc;
--tbp;
--count;
c = sc = rlogin;
}
}
if ((sc == '\n') || (sc == '\r'))
bol = 1;
} else if (sc == escape) {
/*
* Double escape is a pass through of a single escape character.
*/
if (tcc && strip(*tbp) == escape) {
tbp++;
tcc--;
count++;
bol = 0;
} else {
command(0, (char *)tbp, tcc);
bol = 1;
count += tcc;
tcc = 0;
flushline = 1;
break;
}
} else
bol = 0;
#ifdef KLUDGELINEMODE
if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
if (tcc > 0 && strip(*tbp) == echoc) {
tcc--; tbp++; count++;
} else {
dontlecho = !dontlecho;
settimer(echotoggle);
setconnmode(0);
flushline = 1;
break;
}
}
#endif
if (MODE_LOCAL_CHARS(globalmode)) {
if (TerminalSpecialChars(sc) == 0) {
bol = 1;
break;
}
}
if (my_want_state_is_wont(TELOPT_BINARY)) {
switch (c) {
case '\n':
/*
* If we are in CRMOD mode (\r ==> \n)
* on our local machine, then probably
* a newline (unix) is CRLF (TELNET).
*/
if (MODE_LOCAL_CHARS(globalmode)) {
NETADD('\r');
}
NETADD('\n');
bol = flushline = 1;
break;
case '\r':
if (!crlf) {
NET2ADD('\r', '\0');
} else {
NET2ADD('\r', '\n');
}
bol = flushline = 1;
break;
case IAC:
NET2ADD(IAC, IAC);
break;
default:
NETADD(c);
break;
}
} else if (c == IAC) {
NET2ADD(IAC, IAC);
} else {
NETADD(c);
}
}
if (count)
ring_consumed(&ttyiring, count);
return returnValue||count; /* Non-zero if we did anything */
}
/*
* Scheduler()
*
* Try to do something.
*
* If we do something useful, return 1; else return 0.
*
*/
int
Scheduler(block)
int block; /* should we block in the select ? */
{
/* One wants to be a bit careful about setting returnValue
* to one, since a one implies we did some useful work,
* and therefore probably won't be called to block next
* time (TN3270 mode only).
*/
int returnValue;
int netin, netout, netex, ttyin, ttyout;
/* Decide which rings should be processed */
netout = ring_full_count(&netoring) &&
(flushline ||
(my_want_state_is_wont(TELOPT_LINEMODE)
#ifdef KLUDGELINEMODE
&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
#endif
) ||
my_want_state_is_will(TELOPT_BINARY));
ttyout = ring_full_count(&ttyoring);
#if defined(TN3270)
ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
#else /* defined(TN3270) */
ttyin = ring_empty_count(&ttyiring);
#endif /* defined(TN3270) */
#if defined(TN3270)
netin = ring_empty_count(&netiring);
# else /* !defined(TN3270) */
netin = !ISend && ring_empty_count(&netiring);
# endif /* !defined(TN3270) */
netex = !SYNCHing;
/* If we have seen a signal recently, reset things */
# if defined(TN3270) && defined(unix)
if (HaveInput) {
HaveInput = 0;
(void) signal(SIGIO, inputAvailable);
}
#endif /* defined(TN3270) && defined(unix) */
/* Call to system code to process rings */
returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
/* Now, look at the input rings, looking for work to do. */
if (ring_full_count(&ttyiring)) {
# if defined(TN3270)
if (In3270) {
int c;
c = DataFromTerminal(ttyiring.consume,
ring_full_consecutive(&ttyiring));
if (c) {
returnValue = 1;
ring_consumed(&ttyiring, c);
}
} else {
# endif /* defined(TN3270) */
returnValue |= telsnd();
# if defined(TN3270)
}
# endif /* defined(TN3270) */
}
if (ring_full_count(&netiring)) {
# if !defined(TN3270)
returnValue |= telrcv();
# else /* !defined(TN3270) */
returnValue = Push3270();
# endif /* !defined(TN3270) */
}
return returnValue;
}
/*
* Select from tty and network...
*/
void
telnet(user)
char *user;
{
sys_telnet_init();
#if defined(AUTHENTICATION) || defined(ENCRYPTION)
{
static char local_host[256] = { 0 };
if (!local_host[0]) {
gethostname(local_host, sizeof(local_host));
local_host[sizeof(local_host)-1] = 0;
}
auth_encrypt_init(local_host, hostname, "TELNET", 0);
auth_encrypt_user(user);
}
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
# if !defined(TN3270)
if (telnetport) {
#if defined(AUTHENTICATION)
if (autologin)
send_will(TELOPT_AUTHENTICATION, 1);
#endif
#ifdef ENCRYPTION
send_do(TELOPT_ENCRYPT, 1);
send_will(TELOPT_ENCRYPT, 1);
#endif /* ENCRYPTION */
send_do(TELOPT_SGA, 1);
send_will(TELOPT_TTYPE, 1);
send_will(TELOPT_NAWS, 1);
send_will(TELOPT_TSPEED, 1);
send_will(TELOPT_LFLOW, 1);
send_will(TELOPT_LINEMODE, 1);
send_will(TELOPT_NEW_ENVIRON, 1);
send_do(TELOPT_STATUS, 1);
if (env_getvalue((unsigned char *)"DISPLAY"))
send_will(TELOPT_XDISPLOC, 1);
if (eight)
tel_enter_binary(eight);
}
# endif /* !defined(TN3270) */
# if !defined(TN3270)
for (;;) {
int schedValue;
while ((schedValue = Scheduler(0)) != 0) {
if (schedValue == -1) {
setcommandmode();
return;
}
}
if (Scheduler(1) == -1) {
setcommandmode();
return;
}
}
# else /* !defined(TN3270) */
for (;;) {
int schedValue;
while (!In3270 && !shell_active) {
if (Scheduler(1) == -1) {
setcommandmode();
return;
}
}
while ((schedValue = Scheduler(0)) != 0) {
if (schedValue == -1) {
setcommandmode();
return;
}
}
/* If there is data waiting to go out to terminal, don't
* schedule any more data for the terminal.
*/
if (ring_full_count(&ttyoring)) {
schedValue = 1;
} else {
if (shell_active) {
if (shell_continue() == 0) {
ConnectScreen();
}
} else if (In3270) {
schedValue = DoTerminalOutput();
}
}
if (schedValue && (shell_active == 0)) {
if (Scheduler(1) == -1) {
setcommandmode();
return;
}
}
}
# endif /* !defined(TN3270) */
}
#if 0 /* XXX - this not being in is a bug */
/*
* nextitem()
*
* Return the address of the next "item" in the TELNET data
* stream. This will be the address of the next character if
* the current address is a user data character, or it will
* be the address of the character following the TELNET command
* if the current address is a TELNET IAC ("I Am a Command")
* character.
*/
static char *
nextitem(current)
char *current;
{
if ((*current&0xff) != IAC) {
return current+1;
}
switch (*(current+1)&0xff) {
case DO:
case DONT:
case WILL:
case WONT:
return current+3;
case SB: /* loop forever looking for the SE */
{
register char *look = current+2;
for (;;) {
if ((*look++&0xff) == IAC) {
if ((*look++&0xff) == SE) {
return look;
}
}
}
}
default:
return current+2;
}
}
#endif /* 0 */
/*
* netclear()
*
* We are about to do a TELNET SYNCH operation. Clear
* the path to the network.
*
* Things are a bit tricky since we may have sent the first
* byte or so of a previous TELNET command into the network.
* So, we have to scan the network buffer from the beginning
* until we are up to where we want to be.
*
* A side effect of what we do, just to keep things
* simple, is to clear the urgent data pointer. The principal
* caller should be setting the urgent data pointer AFTER calling
* us in any case.
*/
static void
netclear()
{
#if 0 /* XXX */
register char *thisitem, *next;
char *good;
#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
thisitem = netobuf;
while ((next = nextitem(thisitem)) <= netobuf.send) {
thisitem = next;
}
/* Now, thisitem is first before/at boundary. */
good = netobuf; /* where the good bytes go */
while (netoring.add > thisitem) {
if (wewant(thisitem)) {
int length;
next = thisitem;
do {
next = nextitem(next);
} while (wewant(next) && (nfrontp > next));
length = next-thisitem;
memmove(good, thisitem, length);
good += length;
thisitem = next;
} else {
thisitem = nextitem(thisitem);
}
}
#endif /* 0 */
}
/*
* These routines add various telnet commands to the data stream.
*/
static void
doflush()
{
NET2ADD(IAC, DO);
NETADD(TELOPT_TM);
flushline = 1;
flushout = 1;
(void) ttyflush(1); /* Flush/drop output */
/* do printoption AFTER flush, otherwise the output gets tossed... */
printoption("SENT", DO, TELOPT_TM);
}
void
xmitAO()
{
NET2ADD(IAC, AO);
printoption("SENT", IAC, AO);
if (autoflush) {
doflush();
}
}
void
xmitEL()
{
NET2ADD(IAC, EL);
printoption("SENT", IAC, EL);
}
void
xmitEC()
{
NET2ADD(IAC, EC);
printoption("SENT", IAC, EC);
}
int
dosynch()
{
netclear(); /* clear the path to the network */
NETADD(IAC);
setneturg();
NETADD(DM);
printoption("SENT", IAC, DM);
return 1;
}
int want_status_response = 0;
int
get_status()
{
unsigned char tmp[16];
register unsigned char *cp;
if (my_want_state_is_dont(TELOPT_STATUS)) {
printf("Remote side does not support STATUS option\n");
return 0;
}
cp = tmp;
*cp++ = IAC;
*cp++ = SB;
*cp++ = TELOPT_STATUS;
*cp++ = TELQUAL_SEND;
*cp++ = IAC;
*cp++ = SE;
if (NETROOM() >= cp - tmp) {
ring_supply_data(&netoring, tmp, cp-tmp);
printsub('>', tmp+2, cp - tmp - 2);
}
++want_status_response;
return 1;
}
void
intp()
{
NET2ADD(IAC, IP);
printoption("SENT", IAC, IP);
flushline = 1;
if (autoflush) {
doflush();
}
if (autosynch) {
dosynch();
}
}
void
sendbrk()
{
NET2ADD(IAC, BREAK);
printoption("SENT", IAC, BREAK);
flushline = 1;
if (autoflush) {
doflush();
}
if (autosynch) {
dosynch();
}
}
void
sendabort()
{
NET2ADD(IAC, ABORT);
printoption("SENT", IAC, ABORT);
flushline = 1;
if (autoflush) {
doflush();
}
if (autosynch) {
dosynch();
}
}
void
sendsusp()
{
NET2ADD(IAC, SUSP);
printoption("SENT", IAC, SUSP);
flushline = 1;
if (autoflush) {
doflush();
}
if (autosynch) {
dosynch();
}
}
void
sendeof()
{
NET2ADD(IAC, xEOF);
printoption("SENT", IAC, xEOF);
}
void
sendayt()
{
NET2ADD(IAC, AYT);
printoption("SENT", IAC, AYT);
}
/*
* Send a window size update to the remote system.
*/
void
sendnaws()
{
long rows, cols;
unsigned char tmp[16];
register unsigned char *cp;
if (my_state_is_wont(TELOPT_NAWS))
return;
#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
return;
}
cp = tmp;
*cp++ = IAC;
*cp++ = SB;
*cp++ = TELOPT_NAWS;
PUTSHORT(cp, cols);
PUTSHORT(cp, rows);
*cp++ = IAC;
*cp++ = SE;
if (NETROOM() >= cp - tmp) {
ring_supply_data(&netoring, tmp, cp-tmp);
printsub('>', tmp+2, cp - tmp - 2);
}
}
void
tel_enter_binary(rw)
int rw;
{
if (rw&1)
send_do(TELOPT_BINARY, 1);
if (rw&2)
send_will(TELOPT_BINARY, 1);
}
void
tel_leave_binary(rw)
int rw;
{
if (rw&1)
send_dont(TELOPT_BINARY, 1);
if (rw&2)
send_wont(TELOPT_BINARY, 1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -