X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fnet%2FTelnetInputStream.java;h=be3ab507976b72e81d6763b2773b27a6d97d9a34;hb=505be508ae7d3fb48122be548b310a238cfb91eb;hp=ea30171c30d38a47a4acbf13e035739db6a48424;hpb=42873e30bf487bc0b695d60652dba44f82185dbb;p=fanfix.git diff --git a/src/jexer/net/TelnetInputStream.java b/src/jexer/net/TelnetInputStream.java index ea30171..be3ab50 100644 --- a/src/jexer/net/TelnetInputStream.java +++ b/src/jexer/net/TelnetInputStream.java @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (C) 2017 Kevin Lamonte + * Copyright (C) 2019 Kevin Lamonte * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -40,8 +40,15 @@ import static jexer.net.TelnetSocket.*; /** * TelnetInputStream works with TelnetSocket to perform the telnet protocol. */ -public final class TelnetInputStream extends InputStream - implements SessionInfo { +public class TelnetInputStream extends InputStream implements SessionInfo { + + // ------------------------------------------------------------------------ + // Constants -------------------------------------------------------------- + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Variables -------------------------------------------------------------- + // ------------------------------------------------------------------------ /** * The root TelnetSocket that has my telnet protocol state. @@ -76,6 +83,61 @@ public final class TelnetInputStream extends InputStream */ private int readBufferStart; + /** + * User name. + */ + private String username = ""; + + /** + * Language. + */ + private String language = "en_US"; + + /** + * Text window width. + */ + private int windowWidth = 80; + + /** + * Text window height. + */ + private int windowHeight = 24; + + /** + * When true, the last read byte from the remote side was IAC. + */ + private boolean iac = false; + + /** + * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation. + */ + private boolean dowill = false; + + /** + * The telnet option being negotiated. + */ + private int dowillType = 0; + + /** + * When true, we are waiting to see the end of the sub-negotiation + * sequence. + */ + private boolean subnegEnd = false; + + /** + * When true, the last byte read from the remote side was CR. + */ + private boolean readCR = false; + + /** + * The subnegotiation buffer. + */ + private ArrayList subnegBuffer; + + // ------------------------------------------------------------------------ + // Constructors ----------------------------------------------------------- + // ------------------------------------------------------------------------ + /** * Package private constructor. * @@ -97,27 +159,9 @@ public final class TelnetInputStream extends InputStream subnegBuffer = new ArrayList(); } - // SessionInfo interface -------------------------------------------------- - - /** - * User name. - */ - private String username = ""; - - /** - * Language. - */ - private String language = "en_US"; - - /** - * Text window width. - */ - private int windowWidth = 80; - - /** - * Text window height. - */ - private int windowHeight = 24; + // ------------------------------------------------------------------------ + // SessionInfo ------------------------------------------------------------ + // ------------------------------------------------------------------------ /** * Username getter. @@ -155,6 +199,15 @@ public final class TelnetInputStream extends InputStream this.language = language; } + /** + * Get the terminal type as reported by the telnet Terminal Type option. + * + * @return the terminal type + */ + public String getTerminalType() { + return master.terminalType; + } + /** * Text window width getter. * @@ -180,7 +233,9 @@ public final class TelnetInputStream extends InputStream // NOP } - // InputStream interface -------------------------------------------------- + // ------------------------------------------------------------------------ + // InputStream ------------------------------------------------------------ + // ------------------------------------------------------------------------ /** * Returns an estimate of the number of bytes that can be read (or @@ -265,6 +320,7 @@ public final class TelnetInputStream extends InputStream // If we got something, return it. if (rc > 0) { + readBufferEnd += rc; readBufferStart++; return readBuffer[readBufferStart - 1]; } @@ -371,39 +427,9 @@ public final class TelnetInputStream extends InputStream return n; } - // Telnet protocol -------------------------------------------------------- - - - /** - * When true, the last read byte from the remote side was IAC. - */ - private boolean iac = false; - - /** - * When true, we are in the middle of a DO/DONT/WILL/WONT negotiation. - */ - private boolean dowill = false; - - /** - * The telnet option being negotiated. - */ - private int dowillType = 0; - - /** - * When true, we are waiting to see the end of the sub-negotiation - * sequence. - */ - private boolean subnegEnd = false; - - /** - * When true, the last byte read from the remote side was CR. - */ - private boolean readCR = false; - - /** - * The subnegotiation buffer. - */ - private ArrayList subnegBuffer; + // ------------------------------------------------------------------------ + // TelnetInputStream ------------------------------------------------------ + // ------------------------------------------------------------------------ /** * For debugging, return a descriptive string for this telnet option. @@ -488,9 +514,9 @@ public final class TelnetInputStream extends InputStream final int option) throws IOException { byte [] buffer = new byte[3]; - buffer[0] = (byte)TELNET_IAC; - buffer[1] = (byte)response; - buffer[2] = (byte)option; + buffer[0] = (byte) TELNET_IAC; + buffer[1] = (byte) response; + buffer[2] = (byte) option; output.rawWrite(buffer); } @@ -563,12 +589,12 @@ public final class TelnetInputStream extends InputStream final byte [] response) throws IOException { byte [] buffer = new byte[response.length + 5]; - buffer[0] = (byte)TELNET_IAC; - buffer[1] = (byte)TELNET_SB; - buffer[2] = (byte)option; + buffer[0] = (byte) TELNET_IAC; + buffer[1] = (byte) TELNET_SB; + buffer[2] = (byte) option; System.arraycopy(response, 0, buffer, 3, response.length); - buffer[response.length + 3] = (byte)TELNET_IAC; - buffer[response.length + 4] = (byte)TELNET_SE; + buffer[response.length + 3] = (byte) TELNET_IAC; + buffer[response.length + 4] = (byte) TELNET_SE; output.rawWrite(buffer); } @@ -907,28 +933,44 @@ public final class TelnetInputStream extends InputStream int i = 0; i++; - if (subnegBuffer.get(i) == (byte)TELNET_IAC) { + if (subnegBuffer.get(i) == (byte) TELNET_IAC) { i++; } - windowWidth = subnegBuffer.get(i) * 256; + int width = subnegBuffer.get(i); + if (width < 0) { + width += 256; + } + windowWidth = width * 256; i++; - if (subnegBuffer.get(i) == (byte)TELNET_IAC) { + if (subnegBuffer.get(i) == (byte) TELNET_IAC) { i++; } - windowWidth += subnegBuffer.get(i); + width = subnegBuffer.get(i); + windowWidth += width; + if (width < 0) { + windowWidth += 256; + } i++; - if (subnegBuffer.get(i) == (byte)TELNET_IAC) { + if (subnegBuffer.get(i) == (byte) TELNET_IAC) { i++; } - windowHeight = subnegBuffer.get(i) * 256; + int height = subnegBuffer.get(i); + if (height < 0) { + height += 256; + } + windowHeight = height * 256; i++; - if (subnegBuffer.get(i) == (byte)TELNET_IAC) { + if (subnegBuffer.get(i) == (byte) TELNET_IAC) { i++; } - windowHeight += subnegBuffer.get(i); + height = subnegBuffer.get(i); + windowHeight += height; + if (height < 0) { + windowHeight += 256; + } } break; @@ -960,13 +1002,25 @@ public final class TelnetInputStream extends InputStream assert (len > 0); // The current writing position in buf. - int bufN = 0; + int bufN = off; // We will keep trying to read() until we have something to return. do { - // Read up to len bytes - byte [] buffer = new byte[len]; + 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 @@ -987,16 +1041,16 @@ public final class TelnetInputStream extends InputStream if (subnegEnd == true) { // Looking for IAC SE to end this subnegotiation - if (b == (byte)TELNET_SE) { + if (b == (byte) TELNET_SE) { if (iac == true) { iac = false; subnegEnd = false; handleSubneg(); } - } else if (b == (byte)TELNET_IAC) { + } else if (b == (byte) TELNET_IAC) { if (iac == true) { // An argument to the subnegotiation option - subnegBuffer.add((byte)TELNET_IAC); + subnegBuffer.add((byte) TELNET_IAC); } else { iac = true; } @@ -1015,14 +1069,14 @@ public final class TelnetInputStream extends InputStream case 0: // Binary Transmission - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use binary transmission, yay. master.binaryMode = true; - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for binary transmission. WILL(b); master.binaryMode = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // We're screwed, server won't do binary // transmission. master.binaryMode = false; @@ -1034,14 +1088,14 @@ public final class TelnetInputStream extends InputStream case 1: // Echo - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use echo, yay. master.echoMode = true; - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for echo. WILL(b); master.echoMode = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // We're screwed, server won't do echo. master.echoMode = false; } else { @@ -1052,14 +1106,14 @@ public final class TelnetInputStream extends InputStream case 3: // Suppress Go Ahead - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use suppress go-ahead, yay. master.goAhead = false; - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for suppress go-ahead. WILL(b); master.goAhead = false; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // We're screwed, server won't do suppress // go-ahead. master.goAhead = true; @@ -1071,7 +1125,7 @@ public final class TelnetInputStream extends InputStream case 24: // Terminal Type - send what's in TERM - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use terminal type, yay. if (master.isServer && master.doTermType @@ -1081,11 +1135,11 @@ public final class TelnetInputStream extends InputStream } else if (!master.isServer) { master.doTermType = true; } - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for terminal type. WILL(b); master.doTermType = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // We're screwed, server won't do terminal type. master.doTermType = false; } else { @@ -1096,16 +1150,16 @@ public final class TelnetInputStream extends InputStream case 31: // NAWS - if (dowillType == (byte)TELNET_WILL) { + 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) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for NAWS. WILL(b); master.doNAWS = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // Server won't do NAWS. master.doNAWS = false; } else { @@ -1116,7 +1170,7 @@ public final class TelnetInputStream extends InputStream case 32: // Terminal Speed - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use terminal speed, yay. if (master.isServer && master.doTermSpeed @@ -1126,11 +1180,11 @@ public final class TelnetInputStream extends InputStream } else if (!master.isServer) { master.doTermSpeed = true; } - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for terminal speed. WILL(b); master.doTermSpeed = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // We're screwed, server won't do terminal speed. master.doTermSpeed = false; } else { @@ -1141,7 +1195,7 @@ public final class TelnetInputStream extends InputStream case 39: // New Environment - if (dowillType == (byte)TELNET_WILL) { + if (dowillType == (byte) TELNET_WILL) { // Server will use NewEnvironment, yay. if (master.isServer && master.doEnvironment @@ -1151,11 +1205,11 @@ public final class TelnetInputStream extends InputStream } else if (!master.isServer) { master.doEnvironment = true; } - } else if (dowillType == (byte)TELNET_DO) { + } else if (dowillType == (byte) TELNET_DO) { // Server asks for NewEnvironment. WILL(b); master.doEnvironment = true; - } else if (dowillType == (byte)TELNET_WONT) { + } else if (dowillType == (byte) TELNET_WONT) { // Server won't do NewEnvironment. master.doEnvironment = false; } else { @@ -1177,12 +1231,12 @@ public final class TelnetInputStream extends InputStream } // if (dowill == true) // Perform read processing - if (b == (byte)TELNET_IAC) { + if (b == (byte) TELNET_IAC) { // Telnet command if (iac == true) { // IAC IAC -> IAC - buf[bufN++] = (byte)TELNET_IAC; + buf[bufN++] = (byte) TELNET_IAC; iac = false; } else { iac = true; @@ -1193,70 +1247,64 @@ public final class TelnetInputStream extends InputStream switch (b) { - case (byte)TELNET_SE: - // log.debug1(" END Sub-Negotiation"); + case (byte) TELNET_SE: + // END Sub-Negotiation break; - case (byte)TELNET_NOP: - // log.debug1(" NOP"); + case (byte) TELNET_NOP: + // NOP break; - case (byte)TELNET_DM: - // log.debug1(" Data Mark"); + case (byte) TELNET_DM: + // Data Mark break; - case (byte)TELNET_BRK: - // log.debug1(" Break"); + case (byte) TELNET_BRK: + // Break break; - case (byte)TELNET_IP: - // log.debug1(" Interrupt Process"); + case (byte) TELNET_IP: + // Interrupt Process break; - case (byte)TELNET_AO: - // log.debug1(" Abort Output"); + case (byte) TELNET_AO: + // Abort Output break; - case (byte)TELNET_AYT: - // log.debug1(" Are You There?"); + case (byte) TELNET_AYT: + // Are You There? break; - case (byte)TELNET_EC: - // log.debug1(" Erase Character"); + case (byte) TELNET_EC: + // Erase Character break; - case (byte)TELNET_EL: - // log.debug1(" Erase Line"); + case (byte) TELNET_EL: + // Erase Line break; - case (byte)TELNET_GA: - // log.debug1(" Go Ahead"); + case (byte) TELNET_GA: + // Go Ahead break; - case (byte)TELNET_SB: - // log.debug1(" START Sub-Negotiation"); + case (byte) TELNET_SB: + // START Sub-Negotiation // From here we wait for the IAC SE subnegEnd = true; subnegBuffer.clear(); break; - case (byte)TELNET_WILL: - // log.debug1(" WILL"); + case (byte) TELNET_WILL: + // WILL dowill = true; dowillType = b; break; - case (byte)TELNET_WONT: - // log.debug1(" WON'T"); + case (byte) TELNET_WONT: + // WON'T dowill = true; dowillType = b; break; - case (byte)TELNET_DO: - // log.debug1(" DO"); + case (byte) TELNET_DO: + // DO dowill = true; dowillType = b; - - if (master.binaryMode == true) { - // log.debug1("Telnet DO in binary mode"); - } - break; - case (byte)TELNET_DONT: - // log.debug1(" DON'T"); + case (byte) TELNET_DONT: + // DON'T dowill = true; dowillType = b; break; default: // This should be equivalent to IAC NOP - // log.debug1("Will treat as IAC NOP"); break; } iac = false; @@ -1348,5 +1396,4 @@ public final class TelnetInputStream extends InputStream return bufN; } - }