📄 telnetio.java
字号:
} } m_Initializing = false; }//initTelnetCommunication /** * Method that represents the answer to the * AreYouThere question of the telnet protocol specification * <p/> * Output of the String [HostAdress:Yes] */ private void IamHere() { try { write("[" + m_LocalAddress.toString() + ":Yes]"); flush(); } catch (Exception ex) { log.error("IamHere()", ex); } }//IamHere /** * Network virtual terminal break. */ private void nvtBreak() { m_Connection.processConnectionEvent(new ConnectionEvent(m_Connection, ConnectionEvent.CONNECTION_BREAK)); }//nvtBreak /** * Method that checks reported terminal sizes and sets the * asserted values in the ConnectionData instance associated with * the connection. * * @param width Integer that represents the Window width in chars * @param height Integer that represents the Window height in chars */ private void setTerminalGeometry(int width, int height) { if (width < SMALLEST_BELIEVABLE_WIDTH) { width = DEFAULT_WIDTH; } if (height < SMALLEST_BELIEVABLE_HEIGHT) { height = DEFAULT_HEIGHT; } //DEBUG: write("[New Window Size " + window_width + "x" + window_height + "]"); m_ConnectionData.setTerminalGeometry(width, height); }//setTerminalGeometry public void setEcho(boolean b) { }//setEcho /**** End telnet protocol level communication methods *******************************/ /** * An inner class for handling incoming option negotiations implementing the <B>telnet protocol</B> * specification based upon following Standards and RFCs: * <OL> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc854.txt">854 Telnet Protocol Specification</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc855.txt">855 Telnet Option Specifications</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc857.txt">857 Telnet Echo Option</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc858.txt">858 Telnet Supress Go Ahead Option</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc727.txt">727 Telnet Logout Option</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc1073.txt">1073 Telnet Window Size Option</A> * <LI><A HREF="ftp://ds.internic.net/rfc/rfc1091.txt">1091 Telnet Terminal-Type Option</A> * </OL> * <p/> * Furthermore there are some more, which helped to solve problems, or might be important * for future enhancements:<BR> * <A HREF="ftp://ds.internic.net/rfc/rfc1143.txt">1143 The Q Method of Implementing Option Negotiation</A><BR> * <A HREF="ftp://ds.internic.net/rfc/rfc1416.txt">1416 Telnet Authentication Option</A><BR> * <p/> * After an intense study of the available material (mainly cryptical written RFCs, * a telnet client implementation for the macintosh based upon NCSA telnet, and a server side * implementation called key, a mud-like system completely written in Java) I realized * the problems we are facing regarding to the telnet protocol: * <OL> * <LI> a minimal spread of invented options, which means there are a lot of invented options, * but rarely they made it through to become a standard. * <LI> Dependency on a special type of implementation is dangerous in our case. * We are no kind of host that offers the user to run several processes at once, * a BBS is intended to be a single process the user is interacting with. * <LI> The <B>LAMER</B> has to be expected to log in with the standard Mircosoft telnet * implementation. This means forget every nice feature and most of the almost-standards. * <p/> * </OL> * <BR> * * @author Dieter Wimberger * @version 1.1 16/06/1998 * <p/> * <p/> * <B>To-Do</B>:<UL> * <LI>UNIX conform new style TTYPE negotiation. Setting a list and selecting from it... * </UL> */ class IACHandler { /** * Telnet readin buffer * Here its implemented guys. Open your eyes upon this solution. * The others take a one byte solution :) */ private int[] buffer = new int[2]; /** * DO_ECHO or not */ private boolean DO_ECHO = false; /** * DO_SUPGA or not */ private boolean DO_SUPGA = false; /** * DO_NAWS or not */ private boolean DO_NAWS = false; /** * DO_TTYPE or not */ private boolean DO_TTYPE = false; /** * DO_LINEMODE or not */ private boolean DO_LINEMODE = false; /** * DO_NEWENV or not */ private boolean DO_NEWENV = false; /** * Are we waiting for a DO reply? */ private boolean WAIT_DO_REPLY_SUPGA = false; private boolean WAIT_DO_REPLY_ECHO = false; private boolean WAIT_DO_REPLY_NAWS = false; private boolean WAIT_DO_REPLY_TTYPE = false; private boolean WAIT_DO_REPLY_LINEMODE = false; private boolean WAIT_LM_MODE_ACK = false; private boolean WAIT_LM_DO_REPLY_FORWARDMASK = false; private boolean WAIT_DO_REPLY_NEWENV = false; private boolean WAIT_NE_SEND_REPLY = false; /** * Are we waiting for a WILL reply? */ private boolean WAIT_WILL_REPLY_SUPGA = false; private boolean WAIT_WILL_REPLY_ECHO = false; private boolean WAIT_WILL_REPLY_NAWS = false; private boolean WAIT_WILL_REPLY_TTYPE = false; public void doCharacterModeInit() throws IOException { sendCommand(WILL, ECHO, true); sendCommand(DONT, ECHO, true); //necessary for some clients sendCommand(DO, NAWS, true); sendCommand(WILL, SUPGA, true); sendCommand(DO, SUPGA, true); sendCommand(DO, TTYPE, true); sendCommand(DO, NEWENV, true); //environment variables }//doCharacterModeInit public void doLineModeInit() throws IOException { sendCommand(DO, NAWS, true); sendCommand(WILL, SUPGA, true); sendCommand(DO, SUPGA, true); sendCommand(DO, TTYPE, true); sendCommand(DO, LINEMODE, true); sendCommand(DO, NEWENV, true); }//doLineModeInit /** * Method to handle a IAC that came in over the line. * * @param i (int)ed byte that followed the IAC */ public void handleC(int i) throws IOException { buffer[0] = i; if (!parseTWO(buffer)) { buffer[1] = rawread(); parse(buffer); } buffer[0] = 0; buffer[1] = 0; }//handleC /** * Method that parses for options with two characters. * * @param buf int [] that represents the first byte that followed the IAC first. * @return true when it was a two byte command (IAC OPTIONBYTE) */ private boolean parseTWO(int[] buf) { switch (buf[0]) { case IAC: //doubled IAC to escape 255 is handled within the //read method. break; case AYT: IamHere(); break; case AO: case IP: case EL: case EC: case NOP: break; case BRK: nvtBreak(); break; default: return false; } return true; }//parseTWO /** * Method that parses further on for options. * * @param buf that represents the first two bytes that followed the IAC. */ private void parse(int[] buf) throws IOException { switch (buf[0]) { /* First switch on the Negotiation Option */ case WILL: if (supported(buf[1]) && isEnabled(buf[1])) { ;// do nothing } else { if (waitDOreply(buf[1]) && supported(buf[1])) { enable(buf[1]); setWait(DO, buf[1], false); } else { if (supported(buf[1])) { sendCommand(DO, buf[1], false); enable(buf[1]); } else { sendCommand(DONT, buf[1], false); } } } break; case WONT: if (waitDOreply(buf[1]) && supported(buf[1])) { setWait(DO, buf[1], false); } else { if (supported(buf[1]) && isEnabled(buf[1])) { // eanable() Method disables an Option that is already enabled enable(buf[1]); } } break; case DO: if (supported(buf[1]) && isEnabled(buf[1])) { ; // do nothing } else { if (waitWILLreply(buf[1]) && supported(buf[1])) { enable(buf[1]); setWait(WILL, buf[1], false); } else { if (supported(buf[1])) { sendCommand(WILL, buf[1], false); enable(buf[1]); } else { sendCommand(WONT, buf[1], false); } } } break; case DONT: if (waitWILLreply(buf[1]) && supported(buf[1])) { setWait(WILL, buf[1], false); } else { if (supported(buf[1]) && isEnabled(buf[1])) { // enable() Method disables an Option that is already enabled enable(buf[1]); } } break; /* Now about other two byte IACs */ case DM: //How do I implement a SYNCH signal? break; case SB: //handle subnegotiations if ((supported(buf[1])) && (isEnabled(buf[1]))) { switch (buf[1]) { case NAWS: handleNAWS(); break; case TTYPE: handleTTYPE(); break; case LINEMODE: handleLINEMODE(); break; case NEWENV: handleNEWENV(); break; default: ; } } else { //do nothing } break; default: ; }//switch }//parse /** * Method that reads a NawsSubnegotiation that ends up with a IAC SE * If the measurements are unbelieveable it switches to the defaults. */ private void handleNAWS() throws IOException { int width = read16int(); if (width == 255) { width = read16int(); //handle doubled 255 value; } int height = read16int(); if (height == 255) { height = read16int(); //handle doubled 255 value; } skipToSE(); setTerminalGeometry(width, height); }//handleNAWS /** * Method that reads a TTYPE Subnegotiation String that ends up with a IAC SE * If no Terminal is valid, we switch to the dumb "none" terminal. */ private void handleTTYPE() throws IOException { String tmpstr = ""; // The next read should be 0 which is IS by the protocol // specs. hmmm? rawread(); //that should be the is :) tmpstr = readIACSETerminatedString(40); log.debug("Reported terminal name " + tmpstr); m_ConnectionData.setNegotiatedTerminalType(tmpstr); }//handleTTYPE /** * Method that handles LINEMODE subnegotiation. */ public void handleLINEMODE() throws IOException { int c = rawread(); switch (c) { case LM_MODE: handleLMMode(); break; case LM_SLC: handleLMSLC(); break; case WONT: case WILL: handleLMForwardMask(c); break; default: //skip to (including) SE skipToSE(); } }//handleLINEMODE public void handleLMMode() throws IOException { //we sent the default which no client might deny //so we only wait the ACK if (WAIT_LM_MODE_ACK) { int mask = rawread(); if (mask != (LM_EDIT | LM_TRAPSIG | LM_MODEACK)) { log.debug("Client violates linemodeack sent: " + mask); } WAIT_LM_MODE_ACK = false; } skipToSE(); }//handleLMMode public void handleLMSLC() throws IOException { int[] triple = new int[3]; if (!readTriple(triple)) return; //SLC will be initiated by the client //case 1. client requests set //LINEMODE SLC 0 SLC_DEFAULT 0 if ((triple[0] == 0) && (triple[1] == LM_SLC_DEFAULT) && (triple[2] == 0)) { skipToSE(); //reply with SLC xxx SLC_DEFAULT 0 rawWrite(IAC); rawWrite(SB); rawWrite(LINEMODE); rawWrite(LM_SLC); //triples defaults for all for (int i = 1; i < 12; i++) { rawWrite(i); rawWrite(LM_SLC_DEFAULT); rawWrite(0); } rawWrite(IAC); rawWrite(SE); flush(); } else { //case 2: just acknowledge anything we get from the client rawWrite(IAC); rawWrite(SB); rawWrite(LINEMODE); rawWrite(LM_SLC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -