📄 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(void){ int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { 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! */ char *tt; 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 */ } tt = terminaltype; while ((tt < (terminaltype + sizeof terminaltype-1)) && !SB_EOF()) { int c; c = SB_GET(); if (isupper(c)) { c = tolower(c); } *tt++ = c; /* accumulate name */ } *tt = 0; break; } /* end of case TELOPT_TTYPE */ case TELOPT_NAWS: { 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 */ 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'; esetenv("DISPLAY", (char *)subpointer, 1); break; } /* end of case TELOPT_XDISPLOC */#ifdef TELOPT_NEW_ENVIRON case TELOPT_NEW_ENVIRON:#endif case TELOPT_OLD_ENVIRON: { int c; 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) { 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, { output_data("ENVIRON VALUE and VAR are reversed!\r\n"); }); } } 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(envvarok(varp)) { if (valp) esetenv(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(envvarok(varp)) { if (valp) esetenv(varp, valp, 1); else unsetenv(varp); } break; } /* end of case TELOPT_NEW_ENVIRON */#ifdef 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 default: break; } /* end of switch */} /* end of suboption */voiddoclientstat(void){ clientstat(TELOPT_LINEMODE, WILL, 0);}#define ADD(c) *ncp++ = c#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }voidsend_status(void){ unsigned char statusbuf[256]; unsigned char *ncp; 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 (his_want_state_is_will(i)) { ADD(DO); ADD_DATA(i); } } 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(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 + -