Commit Diff


commit - e8dbb7eedfb0f9bd8407e0364bc6a309239c89f6
commit + ef6cad1d6b21c1dcbcbef21861969aa85b54fa0b
blob - /dev/null
blob + 57b7661b720a1b4a082494847edc4af1663cc840 (mode 644)
--- /dev/null
+++ Makefile
@@ -0,0 +1,38 @@
+JAVA	=	java
+JAR	=	jar
+JAVAC	=	javac
+DEBUG	=	-g -deprecation
+JFLAGS	=	-classpath $(CLASSPATH):.
+SRCDIR	=	de
+
+.SUFFIXES:	.java .class
+
+# compile java files to class
+.java.class:
+	$(JAVAC) $(DEBUG) $(JFLAGS) $<
+
+#
+# major rules to create files
+#
+all: 	app doc jar
+	
+doc:	app
+	javadoc -d doc -version -author \
+	  `find de/mud -type d -print | \
+	    grep -v CVS | grep -v '^de/mud$$' | sed 's/\//./g'`
+
+run:	app
+	$(JAVA) $(JFLAGS) de.mud.jta.Main
+
+jar:	app
+	$(JAR) cvf jar/jta.jar `find $(SRCDIR) -name *.class`
+
+# 
+# application dependencies
+#
+app:
+	@find $(SRCDIR) -name \*.java | sed 's/java$$/class/' | xargs make
+
+clean:
+	-find . -name *.class -print | xargs rm > /dev/null 2>&1
+	-find . -name *~ -print | xargs rm > /dev/null 2>&1
blob - /dev/null
blob + 9dd433cc278852d40893a22cf85717e89e88e689 (mode 644)
--- /dev/null
+++ de/mud/jta/Common.java
@@ -0,0 +1,100 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+import de.mud.jta.PluginLoader;
+import de.mud.jta.VisualPlugin;
+import de.mud.jta.Plugin;
+import de.mud.jta.event.ConfigurationRequest;
+import de.mud.jta.event.SocketRequest;
+
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import java.awt.Component;
+import java.awt.Menu;
+
+/**
+ * The common part of the <B>The Java<SUP>tm</SUP> Telnet Application</B>
+ * is handled here. Mainly this includes the loading of the plugins and
+ * the screen setup of the visual plugins.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Common extends PluginLoader {
+
+  private Hashtable plugins, components, menus;
+
+  public Common(Properties config) {
+    System.err.println("** The Java(tm) Telnet Application");
+    System.err.println("** Copyright (c) 1996-1999 Matthias L. Jugel, "
+                      +"Marcus Meißner");
+
+    plugins = new Hashtable();
+    components = new Hashtable();
+    menus = new Hashtable();
+
+    Vector names = split(config.getProperty("plugins"));
+    Enumeration e = names.elements();
+    while(e.hasMoreElements()) {
+      String name = (String)e.nextElement();
+      System.err.println("jta: loading plugin '"+name+"' ...");
+      Plugin plugin = addPlugin(name);
+      if(plugin instanceof VisualPlugin) {
+        Component c = ((VisualPlugin)plugin).getPluginVisual();
+	if(c != null) components.put(name, c);
+	Menu menu = ((VisualPlugin)plugin).getPluginMenu();
+	if(menu != null) menus.put(name, menu);
+      }
+    }
+
+    broadcast(new ConfigurationRequest(config));
+  }
+
+  public Hashtable getComponents() {
+    return components;
+  }
+
+  public Hashtable getMenus() {
+    return menus;
+  }
+
+  /**
+   * Split up comma separated lists of strings. This is quite strict, no
+   * whitespace characters are allowed.
+   * @param s the string to be split up
+   * @return an array of strings
+   */
+  private static Vector split(String s) {
+    Vector v = new Vector();
+    int old = -1, idx = s.indexOf(',');
+    while(idx >= 0) {
+      v.addElement(s.substring(old + 1, idx));
+      old = idx;
+      idx = s.indexOf(',', old + 1);
+    } 
+    v.addElement(s.substring(old + 1));
+    return v;
+  }
+}
blob - /dev/null
blob + 418ed0c04e9f06512128d4f146ff8a1f852e2dbb (mode 644)
--- /dev/null
+++ de/mud/jta/FilterPlugin.java
@@ -0,0 +1,57 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+import java.io.IOException;
+
+/**
+ * The filter plugin is the base interface for plugins that want to intercept
+ * the communication between front end and back end plugins. Filters and
+ * protocol handlers are a good example.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface FilterPlugin {
+  /**
+   * Set the source plugin where we get our data from and where the data
+   * sink (write) is. The actual data handling should be done in the
+   * read() and write() methods.
+   * @param source the data source
+   */
+  public void setFilterSource(FilterPlugin source) 
+    throws IllegalArgumentException;
+
+  /**
+   * Read a block of data from the back end.
+   * @param b the buffer to read the data into
+   * @return the amount of bytes actually read
+   */
+  public int read(byte[] b)
+    throws IOException;
+
+  /**
+   * Write a block of data to the back end.
+   * @param b the buffer to be sent
+   */
+  public void write(byte[] b)
+    throws IOException;
+}
blob - /dev/null
blob + 1ffa2588dc4fd21f04886389031e71be9fa64e3b (mode 644)
--- /dev/null
+++ de/mud/jta/Main.java
@@ -0,0 +1,127 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+import de.mud.jta.event.OnlineStatusListener;
+import de.mud.jta.event.SocketRequest;
+
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import java.io.IOException;
+
+import java.awt.Frame;
+import java.awt.Color;
+import java.awt.Component;
+
+/**
+ * <B>The Java Telnet Application</B><P>
+ * This is the implementation of whole set of applications. It's modular
+ * structure allows to configure the software to act either as a sophisticated
+ * terminal emulation and/or, adding the network backend, as telnet 
+ * implementation. Additional modules provide features like scripting or an
+ * improved graphical user interface.<P>
+ * This software is written entirely in Java<SUP>tm</SUP>.<P>
+ * This is the main program for the command line telnet. It initializes the
+ * system and adds all needed components, such as the telnet backend and
+ * the terminal front end. In contrast to applet functionality it parses
+ * command line arguments used for configuring the software. Additionally
+ * this application is not restricted in the sense of Java<SUP>tmp</SUP>
+ * security.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Main extends Frame {
+
+  public static void main(String args[]) {
+    Properties options = new Properties();
+    try {
+      options.load(options.getClass()
+                     .getResourceAsStream("/de/mud/jta/defaults.opt"));
+    } catch(IOException e) {
+      System.err.println("jta: cannot load defaults");
+    }
+    String error = parseOptions(options, args);
+    if(error != null) {
+      System.err.println(error);
+      System.err.println("usage: de.mud.jta.Main [-term id] [host [port]]");
+      System.exit(0);
+    }
+
+    final Frame frame = new Frame("jta: "
+                                 +options.getProperty("Socket.host")
+                                 +options.getProperty("Socket.port"));
+
+    // configure the application and load all plugins
+    Common setup = new Common(options);
+
+    setup.registerPluginListener(new OnlineStatusListener() {
+      public void online() { /* nothing to do */ }
+      public void offline() {
+/*        frame.dispose();
+        System.exit(0);
+*/      }
+    });
+
+    Hashtable componentList = setup.getComponents();
+    Enumeration names = componentList.keys();
+    while(names.hasMoreElements()) {
+      String name = (String)names.nextElement();
+      Component c = (Component)componentList.get(name);
+      if(options.getProperty("layout."+name) == null) {
+        System.err.println("jta: no layout property set for '"+name+"'");
+	frame.add("South", c);
+      } else
+        frame.add(options.getProperty("layout."+name), c);
+    }
+
+    frame.pack();
+    frame.show();
+
+    setup.broadcast(new SocketRequest(options.getProperty("Socket.host"),
+                     Integer.parseInt(options.getProperty("Socket.port"))));
+  }
+
+  /**
+   * Parse the command line argumens and override any standard options
+   * with the new values if applicable.
+   * <P><SMALL>
+   * This method does not work with jdk 1.1.x as the setProperty()
+   * method is not available. You need to comment this method out
+   * and replace the class for the old jdk!
+   * </SMALL>
+   * @param options the original options
+   * @param args the command line parameters
+   * @return a possible error message if problems occur
+   */
+  private static String parseOptions(Properties options, String args[]) {
+    for(int n = 0; n < args.length; n++) {
+      if(args[n].equals("-term"))
+        if(!args[n+1].startsWith("-"))
+          /* options.setProperty("Terminal.id", args[++n]) */;
+        else 
+	  return "missing parameter for -term";
+    }
+    return null;
+  }
+}
blob - /dev/null
blob + 35d11b8466bc032fee5cbbdc0b9f0cb2c3f35897 (mode 644)
--- /dev/null
+++ de/mud/jta/Plugin.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+import java.io.IOException;
+
+/**
+ * Plugin base class for the Java Telnet Application. 
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Plugin {
+  /** holds the plugin bus used for communication between plugins */
+  protected PluginBus bus;
+
+  /**
+   * Create a new plugin and set the plugin bus used by this plugin.
+   * @param bus the plugin bus
+   */
+  public Plugin(PluginBus bus) {
+    this.bus = bus;
+  }
+}
blob - /dev/null
blob + a2efaff27698bcebb5db824a5ac0cf7473fecf06 (mode 644)
--- /dev/null
+++ de/mud/jta/PluginBus.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+/**
+ * A plugin bus is used for communication between plugins. The interface
+ * describes the broadcast method that should broad cast the message
+ * to all plugins known and return an answer message immediatly.<P>
+ * The functionality is just simuliar to a bus, but depends on the
+ * actual implementation of the bus.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface PluginBus {
+  /** Broadcast a plugin message to all listeners. */
+  public Object broadcast(PluginMessage message);
+  /** Register a plugin listener with this bus object */
+  public void registerPluginListener(PluginListener listener);
+}
blob - /dev/null
blob + 430e191d5bebc822c8ec6a8719427aabf2ef30d9 (mode 644)
--- /dev/null
+++ de/mud/jta/PluginListener.java
@@ -0,0 +1,30 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+/**
+ * A tag interface for a plugin message listener.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface PluginListener {
+}
blob - /dev/null
blob + 3084a81a3cda1649e2c0cf0d3c984bc4b7302fe5 (mode 644)
--- /dev/null
+++ de/mud/jta/PluginLoader.java
@@ -0,0 +1,111 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta;
+
+import java.util.Properties;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * The plugin loader tries to load the plugin by name and returns a
+ * corresponding plugin object. It takes care of connecting filter
+ * plugins
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class PluginLoader implements PluginBus {
+  /** holds the current version id */
+  public final static String ID = "$Id$";
+
+  private final static int debug = 0;
+
+  /** the path to standard plugins */
+  private final static String PATH = "de.mud.jta.plugin.";
+
+  /** holds all the filters */
+  private Vector filter = new Vector();
+
+  /**
+   * Add a new plugin to the system and register the plugin load as its
+   * communication bus. If the plugin is a filter plugin and if it is
+   * not the first filter the last added filter will be set as its filter
+   * source.
+   * @param name the string name of the plugin
+   * @return the newly created plugin or null in case of an error
+   */
+  public Plugin addPlugin(String name) {
+    Plugin plugin = null;
+
+    // load the plugin by name and instantiate it
+    try {
+      Class c = Class.forName(PATH+name);
+      Constructor cc = c.getConstructor(new Class[] { PluginBus.class });
+      plugin = (Plugin)cc.newInstance(new Object[] { this });
+    } catch(Exception e) {
+      System.err.println("plugin loader: cannot load "+name);
+      e.printStackTrace();
+      return null;
+    }
+
+    // configure the filter plugins
+    if(plugin instanceof FilterPlugin) {
+      if(filter.size() > 0)
+        ((FilterPlugin)plugin)
+          .setFilterSource((FilterPlugin)filter.lastElement());
+      filter.addElement(plugin);
+    }
+
+    return plugin;
+  }
+
+  /** holds the plugin listener we serve */
+  private Vector listener = new Vector();
+
+  /**
+   * Register a new plugin listener.
+   */
+  public void registerPluginListener(PluginListener l) {
+    listener.addElement(l);
+  }
+
+  /**
+   * Implementation of the plugin bus. Broadcast a message to all
+   * listeners we know of. The message takes care that the right
+   * methods are called in the  listeners.
+   * @param message the plugin message to be sent
+   * @return the answer to the sent message
+   */
+  public Object broadcast(PluginMessage message) {
+    if(debug>0) System.err.println("broadcast("+message+")");
+    if(message == null || listener == null)
+      return null;
+    Enumeration e = listener.elements();
+    Object res = null;
+    while(res == null && e.hasMoreElements())
+      res = message.firePluginMessage((PluginListener)e.nextElement());
+    return res;
+  }
+}
+
blob - /dev/null
blob + e878d8cce59274a53433983a7451d5c300779748 (mode 644)
--- /dev/null
+++ de/mud/jta/PluginMessage.java
@@ -0,0 +1,37 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+/**
+ * The base interface for a plugin message.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface PluginMessage {
+  /**
+   * Fire the message to all listeners that are compatible with this
+   * message and return the result.
+   * @param pl the list of plugin message listeners
+   * @return the result message
+   */
+  public Object firePluginMessage(PluginListener pl);
+}
blob - /dev/null
blob + 979af0594e61d6b90b55bf2ffe803379806e6895 (mode 644)
--- /dev/null
+++ de/mud/jta/VisualPlugin.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta;
+
+import java.awt.Component;
+import java.awt.Menu;
+
+/**
+ * To show data on-screen a plugin may have a visible component. That component
+ * may either be a single awt component or a container with severel elements.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface VisualPlugin  {
+  /**
+   * Get the visible components from the plugin.
+   * @return a component that represents the plugin
+   */
+  public Component getPluginVisual();
+
+  /**
+   * Get the menu entry for this component.
+   * @return a menu that can be used to change the plugin state
+   */
+  public Menu getPluginMenu();
+}
blob - /dev/null
blob + a06711c2c95d10315bc14c67bfde1d57ee491278 (mode 644)
--- /dev/null
+++ de/mud/jta/defaults.opt
@@ -0,0 +1,52 @@
+# This file is part of "The Java Telnet Application".
+#
+# This is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# "The Java Telnet Application" is distributed in the hope that it will be 
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this software; see the file COPYING.  If not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# =======================================================================
+# common program defaults
+# =======================================================================
+plugins			=	Socket,Telnet,Terminal,Status
+layout			=	BorderLayout
+layout.Terminal		=	Center
+layout.Status		=	South
+
+# =======================================================================
+# Socket defaults
+# =======================================================================
+Socket.host		=	10.1.1.1
+Socket.port		=	23
+
+# =======================================================================
+# Terminal defaults
+# =======================================================================
+Terminal.foreground	=	#000080
+Terminal.background	=	#a0fff6
+Terminal.border		=	0
+Terminal.borderRaised	=	false
+Terminal.borderColor	=	#a0fff6
+Terminal.colorSet	=	@/de/mud/terminal/default.colorset
+Terminal.scrollBar	=	West
+# now the real configuration
+Terminal.id		=	vt320
+Terminal.buffer		=	100
+Terminal.size		=	[80,24]
+Terminal.resize		=	none
+Terminal.font		=	Courier
+Terminal.fontStyle	=	bold
+Terminal.fontSize	=	18
+Terminal.keyCodes	=	@/de/mud/terminal/default.keycodes
+Terminal.VMS		=	false
+Terminal.IBM		=	false
blob - /dev/null
blob + 2ded6f0459a190c4cbfd3ee9142da911023dd655 (mode 644)
--- /dev/null
+++ de/mud/jta/event/ConfigurationListener.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+import java.util.Properties;
+
+/**
+ * Configuration listener will be notified of configuration events.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface ConfigurationListener extends PluginListener {
+  /** Called for configuration changes. */
+  public void setConfiguration(Properties config);
+}
blob - /dev/null
blob + dd390d3a48eccea9a0cca23a9171c7e37f919b93 (mode 644)
--- /dev/null
+++ de/mud/jta/event/ConfigurationRequest.java
@@ -0,0 +1,53 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+import de.mud.jta.event.ConfigurationListener;
+
+import java.util.Properties;
+
+/**
+ * Configuration request message. Subclassing this message can be used to
+ * make the configuration more specific and efficient.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class ConfigurationRequest implements PluginMessage {
+  Properties config;
+
+  public ConfigurationRequest(Properties config) {
+    this.config = config;
+  }
+
+  /**
+   * Notify all listeners of a configuration event.
+   * @param pl the list of plugin message listeners
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof ConfigurationListener) {
+      ((ConfigurationListener)pl).setConfiguration(config);
+    }
+    return null;
+  }
+}
blob - /dev/null
blob + dd22c9a85d0adc75082d4f73f650ed58b343ba1b (mode 644)
--- /dev/null
+++ de/mud/jta/event/LocalEchoListener.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+/**
+ * This interface should be used by plugins who would like to be notified
+ * about the local echo property.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface LocalEchoListener extends PluginListener {
+  /** Called if the local echo property changes. */
+  public void setLocalEcho(boolean echo);
+}
blob - /dev/null
blob + 63dadb1c5aa4bc8a9a899b961b1e8d1d04965164 (mode 644)
--- /dev/null
+++ de/mud/jta/event/LocalEchoRequest.java
@@ -0,0 +1,52 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+import de.mud.jta.event.LocalEchoListener;
+
+/**
+ * Notification of the local echo property. The terminal should echo all
+ * typed in characters locally of this is true.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class LocalEchoRequest implements PluginMessage {
+  protected boolean echo;
+
+  /** Create a new local echo request with the specified value. */
+  public LocalEchoRequest(boolean echo) {
+    this.echo = echo;
+  }
+
+  /**
+   * Notify all listeners about the status of local echo.
+   * @param pl the list of plugin message listeners
+   * @return always null
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof LocalEchoListener)
+      ((LocalEchoListener)pl).setLocalEcho(echo);
+    return null;
+  }
+}
blob - /dev/null
blob + 8da05583f4ecebda6eaa5755d0d521596943105f (mode 644)
--- /dev/null
+++ de/mud/jta/event/OnlineStatus.java
@@ -0,0 +1,53 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+
+/**
+ * Notify all listeners that we on or offline.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class OnlineStatus implements PluginMessage {
+  protected boolean online;
+
+  /** Create a new online status message with the specified value. */
+  public OnlineStatus(boolean online) {
+    this.online = online;
+  }
+
+  /**
+   * Notify the listers about the online status.
+   * @param pl the list of plugin message listeners
+   * @return the window size or null
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof OnlineStatusListener)
+      if(online)
+        ((OnlineStatusListener)pl).online();
+      else
+        ((OnlineStatusListener)pl).offline();
+    return null;
+  }
+}
blob - /dev/null
blob + a5125bf7234df3e11fb5214ef5d7b7ac64afa1ad (mode 644)
--- /dev/null
+++ de/mud/jta/event/OnlineStatusListener.java
@@ -0,0 +1,38 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+import java.awt.Dimension;
+
+/**
+ * This is the interface for a online status listener.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface OnlineStatusListener extends PluginListener {
+  /** Called when the system is online. */
+  public void online();
+  /** Called when the system is offline. */
+  public void offline();
+}
blob - /dev/null
blob + 856bb296752ffc2bce2839ca8db4374b0e678443 (mode 644)
--- /dev/null
+++ de/mud/jta/event/SocketListener.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+import java.net.UnknownHostException;
+import java.io.IOException;
+
+/**
+ * The socket listener should be implemented by plugins that want to know
+ * when the whole systems connects or disconnects.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface SocketListener extends PluginListener {
+  /** Called if a connection should be established. */
+  public void connect(String host, int port)
+    throws UnknownHostException, IOException;
+  /** Called if the connection should be stopped. */
+  public void disconnect() 
+    throws IOException;
+}
blob - /dev/null
blob + d21dc3415ebe488cfaf21d207390f61bc0685dfd (mode 644)
--- /dev/null
+++ de/mud/jta/event/SocketRequest.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+import de.mud.jta.event.SocketListener;
+
+/**
+ * Notification of a socket request. Send this message if the system
+ * should connect or disconnect.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class SocketRequest implements PluginMessage {
+  String host;
+  int port;
+
+  /** Create a new disconnect message */
+  public SocketRequest() {
+    host = null;
+  }
+
+  /** Create a new connect message */
+  public SocketRequest(String host, int port) {
+    this.host = host;
+    this.port = port;
+  }
+
+  /**
+   * Tell all listeners that we would like to connect.
+   * @param pl the list of plugin message listeners
+   * @return the terminal type or null
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof SocketListener) try {
+      if(host != null) 
+        ((SocketListener)pl).connect(host, port);
+      else
+        ((SocketListener)pl).disconnect();
+    } catch(Exception e) { 
+      e.printStackTrace();
+    }
+    return null;
+  }
+}
blob - /dev/null
blob + 2be5aea01d0ec57773b6446d5cb63ec2152d6e67 (mode 644)
--- /dev/null
+++ de/mud/jta/event/TerminalTypeListener.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+/**
+ * This is the interface for a terminal type listener. It should return
+ * the terminal type id as a string. Valid terminal types include
+ * VT52, VT100, VT200, VT220, VT320, ANSI etc.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface TerminalTypeListener extends PluginListener {
+  /** Return the terminal type string */
+  public String getTerminalType();
+}
blob - /dev/null
blob + dc2d8cbd1b7d883d5880fbe05ccf88e6e71b6fb4 (mode 644)
--- /dev/null
+++ de/mud/jta/event/TerminalTypeRequest.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+import de.mud.jta.event.TerminalTypeListener;
+
+/**
+ * Request message for the current terminal type.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class TerminalTypeRequest implements PluginMessage {
+  /**
+   * Ask all terminal type listener about the terminal type and return
+   * the first answer.
+   * @param pl the list of plugin message listeners
+   * @return the terminal type or null
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof TerminalTypeListener) {
+      Object ret = ((TerminalTypeListener)pl).getTerminalType();
+      if(ret != null) return ret;
+    }
+    return null;
+  }
+}
blob - /dev/null
blob + 5a1b866b2bb1a0644e02fd98af2058570ed8aa3b (mode 644)
--- /dev/null
+++ de/mud/jta/event/WindowSizeListener.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginListener;
+
+import java.awt.Dimension;
+
+/**
+ * This is the interface for a window size listener. 
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface WindowSizeListener extends PluginListener {
+  /** Return the current window size of the terminal in rows and columns. */
+  public Dimension getWindowSize();
+}
blob - /dev/null
blob + a1d991f2e4518857c7665eb7d18a2182a4768bed (mode 644)
--- /dev/null
+++ de/mud/jta/event/WindowSizeRequest.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+package de.mud.jta.event;
+
+import de.mud.jta.PluginMessage;
+import de.mud.jta.PluginListener;
+import de.mud.jta.event.WindowSizeListener;
+
+/**
+ * Request the current window size of the terminal.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class WindowSizeRequest implements PluginMessage {
+  /**
+   * Return the size of the window
+   * @param pl the list of plugin message listeners
+   */
+  public Object firePluginMessage(PluginListener pl) {
+    if(pl instanceof WindowSizeListener) {
+      Object ret = ((WindowSizeListener)pl).getWindowSize();
+      if(ret != null) return ret;
+    }
+    return null;
+  }
+}
blob - /dev/null
blob + a20b2ea4a49ceecd7565981ad06fb7fda047fcec (mode 644)
--- /dev/null
+++ de/mud/jta/plugin/Shell.java
@@ -0,0 +1,76 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta.plugin;
+
+import de.mud.jta.Plugin;
+import de.mud.jta.FilterPlugin;
+import de.mud.jta.PluginBus;
+import de.mud.jta.event.LocalEchoRequest;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The shell plugin is the backend component for terminal emulation using
+ * a shell. It provides the i/o streams of the shell as data source.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Shell extends Plugin implements FilterPlugin {
+
+  private final static int debug = 1;
+
+  protected InputStream in, err;
+  protected OutputStream out;
+
+  public Shell(PluginBus bus) {
+    super(bus);
+    Runtime rt = Runtime.getRuntime();
+
+    try {
+      Process p = rt.exec("/bin/bash -i"); System.err.println(p);
+      in = p.getInputStream();
+      out = p.getOutputStream();
+      err = p.getErrorStream();
+    } catch(Exception e) {
+      e.printStackTrace();
+    }
+
+    bus.broadcast(new LocalEchoRequest(true));
+  }
+
+  public void setFilterSource(FilterPlugin plugin) {
+    // we do not have a source other than our socket
+  }
+
+  public int read(byte[] b) throws IOException {
+    if(err.available() > 0) return err.read(b);
+    return in.read(b);
+  }
+
+  public void write(byte[] b) throws IOException {
+    out.write(b);
+    out.flush();
+  }
+}
blob - /dev/null
blob + bde73e12b93315bdf2e1597d748230a04dd7d15e (mode 644)
--- /dev/null
+++ de/mud/jta/plugin/Socket.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta.plugin;
+
+import de.mud.jta.Plugin;
+import de.mud.jta.FilterPlugin;
+import de.mud.jta.PluginBus;
+import de.mud.jta.event.SocketListener;
+import de.mud.jta.event.OnlineStatus;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.net.UnknownHostException;
+
+/**
+ * The socket plugin acts as the data source for networked operations.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Socket extends Plugin implements FilterPlugin, SocketListener {
+
+  private final static int debug = 0;
+  protected java.net.Socket socket;
+  protected InputStream in;
+  protected OutputStream out;
+
+  /**
+   * Create a new socket plugin.
+   */
+  public Socket(PluginBus pbus) {
+    super(pbus);
+    final PluginBus bus = pbus;
+
+    // register socket listener
+    bus.registerPluginListener(this);
+  }
+
+  /** Connect to the host and port passed. */
+  public void connect(String host, int port)
+    throws UnknownHostException, IOException {
+    if(debug>0) System.err.println("Socket: connect("+host+","+port+")");
+    socket = new java.net.Socket(host, port);
+    in = socket.getInputStream();
+    out = socket.getOutputStream();
+    bus.broadcast(new OnlineStatus(true));
+  }  
+
+  /** Disconnect the socket and close the connection. */
+  public void disconnect() throws IOException {
+    if(debug>0) System.err.println("Socket: disconnect()");
+    bus.broadcast(new OnlineStatus(false));
+    socket.close();
+  }
+
+  public void setFilterSource(FilterPlugin plugin) {
+    // we do not have a source other than our socket
+  }
+
+  public int read(byte[] b) throws IOException {
+    int n = in.read(b);
+    if(n < 0) disconnect();
+    return n;
+  }
+
+  public void write(byte[] b) throws IOException {
+    out.write(b);
+  }
+}
blob - /dev/null
blob + 48e9f00eb584bc57cf24da9cfdff27547b5c6156 (mode 644)
--- /dev/null
+++ de/mud/jta/plugin/Status.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta.plugin;
+
+import de.mud.jta.Plugin;
+import de.mud.jta.PluginBus;
+import de.mud.jta.VisualPlugin;
+import de.mud.jta.event.OnlineStatusListener;
+
+import java.awt.Component;
+import java.awt.Menu;
+import java.awt.Label;
+import java.awt.Color;
+
+/**
+ * A simple plugin showing the current status of the application whether
+ * it is online or not.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Status extends Plugin implements VisualPlugin {
+
+  private final static int debug = 1;
+
+  private Label status;
+
+  public Status(PluginBus bus) {
+    super(bus);
+    status = new Label("offline", Label.RIGHT);
+    bus.registerPluginListener(new OnlineStatusListener() {
+      public void online() {
+        status.setText("online");
+	status.setBackground(Color.green);
+      }
+      public void offline() {
+        status.setText("offline");
+	status.setBackground(Color.red);
+      }
+    });
+  }
+
+  public Component getPluginVisual() {
+    return status;
+  }
+
+  public Menu getPluginMenu() {
+    return null;
+  }
+}
blob - /dev/null
blob + 61aa353cc35440bb5a71404113eb8923830e8e63 (mode 644)
--- /dev/null
+++ de/mud/jta/plugin/Telnet.java
@@ -0,0 +1,94 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta.plugin;
+
+import de.mud.jta.Plugin;
+import de.mud.jta.FilterPlugin;
+import de.mud.jta.PluginBus;
+
+import de.mud.jta.event.TerminalTypeRequest;
+import de.mud.jta.event.WindowSizeRequest;
+import de.mud.jta.event.LocalEchoRequest;
+
+import de.mud.telnet.TelnetProtocolHandler;
+
+import java.awt.Dimension;
+
+import java.io.IOException;
+
+/**
+ * The telnet plugin utilizes a telnet protocol handler to filter
+ * telnet negotiation requests from the data stream.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Telnet extends Plugin implements FilterPlugin {
+
+  protected FilterPlugin source;
+  protected TelnetProtocolHandler handler;
+
+  private final static int debug = 0;
+
+  /**
+   * Create a new telnet plugin.
+   */
+  public Telnet(PluginBus pbus) {
+    super(pbus);
+    final PluginBus bus = pbus;
+
+    // create a new telnet protocol handler
+    handler = new TelnetProtocolHandler() {
+      /** get the current terminal type */
+      public String getTerminalType() {
+        return (String)bus.broadcast(new TerminalTypeRequest());
+      }
+      /** get the current window size */
+      public Dimension getWindowSize() {
+        return (Dimension)bus.broadcast(new WindowSizeRequest());
+      }
+      /** notify about local echo */
+      public void setLocalEcho(boolean echo) {
+        bus.broadcast(new LocalEchoRequest(echo));
+      }
+      /** write data to our back end */
+      public void write(byte[] b) throws IOException {
+        source.write(b);
+      }
+    };
+  }
+
+  public void setFilterSource(FilterPlugin source) { 
+    if(debug>0) System.err.println("Telnet: connected to: "+source);
+    this.source = source;
+  }
+
+  public int read(byte[] b) throws IOException {
+    int n = source.read(b);
+    if(n > 0) n = handler.negotiate(b, n);
+    return n;
+  }
+
+  public void write(byte[] b) throws IOException {
+    source.write(b);
+  }
+}
blob - /dev/null
blob + d4bc46654fc3165ebb188932cdde2c68bcc50b89 (mode 644)
--- /dev/null
+++ de/mud/jta/plugin/Terminal.java
@@ -0,0 +1,226 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.jta.plugin;
+
+import de.mud.jta.Plugin;
+import de.mud.jta.FilterPlugin;
+import de.mud.jta.VisualPlugin;
+import de.mud.jta.PluginBus;
+
+import de.mud.terminal.vt320;
+
+import de.mud.jta.event.ConfigurationListener;
+import de.mud.jta.event.OnlineStatusListener;
+import de.mud.jta.event.TerminalTypeListener;
+import de.mud.jta.event.WindowSizeListener;
+import de.mud.jta.event.LocalEchoListener;
+
+import java.awt.Component;
+import java.awt.Menu;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Color;
+
+import java.io.IOException;
+
+import java.util.Properties;
+import java.util.Enumeration;
+
+/**
+ * The terminal plugin represents the actual terminal where the
+ * data will be displayed and the gets the keyboard input to sent
+ * back to the remote host,
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class Terminal extends Plugin 
+  implements FilterPlugin, VisualPlugin, Runnable {
+
+  private final static int debug = 0;
+  
+  /** holds the actual terminal emulation */
+  protected vt320 terminal;
+
+  private Thread reader = null;
+
+  /**
+   * Create a new terminal plugin and initialize the terminal emulation.
+   */
+  public Terminal(PluginBus bus) {
+    super(bus);
+    terminal = new vt320() {
+      public void write(byte[] b) {
+        try {
+	  Terminal.this.write(b);
+	} catch(IOException e) {
+	  reader = null;
+	}
+      }
+    };
+
+    // register an online status listener
+    bus.registerPluginListener(new OnlineStatusListener() {
+      public void online() {
+        if(debug > 0) System.err.println("Terminal: online");
+        if(reader == null) {
+          reader = new Thread(Terminal.this);
+          reader.start();
+        }
+      }
+
+      public void offline() {
+        if(debug > 0) System.err.println("Terminal: offline");
+        if(reader != null)
+          reader = null;
+      }
+    });
+
+    bus.registerPluginListener(new TerminalTypeListener() {
+      public String getTerminalType() {
+        return terminal.getTerminalID();
+      }
+    });
+
+    bus.registerPluginListener(new WindowSizeListener() {
+      public Dimension getWindowSize() {
+        return terminal.getScreenSize();
+      }
+    });
+
+    bus.registerPluginListener(new LocalEchoListener() {
+      public void setLocalEcho(boolean echo) {
+        terminal.setLocalEcho(echo);
+      }
+    });
+
+    bus.registerPluginListener(new ConfigurationListener() {
+      public void setConfiguration(Properties config) {
+        configure(config);
+      }
+    });
+  }
+
+  private void configure(Properties config) {
+    Enumeration p = config.keys();
+
+    while(p.hasMoreElements()) {
+      String key = (String)p.nextElement();
+      if(key.startsWith("Terminal.")) {
+        if(key.equals("Terminal.foreground"))
+	  terminal.setForeground(Color.decode(config.getProperty(key)));
+	else if(key.equals("Terminal.background"))
+	  terminal.setBackground(Color.decode(config.getProperty(key)));
+	else if(key.equals("Terminal.colorSet"))
+	  System.err.println("Terminal.colorSet not implemented yet");
+	else if(key.equals("Terminal.borderRaised")) 
+	  /* do nothing */ ;
+	else if(key.equals("Terminal.border")) {
+	  boolean raised = false;
+	  if(config.contains("Terminal.borderStyle"))
+	    raised = Boolean.getBoolean("Terminal.borderRaised");
+	  terminal.setBorder(Integer.parseInt(config.getProperty(key)),
+	                     raised);
+        } else if(key.equals("Terminal.borderColor"))
+	  terminal.setBackground(Color.decode(config.getProperty(key)));
+	else if(key.equals("Terminal.scrollBar"))
+	  System.err.println("Terminal.scrollBar not implemented yet");
+	else if(key.equals("Terminal.id"))
+	  terminal.setTerminalID(config.getProperty(key));
+	else if(key.equals("Terminal.buffer"))
+	  terminal.setBufferSize(Integer.parseInt(config.getProperty(key)));
+	else if(key.equals("Terminal.size"))
+	  System.err.println("Terminal.size not implemented yet");
+	else if(key.equals("Terminal.resize")) {
+	  String resize = config.getProperty("Terminal.resize");
+	  if(resize.equals("font"))
+	    terminal.setResizeStrategy(terminal.RESIZE_FONT);
+	  else if(resize.equals("screen"))
+	    terminal.setResizeStrategy(terminal.RESIZE_SCREEN);
+	  else 
+	    terminal.setResizeStrategy(terminal.RESIZE_NONE);
+        } else if(key.equals("Terminal.fontSize") || 
+	          key.equals("Terminal.fontStyle"))
+          /* do nothing */ ;
+        else if(key.equals("Terminal.font")) {
+	  int style = Font.PLAIN, fsize = 12;
+	  if(config.containsKey("Terminal.fontSize"))
+	    fsize = Integer.parseInt(config.getProperty("Terminal.fontSize"));
+	  String fontStyle = config.getProperty("Terminal.fontStyle");
+	  if(fontStyle == null || fontStyle.equals("plain"))
+	    style = Font.PLAIN;
+	  else if(fontStyle.equals("bold"))
+	    style = Font.BOLD;
+	  else if(fontStyle.equals("italic"))
+	    style = Font.ITALIC;
+	  System.err.println(new Font(config.getProperty(key), style, fsize));
+	  terminal.setFont(new Font(config.getProperty(key), style, fsize));
+	} else if(key.equals("Terminal.keyCodes")) 
+	  System.err.println("Terminal.keyCodes not implemented yet");
+	else if(key.equals("Terminal.VMS"))
+	  terminal.setVMS(Boolean.getBoolean(config.getProperty(key)));
+	else if(key.equals("Terminal.IBM"))
+	  terminal.setIBMCharset(Boolean.getBoolean(config.getProperty(key)));
+        else
+	  System.err.println("Error: '"+key+"' is not a Terminal property");
+      }
+    }
+  }
+	  
+  /**
+   * Continuously read from our back end and display the data on screen.
+   */
+  public void run() {
+    byte[] t, b = new byte[256];
+    int n = 0;
+    while(n >= 0) try {
+      n = read(b);
+      if(n > 0) terminal.putString(new String(b, 0, n));
+    } catch(IOException e) {
+      reader = null;
+      return;
+    }
+  }
+
+  protected FilterPlugin source;
+
+  public void setFilterSource(FilterPlugin source) {
+    if(debug > 0) System.err.println("Terminal: connected to: "+source);
+    this.source = source;
+  }
+
+  public int read(byte[] b) throws IOException {
+    return source.read(b);
+  }
+
+  public void write(byte[] b) throws IOException {
+    source.write(b);
+  }
+
+  public Component getPluginVisual() {
+    return terminal;
+  }
+
+  public Menu getPluginMenu() {
+    return null;
+  }
+}
blob - /dev/null
blob + a28236e63498f21f2d5ae26e722d0210006f450d (mode 644)
--- /dev/null
+++ de/mud/telnet/TelnetProtocolHandler.java
@@ -0,0 +1,457 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.telnet;
+
+import java.io.IOException;
+import java.awt.Dimension;
+
+/**
+ * This is a telnet protocol handler. The handler needs implementations
+ * for several methods to handle the telnet options and to be able to
+ * read and write the buffer.
+ * <P>
+ * <B>Maintainer:</B> Marcus Meißner
+ *
+ * @version $Id$
+ * @author  Matthias L. Jugel, Marcus Meißner
+ */
+public abstract class TelnetProtocolHandler {
+  /** contains the current revision id */
+  public final static String ID = "$Id$";
+  
+  /** debug level */
+  private final static int debug = 0;
+
+  /**
+   * Create a new telnet protocol handler.
+   */
+  public TelnetProtocolHandler() {
+    reset();
+  }
+
+  /**
+   * Get the current terminal type for TTYPE telnet option.
+   * @return the string id of the terminal
+   */
+  protected abstract String getTerminalType(); 
+
+  /**
+   * Get the current window size of the terminal for the
+   * NAWS telnet option.
+   * @return the size of the terminal as Dimension
+   */
+  protected abstract Dimension getWindowSize();
+
+  /**
+   * Set the local echo option of telnet.
+   * @param echo true for local echo, false for no local echo
+   */
+  protected abstract void setLocalEcho(boolean echo);
+
+  /**
+   * Send data to the remote host.
+   * @param b array of bytes to send
+   */
+  protected abstract void write(byte[] b) throws IOException;
+
+  /**
+   * Send one byte to the remote host.
+   * @param b the byte to be sent
+   * @see #write(byte[] b)
+   */
+  private static byte[] one = new byte[1];
+  private void write(byte b) throws IOException {
+    one[0] = b;
+    write(one);
+  }
+
+  /**
+   * Reset the protocol handler. This may be necessary after the
+   * connection was closed or some other problem occured.
+   */
+  public void reset() {
+    neg_state = 0;
+    receivedDX = new byte[256]; 
+    sentDX = new byte[256];
+    receivedWX = new byte[256]; 
+    sentWX = new byte[256];
+  }
+
+  // ===================================================================
+  // the actual negotiation handling for the telnet protocol follows:
+  // ===================================================================
+
+  /** state variable for telnet negotiation reader */
+  private byte neg_state = 0;
+
+  /** constants for the negotiation state */
+  private final static byte STATE_DATA  = 0;
+  private final static byte STATE_IAC   = 1;
+  private final static byte STATE_IACSB = 2;
+  private final static byte STATE_IACWILL       = 3;
+  private final static byte STATE_IACDO = 4;
+  private final static byte STATE_IACWONT       = 5;
+  private final static byte STATE_IACDONT       = 6;
+  private final static byte STATE_IACSBIAC      = 7;
+  private final static byte STATE_IACSBDATA     = 8;
+  private final static byte STATE_IACSBDATAIAC  = 9;
+
+  /** What IAC SB <xx> we are handling right now */
+  private byte current_sb;
+
+  /** IAC - init sequence for telnet negotiation. */
+  private final static byte IAC  = (byte)255;
+  /** [IAC] End Of Record */
+  private final static byte EOR  = (byte)239;
+  /** [IAC] WILL */
+  private final static byte WILL  = (byte)251;
+  /** [IAC] WONT */
+  private final static byte WONT  = (byte)252;
+  /** [IAC] DO */
+  private final static byte DO    = (byte)253;
+  /** [IAC] DONT */
+  private final static byte DONT  = (byte)254;
+  /** [IAC] Sub Begin */
+  private final static byte SB  = (byte)250;
+  /** [IAC] Sub End */
+  private final static byte SE  = (byte)240;
+  /** Telnet option: echo text */
+  private final static byte TELOPT_ECHO  = (byte)1;  /* echo on/off */
+  /** Telnet option: End Of Record */
+  private final static byte TELOPT_EOR   = (byte)25;  /* end of record */
+  /** Telnet option: Negotiate About Window Size */
+  private final static byte TELOPT_NAWS  = (byte)31;  /* NA-WindowSize*/
+  /** Telnet option: Terminal Type */
+  private final static byte TELOPT_TTYPE  = (byte)24;  /* terminal type */
+
+  private final static byte[] IACWILL  = { IAC, WILL };
+  private final static byte[] IACWONT  = { IAC, WONT };
+  private final static byte[] IACDO    = { IAC, DO      };
+  private final static byte[] IACDONT  = { IAC, DONT };
+  private final static byte[] IACSB  = { IAC, SB };
+  private final static byte[] IACSE  = { IAC, SE };
+
+  /** Telnet option qualifier 'IS' */
+  private final static byte TELQUAL_IS = (byte)0;
+  /** Telnet option qualifier 'SEND' */
+  private final static byte TELQUAL_SEND = (byte)1;
+
+  /** What IAC DO(NT) request do we have received already ? */
+  private byte[] receivedDX;
+  /** What IAC WILL/WONT request do we have received already ? */
+  private byte[] receivedWX;
+  /** What IAC DO/DONT request do we have sent already ? */
+  private byte[] sentDX;
+  /** What IAC WILL/WONT request do we have sent already ? */
+  private byte[] sentWX;
+
+  /**
+   * Handle an incoming IAC SB &lt;type&gt; &lt;bytes&gt; IAC SE
+   * @param type type of SB
+   * @param sbata byte array as &lt;bytes&gt;
+   * @param sbcount nr of bytes. may be 0 too.
+   */
+  private void handle_sb(byte type, byte[] sbdata, int sbcount) 
+    throws IOException {
+    if(debug > 1) 
+      System.err.println("TelnetIO.handle_sb("+type+")");
+    switch (type) {
+    case TELOPT_TTYPE:
+      if (sbcount>0 && sbdata[0]==TELQUAL_SEND) {
+        write(IACSB);write(TELOPT_TTYPE);write(TELQUAL_IS);
+        /* FIXME: need more logic here if we use 
+         * more than one terminal type
+         */
+        String ttype = getTerminalType();
+        if(ttype == null) ttype = "dumb";
+        write(ttype.getBytes());
+        write(IACSE);
+      }
+
+    }
+  }
+
+  /**
+   * Handle telnet protocol negotiation. The buffer will be parsed
+   * and necessary actions are taken according to the telnet protocol.
+   * See <A HREF="RFC-Telnet-URL">RFC-Telnet</A>
+   * @param buf the byte buffer used for negotiation
+   * @param count the amount of bytes in the buffer
+   * @return a new buffer after negotiation
+   */
+  public int negotiate(byte buf[], int count) throws IOException {
+    // wo faengt buf an bei buf[0] oder bei buf[1]
+    // Leo: bei buf[0]
+    if(debug > 1) 
+      System.err.println("TelnetIO.negotiate("+buf+","+count+")");
+    byte nbuf[] = new byte[count];
+    byte sbbuf[] = new byte[count];
+    byte sendbuf[] = new byte[3];
+    byte b,reply;
+    int  sbcount = 0;
+    int boffset = 0, noffset = 0;
+
+    while(boffset < count) {
+      b=buf[boffset++];
+      // of course, byte is a signed entity (-128 -> 127)
+      // but apparently the SGI Netscape 3.0 doesn't seem
+      // to care and provides happily values up to 255
+      if (b>=128)
+        b=(byte)((int)b-256);
+      switch (neg_state) {
+      case STATE_DATA:
+        if (b==IAC)
+          neg_state = STATE_IAC;
+        else 
+          nbuf[noffset++]=b;
+        break;
+      case STATE_IAC:
+        switch (b) {
+        case IAC:
+          if(debug > 2) System.err.print("IAC ");
+          neg_state = STATE_DATA;
+          nbuf[noffset++]=IAC;
+          break;
+        case WILL:
+          if(debug > 2) System.err.print("WILL ");
+          neg_state = STATE_IACWILL;
+          break;
+        case WONT:
+          if(debug > 2) System.err.print("WONT ");
+          neg_state = STATE_IACWONT;
+          break;
+        case DONT:
+          if(debug > 2) System.err.print("DONT ");
+          neg_state = STATE_IACDONT;
+          break;
+        case DO:
+          if(debug > 2) System.err.print("DO ");
+          neg_state = STATE_IACDO;
+          break;
+        case EOR:
+          if(debug > 2) System.err.print("EOR ");
+          neg_state = STATE_DATA;
+          break;
+        case SB:
+          if(debug > 2) System.err.print("SB ");
+          neg_state = STATE_IACSB;
+          sbcount = 0;
+          break;
+        default:
+          if(debug > 2) System.err.print("<UNKNOWN "+b+" > ");
+          neg_state = STATE_DATA;
+          break;
+        }
+        break;
+      case STATE_IACWILL:
+        switch(b) {
+        case TELOPT_ECHO:
+          if(debug > 2) System.err.println("ECHO");
+          reply = DO;
+          setLocalEcho(false);
+          break;
+        case TELOPT_EOR:
+          if(debug > 2) System.err.println("EOR");
+          reply = DO;
+          break;
+        default:
+          if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+          reply = DONT;
+          break;
+        }
+        if(debug > 1) System.err.println("<"+b+", WILL ="+WILL+">");
+        if (reply != sentDX[b+128] || WILL != receivedWX[b+128]) {
+          sendbuf[0]=IAC;
+          sendbuf[1]=reply;
+          sendbuf[2]=b;
+          write(sendbuf);
+          sentDX[b+128] = reply;
+          receivedWX[b+128] = WILL;
+        }
+        neg_state = STATE_DATA;
+        break;
+      case STATE_IACWONT:
+        switch(b) {
+        case TELOPT_ECHO:
+          if(debug > 2) System.err.println("ECHO");
+          setLocalEcho(true);
+          reply = DONT;
+          break;
+        case TELOPT_EOR:
+          if(debug > 2) System.err.println("EOR");
+          reply = DONT;
+          break;
+        default:
+          if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+          reply = DONT;
+          break;
+        }
+        if(reply != sentDX[b+128] || WONT != receivedWX[b+128]) {
+          sendbuf[0]=IAC;
+          sendbuf[1]=reply;
+          sendbuf[2]=b;
+          write(sendbuf);
+          sentDX[b+128] = reply;
+          receivedWX[b+128] = WILL;
+        }
+        neg_state = STATE_DATA;
+        break;
+      case STATE_IACDO:
+        switch (b) {
+        case TELOPT_ECHO:
+          if(debug > 2) System.err.println("ECHO");
+          reply = WILL;
+          setLocalEcho(true);
+          break;
+        case TELOPT_TTYPE:
+          if(debug > 2) System.err.println("TTYPE");
+          reply = WILL;
+          break;
+        case TELOPT_NAWS:
+          if(debug > 2) System.err.println("NAWS");
+          Dimension size = getWindowSize();
+          receivedDX[b] = DO;
+          if(size == null) {
+            // this shouldn't happen
+            write(IAC);
+            write(WONT);
+            write(TELOPT_NAWS);
+            reply = WONT;
+            sentWX[b] = WONT;
+            break;
+          }
+          reply = WILL;
+          sentWX[b] = WILL;
+          sendbuf[0]=IAC;
+          sendbuf[1]=WILL;
+          sendbuf[2]=TELOPT_NAWS;
+          write(sendbuf);
+          write(IAC);write(SB);write(TELOPT_NAWS);
+          write((byte) (size.width >> 8));
+          write((byte) (size.width & 0xff));
+          write((byte) (size.height >> 8));
+          write((byte) (size.height & 0xff));
+          write(IAC);write(SE);
+          break;
+        default:
+          if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+          reply = WONT;
+          break;
+        }
+        if(reply != sentWX[128+b] || DO != receivedDX[128+b]) {
+          sendbuf[0]=IAC;
+          sendbuf[1]=reply;
+          sendbuf[2]=b;
+          write(sendbuf);
+          sentWX[b+128] = reply;
+          receivedDX[b+128] = DO;
+        }
+        neg_state = STATE_DATA;
+        break;
+      case STATE_IACDONT:
+        switch (b) {
+        case TELOPT_ECHO:
+          if(debug > 2) System.err.println("ECHO");
+          reply = WONT;
+          setLocalEcho(false);
+          break;
+        case TELOPT_NAWS:
+          if(debug > 2) System.err.println("NAWS");
+          reply = WONT;
+          break;
+        default:
+          if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+          reply = WONT;
+          break;
+        }
+        if(reply != sentWX[b+128] || DONT != receivedDX[b+128]) {
+          write(IAC);write(reply);write(b);
+          sentWX[b+128] = reply;
+          receivedDX[b+128] = DONT;
+        }
+        neg_state = STATE_DATA;
+        break;
+      case STATE_IACSBIAC:
+        if(debug > 2) System.err.println(""+b+" ");
+        if (b == IAC) {
+          sbcount = 0;
+          current_sb = b;
+          neg_state = STATE_IACSBDATA;
+        } else {
+          System.err.println("(bad) "+b+" ");
+          neg_state = STATE_DATA;
+        }
+        break;
+      case STATE_IACSB:
+        if(debug > 2) System.err.println(""+b+" ");
+        switch (b) {
+        case IAC:
+          neg_state = STATE_IACSBIAC;
+          break;
+        default:
+          current_sb = b;
+          sbcount = 0;
+          neg_state = STATE_IACSBDATA;
+          break;
+        }
+        break;
+      case STATE_IACSBDATA:
+        if (debug > 2) System.err.println(""+b+" ");
+        switch (b) {
+        case IAC:
+          neg_state = STATE_IACSBDATAIAC;
+          break;
+        default:
+          sbbuf[sbcount++] = b;
+          break;
+        }
+        break;
+      case STATE_IACSBDATAIAC:
+        if (debug > 2) System.err.println(""+b+" ");
+        switch (b) {
+        case IAC:
+          neg_state = STATE_IACSBDATA;
+          sbbuf[sbcount++] = IAC;
+          break;
+        case SE:
+          handle_sb(current_sb,sbbuf,sbcount);
+          current_sb = 0;
+          neg_state = STATE_DATA;
+          break;
+        case SB:
+          handle_sb(current_sb,sbbuf,sbcount);
+          neg_state = STATE_IACSB;
+          break;
+        default:
+          neg_state = STATE_DATA;
+          break;
+        }
+        break;
+      default:
+        if (debug > 2) 
+          System.err.println("This should not happen: "+neg_state+" ");
+        neg_state = STATE_DATA;
+        break;
+      }
+    }
+    System.arraycopy(nbuf, 0, buf, 0, noffset);
+    return noffset;
+  }
+}
blob - /dev/null
blob + 53d4cdc95f2c62d72298b476293c3bf00e6c47b5 (mode 644)
--- /dev/null
+++ de/mud/terminal/SoftFont.java
@@ -0,0 +1,1006 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.terminal;
+
+import java.awt.*;
+import java.util.*;
+
+/**
+ * Any characters that are not available in standard java fonts may be
+ * drawn using the softfont utility. This utility class was derived from
+ * the cpi fonts used in linux console drivers.<P>
+ * <small>Font file generated by cpi2fnt</small>
+ * <P>
+ * <B>Maintainer:</B> Marcus Meißner
+ *
+ * @version $Id$
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class SoftFont {
+	final static private char	SF_BITMAP = 0;
+	final static private char	SF_FILLRECT = 1;
+
+
+	final static private char	SF_CHAR	= 0;
+	final static private char	SF_WIDTH= 1;
+	final static private char	SF_HEIGHT= 2;
+	final static private char	SF_TYPE  = 3;
+	final static private char	SF_DATA  = 4;
+	java.util.Hashtable font;
+	/** softfont characterdata */
+	private static char[][] fontdata = {
+	
+	{0x01,8,8,SF_BITMAP, /* 1 0x01 '^A' */
+	0x7e, /* 01111110 */
+	0x81, /* 10000001 */
+	0xa5, /* 10100101 */
+	0x81, /* 10000001 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0x81, /* 10000001 */
+	0x7e, /* 01111110 */
+	},{ 0x02,8,8,SF_BITMAP,/* 2 0x02 '^B' */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xdb, /* 11011011 */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	},{ 0x03,8,8,SF_BITMAP,/* 3 0x03 '^C' */
+	0x6c, /* 01101100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	},{ 0x04,8,8,SF_BITMAP,/* 4 0x04 '^D' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0x10, /* 00010000 */
+	0x00, /* 00000000 */
+	},{ 0x05,8,8,SF_BITMAP,/* 5 0x05 '^E' */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0x38, /* 00111000 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0xd6, /* 11010110 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	},{ 0x06,8,8,SF_BITMAP,/* 6 0x06 '^F' */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x7c, /* 01111100 */
+	0xfe, /* 11111110 */
+	0xfe, /* 11111110 */
+	0x7c, /* 01111100 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	},{ 0x2666,8,8,SF_BITMAP,/* 9830 0x2666 BLACK DIAMOND */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x07,8,8,SF_BITMAP,/* 7 0x07 '^G' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x08,8,8,SF_BITMAP,/* 8 0x08 '^H' */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0xe7, /* 11100111 */
+	0xc3, /* 11000011 */
+	0xc3, /* 11000011 */
+	0xe7, /* 11100111 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	},{ 0x09,8,8,SF_BITMAP,/* 9 0x09 '^I' */
+	0x00, /* 00000000 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x42, /* 01000010 */
+	0x42, /* 01000010 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x00, /* 00000000 */
+	},{ 0x0a,8,8,SF_BITMAP,/* 10 0x0a '^J' */
+	0xff, /* 11111111 */
+	0xc3, /* 11000011 */
+	0x99, /* 10011001 */
+	0xbd, /* 10111101 */
+	0xbd, /* 10111101 */
+	0x99, /* 10011001 */
+	0xc3, /* 11000011 */
+	0xff, /* 11111111 */
+	},{ 0x0b,8,8,SF_BITMAP,/* 11 0x0b '^K' */
+	0x0f, /* 00001111 */
+	0x07, /* 00000111 */
+	0x0f, /* 00001111 */
+	0x7d, /* 01111101 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0xcc, /* 11001100 */
+	0x78, /* 01111000 */
+	},{ 0x0c,8,8,SF_BITMAP,/* 12 0x0c '^L' */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	},{ 0x0d,8,8,SF_BITMAP,/* 13 0x0d '^M' */
+	0x3f, /* 00111111 */
+	0x33, /* 00110011 */
+	0x3f, /* 00111111 */
+	0x30, /* 00110000 */
+	0x30, /* 00110000 */
+	0x70, /* 01110000 */
+	0xf0, /* 11110000 */
+	0xe0, /* 11100000 */
+	},{ 0x0e,8,8,SF_BITMAP,/* 14 0x0e '^N' */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x7f, /* 01111111 */
+	0x63, /* 01100011 */
+	0x63, /* 01100011 */
+	0x67, /* 01100111 */
+	0xe6, /* 11100110 */
+	0xc0, /* 11000000 */
+	},{ 0x0f,8,8,SF_BITMAP,/* 15 0x0f '^O' */
+	0x18, /* 00011000 */
+	0xdb, /* 11011011 */
+	0x3c, /* 00111100 */
+	0xe7, /* 11100111 */
+	0xe7, /* 11100111 */
+	0x3c, /* 00111100 */
+	0xdb, /* 11011011 */
+	0x18, /* 00011000 */
+	},{ 0x10,8,8,SF_BITMAP,/* 16 0x10 '^P' */
+	0x80, /* 10000000 */
+	0xe0, /* 11100000 */
+	0xf8, /* 11111000 */
+	0xfe, /* 11111110 */
+	0xf8, /* 11111000 */
+	0xe0, /* 11100000 */
+	0x80, /* 10000000 */
+	0x00, /* 00000000 */
+	},{ 0x11,8,8,SF_BITMAP,/* 17 0x11 '^Q' */
+	0x02, /* 00000010 */
+	0x0e, /* 00001110 */
+	0x3e, /* 00111110 */
+	0xfe, /* 11111110 */
+	0x3e, /* 00111110 */
+	0x0e, /* 00001110 */
+	0x02, /* 00000010 */
+	0x00, /* 00000000 */
+	},{ 0x12,8,8,SF_BITMAP,/* 18 0x12 '^R' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	},{ 0x13,8,8,SF_BITMAP,/* 19 0x13 '^S' */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	0x66, /* 01100110 */
+	0x00, /* 00000000 */
+	},{ 0x14,8,8,SF_BITMAP,/* 20 0x14 '^T' */
+	0x7f, /* 01111111 */
+	0xdb, /* 11011011 */
+	0xdb, /* 11011011 */
+	0x7b, /* 01111011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x1b, /* 00011011 */
+	0x00, /* 00000000 */
+	},{ 0x15,8,8,SF_BITMAP,/* 21 0x15 '^U' */
+	0x3e, /* 00111110 */
+	0x61, /* 01100001 */
+	0x3c, /* 00111100 */
+	0x66, /* 01100110 */
+	0x66, /* 01100110 */
+	0x3c, /* 00111100 */
+	0x86, /* 10000110 */
+	0x7c, /* 01111100 */
+	},{ 0x16,8,8,SF_BITMAP,/* 22 0x16 '^V' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x7e, /* 01111110 */
+	0x00, /* 00000000 */
+	},{ 0x17,8,8,SF_BITMAP,/* 23 0x17 '^W' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0xff, /* 11111111 */
+	},{ 0x18,8,8,SF_BITMAP,/* 24 0x18 '^X' */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	},{ 0x19,8,8,SF_BITMAP,/* 25 0x19 '^Y' */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x18, /* 00011000 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	},{ 0x1a,8,8,SF_BITMAP,/* 26 0x1a '^Z' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x0c, /* 00001100 */
+	0xfe, /* 11111110 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x1b,8,8,SF_BITMAP,/* 27 0x1b '^[' */
+	0x00, /* 00000000 */
+	0x30, /* 00110000 */
+	0x60, /* 01100000 */
+	0xfe, /* 11111110 */
+	0x60, /* 01100000 */
+	0x30, /* 00110000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x1c,8,8,SF_BITMAP,/* 28 0x1c '^\' */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xc0, /* 11000000 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x1d,8,8,SF_BITMAP,/* 29 0x1d '^]' */
+	0x00, /* 00000000 */
+	0x24, /* 00100100 */
+	0x66, /* 01100110 */
+	0xff, /* 11111111 */
+	0x66, /* 01100110 */
+	0x24, /* 00100100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x1e,8,8,SF_BITMAP,/* 30 0x1e '^^' */
+	0x00, /* 00000000 */
+	0x18, /* 00011000 */
+	0x3c, /* 00111100 */
+	0x7e, /* 01111110 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x1f,8,8,SF_BITMAP,/* 31 0x1f '^_' */
+	0x00, /* 00000000 */
+	0xff, /* 11111111 */
+	0xff, /* 11111111 */
+	0x7e, /* 01111110 */
+	0x3c, /* 00111100 */
+	0x18, /* 00011000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x7f,8,8,SF_BITMAP,/* 127 0x7f '' */
+	0x00, /* 00000000 */
+	0x10, /* 00010000 */
+	0x38, /* 00111000 */
+	0x6c, /* 01101100 */
+	0xc6, /* 11000110 */
+	0xc6, /* 11000110 */
+	0xfe, /* 11111110 */
+	0x00, /* 00000000 */
+	},{ 0x2591,8,8,SF_BITMAP,/* LIGHT SHADE */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	0x22, /* 00100010 */
+	0x88, /* 10001000 */
+	},{ 0x2592,8,8,SF_BITMAP,/* MEDIUM SHADE */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	0x55, /* 01010101 */
+	0xaa, /* 10101010 */
+	},{ 0x2593,8,8,SF_BITMAP,/* DARK SHADE */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	0x77, /* 01110111 */
+	0xdd, /* 11011101 */
+	},{ 0x221a,8,8,SF_BITMAP,/* SQUARE ROOT */
+	0x78, /* 01111000 */
+	0x0c, /* 00001100 */
+	0x18, /* 00011000 */
+	0x30, /* 00110000 */
+	0x7c, /* 01111100 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	0x00, /* 00000000 */
+	},{ 0x2320,8,8,SF_BITMAP,/* UPPER INTERVAL*/
+        0x0e, /* 00001110 */
+        0x1b, /* 00011011 */
+        0x1b, /* 00011011 */
+        0x18, /* 00011000 */
+        0x18, /* 00011000 */
+        0x18, /* 00011000 */
+        0x18, /* 00011000 */
+        0x18, /* 00011000 */
+	},{ 0x25a0,8,8,SF_FILLRECT,/* BLACK SQUARE */
+		0x2244,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00111100 */
+		/* 00111100 */
+		/* 00111100 */
+		/* 00111100 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2502,8,8,SF_FILLRECT,/*BOX DRAWINGS LIGHT VERTICAL*/
+		0x3028,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2524,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+		0x3028,
+		0x0431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2561,8,8,SF_FILLRECT,/*BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE*/
+		0x3028,
+		0x0231,
+		0x0431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2562,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */
+		0x2028,
+		0x5028,
+		0x0421,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 11110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2556,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */
+		0x0471,
+		0x2523,
+		0x5523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2555,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */
+		0x3226,
+		0x0231,
+		0x0431,
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2563,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND LEFT*/
+		0x2022,
+		0x0221,
+		0x0421,
+		0x2424,
+		0x5028,
+		/* 00110110 */
+		/* 00110110 */
+		/* 11110110 */
+		/* 00000110 */
+		/* 11110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2551,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL */
+		0x2028,
+		0x5028,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2557,8,8,SF_FILLRECT,/*  BOX DRAWINGS DOUBLE DOWN AND LEFT */
+		0x0271,
+		0x5325,
+		0x0441,
+		0x2523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111110 */
+		/* 00000110 */
+		/* 11110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x255d,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND LEFT */
+		0x2022,
+		0x0241,
+		0x5025,
+		0x0451,
+		/* 00110110 */
+		/* 00110110 */
+		/* 11110110 */
+		/* 00000110 */
+		/* 11111110 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x255c,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */
+		0x2024,
+		0x5024,
+		0x0471,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 11111110 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x255b,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */
+		0x3025,
+		0x0231,
+		0x0431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2510,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND LEFT */
+		0x0451,
+		0x3523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2514,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND RIGHT */
+		0x3025,
+		0x5431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2534,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+		0x3024,
+		0x0481,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x252c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+		0x0481,
+		0x3523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x251c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+		0x3028,
+		0x5431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2500,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT HORIZONTAL */
+		0x0481,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x253c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+		0x3028,
+		0x0481,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x255e,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */
+		0x3028,
+		0x5231,
+		0x5431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x255f,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */
+		0x2028,
+		0x5028,
+		0x7411,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x255a,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND RIGHT */
+		0x2025,
+		0x5023,
+		0x7211,
+		0x4441,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110111 */
+		/* 00110000 */
+		/* 00111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2554,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND RIGHT */
+		0x2261,
+		0x2325,
+		0x5424,
+		0x7411,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00111111 */
+		/* 00110000 */
+		/* 00110111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2569,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
+		0x2022,
+		0x0241,
+		0x5022,
+		0x5231,
+		0x0481,
+		/* 00110110 */
+		/* 00110110 */
+		/* 11110111 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2566,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
+		0x0281,
+		0x0441,
+		0x2523,
+		0x5431,
+		0x5523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 11110111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2560,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
+		0x2028,
+		0x5022,
+		0x5231,
+		0x5431,
+		0x5623,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110111 */
+		/* 00110000 */
+		/* 00110111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2550,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE HORIZONTAL */
+		0x0281,
+		0x0481,
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x256c,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
+		0x2022,
+		0x0241,
+		0x5022,
+		0x5231,
+		0x0441,
+		0x2523,
+		0x5431,
+		0x5523,
+		/* 00110110 */
+		/* 00110110 */
+		/* 11110111 */
+		/* 00000000 */
+		/* 11110111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2567,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */
+		0x3022,
+		0x0281,
+		0x0481,
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2568,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */
+		0x2024,
+		0x5024,
+		0x0481,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2564,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */
+		0x0281,
+		0x0481,
+		0x3523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2565,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */
+		0x0481,
+		0x2523,
+		0x5523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x2559,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */
+		0x2024,
+		0x5024,
+		0x2461,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2558,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */
+		0x3025,
+		0x5231,
+		0x5431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x2552,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */
+		0x3226,
+		0x5231,
+		0x5431,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2553,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */
+		0x2461,
+		0x2523,
+		0x5523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00111111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x256b,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */
+		0x2028,
+		0x5028,
+		0x0481,
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 11111111 */
+		/* 00110110 */
+		/* 00110110 */
+		/* 00110110 */
+	},{ 0x256a,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */
+		0x3028,
+		0x0281,
+		0x0481,
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111111 */
+		/* 00011000 */
+		/* 11111111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2518,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND LEFT */
+		0x3025,
+		0x0431,
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 11111000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	},{ 0x250c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND RIGHT */
+		0x3451,
+		0x3523,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00011111 */
+		/* 00011000 */
+		/* 00011000 */
+		/* 00011000 */
+	},{ 0x2588,8,8,SF_FILLRECT,/* FULL BLOCK */
+		0x0088,
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+	},{ 0x2584,8,8,SF_FILLRECT,/* LOWER HALF BLOCK */
+		0x0484,
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+	},{ 0x258c,8,8,SF_FILLRECT,/* LEFT HALF BLOCK */
+		0x0048,
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+		/* 11110000 */
+	},{ 0x2590,8,8,SF_FILLRECT,/* RIGHT HALF BLOCK */
+		0x4048,
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+		/* 00001111 */
+	},{ 0x2580,8,8,SF_FILLRECT,/* UPPER HALF BLOCK */
+		0x0084,
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 11111111 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+		/* 00000000 */
+	}};
+
+	public SoftFont() {
+		font = new java.util.Hashtable();
+		for (int i=0;i<fontdata.length;i++)
+			font.put(new Integer(fontdata[i][0]),new Integer(i));
+
+	}
+
+	public boolean inSoftFont(char c) {
+		boolean insoftfont;
+
+		insoftfont = (null!=font.get(new Integer(c)));
+		if (!insoftfont && (int)c>=0x100) {
+			System.out.println("Character "+((int)c)+" not in softfont");
+		}
+		return insoftfont;
+	}
+
+	public void drawChar(Graphics g,char c,int x,int y,int cw,int ch) {
+		double	dw,dh;
+		Object	Ientry;
+		int	w,h,entry,i,fontwidth,fontheight;
+		
+		Ientry = font.get(new Integer(c));
+		if (Ientry == null)
+			return;
+		entry = ((Integer)Ientry).intValue();
+		fontwidth = fontdata[entry][SF_WIDTH];
+		fontheight = fontdata[entry][SF_HEIGHT];
+
+		dw = cw*1.0/fontwidth;
+		dh = ch*1.0/fontheight;
+
+		switch (fontdata[entry][SF_TYPE]) {
+		case SF_BITMAP:
+			for (h=0;h<fontheight;h++) {
+				for (w=0;w<fontwidth;w++) {
+					//FIXME: 8 bit max currently...
+					if (0!=(fontdata[entry][h+SF_DATA] & (1<<(7-w)))) {
+						g.fillRect(
+							x+(int)(w*dw),
+							y+(int)(h*dh),
+							((int)((w+1)*dw))-(int)(w*dw),
+							((int)((h+1)*dh))-(int)(h*dh)
+						);
+					}
+				}
+			}
+			break;
+		case SF_FILLRECT:
+			i=SF_DATA;
+			while (i<fontdata[entry].length) {
+				int	xw,xh;
+
+				w=(fontdata[entry][i]&0xF000)>>12;
+				h=(fontdata[entry][i]&0x0F00)>>8;
+				xw = (fontdata[entry][i]&0x00F0)>>4;
+				xh = (fontdata[entry][i]&0x000F);
+				g.fillRect(
+					x+(int)(w*dw),
+					y+(int)(h*dh),
+					((int)((w+xw)*dw))-(int)(w*dw),
+					((int)((h+xh)*dh))-(int)(h*dh)
+				);
+				i++;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
blob - /dev/null
blob + baa659369be0ad30a2f8ead65ac57ea3071b7cbb (mode 644)
--- /dev/null
+++ de/mud/terminal/VDU.java
@@ -0,0 +1,1196 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.terminal;
+
+import java.awt.Graphics;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+import java.awt.Insets;
+import java.awt.Event;
+import java.awt.Label;
+import java.awt.Frame;
+import java.awt.Rectangle;
+
+import java.awt.AWTEvent;
+
+/**
+ * Video Display Unit emulation. This class implements all necessary
+ * features of a character display unit, but not the actual terminal emulation.
+ * It can be used as the base for terminal emulations of any kind.
+ * <P>
+ * <B>Maintainer:</B> Matthias L. Jugel
+ *
+ * @version $Id$
+ * @author  Matthias L. Jugel, Marcus Meißner
+ */
+public class VDU extends Canvas {
+  /** The current version id tag */
+  public final static String ID = "$Id$";
+
+  /** Enable debug messages. */
+  public final static int debug = 0;
+  
+  private Dimension size;                             /* rows and columns */
+  private Insets insets;                            /* size of the border */
+  private boolean raised;            /* indicator if the border is raised */
+
+  private char charArray[][];                  /* contains the characters */
+  private int charAttributes[][];             /* contains character attrs */
+  private int bufSize, maxBufSize;                        /* buffer sizes */
+
+  private int windowBase;                   /* where the start displaying */
+  private int screenBase;                      /* the actual screen start */
+  private int topMargin;                             /* top scroll margin */
+  private int bottomMargin;                       /* bottom scroll margin */
+
+  private Font normalFont;                                 /* normal font */
+  private FontMetrics fm;                         /* current font metrics */
+  private int charWidth;                       /* current width of a char */
+  private int charHeight;                     /* current height of a char */
+  private int charDescent;                           /* base line descent */
+  private int resizeStrategy;                /* current resizing strategy */
+
+  private int cursorX, cursorY;                /* current cursor position */
+  private Point selectBegin, selectEnd;          /* selection coordinates */
+
+  private SoftFont  sf = new SoftFont();
+
+  private boolean screenLocked = false;      /* screen needs to be locked */
+                                             /* because of paint requests */
+                                             /*   during other operations */
+  private boolean update[];        /* contains the lines that need update */
+  
+  /**
+   * Create a color representation that is brighter than the standard
+   * color but not what we would like to use for bold characters.
+   * @param clr the standard color
+   * @return the new brighter color
+   */
+  private Color brighten(Color clr) {
+    return new Color(Math.max((int) (clr.getRed() *.85), 0),
+		     Math.max((int) (clr.getGreen() * .85), 0),
+		     Math.max((int) (clr.getBlue() * .85), 0));
+  }
+
+  /** A list of colors used for representation of the display */
+  private Color color[] = { brighten(Color.black),
+                            brighten(Color.red),
+                            brighten(Color.green),
+                            brighten(Color.yellow),
+                            brighten(Color.blue),
+                            brighten(Color.magenta),
+                            brighten(Color.cyan),
+                            brighten(Color.white),
+  };
+
+  public final static int COLOR_0 = 0;
+  public final static int COLOR_1 = 1;
+  public final static int COLOR_2 = 2;
+  public final static int COLOR_3 = 3;
+  public final static int COLOR_4 = 4;
+  public final static int COLOR_5 = 5;
+  public final static int COLOR_6 = 6;
+  public final static int COLOR_7 = 7;
+
+  /* definitions of standards for the display unit */
+  private static int COLOR_FG_STD  = 7;
+  private static int COLOR_FG_BOLD = 3;
+  private static int COLOR_BG_STD  = 0;
+  private final static int COLOR         = 0x7f8;
+  private final static int COLOR_FG      = 0x78;
+  private final static int COLOR_BG      = 0x780;
+
+  /** Scroll up when inserting a line. */
+  public final static boolean SCROLL_UP   = false;
+  /** Scroll down when inserting a line. */
+  public final static boolean SCROLL_DOWN = true;
+
+  /** Do nothing when the component is resized. */
+  public final static int RESIZE_NONE  = 0;
+  /** Resize the width and height of the character screen. */
+  public final static int RESIZE_SCREEN  = 1;
+  /** Resize the font to the new screen size. */
+  public final static int RESIZE_FONT  = 2;
+  
+  /** Make character normal. */ 
+  public final static int NORMAL  = 0x00;
+  /** Make character bold. */ 
+  public final static int BOLD    = 0x01;
+  /** Underline character. */ 
+  public final static int UNDERLINE  = 0x02;
+  /** Invert character. */ 
+  public final static int INVERT  = 0x04;
+
+  /** 
+   * Create a new video display unit with the passed width and height in
+   * characters using a special font and font size. These features can
+   * be set independently using the appropriate properties.
+   * @param width the length of the character lines
+   * @param height the amount of lines on the screen
+   * @param font the font to be used (usually Monospaced)
+   */
+  public VDU(int width, int height, Font font) {
+    // set the normal font to use
+    setFont(font);
+    // set the standard resize strategy
+    setResizeStrategy(RESIZE_FONT);
+    // set the display screen size
+    setScreenSize(width, height);
+
+    selectBegin = new Point(0,0);
+    selectEnd = new Point(0,0);
+  }
+  
+  /**
+   * Create a display unit with specific size, Font is "Monospaced", size 12.
+   * @param width the length of the character lines
+   * @param height the amount of lines on the screen
+   */
+  public VDU(int width, int height) {
+    this(width, height, new Font("Monospaced", Font.PLAIN, 12));
+  }
+
+  /**
+   * Create a display with the font passed and size 80x24.
+   * @param font the font to be used (usually Monospaced)
+   */
+  public VDU(Font font) {
+    this(80, 24, font);
+  }
+
+  /**
+   * Create a display unit with size 80x24 and Font "Monospaced", size 12.
+   */
+  public VDU() {
+    this(80, 24, new Font("Monospaced", Font.PLAIN, 12));
+  }
+
+  public void setColorSet(Color[] colorset) {
+    System.arraycopy(colorset, 0, color, 0, 8);
+  }
+
+  public Color[] getColorSet() {
+    return color;
+  }
+
+  /**
+   * Put a character on the screen with normal font and outline.
+   * The character previously on that position will be overwritten.
+   * You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @param ch the character to show on the screen
+   * @see #insertChar
+   * @see #deleteChar
+   * @see #redraw
+   */
+  public void putChar(int c, int l, char ch) {
+    putChar(c, l, ch, NORMAL);
+  }
+
+  /**
+   * Put a character on the screen with specific font and outline.
+   * The character previously on that position will be overwritten.
+   * You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @param ch the character to show on the screen
+   * @param attributes the character attributes
+   * @see #BOLD
+   * @see #UNDERLINE
+   * @see #INVERT
+   * @see #NORMAL
+   * @see #insertChar
+   * @see #deleteChar
+   * @see #redraw
+   */  
+
+  public void putChar(int c, int l, char ch, int attributes) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    charArray[screenBase + l][c] = ch;
+    charAttributes[screenBase + l][c] = attributes;
+    markLine(l, 1);
+  }
+
+  /**
+   * Get the character at the specified position.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @see #putChar
+   */
+  public char getChar(int c, int l) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    return charArray[l][c];
+  }
+
+  /**
+   * Get the attributes for the specified position.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @see #putChar
+   */
+  public int getAttributes(int c, int l) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    return charAttributes[l][c];
+  }
+
+  /**
+   * Insert a character at a specific position on the screen.
+   * All character right to from this position will be moved one to the right.
+   * You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @param ch the character to insert
+   * @param attributes the character attributes
+   * @see #BOLD
+   * @see #UNDERLINE
+   * @see #INVERT
+   * @see #NORMAL
+   * @see #putChar
+   * @see #deleteChar
+   * @see #redraw
+   */
+  public void insertChar(int c, int l, char ch, int attributes) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    System.arraycopy(charArray[screenBase + l], c, 
+         charArray[screenBase + l], c + 1, size.width - c - 1);
+    System.arraycopy(charAttributes[screenBase + l], c, 
+         charAttributes[screenBase + l], c + 1, size.width - c - 1);
+    putChar(c, l, ch, attributes);
+  }
+
+  /**
+   * Delete a character at a given position on the screen.
+   * All characters right to the position will be moved one to the left.
+   * You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @see #putChar
+   * @see #insertChar
+   * @see #redraw
+   */
+  public void deleteChar(int c, int l) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    if(c < size.width - 1) {
+      System.arraycopy(charArray[screenBase + l], c + 1,
+           charArray[screenBase + l], c, size.width - c - 1);
+      System.arraycopy(charAttributes[screenBase + l], c + 1,
+           charAttributes[screenBase + l], c, size.width - c - 1);
+    }
+    putChar(size.width - 1, l, (char)0);
+  }
+
+  /**
+   * Put a String at a specific position. Any characters previously on that 
+   * position will be overwritten. You need to call redraw() for screen update.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @param s the string to be shown on the screen
+   * @see #BOLD
+   * @see #UNDERLINE
+   * @see #INVERT
+   * @see #NORMAL
+   * @see #putChar
+   * @see #insertLine
+   * @see #deleteLine
+   * @see #redraw
+   */  
+  public void putString(int c, int l, String s) {
+    putString(c, l, s, NORMAL);
+  }
+  
+  /**
+   * Put a String at a specific position giving all characters the same
+   * attributes. Any characters previously on that position will be 
+   * overwritten. You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (line)
+   * @param s the string to be shown on the screen
+   * @param attributes character attributes
+   * @see #BOLD
+   * @see #UNDERLINE
+   * @see #INVERT
+   * @see #NORMAL
+   * @see #putChar
+   * @see #insertLine
+   * @see #deleteLine
+   * @see #redraw
+   */
+  public void putString(int c, int l, String s, int attributes) {
+    for(int i = 0; i < s.length() && c + i < size.width; i++)
+      putChar(c + i, l, s.charAt(i), attributes);
+  }
+
+  /**
+   * Insert a blank line at a specific position.
+   * The current line and all previous lines are scrolled one line up. The
+   * top line is lost. You need to call redraw() to update the screen.
+   * @param l the y-coordinate to insert the line
+   * @see #deleteLine
+   * @see #redraw
+   */
+  public void insertLine(int l) {
+    insertLine(l, 1, SCROLL_UP);
+  }
+
+  /**
+   * Insert blank lines at a specific position.
+   * You need to call redraw() to update the screen
+   * @param l the y-coordinate to insert the line
+   * @param n amount of lines to be inserted
+   * @see #deleteLine
+   * @see #redraw
+   */
+  public void insertLine(int l, int n) {
+    insertLine(l, n, SCROLL_UP);
+  }  
+
+  /**
+   * Insert a blank line at a specific position. Scroll text according to
+   * the argument.
+   * You need to call redraw() to update the screen
+   * @param l the y-coordinate to insert the line
+   * @param scrollDown scroll down
+   * @see #deleteLine
+   * @see #SCROLL_UP
+   * @see #SCROLL_DOWN
+   * @see #redraw
+   */
+  public void insertLine(int l, boolean scrollDown) {
+    insertLine(l, 1, scrollDown);
+  }  
+
+  /**
+   * Insert blank lines at a specific position.
+   * The current line and all previous lines are scrolled one line up. The
+   * top line is lost. You need to call redraw() to update the screen.
+   * @param l the y-coordinate to insert the line
+   * @param n number of lines to be inserted
+   * @param scrollDown scroll down
+   * @see #deleteLine
+   * @see #SCROLL_UP
+   * @see #SCROLL_DOWN
+   * @see #redraw
+   */
+  public synchronized void insertLine(int l, int n, boolean scrollDown) {
+    screenLocked = true;
+
+    l = checkBounds(l, 0, size.height - 1);
+
+    char cbuf[][] = null;
+    int abuf[][] = null;
+    int offset = 0;
+    int oldBase = screenBase;
+    int top = (l < topMargin ? 
+               0 : (l > bottomMargin ?
+                    (bottomMargin + 1 < size.height ?
+                     bottomMargin + 1 : size.height - 1) : topMargin));
+    int bottom = (l > bottomMargin ?
+                  size.height - 1 : (l < topMargin ? 
+                                     (topMargin > 0 ?
+                                      topMargin - 1 : 0) : bottomMargin));
+    
+    
+    if(scrollDown) {
+      if(n > (bottom - top)) n = (bottom - top);
+      cbuf = new char[bottom - l - (n - 1)][size.width];
+      abuf = new int[bottom - l - (n - 1)][size.width];
+      
+      System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1));
+      System.arraycopy(charAttributes, oldBase + l, 
+		       abuf, 0, bottom - l - (n - 1));
+      System.arraycopy(cbuf, 0, charArray, oldBase + l + n, 
+		       bottom - l - (n - 1));
+      System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, 
+		       bottom - l - (n - 1));
+      cbuf = charArray;
+      abuf = charAttributes;
+    } else try {
+      if(n > (bottom - top) + 1) n = (bottom - top) + 1;
+      if(bufSize < maxBufSize) {
+        if(bufSize + n > maxBufSize) {
+          offset = n - (maxBufSize - bufSize);
+          bufSize = maxBufSize;
+          screenBase = maxBufSize - size.height - 1;
+          windowBase = screenBase;
+        } else {
+          screenBase += n;
+          windowBase += n;
+          bufSize += n;
+        }
+        cbuf = new char[bufSize][size.width];
+        abuf = new int[bufSize][size.width];
+      } else {
+        offset = n;
+        cbuf = charArray;
+        abuf = charAttributes;
+      }
+      // copy anything from the top of the buffer (+offset) to the new top
+      // up to the screenBase.
+      if(oldBase > 0) {
+        System.arraycopy(charArray, offset, 
+                         cbuf, 0, 
+                         oldBase - offset);
+        System.arraycopy(charAttributes, offset, 
+                         abuf, 0, 
+                         oldBase - offset);
+      }
+      // copy anything from the top of the screen (screenBase) up to the
+      // topMargin to the new screen
+      if(top > 0) {
+        System.arraycopy(charArray, oldBase, 
+                         cbuf, screenBase, 
+                         top);
+        System.arraycopy(charAttributes, oldBase, 
+                         abuf, screenBase, 
+                         top);
+      }
+      // copy anything from the topMargin up to the amount of lines inserted
+      // to the gap left over between scrollback buffer and screenBase
+      if(oldBase > 0) {
+	System.arraycopy(charArray, oldBase + top, 
+			 cbuf, oldBase - offset,
+			 n);
+	System.arraycopy(charAttributes, oldBase + top, 
+			 abuf, oldBase - offset,
+			 n);
+      }
+      // copy anything from topMargin + n up to the line linserted to the
+      // topMargin
+      System.arraycopy(charArray, oldBase + top + n,
+                       cbuf, screenBase + top,
+                       l - top - (n - 1));
+      System.arraycopy(charAttributes, oldBase + top + n,
+                       abuf, screenBase + top,
+                       l - top - (n - 1));
+      //
+      // copy the all lines next to the inserted to the new buffer
+      if(l < size.height - 1) {
+        System.arraycopy(charArray, oldBase + l + 1,
+                         cbuf, screenBase + l + 1,
+                         (size.height - 1) - l);
+        System.arraycopy(charAttributes, oldBase + l + 1,
+                         abuf, screenBase + l + 1,
+                         (size.height - 1) - l);
+      }
+    } catch(ArrayIndexOutOfBoundsException e) {
+      // this should not happen anymore, but I will leave the code
+      // here in case something happens anyway. That code above is
+      // so complex I always have a hard time understanding what
+      // I did, even though there are comments
+      System.err.println("*** Error while scrolling up:");
+      System.err.println("--- BEGIN STACK TRACE ---");
+      e.printStackTrace();
+      System.err.println("--- END STACK TRACE ---");
+      System.err.println("bufSize="+bufSize+", maxBufSize="+maxBufSize);
+      System.err.println("top="+top+", bottom="+bottom);
+      System.err.println("n="+n+", l="+l);
+      System.err.println("screenBase="+screenBase+", windowBase="+windowBase);
+      System.err.println("oldBase="+oldBase);
+      System.err.println("size.width="+size.width+", size.height="+size.height);
+      System.err.println("abuf.length="+abuf.length+", cbuf.length="+cbuf.length);
+      System.err.println("*** done dumping debug information");
+    }
+    
+    for(int i = 0; i < n; i++) {
+      cbuf[(screenBase + l) + (scrollDown ? i : -i) ] = new char[size.width];
+      abuf[(screenBase + l) + (scrollDown ? i : -i) ] = new int[size.width];
+    }
+
+    charArray = cbuf;
+    charAttributes = abuf;
+    
+    if(scrollDown)
+      markLine(l, bottom - l + 1);
+    else
+      markLine(top, l - top + 1);
+
+    screenLocked = false;
+  }
+  
+  /**
+   * Delete a line at a specific position. Subsequent lines will be scrolled 
+   * up to fill the space and a blank line is inserted at the end of the 
+   * screen.
+   * @param l the y-coordinate to insert the line
+   * @see #deleteLine
+   */
+  public void deleteLine(int l) {
+    l = checkBounds(l, 0, size.height - 1);
+
+    int bottom = (l>bottomMargin?size.height-1:
+		  (l<topMargin?topMargin:bottomMargin+1));
+    System.arraycopy(charArray, screenBase + l + 1,
+                     charArray, screenBase + l, bottom - l -1 );
+    System.arraycopy(charAttributes, screenBase + l + 1,
+                     charAttributes, screenBase + l, bottom - l -1);
+    charArray[screenBase + bottom - 1] = new char[size.width];
+    charAttributes[screenBase + bottom - 1] = new int[size.width];
+    markLine(l, bottom - l);
+  }
+
+
+  /**
+   * Delete a rectangular portion of the screen.
+   * You need to call redraw() to update the screen.
+   * @param c x-coordinate (column)
+   * @param l y-coordinate (row)
+   * @param w with of the area in characters
+   * @param h height of the area in characters
+   * @see #deleteChar
+   * @see #deleteLine
+   * @see redraw
+   */
+  public void deleteArea(int c, int l, int w, int h) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+
+    char cbuf[] = new char[w];
+    int abuf[] = new int[w];
+    
+    for(int i = 0; i < h && l + i < size.height; i++)
+    {
+      System.arraycopy(cbuf, 0, charArray[screenBase + l + i], c, w);
+      System.arraycopy(abuf, 0, charAttributes[screenBase + l + i], c, w);
+    }
+    markLine(l, h);
+  }
+
+  /**
+   * Puts the cursor at the specified position.
+   * @param c column
+   * @param l line
+   */
+  public void setCursorPosition(int c, int l) {
+    c = checkBounds(c, 0, size.width - 1);
+    l = checkBounds(l, 0, size.height - 1);
+    markLine(cursorY, 1);
+    cursorX = (c < size.width ? c : size.width);
+    cursorY = (l < size.height ? l : size.height);
+    markLine(l, 1);
+  }
+
+  /**
+   * Get the current cursor position.
+   * @see java.awt.Dimension
+   */
+  public Dimension getCursorPosition() {
+    return new Dimension(cursorX, cursorY);
+  }
+
+  /**
+   * Set the top scroll margin for the screen. If the current bottom margin
+   * is smaller it will become the top margin and the line will become the
+   * bottom margin.
+   * @param l line that is the margin
+   */
+  public void setTopMargin(int l) {
+    if(l > bottomMargin) {
+      topMargin = bottomMargin;
+      bottomMargin = l;
+    }
+    else
+      topMargin = l;
+    if(topMargin < 0) topMargin = 0;
+    if(bottomMargin > size.height - 1) bottomMargin = size.height - 1;
+  }
+
+  /**
+   * Get the top scroll margin.
+   */
+  public int getTopMargin() {
+    return topMargin;
+  }
+
+  /**
+   * Set the bottom scroll margin for the screen. If the current top margin
+   * is bigger it will become the bottom margin and the line will become the
+   * top margin.
+   * @param l line that is the margin
+   */
+  public void setBottomMargin(int l) {
+    if(l < topMargin) {
+      bottomMargin = topMargin;
+      topMargin = l;
+    }
+    else
+      bottomMargin = l;
+    if(topMargin < 0) topMargin = 0;
+    if(bottomMargin > size.height - 1) bottomMargin = size.height - 1;
+  }
+
+  /**
+   * Get the bottom scroll margin.
+   */
+  public int getBottomMargin() {
+    return bottomMargin;
+  }
+    
+  /**
+   * Set scrollback buffer size.
+   * @param amount new size of the buffer
+   */
+  public void setBufferSize(int amount) {
+    screenLocked = true;
+
+    if(amount < size.height) amount = size.height;
+    if(amount < maxBufSize) {
+      char cbuf[][] = new char[amount][size.width];
+      int abuf[][] = new int[amount][size.width];
+      if(charArray != null)
+        System.arraycopy(charArray, bufSize - amount, cbuf, 0, amount);
+      if(charAttributes != null)
+        System.arraycopy(charAttributes, bufSize - amount, abuf, 0, amount);
+      charArray = cbuf;
+      charAttributes = abuf;
+    }
+    maxBufSize = amount;
+ 
+    screenLocked = false;
+
+    repaint();
+  }
+
+  /**
+   * Retrieve current scrollback buffer size.
+   * @see #setBufferSize
+   */
+  public int getBufferSize() {
+    return bufSize;
+  }
+
+  /**
+   * Retrieve maximum buffer Size.
+   * @see #getBufferSize
+   */
+  public int getMaxBufferSize() {
+    return maxBufSize;
+  }
+
+  /**
+   * Set the current window base. This allows to view the scrollback buffer.
+   * @param line the line where the screen window starts
+   * @see setBufferSize
+   * @see getBufferSize
+   */
+  public void setWindowBase(int line) {
+    if(line > screenBase) line = screenBase;
+    else if(line < 0) line = 0;
+    windowBase = line;
+    repaint();
+  }
+
+  /**
+   * Get the current window base.
+   * @see setWindowBase
+   */
+  public int getWindowBase() {
+    return windowBase;
+  }
+
+  /**
+   * Set the font to be used for rendering the characters on screen.
+   * @param font the new font to be used.
+   */
+  public void setFont(Font font) {
+    super.setFont(normalFont = font);
+    fm = getFontMetrics(font);
+    if(fm != null) {
+      charWidth = fm.charWidth('@');
+      charHeight = fm.getHeight();
+      charDescent = fm.getDescent();
+    }
+  }
+      
+  /**
+   * Change the size of the screen. This will include adjustment of the 
+   * scrollback buffer.
+   * @param columns width of the screen
+   * @param columns height of the screen
+   */
+  public void setScreenSize(int width, int height) {
+    char cbuf[][];
+    int abuf[][];
+    int bsize = bufSize;
+
+    if(width < 1 || height < 1) return;
+    
+    if(debug > 0)
+      System.err.println("VDU: screen size ["+width+","+height+"]");
+
+    screenLocked = true;
+    
+    // super.update(getGraphics());
+    
+    if(height > maxBufSize) 
+      maxBufSize = height;
+
+    if(height > bufSize) {
+      bufSize = height;
+      screenBase = 0;
+      windowBase = 0;
+    }
+
+    cbuf = new char[bufSize][width];
+    abuf = new int[bufSize][width];
+    
+    if(charArray != null && charAttributes != null)
+      for(int i = 0; i < bsize && i < bufSize; i++) {
+        System.arraycopy(charArray[i], 0, cbuf[i], 0, 
+             width < size.width ? width : size.width);
+        System.arraycopy(charAttributes[i], 0, abuf[i], 0, 
+             width < size.width ? width : size.width);
+      }
+    charArray = cbuf;
+    charAttributes = abuf;
+    size = new Dimension(width, height);
+    topMargin = 0;
+    bottomMargin = height - 1;
+    update = new boolean[height + 1];
+    for(int i = 0; i <= height; i++) update[i] = true;
+    screenLocked = false;
+  }
+
+  /**
+   * Get the screen size in rows and columns.
+   */
+  public Dimension getScreenSize() {
+    return size;
+  }
+
+  /**
+   * Set the strategy when window is resized.
+   * RESIZE_FONT is default.
+   * @param strategy the strategy
+   * @see #RESIZE_NONE
+   * @see #RESIZE_FONT
+   * @see #RESIZE_SCREEN
+   */
+  public void setResizeStrategy(int strategy) {
+    resizeStrategy = strategy;
+  }
+  
+  /**
+   * Get amount of rows on the screen.
+   */
+  public int getRows() { return size.height; }
+
+  /**
+   * Get amount of columns on the screen.
+   */
+  public int getColumns() { return size.width; }
+
+  /**
+   * Set the border thickness and the border type.
+   * @param thickness border thickness in pixels, zero means no border
+   * @param raised a boolean indicating a raised or embossed border
+   */
+  public void setBorder(int thickness, boolean raised) {
+    if(thickness == 0) insets = null;
+    else insets = new Insets(thickness+1, thickness+1, 
+                             thickness+1, thickness+1);
+    this.raised = raised;
+  }
+
+  /**
+   * Mark lines to be updated with redraw().
+   * @param l starting line
+   * @param n amount of lines to be updated
+   * @see #redraw
+   */
+  public void markLine(int l, int n) {
+    l = checkBounds(l, 0, size.height - 1);
+    for(int i = 0; i < n && l + i < size.height; i++) 
+      update[l + i + 1] = true;
+  }
+  
+  /**
+   * Redraw marked lines.
+   * @see #markLine
+   */
+  public void redraw() {
+    update[0] = true;
+    repaint();
+  }
+
+  /**
+   * Update the display. to reduce flashing we have overridden this method.
+   */
+  public void update(Graphics g) {
+    paint(g);
+  }
+  
+  /**
+   * Paint the current screen. All painting is done here. Only lines that have
+   * changed will be redrawn!
+   */
+  public synchronized void paint(Graphics g) {
+    if(screenLocked) return;
+    int xoffset = (super.getSize().width - size.width * charWidth) / 2;
+    int yoffset = (super.getSize().height - size.height * charHeight) / 2;
+
+    Color fg = color[COLOR_FG_STD];
+    Color bg = color[COLOR_BG_STD];
+
+    g.setFont(normalFont);
+
+    for(int l = 0; l < size.height; l++) {
+      if(update[0] && !update[l + 1]) continue;
+      update[l + 1] = false;
+      for(int c = 0; c < size.width; c++) {
+        int addr = 0;
+        int currAttr = charAttributes[windowBase + l][c];
+
+        fg = getForeground();
+        bg = getBackground();
+        // fg = color[COLOR_FG_STD];
+    	// bg = color[COLOR_BG_STD];
+
+	// Special handling of BOLD for terminals used on 5ESS 
+        if(((currAttr & BOLD) != 0)   &&
+	   ((currAttr & COLOR_FG) == 0) &&
+	   ((currAttr & COLOR_BG) == 0))
+	  fg = color[COLOR_FG_BOLD];
+
+        if ((currAttr & COLOR_FG) != 0)
+          fg = color[((currAttr & COLOR_FG) >> 3)-1];
+        if ((currAttr & COLOR_BG) != 0)
+          bg = color[((currAttr & COLOR_BG) >> 7)-1];
+
+        if((currAttr & BOLD) != 0)
+          if(fg.equals(Color.black))
+            fg = Color.gray;
+          else {
+	    fg = fg.brighter();
+	    bg = bg.brighter();
+	  }
+
+        if((currAttr & INVERT) != 0) { Color swapc = bg; bg=fg;fg=swapc; }
+
+        if (sf.inSoftFont(charArray[windowBase + l][c])) {
+          g.setColor(bg);	
+          g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset, 
+		     charWidth, charHeight);
+          g.setColor(fg);	
+          sf.drawChar(g,charArray[windowBase + l][c],xoffset+c*charWidth,
+		      l*charHeight+yoffset, charWidth, charHeight);
+          if((currAttr & UNDERLINE) != 0)
+            g.drawLine(c * charWidth + xoffset,
+                     (l+1) * charHeight - charDescent / 2 + yoffset,
+                     c * charWidth + charWidth + xoffset, 
+                     (l+1) * charHeight - charDescent / 2 + yoffset);
+          continue;
+        }
+        
+	// determine the maximum of characters we can print in one go
+        while(c + addr < size.width && 
+              charAttributes[windowBase + l][c + addr] == currAttr &&
+              !sf.inSoftFont(charArray[windowBase + l ][c+addr])
+        ) {
+          if(charArray[windowBase + l][c + addr] < ' ')
+            charArray[windowBase + l][c + addr] = ' ';
+          addr++;
+        }
+        
+        // clear the part of the screen we want to change (fill rectangle)
+        g.setColor(bg);
+        g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset,
+                   addr * charWidth, charHeight);
+
+        g.setColor(fg);
+        
+	// draw the characters
+        g.drawChars(charArray[windowBase + l], c, addr, 
+                    c * charWidth + xoffset, 
+                    (l+1) * charHeight - charDescent + yoffset);
+
+        if((currAttr & UNDERLINE) != 0)
+          g.drawLine(c * charWidth + xoffset,
+                     (l+1) * charHeight - charDescent / 2 + yoffset,
+                     c * charWidth + addr * charWidth + xoffset, 
+                     (l+1) * charHeight - charDescent / 2 + yoffset);
+        
+        c += addr - 1;
+      }
+    }
+
+    // draw cursor
+    if(screenBase + cursorY >= windowBase && 
+       screenBase + cursorY < windowBase + size.height) {
+      g.setColor(color[COLOR_FG_STD]);
+      g.setXORMode(color[COLOR_BG_STD]);
+      g.fillRect( cursorX * charWidth + xoffset, 
+                 (cursorY + screenBase - windowBase) * charHeight + yoffset,
+                 charWidth, charHeight);
+      g.setPaintMode();
+    }
+
+    if(windowBase <= selectBegin.y || windowBase <= selectEnd.y) {
+      int beginLine = selectBegin.y - windowBase;
+      int endLine = selectEnd.y - selectBegin.y;
+      if(beginLine < 0) {
+        endLine += beginLine;
+        beginLine = 0;
+      }
+      if(endLine > size.height) endLine = size.height - beginLine;
+       
+      g.setXORMode(color[COLOR_BG_STD]);
+      g.fillRect(selectBegin.x * charWidth + xoffset,
+                 beginLine * charHeight + yoffset,
+                 (endLine == 0 ? (selectEnd.x - selectBegin.x) : 
+                  (size.width - selectBegin.x)) 
+                 * charWidth,
+                 charHeight);
+      if(endLine > 1)
+        g.fillRect(0 + xoffset, 
+                   (beginLine + 1) * charHeight + yoffset, 
+                   size.width * charWidth, 
+                   (endLine - 1) * charHeight);
+      if(endLine > 0)
+        g.fillRect(0 + xoffset, 
+                   (beginLine + endLine) * charHeight + yoffset,
+                   selectEnd.x * charWidth, 
+                   charHeight);
+      g.setPaintMode();
+    }
+
+    if(insets != null) {
+      g.setColor(getBackground());
+      xoffset--; yoffset--;
+      for(int i = insets.top - 1; i >= 0; i--)
+        g.draw3DRect(xoffset - i, yoffset - i,
+                     charWidth * size.width + 1 + i * 2, 
+                     charHeight * size.height + 1 + i * 2,
+                     raised);
+    }
+
+    update[0] = false;
+  }
+
+  private int checkBounds(int value, int lower, int upper) {
+    if(value < lower) return lower;
+    if(value > upper) return upper;
+    return value;
+  }
+
+  /**
+   * Reshape character display according to resize strategy.
+   * @see #setResizeStrategy
+   */
+  public void setBounds(int x, int y, int w, int h) {
+    if(debug > 0)
+      System.err.println("VDU: setBounds("+x+","+y+","+w+","+h+")");
+
+    int xborder = 0, yborder = 0;
+    
+    if(insets != null) {
+      w -= (xborder = insets.left + insets.right);
+      h -= (yborder = insets.top + insets.bottom);
+    }
+
+    if(debug > 0)
+      System.err.println("VDU: looking for better match for "+normalFont);
+
+    Font tmpFont = normalFont;
+    String fontName = normalFont.getName();
+    fm = getFontMetrics(normalFont);
+    if(fm != null) {
+      charWidth = fm.charWidth('@');
+      charHeight = fm.getHeight();
+    }
+    
+    switch(resizeStrategy) {
+    case RESIZE_SCREEN:
+      setScreenSize(w / charWidth, size.height = h / charHeight);
+      break;
+    case RESIZE_FONT:
+      int height = h / size.height;
+      int width = w / size.width;
+      
+      fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, 
+                                                charHeight));
+      
+      // adapt current font size (from small up to best fit)
+      if(fm.getHeight() < height || fm.charWidth('@') < width)
+        do {
+          fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, 
+                                                    ++charHeight));
+        } while(fm.getHeight() < height || fm.charWidth('@') < width); 
+      
+      // now check if we got a font that is too large
+      if(fm.getHeight() > height || fm.charWidth('@') > width)
+        do {
+          fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, 
+                                                    --charHeight));
+        } while(charHeight > 1 && 
+                (fm.getHeight() > height || 
+                 fm.charWidth('@') > width));
+      
+      if(charHeight <= 1) {
+        System.err.println("VDU: error during resize, resetting");
+        normalFont = tmpFont;
+        System.err.println("VDU: disabling font/screen resize");
+        resizeStrategy = RESIZE_NONE;
+      }
+
+      setFont(normalFont);
+      fm = getFontMetrics(normalFont);
+      charWidth = fm.charWidth('@');
+      charHeight = fm.getHeight();
+      charDescent = fm.getDescent();
+      break;
+    case RESIZE_NONE:
+    default:
+      break;
+    }
+    if(debug > 0) {
+      System.err.println("VDU: charWidth="+charWidth+", "+
+                              "charHeight="+charHeight+", "+
+                              "charDescent="+charDescent);
+    }
+
+    // now set the bounds for the whole component accordingly
+    super.setBounds(x, y, w + xborder, h + yborder);
+  }
+
+  /**
+   * Return the real size in points of the character display.
+   * @return Dimension the dimension of the display
+   * @see java.awt.Dimension
+   */
+  public Dimension getSize() {
+    int xborder = 0, yborder = 0;
+    if(insets != null) {
+      xborder = insets.left + insets.right;
+      yborder = insets.top + insets.bottom;
+    }
+    return new Dimension(size.width * charWidth + xborder, 
+                         size.height * charHeight + yborder);
+  }
+
+  /**
+   * Return the preferred Size of the character display.
+   * This turns out to be the actual size.
+   * @return Dimension dimension of the display
+   * @see size
+   */
+  public Dimension getPreferredSize() {
+    return getSize();
+  }
+
+  /**
+   * The insets of the character display define the border.
+   * @return Insets border thickness in pixels
+   */
+  public Insets getInsets() {
+    return insets;
+  }
+
+  /**
+   * Handle mouse events for copy & paste
+   * @param evt the event that occured
+   * @return boolean true if action was taken
+   * @see java.awt.Event
+   */
+ /*
+  public void mouseDown(MouseEvent evt) {
+    // handle scrollbar events
+    if(evt != null && evt.arg != null) {
+      int val = ((Integer)evt.arg).intValue();
+      setWindowBase(val);
+      return true;
+    }
+
+    if(evt.id == Event.MOUSE_DOWN || evt.id == Event.MOUSE_UP ||
+       evt.id == Event.MOUSE_DRAG) {
+      int xoffset = (super.size().width - size.width * charWidth) / 2;
+      int yoffset = (super.size().height - size.height * charHeight) / 2;
+      switch(evt.id) {
+      case Event.MOUSE_DOWN:
+        selectBegin.x = (evt.x - xoffset) / charWidth;
+        selectBegin.y = (evt.y - yoffset) / charHeight + windowBase;
+        selectEnd.x = selectBegin.x;
+        selectEnd.y = selectBegin.y;
+        break;
+      case Event.MOUSE_UP:
+      case Event.MOUSE_DRAG:
+        int x = (evt.x - xoffset) / charWidth;
+        int y = (evt.y - yoffset) / charHeight + windowBase;
+        int oldx = selectEnd.x, oldy = selectEnd.y;
+
+        if((x < selectBegin.x && y < selectBegin.y) &&
+           (x < selectEnd.x && y < selectEnd.y)) {
+          selectBegin.x = x;
+          selectBegin.y = y;
+        } else {
+          selectEnd.x = x;
+          selectEnd.y = y;
+        }
+
+        if(evt.id == Event.MOUSE_UP) {
+          if(selectBegin.x == selectEnd.x &&
+             selectBegin.y == selectEnd.y) {
+            repaint();
+            return true;
+          }
+          String tmp = "";
+	  // fix end.x and end.y, they can get over the border
+	  if (selectEnd.x < 0) selectEnd.x = 0;
+	  if (selectEnd.y < 0) selectEnd.y = 0;
+	  if (selectEnd.y >= charArray.length) {
+		selectEnd.y = charArray.length-1;
+	  }
+	  if (selectEnd.x >= charArray[0].length) {
+		selectEnd.x = charArray[0].length-1;
+	  }
+          for(int l = selectBegin.y; l <= selectEnd.y; l++)
+            if(l == selectBegin.y) 
+              tmp = (new String(charArray[l])).substring(selectBegin.x) + "\n";
+            else if(l == selectEnd.y) 
+              tmp += (new String(charArray[l])).substring(0, selectEnd.x);
+            else tmp += new String(charArray[l]) + "\n";
+
+	    // for jdk-1.1
+	  //   String s=(String) ((StringSelection)this.getToolkit().
+	// 		       getSystemClipboard().
+	// 		       getContents(this)).
+	    //   getTransferData(DataFlavor.stringFlavor);
+	    // System.out.println(s);
+	    //
+          repaint();
+        } else
+          if(oldx != x || oldy != y) repaint();
+        break;
+      }
+      return true;
+    }
+    return false;
+  }
+  */
+}
blob - /dev/null
blob + 86d5f70125316fb6b421c8f612f3dc58a74b1ade (mode 644)
--- /dev/null
+++ de/mud/terminal/vt320.java
@@ -0,0 +1,1878 @@
+/*
+ * This file is part of "The Java Telnet Application".
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * "The Java Telnet Application" is distributed in the hope that it will be 
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package de.mud.terminal;
+
+import java.awt.Font;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import java.util.Properties;
+
+/**
+ * Implementation of a VT terminal emulation plus ANSI compatible.
+ * <P>
+ * <B>Maintainer:</B> Marcus Meißner
+ *
+ * @version $Id$
+ * @author  Matthias L. Jugel, Marcus Meißner
+ */
+public abstract class vt320 extends VDU implements KeyListener {
+  /** The current version id tag.<P>
+   * $Id$
+   */
+  public final static String ID = "$Id$";
+
+  /** the debug level */
+  private final static int debug = 0;
+
+  /**
+   * Write an answer back to the remote host. This is needed to be able to
+   * send terminal answers requests like status and type information.
+   * @param b the array of bytes to be sent
+   */
+  protected abstract void write(byte[] b);
+
+  /**
+   * Put string at current cursor position. Moves cursor
+   * according to the String. Does NOT wrap.
+   * @param s the string
+   */
+  public void putString(String s) {
+    int  i,len=s.length();
+
+    markLine(R,1);
+    for (i=0;i<len;i++)
+      putChar(s.charAt(i),false);
+    setCursorPosition(C, R);
+    redraw();
+  }
+
+  /**
+   * Create a new vt320 terminal and intialize it with useful settings.
+   * @param width the width of the character screen
+   * @param height the amount of rows on screen
+   * @param font the font to be used for rendering characters
+   */
+  public vt320(int width, int height, Font font) {
+    super(width, height, font);
+
+    setVMS(false);
+    setIBMCharset(false);
+    setTerminalID("vt320");
+    setBufferSize(100);
+    setBorder(2, false);
+
+    int nw = getColumns();
+    if (nw<132) nw=132; //catch possible later 132/80 resizes
+    Tabs = new byte[nw];
+    for (int i=0;i<nw;i+=8) {
+      Tabs[i]=1;
+    }
+
+    /* top row of numpad */
+    PF1  = "\u001bOP";
+    PF2  = "\u001bOQ";
+    PF3  = "\u001bOR";
+    PF4  = "\u001bOS";
+
+    /* the 3x2 keyblock on PC keyboards */
+    Insert = new String[4];
+    Remove = new String[4];
+    KeyHome = new String[4];
+    KeyEnd = new String[4];
+    NextScn = new String[4];
+    PrevScn = new String[4];
+    Insert[0]  = Insert[1]  = Insert[2]  = Insert[3]  = "\u001b[2~";
+    Remove[0]  = Remove[1]  = Remove[2]  = Remove[3]  = "\u001b[3~";
+    PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
+    NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
+    KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001bOH";
+    KeyEnd[0]  = KeyEnd[1]  = KeyEnd[2]  = KeyEnd[3]  = "\u001bOF";
+
+    /* some more VT100 keys */
+    Find   = "\u001b[1~";
+    Select = "\u001b[4~";
+    Help   = "\u001b[28~";
+    Do     = "\u001b[29~";
+
+    FunctionKey = new String[21];
+    FunctionKey[0]= "";
+    FunctionKey[1]= PF1;
+    FunctionKey[2]= PF2;
+    FunctionKey[3]= PF3;
+    FunctionKey[4]= PF4;
+    /* following are defined differently for vt220 / vt132 ... */
+    FunctionKey[5]= "\u001b[15~";
+    FunctionKey[6]= "\u001b[17~";
+    FunctionKey[7]= "\u001b[18~";
+    FunctionKey[8]= "\u001b[19~";
+    FunctionKey[9]= "\u001b[20~";
+    FunctionKey[10]= "\u001b[21~";
+    FunctionKey[11]= "\u001b[23~";
+    FunctionKey[12]= "\u001b[24~";
+    FunctionKey[13]= "\u001b[25~";
+    FunctionKey[14]= "\u001b[26~";
+    FunctionKey[15]= Help;
+    FunctionKey[16]= Do;
+    FunctionKey[17]= "\u001b[31~";
+    FunctionKey[18]= "\u001b[32~";
+    FunctionKey[19]= "\u001b[33~";
+    FunctionKey[20]= "\u001b[34~";
+
+    FunctionKeyShift = new String[21];
+    FunctionKeyAlt = new String[21];
+    FunctionKeyCtrl = new String[21];
+
+    for (int i=0;i<20;i++) {
+      FunctionKeyShift[i]="";
+      FunctionKeyAlt[i]="";
+      FunctionKeyCtrl[i]="";
+    }
+    FunctionKeyShift[15] = Find;
+    FunctionKeyShift[16] = Select;
+
+
+    KeyTab     = "\u0009";
+    KeyBacktab = "\u001bOP\u0009";
+    KeyUp      = "\u001b[A";
+    KeyDown    = "\u001b[B";
+    KeyRight   = "\u001b[C";
+    KeyLeft    = "\u001b[D";
+    KP0  = "\u001bOp";
+    KP1  = "\u001bOq";
+    KP2  = "\u001bOr";
+    KP3  = "\u001bOs";
+    KP4  = "\u001bOt";
+    KP5  = "\u001bOu";
+    KP6  = "\u001bOv";
+    KP7  = "\u001bOw";
+    KP8  = "\u001bOx";
+    KP9  = "\u001bOy";
+    KPMinus  = "\u001bOm";
+    KPComma  = "\u001bOl";
+    KPPeriod  = "\u001bOn";
+    KPEnter  = "\u001bOM";
+
+    /* ... */
+
+    addKeyListener(this);
+    addMouseListener(new MouseAdapter() {
+      public void mouseEntered(MouseEvent evt) {
+        requestFocus();
+      }
+    });
+      
+  }
+
+  /**
+   * Create a new terminal emulation with specific width and height.
+   * @param width the width of the character screen
+   * @param height the amount of rows on screen
+   */
+  public vt320(int width, int height) {
+    this(width, height, new Font("Monospaced", Font.PLAIN, 10));
+  }
+
+  /**
+   * Create a new terminal emulation with a specific font.
+   * @param font the font to be used for rendering characters
+   */
+  public vt320(Font font) {
+    this(80, 24, font);
+  }
+
+  /**
+   * Create a new terminal emulation with a specific font.
+   */
+  public vt320() {
+    this(80, 24, new Font("Monospaced", Font.PLAIN, 10));
+  }
+
+  private boolean localecho = false;
+
+  /**
+   * Enable or disable the local echo property of the terminal.
+   * @param echo true if the terminal should echo locally
+   */
+  public void setLocalEcho(boolean echo) {
+    localecho = echo;
+  }
+
+  /**
+   * Enable the VMS mode of the terminal to handle some things differently
+   * for VMS hosts.
+   * @param vms true for vms mode, false for normal mode
+   */
+  public void setVMS(boolean vms) {
+    this.vms = vms;
+  }
+
+  /**
+   * Enable the usage of the IBM character set used by some BBS's. Special
+   * graphical character are available in this mode.
+   * @param ibm true to use the ibm character set
+   */
+  public void setIBMCharset(boolean ibm) {
+    useibmcharset = ibm;
+  }
+
+  /**
+   * Override the standard key codes used by the terminal emulation.
+   * @param codes a properties object containing key code definitions
+   */
+  public void setKeyCodes(Properties codes) {
+    String res, prefixes[] = {"","S","C","A"};
+    for (int i=1;i<20;i++) {
+      for (int j=0;j<4;j++) {
+	res= codes.getProperty(prefixes[j]+"F"+i);
+	if (res!=null) FunctionKey[i] = unEscape(res);
+      }
+    }
+    for (int i=0;i<4;i++) {
+      res = codes.getProperty(prefixes[i]+"PGUP");
+      if (res!=null) PrevScn[i]=unEscape(res);
+      res = codes.getProperty(prefixes[i]+"PGDOWN");
+      if (res!=null) NextScn[i]=unEscape(res);
+      res = codes.getProperty(prefixes[i]+"END");
+      if (res!=null) KeyEnd[i]=unEscape(res);
+      res = codes.getProperty(prefixes[i]+"HOME");
+      if (res!=null) KeyHome[i]=unEscape(res);
+      res = codes.getProperty(prefixes[i]+"INSERT");
+      if (res!=null) Insert[i]=unEscape(res);
+      res = codes.getProperty(prefixes[i]+"REMOVE");
+      if (res!=null) Remove[i]=unEscape(res);
+    }
+    res = codes.getProperty("UP");if (res!=null) KeyUp=unEscape(res);
+    res = codes.getProperty("DOWN");if (res!=null) KeyDown=unEscape(res);
+    res = codes.getProperty("LEFT");if (res!=null) KeyLeft=unEscape(res);
+    res = codes.getProperty("RIGHT");if (res!=null) KeyRight=unEscape(res);
+
+  }
+
+  /**
+   * Set the terminal id used to identify this terminal.
+   * @param terminalID the id string
+   */
+  public void setTerminalID(String terminaID) { 
+    this.terminalID = terminalID; 
+  }
+
+  /**
+   * Get the terminal id used to identify this terminal.
+   * @param terminalID the id string
+   */
+  public String getTerminalID() { 
+    return terminalID; 
+  }
+
+  /**
+   * A small conveniance method thar converts the string to a byte array
+   * for sending.
+   * @param s the string to be sent
+   */
+  private boolean write(String s) {
+    write(s.getBytes());
+    return true;
+  }
+
+
+  // ===================================================================
+  // the actual terminal emulation code comes here:
+  // ===================================================================
+
+  // due to a bug with Windows we need a keypress cache
+  private int pressedKey = ' ';
+  private long pressedWhen = ' ';
+
+  private String terminalID = "vt320";
+
+  // X - COLUMNS, Y - ROWS
+  int  R,C;
+  int  Sc,Sr,Sa;
+  int  attributes  = 0;
+  int  insertmode  = 0;
+  int  statusmode = 0;
+  int  vt52mode  = 0;
+  int  normalcursor  = 0;
+  boolean moveoutsidemargins = true;
+  boolean sendcrlf = false;
+  boolean capslock = false;
+  boolean numlock = false;
+
+  private boolean  useibmcharset = false;
+
+  private  static  int  lastwaslf = 0;
+  private static  int i;
+  private final static char ESC = 27;
+  private final static char IND = 132;
+  private final static char NEL = 133;
+  private final static char RI  = 141;
+  private final static char HTS = 136;
+  private final static char DCS = 144;
+  private final static char CSI = 155;
+  private final static char OSC = 157;
+  private final static int TSTATE_DATA  = 0;
+  private final static int TSTATE_ESC  = 1; /* ESC */
+  private final static int TSTATE_CSI  = 2; /* ESC [ */
+  private final static int TSTATE_DCS  = 3; /* ESC P */
+  private final static int TSTATE_DCEQ  = 4; /* ESC [? */
+  private final static int TSTATE_ESCSQUARE= 5; /* ESC # */
+  private final static int TSTATE_OSC= 6;       /* ESC ] */
+  private final static int TSTATE_SETG0= 7;     /* ESC (? */
+  private final static int TSTATE_SETG1= 8;     /* ESC )? */
+  private final static int TSTATE_SETG2= 9;     /* ESC *? */
+  private final static int TSTATE_SETG3= 10;    /* ESC +? */
+  private final static int TSTATE_CSI_DOLLAR  = 11; /* ESC [ Pn $ */
+
+  /* The graphics charsets
+   * B - default ASCII
+   * A - default UK
+   * 0 - DEC SPECIAL
+   * < - User defined
+   * ....
+   */
+  private static char gx[] = {
+    'B',      // g0
+    '0',      // g1
+    'A',      // g2
+    '<',      // g3
+  };
+  private static char gr = 1;  // default GR to G1
+  private static char gl = 0;  // default GL to G0
+
+  // array to store DEC Special -> Unicode mapping
+  //  Unicode   DEC  Unicode name    (DEC name)
+  private static char DECSPECIAL[] = {
+    '\u0040', //5f blank
+    '\u2666', //60 black diamond
+    '\u2592', //61 grey square
+    '\u2409', //62 Horizontal tab  (ht) pict. for control
+    '\u240c', //63 Form Feed       (ff) pict. for control
+    '\u240d', //64 Carriage Return (cr) pict. for control
+    '\u240a', //65 Line Feed       (lf) pict. for control
+    '\u00ba', //66 Masculine ordinal indicator
+    '\u00b1', //67 Plus or minus sign
+    '\u2424', //68 New Line        (nl) pict. for control
+    '\u240b', //69 Vertical Tab    (vt) pict. for control
+    '\u2518', //6a Forms light up   and left
+    '\u2510', //6b Forms light down and left
+    '\u250c', //6c Forms light down and right
+    '\u2514', //6d Forms light up   and right
+    '\u253c', //6e Forms light vertical and horizontal
+    '\u2594', //6f Upper 1/8 block                        (Scan 1)
+    '\u2580', //70 Upper 1/2 block                        (Scan 3)
+    '\u2500', //71 Forms light horizontal or ?em dash?    (Scan 5)
+    '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
+    '\u005f', //73 \u005f underscore  or \u2581 lower 1/8 (Scan 9)
+    '\u251c', //74 Forms light vertical and right
+    '\u2524', //75 Forms light vertical and left
+    '\u2534', //76 Forms light up   and horizontal
+    '\u252c', //77 Forms light down and horizontal
+    '\u2502', //78 vertical bar
+    '\u2264', //79 less than or equal
+    '\u2265', //7a greater than or equal
+    '\u00b6', //7b paragraph
+    '\u2260', //7c not equal
+    '\u00a3', //7d Pound Sign (british)
+    '\u00b7'  //7e Middle Dot
+  };
+
+  /** Strings to send on function key pressing */
+  private String FunctionKey[];
+  private String FunctionKeyShift[];
+  private String FunctionKeyCtrl[];
+  private String FunctionKeyAlt[];
+  private String KeyUp,KeyDown,KeyLeft,KeyRight,KeyTab,KeyBacktab;
+
+  private String KP0, KP1, KP2, KP3, KP4, KP5, KP6, KP7, KP8, KP9;
+  private String KPMinus, KPComma, KPPeriod,KPEnter;
+  private String PF1, PF2, PF3, PF4;
+  private String Help, Do, Find, Select;
+
+  private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
+
+  private String osc,dcs;  /* to memorize OSC & DCS control sequence */
+
+  private int term_state = TSTATE_DATA;
+  private boolean vms = false;
+  private byte[]  Tabs;
+  private int[]  DCEvars = new int [10];
+  private int  DCEvar;
+
+  /**
+   * Replace escape code characters (backslash + identifier) with their
+   * respective codes.
+   * @param tmp the string to be parsed
+   * @return a unescaped string
+   */
+  static String unEscape(String tmp) {
+    int idx = 0, oldidx = 0;
+    String cmd;
+
+    cmd = "";
+    while((idx = tmp.indexOf('\\', oldidx)) >= 0 &&
+	  ++idx <= tmp.length()) {
+      cmd += tmp.substring(oldidx, idx-1);
+      if(idx == tmp.length()) return cmd;
+      switch(tmp.charAt(idx)) {
+      case 'b': cmd += "\b"; break;
+      case 'e': cmd += "\u001b"; break;
+      case 'n': cmd += "\n"; break;
+      case 'r': cmd += "\r"; break;
+      case 't': cmd += "\t"; break;
+      case 'v': cmd += "\u000b"; break;
+      case 'a': cmd += "\u0012"; break;
+      default : 
+	if ( (tmp.charAt(idx)>='0') && (tmp.charAt(idx)<='9')) {
+	  for (i = idx;i<tmp.length();i++)
+	    if ( (tmp.charAt(i)<'0') || (tmp.charAt(i)>'9'))
+	      break;
+	  cmd += (char)Integer.parseInt(tmp.substring(idx, i));
+	  idx = i-1;
+	} else
+	  cmd += tmp.substring(idx, ++idx);break;
+      }
+      oldidx = ++idx;
+    }
+    if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx);
+    return cmd;
+  }
+
+  /**
+   * Not used.
+   */
+  public void keyTyped(KeyEvent evt) {
+    // nothing to to, however maybe we should use it?
+  }
+
+  /**
+   * Not used.
+   */
+  public void keyReleased(KeyEvent evt) {
+    // nothing to to, however maybe we should use it?
+  }
+
+  /**
+   * Handle events for the terminal. Only accept events for the scroll
+   * bar. Any other events have to be propagated to the parent.
+   * @param evt the event
+   */
+  public void keyPressed(KeyEvent evt) {
+    boolean control = evt.isControlDown();
+    boolean shift = evt.isShiftDown();
+    boolean alt = evt.isAltDown();
+
+    int keyCode = evt.getKeyCode();
+    char keyChar = evt.getKeyChar();
+
+    if(pressedKey == KeyEvent.VK_ENTER && 
+        (keyCode == KeyEvent.VK_ENTER || keyChar == 10)
+        && evt.getWhen() - pressedWhen < 50) 
+      //  Ray: Elliminate stuttering enter/return
+      return;
+
+    pressedWhen = evt.getWhen();
+
+    if(keyCode == KeyEvent.VK_ENTER && !control) {
+      if(sendcrlf)
+	write("\r\n"); /* YES, see RFC 854 */
+      else
+	write("\r"); /* YES, see RFC 854 */
+    } 
+    
+    // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
+    // so we can't just use it here... will probably break some other VMS
+    // codes.  -Marcus
+    // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ') 
+    //    && control)
+    if (((!vms && keyChar == '2') || keyChar == ' ') && control)
+      write("" + (char)0);
+    
+    if(vms) {
+      if (keyChar == 8) {
+	if(shift && !control)
+	  write("" + (char)10);    //  VMS shift deletes word back
+	else if(control && !shift)
+	  write("" + (char)24);    //  VMS control deletes line back
+	else
+	  write("" + (char)127);   //  VMS other is delete
+      } else if(keyChar == 127 && !control) {
+	if (shift) 
+	  write(Insert[0]);        //  VMS shift delete = insert
+	else
+	  write(Remove[0]);        //  VMS delete = remove
+      } else if(control)
+	switch(keyChar) {
+	case '0':
+	  write(KP0); return;
+	case '1':
+	  write(KP1); return;
+	case '2':
+	  write(KP2); return;
+	case '3':
+	  write(KP3); return;
+	case '4':
+	  write(KP4); return;
+	case '5':
+	  write(KP5); return;
+	case '6':
+	  write(KP6); return;
+	case '7':
+	  write(KP7); return;
+	case '8':
+	  write(KP8); return;
+	case '9':
+	  write(KP9); return;
+	case '.':
+	  write(KPPeriod); return;
+	case '-':
+	case 31:
+	  write(KPMinus); return;
+	case '+':
+	  write(KPComma); return;
+	case 10:
+	  write(KPEnter); return;
+	case '/':
+	  write(PF2); return;
+	case '*':
+	  write(PF3); return;
+	}
+	if (shift && keyChar < 32)
+	  write(PF1+(char)(keyChar + 64));
+        return;
+    }
+
+    String fmap[];
+    int    xind;
+    xind = 0;
+    fmap = FunctionKey;
+    if(shift) { fmap = FunctionKeyShift; xind=1; }
+    if(control) { fmap = FunctionKeyCtrl; xind=2; }
+    if(alt) { fmap = FunctionKeyAlt; xind=3; }
+
+    switch (keyCode) {
+      case KeyEvent.VK_F1:
+        write(fmap[1]); return;
+      case KeyEvent.VK_F2:
+        write(fmap[2]); return;
+      case KeyEvent.VK_F3:
+        write(fmap[3]); return;
+      case KeyEvent.VK_F4:
+        write(fmap[4]); return;
+      case KeyEvent.VK_F5:
+        write(fmap[5]); return;
+      case KeyEvent.VK_F6:
+        write(fmap[6]); return;
+      case KeyEvent.VK_F7:
+        write(fmap[7]); return;
+      case KeyEvent.VK_F8:
+        write(fmap[8]); return;
+      case KeyEvent.VK_F9:
+        write(fmap[9]); return;
+      case KeyEvent.VK_F10:
+        write(fmap[10]); return;
+      case KeyEvent.VK_F11:
+        write(fmap[11]); return;
+      case KeyEvent.VK_F12:
+        write(fmap[12]); return;
+      case KeyEvent.VK_UP:
+        write(KeyUp); return;
+      case KeyEvent.VK_DOWN:
+        write(KeyDown); return;
+      case KeyEvent.VK_LEFT:
+        write(KeyLeft); return;
+      case KeyEvent.VK_RIGHT:
+        write(KeyRight); return;
+      case KeyEvent.VK_PAGE_DOWN:
+        write(NextScn[xind]); return;
+      case KeyEvent.VK_PAGE_UP:
+        write(PrevScn[xind]); return;
+      case KeyEvent.VK_INSERT:
+        write(Insert[xind]); return;
+      case KeyEvent.VK_HOME:
+        if(vms) 
+	  write("" + (char)8);
+        else
+	  write(KeyHome[xind]);
+	return;
+      case KeyEvent.VK_END:
+        if(vms)
+	  write("" + (char)5);
+        else
+	  write(KeyEnd[xind]);
+	return;
+      case KeyEvent.VK_NUM_LOCK:
+        if(vms && control)
+	  if(pressedKey != keyCode) {
+	    pressedKey = keyCode;
+	    write(PF1);
+	  } else
+	    //  Here, we eat a second numlock since that returns numlock state
+	    pressedKey = ' ';
+	if(!control)
+	  numlock = !numlock;
+	return;
+      case KeyEvent.VK_CAPS_LOCK:
+      	capslock = !capslock;
+        return;
+      default:
+	if(debug > 0)
+	  System.out.println("vt320: unknown event: "+evt);
+    }
+
+    // Hmmm. Outside the VMS case?
+    if(shift && (keyChar == '\t')) 
+      write(KeyBacktab);
+    else if (alt)
+      write(""+((char)(keyChar|0x80)));
+    else if(capslock) 
+      write((""+keyChar).toUpperCase());
+    else
+      write(""+keyChar);
+  }
+
+  private void handle_dcs(String dcs) {
+    System.out.println("DCS: "+dcs);
+  }
+  private void handle_osc(String osc) {
+    System.out.println("OSC: "+osc);
+  }
+
+  private final static char unimap[] = {
+    //#
+    //#    Name:     cp437_DOSLatinUS to Unicode table
+    //#    Unicode version: 1.1
+    //#    Table version: 1.1
+    //#    Table format:  Format A
+    //#    Date:          03/31/95
+    //#    Authors:       Michel Suignard <michelsu@microsoft.com>
+    //#                   Lori Hoerth <lorih@microsoft.com>
+    //#    General notes: none
+    //#
+    //#    Format: Three tab-separated columns
+    //#        Column #1 is the cp1255_WinHebrew code (in hex)
+    //#        Column #2 is the Unicode (in hex as 0xXXXX)
+    //#        Column #3 is the Unicode name (follows a comment sign, '#')
+    //#
+    //#    The entries are in cp437_DOSLatinUS order
+    //#
+
+    0x0000,// #NULL
+    0x0001,// #START OF HEADING
+    0x0002,// #START OF TEXT
+    0x0003,// #END OF TEXT
+    0x0004,// #END OF TRANSMISSION
+    0x0005,// #ENQUIRY
+    0x0006,// #ACKNOWLEDGE
+    0x0007,// #BELL
+    0x0008,// #BACKSPACE
+    0x0009,// #HORIZONTAL TABULATION
+    0x000a,// #LINE FEED
+    0x000b,// #VERTICAL TABULATION
+    0x000c,// #FORM FEED
+    0x000d,// #CARRIAGE RETURN
+    0x000e,// #SHIFT OUT
+    0x000f,// #SHIFT IN
+    0x0010,// #DATA LINK ESCAPE
+    0x0011,// #DEVICE CONTROL ONE
+    0x0012,// #DEVICE CONTROL TWO
+    0x0013,// #DEVICE CONTROL THREE
+    0x0014,// #DEVICE CONTROL FOUR
+    0x0015,// #NEGATIVE ACKNOWLEDGE
+    0x0016,// #SYNCHRONOUS IDLE
+    0x0017,// #END OF TRANSMISSION BLOCK
+    0x0018,// #CANCEL
+    0x0019,// #END OF MEDIUM
+    0x001a,// #SUBSTITUTE
+    0x001b,// #ESCAPE
+    0x001c,// #FILE SEPARATOR
+    0x001d,// #GROUP SEPARATOR
+    0x001e,// #RECORD SEPARATOR
+    0x001f,// #UNIT SEPARATOR
+    0x0020,// #SPACE
+    0x0021,// #EXCLAMATION MARK
+    0x0022,// #QUOTATION MARK
+    0x0023,// #NUMBER SIGN
+    0x0024,// #DOLLAR SIGN
+    0x0025,// #PERCENT SIGN
+    0x0026,// #AMPERSAND
+    0x0027,// #APOSTROPHE
+    0x0028,// #LEFT PARENTHESIS
+    0x0029,// #RIGHT PARENTHESIS
+    0x002a,// #ASTERISK
+    0x002b,// #PLUS SIGN
+    0x002c,// #COMMA
+    0x002d,// #HYPHEN-MINUS
+    0x002e,// #FULL STOP
+    0x002f,// #SOLIDUS
+    0x0030,// #DIGIT ZERO
+    0x0031,// #DIGIT ONE
+    0x0032,// #DIGIT TWO
+    0x0033,// #DIGIT THREE
+    0x0034,// #DIGIT FOUR
+    0x0035,// #DIGIT FIVE
+    0x0036,// #DIGIT SIX
+    0x0037,// #DIGIT SEVEN
+    0x0038,// #DIGIT EIGHT
+    0x0039,// #DIGIT NINE
+    0x003a,// #COLON
+    0x003b,// #SEMICOLON
+    0x003c,// #LESS-THAN SIGN
+    0x003d,// #EQUALS SIGN
+    0x003e,// #GREATER-THAN SIGN
+    0x003f,// #QUESTION MARK
+    0x0040,// #COMMERCIAL AT
+    0x0041,// #LATIN CAPITAL LETTER A
+    0x0042,// #LATIN CAPITAL LETTER B
+    0x0043,// #LATIN CAPITAL LETTER C
+    0x0044,// #LATIN CAPITAL LETTER D
+    0x0045,// #LATIN CAPITAL LETTER E
+    0x0046,// #LATIN CAPITAL LETTER F
+    0x0047,// #LATIN CAPITAL LETTER G
+    0x0048,// #LATIN CAPITAL LETTER H
+    0x0049,// #LATIN CAPITAL LETTER I
+    0x004a,// #LATIN CAPITAL LETTER J
+    0x004b,// #LATIN CAPITAL LETTER K
+    0x004c,// #LATIN CAPITAL LETTER L
+    0x004d,// #LATIN CAPITAL LETTER M
+    0x004e,// #LATIN CAPITAL LETTER N
+    0x004f,// #LATIN CAPITAL LETTER O
+    0x0050,// #LATIN CAPITAL LETTER P
+    0x0051,// #LATIN CAPITAL LETTER Q
+    0x0052,// #LATIN CAPITAL LETTER R
+    0x0053,// #LATIN CAPITAL LETTER S
+    0x0054,// #LATIN CAPITAL LETTER T
+    0x0055,// #LATIN CAPITAL LETTER U
+    0x0056,// #LATIN CAPITAL LETTER V
+    0x0057,// #LATIN CAPITAL LETTER W
+    0x0058,// #LATIN CAPITAL LETTER X
+    0x0059,// #LATIN CAPITAL LETTER Y
+    0x005a,// #LATIN CAPITAL LETTER Z
+    0x005b,// #LEFT SQUARE BRACKET
+    0x005c,// #REVERSE SOLIDUS
+    0x005d,// #RIGHT SQUARE BRACKET
+    0x005e,// #CIRCUMFLEX ACCENT
+    0x005f,// #LOW LINE
+    0x0060,// #GRAVE ACCENT
+    0x0061,// #LATIN SMALL LETTER A
+    0x0062,// #LATIN SMALL LETTER B
+    0x0063,// #LATIN SMALL LETTER C
+    0x0064,// #LATIN SMALL LETTER D
+    0x0065,// #LATIN SMALL LETTER E
+    0x0066,// #LATIN SMALL LETTER F
+    0x0067,// #LATIN SMALL LETTER G
+    0x0068,// #LATIN SMALL LETTER H
+    0x0069,// #LATIN SMALL LETTER I
+    0x006a,// #LATIN SMALL LETTER J
+    0x006b,// #LATIN SMALL LETTER K
+    0x006c,// #LATIN SMALL LETTER L
+    0x006d,// #LATIN SMALL LETTER M
+    0x006e,// #LATIN SMALL LETTER N
+    0x006f,// #LATIN SMALL LETTER O
+    0x0070,// #LATIN SMALL LETTER P
+    0x0071,// #LATIN SMALL LETTER Q
+    0x0072,// #LATIN SMALL LETTER R
+    0x0073,// #LATIN SMALL LETTER S
+    0x0074,// #LATIN SMALL LETTER T
+    0x0075,// #LATIN SMALL LETTER U
+    0x0076,// #LATIN SMALL LETTER V
+    0x0077,// #LATIN SMALL LETTER W
+    0x0078,// #LATIN SMALL LETTER X
+    0x0079,// #LATIN SMALL LETTER Y
+    0x007a,// #LATIN SMALL LETTER Z
+    0x007b,// #LEFT CURLY BRACKET
+    0x007c,// #VERTICAL LINE
+    0x007d,// #RIGHT CURLY BRACKET
+    0x007e,// #TILDE
+    0x007f,// #DELETE
+    0x00c7,// #LATIN CAPITAL LETTER C WITH CEDILLA
+    0x00fc,// #LATIN SMALL LETTER U WITH DIAERESIS
+    0x00e9,// #LATIN SMALL LETTER E WITH ACUTE
+    0x00e2,// #LATIN SMALL LETTER A WITH CIRCUMFLEX
+    0x00e4,// #LATIN SMALL LETTER A WITH DIAERESIS
+    0x00e0,// #LATIN SMALL LETTER A WITH GRAVE
+    0x00e5,// #LATIN SMALL LETTER A WITH RING ABOVE
+    0x00e7,// #LATIN SMALL LETTER C WITH CEDILLA
+    0x00ea,// #LATIN SMALL LETTER E WITH CIRCUMFLEX
+    0x00eb,// #LATIN SMALL LETTER E WITH DIAERESIS
+    0x00e8,// #LATIN SMALL LETTER E WITH GRAVE
+    0x00ef,// #LATIN SMALL LETTER I WITH DIAERESIS
+    0x00ee,// #LATIN SMALL LETTER I WITH CIRCUMFLEX
+    0x00ec,// #LATIN SMALL LETTER I WITH GRAVE
+    0x00c4,// #LATIN CAPITAL LETTER A WITH DIAERESIS
+    0x00c5,// #LATIN CAPITAL LETTER A WITH RING ABOVE
+    0x00c9,// #LATIN CAPITAL LETTER E WITH ACUTE
+    0x00e6,// #LATIN SMALL LIGATURE AE
+    0x00c6,// #LATIN CAPITAL LIGATURE AE
+    0x00f4,// #LATIN SMALL LETTER O WITH CIRCUMFLEX
+    0x00f6,// #LATIN SMALL LETTER O WITH DIAERESIS
+    0x00f2,// #LATIN SMALL LETTER O WITH GRAVE
+    0x00fb,// #LATIN SMALL LETTER U WITH CIRCUMFLEX
+    0x00f9,// #LATIN SMALL LETTER U WITH GRAVE
+    0x00ff,// #LATIN SMALL LETTER Y WITH DIAERESIS
+    0x00d6,// #LATIN CAPITAL LETTER O WITH DIAERESIS
+    0x00dc,// #LATIN CAPITAL LETTER U WITH DIAERESIS
+    0x00a2,// #CENT SIGN
+    0x00a3,// #POUND SIGN
+    0x00a5,// #YEN SIGN
+    0x20a7,// #PESETA SIGN
+    0x0192,// #LATIN SMALL LETTER F WITH HOOK
+    0x00e1,// #LATIN SMALL LETTER A WITH ACUTE
+    0x00ed,// #LATIN SMALL LETTER I WITH ACUTE
+    0x00f3,// #LATIN SMALL LETTER O WITH ACUTE
+    0x00fa,// #LATIN SMALL LETTER U WITH ACUTE
+    0x00f1,// #LATIN SMALL LETTER N WITH TILDE
+    0x00d1,// #LATIN CAPITAL LETTER N WITH TILDE
+    0x00aa,// #FEMININE ORDINAL INDICATOR
+    0x00ba,// #MASCULINE ORDINAL INDICATOR
+    0x00bf,// #INVERTED QUESTION MARK
+    0x2310,// #REVERSED NOT SIGN
+    0x00ac,// #NOT SIGN
+    0x00bd,// #VULGAR FRACTION ONE HALF
+    0x00bc,// #VULGAR FRACTION ONE QUARTER
+    0x00a1,// #INVERTED EXCLAMATION MARK
+    0x00ab,// #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+    0x00bb,// #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+    0x2591,// #LIGHT SHADE
+    0x2592,// #MEDIUM SHADE
+    0x2593,// #DARK SHADE
+    0x2502,// #BOX DRAWINGS LIGHT VERTICAL
+    0x2524,// #BOX DRAWINGS LIGHT VERTICAL AND LEFT
+    0x2561,// #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+    0x2562,// #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+    0x2556,// #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+    0x2555,// #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+    0x2563,// #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+    0x2551,// #BOX DRAWINGS DOUBLE VERTICAL
+    0x2557,// #BOX DRAWINGS DOUBLE DOWN AND LEFT
+    0x255d,// #BOX DRAWINGS DOUBLE UP AND LEFT
+    0x255c,// #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+    0x255b,// #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+    0x2510,// #BOX DRAWINGS LIGHT DOWN AND LEFT
+    0x2514,// #BOX DRAWINGS LIGHT UP AND RIGHT
+    0x2534,// #BOX DRAWINGS LIGHT UP AND HORIZONTAL
+    0x252c,// #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+    0x251c,// #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+    0x2500,// #BOX DRAWINGS LIGHT HORIZONTAL
+    0x253c,// #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+    0x255e,// #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+    0x255f,// #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+    0x255a,// #BOX DRAWINGS DOUBLE UP AND RIGHT
+    0x2554,// #BOX DRAWINGS DOUBLE DOWN AND RIGHT
+    0x2569,// #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+    0x2566,// #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+    0x2560,// #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+    0x2550,// #BOX DRAWINGS DOUBLE HORIZONTAL
+    0x256c,// #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+    0x2567,// #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+    0x2568,// #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+    0x2564,// #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+    0x2565,// #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+    0x2559,// #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+    0x2558,// #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+    0x2552,// #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+    0x2553,// #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+    0x256b,// #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+    0x256a,// #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+    0x2518,// #BOX DRAWINGS LIGHT UP AND LEFT
+    0x250c,// #BOX DRAWINGS LIGHT DOWN AND RIGHT
+    0x2588,// #FULL BLOCK
+    0x2584,// #LOWER HALF BLOCK
+    0x258c,// #LEFT HALF BLOCK
+    0x2590,// #RIGHT HALF BLOCK
+    0x2580,// #UPPER HALF BLOCK
+    0x03b1,// #GREEK SMALL LETTER ALPHA
+    0x00df,// #LATIN SMALL LETTER SHARP S
+    0x0393,// #GREEK CAPITAL LETTER GAMMA
+    0x03c0,// #GREEK SMALL LETTER PI
+    0x03a3,// #GREEK CAPITAL LETTER SIGMA
+    0x03c3,// #GREEK SMALL LETTER SIGMA
+    0x00b5,// #MICRO SIGN
+    0x03c4,// #GREEK SMALL LETTER TAU
+    0x03a6,// #GREEK CAPITAL LETTER PHI
+    0x0398,// #GREEK CAPITAL LETTER THETA
+    0x03a9,// #GREEK CAPITAL LETTER OMEGA
+    0x03b4,// #GREEK SMALL LETTER DELTA
+    0x221e,// #INFINITY
+    0x03c6,// #GREEK SMALL LETTER PHI
+    0x03b5,// #GREEK SMALL LETTER EPSILON
+    0x2229,// #INTERSECTION
+    0x2261,// #IDENTICAL TO
+    0x00b1,// #PLUS-MINUS SIGN
+    0x2265,// #GREATER-THAN OR EQUAL TO
+    0x2264,// #LESS-THAN OR EQUAL TO
+    0x2320,// #TOP HALF INTEGRAL
+    0x2321,// #BOTTOM HALF INTEGRAL
+    0x00f7,// #DIVISION SIGN
+    0x2248,// #ALMOST EQUAL TO
+    0x00b0,// #DEGREE SIGN
+    0x2219,// #BULLET OPERATOR
+    0x00b7,// #MIDDLE DOT
+    0x221a,// #SQUARE ROOT
+    0x207f,// #SUPERSCRIPT LATIN SMALL LETTER N
+    0x00b2,// #SUPERSCRIPT TWO
+    0x25a0,// #BLACK SQUARE
+    0x00a0,// #NO-BREAK SPACE
+  };
+
+  public char map_cp850_unicode(char x) {
+    if (x>=0x100)
+      return x;
+    return unimap[x];
+  }
+
+  private void _SetCursor(int row,int col) {
+    int maxr = getRows();
+    int tm = getTopMargin();
+
+    R = (row<0)?0:row;
+    C = (col<0)?0:col;
+
+    if (!moveoutsidemargins) {
+      R	+= getTopMargin();
+      maxr	 = getBottomMargin();
+    }
+    if (R>maxr) R = maxr;
+  }
+
+  private void putChar(char c, boolean doshowcursor) {
+    Dimension size;
+    int  rows = getRows(); //statusline
+    int  columns = getColumns();
+    int  tm = getTopMargin();
+    int  bm = getBottomMargin();
+    String  tosend;
+    byte  msg[];
+
+    if (debug>4) System.out.println("putChar("+c+" ["+((int)c)+"]) at R="+R+" , C="+C+", columns="+columns+", rows="+rows);
+    markLine(R,1);
+    if (c>255) {
+      if (debug>0)
+        System.out.println("char > 255:"+((int)c));
+      return;
+    }
+    switch (term_state) {
+    case TSTATE_DATA:
+      /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
+       * probably... but some BBS do anyway...
+       */
+      if (!useibmcharset) {
+        boolean doneflag = true;
+        switch (c) {
+        case OSC:
+          osc="";
+          term_state = TSTATE_OSC;
+          break;
+        case RI:
+          if (R>tm)
+            R--;
+          else
+            insertLine(R,1,SCROLL_DOWN);
+          if (debug>1)
+            System.out.println("RI");
+          break;
+        case IND:
+          if (R == tm - 1 || R == bm || R == rows - 1) //  Ray: not bottom margin - 1
+            insertLine(R,1,SCROLL_UP);
+          else
+            R++;
+          if (debug>1)
+            System.out.println("IND (at "+R+" )");
+          break;
+        case NEL:
+          if (R == tm - 1 || R == bm || R == rows - 1) //  Ray: not bottom margin - 1
+            insertLine(R,1,SCROLL_UP);
+          else
+            R++;
+          C=0;
+          if (debug>1)
+            System.out.println("NEL (at "+R+" )");
+          break;
+        case HTS:
+          Tabs[C] = 1;
+          if (debug>1)
+            System.out.println("HTS");
+          break;
+        case DCS:
+          dcs="";
+          term_state = TSTATE_DCS;
+          break;
+        default:
+          doneflag = false;
+          break;
+        }
+        if (doneflag) break;
+      }
+      switch (c) {
+      case CSI: // should be in the 8bit section, but some BBS use this
+        term_state = TSTATE_DCEQ;
+        break;
+      case ESC:
+        term_state = TSTATE_ESC;
+        lastwaslf=0;
+        break;
+      case '\b':
+        C--;
+        if (C<0)
+          C=0;
+        lastwaslf = 0;
+        break;
+      case '\t':
+        if (insertmode == 1) {
+          int  nr,newc;
+
+          newc = C;
+          do {
+            insertChar(C,R,' ',attributes);
+            newc++;
+          } while (newc<columns && Tabs[newc]==0);
+        } else {
+          do {
+            putChar(C++,R,' ',attributes);
+          } while (C<columns && (Tabs[C]==0));
+        }
+        lastwaslf = 0;
+        break;
+      case '\r':
+        C=0;
+        break;
+      case '\n':
+	if (debug>3)
+	  System.out.println("R= "+R+", bm "+bm+", tm="+tm+", rows="+rows);
+        if (!vms)
+	  {
+            if (lastwaslf!=0 && lastwaslf!=c)   //  Ray: I do not understand this logic.
+              break;
+            lastwaslf=c;
+            /*C = 0;*/
+	  }
+	// note: we do not scroll at the topmargin! only at the bottommargin
+	// of the scrollregion and at the bottom.
+	if ( R == bm || R >= rows - 1)
+	  insertLine(R,1);
+	else
+	  R++;
+        break;
+      case '\016':
+        /* ^N, Shift out - Put G1 into GL */
+        gl = 1;
+        break;
+      case '\017':
+        /* ^O, Shift in - Put G0 into GL */
+        gl = 0;
+        break;
+      default:
+        lastwaslf=0;
+        if (c<32) {
+          if (c!=0)
+            if (debug>0)
+              System.out.println("TSTATE_DATA char: "+((int)c));
+          break;
+        }
+        if(C >= columns) {
+          if(R < rows - 1)
+            R++;
+          else
+            insertLine(R,SCROLL_UP);
+          C = 0;
+        }
+
+        // Mapping if DEC Special is chosen charset
+        if ( gx[gl] == '0' ) {
+          if ( c >= '\u005f' && c <= '\u007e' ) {
+	    if (debug>3)
+	      System.out.print("Mapping "+c+" (index "+((short)c-0x5f)+" to ");
+	    c = DECSPECIAL[(short)c - 0x5f];
+	    if (debug>3)
+	      System.out.println(c+" ("+(int)c+")");
+          }
+        }
+	/*
+	  if ( gx[gr] == '0' ) {
+          if ( c >= '\u00bf' && c <= '\u00fe' ) {
+          if (debug>2)
+	  System.out.print("Mapping "+c);
+	  c = DECSPECIAL[(short)c - 0xbf];
+	  if (debug>2)
+	  System.out.println("to "+c);
+          }
+	  }
+	*/
+        if (useibmcharset)
+          c = map_cp850_unicode(c);
+
+	/*if(true || (statusmode == 0)) { */
+	if (debug>4) System.out.println("output "+c+" at "+C+","+R);
+	if (insertmode==1) {
+	  insertChar(C, R, c, attributes);
+	} else {
+	  putChar(C, R, c, attributes);
+	}
+	/*
+	  } else {
+	  if (insertmode==1) {
+	  insertChar(C, rows, c, attributes);
+	  } else {
+	  putChar(C, rows, c, attributes);
+	  }
+	  }
+	*/
+        C++;
+        break;
+      } /* switch(c) */
+      break;
+    case TSTATE_OSC:
+      if ((c<0x20) && (c!=ESC)) {// NP - No printing character
+        handle_osc(osc);
+        term_state = TSTATE_DATA;
+        break;
+      }
+      //but check for vt102 ESC \
+      if (c=='\\' && osc.charAt(osc.length()-1)==ESC) {
+				  handle_osc(osc);
+				  term_state = TSTATE_DATA;
+				  break;
+      }
+    osc = osc + c;
+    break;
+    case TSTATE_ESC:
+      switch (c) {
+      case '#':
+        term_state = TSTATE_ESCSQUARE;
+        break;
+      case 'c':
+        /* Hard terminal reset */
+        /*FIXME:*/
+        term_state = TSTATE_DATA;
+        break;
+      case '[':
+        term_state = TSTATE_CSI;
+        DCEvar    = 0;
+        DCEvars[0]  = 0;
+        DCEvars[1]  = 0;
+        DCEvars[2]  = 0;
+        DCEvars[3]  = 0;
+        break;
+      case ']':
+        osc="";
+        term_state = TSTATE_OSC;
+        break;
+      case 'P':
+        dcs="";
+        term_state = TSTATE_DCS;
+        break;
+      case 'E':
+        if (R == tm - 1 || R == bm || R == rows - 1) //  Ray: not bottom margin - 1
+          insertLine(R,1,SCROLL_UP);
+        else
+          R++;
+        C=0;
+        if (debug>1)
+          System.out.println("ESC E (at "+R+")");
+        term_state = TSTATE_DATA;
+        break;
+      case 'D':
+        if (R == tm - 1 || R == bm || R == rows - 1)
+          insertLine(R,1,SCROLL_UP);
+        else
+          R++;
+        if (debug>1)
+          System.out.println("ESC D (at "+R+" )");
+        term_state = TSTATE_DATA;
+        break;
+      case 'M': // IL
+        if ((R>=tm) && (R<=bm)) // in scrolregion
+          insertLine(R,1,SCROLL_DOWN);
+	/* else do nothing ; */
+        if (debug>1)
+          System.out.println("ESC M ");
+        term_state = TSTATE_DATA;
+        break;
+      case 'H':
+        if (debug>1)
+          System.out.println("ESC H at "+C);
+        /* right border probably ...*/
+        if (C>=columns)
+          C=columns-1;
+        Tabs[C] = 1;
+        term_state = TSTATE_DATA;
+        break;
+      case '=':
+        /*application keypad*/
+        if (debug>0)
+          System.out.println("ESC =");
+        term_state = TSTATE_DATA;
+        break;
+      case '>':
+        /*normal keypad*/
+        if (debug>0)
+          System.out.println("ESC >");
+        term_state = TSTATE_DATA;
+        break;
+      case '7':
+        /*save cursor */
+        Sc = C;
+        Sr = R;
+        Sa = attributes;
+        if (debug>1)
+          System.out.println("ESC 7");
+        term_state = TSTATE_DATA;
+        break;
+      case '8':
+        /*restore cursor */
+        C = Sc;
+        R = Sr;
+        attributes = Sa;
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC 7");
+        break;
+      case '(':
+        /* Designate G0 Character set (ISO 2022) */
+        term_state = TSTATE_SETG0;
+        break;
+      case ')':
+        /* Designate G0 character set (ISO 2022) */
+        term_state = TSTATE_SETG1;
+        break;
+      case '*':
+        /* Designate G1 Character set (ISO 2022) */
+        term_state = TSTATE_SETG2;
+        break;
+      case '+':
+        /* Designate G1 Character set (ISO 2022) */
+        term_state = TSTATE_SETG3;
+        break;
+      case '~':
+        /* Locking Shift 1, right */
+        term_state = TSTATE_DATA;
+        gr = 1;
+        break;
+      case 'n':
+        /* Locking Shift 2 */
+        term_state = TSTATE_DATA;
+        gl = 2;
+        break;
+      case '}':
+        /* Locking Shift 2, right */
+        term_state = TSTATE_DATA;
+        gr = 2;
+        break;
+      case 'o':
+        /* Locking Shift 3 */
+        term_state = TSTATE_DATA;
+        gl = 3;
+        break;
+      case '|':
+        /* Locking Shift 3, right */
+        term_state = TSTATE_DATA;
+        gr = 3;
+        break;
+      default:
+        System.out.println("ESC unknown letter: ("+((int)c)+")");
+        term_state = TSTATE_DATA;
+        break;
+      }
+      break;
+    case TSTATE_SETG0:
+      if(c!='0' && c!='A' && c!='B')
+        System.out.println("ESC ( : G0 char set?  ("+((int)c)+")");
+      else {
+        if (debug>2) System.out.println("ESC ( : G0 char set  ("+c+" "+((int)c)+")");
+        gx[0] = c;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_SETG1:
+      if(c!='0' && c!='A' && c!='B')
+        System.out.println("ESC ) :G1 char set?  ("+((int)c)+")");
+      else {
+        if (debug>2) System.out.println("ESC ) :G1 char set  ("+c+" "+((int)c)+")");
+        gx[1] = c;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_SETG2:
+      if(c!='0' && c!='A' && c!='B')
+        System.out.println("ESC*:G2 char set?  ("+((int)c)+")");
+      else {
+        if (debug>2) System.out.println("ESC*:G2 char set  ("+c+" "+((int)c)+")");
+	gx[2] = c;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_SETG3:
+      if(c!='0' && c!='A' && c!='B')
+        System.out.println("ESC+:G3 char set?  ("+((int)c)+")");
+      else {
+        if (debug>2) System.out.println("ESC+:G3 char set  ("+c+" "+((int)c)+")");
+        gx[3] = c;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_ESCSQUARE:
+      switch (c) {
+      case '8':
+        for (int i=0;i<columns;i++)
+          for (int j=0;j<rows;j++)
+            putChar(i,j,'E',0);
+        break;
+      default:
+        System.out.println("ESC # "+c+" not supported.");
+        break;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_DCS:
+      if (c=='\\' && dcs.charAt(dcs.length()-1)==ESC) {
+        handle_dcs(dcs);
+        term_state = TSTATE_DATA;
+        break;
+      }
+      dcs = dcs + c;
+      break;
+    case TSTATE_DCEQ:
+      switch (c) {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        DCEvars[DCEvar]=DCEvars[DCEvar]*10+((int)c)-48;
+        break;
+      case 'r': // XTERM_RESTORE
+        if (true || debug>1)
+          System.out.println("ESC [ ? "+DCEvars[0]+" r");
+        /* DEC Mode reset */
+        switch (DCEvars[0]){
+        case 3: /* 80 columns*/
+          size = getSize();
+          setScreenSize(80,rows);
+          break;
+        case 4: /* scrolling mode, smooth */
+          break;
+        case 5: /* light background */
+          break;
+        case 6: /* move inside margins ? */
+          moveoutsidemargins = true;
+          break;
+        case 12:/* local echo off */
+          break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      case 'h': // DECSET
+        if (debug>0)
+          System.out.println("ESC [ ? "+DCEvars[0]+" h");
+        /* DEC Mode set */
+        switch (DCEvars[0]){
+        case 1:  /* Application cursor keys */
+          KeyUp  = "\u001bOA";
+          KeyDown  = "\u001bOB";
+          KeyRight= "\u001bOC";
+          KeyLeft  = "\u001bOD";
+          break;
+        case 3: /* 132 columns*/
+          size = getSize();
+          setScreenSize(132,rows);
+          break;
+        case 4: /* scrolling mode, smooth */
+          break;
+        case 5: /* light background */
+          break;
+        case 6: /* move inside margins ? */
+          moveoutsidemargins = false;
+          break;
+        case 12:/* local echo off */
+          break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      case 'l':	//DECRST
+        /* DEC Mode reset */
+        if (debug>0)
+          System.out.println("ESC [ ? "+DCEvars[0]+" l");
+        switch (DCEvars[0]){
+        case 1:  /* Application cursor keys */
+          KeyUp  = "\u001b[A";
+          KeyDown  = "\u001b[B";
+          KeyRight= "\u001b[C";
+          KeyLeft  = "\u001b[D";
+          break;
+        case 3: /* 80 columns*/
+          size = getSize();
+          setScreenSize(80,rows);
+          break;
+        case 4: /* scrolling mode, jump */
+          break;
+        case 5: /* dark background */
+          break;
+        case 6: /* move outside margins ? */
+          moveoutsidemargins = true;
+          break;
+        case 12:/* local echo on */
+          break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      case ';':
+        DCEvar++;
+        DCEvars[DCEvar] = 0;
+        break;
+      case 'n':
+        if (debug>0)
+          System.out.println("ESC [ ? "+DCEvars[0]+" n");
+        switch (DCEvars[0]) {
+        case 15:
+          /* printer? no printer. */
+          write(((char)ESC)+"[?13n");
+          System.out.println("ESC[5n");
+          break;
+        default:break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      default:
+        if (debug>0)
+          System.out.println("ESC [ ? "+DCEvars[0]+" "+c);
+        term_state = TSTATE_DATA;
+        break;
+      }
+      break;
+    case TSTATE_CSI_DOLLAR:
+      switch (c) {
+      case '}':
+	System.out.println("Active Status Display now "+DCEvars[0]);
+	statusmode = DCEvars[0];
+	break;
+	/* bad documentation?
+	   case '-':
+	   System.out.println("Set Status Display now "+DCEvars[0]);
+	   break;
+	*/
+      case '~':
+	System.out.println("Status Line mode now "+DCEvars[0]);
+	break;
+      default:
+	System.out.println("UNKNOWN Status Display code "+c+", with Pn="+DCEvars[0]);
+	break;
+      }
+      term_state = TSTATE_DATA;
+      break;
+    case TSTATE_CSI:
+      switch (c) {
+      case '$':
+	term_state=TSTATE_CSI_DOLLAR;
+	break;
+      case '?':
+        DCEvar=0;
+        DCEvars[0]=0;
+        term_state=TSTATE_DCEQ;
+        break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        DCEvars[DCEvar]=DCEvars[DCEvar]*10+((int)c)-48;
+        break;
+      case ';':
+        DCEvar++;
+        DCEvars[DCEvar] = 0;
+        break;
+      case 'c':/* send primary device attributes */
+        /* send (ESC[?61c) */
+        write(((char)ESC)+"[?1;2c");
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" c");
+        break;
+      case 'q':
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" q");
+        term_state = TSTATE_DATA;
+        break;
+      case 'g':
+        /* used for tabsets */
+        switch (DCEvars[0]){
+        case 3:/* clear them */
+          int nw = getColumns();
+          Tabs = new byte[nw];
+          break;
+        case 0:
+          Tabs[C] = 0;
+          break;
+        }
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" g");
+        term_state = TSTATE_DATA;
+        break;
+      case 'h':
+        switch (DCEvars[0]) {
+        case 4:
+          insertmode = 1;
+          break;
+        case 20:
+          sendcrlf = true;
+          break;
+        default:
+          System.out.println("unsupported: ESC [ "+DCEvars[0]+" h");
+          break;
+        }
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" h");
+        break;
+      case 'l':
+        switch (DCEvars[0]) {
+        case 4:
+          insertmode = 0;
+          break;
+        case 20:
+          sendcrlf = false;
+          break;
+        }
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" l");
+        break;
+      case 'A': // CUU
+	{
+	  int limit;
+	  /* FIXME: xterm only cares about 0 and topmargin */
+	  if (R > bm)
+            limit = bm+1;
+	  else if (R >= tm) {
+            limit = tm;
+	  } else
+            limit = 0;
+	  if (DCEvars[0]==0)
+	    R--;
+	  else
+	    R-=DCEvars[0];
+	  if (R < limit)
+            R = limit;
+	  term_state = TSTATE_DATA;
+	  if (debug>1)
+	    System.out.println("ESC [ "+DCEvars[0]+" A");
+	  break;
+	}
+      case 'B':	// CUD
+        /* cursor down n (1) times */
+	{
+	  int limit;
+	  if (R < tm)
+            limit = tm-1;
+	  else if (R <= bm) {
+            limit = bm;
+	  } else
+            limit = rows - 1;
+	  if (DCEvars[0]==0)
+	    R++;
+	  else
+	    R+=DCEvars[0];
+	  if (R > limit)
+            R = limit;
+	  else {
+            if (debug>2) System.out.println("Not limited.");
+	  }
+	  if (debug>2) System.out.println("to: " + R);
+	  term_state = TSTATE_DATA;
+	  if (debug>1)
+	    System.out.println("ESC [ "+DCEvars[0]+" B (at C="+C+")");
+	  break;
+	}
+      case 'C':
+        if (DCEvars[0]==0)
+          C++;
+        else
+          C+=DCEvars[0];
+        if (C>columns-1)
+          C=columns-1;
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" C");
+        break;
+      case 'd': // CVA
+	R = DCEvars[0];
+        System.out.println("ESC [ "+DCEvars[0]+" d");
+        term_state = TSTATE_DATA;
+	break;
+      case 'D':
+        if (DCEvars[0]==0)
+          C--;
+        else
+          C-=DCEvars[0];
+        if (C<0) C=0;
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" D");
+        break;
+      case 'r': // DECSTBM
+        if (DCEvar>0)   //  Ray:  Any argument is optional
+	  {
+	    R = DCEvars[1]-1;
+	    if (R < 0)
+	      R = rows-1;
+	    else if (R >= rows) {
+	      R = rows - 1;
+	    }
+	  } else
+	    R = rows - 1;
+        setBottomMargin(DCEvars[1]-1);
+        if (R >= DCEvars[0])
+	  {
+	    R = DCEvars[0]-1;
+	    if (R < 0)
+	      R = 0;
+	  }
+        setTopMargin(DCEvars[0]-1);
+	_SetCursor(0,0);
+        if (debug>1)
+          System.out.println("ESC ["+DCEvars[0]+" ; "+DCEvars[1]+" r");
+        term_state = TSTATE_DATA;
+        break;
+      case 'G':  /* CUP  / cursor absolute column */
+	C = DCEvars[0];
+	System.out.println("ESC [ "+DCEvars[0]+" G");
+        term_state = TSTATE_DATA;
+	break;
+      case 'H':  /* CUP  / cursor position */
+        /* gets 2 arguments */
+	_SetCursor(DCEvars[0]-1,DCEvars[1]-1);
+        term_state = TSTATE_DATA;
+        if (debug>2) {
+          System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" H, moveoutsidemargins "+moveoutsidemargins);
+          System.out.println("	-> R now "+R+", C now "+C);
+	}
+        break;
+      case 'f':  /* move cursor 2 */
+        /* gets 2 arguments */
+        R = DCEvars[0]-1;
+        C = DCEvars[1]-1;
+        if (C<0) C=0;
+        if (R<0) R=0;
+        term_state = TSTATE_DATA;
+        if (debug>2)
+          System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" f");
+        break;
+      case 'L':
+        /* insert n lines */
+        if (DCEvars[0]==0)
+          insertLine(R,SCROLL_DOWN);
+        else
+          insertLine(R,DCEvars[0],SCROLL_DOWN);
+        term_state = TSTATE_DATA;
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" L (at R "+R+")");
+        break;
+      case 'M':
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+"M at R="+R);
+        if (DCEvars[0]==0)
+          deleteLine(R);
+        else
+          for (int i=0;i<DCEvars[0];i++)
+            deleteLine(R);
+        term_state = TSTATE_DATA;
+        break;
+      case 'K':
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" K");
+        /* clear in line */
+        switch (DCEvars[0]) {
+        case 0:/*clear to right*/
+          if (C<columns-1)
+            deleteArea(C,R,columns-C,1);
+          break;
+        case 1:/*clear to the left*/
+          if (C>0)
+            deleteArea(0,R,C,1);    // Ray: Should at least include character before this one, not C-1
+          break;
+        case 2:/*clear whole line */
+          deleteArea(0,R,columns,1);
+          break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      case 'J':
+        /* clear below current line */
+        switch (DCEvars[0]) {
+        case 0:
+          if (R<rows-1)
+            deleteArea(0,R + 1,columns,rows-R-1);
+          if (C<columns-1)
+            deleteArea(C,R,columns-C,1);
+          break;
+        case 1:
+          if (R>0)
+            deleteArea(0,0,columns,R-1);
+          if (C>0)
+            deleteArea(0,R,C,1);    // Ray: Should at least include character before this one, not C-1
+          break;
+        case 2:
+          deleteArea(0,0,columns,rows);
+          break;
+        }
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" J");
+        term_state = TSTATE_DATA;
+        break;
+      case '@':
+	if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" @");
+	for (int i=0;i<DCEvars[0];i++)
+	  insertChar(C,R,' ',attributes);
+	term_state = TSTATE_DATA;
+	break;
+      case 'P':
+        if (debug>1)
+          System.out.println("ESC [ "+DCEvars[0]+" P, C="+C+",R="+R);
+	if (DCEvars[0]==0) DCEvars[0]=1;
+	for (int i=0;i<DCEvars[0];i++)
+          deleteChar(C,R);
+        term_state = TSTATE_DATA;
+        break;
+      case 'n':
+        switch (DCEvars[0]){
+        case 5: /* malfunction? No malfunction. */
+          write(((char)ESC)+"[0n");
+          if(debug > 1)
+            System.out.println("ESC[5n");
+          break;
+        case 6:
+          write(((char)ESC)+"["+R+";"+C+"R");
+          if(debug > 1)
+            System.out.println("ESC[6n");
+          break;
+        default:
+          if (debug>0)
+            System.out.println("ESC [ "+DCEvars[0]+" n??");
+          break;
+        }
+        term_state = TSTATE_DATA;
+        break;
+      case 'm':  /* attributes as color, bold , blink,*/
+        if (debug>3)
+          System.out.print("ESC [ ");
+        if (DCEvar == 0 && DCEvars[0] == 0)
+          attributes = 0;
+        for (i=0;i<=DCEvar;i++) {
+          switch (DCEvars[i]) {
+          case 0:
+            if (DCEvar>0)
+              attributes =0;
+            break;
+          case 4:
+            attributes |= UNDERLINE;
+            break;
+          case 1:
+            attributes |= BOLD;
+            break;
+          case 7:
+            attributes |= INVERT;
+            break;
+          case 5: /* blink on */
+            break;
+          case 25: /* blinking off */
+            break;
+          case 27:
+            attributes &= ~INVERT;
+            break;
+          case 24:
+            attributes &= ~UNDERLINE;
+            break;
+          case 22:
+            attributes &= ~BOLD;
+            break;
+          case 30:
+          case 31:
+          case 32:
+          case 33:
+          case 34:
+          case 35:
+          case 36:
+          case 37:
+            attributes &= ~(0xf<<3);
+            attributes |= ((DCEvars[i]-30)+1)<<3;
+            break;
+          case 39:
+            attributes &= ~(0xf<<3);
+            break;
+          case 40:
+          case 41:
+          case 42:
+          case 43:
+          case 44:
+          case 45:
+          case 46:
+          case 47:
+            attributes &= ~(0xf<<7);
+            attributes |= ((DCEvars[i]-40)+1)<<7;
+            break;
+          case 49:
+            attributes &= ~(0xf<<7);
+            break;
+
+          default:
+            System.out.println("ESC [ "+DCEvars[i]+" m unknown...");
+            break;
+          }
+          if (debug>3)
+            System.out.print(""+DCEvars[i]+";");
+        }
+        if (debug>3)
+          System.out.print(" (attributes = "+attributes+")m \n");
+        term_state = TSTATE_DATA;
+        break;
+      default:
+        if (debug>0)
+          System.out.println("ESC [ unknown letter:"+c+" ("+((int)c)+")");
+        term_state = TSTATE_DATA;
+        break;
+      }
+      break;
+    default:
+      term_state = TSTATE_DATA;
+      break;
+    }
+  if (C > columns) C = columns;
+  if (R > rows)  R = rows;
+  if (C < 0)  C = 0;
+  if (R < 0)  R = 0;
+  if (doshowcursor)
+    setCursorPosition(C, R);
+  markLine(R,1);
+  }
+}