package net.sourceforge.pain.network.console.telnet; import net.sourceforge.pain.network.console.*; import net.sourceforge.pain.util.*; import java.io.*; import java.net.*; public class TelnetConsoleAdapter extends ConsoleAdapter implements Runnable { /** IAC - init sequence for telnet negotiation. */ private final static int IAC = 255; /** [IAC] End Of Record */ // private final static int EOR = 239; not used /** [IAC] WILL */ private final static int WILL = 251; /** [IAC] WONT */ private final static int WONT = 252; /** [IAC] DO */ private final static int DO = 253; /** [IAC] DONT */ private final static int DONT = 254; /** [AYT] are you there?*/ private final static int AYT = 246; private final byte[] IACWONT = {(byte) IAC, (byte) WONT, 0}; private final byte[] IACDONT = {(byte) IAC, (byte) DONT, 0}; private final byte[] IACAYT = {(byte) IAC, (byte) AYT, 0}; TelnetConsoleServer server; Socket socket; InputStream is; OutputStream os; boolean forcedClose; boolean lostLink; Object monitor = new Object(); int currentColor = AnsiColor.COLOR_CLEAR; StringBuffer out = new StringBuffer(); protected TelnetConsoleAdapter(TelnetConsoleServer server, Socket socket) throws Exception { super(); this.server = server; this.socket = socket; socket.setSoTimeout(10000); is = socket.getInputStream(); os = socket.getOutputStream(); init(); } public void run() { startService(); } public void startService() { forcedClose = false; try { StringBuffer buf = new StringBuffer(); int c = 0; do { try { c = read(is); if (c > 0) { if (c == IAC) { //Interpret As Command c = read(is); if (c != IAC) { // its really command if (c == WILL) { // if command is WILL echo DON'T Log.debug("will"); c = read(is); IACDONT[2] = (byte) c; sendRaw(IACDONT); // we do not want any command :) } else if (c == DO) {// if command is DO echo WON'T Log.debug("do"); c = read(is); IACWONT[2] = (byte) c; sendRaw(IACWONT); } else { Log.debug("telnet command:" + c); } continue; } } if (c == '\r') { continue; } if (c == '\n') { if (buf.length() > 0) { lineReceived(buf.toString()); buf.delete(0, buf.length()); } else { lineReceived(""); } } else { buf.append((char) c); } } } catch (InterruptedIOException e) { break; } catch (IOException e) { if (!forcedClose) { Log.error(e.getMessage(), e); lostLink = true; } break; } catch (Exception e) { Log.error(e.getMessage(), e); } } while (c > -1 && !forcedClose && !lostLink); } catch (Exception e) { e.printStackTrace(); } finally { server.onClose(this); try { socket.close(); } catch (Exception ignored) { } if (!forcedClose) { closedRemote(); } } } private int read(InputStream is) throws Exception { if (is.available() > 0) { return is.read(); } do { synchronized (monitor) { monitor.wait(10); } if (forcedClose) { throw new IOException("forced close!"); } if (lostLink) { throw new InterruptedIOException("lost link!"); } } while (is.available() <= 0); return is.read(); } public void outText(String text) { // special symbol color parsing for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (c == '{') { i++; if (i < text.length()) { // explicit mapping inherited from old version -> todo: do more clear color model int newColor = AnsiColor.toColor(text.charAt(i)); if (newColor != currentColor) { appendColorMask(newColor); currentColor = newColor; } } } else if (c == '\n') { out.append("\r\n"); } else { out.append(c); } } } private synchronized void sendRaw(byte[] data) throws IOException { os.write(data); os.flush(); } public void flush() throws IOException { if (out.length() == 0) { return; } os.write(out.substring(1, out.length()).getBytes()); os.flush(); out.delete(1, out.length()); } public void forceClose() { forcedClose = true; synchronized (monitor) { monitor.notify(); } } public void appendColorMask(int colorCode) { String color; switch (colorCode) { case AnsiColor.COLOR_CLEAR: color = "\033[m"; break; case AnsiColor.COLOR_BLACK: color = "\033[0;30m"; break; case AnsiColor.COLOR_RED: color = "\033[0;31m"; break; case AnsiColor.COLOR_GREEN: color = "\033[0;32m"; break; case AnsiColor.COLOR_YELLOW: color = "\033[0;33m"; break; case AnsiColor.COLOR_BLUE: color = "\033[0;34m"; break; case AnsiColor.COLOR_MAGENTA: color = "\033[0;35m"; break; case AnsiColor.COLOR_CYAN: color = "\033[0;36m"; break; case AnsiColor.COLOR_WHITE: color = "\033[0;37m"; break; // brighter case AnsiColor.COLOR_DARK_GREY: color = "\033[1;30m"; break; case AnsiColor.COLOR_BRIGHT_RED: color = "\033[1;31m"; break; case AnsiColor.COLOR_BRIGHT_GREEN: color = "\033[1;32m"; break; case AnsiColor.COLOR_BRIGHT_YELLOW: color = "\033[1;33m"; break; case AnsiColor.COLOR_BRIGHT_BLUE: color = "\033[1;34m"; break; case AnsiColor.COLOR_BRIGHT_MAGENTA: color = "\033[1;35m"; break; case AnsiColor.COLOR_BRIGHT_CYAN: color = "\033[1;36m"; break; case AnsiColor.COLOR_BRIGHT_WHITE: color = "\033[1;37m"; break; // special case AnsiColor.COLOR_BEEP: color = "\007"; break; default: Log.warn("Unknown color:" + colorCode); return; } currentColor = colorCode; out.append(color); } protected void ping() { try { sendRaw(IACAYT); } catch (Exception e) { Log.error(e.getMessage(), e); lostLink = true; synchronized (monitor) { monitor.notify(); } } } }