+ // The current writing position in buf.
+ int bufN = off;
+
+ // We will keep trying to read() until we have something to return.
+ do {
+
+ byte [] buffer = null;
+ if (master.binaryMode) {
+ // Binary mode: read up to len bytes. There will never be
+ // more bytes to pass upstream than there are bytes on the
+ // wire.
+ buffer = new byte[len];
+ } else {
+ // ASCII mode: read up to len - 2 bytes. There may have been
+ // some combination of IAC, CR, and NUL from a previous
+ // readImpl() that could result in more bytes to pass up than
+ // are on the wire.
+ buffer = new byte[len - 2];
+ }
+
+ int bufferN = 0;
+
+ // Read some data from the other end
+ int rc = input.read(buffer);
+
+ // Check for EOF or error
+ if (rc > 0) {
+ // More data came in
+ bufferN = rc;
+ } else {
+ // EOF, just return it.
+ return rc;
+ }
+
+ // Loop through the read bytes
+ for (int i = 0; i < bufferN; i++) {
+ byte b = buffer[i];
+
+ if (subnegEnd == true) {
+ // Looking for IAC SE to end this subnegotiation
+ if (b == (byte) TELNET_SE) {
+ if (iac == true) {
+ iac = false;
+ subnegEnd = false;
+ handleSubneg();
+ }
+ } else if (b == (byte) TELNET_IAC) {
+ if (iac == true) {
+ // An argument to the subnegotiation option
+ subnegBuffer.add((byte) TELNET_IAC);
+ } else {
+ iac = true;
+ }
+ } else {
+ // An argument to the subnegotiation option
+ subnegBuffer.add(b);
+ }
+ continue;
+ }
+
+ // Look for DO/DON'T/WILL/WON'T option
+ if (dowill == true) {
+
+ // Look for option/
+ switch (b) {
+
+ case 0:
+ // Binary Transmission
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use binary transmission, yay.
+ master.binaryMode = true;
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for binary transmission.
+ WILL(b);
+ master.binaryMode = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // We're screwed, server won't do binary
+ // transmission.
+ master.binaryMode = false;
+ } else {
+ // Server demands NVT ASCII mode.
+ master.binaryMode = false;
+ }
+ break;
+
+ case 1:
+ // Echo
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use echo, yay.
+ master.echoMode = true;
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for echo.
+ WILL(b);
+ master.echoMode = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // We're screwed, server won't do echo.
+ master.echoMode = false;
+ } else {
+ // Server demands no echo.
+ master.echoMode = false;
+ }
+ break;
+
+ case 3:
+ // Suppress Go Ahead
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use suppress go-ahead, yay.
+ master.goAhead = false;
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for suppress go-ahead.
+ WILL(b);
+ master.goAhead = false;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // We're screwed, server won't do suppress
+ // go-ahead.
+ master.goAhead = true;
+ } else {
+ // Server demands Go-Ahead mode.
+ master.goAhead = true;
+ }
+ break;
+
+ case 24:
+ // Terminal Type - send what's in TERM
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use terminal type, yay.
+ if (master.isServer
+ && master.doTermType
+ ) {
+ requestTerminalType();
+ master.doTermType = false;
+ } else if (!master.isServer) {
+ master.doTermType = true;
+ }
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for terminal type.
+ WILL(b);
+ master.doTermType = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // We're screwed, server won't do terminal type.
+ master.doTermType = false;
+ } else {
+ // Server will not listen to terminal type.
+ master.doTermType = false;
+ }
+ break;
+
+ case 31:
+ // NAWS
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use NAWS, yay.
+ master.doNAWS = true;
+ // NAWS cannot be requested by the server, it is
+ // only sent by the client.
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for NAWS.
+ WILL(b);
+ master.doNAWS = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // Server won't do NAWS.
+ master.doNAWS = false;
+ } else {
+ // Server will not listen to NAWS.
+ master.doNAWS = false;
+ }
+ break;
+
+ case 32:
+ // Terminal Speed
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use terminal speed, yay.
+ if (master.isServer
+ && master.doTermSpeed
+ ) {
+ requestTerminalSpeed();
+ master.doTermSpeed = false;
+ } else if (!master.isServer) {
+ master.doTermSpeed = true;
+ }
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for terminal speed.
+ WILL(b);
+ master.doTermSpeed = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // We're screwed, server won't do terminal speed.
+ master.doTermSpeed = false;
+ } else {
+ // Server will not listen to terminal speed.
+ master.doTermSpeed = false;
+ }
+ break;
+
+ case 39:
+ // New Environment
+ if (dowillType == (byte) TELNET_WILL) {
+ // Server will use NewEnvironment, yay.
+ if (master.isServer
+ && master.doEnvironment
+ ) {
+ requestEnvironment();
+ master.doEnvironment = false;
+ } else if (!master.isServer) {
+ master.doEnvironment = true;
+ }
+ } else if (dowillType == (byte) TELNET_DO) {
+ // Server asks for NewEnvironment.
+ WILL(b);
+ master.doEnvironment = true;
+ } else if (dowillType == (byte) TELNET_WONT) {
+ // Server won't do NewEnvironment.
+ master.doEnvironment = false;
+ } else {
+ // Server will not listen to New Environment.
+ master.doEnvironment = false;
+ }
+ break;
+
+
+ default:
+ // Other side asked for something we don't
+ // understand. Tell them we will not do this option.
+ refuse(dowillType, b);
+ break;
+ }
+
+ dowill = false;
+ continue;
+ } // if (dowill == true)
+
+ // Perform read processing
+ if (b == (byte) TELNET_IAC) {
+
+ // Telnet command
+ if (iac == true) {
+ // IAC IAC -> IAC
+ buf[bufN++] = (byte) TELNET_IAC;
+ iac = false;
+ } else {
+ iac = true;
+ }
+ continue;
+ } else {
+ if (iac == true) {
+
+ switch (b) {
+
+ case (byte) TELNET_SE:
+ // END Sub-Negotiation
+ break;
+ case (byte) TELNET_NOP:
+ // NOP
+ break;
+ case (byte) TELNET_DM:
+ // Data Mark
+ break;
+ case (byte) TELNET_BRK:
+ // Break
+ break;
+ case (byte) TELNET_IP:
+ // Interrupt Process
+ break;
+ case (byte) TELNET_AO:
+ // Abort Output
+ break;
+ case (byte) TELNET_AYT:
+ // Are You There?
+ break;
+ case (byte) TELNET_EC:
+ // Erase Character
+ break;
+ case (byte) TELNET_EL:
+ // Erase Line
+ break;
+ case (byte) TELNET_GA:
+ // Go Ahead
+ break;
+ case (byte) TELNET_SB:
+ // START Sub-Negotiation
+ // From here we wait for the IAC SE
+ subnegEnd = true;
+ subnegBuffer.clear();
+ break;
+ case (byte) TELNET_WILL:
+ // WILL
+ dowill = true;
+ dowillType = b;
+ break;
+ case (byte) TELNET_WONT:
+ // WON'T
+ dowill = true;
+ dowillType = b;
+ break;
+ case (byte) TELNET_DO:
+ // DO
+ dowill = true;
+ dowillType = b;
+ break;
+ case (byte) TELNET_DONT:
+ // DON'T
+ dowill = true;
+ dowillType = b;
+ break;
+ default:
+ // This should be equivalent to IAC NOP
+ break;
+ }
+ iac = false;
+ continue;
+
+ } // if (iac == true)
+
+ /*
+ * All of the regular IAC processing is completed at this
+ * point. Now we need to handle the CR and CR LF cases.
+ *
+ * According to RFC 854, in NVT ASCII mode:
+ * Bare CR -> CR NUL
+ * CR LF -> CR LF
+ *
+ */
+ if (master.binaryMode == false) {
+
+ if (b == C_LF) {
+ if (readCR == true) {
+ // This is CR LF. Send CR LF and turn the cr
+ // flag off.
+ buf[bufN++] = C_CR;
+ buf[bufN++] = C_LF;
+ readCR = false;
+ continue;
+ }
+ // This is bare LF. Send LF.
+ buf[bufN++] = C_LF;
+ continue;
+ }
+
+ if (b == C_NUL) {
+ if (readCR == true) {
+ // This is CR NUL. Send CR and turn the cr
+ // flag off.
+ buf[bufN++] = C_CR;
+ readCR = false;
+ continue;
+ }
+ // This is bare NUL. Send NUL.
+ buf[bufN++] = C_NUL;
+ continue;
+ }
+
+ if (b == C_CR) {
+ if (readCR == true) {
+ // This is CR CR. Send a CR NUL and leave
+ // the cr flag on.
+ buf[bufN++] = C_CR;
+ buf[bufN++] = C_NUL;
+ continue;
+ }
+ // This is the first CR. Set the cr flag.
+ readCR = true;
+ continue;
+ }
+
+ if (readCR == true) {
+ // This was a bare CR in the stream.
+ buf[bufN++] = C_CR;
+ readCR = false;
+ }
+
+ // This is a regular character. Pass it on.
+ buf[bufN++] = b;
+ continue;
+ }
+
+ /*
+ * This is the case for any of:
+ *
+ * 1) A NVT ASCII character that isn't CR, LF, or
+ * NUL.
+ *
+ * 2) A NVT binary character.
+ *
+ * For all of these cases, we just pass the character on.
+ */
+ buf[bufN++] = b;
+
+ } // if (b == TELNET_IAC)
+
+ } // for (int i = 0; i < bufferN; i++)
+
+ } while (bufN == 0);
+
+ // Return bytes read
+ return bufN;
+ }