package ring.comms.telnet; import java.io.IOException; import java.io.InputStream; import net.wimpi.telnetd.io.BasicTerminalIO; /** * InputStream implementation built on top of telnetd2. Allows standard Java I/O classes and * practices to be used to get and send data to the connected user. By default, this InputStream * echoes all input back to the user. This can be turned off by calling setEcho(false). * <br/> * <br/> * This class should be thread-safe, as the underlying I/O library synchronizes its read methods. * @author projectmoon * */ public class TelnetInputStream extends InputStream { private BasicTerminalIO io; private boolean echo = true; private byte[] currentBuffer; /** * Creates an input stream from the given BasicTerminalIO object. * @param io The IO object. Usually gotten from a telnet connection. */ public TelnetInputStream(BasicTerminalIO io) { this.io = io; } @Override public int read() throws IOException { int i = io.read(); if (echo) { io.write((char)i); } return i; } @Override public int read(byte[] b, int off, int len) throws IOException { int bytesRead = 0; currentBuffer = new byte[len]; for (int c = off; c < len; c++) { int i = io.read(); //Yes, this is a terrible hack. BACKSPACE - 1 is the actual backspace key, //whereas BACKSPACE is ^H key. This should cover most modern telnet connections... //Depending on user settings, they could have this mapped to either BACKSPACE //or BACKSPACE -1. if (i == BasicTerminalIO.BACKSPACE || i == BasicTerminalIO.BACKSPACE - 1) { //Can't backspace beyond the start... if (bytesRead > 0) { //Update visually. io.moveLeft(1); io.write(' '); io.moveLeft(1); //and internally. b[c] = (byte)0; currentBuffer[c] = (byte)0; bytesRead --; //needs to be decremented because we are moving backwards in the array. c--; } //decrement c because we either went backwards or nowhere. //loop's c++ will offset this, but if we don't do it, //c keeps increasing. c--; continue; } else { //This is a regular character, so we read it into the stream. b[c] = (byte)i; currentBuffer[c] = (byte)i; bytesRead++; //Echo it back, if it's turned on. //Currently does not echo newlines. if (echo && (char)i != '\n') { io.write((char)i); } } //Only read up to the next line. if ((char)b[c] == '\n') break; } //end of for loop. return bytesRead; } @Override public boolean markSupported() { return false; } /** * Whether or not to echo input back to the user as input is typed. * This defaults to true. * @return */ public boolean getEcho() { return echo; } /** * Sets whether or not to echo input back to the user as input is typed. * @param echo */ public void setEcho(boolean echo) { this.echo = echo; } public String getCurrentBuffer() { return new String(currentBuffer); } }