📄 telnet.c
字号:
spcp->val = *spcp->valp;
slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
}
}
slc_end_reply();
(void)slc_update();
setconnmode(1); /* Make sure the character values are set */
}
void
slc(cp, len)
register unsigned char *cp;
int len;
{
register struct spc *spcp;
register int func,level;
slc_start_reply();
for (; len >= 3; len -=3, cp +=3) {
func = cp[SLC_FUNC];
if (func == 0) {
/*
* Client side: always ignore 0 function.
*/
continue;
}
if (func > NSLC) {
if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
slc_add_reply(func, SLC_NOSUPPORT, 0);
continue;
}
spcp = &spc_data[func];
level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
continue;
}
if (level == (SLC_DEFAULT|SLC_ACK)) {
/*
* This is an error condition, the SLC_ACK
* bit should never be set for the SLC_DEFAULT
* level. Our best guess to recover is to
* ignore the SLC_ACK bit.
*/
cp[SLC_FLAGS] &= ~SLC_ACK;
}
if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
spcp->val = (cc_t)cp[SLC_VALUE];
spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
continue;
}
level &= ~SLC_ACK;
if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
spcp->val = (cc_t)cp[SLC_VALUE];
}
if (level == SLC_DEFAULT) {
if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
spcp->flags = spcp->mylevel;
else
spcp->flags = SLC_NOSUPPORT;
}
slc_add_reply(func, spcp->flags, spcp->val);
}
slc_end_reply();
if (slc_update())
setconnmode(1); /* set the new character values */
}
void
slc_check()
{
register struct spc *spcp;
slc_start_reply();
for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
if (spcp->valp && spcp->val != *spcp->valp) {
spcp->val = *spcp->valp;
if (spcp->val == (cc_t)(_POSIX_VDISABLE))
spcp->flags = SLC_NOSUPPORT;
else
spcp->flags = spcp->mylevel;
slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
}
}
slc_end_reply();
setconnmode(1);
}
unsigned char slc_reply[128];
unsigned char *slc_replyp;
void
slc_start_reply()
{
slc_replyp = slc_reply;
*slc_replyp++ = IAC;
*slc_replyp++ = SB;
*slc_replyp++ = TELOPT_LINEMODE;
*slc_replyp++ = LM_SLC;
}
void
slc_add_reply(func, flags, value)
unsigned char func;
unsigned char flags;
cc_t value;
{
if ((*slc_replyp++ = func) == IAC)
*slc_replyp++ = IAC;
if ((*slc_replyp++ = flags) == IAC)
*slc_replyp++ = IAC;
if ((*slc_replyp++ = (unsigned char)value) == IAC)
*slc_replyp++ = IAC;
}
void
slc_end_reply()
{
register int len;
*slc_replyp++ = IAC;
*slc_replyp++ = SE;
len = slc_replyp - slc_reply;
if (len <= 6)
return;
if (NETROOM() > len) {
ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
}
/*@*/else printf("slc_end_reply: not enough room\n");
}
int
slc_update()
{
register struct spc *spcp;
int need_update = 0;
for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
if (!(spcp->flags&SLC_ACK))
continue;
spcp->flags &= ~SLC_ACK;
if (spcp->valp && (*spcp->valp != spcp->val)) {
*spcp->valp = spcp->val;
need_update = 1;
}
}
return(need_update);
}
#ifdef OLD_ENVIRON
# ifdef ENV_HACK
/*
* Earlier version of telnet/telnetd from the BSD code had
* the definitions of VALUE and VAR reversed. To ensure
* maximum interoperability, we assume that the server is
* an older BSD server, until proven otherwise. The newer
* BSD servers should be able to handle either definition,
* so it is better to use the wrong values if we don't
* know what type of server it is.
*/
int env_auto = 1;
int old_env_var = OLD_ENV_VAR;
int old_env_value = OLD_ENV_VALUE;
# else
# define old_env_var OLD_ENV_VAR
# define old_env_value OLD_ENV_VALUE
# endif
#endif
void
env_opt(buf, len)
register unsigned char *buf;
register int len;
{
register unsigned char *ep = 0, *epc = 0;
register int i;
switch(buf[0]&0xff) {
case TELQUAL_SEND:
env_opt_start();
if (len == 1) {
env_opt_add(NULL);
} else for (i = 1; i < len; i++) {
switch (buf[i]&0xff) {
#ifdef OLD_ENVIRON
case OLD_ENV_VAR:
# ifdef ENV_HACK
if (telopt_environ == TELOPT_OLD_ENVIRON
&& env_auto) {
/* Server has the same definitions */
old_env_var = OLD_ENV_VAR;
old_env_value = OLD_ENV_VALUE;
}
/* FALL THROUGH */
# endif
case OLD_ENV_VALUE:
/*
* Although OLD_ENV_VALUE is not legal, we will
* still recognize it, just in case it is an
* old server that has VAR & VALUE mixed up...
*/
/* FALL THROUGH */
#else
case NEW_ENV_VAR:
#endif
case ENV_USERVAR:
if (ep) {
*epc = 0;
env_opt_add(ep);
}
ep = epc = &buf[i+1];
break;
case ENV_ESC:
i++;
/*FALL THROUGH*/
default:
if (epc)
*epc++ = buf[i];
break;
}
}
if (ep) {
*epc = 0;
env_opt_add(ep);
}
env_opt_end(1);
break;
case TELQUAL_IS:
case TELQUAL_INFO:
/* Ignore for now. We shouldn't get it anyway. */
break;
default:
break;
}
}
#define OPT_REPLY_SIZE 256
unsigned char *opt_reply;
unsigned char *opt_replyp;
unsigned char *opt_replyend;
void
env_opt_start()
{
if (opt_reply)
opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
else
opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
if (opt_reply == NULL) {
/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
opt_reply = opt_replyp = opt_replyend = NULL;
return;
}
opt_replyp = opt_reply;
opt_replyend = opt_reply + OPT_REPLY_SIZE;
*opt_replyp++ = IAC;
*opt_replyp++ = SB;
*opt_replyp++ = telopt_environ;
*opt_replyp++ = TELQUAL_IS;
}
void
env_opt_start_info()
{
env_opt_start();
if (opt_replyp)
opt_replyp[-1] = TELQUAL_INFO;
}
void
env_opt_add(ep)
register unsigned char *ep;
{
register unsigned char *vp, c;
if (opt_reply == NULL) /*XXX*/
return; /*XXX*/
if (ep == NULL || *ep == '\0') {
/* Send user defined variables first. */
env_default(1, 0);
while (ep = env_default(0, 0))
env_opt_add(ep);
/* Now add the list of well know variables. */
env_default(1, 1);
while (ep = env_default(0, 1))
env_opt_add(ep);
return;
}
vp = env_getvalue(ep);
if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
strlen((char *)ep) + 6 > opt_replyend)
{
register int len;
opt_replyend += OPT_REPLY_SIZE;
len = opt_replyend - opt_reply;
opt_reply = (unsigned char *)realloc(opt_reply, len);
if (opt_reply == NULL) {
/*@*/ printf("env_opt_add: realloc() failed!!!\n");
opt_reply = opt_replyp = opt_replyend = NULL;
return;
}
opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
opt_replyend = opt_reply + len;
}
if (opt_welldefined(ep))
#ifdef OLD_ENVIRON
if (telopt_environ == TELOPT_OLD_ENVIRON)
*opt_replyp++ = old_env_var;
else
#endif
*opt_replyp++ = NEW_ENV_VAR;
else
*opt_replyp++ = ENV_USERVAR;
for (;;) {
while (c = *ep++) {
switch(c&0xff) {
case IAC:
*opt_replyp++ = IAC;
break;
case NEW_ENV_VAR:
case NEW_ENV_VALUE:
case ENV_ESC:
case ENV_USERVAR:
*opt_replyp++ = ENV_ESC;
break;
}
*opt_replyp++ = c;
}
if (ep = vp) {
#ifdef OLD_ENVIRON
if (telopt_environ == TELOPT_OLD_ENVIRON)
*opt_replyp++ = old_env_value;
else
#endif
*opt_replyp++ = NEW_ENV_VALUE;
vp = NULL;
} else
break;
}
}
int
opt_welldefined(ep)
char *ep;
{
if ((strcmp(ep, "USER") == 0) ||
(strcmp(ep, "DISPLAY") == 0) ||
(strcmp(ep, "PRINTER") == 0) ||
(strcmp(ep, "SYSTEMTYPE") == 0) ||
(strcmp(ep, "JOB") == 0) ||
(strcmp(ep, "ACCT") == 0))
return(1);
return(0);
}
void
env_opt_end(emptyok)
register int emptyok;
{
register int len;
len = opt_replyp - opt_reply + 2;
if (emptyok || len > 6) {
*opt_replyp++ = IAC;
*opt_replyp++ = SE;
if (NETROOM() > len) {
ring_supply_data(&netoring, opt_reply, len);
printsub('>', &opt_reply[2], len - 2);
}
/*@*/ else printf("slc_end_reply: not enough room\n");
}
if (opt_reply) {
free(opt_reply);
opt_reply = opt_replyp = opt_replyend = NULL;
}
}
int
telrcv()
{
register int c;
register int scc;
register unsigned char *sbp;
int count;
int returnValue = 0;
scc = 0;
count = 0;
while (TTYROOM() > 2) {
if (scc == 0) {
if (count) {
ring_consumed(&netiring, count);
returnValue = 1;
count = 0;
}
sbp = netiring.consume;
scc = ring_full_consecutive(&netiring);
if (scc == 0) {
/* No more data coming in */
break;
}
}
c = *sbp++ & 0xff, scc--; count++;
#ifdef ENCRYPTION
if (decrypt_input)
c = (*decrypt_input)(c);
#endif /* ENCRYPTION */
switch (telrcv_state) {
case TS_CR:
telrcv_state = TS_DATA;
if (c == '\0') {
break; /* Ignore \0 after CR */
}
else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
TTYADD(c);
break;
}
/* Else, fall through */
case TS_DATA:
if (c == IAC) {
telrcv_state = TS_IAC;
break;
}
# if defined(TN3270)
if (In3270) {
*Ifrontp++ = c;
while (scc > 0) {
c = *sbp++ & 0377, scc--; count++;
#ifdef ENCRYPTION
if (decrypt_input)
c = (*decrypt_input)(c);
#endif /* ENCRYPTION */
if (c == IAC) {
telrcv_state = TS_IAC;
break;
}
*Ifrontp++ = c;
}
} else
# endif /* defined(TN3270) */
/*
* The 'crmod' hack (see following) is needed
* since we can't * set CRMOD on output only.
* Machines like MULTICS like to send \r without
* \n; since we must turn off CRMOD to get proper
* input, the mapping is done here (sigh).
*/
if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
if (scc > 0) {
c = *sbp&0xff;
#ifdef ENCRYPTION
if (decrypt_input)
c = (*decrypt_input)(c);
#endif /* ENCRYPTION */
if (c == 0) {
sbp++, scc--; count++;
/* a "true" CR */
TTYADD('\r');
} else if (my_want_state_is_dont(TELOPT_ECHO) &&
(c == '\n')) {
sbp++, scc--; count++;
TTYADD('\n');
} else {
#ifdef ENCRYPTION
if (decrypt_input)
(*decrypt_input)(-1);
#endif /* ENCRYPTION */
TTYADD('\r');
if (crmod) {
TTYADD('\n');
}
}
} else {
telrcv_state = TS_CR;
TTYADD('\r');
if (crmod) {
TTYADD('\n');
}
}
} else {
TTYADD(c);
}
continue;
case TS_IAC:
process_iac:
switch (c) {
case WILL:
telrcv_state = TS_WILL;
continue;
case WONT:
telrcv_state = TS_WONT;
continue;
case DO:
telrcv_state = TS_DO;
continue;
case DONT:
telrcv_state = TS_DONT;
continue;
case DM:
/*
* We may have missed an urgent notification,
* so make sure we flush whatever is in the
* buffer currently.
*/
printoption("RCVD", IAC, DM);
SYNCHing = 1;
(void) ttyflush(1);
SYNCHing = stilloob();
settimer(gotDM);
break;
case SB:
SB_CLEAR();
telrcv_state = TS_SB;
continue;
# if defined(TN3270)
case EOR:
if (In3270) {
if (Ibackp == Ifrontp) {
Ibackp = Ifrontp = Ibuf;
ISend = 0; /* should have been! */
} else {
Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
ISend = 1;
}
}
printoption("RCVD", IAC, EOR);
break;
# endif /* defined(TN3270) */
case IAC:
# if !defined(TN3270)
TTYADD(IAC);
# else /* !defined(TN3270) */
if (In3270) {
*Ifrontp++ = IAC;
} else {
TTYADD(IAC);
}
# endif /* !defined(TN3270) */
break;
case NOP:
case GA:
default:
printoption("RCVD", IAC, c);
break;
}
telrcv_state = TS_DATA;
continue;
case TS_WILL:
printoption("RCVD", WILL, c);
willoption(c);
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_WONT:
printoption("RCVD", WONT, c);
wontoption(c);
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_DO:
printoption("RCVD", DO, c);
dooption(c);
SetIn3270();
if (c == TELOPT_NAWS) {
sendnaws();
} else if (c == TELOPT_LFLOW) {
localflow = 1;
setcommandmode();
setconnmode(0);
}
telrcv_state = TS_DATA;
continue;
case TS_DONT:
printoption("RCVD", DONT, c);
dontoption(c);
flushline = 1;
setconnmode(0); /* set new tty mode (maybe) */
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_SB:
if (c == IAC) {
telrcv_state = TS_SE;
} else {
SB_ACCUM(c);
}
continue;
case TS_SE:
if (c != SE) {
if (c != IAC) {
/*
* This is an error. We only expect to get
* "IAC IAC" or "IAC SE". Several things may
* have happend. An IAC was not doubled, the
* IAC SE was left off, or another option got
* inserted into the suboption are all possibilities.
* If we assume that the IAC was not doubled,
* and really the IAC SE was left off, we could
* get into an infinate loop here. So, instead,
* we terminate the suboption, and process the
* partial suboption if we can.
*/
SB_ACCUM(IAC);
SB_ACCUM(c);
subpointer -= 2;
SB_TERM();
printoption("In SUBOPTION processing, RCVD", IAC, c);
suboption(); /* handle sub-option */
SetIn3270();
telrcv_state = TS_IAC;
goto process_iac;
}
SB_ACCUM(c);
telrcv_state = TS_SB;
} else {
SB_ACCUM(IAC);
SB_ACCUM(SE);
subpointer -= 2;
SB_TERM();
suboption(); /* handle sub-option */
SetIn3270();
telrcv_state = TS_DATA;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -