state.c
字号:
/* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type is * Linemode * Window size * Terminal speed */ voidsuboption(){ register int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { register int xspeed, rspeed; if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ break; settimer(tspeedsubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) return; xspeed = atoi((char *)subpointer); while (SB_GET() != ',' && !SB_EOF()); if (SB_EOF()) return; rspeed = atoi((char *)subpointer); clientstat(TELOPT_TSPEED, xspeed, rspeed); break; } /* end of case TELOPT_TSPEED */ case TELOPT_TTYPE: { /* Yaaaay! */ static char terminalname[41]; if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ break; settimer(ttypesubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) { return; /* ??? XXX but, this is the most robust */ } terminaltype = terminalname; while ((terminaltype < (terminalname + sizeof terminalname-1)) && !SB_EOF()) { register int c; c = SB_GET(); if (isupper(c)) { c = tolower(c); } *terminaltype++ = c; /* accumulate name */ } *terminaltype = 0; terminaltype = terminalname; break; } /* end of case TELOPT_TTYPE */ case TELOPT_NAWS: { register int xwinsize, ywinsize; if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ break; if (SB_EOF()) return; xwinsize = SB_GET() << 8; if (SB_EOF()) return; xwinsize |= SB_GET(); if (SB_EOF()) return; ywinsize = SB_GET() << 8; if (SB_EOF()) return; ywinsize |= SB_GET(); clientstat(TELOPT_NAWS, xwinsize, ywinsize); break; } /* end of case TELOPT_NAWS */#ifdef LINEMODE case TELOPT_LINEMODE: { register int request; if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ break; /* * Process linemode suboptions. */ if (SB_EOF()) break; /* garbage was sent */ request = SB_GET(); /* get will/wont */ if (SB_EOF()) break; /* another garbage check */ if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ /* * Process suboption buffer of slc's */ start_slc(1); do_opt_slc(subpointer, subend - subpointer); (void) end_slc(0); break; } else if (request == LM_MODE) { if (SB_EOF()) return; useeditmode = SB_GET(); /* get mode flag */ clientstat(LM_MODE, 0, 0); break; } if (SB_EOF()) break; switch (SB_GET()) { /* what suboption? */ case LM_FORWARDMASK: /* * According to spec, only server can send request for * forwardmask, and client can only return a positive response. * So don't worry about it. */ default: break; } break; } /* end of case TELOPT_LINEMODE */#endif case TELOPT_STATUS: { int mode; if (SB_EOF()) break; mode = SB_GET(); switch (mode) { case TELQUAL_SEND: if (my_state_is_will(TELOPT_STATUS)) send_status(); break; case TELQUAL_IS: break; default: break; } break; } /* end of case TELOPT_STATUS */ case TELOPT_XDISPLOC: { if (SB_EOF() || SB_GET() != TELQUAL_IS) return; settimer(xdisplocsubopt); subpointer[SB_LEN()] = '\0'; (void)setenv("DISPLAY", (char *)subpointer, 1); break; } /* end of case TELOPT_XDISPLOC */#ifdef TELOPT_NEW_ENVIRON case TELOPT_NEW_ENVIRON:#endif case TELOPT_OLD_ENVIRON: { register int c; register char *cp, *varp, *valp; if (SB_EOF()) return; c = SB_GET(); if (c == TELQUAL_IS) { if (subchar == TELOPT_OLD_ENVIRON) settimer(oenvironsubopt); else settimer(environsubopt); } else if (c != TELQUAL_INFO) { return; }#ifdef TELOPT_NEW_ENVIRON if (subchar == TELOPT_NEW_ENVIRON) { while (!SB_EOF()) { c = SB_GET(); if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) break; } } else#endif {#ifdef ENV_HACK /* * We only want to do this if we haven't already decided * whether or not the other side has its VALUE and VAR * reversed. */ if (env_ovar < 0) { register int last = -1; /* invalid value */ int empty = 0; int got_var = 0, got_value = 0, got_uservar = 0; /* * The other side might have its VALUE and VAR values * reversed. To be interoperable, we need to determine * which way it is. If the first recognized character * is a VAR or VALUE, then that will tell us what * type of client it is. If the fist recognized * character is a USERVAR, then we continue scanning * the suboption looking for two consecutive * VAR or VALUE fields. We should not get two * consecutive VALUE fields, so finding two * consecutive VALUE or VAR fields will tell us * what the client is. */ SB_SAVE(); while (!SB_EOF()) { c = SB_GET(); switch(c) { case OLD_ENV_VAR: if (last < 0 || last == OLD_ENV_VAR || (empty && (last == OLD_ENV_VALUE))) goto env_ovar_ok; got_var++; last = OLD_ENV_VAR; break; case OLD_ENV_VALUE: if (last < 0 || last == OLD_ENV_VALUE || (empty && (last == OLD_ENV_VAR))) goto env_ovar_wrong; got_value++; last = OLD_ENV_VALUE; break; case ENV_USERVAR: /* count strings of USERVAR as one */ if (last != ENV_USERVAR) got_uservar++; if (empty) { if (last == OLD_ENV_VALUE) goto env_ovar_ok; if (last == OLD_ENV_VAR) goto env_ovar_wrong; } last = ENV_USERVAR; break; case ENV_ESC: if (!SB_EOF()) c = SB_GET(); /* FALL THROUGH */ default: empty = 0; continue; } empty = 1; } if (empty) { if (last == OLD_ENV_VALUE) goto env_ovar_ok; if (last == OLD_ENV_VAR) goto env_ovar_wrong; } /* * Ok, the first thing was a USERVAR, and there * are not two consecutive VAR or VALUE commands, * and none of the VAR or VALUE commands are empty. * If the client has sent us a well-formed option, * then the number of VALUEs received should always * be less than or equal to the number of VARs and * USERVARs received. * * If we got exactly as many VALUEs as VARs and * USERVARs, the client has the same definitions. * * If we got exactly as many VARs as VALUEs and * USERVARS, the client has reversed definitions. */ if (got_uservar + got_var == got_value) { env_ovar_ok: env_ovar = OLD_ENV_VAR; env_ovalue = OLD_ENV_VALUE; } else if (got_uservar + got_value == got_var) { env_ovar_wrong: env_ovar = OLD_ENV_VALUE; env_ovalue = OLD_ENV_VAR; DIAG(TD_OPTIONS, {sprintf(nfrontp, "ENVIRON VALUE and VAR are reversed!\r\n"); nfrontp += strlen(nfrontp);}); } } SB_RESTORE();#endif while (!SB_EOF()) { c = SB_GET(); if ((c == env_ovar) || (c == ENV_USERVAR)) break; } } if (SB_EOF()) return; cp = varp = (char *)subpointer; valp = 0; while (!SB_EOF()) { c = SB_GET(); if (subchar == TELOPT_OLD_ENVIRON) { if (c == env_ovar) c = NEW_ENV_VAR; else if (c == env_ovalue) c = NEW_ENV_VALUE; } switch (c) { case NEW_ENV_VALUE: *cp = '\0'; cp = valp = (char *)subpointer; break; case NEW_ENV_VAR: case ENV_USERVAR: *cp = '\0'; if (valp) (void)setenv(varp, valp, 1); else unsetenv(varp); cp = varp = (char *)subpointer; valp = 0; break; case ENV_ESC: if (SB_EOF()) break; c = SB_GET(); /* FALL THROUGH */ default: *cp++ = c; break; } } *cp = '\0'; if (valp) (void)setenv(varp, valp, 1); else unsetenv(varp); break; } /* end of case TELOPT_NEW_ENVIRON */#if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: if (SB_EOF()) break; switch(SB_GET()) { case TELQUAL_SEND: case TELQUAL_REPLY: /* * These are sent by us and cannot be sent by * the client. */ break; case TELQUAL_IS: auth_is(subpointer, SB_LEN()); break; case TELQUAL_NAME: auth_name(subpointer, SB_LEN()); break; } break;#endif#ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) break; switch(SB_GET()) { case ENCRYPT_SUPPORT: encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_IS: encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_START: encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: encrypt_end(); break; case ENCRYPT_REQSTART: encrypt_request_start(subpointer, SB_LEN()); break; case ENCRYPT_REQEND: /* * We can always send an REQEND so that we cannot * get stuck encrypting. We should only get this * if we have been able to get in the correct mode * anyhow. */ encrypt_request_end(); break; case ENCRYPT_ENC_KEYID: encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break;#endif /* ENCRYPTION */ default: break; } /* end of switch */} /* end of suboption */ voiddoclientstat(){ clientstat(TELOPT_LINEMODE, WILL, 0);}#define ADD(c) *ncp++ = c;#define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; } voidsend_status(){ unsigned char statusbuf[256]; register unsigned char *ncp; register unsigned char i; ncp = statusbuf; netflush(); /* get rid of anything waiting to go out */ ADD(IAC); ADD(SB); ADD(TELOPT_STATUS); ADD(TELQUAL_IS); /* * We check the want_state rather than the current state, * because if we received a DO/WILL for an option that we * don't support, and the other side didn't send a DONT/WONT * in response to our WONT/DONT, then the "state" will be * WILL/DO, and the "want_state" will be WONT/DONT. We * need to go by the latter. */ for (i = 0; i < (unsigned char)NTELOPTS; i++) { if (my_want_state_is_will(i)) { ADD(WILL); ADD_DATA(i); if (i == IAC) ADD(IAC); } if (his_want_state_is_will(i)) { ADD(DO); ADD_DATA(i); if (i == IAC) ADD(IAC); } } if (his_want_state_is_will(TELOPT_LFLOW)) { ADD(SB); ADD(TELOPT_LFLOW); if (flowmode) { ADD(LFLOW_ON); } else { ADD(LFLOW_OFF); } ADD(SE); if (restartany >= 0) { ADD(SB) ADD(TELOPT_LFLOW); if (restartany) { ADD(LFLOW_RESTART_ANY); } else { ADD(LFLOW_RESTART_XON); } ADD(SE) ADD(SB); } }#ifdef LINEMODE if (his_want_state_is_will(TELOPT_LINEMODE)) { unsigned char *cp, *cpe; int len; ADD(SB); ADD(TELOPT_LINEMODE); ADD(LM_MODE); ADD_DATA(editmode); if (editmode == IAC) ADD(IAC); ADD(SE); ADD(SB); ADD(TELOPT_LINEMODE); ADD(LM_SLC); start_slc(0); send_slc(); len = end_slc(&cp); for (cpe = cp + len; cp < cpe; cp++) ADD_DATA(*cp); ADD(SE); }#endif /* LINEMODE */ ADD(IAC); ADD(SE); writenet(statusbuf, ncp - statusbuf); netflush(); /* Send it on its way */ DIAG(TD_OPTIONS, {printsub('>', statusbuf, ncp - statusbuf); netflush();});}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -