run: fleet.jar
java -cp lib/edu.berkeley.sbp.jar:fleet.jar edu.berkeley.fleet.FleetParser < test.fleet
+applet: fleet.jar
+ java -cp lib/edu.berkeley.sbp.jar:fleet.jar edu.berkeley.fleet.FleetApplet < test.fleet
+
fleet.jar: $(shell find src -name \*.java) fleet.g
mkdir -p bin
cp fleet.g bin
+ cp test.fleet bin
javac -cp lib/edu.berkeley.sbp.jar -d bin $(shell find src -name \*.java)
cd bin; jar cvf ../$@ .
--- /dev/null
+package de.mud.telnet;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * CharDisplayTest
+ * --
+ * $Id: CharDisplayTest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * $timestamp: Mon Feb 17 20:11:20 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.applet.Applet;
+import java.awt.Button;
+import java.awt.Panel;
+import java.awt.Event;
+import java.awt.FlowLayout;
+import java.awt.BorderLayout;
+import java.awt.Choice;
+import java.awt.TextField;
+import java.awt.Font;
+
+import de.mud.telnet.display.CharDisplay;
+
+/**
+ * CharDisplayTest -- a test applet to show the display/CharDisplay features
+ * --
+ * @version $Id: CharDisplayTest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class CharDisplayTest extends Applet
+{
+ CharDisplay display = new CharDisplay(80, 24, "Courier", 14);
+
+ Panel buttons = new Panel();
+ Button info = new Button("Information");
+ Button chars = new Button("Character Table");
+ Button attr = new Button("Attributes");
+ Choice fonts = new Choice();
+ TextField from = new TextField("0", 4);
+
+ public void init()
+ {
+ setLayout(new BorderLayout());
+ fonts.addItem("Helvetica");
+ fonts.addItem("TimesRoman");
+ fonts.addItem("Courier");
+ fonts.addItem("Dialog");
+ fonts.addItem("DialogInput");
+ fonts.addItem("ZapfDingBats");
+ fonts.addItem("default");
+ buttons.add(info);
+ buttons.add(chars);
+ buttons.add(attr);
+ buttons.add(fonts);
+ buttons.add(from);
+ add("North", buttons);
+ display.setResizeStrategy(CharDisplay.RESIZE_FONT);
+ add("Center", display);
+ Info();
+ }
+
+ public boolean handleEvent(Event evt)
+ {
+ if(evt.target == info) { Info(); return true; }
+ if(evt.target == chars) { CharacterTable(); return true; }
+ if(evt.target == attr) { Attributes(); return true; }
+ if(evt.id == Event.ACTION_EVENT &&
+ (evt.target == fonts || evt.target == from))
+ {
+ remove(display);
+ display = new CharDisplay(80, 24, fonts.getSelectedItem(), 12);
+ add("Center", display);
+ CharacterTable();
+ layout();
+ return true;
+ }
+ return false;
+ }
+
+ private void Clear()
+ {
+ display.deleteArea(0, 0, 80, 24);
+ }
+
+ private void Info()
+ {
+ Clear();
+ display.putString(4, 1, "CharDisplay.class Information", CharDisplay.INVERT);
+ display.putString(4, 3, "Version: "+display.version, CharDisplay.BOLD);
+ display.putString(4, 5, "This class implements several hardware features needed to implement");
+ display.putString(4, 6, "a video terminal.");
+ display.putString(4, 7, "This includes simple operations, such as putting and inserting single");
+ display.putString(4, 8, "characters or strings on the screen, character attributes and colors.");
+ display.putString(4, 9, "Special features like inserting lines, scrolling text up or down and");
+ display.putString(4,10, "defining scrollareas help implementing terminal emulations.");
+ display.redraw();
+ }
+
+ private void CharacterTable()
+ {
+ int ch = (new Integer(from.getText())).intValue();
+
+ Clear();
+ display.putString( 4, 1, "Character Table", CharDisplay.INVERT);
+ for(int c = 1; c < 80; c += 6)
+ for(int l = 3; l < 23; l++)
+ {
+ display.putString(c, l, ""+ch, CharDisplay.INVERT);
+ display.putChar(c+4, l, (char)ch++);
+ }
+ display.markLine(3, 20);
+ display.redraw();
+ }
+
+ private void Attributes()
+ {
+ int c = 4, l = 8;
+
+ Clear();
+ display.putString( 4, 1, "Character attributes", CharDisplay.INVERT);
+ display.putString( 4, 3, "Normal", CharDisplay.NORMAL);
+ display.putString(22, 3, "Bold", CharDisplay.BOLD);
+ display.putString(40, 3, "Underline", CharDisplay.UNDERLINE);
+ display.putString(58, 3, "Invert", CharDisplay.INVERT);
+
+ display.putString( 4, 5, "Black", 1 << 3 | 8 << 7);
+ display.putString(13, 5, "Red", 2 << 3);
+ display.putString(22, 5, "Green", 3 << 3);
+ display.putString(31, 5, "Yellow", 4 << 3);
+ display.putString(40, 5, "Blue", 5 << 3);
+ display.putString(49, 5, "Magenta", 6 << 3);
+ display.putString(58, 5, "Cyan", 7 << 3);
+ display.putString(67, 5, "LightGray", 8 << 3);
+
+ for(int bg = 1; bg <= 8; bg++)
+ {
+ for(int fg = 1; fg <= 8; fg++)
+ {
+ for(int a = 0; a <= 7; a++)
+ {
+ display.putChar(c++, l, '@', (fg << 3) | (bg << 7) | a);
+ display.redraw();
+ }
+ c++;
+ }
+ l += 2; c = 4;
+ }
+
+ }
+}
--- /dev/null
+package de.mud.telnet;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/* IOtest.java -- An example how to use the TelnetIO class
+ * --
+ * Author: Matthias L. Jugel
+ *
+ * Usage: compile with javac IOtest.java
+ * run program with java IOtest
+ *
+ * This is not an applet, but the idea might be used in one.
+ */
+
+import java.util.Vector;
+import java.io.*;
+import de.mud.telnet.socket.*;
+
+/**
+ * IOtest -- a test class for telnet i/o
+ * --
+ * @version $Id: IOtest.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * @author Matthias L. Jugel
+ */
+class IOtest {
+
+ // create a new telnet io instance
+ static TelnetIO tio = new TelnetIO();
+
+ // skip any received data until the prompt appears
+ private static void wait(String prompt)
+ {
+ String tmp = "";
+ do {
+ try { tmp = new String(tio.receive(), 0); }
+ catch(IOException e) { e.printStackTrace(); }
+ System.out.println(tmp);
+ } while(tmp.indexOf(prompt) == -1);
+ }
+
+ // send a string to the remote host, since TelnetIO needs a byte buffer
+ // we have to convert the string first
+ private static void send(String str)
+ {
+ byte[] buf = new byte[str.length()];
+ str.getBytes(0, str.length(), buf, 0);
+ try { tio.send(buf); } catch(IOException e) {}
+ }
+
+ // this function is called when running the class with java IOtest
+ // looks very much like a modem login script ;-)
+ public static void main(String args[])
+ {
+ try {
+ tio.connect("localhost");
+ wait("login:");
+ send("<YOUR LOGIN NAME>\r");
+ wait("Password:");
+ send("<YOUR PASSWORD>\r");
+ wait("<YOUR SHELL PROMPT>");
+ send("touch /tmp/THIS_WAS_AN_APPLET\r");
+ tio.disconnect();
+ } catch(IOException e) { e.printStackTrace(); }
+ }
+}
--- /dev/null
+package de.mud.telnet;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * appWrapper -- applet/application wrapper
+ * --
+ * $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $
+ * $timestamp: Thu Jul 24 13:08:23 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.applet.Applet;
+import java.applet.AppletStub;
+
+import java.awt.Frame;
+import java.awt.Event;
+import java.awt.Panel;
+import java.awt.Button;
+import java.awt.BorderLayout;
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.FontMetrics;
+
+/**
+ * The appWrapper is thought to make the applet itself independent from
+ * the original context. This is necessary to be able to detach the applet
+ * from the web browsers window without disconnecting it from events.
+ * Note: This applet should work with any applet without changes.
+ *
+ * <DL>
+ * <DT><B><PRE><PARAM NAME="applet" VALUE="<I>applet</I>"></PRE></B>
+ * <DD>Defines the applet to be loaded by the appWrapper. State the applet
+ * class name without ".class"!<P>
+ * <DT><B><PRE><PARAM NAME="startButton" VALUE="<I>text</I>"></PRE></B>
+ * <DD>If this parameter is set the applet is not loaded until the user presses
+ * the button. This decreases first time download delay. The <I>text</I>
+ * given as value to the parameter is shown on the button. While loading
+ * the applet the message "Loading ..." is shown on the button.<P>
+ * <DT><B><PRE><PARAM NAME="stopButton" VALUE="<I>text</I>"></PRE></B>
+ * <DD>This parameter defines the button text when the applet is loaded. When
+ * pressing the button while the applet is running this causes the applet
+ * window to be destroyed and the applet is stopped.<P>
+ * <DT><B><PRE><PARAM NAME="frameTitle" VALUE="<I>text</I>"></PRE></B>
+ * <DD>The <I>frameTitle</I> is the text that is shown in the title bar of the
+ * applet window.<P>
+ * </DL>
+ * @version $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $
+ * @author Matthias L. Jugel
+ */
+public class appWrapper extends Applet implements AppletStub, Runnable
+{
+ Thread loader = null;
+
+ String appletName = null;
+ Applet applet = null;
+
+ Button startButton = null;
+ String startLabel, stopLabel, frameTitle;
+
+ frame f;
+
+ /**
+ * Applet initialization. We load the class giving in parameter "applet"
+ * and set the stub corresponding to ours. Thus we are able to give
+ * it access to the parameters and any applet specific context.
+ */
+ public void init() {
+
+ // get the applet parameter
+ if((appletName = getParameter("applet")) == null) {
+ showStatus("appWrapper: missing applet parameter, nothing loaded");
+ System.err.println("appWrapper: missing applet parameter");
+ return;
+ }
+
+ setLayout(new BorderLayout());
+
+ // get the button and title parameters
+ if((startLabel = getParameter("startButton")) == null)
+ run();
+ else {
+ startButton = new Button(getParameter("startButton"));
+ add("Center", startButton);
+ if((stopLabel = getParameter("stopButton")) == null)
+ stopLabel = "STOP!";
+ if((frameTitle = getParameter("frameTitle")) == null)
+ frameTitle = "The Java Telnet Applet";
+ }
+
+ }
+
+ /**
+ * Load the applet finally. When using a button this creates a new frame
+ * to put the applet in.
+ */
+ public void run() {
+ if(applet == null) try {
+ applet = (Applet)Class.forName(getParameter("applet")).newInstance();
+ applet.setStub(this);
+ } catch(Exception e) {
+ System.err.println("appWrapper: could not load "+appletName);
+ e.printStackTrace();
+ return;
+ } else {
+ System.err.println("appWrapper: applet already loaded");
+ return;
+ }
+
+ if(startButton == null) {
+ add("Center", applet);
+ applet.init();
+ } else {
+ f = new frame(frameTitle);
+ f.setLayout(new BorderLayout());
+ f.add("Center", applet);
+ applet.init();
+ f.resize(applet.minimumSize());
+ f.pack();
+ f.show();
+ }
+ applet.start();
+
+ if(startButton != null)
+ startButton.setLabel(stopLabel);
+
+ // stop loader thread
+ while(loader != null) {
+ if(f == null || !f.isVisible()) {
+ startButton.setLabel(startLabel);
+ loader.stop();
+ loader = null;
+ }
+ try { loader.sleep(5000); }
+ catch(InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * This method is called when the applet want's to be resized.
+ * @param width the width of the applet
+ * @param height the height of the applet
+ */
+ public void appletResize(int width, int height) {
+ System.err.println("appWrapper: appletResize()");
+ if(applet != null) applet.resize(width, height);
+ }
+
+ /**
+ * Give information about the applet.
+ */
+ public String getAppletInfo()
+ {
+ String info = "appWrapper: $Id: appWrapper.java,v 1.9 1997/07/24 13:26:24 leo Exp $\n";
+ if(applet != null)
+ info += applet.getAppletInfo();
+ return info;
+ }
+
+ /**
+ * Give information about the appWrapper and the applet loaded.
+ */
+ public String[][] getParameterInfo()
+ {
+ String info[][];
+ String wrapper[][] = {
+ {"applet", "String", "appWrapper: Applet to load"},
+ };
+ if(applet != null) {
+ String tmp[][] = applet.getParameterInfo();
+ info = new String[tmp.length + 1][3];
+ System.arraycopy(tmp, 0, info, 1, tmp.length);
+ }
+ else info = new String[1][3];
+ System.arraycopy(wrapper, 0, info, 0, 1);
+
+ return info;
+ }
+
+ /**
+ * Write a message to the applet area.
+ */
+ public void paint(Graphics g)
+ {
+ String message;
+ if(applet != null)
+ message = "Click to reattach the Applet!";
+ else message = "The was no applet load (maybe an error)!";
+
+
+ int width = size().width / 2 -
+ (getFontMetrics(getFont())).stringWidth(message) / 2;
+ int height = size().height / 2;
+
+ g.setColor(Color.red);
+ g.drawString(message, width, height);
+ }
+
+ /**
+ * reshape the applet and ourself
+ */
+ public void reshape(int x, int y, int w, int h)
+ {
+ if(applet != null) applet.reshape(x, y, w, h);
+ super.reshape(x, y, w, h);
+ }
+
+ /**
+ * Handle button events. When pressed it either creates the new applet
+ * window or destoys it.
+ */
+ public boolean handleEvent(Event evt)
+ {
+ if(evt.target == startButton && evt.id == Event.ACTION_EVENT) {
+ if(applet == null) {
+ startButton.setLabel("Loading ...");
+ (loader = new Thread(this)).start();
+ } else {
+ if(applet.getParent() instanceof Frame) {
+ Frame frame = (Frame)applet.getParent();
+ frame.hide();
+ frame.dispose();
+ }
+ applet.stop();
+ applet.destroy();
+ applet = null;
+ startButton.setLabel(startLabel);
+ }
+ return true;
+ }
+ if(evt.id == Event.MOUSE_UP && applet.getParent() instanceof Frame) {
+ Frame frame = (Frame)applet.getParent();
+ frame.hide();
+ frame.dispose();
+ add("Center", applet);
+ validate();
+ layout();
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+package de.mud.telnet.display;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/**
+ * CharDisplay -- a simple character display
+ * --
+ * $Id: CharDisplay.java,v 1.27 1998/03/18 12:43:33 leo Exp $
+ * $timestamp: Thu Jul 24 15:19:18 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.awt.Graphics;
+import java.awt.Panel;
+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.TextArea;
+import java.awt.Label;
+import java.awt.Frame;
+import java.awt.Scrollbar;
+import java.awt.Rectangle;
+
+/**
+ * A simple character display.
+ * @version $Id: CharDisplay.java,v 1.27 1998/03/18 12:43:33 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class CharDisplay extends Panel
+{
+ /**
+ * If you need the runtime version, just ask this variable.
+ */
+ public String version = "$Revision: 1.27 $ $Date: 1998/03/18 12:43:33 $";
+ /**
+ * Enable debug messages. This is final static to prevent unused
+ * code to be compiled.
+ */
+ 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 margon */
+ private int bottomMargin; /* bottom scroll margon */
+ private Scrollbar scrollBar; /* the scroll bar */
+ private String scrBarPos; /* the scroll bar position */
+
+ 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 TextArea selection;
+ private Frame selectFrame;
+
+ private de.mud.telnet.display.SoftFont sf = new de.mud.telnet.display.SoftFont();
+
+ private boolean screenLocked = false; /* screen needs to be locked */
+ /* because of paint requests */
+ /* during other operations */
+ private boolean update[];
+
+ private Color color[] = { Color.black.brighter(),
+ Color.red.brighter(),
+ Color.green.brighter(),
+ Color.yellow.brighter(),
+ Color.blue.brighter(),
+ Color.magenta.brighter(),
+ Color.cyan.brighter(),
+ Color.white.brighter(),
+ };
+ private final static int COLOR_FG_STD = 7;
+ private final 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 container is resized.
+ */
+ public final static int RESIZE_NONE = 0;
+ /**
+ * Resize the width and height of the characterscreen.
+ */
+ public final static int RESIZE_SCREEN = 1;
+ /**
+ * Resize the font to the new screensize.
+ */
+ 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;
+
+ private void InitializeCharDisplay(int width, int height,
+ String fontname, int fsize)
+ {
+ System.err.println("CharDisplay: screen size: ["+width+","+height+"]");
+ normalFont = new Font(fontname, Font.BOLD, fsize);
+ setFont(normalFont);
+ fm = getFontMetrics(normalFont);
+ if(fm != null)
+ {
+ charWidth = fm.charWidth('@');
+ charHeight = fm.getHeight();
+ charDescent = fm.getDescent();
+ }
+
+ resizeStrategy = RESIZE_FONT;
+ size = new Dimension(width, height);
+ charArray = new char[size.height][size.width];
+ charAttributes = new int[size.height][size.width];
+ bufSize = size.height;
+ maxBufSize = 2 * size.height;
+
+ windowBase = 0;
+ screenBase = 0;
+ topMargin = 0;
+ bottomMargin = size.height - 1;
+
+ update = new boolean[size.height + 1];
+ for(int i = 1; i <= size.height; i++) update[i] = true;
+
+ selectBegin = new Point(0,0);
+ selectEnd = new Point(0,0);
+
+ setLayout(null);
+ }
+
+ /**
+ * Create a character display with size 80x24 and Font "Courier", size 12.
+ */
+ public CharDisplay()
+ {
+ InitializeCharDisplay(80, 24, "Courier", 12);
+ }
+
+ /**
+ * Create a character display with specific size, Font is "Courier", size 12.
+ */
+ public CharDisplay(int width, int height)
+ {
+ InitializeCharDisplay(width, height, "Courier", 12);
+ }
+
+ /**
+ * Create a character display with 80x24 and specific font and font size.
+ */
+ public CharDisplay(String fname, int fsize)
+ {
+ InitializeCharDisplay(80, 24, fname, fsize);
+ }
+
+ /**
+ * Create a character display with specific size, font and font size.
+ */
+ public CharDisplay(int width, int height, String fname, int fsize)
+ {
+ InitializeCharDisplay(width, height, fname, fsize);
+ }
+
+ /**
+ * 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) {
+ System.err.println("*** Error while scrolling up:");
+ System.err.println("--- BEGIN STACKTRACE ---");
+ e.printStackTrace();
+ System.err.println("--- END STACKTRACE ---");
+ 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);
+
+ if(scrollBar != null)
+ scrollBar.setValues(windowBase, size.height, 0, bufSize);
+
+ 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 setCursorPos(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 getCursorPos()
+ {
+ 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];
+ System.arraycopy(charArray, bufSize - amount, cbuf, 0, amount);
+ 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;
+ }
+
+ /**
+ * 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 setWindowSize(int width, int height)
+ {
+ char cbuf[][];
+ int abuf[][];
+ int bsize = bufSize;
+
+ if(width < 1 || height < 1) return;
+
+ 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];
+
+ 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;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Set the scrollbar position. valid values are "East" or "West".
+ * @param position the position of the scrollbar
+ */
+ public void setScrollbar(String position)
+ {
+ add(scrollBar = new Scrollbar());
+ scrollBar.setValues(windowBase, size.height, 0, bufSize - size.height);
+ scrBarPos = position;
+ }
+
+ /**
+ * 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.size().width - size.width * charWidth -
+ (scrollBar != null ? 15 : 0)) / 2;
+ int yoffset = (super.size().height - size.height * charHeight) / 2;
+
+ Color fg = color[COLOR_FG_STD];
+ Color bg = color[COLOR_BG_STD];
+
+ if(scrollBar != null && scrBarPos.equals("West")) xoffset += 15;
+
+ 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 = color[COLOR_FG_STD];
+ bg = color[COLOR_BG_STD];
+ 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.darker();
+ }
+ 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);
+ 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 + 1 + 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 reshape(int x, int y, int w, int h)
+ {
+ if(debug > 0)
+ System.err.println("CharDisplay: reshape("+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(scrollBar != null) { w -= 15;}
+
+ Font tmpFont = normalFont;
+ String fontName = normalFont.getName();
+ fm = getFontMetrics(normalFont);
+ if(fm != null)
+ {
+ charWidth = fm.charWidth('@');
+ charHeight = fm.getHeight();
+ }
+
+ switch(resizeStrategy)
+ {
+ case RESIZE_SCREEN:
+ setWindowSize(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("CharDisplay: error during resize, resetting");
+ normalFont = tmpFont;
+ System.err.println("CharDisplay: 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("CharDisplay: charWidth="+charWidth+", "+
+ "charHeight="+charHeight+", "+
+ "charDescent="+charDescent);
+ System.err.println("CharDisplay: "+normalFont+", "+fm);
+ }
+ super.reshape(x, y,
+ w + xborder + (scrollBar != null ? 15 : 0),
+ h + yborder);
+
+ if(scrollBar != null) {
+ int xoffset = (super.size().width - size.width * charWidth - 15) / 2;
+ int yoffset = (super.size().height - size.height * charHeight) / 2;
+ if(scrBarPos.equals("West"))
+ scrollBar.reshape(xoffset - (xborder / 2), yoffset - yborder / 2,
+ 15, size.height * charHeight + yborder);
+ else
+ scrollBar.reshape(xoffset + (xborder / 2) + size.width * charWidth,
+ yoffset - yborder / 2, 15,
+ size.height * charHeight + yborder);
+ }
+ }
+
+ /**
+ * Return the real size in points of the character display.
+ * @return Dimension the dimension of the display
+ * @see java.awt.Dimension
+ */
+ public Dimension size()
+ {
+ int xborder = 0, yborder = 0;
+ if(insets != null) {
+ xborder = insets.left + insets.right;
+ yborder = insets.top + insets.bottom;
+ }
+ if(scrollBar != null) xborder += 15;
+
+ 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 preferredSize()
+ {
+ return size();
+ }
+
+ /**
+ * The insets of the character display define the border.
+ * @return Insets border thickness in pixels
+ */
+ public Insets insets()
+ {
+ return insets == null ? super.insets() : 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 boolean handleEvent(Event evt)
+ {
+ // handle scrollbar events
+ if(evt != null && evt.target == scrollBar && 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;
+ if(selectFrame != null) selectFrame.hide();
+ 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";
+ if(selectFrame == null) {
+ /* for jdk-1.1
+ String s=(String) ((StringSelection)this.getToolkit().
+ getSystemClipboard().
+ getContents(this)).
+ getTransferData(DataFlavor.stringFlavor);
+ System.out.println(s);
+ */
+
+ selectFrame = new Frame("Pasteboard");
+ selection = new TextArea();
+ selection.setFont(normalFont);
+ selectFrame.add("Center", selection);
+ selectFrame.add("South", new Label("Click on the terminal window"+
+ " to hide!"));
+ selectFrame.pack();
+ }
+ selection.setText(tmp);
+ //selectFrame.show();
+ selection.selectAll();
+ repaint();
+ } else
+ if(oldx != x || oldy != y) repaint();
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+package de.mud.telnet.display;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/*
+ * SoftFont -- a unicode softfont displayer
+ * --
+ * $Id: SoftFont.java,v 1.8 1997/11/03 17:10:26 marcus Exp $
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.awt.*;
+import java.util.*;
+/**********************************************/
+/* */
+/* Font file generated by cpi2fnt */
+/* */
+/**********************************************/
+
+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 '\7f' */
+ 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;
+ }
+ }
+}
--- /dev/null
+package de.mud.telnet.display;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/*
+ * Terminal -- Terminal emulation (abstract class)
+ * --
+ * $Id: Terminal.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * $timestamp: Wed Mar 5 11:27:13 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.awt.Panel;
+import java.awt.Dimension;
+
+/**
+ * Terminal is an abstract emulation class.
+ * It contains a character display.
+ *
+ * @version $Id: Terminal.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public abstract class Terminal extends Panel
+{
+ /**
+ * Get the specific parameter info for the emulation.
+ * @see java.applet.Applet
+ */
+ public abstract String[][] getParameterInfo();
+
+ /**
+ * Put a character on the screen. The method has to see if it is
+ * a special character that needs to be handles special.
+ * @param c the character
+ * @see #putString
+ */
+ public abstract void putChar(char c);
+
+ /**
+ * Put a character on the screen. The method has to parse the string
+ * may handle special characters.
+ * @param s the string
+ * @see #putString
+ */
+ public abstract void putString(String s);
+
+ /**
+ * Return the current size of the terminal in characters.
+ */
+ public abstract Dimension getSize();
+
+ /**
+ * Return actual terminal type identifier.
+ */
+ public abstract String getTerminalType();
+}
--- /dev/null
+package de.mud.telnet.display;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/*
+ * TerminalHost -- this interface defines the remote end of the connection
+ * from our Terminal to the Host (virtual).
+ * --
+ * $Id: TerminalHost.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * $timestamp: Wed Mar 5 12:01:31 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+/**
+ * TerminalHost is an interface for the remote (virtual) end of our connection
+ * to the host computer we are connected to.
+ * @version $Id: TerminalHost.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * @author Matthias L Jugel, Marcus Meißner
+ */
+public interface TerminalHost
+{
+ /**
+ * Send a string to the host and return if it was received successfully.
+ * @param s the string to send
+ * @return True for successful receivement.
+ */
+ public boolean send(String s);
+}
+
--- /dev/null
+package de.mud.telnet.display;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/*
+ * vt320 -- a DEC VT320 Terminal emulation
+ * --
+ * $Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.awt.Scrollbar;
+import java.awt.Event;
+import java.awt.Dimension;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.util.Vector;
+
+import java.applet.Applet;
+
+/**
+ * A DEC VT320 Terminal Emulation (includes VT100/220 and ANSI).
+ *
+ * The terminal emulation accesses the applet parameters to configure itself.
+ * The following parameters may be set. Default values are written in
+ * <I>italics</I> and other possible values are <B>bold</B>.
+ * <DL>
+ * <DT><TT><PARAM NAME="Fx" VALUE="<I>functionkeytext</I>"></TT>
+ * <DD>Sets the string sent when the function key Fx (x between 1 und 20)
+ * is pressed.
+ * <DT><TT><PARAM NAME="VTcolumns" VALUE="<I>80</I>"></TT>
+ * <DD>Sets the columns of the terminal initially. If the parameter
+ * VTresize is set to <B>screen</B> this may change, else it is fixed.
+ * <DT><TT><PARAM NAME="VTrows" VALUE="<I>24</I>"></TT>
+ * <DD>Sets the rows of the terminal initially. If the parameter
+ * value of VTresize <B>screen</B> this may change!
+ * <DT><TT><PARAM NAME="VTfont" VALUE="<I>Courier</I>"></TT>
+ * <DD>Sets the font to be used for the terminal. It is recommended to
+ * use <I>Courier</I> or at least a fixed width font.
+ * <DT><TT><PARAM NAME="VTfontsize" VALUE="<I>14</I>"></TT>
+ * <DD>Sets the font size for the terminal. If the parameter
+ * value of VTresize is set to <B>font</B> this may change!
+ * <DT><TT><PARAM NAME="VTresize" VALUE="<I>font</I>"></TT>
+ * <DD>This parameter determines what the terminal should do if the window
+ * is resized. The default setting <I><B>font</B></I> will result in
+ * resizing the font until is matches the window best. Other possible
+ * values are <B>none</B> or <B>screen</B>. <B>none</B> will let nothing
+ * happen and <B>screen</B> will let the display try to change the
+ * amount of rows and columns to match the window best.
+ * <DT><TT><PARAM NAME="VTscrollbar" VALUE="<I>false</I>"></TT>
+ * <DD>Setting this parameter to <B>true</B> will add a scrollbar west to
+ * the terminal. Other possible values include <B>left</B> to put the
+ * scrollbar on the left side of the terminal and <B>right</B> to put it
+ * explicitely to the right side.
+ * <DT><TT><PARAM NAME="VTid" VALUE="<I>vt320</I>"></TT>
+ * <DD>This parameter will override the terminal id <I>vt320</I>. It may
+ * be used to determine special terminal abilities of VT Terminals.
+ * <DT><TT><PARAM NAME="VTbuffer" VALUE="<I>xx</I>"></TT>
+ * <DD>Initially this parameter is the same as the VTrows parameter. It
+ * cannot be less than the amount of rows on the display. It determines
+ * the available scrollback buffer.
+ * <DT><TT><PARAM NAME="VTcharset" VALUE="<I>none</I>"></TT>
+ * <DD>Setting this parameter to <B>ibm</B> will enable mapping of ibm
+ * characters (as used in PC BBS systems) to UNICODE characters. Note
+ * that those special characters probably won't show on UNIX systems
+ * due to lack in X11 UNICODE support.
+ * <DT><TT><PARAM NAME="VTvms" VALUE="<I>false</I>"></TT>
+ * <DD>Setting this parameter to <B>true</B> will change the Backspace key
+ * into a delete key, cause the numeric keypad keys to emit VT100
+ * codes when Ctrl is pressed, and make other VMS-important keyboard
+ * definitions.
+ * <DT><TT><PARAM NAME="F<I>nr</I>" VALUE="<I>string</I>"></TT>
+ * <DD>Function keys from <I>F1</I> to <I>F20</I> are programmable. You can
+ * install any possible string including special characters, such as
+ * <TABLE BORDER>
+ * <TR><TD><TT>\e</TT></TD><TD>Escape</TD>
+ * <TR><TD><TT>\b</TT></TD><TD>Backspace</TD>
+ * <TR><TD><TT>\n</TT></TD><TD>Newline</TD>
+ * <TR><TD><TT>\r</TT></TD><TD>Return</TD>
+ * </TABLE>
+ * <DT><TT><PARAM NAME="CF<I>nr</I>" VALUE="<I>string</I>"></TT>
+ * <DD>Function keys (with the Control-key pressed) from <I>CF1</I> to <I>CF20</I> are programmable too.
+ * <DT><TT><PARAM NAME="SF<I>nr</I>" VALUE="<I>string</I>"></TT>
+ * <DD>Function keys (with the Shift-key pressed) from <I>SF1</I> to <I>SF20</I> are programmable too.
+ * <DT><TT><PARAM NAME="AF<I>nr</I>" VALUE="<I>string</I>"></TT>
+ * <DD>Function keys (with the Alt-key pressed) from <I>AF1</I> to <I>AF20</I> are programmable too.
+ * </DL>
+ * @version $Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $
+ * @author Matthias L. Jugel, Marcus Mei?ner
+ */
+public class vt320 extends Terminal implements TerminalHost
+{
+ /**
+ * Return the version of the terminal emulation and its display.
+ */
+ public String toString() { return "$Id: vt320.java,v 1.56 1998/03/07 23:47:03 marcus Exp $ "+display.version; }
+
+ // the input handler takes the keyboard input from us.
+ private TerminalHost host = this;
+
+ // due to a bug with Windows we need a keypress cache
+ private int pressedKey = ' ';
+ private long pressedWhen = ' ';
+
+ // The character display
+ private CharDisplay display;
+ private static int debug = 0;
+ 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 originmode = false;
+ boolean sendcrlf = true;
+
+ 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
+ };
+
+ private final static int KEYUP = Event.UP % 1000;
+ private final static int KEYDOWN = Event.DOWN % 1000;
+ private final static int KEYLEFT = Event.LEFT % 1000;
+ private final static int KEYRIGHT = Event.RIGHT % 1000;
+ private final static int KEYF1 = Event.F1 % 1000;
+ private final static int KEYF2 = Event.F2 % 1000;
+ private final static int KEYF3 = Event.F3 % 1000;
+ private final static int KEYF4 = Event.F4 % 1000;
+ private final static int KEYF5 = Event.F5 % 1000;
+ private final static int KEYF6 = Event.F6 % 1000;
+ private final static int KEYF7 = Event.F7 % 1000;
+ private final static int KEYF8 = Event.F8 % 1000;
+ private final static int KEYF9 = Event.F9 % 1000;
+ private final static int KEYF10 = Event.F10 % 1000;
+ private final static int KEYF11 = Event.F11 % 1000;
+ private final static int KEYF12 = Event.F12 % 1000;
+ private final static int KEYPGDN = Event.PGDN % 1000;
+ private final static int KEYPGUP = Event.PGUP % 1000;
+
+ private final static int KEYHOME = Event.HOME % 1000;
+ private final static int KEYEND = Event.END % 1000;
+
+ public static final int KEYPRINT_SCREEN = 20;
+ public static final int KEYSCROLL_LOCK = 21;
+ public static final int KEYCAPS_LOCK = 22;
+ public static final int KEYNUM_LOCK = 23;
+ public static final int KEYPAUSE = 24;
+ public static final int KEYINSERT = 25;
+
+ /**
+ * The Insert key.
+ */
+ public static final int INSERT = 1025;
+
+ /**
+ * Strings to send on function key presseic
+ */
+ private String FunctionKey[];
+ private String FunctionKeyShift[];
+ private String FunctionKeyCtrl[];
+ private String FunctionKeyAlt[];
+ private String KeyUp;
+ private String KeyDown;
+ private String KeyLeft;
+ private String KeyRight;
+ private String KeyBacktab;
+ private String KeyTab;
+
+ private String KP0;
+ private String KP1;
+ private String KP2;
+ private String KP3;
+ private String KP4;
+ private String KP5;
+ private String KP6;
+ private String KP7;
+ private String KP8;
+ private String KP9;
+ private String KPMinus;
+ private String KPComma;
+ private String KPPeriod;
+ private String KPEnter;
+ private String PF1;
+ private String PF2;
+ private String PF3;
+ private String PF4;
+ private String Help;
+ private String Do;
+ private String Find;
+ private String Insert;
+ private String Remove;
+ private String Select;
+ private String PrevScn;
+ private String 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;
+
+ /* operation system we run on, Scrollbar hack */
+ private String osn = System.getProperty("os.name");
+
+ public String[][] getParameterInfo() {
+ String pinfo[][] = {
+ {"VTcolumns", "Integer", "Columns of the terminal"},
+ {"VTrows", "Integer", "Rows of the terminal"},
+ {"VTfont", "String", "Terminal font (default is Courier)"},
+ {"VTfontsize", "Integer", "Font size"},
+ {"VTbuffer", "Integer", "Scrollback buffer size"},
+ {"VTscrollbar","Boolean", "Enable or disable scrollbar"},
+ {"VTresize", "String", "One of none, font, screen"},
+ {"VTid", "String", "Terminal id, standard is VT320"},
+ {"VTcharset", "String", "Charset used"},
+ {"VTvms", "Boolean", "Enable or disable VMS key mappings"},
+ {"F1 - F20", "String", "Programmable Function Keys"},
+ {"SF1 - SF20", "String", "Programmable Shift-ed Function Keys"},
+ {"CF1 - CF20", "String", "Programmable Control-ed Function Keys"},
+ {"AF1 - AF20", "String", "Programmable Alt-ed Function Keys"},
+ };
+ return pinfo;
+ }
+
+ 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 : cmd += tmp.substring(idx, ++idx);break;
+ }
+ oldidx = ++idx;
+ }
+ if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx);
+ return cmd;
+ }
+
+ /**
+ * Initialize terminal.
+ * @param parent the applet parent where to get parameters from
+ * @see display.Terminal
+ */
+ public void addNotify() {
+ if(display == null) {
+ String width = "80", height = "24", resize ="screen";
+ String font = "monaco", fs = "14", bufs = "100";
+ String scrb = "false";
+ String vms = "false";
+ String ibmcset = "false";
+
+ Applet applet = getParent() instanceof Applet ? (Applet)getParent() : null;
+
+ if(applet != null) {
+ try {
+ host = (TerminalHost)applet;
+ } catch(ClassCastException e) {
+ System.err.println("vt320: "+applet+" cannot receive terminal input");
+ host = this;
+ }
+
+ width = applet.getParameter("VTcolumns");
+ height = applet.getParameter("VTrows");
+ font = applet.getParameter("VTfont");
+ fs = applet.getParameter("VTfontsize");
+ bufs = applet.getParameter("VTbuffer");
+ scrb = applet.getParameter("VTscrollbar");
+ vms = applet.getParameter("VTvms");
+ resize = applet.getParameter("VTresize");
+ resize = resize == null ? "font" : resize;
+ ibmcset = applet.getParameter("VTcharset");
+ if ((ibmcset!=null)&&(ibmcset.equals("ibm")))
+ useibmcharset=true;
+
+ if(applet.getParameter("VTid") != null)
+ terminalID = applet.getParameter("VTid");
+ }
+
+ display = new CharDisplay(
+ width==null?80:(new Integer(width)).intValue(),
+ (height==null?24:(new Integer(height)).intValue()),
+ font==null?"Courier":font,
+ fs==null?14:(new Integer(fs)).intValue()
+ );
+ display.setBottomMargin((height==null?
+ 24:
+ (new Integer(height)).intValue()) - 1);
+ display.setBufferSize(bufs==null?100:(new Integer(bufs)).intValue());
+ if(resize.equals("none"))
+ display.setResizeStrategy(CharDisplay.RESIZE_NONE);
+ else if(resize.equals("font"))
+ display.setResizeStrategy(CharDisplay.RESIZE_FONT);
+ else if(resize.equals("screen"))
+ display.setResizeStrategy(CharDisplay.RESIZE_SCREEN);
+
+ display.setResizeStrategy(CharDisplay.RESIZE_SCREEN);
+
+ display.setBorder(2, false);
+
+ setLayout(new BorderLayout());
+ display.setScrollbar("East");
+ /*
+ if(scrb != null && !scrb.equals("false")) {
+ if(scrb.equals("left") || scrb.equals("true"))
+ display.setScrollbar("West");
+ else if(scrb.equals("right"))
+ display.setScrollbar("East");
+ else
+ System.out.println("vt320: unknown scrollbar location: "+scrb);
+ }
+ */
+ if(vms != null && vms.equals("true"))
+ {
+ this.vms = true;
+ }
+ add("Center", display);
+ InitTerminalVars();
+ if (applet != null) for (int i=1;i<20;i++)
+ {
+ if (applet.getParameter("F"+i)!=null)
+ FunctionKey[i] = unEscape(applet.getParameter("F"+i));
+ if (applet.getParameter("SF"+i)!=null)
+ FunctionKeyShift[i] = unEscape(applet.getParameter("SF"+i));
+ if (applet.getParameter("CF"+i)!=null)
+ FunctionKeyCtrl[i] = unEscape(applet.getParameter("CF"+i));
+ if (applet.getParameter("AF"+i)!=null)
+ FunctionKeyAlt[i] = unEscape(applet.getParameter("AF"+i));
+ }
+ }
+ super.addNotify();
+ }
+
+ private void InitTerminalVars() {
+ int nw = display.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;
+ }
+
+ PF1 = "\u001bOP";
+ PF2 = "\u001bOQ";
+ PF3 = "\u001bOR";
+ PF4 = "\u001bOS";
+
+ Find = "\u001b[1~";
+ Insert = "\u001b[2~";
+ Remove = "\u001b[3~";
+ Select = "\u001b[4~";
+ PrevScn = "\u001b[5~";
+ NextScn = "\u001b[6~";
+
+ 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";
+
+ /* ... */
+ }
+
+ public Dimension getSize() {
+ return new Dimension(display.getColumns(), display.getRows());
+ }
+
+ public String getTerminalType() { return terminalID; }
+
+ /**
+ * 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 boolean handleEvent(Event evt) {
+ // request focus if mouse enters (necessary to avoid mistakes)
+ if(evt.id == Event.MOUSE_ENTER) { display.requestFocus(); return true; }
+ // give focus away if mouse leaves the window
+ if(evt.id == Event.MOUSE_EXIT) { nextFocus(); return true; }
+
+ // handle keyboard events
+
+ /* Netscape for windows does not send keyDown when period
+ * is pressed. This hack catches the keyUp event.
+ */
+ int id = evt.id;
+
+ boolean control = (((evt.CTRL_MASK & evt.modifiers)==0) ? false : true);
+ boolean shift = (((evt.SHIFT_MASK & evt.modifiers)==0) ? false : true );
+ boolean alt = (((evt.ALT_MASK & evt.modifiers)==0) ? false :true);
+
+ pressedKey:
+ {
+ if (pressedKey == 10
+ && (evt.key == 10
+ || evt.key == 13)
+ && evt.when - pressedWhen < 50) // Ray: Elliminate stuttering enter/return
+ break pressedKey;
+
+ int priorKey = pressedKey;
+ if(id == Event.KEY_PRESS)
+ pressedKey = evt.key; // Keep track of last pressed key
+ else if (evt.key == '.'
+ && evt.id != Event.KEY_RELEASE
+ && evt.key != pressedKey
+ ) {
+ pressedKey = 0;
+ } else
+ break pressedKey;
+ pressedWhen = evt.when;
+ if (evt.key == 10 && !control) {
+ if (sendcrlf)
+ host.send("\r\n"); /* YES, see RFC 854 */
+ else
+ host.send("\r"); /* YES, see RFC 854 */
+ return true;
+ } else
+/* 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 stuff
+ * -Marcus
+ if (((!vms && evt.key == '2') || evt.key == '@' || evt.key == ' ') && control)
+ */
+ if (((!vms && evt.key == '2') || evt.key == ' ') && control)
+ return host.send("" + (char)0);
+ else if (vms) {
+ if (evt.key == 8) {
+ if (shift && !control)
+ return host.send("" + (char)10); // VMS shift deletes word back
+ if (control && !shift)
+ return host.send("" + (char)24); // VMS control deletes line back
+ return host.send("" + (char)127); // VMS other is delete
+ }
+ if (evt.key == 127 && !control) {
+ if (shift)
+ return host.send(Insert); // VMS shift delete = insert
+ else
+ return host.send(Remove); // VMS delete = remove
+ }
+ if (control) {
+ switch(evt.key) {
+ case '0':
+ return host.send(KP0);
+ case '1':
+ return host.send(KP1);
+ case '2':
+ return host.send(KP2);
+ case '3':
+ return host.send(KP3);
+ case '4':
+ return host.send(KP4);
+ case '5':
+ return host.send(KP5);
+ case '6':
+ return host.send(KP6);
+ case '7':
+ return host.send(KP7);
+ case '8':
+ return host.send(KP8);
+ case '9':
+ return host.send(KP9);
+ case '.':
+ return host.send(KPPeriod);
+ case '-':
+ case 31:
+ return host.send(KPMinus);
+ case '+':
+ return host.send(KPComma);
+ case 10:
+ return host.send(KPEnter);
+ case '/':
+ return host.send(PF2);
+ case '*':
+ return host.send(PF3);
+ }
+ if (shift && evt.key < 32)
+ return host.send(PF1+(char)(evt.key + 64));
+ }
+ }
+ // Hmmm. Outside the VMS case?
+ if (shift && (evt.key == '\t'))
+ return host.send(KeyBacktab);
+ else
+ return host.send(""+(char)evt.key);
+ }
+
+ String input = "";
+
+ if (evt.id == evt.KEY_ACTION && !control)
+ {
+ String fmap[];
+ /* bloodsucking little buggers at netscape
+ * don't keep to the standard java values
+ * of <ARROW> or <Fx>
+ */
+ fmap = FunctionKey;
+ if (shift)
+ fmap = FunctionKeyShift;
+ if (control)
+ fmap = FunctionKeyCtrl;
+ if (alt)
+ fmap = FunctionKeyAlt;
+ switch (evt.key % 1000) {
+ case KEYF1:
+ input = fmap[1];
+ break;
+ case KEYF2:
+ input = fmap[2];
+ break;
+ case KEYF3:
+ input = fmap[3];
+ break;
+ case KEYF4:
+ input = fmap[4];
+ break;
+ case KEYF5:
+ input = fmap[5];
+ break;
+ case KEYF6:
+ input = fmap[6];
+ break;
+ case KEYF7:
+ input = fmap[7];
+ break;
+ case KEYF8:
+ input = fmap[8];
+ break;
+ case KEYF9:
+ input = fmap[9];
+ break;
+ case KEYF10:
+ input = fmap[10];
+ break;
+ case KEYF11:
+ input = fmap[11];
+ break;
+ case KEYF12:
+ input = fmap[12];
+ break;
+ case KEYUP:
+ input = KeyUp;
+ break;
+ case KEYDOWN:
+ input = KeyDown;
+ break;
+ case KEYLEFT:
+ input = KeyLeft;
+ break;
+ case KEYRIGHT:
+ input = KeyRight;
+ break;
+ case KEYPGDN:
+ input = NextScn;
+ break;
+ case KEYPGUP:
+ input = PrevScn;
+ break;
+ case KEYINSERT:
+ input = Insert;
+ break;
+// The following cases fall through if not in VMS mode.
+ case KEYHOME:
+ if (vms)
+ {
+ input = "" + (char)8;
+ break;
+ }
+ //FALLTHROUGH
+ case KEYEND:
+ if (vms)
+ {
+ input = "" + (char)5;
+ break;
+ }
+ //FALLTHROUGH
+ case KEYNUM_LOCK:
+ if (vms && control) {
+ if (pressedKey != evt.key) {
+ pressedKey = evt.key;
+ input = PF1;
+ } else
+ pressedKey = ' '; // Here, we eat a second numlock since that returns numlock state
+ }
+ break;
+ default:
+ /*if (debug>0)*/
+ System.out.println("vt320: unknown event:"+(int)evt.key);
+ break;
+ }
+ }
+
+ if(input != null && input.length() > 0)
+ return host.send(input);
+
+ return false;
+ }
+
+ /**
+ * Dummy method to handle input events (String).
+ * This is only needed if our parent is not TerminalHost
+ * @param s String to handle
+ * @return always true
+ * @see display.TerminalHost
+ */
+ public boolean send(String s) {
+ putString(s);
+ return true;
+ }
+
+ private void handle_dcs(String dcs) {
+ if (debug>1)
+ System.out.println("DCS: "+dcs);
+ }
+ private void handle_osc(String osc) {
+ if (debug>1)
+ System.out.println("OSC: "+osc);
+ }
+
+ /**
+ * 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();
+
+ display.markLine(R,1);
+ for (i=0;i<len;i++)
+ putChar(s.charAt(i),false);
+ display.setCursorPos(C, R);
+ display.redraw();
+ }
+
+ public void putChar(char c) {
+ putChar(c,true);
+ display.redraw();
+ }
+
+ public 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 = display.getRows();
+ int tm = display.getTopMargin();
+
+ R = (row<0)?0:row;
+ C = (col<0)?0:col;
+
+ if (originmode) {
+ R += display.getTopMargin();
+ maxr = display.getBottomMargin();
+ }
+ if (R>maxr) R = maxr;
+ }
+
+ public void putChar(char c,boolean doshowcursor) {
+ Dimension size;
+ int rows = display.getRows() ; //statusline
+ int columns = display.getColumns();
+ int tm = display.getTopMargin();
+ int bm = display.getBottomMargin();
+ String tosend;
+ Vector vec;
+ byte msg[];
+
+ if (debug>4) System.out.println("putChar("+c+" ["+((int)c)+"]) at R="+R+" , C="+C+", columns="+columns+", rows="+rows);
+ display.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
+ display.insertLine(R,1,display.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
+ display.insertLine(R,1,display.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
+ display.insertLine(R,1,display.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 {
+ display.insertChar(C,R,' ',attributes);
+ newc++;
+ } while (newc<columns && Tabs[newc]==0);
+ } else {
+ do {
+ display.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;
+ }
+ if (R == tm - 1 || R == bm || R >= rows - 1)
+ display.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
+ display.insertLine(R,display.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) {
+ display.insertChar(C, R, c, attributes);
+ } else {
+ display.putChar(C, R, c, attributes);
+ }
+ /*
+ } else {
+ if (insertmode==1) {
+ display.insertChar(C, rows, c, attributes);
+ } else {
+ display.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
+ display.insertLine(R,1,display.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)
+ display.insertLine(R,1,display.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
+ display.insertLine(R,1,display.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++)
+ display.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 = display.size();
+ display.setWindowSize(80,rows);
+ layout();
+ break;
+ case 4: /* scrolling mode, smooth */
+ break;
+ case 5: /* light background */
+ break;
+ case 6: /* move inside margins ? */
+ originmode = false;
+ 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 = display.size();
+ display.setWindowSize(132,rows);
+ layout();
+ break;
+ case 4: /* scrolling mode, smooth */
+ break;
+ case 5: /* light background */
+ break;
+ case 6: /* move inside margins ? */
+ originmode = true;
+ 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 = display.size();
+ display.setWindowSize(80,rows);
+ layout();
+ break;
+ case 4: /* scrolling mode, jump */
+ break;
+ case 5: /* dark background */
+ break;
+ case 6: /* move outside margins ? */
+ originmode = false;
+ 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. */
+ host.send(((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) */
+ host.send(((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 = display.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;
+ display.setBottomMargin(DCEvars[1]-1);
+ if (R >= DCEvars[0])
+ {
+ R = DCEvars[0]-1;
+ if (R < 0)
+ R = 0;
+ }
+ display.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, originmode "+originmode);
+ 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)
+ display.insertLine(R,display.SCROLL_DOWN);
+ else
+ display.insertLine(R,DCEvars[0],display.SCROLL_DOWN);
+ term_state = TSTATE_DATA;
+ if (debug>1)
+ System.out.println("ESC [ "+DCEvars[0]+" L");
+ break;
+ case 'M':
+ if (debug>1)
+ System.out.println("ESC [ "+DCEvars[0]+"M at R="+R);
+ if (DCEvars[0]==0)
+ display.deleteLine(R);
+ else
+ for (int i=0;i<DCEvars[0];i++)
+ display.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)
+ display.deleteArea(C,R,columns-C,1);
+ break;
+ case 1:/*clear to the left*/
+ if (C>0)
+ display.deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1
+ break;
+ case 2:/*clear whole line */
+ display.deleteArea(0,R,columns,1);
+ break;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case 'J':
+ /* clear display.below current line */
+ switch (DCEvars[0]) {
+ case 0:
+ if (R<rows-1)
+ display.deleteArea(0,R + 1,columns,rows-R-1);
+ if (C<columns-1)
+ display.deleteArea(C,R,columns-C,1);
+ break;
+ case 1:
+ if (R>0)
+ display.deleteArea(0,0,columns,R-1);
+ if (C>0)
+ display.deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1
+ break;
+ case 2:
+ display.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++)
+ display.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);
+ for (int i=0;i<DCEvars[0];i++)
+ display.deleteChar(C,R);
+ term_state = TSTATE_DATA;
+ break;
+ case 'n':
+ switch (DCEvars[0]){
+ case 5: /* malfunction? No malfunction. */
+ host.send(((char)ESC)+"[0n");
+ if(debug > 1)
+ System.out.println("ESC[5n");
+ break;
+ case 6:
+ host.send(((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>1)
+ 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 |= CharDisplay.UNDERLINE;
+ break;
+ case 1:
+ attributes |= CharDisplay.BOLD;
+ break;
+ case 7:
+ attributes |= CharDisplay.INVERT;
+ break;
+ case 5: /* blink on */
+ break;
+ case 25: /* blinking off */
+ break;
+ case 27:
+ attributes &= ~CharDisplay.INVERT;
+ break;
+ case 24:
+ attributes &= ~CharDisplay.UNDERLINE;
+ break;
+ case 22:
+ attributes &= ~CharDisplay.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>1)
+ System.out.print(""+DCEvars[i]+";");
+ }
+ if (debug>1)
+ 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)
+ display.setCursorPos(C, R);
+ display.markLine(R,1);
+ }
+}
--- /dev/null
+package de.mud.telnet;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * frame -- a frame subclass for handling frame events
+ * --
+ * $Id: frame.java,v 1.1 1997/07/08 09:21:56 leo Exp $
+ * $timestamp: Tue Jul 8 10:02:36 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.awt.Frame;
+import java.awt.Component;
+import java.awt.Event;
+import java.applet.Applet;
+
+public class frame extends Frame
+{
+ public frame(String title) { super(title); }
+
+ public boolean handleEvent(Event evt) {
+ if(evt.target == this && evt.id == Event.WINDOW_DESTROY) {
+ Component comp[] = getComponents();
+ for(int i = comp.length - 1; i >= 0; i--)
+ if(comp[i] instanceof Applet) {
+ ((Applet)comp[i]).stop();
+ this.dispose();
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+
+
--- /dev/null
+package de.mud.telnet.modules;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/**
+ * ButtonBar -- a programmable button bar
+ * --
+ * $Id: ButtonBar.java,v 1.22 1998/02/24 13:09:09 leo Exp $
+ * $timestamp: Mon Aug 4 14:12:21 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+
+import java.applet.Applet;
+import java.util.Hashtable;
+import java.util.Vector;
+import de.mud.telnet.*;
+
+import java.awt.Panel;
+import java.awt.Button;
+import java.awt.TextField;
+import java.awt.Event;
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.awt.Dimension;
+import java.awt.Container;
+import java.awt.Frame;
+
+/**
+ * This class implements a programmable button bar.
+ * You can add <A HREF="#buttons">Buttons</A> and <A HREF="#fields">Input
+ * fields</A> to trigger actions in the <A HREF="telnet.html">telnet
+ * applet</A>. On how to load a module, please refer to the
+ * <A HREF="telnet.html">telnet</A> documentation.
+ *
+ * <DL>
+ * <A NAME="buttons"></A>
+ * <DT><B>Buttons:</B>
+ * <DD><TT><PARAM NAME=<B><I>number</I></B>#Button VALUE="<B><I>buttontext</I></B>|<B><I>buttonaction</I></B>"></TT>
+ * <DD><B><I>number</I></B> is the sequence number and determines the place
+ * of the button on the row.
+ * <P>
+ * <DD><B><I>buttontext</I></B> is a string displayed on the button.
+ * <P>
+ * <DD><A NAME="buttonaction"><B><I>buttonaction</I></B></A> may be one
+ * of the following functions or strings<BR>
+ * <FONT SIZE=-1>(<I>Note:</I> the backslash character
+ * in front of the dollar sign is mandatory!)</FONT>
+ * <UL>
+ * <LI><TT><I>simple text</I></TT>
+ * to be sent to the remote host. Newline and/or carriage return
+ * characters may be added in C syntax <B>\n</B> and <B>\r</B>.
+ * To support unimplemented function keys the <B>\e</B> escape
+ * character may be useful. The <B>\b</B> backspace character is
+ * also supported.
+ * The text may contain <A HREF="#fieldreference"><B><I>field
+ * reference(s)</I></B></A>.
+ * <P>
+ * <LI><TT>\$connect(<B><I>host</I></B>[,<B><I>port</I></B>])</TT>
+ * tries to initiate a connection to the <B><I>host</I></B>
+ * at the <B><I>port</I></B>, if given. The standard port is
+ * 23. <B><I>host</I></B> and <B><I>port</I></B> may be hostname
+ * and number or <A HREF="#fieldreference"><B><I>field
+ * reference(s)</I></B></A>. If a connection already exists
+ * nothing will happen.<BR>
+ * <FONT SIZE=-1>(<I>Note:</I> It is not allowed to have
+ * spaces anywhere inside the parenthesis!)</FONT>
+ * <P>
+ * <LI><TT>\$disconnect()</TT>
+ * terminates the current connection, but if there was no
+ * connection nothing will happen.
+ * <P>
+ * <LI><TT>\$detach()</TT>
+ * detaches the applet from the web browser window and
+ * creates a new frame externally. This may be used to allow
+ * users to use the applet while browsing the web with the
+ * same browser window.<BR>
+ * <FONT SIZE=-1>(<I>Note:</I> You need to load the applet via the
+ * <A HREF="appWrapper.html">appWrapper class</A> or
+ * it will not work properly!)</FONT>
+ * </UL>
+ * <DD><B>Examples:</B><BR>
+ * <FONT SIZE=-1>(<I>Note:</I> It makes sense if you look at the
+ * examples for input fields below.)</FONT>
+ * <PRE>
+ * <PARAM NAME=1#Button VALUE="HELP!|help\r\n">
+ * <PARAM NAME=2#Button VALUE="HELP:|help \@help@\r\n">
+ * <PARAM NAME=4#Button VALUE="simple|\$connect(localhost)">
+ * <PARAM NAME=5#Button VALUE="complete|\$connect(www,4711)">
+ * <PARAM NAME=6#Button VALUE="connect|\$connect(\@address@)">
+ * <PARAM NAME=8#Button VALUE="connect to port|\$connect(\@address@,\@port@)">
+ * <PARAM NAME=10#Button VALUE="window|\$detach()">
+ * </PRE>
+ * <P>
+ * <A NAME="fields"></A>
+ * <DT><B>Input fields</B>
+ * <DD><TT><PARAM NAME=<B><I>number</I></B>#Input VALUE="<B><I>fieldname</I></B>[#<I><B>length</B></I>]|<B><I>initial text</I></B>[|<B><I>action</I></B>]"></TT>
+ * <DD><B><I>number</I></B> is the sequence number and determines the place
+ * of the field on the row.
+ * <P>
+ * <DD><A NAME="fieldreference"><B><I>fieldname</I></B></A> is a
+ * symbolic name to reference the input field. A reference may be used in
+ * <A HREF="#buttonaction"><B><I>button actions</I></B></A> and
+ * is constructed as follows:
+ * <TT>\@<B><I>fieldname</I></B>@</TT>
+ * The <B>\@fieldname@</B> macro will be replaced by the string entered in
+ * the text field.
+ * <P>
+ * <DD><B><I>length</I></B> is the length of the input field in numbers of
+ * characters.
+ * <P>
+ * <DD><B><I>initial text</I></B> is the text to be placed into the input
+ * field on startup
+ * <DD><B><I>action</I></B> may be used similar to a
+ * <A HREF="#buttonaction"><B><I>button action</I></B></A>. This action
+ * will be used if the users presses Return in the inputfield. Leave
+ * empty if you only want to use a button to send the text!
+ * <DD><B>Examples:</B><BR>
+ * <FONT SIZE=-1>(<I>Note:</I> It makes sense if you look at the
+ * examples for buttons before.)</FONT>
+ * <PRE>
+ * <PARAM NAME=3#Input VALUE="help#10|">
+ * <PARAM NAME=7#Input VALUE="address|www.first.gmd.de">
+ * <PARAM NAME=8#Input VALUE="send#5|who|\@send@\r\n">
+ * <PARAM NAME=9#Input VALUE="port#5|4711">
+ * </PRE>
+ * <P>
+ * </DL>
+ * @version $Id: ButtonBar.java,v 1.22 1998/02/24 13:09:09 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @see modules.Module
+ */
+public class ButtonBar extends Panel implements Module
+{
+ // our parent is the telnet app
+ private telnet parent;
+
+ // these tables contain our buttons and fields.
+ private Hashtable buttons = null;
+ private Hashtable fields = null;
+
+ // the top level (for detaching)
+ private Container toplevel;
+
+ /**
+ * This method is called by our loader to notify us of it.
+ * @param o The object that has loaded this object.
+ * @see display.Module
+ */
+ public void setLoader(Object o) { parent = (telnet)o; }
+
+ /**
+ * If the applet connects this method is called.
+ * @param host remote hostaddress - not used
+ * @param port remote port - not used
+ */
+ public void connect(String host, int port) {
+ // do nothing yet.
+ }
+
+ /**
+ * Get notified of disconnection. Do nothing.
+ */
+ public void disconnect() {
+ // do nothing yet
+ }
+
+ /**
+ * This module does not take any input. It works passive.
+ * @return null to remove from the list of receiver modules.
+ * @see display.Module
+ */
+ public String receive(String s) { return null; }
+
+ /**
+ * create the buttonbar from the parameter list. We will know our parent,
+ * when we have been added.
+ */
+ public void addNotify() {
+ if(buttons == null && fields == null) {
+ String tmp;
+
+ int nr = 1;
+ String button = null, input = null;
+ while((button = parent.getParameter(nr+"#Button")) != null ||
+ (input = parent.getParameter(nr+"#Input")) != null) {
+ nr++;
+ if(button != null) {
+ if(buttons == null) buttons = new Hashtable();
+ int idx = button.indexOf('|');
+ if(button.length() == 0)
+ System.out.println("ButtonBar: Button: no definition");
+ if(idx < 0 || idx == 0) {
+ System.out.println("ButtonBar: Button: empty name \""+button+"\"");
+ continue;
+ }
+ if(idx == button.length() - 1) {
+ System.out.println("ButtonBar: Button: empty command \""+button+"\"");
+ continue;
+ }
+ Button b = new Button(button.substring(0, idx));
+ buttons.put(b, button.substring(idx+1, button.length()));
+ add(b);
+ } else
+ if(input != null) {
+ if(fields == null) fields = new Hashtable();
+ int idx = input.indexOf('|');
+ if(input.length() == 0)
+ System.out.println("ButtonBar: Input field: no definition");
+ if(idx < 0 || idx == 0) {
+ System.out.println("ButtonBar: Input field: empty name \""+input+"\"");
+ continue;
+ }
+ int si, size;
+ if((si = input.indexOf('#', 0)) == 0) {
+ System.out.println("ButtonBar: Input field: empty name");
+ continue;
+ }
+ if(si < 0 || si == idx-1) size = 10;
+ else size = Integer.parseInt(input.substring(si+1, idx));
+ TextField t =
+ new TextField(input.substring(idx + 1,
+ ((input.lastIndexOf('|') == idx) ?
+ input.length() :
+ (idx = input.lastIndexOf('|')))),
+ size);
+ buttons.put(t, input.substring(idx + 1, input.length()));
+ fields.put(input.substring(0, (si < 0 ? idx : si)), t);
+ add(t);
+ }
+ button = input = null;
+ }
+ }
+ super.addNotify();
+ }
+
+ public boolean handleEvent(Event evt) {
+ String tmp;
+ if(evt.id == Event.ACTION_EVENT &&
+ (tmp = (String)buttons.get(evt.target)) != null) {
+ System.out.println("ButtonBar: "+tmp);
+ String cmd = "", function = null;
+ int idx = 0, oldidx = 0;
+ while((idx = tmp.indexOf('\\', oldidx)) >= 0 &&
+ ++idx <= tmp.length()) {
+ cmd += tmp.substring(oldidx, idx-1);
+ switch(tmp.charAt(idx)) {
+ case 'b': cmd += "\b"; break;
+ case 'e': cmd += "\e"; break;
+ case 'n': cmd += "\n"; break;
+ case 'r': cmd += "\r"; break;
+ case '$': {
+ int ni = tmp.indexOf('(', idx+1);
+ if(ni < idx) {
+ System.out.println("ERROR: Function: missing '('");
+ break;
+ }
+ if(ni == ++idx) {
+ System.out.println("ERROR: Function: missing name");
+ break;
+ }
+ function = tmp.substring(idx, ni);
+ idx = ni+1;
+ ni = tmp.indexOf(')', idx);
+ if(ni < idx) {
+ System.out.println("ERROR: Function: missing ')'");
+ break;
+ }
+ tmp = tmp.substring(idx, ni);
+ idx = oldidx = 0;
+ continue;
+ }
+ case '@': {
+ int ni = tmp.indexOf('@', idx+1);
+ if(ni < idx) {
+ System.out.println("ERROR: Input Field: '@'-End Marker not found");
+ break;
+ }
+ if(ni == ++idx) {
+ System.out.println("ERROR: Input Field: no name specified");
+ break;
+ }
+ String name = tmp.substring(idx, ni);
+ idx = ni;
+ TextField t;
+ if(fields == null || (t = (TextField)fields.get(name)) == null) {
+ System.out.println("ERROR: Input Field: requested input \""+
+ name+"\" does not exist");
+ break;
+ }
+ cmd += t.getText();
+ t.setText("");
+ break;
+ }
+ default : cmd += tmp.substring(idx, ++idx);
+ }
+ oldidx = ++idx;
+ }
+
+ if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx, tmp.length());
+
+ if(function != null) {
+ if(function.equals("exit")) {
+ try {
+ System.exit(0);
+ } catch(Exception e) { e.printStackTrace(); }
+ }
+ if(function.equals("connect")) {
+ String address = null;
+ int port = -1;
+ try {
+ if((idx = cmd.indexOf(",")) >= 0) {
+ try {
+ port = Integer.parseInt(cmd.substring(idx+1, cmd.length()));
+ } catch(Exception e) {
+ port = -1;
+ }
+ cmd = cmd.substring(0, idx);
+ }
+ if(cmd.length() > 0) address = cmd;
+ if(address != null)
+ if(port != -1) parent.connect(address, port);
+ else parent.connect(address);
+ else parent.connect();
+ } catch(Exception e) {
+ System.err.println("ButtonBar: connect(): failed");
+ e.printStackTrace();
+ }
+ } else
+ if(function.equals("disconnect") && parent.disconnect())
+ parent.send("\r\nClosed connection.\r\n");
+ else
+ if(function.equals("detach")) {
+ if(parent.getParent() instanceof Frame) {
+ Frame top = (Frame)parent.getParent();
+ if(toplevel != null) {
+ System.out.println("ButtonBar: reattaching applet...");
+ toplevel.setLayout(new BorderLayout());
+ toplevel.add("Center", parent);
+ toplevel.validate();
+ toplevel.layout();
+ toplevel = null;
+ } else {
+ System.out.println("ButtonBar: destroying window...");
+ parent.disconnect();
+ }
+ top.dispose();
+ } else {
+ System.out.println("ButtonBar: detaching applet...");
+ toplevel = parent.getParent();
+ frame top = new frame("The Java Telnet Applet");
+ Dimension s = parent.size();
+ top.reshape(0, 0, s.width, s.height);
+ top.setLayout(new BorderLayout());
+ top.add("Center", parent);
+ top.pack();
+ top.show();
+ }
+ }
+ else
+ System.out.println("ERROR: function not implemented: \""+
+ function+"\"");
+ return true;
+ }
+ // cmd += tmp.substring(oldidx, tmp.length());
+ if(cmd.length() > 0) parent.send(cmd);
+ return true;
+ }
+ return false;
+ }
+}
+
--- /dev/null
+package de.mud.telnet.modules;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+/**
+ * Module -- Module interface
+ * --
+ * $Id: Module.java,v 1.3 1997/03/24 14:55:18 leo Exp $
+ * $timestamp: Mon Mar 24 15:35:13 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+/**
+ * Modules must implement this interface to be detected as valid modules
+ * @version $Id: Module.java,v 1.3 1997/03/24 14:55:18 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public interface Module
+{
+ /**
+ * Set the loader of the module. This is necessary to know if you want to
+ * contact the modules parent.
+ * @param loader The object that has loaded this module.
+ */
+ public void setLoader(Object loader);
+
+ /**
+ * Connected to the remote host. This method notifies upon new connection.
+ * @param host remote hostname
+ * @param port remote port
+ */
+ public void connect(String host, int port);
+
+ /**
+ * Disconnect from the host. This method notifies of lost connection.
+ */
+ public void disconnect();
+
+ /**
+ * Receive data from somewhere. If a modules does not want to receive data
+ * it should return null to remove itself from the list of receiver modules.
+ * @param s The string we receive.
+ * @return the modified string or null (to remove from receiver list)
+ */
+ public String receive(String s);
+}
+
--- /dev/null
+package de.mud.telnet.modules;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * Script -- A module for scripting (very simple).
+ * --
+ * $Id: Script.java,v 1.6 1997/11/03 10:25:57 leo Exp $
+ * $timestamp: Mon Mar 24 15:52:12 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import de.mud.telnet.*;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.TextField;
+import java.awt.Label;
+import java.awt.Event;
+
+/**
+ * A very simple scripting module. It takes pairs of pattern and text and
+ * sends the corresponding text when the pattern matches. Each pattern is
+ * only matched once per connected session.
+ *
+ * <DL>
+ * <DT><B>Scripts:</B>
+ * <DD><PRE><PARAM NAME=script VALUE="<B><I>pattern</I></B>|<B><I>text</I></B>|<B><I>...</I></B>"></PRE>
+ * <DD>A script contains of pairs of <I>pattern</I> and <I>text</I> strings.
+ * If the pattern is matched against the output from the remote host,
+ * the corresponding text will be sent. Each pattern will match only
+ * <B>once</B> per session. A session is defined by connect and
+ * disconnect.<P>
+ * Thus it is possible to program an autologin as follows:<BR>
+ * <PRE><B>"login:|leo|Password:|mypassword|leo@www|ls"</B></PRE>
+ * Newlines will be added automatically to the string sent! At the
+ * moment the order of the pattern and text pairs is <I>not</I> relevant.
+ * <P>
+ * It is possible to prompt the user for input if a match occurs. If the
+ * corresponding <I>text</I> is a string enclosed in braces ([] or {}) a
+ * dialog window is opened with <I>text</I> as prompt. A special case
+ * is an empty prompt in which case the <I>pattern</I> will be shown as
+ * prompt. "[Your name:]" would open a dialog window with the
+ * text "Your name" as prompt. Curly braces have a special
+ * meaning; any user input will be shown as "*" which makes
+ * it possible to program password prompts. Example:
+ * "{Your password:}".<P>
+ * A special match like: "login:|[]" can be used to open a
+ * dialog and display "login:" as prompt. This works for
+ * "{}" as well.
+ *
+ * </DL>
+ * @version $Id: Script.java,v 1.6 1997/11/03 10:25:57 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @see modules.Module
+ */
+public class Script extends Hashtable implements Module
+{
+ // This is the target for any text we want to send
+ private telnet applet = null;
+
+ /**
+ * Set the applet as module loader
+ * @param o the object that is the applet (must be an Applet)
+ * @see module.Module
+ * @see java.applet.Applet
+ */
+ public void setLoader(Object o) { applet = (telnet)o; }
+
+ /**
+ * Configure the script module by reading the script PARAMeter.
+ * @param host remote hostaddress - not used
+ * @param port remote port - not used
+ */
+ public void connect(String host, int port) {
+ String tmp = applet.getParameter("script");
+
+ // delete all entries
+ clear();
+
+ if(tmp != null) {
+ int idx = tmp.indexOf('|');
+ int oldidx = 0;
+ while(idx >= 0) {
+ String match = tmp.substring(oldidx, idx);
+ oldidx = idx;
+ idx = tmp.indexOf('|', idx+1);
+ idx = idx < 0 ? idx = tmp.length() : idx;
+ String send = tmp.substring(oldidx+1, idx);
+ put(match, send);
+ oldidx = idx+1;
+ idx = tmp.indexOf('|', idx+1);
+ }
+ }
+ }
+
+ /**
+ * Get notified of disconnection. Do nothing.
+ */
+ public void disconnect() {}
+
+ /**
+ * This method is called when data is received. It tries to match the
+ * input to the list of patterns and sends corresponding text on success.
+ * If the response is [] or {} the user will be prompted with the matching
+ * text. You can modify the prompt string by entering it inside of the
+ * brackets or curly braces (e.g. [Enter your id:]). In case of curly
+ * braces the input area will not show the typed in text (for passwords)!
+ *
+ * @param s The string to test.
+ * @see peer.InputPeer
+ */
+ public String receive(String s) {
+ if(isEmpty()) return s;
+ Enumeration match = keys();
+ while(match.hasMoreElements()) {
+ String key = (String)match.nextElement();
+ if(s.indexOf(key) != -1) {
+ String value = (String)get(key);
+ if(value.indexOf("[") == 0 || value.indexOf("{") == 0) {
+ TextField input = new TextField(20);
+ if(value.startsWith("{")) input.setEchoCharacter('*');
+ if("[]".equals(value) || "{}".equals(value)) value = key;
+ else value = value.substring(1, value.length() - 1);
+ Thread current = Thread.currentThread();
+ new UserDialog(new Frame(), value, false, current, input);
+ current.suspend();
+ value = input.getText();
+ }
+ applet.send(value + "\r");
+ remove(key);
+ }
+ }
+ return s;
+ }
+static class UserDialog extends Dialog {
+ TextField input;
+ Thread thread;
+ String value;
+
+ public UserDialog(Frame parent, String value, boolean modal,
+ Thread t, TextField reply) {
+ super(parent, value, modal);
+ thread = t; input = reply;
+ add("West", new Label(value));
+ add("Center", input);
+ pack();
+ show();
+ }
+
+ public boolean handleEvent(Event evt) {
+ if(evt.target == input && evt.key == 10) {
+ thread.resume();
+ hide(); dispose();
+ return true;
+ }
+ return false;
+ }
+}
+
+}
+
--- /dev/null
+package de.mud.telnet.modules;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * TextLabel -- A module to display a Label on the applet.
+ * --
+ * $Id: TextLabel.java,v 1.1 1997/07/09 20:12:05 leo Exp $
+ * $timestamp: Wed Jul 9 17:37:28 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import de.mud.telnet.*;
+import java.awt.Panel;
+import java.awt.Label;
+import java.awt.GridLayout;
+import java.awt.Font;
+
+/**
+ * This small module lets you display text somewhere in the applets area.
+ *
+ * <DL>
+ * <DT><B>Label:</B>
+ * <DD><PRE><PARAM NAME=labelRows VALUE="<B><I>rows</B></I>"></PRE>
+ * <DD>Defines the how many rows the label will have.
+ * <DD><PRE><PARAM NAME=labelCols VALUE="<B><I>cols</B></I>"></PRE>
+ * <DD>Defines the how many columns the label will have.
+ * <DD><PRE><PARAM NAME=labelFont VALUE="<B><I>font[,size]</B></I>"></PRE>
+ * <DD>The font for displaying the label text. If the <I>size</I> is left out
+ * a standard size of 14 points is assumed.
+ * <DD><PRE><PARAM NAME=label#<I>number</I> VALUE="<B><I>text</I></B>"></PRE>
+ * <DT>The labels are enumerated and displayed in rows and columns.
+ * </DL>
+ * @version $Id: TextLabel.java,v 1.1 1997/07/09 20:12:05 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @see modules.Module
+ */
+public class TextLabel extends Panel implements Module
+{
+ telnet applet;
+
+ /**
+ * Set the applet as module loader and configure.
+ * @param o the object that is the applet (must be an Applet)
+ * @see module.Module
+ * @see java.applet.Applet
+ */
+ public void setLoader(Object o) {
+ applet = (telnet)o;
+
+ int rows = 1, cols = 1;
+
+ String tmp = applet.getParameter("labelRows");
+ if(tmp != null) rows = Integer.parseInt(tmp);
+ if((tmp = applet.getParameter("labelCols")) != null)
+ cols = Integer.parseInt(tmp);
+
+ setLayout(new GridLayout(rows, cols));
+
+ Font labelFont = null;
+ if((tmp = applet.getParameter("labelFont")) != null) {
+ int idx = tmp.indexOf(",");
+ int size = 14;
+ if(idx != -1) size = Integer.parseInt(tmp.substring(idx+1));
+ labelFont = new Font(tmp, Font.PLAIN, size);
+ }
+
+ int no = 1;
+ while((tmp = applet.getParameter("label#"+no++)) != null) {
+ Label text = new Label(tmp);
+ if(labelFont != null) text.setFont(labelFont);
+ add(text);
+ }
+ }
+
+ /**
+ * Do nothing upon connect.
+ * @param host remote hostaddress - not used
+ * @param port remote port - not used
+ */
+ public void connect(String host, int port) {}
+
+ /**
+ * Do nothing upon disconnecton.
+ */
+ public void disconnect() {}
+
+ /**
+ * Do nothing when receiving text. Be removed upon first call.
+ * @param s The string received.
+ * @see peer.InputPeer
+ */
+ public String receive(String s) { return null; }
+}
+
--- /dev/null
+package de.mud.telnet.socket;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * Status peer interface.
+ * --
+ * $Id: StatusPeer.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * $timestamp: Wed Mar 5 13:40:54 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.util.Vector;
+
+/**
+ * StatusPeer -- interface for status messages
+ * --
+ * @version $Id: StatusPeer.java,v 1.1.1.1 1997/03/05 13:35:16 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+
+public interface StatusPeer
+{
+ /**
+ * This method is called for the peer of the TelnetIO class if there is
+ * a statuschange.
+ * @param status A Vector containing the key as element 0 and any arguments
+ * from element 1 on.
+ * @return an object that matches the requested information or null
+ * @see socket.TelnetIO
+ */
+ public Object notifyStatus(Vector status);
+}
--- /dev/null
+package de.mud.telnet.socket;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * socket.TelnetIO - a telnet implementation
+ * --
+ * $Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $
+ * $timestamp: Tue May 27 13:27:05 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.net.Socket;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.awt.Dimension;
+import java.util.Vector;
+
+/**
+ * Implements simple telnet io
+ *
+ * @version $Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @version 1.2 3/7/97 George Ruban added available() because it was needed.
+ */
+public class TelnetIO implements StatusPeer
+{
+ /**
+ * Return the version of TelnetIO.
+ */
+ public String toString() { return "$Id: TelnetIO.java,v 1.10 1998/02/09 10:22:18 leo Exp $"; }
+
+ /**
+ * Debug level. This results in additional diagnostic messages on the
+ * java console.
+ */
+ private static int debug = 0;
+
+ /**
+ * State variable for telnetnegotiation 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;
+
+ private Socket socket;
+ private BufferedInputStream is;
+ private BufferedOutputStream os;
+
+ private StatusPeer peer = this; /* peer, notified on status */
+
+ /**
+ * Connect to the remote host at the specified port.
+ * @param address the symbolic host address
+ * @param port the numeric port
+ * @see #disconnect
+ */
+ public void connect(String address, int port) throws IOException {
+ if(debug > 0) System.out.println("Telnet.connect("+address+","+port+")");
+ socket = new Socket(address, port);
+ is = new BufferedInputStream(socket.getInputStream());
+ os = new BufferedOutputStream(socket.getOutputStream());
+ neg_state = 0;
+ receivedDX = new byte[256];
+ sentDX = new byte[256];
+ receivedWX = new byte[256];
+ sentWX = new byte[256];
+ }
+
+ /**
+ * Disconnect from remote host.
+ * @see #connect
+ */
+ public void disconnect() throws IOException {
+ if(debug > 0) System.out.println("TelnetIO.disconnect()");
+ if(socket !=null) socket.close();
+ }
+
+ /**
+ * Connect to the remote host at the default telnet port (23).
+ * @param address the symbolic host address
+ */
+ public void connect(String address) throws IOException {
+ connect(address, 23);
+ }
+
+ /**
+ * Set the object to be notified about current status.
+ * @param obj object to be notified.
+ */
+ public void setPeer(StatusPeer obj) { peer = obj; }
+
+ /** Returns bytes available to be read. Since they haven't been
+ * negotiated over, this could be misleading.
+ * Most useful as a boolean value - "are any bytes available" -
+ * rather than as an exact count of "how many ara available."
+ *
+ * @exception IOException on problems with the socket connection
+ */
+ public int available() throws IOException
+ {
+ return is.available();
+ }
+
+
+ /**
+ * Read data from the remote host. Blocks until data is available.
+ * Returns an array of bytes.
+ * @see #send
+ */
+ public byte[] receive() throws IOException {
+ int count = is.available();
+ byte buf[] = new byte[count];
+ count = is.read(buf);
+ if(count < 0) throw new IOException("Connection closed.");
+ if(debug > 1) System.out.println("TelnetIO.receive(): read bytes: "+count);
+ buf = negotiate(buf, count);
+ return buf;
+ }
+
+ /**
+ * Send data to the remote host.
+ * @param buf array of bytes to send
+ * @see #receive
+ */
+ public void send(byte[] buf) throws IOException {
+ if(debug > 1) System.out.println("TelnetIO.send("+buf+")");
+ os.write(buf);
+ os.flush();
+ }
+
+ public void send(byte b) throws IOException {
+ if(debug > 1) System.out.println("TelnetIO.send("+b+")");
+ os.write(b);
+ os.flush();
+ }
+
+ /**
+ * Handle an incoming IAC SB <type> <bytes> IAC SE
+ * @param type type of SB
+ * @param sbata byte array as <bytes>
+ * @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.out.println("TelnetIO.handle_sb("+type+")");
+ switch (type) {
+ case TELOPT_TTYPE:
+ if (sbcount>0 && sbdata[0]==TELQUAL_SEND) {
+ String ttype;
+ send(IACSB);send(TELOPT_TTYPE);send(TELQUAL_IS);
+ /* FIXME: need more logic here if we use
+ * more than one terminal type
+ */
+ Vector vec = new Vector(2);
+ vec.addElement("TTYPE");
+ ttype = (String)peer.notifyStatus(vec);
+ if(ttype == null) ttype = "dumb";
+ byte[] bttype = new byte[ttype.length()];
+
+ ttype.getBytes(0,ttype.length(), bttype, 0);
+ send(bttype);
+ send(IACSE);
+ }
+
+ }
+ }
+
+ /**
+ * Notify about current telnet status. This method is called top-down.
+ * @param status contains status information
+ */
+ public Object notifyStatus(Vector status) {
+ if(debug > 0)
+ System.out.println("TelnetIO.notifyStatus("+status+")");
+ return null;
+ }
+
+ /* wo faengt buf an bei buf[0] oder bei buf[1] */
+ private byte[] negotiate(byte buf[], int count) throws IOException {
+ if(debug > 1)
+ System.out.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;
+ Vector vec = new Vector(2);
+
+ 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.out.print("IAC ");
+ neg_state = STATE_DATA;
+ nbuf[noffset++]=IAC;
+ break;
+ case WILL:
+ if(debug > 2)
+ System.out.print("WILL ");
+ neg_state = STATE_IACWILL;
+ break;
+ case WONT:
+ if(debug > 2)
+ System.out.print("WONT ");
+ neg_state = STATE_IACWONT;
+ break;
+ case DONT:
+ if(debug > 2)
+ System.out.print("DONT ");
+ neg_state = STATE_IACDONT;
+ break;
+ case DO:
+ if(debug > 2)
+ System.out.print("DO ");
+ neg_state = STATE_IACDO;
+ break;
+ case EOR:
+ if(debug > 2)
+ System.out.print("EOR ");
+ neg_state = STATE_DATA;
+ break;
+ case SB:
+ if(debug > 2)
+ System.out.print("SB ");
+ neg_state = STATE_IACSB;
+ sbcount = 0;
+ break;
+ default:
+ if(debug > 2)
+ System.out.print(
+ "<UNKNOWN "+b+" > "
+ );
+ neg_state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_IACWILL:
+ switch(b) {
+ case TELOPT_ECHO:
+ if(debug > 2)
+ System.out.println("ECHO");
+ reply = DO;
+ vec = new Vector(2);
+ vec.addElement("NOLOCALECHO");
+ peer.notifyStatus(vec);
+ break;
+ case TELOPT_EOR:
+ if(debug > 2)
+ System.out.println("EOR");
+ reply = DO;
+ break;
+ default:
+ if(debug > 2)
+ System.out.println(
+ "<UNKNOWN,"+b+">"
+ );
+ reply = DONT;
+ break;
+ }
+ if(debug > 1)
+ System.out.println("<"+b+", WILL ="+WILL+">");
+ if ( reply != sentDX[b+128] ||
+ WILL != receivedWX[b+128]
+ ) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ send(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.out.println("ECHO");
+
+ vec = new Vector(2);
+ vec.addElement("LOCALECHO");
+ peer.notifyStatus(vec);
+ reply = DONT;
+ break;
+ case TELOPT_EOR:
+ if(debug > 2)
+ System.out.println("EOR");
+ reply = DONT;
+ break;
+ default:
+ if(debug > 2)
+ System.out.println(
+ "<UNKNOWN,"+b+">"
+ );
+ reply = DONT;
+ break;
+ }
+ if ( reply != sentDX[b+128] ||
+ WONT != receivedWX[b+128]
+ ) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ send(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.out.println("ECHO");
+ reply = WILL;
+ vec = new Vector(2);
+ vec.addElement("LOCALECHO");
+ peer.notifyStatus(vec);
+ break;
+ case TELOPT_TTYPE:
+ if(debug > 2)
+ System.out.println("TTYPE");
+ reply = WILL;
+ break;
+ case TELOPT_NAWS:
+ if(debug > 2)
+ System.out.println("NAWS");
+ vec = new Vector(2);
+ vec.addElement("NAWS");
+ Dimension size = (Dimension)
+ peer.notifyStatus(vec);
+ receivedDX[b] = DO;
+ if(size == null)
+ {
+ /* this shouldn't happen */
+ send(IAC);
+ send(WONT);
+ send(TELOPT_NAWS);
+ reply = WONT;
+ sentWX[b] = WONT;
+ break;
+ }
+ reply = WILL;
+ sentWX[b] = WILL;
+ sendbuf[0]=IAC;
+ sendbuf[1]=WILL;
+ sendbuf[2]=TELOPT_NAWS;
+ send(sendbuf);
+ send(IAC);send(SB);send(TELOPT_NAWS);
+ send((byte) (size.width >> 8));
+ send((byte) (size.width & 0xff));
+ send((byte) (size.height >> 8));
+ send((byte) (size.height & 0xff));
+ send(IAC);send(SE);
+ break;
+ default:
+ if(debug > 2)
+ System.out.println(
+ "<UNKNOWN,"+b+">"
+ );
+ reply = WONT;
+ break;
+ }
+ if ( reply != sentWX[128+b] ||
+ DO != receivedDX[128+b]
+ ) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ send(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.out.println("ECHO");
+ reply = WONT;
+ vec = new Vector(2);
+ vec.addElement("NOLOCALECHO");
+ peer.notifyStatus(vec);
+ break;
+ case TELOPT_NAWS:
+ if(debug > 2)
+ System.out.println("NAWS");
+ reply = WONT;
+ break;
+ default:
+ if(debug > 2)
+ System.out.println(
+ "<UNKNOWN,"+b+">"
+ );
+ reply = WONT;
+ break;
+ }
+ if ( reply != sentWX[b+128] ||
+ DONT != receivedDX[b+128]
+ ) {
+ send(IAC);send(reply);send(b);
+ sentWX[b+128] = reply;
+ receivedDX[b+128] = DONT;
+ }
+ neg_state = STATE_DATA;
+ break;
+ case STATE_IACSBIAC:
+ if(debug > 2) System.out.println(""+b+" ");
+ if (b == IAC) {
+ sbcount = 0;
+ current_sb = b;
+ neg_state = STATE_IACSBDATA;
+ } else {
+ System.out.println("(bad) "+b+" ");
+ neg_state = STATE_DATA;
+ }
+ break;
+ case STATE_IACSB:
+ if(debug > 2) System.out.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.out.println(""+b+" ");
+ switch (b) {
+ case IAC:
+ neg_state = STATE_IACSBDATAIAC;
+ break;
+ default:
+ sbbuf[sbcount++] = b;
+ break;
+ }
+ break;
+ case STATE_IACSBDATAIAC:
+ if (debug > 2) System.out.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.out.println(
+ "This should not happen: "+
+ neg_state+" "
+ );
+ neg_state = STATE_DATA;
+ break;
+ }
+ }
+ buf = new byte[noffset];
+ System.arraycopy(nbuf, 0, buf, 0, noffset);
+ return buf;
+ }
+}
--- /dev/null
+package de.mud.telnet.socket;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+import java.io.IOException;
+import java.util.Date;
+
+/** Wrapper for a Java Telnet call.
+ * To use, make a new TelnetWrapper() with the name or IP address of a host.
+ * Then, for most uses, the easiest way is to call setPrompt() with the
+ * expected prompt, then call login(), and a sequence of sendLine()'s
+ * until you get what you want done.
+ * <P>
+ * If you don't know the prompt ahead of time, you have to do a sequence of
+ * send() and wait() or receiveUntil() calls. send() sends a string across
+ * the telnet connection. Add a '\r' to the end if you want to
+ * complete a command. wait() waits for an exact string from the other side
+ * of the telnet connection, and returns nothing,
+ * receiveUntil() also waits for a string, but returns all the data
+ * that it received while waiting, including the string itself.
+ * Use this if you want the output from a command. Please note that
+ * the telnet connection will usually echo the sent command.
+ * <P>
+ * sendLine() is generally better, since it adds the '\r'
+ * automatically, waits for the prompt before returning, and returns all
+ * data received before the prompt, with the prompt itself cut off the
+ * end, and the sent command cut off the beginning. login() and
+ * sendLine() are implemented using send(), wait() and receiveUntil().
+ * They can be freely mixed and matched.
+ * <P>
+ * Here is a simple example of the use of TelnetWrapper:
+ * <PRE>
+ * // creates a new file in /tmp, lists the directory to prove it done
+ * {
+ * TelnetWrapper telnet = new TelnetWrapper("123.45.78.90");
+ *
+ * // setting the correct prompt ahead of time is very important
+ * // if you want to use login and sendLine
+ * telnet.setPrompt("$ ");
+ * telnet.login("loginname", "password");
+ *
+ * // this is how you have to do it otherwise
+ * telnet.send("touch /tmp/TELNET_WRAPPER" + "\r");
+ * telnet.wait("$ ");
+ *
+ * // sendLine 1: adds the \r automatically, 2: waits for the prompt
+ * // before returning 3: returns what was printed from the command
+ * String ls = telnet.sendLine("ls /tmp");
+ * System.out.println(ls);
+ *
+ * // clean up
+ * telnet.disconnect();
+ * }
+ * </PRE>
+ * @author George Ruban 3/4/97
+ * @version 0.2 5/15/97 - added comments, replaced String += with
+ * StringBuffer.append() in receiveUntil(), added port constructor
+ * @version 0.3 7/30/97 - added optional timeout to receiveUntil() and wait()
+ * @see TelnetIO
+ */
+public class TelnetWrapper
+{
+ /** The telnet connection. That which is wrapped. */
+ TelnetIO tio;
+ /** Set to true for System.out.println debugging. */
+ public boolean debug = false;
+ /** The current prompt on the remote system. */
+ private String prompt;
+
+ /** The default prompt used by all TelnetWrappers unless specifically
+ * overridden.
+ * @see #setPrompt
+ */
+ private static String defaultPrompt = "$ ";
+
+ /** The default login name used by TelnetWrappers.
+ * If defaultLogin and defaultPassword are both non-null
+ * when a TelnetWrapper is created, the TelnetWrapper will attempt
+ * to login.
+ */
+ private static String defaultLogin = null;
+
+ /** The default password used by TelnetWrappers.
+ * If defaultLogin and defaultPassword are both non-null
+ * when a TelnetWrapper is created, the TelnetWrapper will attempt
+ * to login.
+ */
+ private static String defaultPassword = null;
+
+ /** Skip any received data until the token appears.
+ * More efficient than receiveUntil, but liable to fail on large
+ * tokens that can be spread over several "send"s. In that case,
+ * consider using receiveUntil and ignoring the return value.
+ * @param token String to wait for
+ * @exception IOException on problems with the socket connection
+ * @see #receiveUntil
+ */
+ public void wait(String token) throws IOException
+ {
+ wait(token, -1);
+ }
+
+ /** Wait for a String or a timeout.
+ * If time runs out, throws a TimedOutException.
+ * Sleeps in intervals of 100 milliseconds until either receiving the
+ * token or timeout.
+ * <P>
+ * More efficient than receiveUntil, but liable to fail on large
+ * tokens that can be spread over several "send"s. In that case,
+ * consider using receiveUntil and ignoring the return value.
+ * @param token String to wait for
+ * @param timeout time in milliseconds to wait (negative means wait forever)
+ * @exception IOException on problems with the socket connection
+ * @exception TimedOutException if time runs out before token received
+ * @see #receiveUntil(String, long)
+ */
+ public void wait(String token, long timeout)
+ throws IOException, TimedOutException
+ {
+ if(debug) System.out.println("wait(" + token + ", " + timeout + ")...");
+ String tmp = "";
+ long deadline = 0;
+ if(timeout >= 0)
+ deadline = new Date().getTime() + timeout;
+
+ do {
+ if(timeout >= 0)
+ {
+ while(available() <= 0)
+ {
+ if(new Date().getTime() > deadline)
+ throw new TimedOutException();
+ try{
+ Thread.currentThread().sleep(100);
+ }
+ catch(InterruptedException ignored)
+ {}
+ }
+ }
+ tmp = receive();
+ } while(tmp.indexOf(token) == -1);
+ if(debug) System.out.println("wait(" + token + ", " + timeout +
+ ") successful.");
+ }
+
+ /** Returns bytes available to be read. Since they haven't been
+ * negotiated over, this could be misleading...
+ */
+ public int available() throws IOException
+ {
+ return tio.available();
+ }
+
+ /** Returns a String from the telnet connection. Blocks
+ * until one is available. No guarantees that the string is in
+ * any way complete.
+ * NOTE: uses Java 1.0.2 style String-bytes conversion.*/
+ public String receive() throws IOException
+ {
+ String s = new String(receiveBytes(), 0);
+ if(debug) System.out.println(s);
+ return s;
+ }
+
+ /** Returns a byte array. Blocks until data is available. */
+ public byte[] receiveBytes() throws IOException
+ {
+ return tio.receive();
+ }
+
+ /** Returns all data received up until a certain token.
+ * @param token String to wait for
+ * @exception IOException on problems with the socket connection
+ * @see #wait
+ */
+ public String receiveUntil(String token) throws IOException
+ {
+ return receiveUntil(token, -1);
+ }
+
+
+ /** Returns all data received up until a certain token.
+ * @param token String to wait for
+ * @param timeout time in milliseconds to wait (negative means wait forever)
+ * @exception IOException on problems with the socket connection
+ * @exception TimedOutException if time runs out before token received
+ * @see #wait(String, long)
+ */
+ public String receiveUntil(String token, long timeout)
+ throws IOException, TimedOutException
+ {
+ StringBuffer buf = new StringBuffer();
+ long deadline = 0;
+ if(timeout >= 0)
+ deadline = new Date().getTime() + timeout;
+ do
+ {
+ if(timeout >= 0)
+ {
+ while(available() <= 0)
+ {
+ if(new Date().getTime() > deadline)
+ throw new TimedOutException();
+ try{
+ Thread.currentThread().sleep(100);
+ }
+ catch(InterruptedException ignored)
+ {}
+ }
+ }
+ buf.append(receive());
+ } while(buf.toString().indexOf(token) == -1);
+ return buf.toString();
+ }
+
+ /** Sends a String to the remote host.
+ * NOTE: uses Java 1.0.2 style String-bytes conversion.
+ * @exception IOException on problems with the socket connection
+ */
+ public void send(String s) throws IOException
+ {
+ if(debug) System.out.println(s);
+ byte[] buf = new byte[s.length()];
+ s.getBytes(0, buf.length, buf, 0);
+ tio.send(buf);
+ }
+
+ /** Sends a line to the remote host, returns all data before the prompt.
+ * Since telnet seems to rely on carriage returns ('\r'),
+ * one will be appended to the sent string, if necessary.
+ * @param command command line to send
+ * @return whatever data the command produced before the prompt.
+ * @see #setPrompt
+ */
+ public String sendLine(String command) throws IOException
+ {
+ if(command.charAt(command.length() -1) != '\r')
+ command += "\r";
+ send(command);
+ String s = receiveUntil(prompt);
+
+ // telnet typically echoes the command with a \r\n ending...
+ return s.substring(command.length() + 1, s.indexOf(prompt));
+ }
+
+ /** Sends bytes over the telnet connection. */
+ public void send(byte[] buf) throws IOException
+ {
+ tio.send(buf);
+ }
+
+ /** Logs in as a particular user and password.
+ * Returns after receiving prompt. */
+ public void login(String loginName, String password) throws IOException
+ {
+ wait("login:");
+ send(loginName + "\r");
+ wait("Password:");
+ sendLine(password + "\r");
+ }
+
+ /** Connects to the default telnet port on the given host.
+ * If the defaultLogin and defaultPassword are non-null, attempts login. */
+ public TelnetWrapper(String host) throws IOException
+ {
+ tio = new TelnetIO();
+ setPrompt(defaultPrompt);
+ tio.connect(host);
+ if(defaultLogin != null && defaultPassword != null)
+ {
+ login(defaultLogin, defaultPassword);
+ }
+ }
+
+ /** Connects to a specific telnet port on the given host.
+ * If the defaultLogin and defaultPassword are non-null, attempts login. */
+ public TelnetWrapper(String host, int port) throws IOException
+ {
+ tio = new TelnetIO();
+ setPrompt(defaultPrompt);
+ tio.connect(host, port);
+ if(defaultLogin != null && defaultPassword != null)
+ {
+ login(defaultLogin, defaultPassword);
+ }
+ }
+
+ /** Sets the expected prompt.
+ * If this function is not explicitly called, the default prompt is used.
+ * @see #setDefaultPrompt
+ */
+ public void setPrompt(String prompt)
+ {
+ if(prompt == null) throw new IllegalArgumentException("null prompt.");
+ this.prompt = prompt;
+ }
+
+ /** Sets the default prompt used by all TelnetWrappers.
+ * This can be specifically overridden for a specific instance.
+ * The default prompt starts out as "$ " until this function is called.
+ * @see #setPrompt
+ */
+ public static void setDefaultPrompt(String prompt)
+ {
+ if(prompt == null) throw new IllegalArgumentException("null prompt.");
+ defaultPrompt = prompt;
+ }
+
+ /** Sets the default login used by TelnetWrappers.
+ * If this method is called with non-null login and password,
+ * all TelnetWrappers will attempt to login when first created.
+ * @param login login name to use
+ * @param password password to use
+ * @see #login
+ * @see #unsetLogin
+ */
+ public static void setLogin(String login, String password)
+ {
+ if(login == null || password == null)
+ throw new IllegalArgumentException("null login or password.");
+ defaultLogin = login;
+ defaultPassword = password;
+ }
+
+
+ /** Turns off the default login of TelnetWrappers.
+ * After this method is called, TelnetWrappers will not
+ * login until that method is explicitly called.
+ * @see #setLogin
+ * @see #login
+ */
+ public static void unsetLogin()
+ {
+ defaultLogin = defaultPassword = null;
+ }
+
+ /** Ends the telnet connection. */
+ public void disconnect() throws IOException
+ {
+ if(tio != null) tio.disconnect();
+ tio = null;
+ }
+
+ /** Ends the telnet connection. */
+ public void finalize()
+ {
+ try
+ {
+ disconnect();
+ }
+ catch(IOException e)
+ {} // after all, what can be done at this point?
+ }
+
+ /** Telnet test driver.
+ * Modeled after the IOtest.java example in the Telnet Applet.
+ * Logs in to "host", creates a timestamped file in /tmp, lists the
+ * /tmp directory to System.out, disconnects. Shows off several
+ * TelnetWrapper methods.
+ * @param args host login password prompt
+ */
+ public static void main(String args[]) throws IOException
+ {
+ if(args.length != 4) throw new
+ IllegalArgumentException("Usage: TelnetWrapper host login password prompt");
+
+ String host = args[0];
+ String login = args[1];
+ String password = args[2];
+ String prompt = args[3];
+
+ Date now = new Date();
+ String timestamp = now.getYear() + "-" +
+ (now.getMonth()+1) + "-" + now.getDate() + "-" +
+ now.getHours() + ":" + now.getMinutes() + ":" +
+ now.getSeconds();
+ TelnetWrapper telnet = new TelnetWrapper(host);
+ telnet.debug = true;
+
+ // setting the correct prompt ahead of time is very important
+ // if you want to use login and sendLine
+ telnet.setPrompt(prompt);
+ telnet.login(login, password);
+
+ // this is how you have to do it otherwise
+ telnet.send("touch /tmp/TELNET_WRAPPER-" + timestamp + "\r");
+ telnet.wait(prompt);
+
+ // sendLine 1: adds the \r automatically, 2: waits for the prompt
+ // before returning 3: returns what was printed from the command
+ String ls = telnet.sendLine("ls /tmp");
+ System.out.println(ls);
+
+ // clean up
+ telnet.disconnect();
+ }
+}
+
--- /dev/null
+package de.mud.telnet.socket;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+import java.io.IOException;
+
+/** Exception thrown when a Telnet connection takes too long
+ * before receiving a specified String token.
+ * @author George Ruban
+ * @version 0.1 7/30/97 */
+public class TimedOutException extends IOException
+{
+ public TimedOutException()
+ {
+ }
+
+ public TimedOutException(String message)
+ {
+ super(message);
+ }
+}
+
--- /dev/null
+package de.mud.telnet;
+/* "In case you would like to use the packages as libraries please
+ * apply the GNU Library General Public License as documented in the
+ * file COPYING.LIB." (from Telnet/Documentation/index.html)
+ */
+
+/**
+ * telnet -- implements a simple telnet
+ * --
+ * $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $
+ * $timestamp: Mon Aug 4 13:11:14 1997 by Matthias L. Jugel :$
+ *
+ * This file is part of "The Java Telnet Applet".
+ *
+ * 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 Applet" 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.
+ */
+
+import java.applet.Applet;
+import java.awt.Frame;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Panel;
+import java.awt.Event;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.io.IOException;
+
+import de.mud.telnet.socket.*;
+import de.mud.telnet.display.*;
+import de.mud.telnet.modules.*;
+
+/**
+ * A telnet implementation that supports different terminal emulations.
+ * @version $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public class telnet extends Applet implements Runnable, TerminalHost, StatusPeer
+{
+ /**
+ * The telnet io methods.
+ * @see socket.TelnetIO
+ */
+ protected TelnetIO tio;
+
+ /**
+ * The terminal emulation (dynamically loaded).
+ * @see emulation
+ * @see display.Terminal
+ * @see display.TerminalHost
+ */
+ protected Terminal term;
+
+ /**
+ * The host address to connect to. This is retrieved from the PARAM tag
+ * "address".
+ */
+ protected String address;
+
+ /**
+ * The port number (default ist 23). This can be specified as the PARAM tag
+ * "port".
+ */
+ protected int port = 23;
+
+ /**
+ * The proxy ip address. If this variable is set telnet will try to connect
+ * to this address and then send a string to tell the relay where the
+ * target host is.
+ * @see address
+ */
+ protected String proxy = null;
+ /**
+ * The proxy port number. This is the port where the relay is expected to
+ * listen for incoming connections.
+ * @see proxy
+ * @see port
+ */
+ protected int proxyport;
+
+ /**
+ * Emulation type (default is vt320). This can be specified as the PARAM
+ * tag "emulation".
+ * @see term
+ * @see display.Terminal
+ * @see display.TerminalHost
+ */
+ protected String emulation = "vt320";
+
+ /**
+ * Dynamically loaded modules are stored here.
+ */
+ protected Vector modules = null;
+
+ // some state variables;
+ private boolean localecho = true;
+ private boolean connected = false;
+
+ private Thread t;
+ private Container parent;
+
+ /**
+ * This Hashtable contains information retrievable by getParameter() in case
+ * the program is run as an application and the AppletStub is missing.
+ */
+ public Hashtable params;
+
+ /**
+ * Retrieve the current version of the applet.
+ * @return String a string with the version information.
+ */
+ public String getAppletInfo()
+ {
+ String info = "The Java(tm) Telnet Applet\n$Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $\n";
+ info += "Terminal emulation: "+term.getTerminalType()+
+ " ["+term.toString()+"]\n";
+ info += "Terminal IO version: "+tio.toString()+"\n";
+ if(modules != null && modules.size() > 0) {
+ info += "Resident modules loaded: ("+modules.size()+")";
+ for(int i = 0; i < modules.size(); i++)
+ info += " + "+(modules.elementAt(i)).toString()+"\n";
+ }
+
+ return info;
+ }
+
+ /**
+ * Retrieve parameter tag information. This includes the tag information from
+ * terminal and loaded modules.
+ * @return String an array of array of string with tag information
+ * @see java.applet.Applet#getParameterInfo
+ */
+ public String[][] getParameterInfo()
+ {
+ String pinfo[][];
+ String info[][] = {
+ {"address", "String", "IP address"},
+ {"port", "Integer", "Port number"},
+ {"proxy", "String", "IP address of relay"},
+ {"proxyport","Integer", "Port number of relay"},
+ {"emulation","String", "Emulation to be used (standard is vt320)"},
+ };
+ String tinfo[][] = (term != null ? term.getParameterInfo() : null);
+ if(tinfo != null) pinfo = new String[tinfo.length + 3][3];
+ else pinfo = new String[3][3];
+ System.arraycopy(info, 0, pinfo, 0, 3);
+ System.arraycopy(tinfo, 0, pinfo, 3, tinfo.length);
+ return pinfo;
+ }
+
+ /**
+ * We override the Applet method getParameter() to be able to handle
+ * parameters even as application.
+ * @param name The name of the queried parameter.
+ * @return the value of the parameter
+ * @see java.applet.Applet#getParameter
+ */
+ public String getParameter(String name)
+ {
+ if(params == null) return super.getParameter(name);
+ return (String)params.get(name);
+ }
+
+ /**
+ * The main function is called on startup of the application.
+ */
+ public static void main(String args[])
+ {
+ // an application has to create a new instance of itself.
+ telnet applet = new telnet();
+
+ // create params from command line arguments
+ applet.params = new Hashtable();
+ switch(args.length)
+ {
+ case 2: applet.params.put("port", args[1]);
+ case 1: applet.params.put("address", args[0]);
+ break;
+ default:
+ System.out.println("Usage: java telnet host [port]");
+ System.exit(0);
+ }
+ applet.params.put("VTscrollbar", "true");
+ applet.params.put("module#1", "ButtonBar");
+ applet.params.put("1#Button", "Exit|\\$exit()");
+ applet.params.put("2#Button", "Connect|\\$connect(\\@address@,\\@port@)");
+ applet.params.put("3#Input", "address#30|"
+ +(args.length > 0 ? args[0] : "localhost"));
+ applet.params.put("4#Input", "port#4|23");
+ applet.params.put("5#Button", "Disconnect|\\$disconnect()");
+
+ // we put the applet in its own frame
+ Frame frame = new Frame("The Java Telnet Application ["+args[0]+"]");
+ frame.setLayout(new BorderLayout());
+ frame.add("Center", applet);
+ frame.resize(380, 590);
+
+ applet.init();
+
+ frame.pack();
+ frame.show();
+
+ applet.start();
+ }
+
+ /**
+ * Initialize applet. This method reads the PARAM tags "address",
+ * "port" and "emulation". The emulation class is loaded dynamically.
+ * It also loads modules given as parameter "module#<nr>".
+ */
+ public void init()
+ {
+ String tmp;
+
+ // save the current parent for future use
+ parent = getParent();
+
+ // get the address we want to connect to
+ address = getParameter("address");
+
+ if((tmp = getParameter("port")) == null)
+ port = 23;
+ else
+ port = Integer.parseInt(tmp);
+
+ if((proxy = getParameter("proxy")) != null)
+ if((tmp = getParameter("proxyport")) == null)
+ proxyport = 31415;
+ else
+ proxyport = Integer.parseInt(tmp);
+
+ if((emulation = getParameter("emulation")) == null)
+ emulation = "vt320";
+
+ // load the terminal emulation
+ try {
+ term = (Terminal)Class.forName("display."+emulation).newInstance();
+ System.out.println("telnet: load terminal emulation: "+emulation);
+ } catch(Exception e) {
+ System.err.println("telnet: cannot load terminal emulation "+emulation);
+ e.printStackTrace();
+ }
+ setLayout(new BorderLayout());
+
+ // load modules, position is determined by the @<position> modifier
+ modules = new Vector();
+ int nr = 1;
+ while((tmp = getParameter("module#"+nr++)) != null) try {
+ Panel north = null, south = null, west = null, east = null;
+ String position = "North", initFile = null;
+
+ // try to get the initialization file name
+ if(tmp.indexOf(',') != -1) {
+ initFile = tmp.substring(tmp.indexOf(','+1));
+ tmp = tmp.substring(0, tmp.indexOf(','));
+ initFile = tmp.substring(tmp.indexOf(','+1));
+ }
+
+ // find the desired location
+ if(tmp.indexOf('@') != -1) {
+ position = tmp.substring(tmp.indexOf('@')+1);
+ tmp = tmp.substring(0, tmp.indexOf('@'));
+ }
+ Object obj = (Object)Class.forName("modules."+tmp).newInstance();
+
+ // probe for module (implementing modules.Module)
+ try {
+ ((Module)obj).setLoader(this);
+ modules.addElement((Module)obj);
+ System.out.println("telnet: module "+tmp+" detected");
+ } catch(ClassCastException e) {
+ System.out.println("telnet: warning: "+tmp+" may not be a "+
+ "valid module");
+ }
+
+ // probe for visible component (java.awt.Component and descendants)
+ try {
+ Component component = (Component)obj;
+ if(position.equals("North")) {
+ if(north == null) { north = new Panel(); add("North", north); }
+ north.add(component);
+ } else if(position.equals("South")) {
+ if(south == null) { south = new Panel(); add("South", south); }
+ south.add(component);
+ } else if(position.equals("East")) {
+ if(east == null) { east = new Panel(); add("East", east); }
+ east.add(component);
+ } else if(position.equals("West")) {
+ if(west == null) { west = new Panel(); add("West", west); }
+ west.add(component);
+ }
+ System.err.println("telnet: module "+tmp+" is a visible component");
+ } catch(ClassCastException e) {}
+
+ } catch(Exception e) {
+ System.err.println("telnet: cannot load module "+tmp);
+ e.printStackTrace();
+ }
+ if(modules.isEmpty()) modules = null;
+ add("Center", term);
+ }
+
+ /**
+ * Upon start of the applet try to create a new connection.
+ */
+ public void start()
+ {
+ if(!connect(address, port) && params == null)
+ showStatus("telnet: connection to "+address+" "+port+" failed");
+ }
+
+ /**
+ * Disconnect when the applet is stopped.
+ */
+ public final void stop()
+ {
+ disconnect();
+ }
+
+ /**
+ * Try to read data from the sockets and put it on the terminal.
+ * This is done until the thread dies or an error occurs.
+ */
+ public void run()
+ {
+ while(t != null)
+ try {
+ String tmp = new String(tio.receive(), 0);
+
+ // cycle through the list of modules
+ if(modules != null) {
+ Enumeration modlist = modules.elements();
+ while(modlist.hasMoreElements()) {
+ Module m = (Module)modlist.nextElement();
+ String modified = m.receive(tmp);
+ // call the receive() method and if it returns null
+ // remove the module from the list
+ if(modified == null) modules.removeElement(m);
+ else tmp = modified;
+ }
+ }
+ // put the modified string to the terminal
+ term.putString(tmp);
+ } catch(IOException e) {
+ disconnect();
+ }
+ }
+
+ /**
+ * Connect to the specified host and port but don't break existing
+ * connections. Connects to the host and port specified in the tags.
+ * @return false if connection was unsuccessful
+ */
+ public boolean connect()
+ {
+ return connect(address, port);
+ }
+
+ /**
+ * Connect to the specified host and port but don't break existing
+ * connections. Uses the port specified in the tags or 23.
+ * @param host destination host address
+ */
+ public boolean connect(String host)
+ {
+ return connect(host, port);
+ }
+
+ /**
+ * Connect to the specified host and port but don't break existing
+ * connections.
+ * @param host destination host address
+ * @param prt destination hosts port
+ */
+ public boolean connect(String host, int prt)
+ {
+ address = host; port = prt;
+
+ if(address == null || address.length() == 0) return false;
+
+ // There should be no thread when we try to connect
+ if(t != null && connected) {
+ System.err.println("telnet: connect: existing connection preserved");
+ return false;
+ } else t = null;
+
+ try {
+ // In any case try to disconnect if tio is still active
+ // if there was no tio create a new one.
+ if(tio != null) try { tio.disconnect(); } catch(IOException e) {}
+ else (tio = new TelnetIO()).setPeer(this);
+
+ term.putString("Trying "+address+(port==23?"":" "+port)+" ...\n\r");
+ try {
+ // connect to to our destination at the given port
+ if(proxy != null) {
+ tio.connect(proxy, proxyport);
+ String str = "relay "+address+" "+port+"\n";
+ byte[] bytes = new byte[str.length()];
+ str.getBytes(0, str.length(), bytes, 0);
+ tio.send(bytes);
+ } else
+ tio.connect(address, port);
+ term.putString("Connected to "+address+".\n\r");
+ // initial conditions are connected and localecho
+ connected = true;
+ localecho = true;
+
+ // cycle through the list of modules and notify connection
+ if(modules != null) {
+ Enumeration modlist = modules.elements();
+ while(modlist.hasMoreElements())
+ // call the connect() method
+ ((Module)modlist.nextElement()).connect(address, port);
+ }
+ } catch(IOException e) {
+ term.putString("Failed to connect.\n\r");
+ // to be sure, we remove the TelnetIO instance
+ tio = null;
+ System.err.println("telnet: failed to connect to "+address+" "+port);
+ e.printStackTrace();
+ return false;
+ }
+ // if our connection was successful, create a new thread and start it
+ t = new Thread(this);
+ t.setPriority(Thread.MIN_PRIORITY);
+ t.start();
+ } catch(Exception e) {
+ // hmm, what happened?
+ System.err.println("telnet: an error occured:");
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Disconnect from the remote host.
+ * @return false if there was a problem disconnecting.
+ */
+ public boolean disconnect()
+ {
+ if(tio == null) {
+ System.err.println("telnet: no connection");
+ return false;
+ }
+ try {
+ connected = false; t = null;
+ // cycle through the list of modules and notify connection
+ if(modules != null) {
+ Enumeration modlist = modules.elements();
+ while(modlist.hasMoreElements())
+ // call the disconnect() method
+ ((Module)modlist.nextElement()).disconnect();
+ }
+ term.putString("\n\rConnection closed.\n\r");
+ tio.disconnect();
+ } catch(Exception e) {
+ System.err.println("telnet: disconnection problem");
+ e.printStackTrace();
+ tio = null; t = null;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Send a String to the remote host. Implements display.TerminalHost
+ * @param s String to be sent
+ * @return true if we are connected
+ * @see display.TerminalHost
+ */
+ public boolean send(String str)
+ {
+ if(connected) try {
+ byte[] bytes = new byte[str.length()];
+ str.getBytes(0, str.length(), bytes, 0);
+ tio.send(bytes);
+ if(localecho) {
+ if ((str.length()==2) && (str.charAt(0)=='\r') && (str.charAt(1)==0))
+ term.putString("\r\n");
+ else
+ term.putString(str);
+ }
+ } catch(Exception e) {
+ System.err.println("telnet.send(): disconnected");
+ disconnect();
+ return false;
+ }
+ else return false;
+ return true;
+ }
+
+ /**
+ * Send a String to the remote Host.
+ * @param str String to be sent
+ * @return true if we are connected
+ * @see modules.BSXModule
+ */
+ public boolean writeToSocket(String str)
+ {
+ if (connected) try {
+ byte[] bytes = new byte[str.length()];
+ str.getBytes(0, str.length(), bytes, 0);
+ tio.send(bytes);
+ } catch(Exception e) {
+ System.err.println("telnet.send(): disconnected");
+ disconnect();
+ return false;
+ }
+ else return false;
+ return true;
+ }
+ /**
+ * Send a String to the users terminal
+ * @param str String to be displayed
+ * @return void
+ * @see modules.BSXModule
+ */
+ public void writeToUser(String str)
+ {
+ if (term!=null)
+ term.putString(str);
+ }
+
+ /**
+ * This method is called when telnet needs to be notified of status changes.
+ * @param status Vector of status information.
+ * @return an object of the information requested.
+ * @see socket.StatusPeer
+ */
+ public Object notifyStatus(Vector status)
+ {
+ String what = (String)status.elementAt(0);
+ if(what.equals("NAWS"))
+ return term.getSize();
+ if(what.equals("TTYPE"))
+ if(term.getTerminalType() == null)
+ return emulation;
+ else return term.getTerminalType();
+ if(what.equals("LOCALECHO"))
+ localecho = true;
+ if(what.equals("NOLOCALECHO"))
+ localecho = false;
+ return null;
+ }
+}
}
public void dispatchCodeBag(int descriptor) {
- System.out.println("instr: dispatching codebag #"+descriptor);
+ Log.println("instr: dispatching codebag #"+descriptor);
Program.allCodeBags.get(descriptor).dispatch(this);
}
--- /dev/null
+package edu.berkeley.fleet;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.*;
+import java.io.*;
+import java.util.*;
+
+public class FleetApplet extends Applet {
+
+ public static void main(String[] s) throws Exception {
+ Frame f = new Frame();
+ f.show();
+
+ PipedOutputStream po1 = new PipedOutputStream();
+ PipedInputStream pi1 = new PipedInputStream(po1);
+
+ PipedOutputStream po2 = new PipedOutputStream();
+ final PipedInputStream pi2 = new PipedInputStream(po2);
+
+ JPanel top = new JPanel();
+ top.setLayout(new BorderLayout());
+ final JTextArea text = new JTextArea(100, 10);
+ top.add(new JScrollPane(text), BorderLayout.CENTER);
+
+ JButton button = new JButton("interpret");
+ top.add(button, BorderLayout.SOUTH);
+
+ Term term = new Term(pi1, po2);
+ term.setMinimumSize(new Dimension(Integer.MAX_VALUE, 10));
+
+ JSplitPane jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+ top,
+ term
+ );
+ f.add(jsp);
+
+ Log.log = new PrintWriter(new OutputStreamWriter(po1));
+
+ new Thread() {
+ public void run() {
+ try {
+ while(true)
+ System.err.println(pi2.read());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ f.pack();
+
+ text.setFont(new Font("monospaced", 0, 20));
+ StringBuffer in = new StringBuffer();
+ BufferedReader br =
+ new BufferedReader(new InputStreamReader(FleetApplet.class.getClassLoader().getResourceAsStream("test.fleet")));
+ while(true) {
+ String str = br.readLine();
+ if (str==null) break;
+ in.append(str+"\n");
+ }
+ text.setText(in.toString());
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ try {
+ System.err.println("launching");
+ FleetParser.go(new StringReader(text.getText()));
+ System.err.println("launched");
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+
+ jsp.setDividerLocation(0.5);
+ f.pack();
+ f.show();
+ f.setSize(800, 600);
+ f.doLayout();
+ }
+
+}
public class FleetParser {
public static void main(String[] s) throws Exception {
+ go(new InputStreamReader(System.in));
+ }
+ public static void go(Reader r) throws Exception {
InputStream grammarStream =
FleetParser.class.getClassLoader().getResourceAsStream("fleet.g");
Union mathGrammar = Grammar.create(parsedGrammar, "s", gbr);
Parser mathParser = new CharParser(mathGrammar);
- System.out.println("about to parse: tests/test.fleet");
- Tree tree = mathParser.parse(new CharInput(System.in)).expand1();
+ Log.println("about to parse: tests/test.fleet");
+ Tree tree = mathParser.parse(new CharInput(r)).expand1();
// below is ugly voodoo which will go away very soon. ignore it.
TreeFunctor tf = (TreeFunctor)tree.head();
Program program = (Program)tf.invoke(tree);
// above is ugly voodoo which will go away very soon. ignore it.
- System.out.println();
- System.out.println("dispatching root codebag:");
- System.out.println(program.root);
+ Log.println();
+ Log.println("dispatching root codebag:");
+ Log.println(program.root);
Fleet fleet = new Fleet();
program.configure(fleet);
- System.out.println("memory before execution:");
- System.out.print(" ");
+ Log.println("memory before execution:");
+ Log.print(" ");
for(int i=0; i<fleet.mem.length; i++)
- System.out.print(fleet.mem[i] + " ");
- System.out.println();
+ Log.print(fleet.mem[i] + " ");
+ Log.println();
- System.out.println();
- System.out.println("enabling execution...");
+ Log.println();
+ Log.println("enabling execution...");
fleet.go();
- System.out.println("execution halted.");
+ Log.println("execution halted.");
- System.out.println();
- System.out.println("memory after execution:");
- System.out.print(" ");
+ Log.println();
+ Log.println("memory after execution:");
+ Log.print(" ");
for(int i=0; i<fleet.mem.length; i++)
- System.out.print(fleet.mem[i] + " ");
- System.out.println();
+ Log.print(fleet.mem[i] + " ");
+ Log.println();
}
}
--- /dev/null
+package edu.berkeley.fleet;
+import java.io.*;
+
+public class Log {
+
+ public static PrintWriter log = new PrintWriter(new OutputStreamWriter(System.out));
+
+ public static void print(Object o) {
+ try {
+ log.print(o);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static void println() { println(""); }
+ public static void println(Object o) {
+ try {
+ log.println(o);
+ log.flush();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
for(Port d : dest) {
Ship.Inbox ib = fleet.getInbox(d.ship, d.port);
ob.addDestination(ib);
- System.out.println("instr: " + ob + " -> " + ib);
+ Log.println("instr: " + ob + " -> " + ib);
}
}
public String toString() {
for(Port d : dest) {
Ship.Inbox ib = fleet.getInbox(d.ship, d.port);
ib.add(val);
- System.out.println("instr: " + val + " -> " + ib);
+ Log.println("instr: " + val + " -> " + ib);
}
}
public String toString() {
for(Port d : dest) {
Ship.Inbox ib = fleet.getInbox(d.ship, d.port);
ib.add(cb.getIdentifier());
- System.out.println("instr: codebag #" + cb.getIdentifier() + " -> " + ib);
+ Log.println("instr: codebag #" + cb.getIdentifier() + " -> " + ib);
}
}
public String toString() {
int data = ob.data.remove();
Inbox destination = ob.destination.remove();
destination.add(data);
- System.out.println("data: " + ob + " ----("+data+")----> " + destination);
+ Log.println("data: " + ob + " ----("+data+")----> " + destination);
}
}
service();
--- /dev/null
+package edu.berkeley.fleet;
+
+import de.mud.telnet.*;
+import de.mud.telnet.modules.*;
+import de.mud.telnet.display.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.border.*;
+import java.net.*;
+import java.io.*;
+
+public class Term extends vt320 implements ComponentListener {
+ private final InputStream is;
+ private final OutputStream os;
+
+ public Term(InputStream is, OutputStream os) { this.is = is; this.os = os; addComponentListener(this); }
+
+ public void componentResized(ComponentEvent e) { repaint(); }
+ public void componentMoved(ComponentEvent e) { }
+ public void componentHidden(ComponentEvent e) { }
+ public void componentShown(ComponentEvent e) { }
+
+ private class ListenerThread extends Thread {
+ public void run() {
+ try {
+ byte[] buf = new byte[1024];
+ while(true) {
+ int numread = is.read(buf, 0, buf.length);
+ if (numread==-1) break;
+ if (numread==0) continue;
+ Term.this.putString(new String(buf, 0, numread, "US-ASCII"));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ boolean listenerStarted = false;
+ public void paint(Graphics g) {
+ if (!listenerStarted) { listenerStarted = true; new ListenerThread().start(); }
+ super.paint(g);
+ }
+ public synchronized void putString(String s) { super.putString(s); }
+ public synchronized boolean send(String s) {
+ try {
+ os.write(s.getBytes("US-ASCII"));
+ os.flush();
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+}
// define the initial contents of memory
-
#memory { 000, 100, 200, 300, 400, 500 }
+// preload the counter register
+4 -> i.write
+i.writedone -> gate.release
+gate.codebag <- top
+
top: { i.read -> less.in1
0 -> less.in2
less.out -> ifthen.if
1000 -> adder.in2
adder.out -> memwrite.data
memwrite.done -> gate.release
- gate.codebag <- write
+ gate.codebag <- {
+ i.read -> adder2.in1
+ -1 -> adder2.in2
+ adder2.out -> i.write
+ i.writedone -> gate2.release
+ gate2.codebag <- top
+ }
}
-write: {
- i.read -> adder2.in1
- -1 -> adder2.in2
- adder2.out -> i.write
- i.writedone -> gate2.release
- gate2.codebag <- top
-}
-
-
-4 -> i.write
-i.writedone -> gate.release
-gate.codebag <- top
-//1 -> adder.in1
-//1 -> adder.in2
-//adder.out -> memread.addr
-//memread.data -> adder.in1
-//13 -> adder.in2
-//
-//adder.out -> less.in1
-//214 -> less.in2
-//less.out -> ifthen.if
-//{ 7 -> halt.in } -> ifthen.then
-//{ 9 -> halt.in } -> ifthen.else