package net.sourceforge.pain.console.telnet;
import net.sourceforge.pain.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 close() {
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();
}
}
}
}