dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;

import java.awt.*;
import java.awt.event.*;

public class ANSI_ClientDisplay extends Canvas implements AdjustmentListener {
    public int lineHeight;
    public int charWidth;
    public int offset;
    int numColumns = 80;
    int numRows = 24;

    public static Color[] colors = {
        Color.black, new Color(192, 0, 0), new Color(0, 192, 0), new Color(192, 192, 0),
        new Color(0, 0, 192), new Color(192, 0, 192), new Color(0, 192, 192), new Color(192, 192, 192),
        new Color(64, 64, 64), new Color(255, 64, 64), new Color(64, 255, 64), new Color(255, 255, 64),
        new Color(64, 64, 255), new Color(255, 64, 255), new Color(64, 255, 255), new Color(255, 255, 255)
    };

    private Socket inputSocket;
    private final static int MAX_LINES = 500;
    private ANSI_ClientString[] lines = new ANSI_ClientString[MAX_LINES];
    private int numLines = 0;
    private Scrollbar scrolly;
    private InputStreamHandler in;

    private Image offScrImg = null;
    private Graphics offScrGc = null;
    private Dimension dim = null;

    private char ANSI_buffer[] = new char[80];
    private char ANSI_bufferLength = 0;
    private boolean escFound = false;
    private boolean bracketFound = false;
    boolean reverse = false;
    int newColorIndex = 7;
    int newBackIndex = 0;

    private boolean foundIAC = false;
    private int termCount = 0;

    public final static char IS = 0;
    public final static char SEND = 1;
    public final static char NAWS = 31;
    public final static char TERM = 24;
    public final static char COMPRESS = 85;
    public final static char COMPRESS2 = 86;
    public final static char GA = 239;
    public final static char SE = 240;
    public final static char SB = 250;
    public final static char WILL = 251;
    public final static char WONT = 252;
    public final static char DO = 253;
    public final static char DONT = 254;
    public final static char IAC = 255;

    /** Means we're allowed to send window size each time it's changed.
     *  Set to true after the first IAC DO NAWS is received from the
     *  server. (I.e., after we know the server is willing to accept
     *  NAWS.)
     */
    private boolean enabledNAWS = false;

    private class InputStreamHandler extends Thread {
        private Socket sock;
        private InputStream in; 
	     private InflaterInputStream comp;
        private OutputStream out;
        private boolean closed = false;
        private boolean enabledCOMP = false;

        public InputStreamHandler(String host, int port) {
            try {
                sock = new Socket(host, port);
                in = sock.getInputStream();
                out = sock.getOutputStream();
                setDaemon(true);
                start();
            }
            catch (Exception e) {
                e.printStackTrace();
                add(e.toString());
                close();
                repaint();
            }
            
        }

        public synchronized void close() {
            closed = true;
            try {
                in.close();
            }
            catch (Exception e) {
            }
            try {
                out.close();
            }
            catch (Exception e) {
            }
            try {
                sock.close();
            }
            catch (Exception e) {
            }
            try {
            	comp.close();
	         }
            catch (Exception e) {
            }
        }
        
        public void compressedStream() {        	                      
			  enabledCOMP = true;
			  comp = new InflaterInputStream (in);
			}

        public void run() {
            String line;
            int c=0 ;
            int len;

            try {
					while (!closed)
					{
			            if (enabledCOMP) {
			            	if (comp.available() == 0) {
			 			   	   repaint();
							   }
								c = comp.read();								
							}				
						   else 
						   {
						   	if (in.available() == 0) {
							   	repaint();
								}
			                  c = in.read();
			            }
			            
	                 if (c == -1) {
	                        add("Connection lost.");
	                        break;
	                 }
	                 
	                 add((char)c);
	             }
				}
				   
		      catch (IOException e) {
               add("Connection lost.");
            }
            finally {
                close();
                repaint();
            }

        }

        public synchronized void send(byte s[]) {
            if (!closed) {
                try {
                    out.write(s);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
            repaint();
        }

        public synchronized void send(byte s[], int length) {
            if (!closed) {
                try {
                    out.write(s, 0, length);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
            repaint();
        }

        public synchronized void send(String s) {
            send(s.getBytes());
            repaint();
        }
    }
    
    public ANSI_ClientDisplay(String host, int port, Scrollbar myScrollBar) {
        this(myScrollBar);
        connect(host, port);
    }

    public ANSI_ClientDisplay(Scrollbar myScrollBar) {
        super();
        setBackground(Color.black);

        scrolly = myScrollBar;
        scrolly.addAdjustmentListener(this);

        add("Simple Java MUD Client v1.02, by Cristian Golumbovici (JagdTiger/Moraelin)");
    }

    public void setFont(Font f) {
        super.setFont(f);
        FontMetrics fm = getFontMetrics(f);
        charWidth = fm.charWidth('w');
        lineHeight = fm.getHeight();
        numColumns = getSize().width / charWidth; 
    }

    public synchronized void connect(String host, int port) {
        close();
        in = new InputStreamHandler(host, port);
    }

    public synchronized void close() {
        if (in != null) {
            in.close();
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(80 * charWidth, 24 * lineHeight);
    }

    public Dimension getMinimumSize() {
        return new Dimension(80 * charWidth, 24 * lineHeight);
    }

    public synchronized void addLine(ANSI_ClientString s) {
        if (numLines == MAX_LINES) {
            System.arraycopy(lines, 1, lines, 0, MAX_LINES - 1);
            lines[MAX_LINES - 1] = s;
            repaint();
        }
        else {
            lines[numLines++] = s;
            scrolly.setMaximum(numLines * lineHeight);
        }
        scrolly.setValue(Math.max(0, numLines * lineHeight - getSize().height));
    }

    public synchronized void appendChar(char c) {
        ANSI_ClientString line = lines[numLines - 1];
        line.append(c);
        if (line.visibleLength > numColumns) {
            int breakPos = line.lastIndexOf(' ', numColumns);
            if (breakPos > 0) {
                breakPos++;
                ANSI_ClientString newLine = line.substring(breakPos);
                lines[numLines - 1] = line.substring(0, breakPos);
                addLine(newLine);
            }
        }
    }

    public synchronized void add(String s) {
        if (numLines > 0) {
            if (lines[numLines - 1].length == 0) {
                numLines--;
            }
        }
        ANSI_ClientString s1 = new ANSI_ClientString("\uFF0B" + s);
        s1.isEchoText = true;
        addLine(s1);
        addLine(new ANSI_ClientString());
    }

    public synchronized void add(char c) {
        if (numLines == 0) {
            addLine(new ANSI_ClientString());
        }
        repaint();
        
        // here I deal with the telnet RFC's
        if (foundIAC) {
            if (ANSI_bufferLength == 0) {
                // twice IAC means I actually have received a printable character
                // 255, not a command
                if (c == IAC) {
                    appendChar(c);
                    foundIAC = false;
                }
                else if (c == DO || c == WILL || c == WONT || c == SB ||
                	c == COMPRESS2) {
                    ANSI_buffer[ANSI_bufferLength++] = c;
                }
                else {
                    foundIAC = false;
                }
            }
            else if (ANSI_bufferLength == 1) {
                if (ANSI_buffer[0] == WILL) {                    
                		if (c == COMPRESS2) {
		                  in.send ("" + IAC + DO + COMPRESS2);
		                  
	                 }
                
                    in.send("" + IAC + DONT + c);
                    foundIAC = false;
        
                }
                else if (ANSI_buffer[0] == DO) {

        					if (c == NAWS) {
                        in.send("" + IAC + WILL + NAWS);
                        in.send("" + IAC + SB + NAWS +
                             (char)0 + 
                             (char)numColumns +
                             (char)0 +
                             (char)numRows + 
                             IAC + SE);
                        enabledNAWS = true;
                    }
                    else if (c == TERM) {                   
                        in.send("" + IAC + WILL + TERM);
                        termCount = 0;
                    }
                    else {
                        in.send("" + IAC + WONT + c);
                    }
                    foundIAC = false;
                }
                else if (ANSI_buffer[0] != SB) {
                    foundIAC = false;
                }
                else {
                    ANSI_buffer[ANSI_bufferLength++] = c;      
                                  
                }
            }
			               
            else if (c == SE) {
                if (ANSI_bufferLength == 4 &&
                    ANSI_buffer[0] == SB &&
                    ANSI_buffer[1] == TERM &&
                    ANSI_buffer[2] == SEND &&
                    ANSI_buffer[3] == IAC) {

                    if (termCount == 0) {
                        in.send("" + IAC + SB + TERM + IS + "ANSI" + IAC + SE);
                        termCount = 1;
                    }
                    else if (termCount == 1) {
                        in.send("" + IAC + SB + TERM + IS + "VT100" + IAC + SE);
                        termCount = 2;
                    }
                    else {
                        in.send("" + IAC + SB + TERM + IS + "UNKNOWN" + IAC + SE);
                        termCount = 0;
                    }
                }

            	if (ANSI_bufferLength == 3 &&
                        ANSI_buffer[0] == SB &&
		                  ANSI_buffer[1] == COMPRESS2 &&
		                  ANSI_buffer[2] == IAC)
		                  {
		                  	in.compressedStream();
			               }

                foundIAC = false;
            }
            else if (ANSI_bufferLength < 80) {
                ANSI_buffer[ANSI_bufferLength++] = c;
            }
        }
        // and here starts ANSI/VT100 support
        else if (escFound) {
            escFound = false;
            if (c == '[') {
                bracketFound = true;
                ANSI_bufferLength = 0;
            }
            // basically, ESC Z means "are you a VT100?", and I say "yes"
            else if (c == 'Z') {
                send("\u001b[?1;0c");
            }
        }
        else if (bracketFound) {
            // some terminal querying. It's not entirely accurate, but
            // it should make DW recognize this as an ANSI terminal.
            // (Later: it doesn't. *SIGH*)
            if (c == 'n') {
                // request terminal status -- answer: no malfunction
                if (ANSI_bufferLength == 1 && ANSI_buffer[0] == '5') {
                    send("\u001b[0n");
                }
                // request cursor position -- answer: a bogus position
                else if (ANSI_bufferLength == 1 && ANSI_buffer[0] == '6') {
                    send("\u001b[24;0R");
                }
                else if (ANSI_bufferLength == 3 && 
                         ANSI_buffer[0] == '2' &&
                         ANSI_buffer[1] == '5' &&
                         ANSI_buffer[2] == '5') {
                    send("\u001b[" + (getSize().height / Math.max(1, lineHeight)) + ";80R");
                }
            }
            // color codes
            else if (c == 'm') {
                if (ANSI_bufferLength == 0) {
                    newColorIndex = 7;
                    newBackIndex = 0;
                    reverse = false;
                }
                else if (ANSI_bufferLength == 1) {
                    if (ANSI_buffer[0] == '1') {
                        newColorIndex |= 8;
                    }
                    else if (ANSI_buffer[0] == '2') {
                        newColorIndex &= 7;
                    }
                    else if (ANSI_buffer[0] == '7') {
                        reverse = true;
                    }
                    else if (ANSI_buffer[0] == '8') {
                        newColorIndex = newBackIndex;
                    }
                    else if (ANSI_buffer[0] == '0') {
                        //newColorIndex &= 7;
                        newColorIndex = 7;
                        newBackIndex = 0;
                        reverse = false;
                    }
                }
                else if (ANSI_bufferLength == 2 && ANSI_buffer[0] == '3') {
                    int col = ANSI_buffer[1] - '0';
                    if (col > 7) {
                        col = 7;
                    }
                    newColorIndex = (newColorIndex & 8) | col;
                }
                else if (ANSI_bufferLength == 2 && ANSI_buffer[0] == '4') {
                    newBackIndex = ANSI_buffer[1] - '0';
                    if (newBackIndex > 7) {
                        newBackIndex = 0;
                    }
                }
                bracketFound = false;
                ANSI_ClientString.currentColorIndex = newColorIndex + 16 * newBackIndex + (reverse ? 128 : 0);
                add((char)('\uFF00' + ANSI_ClientString.currentColorIndex));
            }
            else if (c == ';') {
                if (ANSI_bufferLength == 1) {
                    if (ANSI_buffer[0] == '1') {
                        newColorIndex |= 8;
                    }
                    else if (ANSI_buffer[0] == '2') {
                        newColorIndex &= 7;
                    }
                    else if (ANSI_buffer[0] == '7') {
                        reverse = true;
                    }
                    else if (ANSI_buffer[0] == '8') {
                        newColorIndex = newBackIndex;
                    }
                    else if (ANSI_buffer[0] == '0') {
                        //newColorIndex &= 7;
                        newColorIndex = 7;
                        newBackIndex = 0;
                        reverse = false;
                    }
                }
                else if (ANSI_bufferLength == 2 && ANSI_buffer[0] == '3') {
                    int col = ANSI_buffer[1] - '0';
                    if (col > 7) {
                        col = 7;
                    }
                    newColorIndex = (newColorIndex & 8) | col;
                }
                else if (ANSI_bufferLength == 2 && ANSI_buffer[0] == '4') {
                    newBackIndex = ANSI_buffer[1] - '0';
                    if (newBackIndex > 7) {
                        newBackIndex = 0;
                    }
                }
                ANSI_bufferLength = 0;
            }
            else if (c >= '0' && c <= '9') {
                if (ANSI_bufferLength < 80) {
                    ANSI_buffer[ANSI_bufferLength++] = c;
                }
            }
            else {
                bracketFound = false;
            }
        }
        else if (c == '\u001B') {
            escFound = true;
            newColorIndex = ANSI_ClientString.currentColorIndex & 15;
            newBackIndex = (ANSI_ClientString.currentColorIndex >> 4) & 7;
            reverse = (ANSI_ClientString.currentColorIndex & 128) != 0;
        }
        else if (c == '\n') {
            addLine(new ANSI_ClientString());
        }
        else if (c < ' ' && c != '\u001b') {
        }
        else if (c == IAC) {
            ANSI_bufferLength = 0;
            foundIAC = true;
        }
        else {
            appendChar(c);
        }
    }

    public void update(Graphics g) {
        paint(g);
    }

    public synchronized void paint(Graphics g) {
        Dimension d = getSize();
        if (dim == null ||
            offScrGc == null ||
            dim.width != d.width ||
            dim.height != d.height) {

            offScrImg = createImage(d.width, d.height);
            offScrGc = offScrImg.getGraphics();
        }

        Font f = getFont();
        offScrGc.setFont(f);
        FontMetrics fm = getFontMetrics(f);
        lineHeight = fm.getHeight();
        charWidth = fm.charWidth('w');
        int prevRows = numRows;
        int prevColumns = numColumns;
        numColumns = Math.min(127, d.width / charWidth);
        numRows = Math.min(127, d.height / charWidth);

        if (enabledNAWS && (numColumns != prevColumns || numRows != prevRows)) {
            // screen size has chaged, and the server requested NAWS.
            // (Negotiate About Window Size)
            in.send("" + IAC + SB + NAWS +
                    (char)0 +
                    (char)numColumns+
                    (char)0 +
                    (char)numRows +
                    IAC + SE);
        }

        scrolly.setMaximum(numLines * lineHeight);
        scrolly.setVisibleAmount(d.height);
        scrolly.setBlockIncrement(Math.max(lineHeight, d.height - lineHeight));
        scrolly.setUnitIncrement(lineHeight);

        offScrGc.setColor(Color.black);
        offScrGc.fillRect(0, 0, d.width, d.height);

        offset = scrolly.getValue();
        int ascent = offScrGc.getFontMetrics(f).getAscent();
        int i = Math.max(0, offset / lineHeight);
        int y = ascent - offset + i * lineHeight;
        for (; i < numLines; i ++, y += lineHeight) {
            if (y < 0) {
                continue;
            }
            drawANSI_ClientString(offScrGc, lines[i], y - ascent, y);
        }
        g.drawImage(offScrImg, 0, 0, d.width, d.height, null);
    }

    private void drawANSI_ClientString(Graphics g, ANSI_ClientString ms, int y, int baselineY) {
        int colorIndex = ms.colorIndex & 15;
        int backIndex = (ms.colorIndex >> 4) & 8;
        boolean reverse = (ms.colorIndex & 128) == 128;
        int x = 0;
        int prevIndex = 0;

        for (int i = 0; i < ms.length; i++) {
            if ((ms.buf[i] & '\uFF00') == '\uFF00') {
                if (backIndex != 0 || reverse) {
                    g.setColor(colors[reverse ? colorIndex : backIndex]);
                    g.fillRect(x, y, (i - prevIndex) * charWidth, lineHeight);
                }
                g.setColor(colors[reverse ? backIndex : colorIndex]);
                g.drawChars(ms.buf, prevIndex, i - prevIndex, x, baselineY);
                x += (i - prevIndex) * charWidth;
                prevIndex = i + 1;

                colorIndex = ms.buf[i] & 15;
                backIndex = (ms.buf[i] >> 4) & 8;
                reverse = (ms.buf[i] & 128) == 128;
            }
        }
        if (ms.length > prevIndex) {
            if (backIndex != 0 || reverse) {
                g.setColor(colors[reverse ? colorIndex : backIndex]);
                g.fillRect(x, y, (ms.length - prevIndex) * charWidth, lineHeight);
            }
            g.setColor(colors[reverse ? backIndex : colorIndex]);
            g.drawChars(ms.buf, prevIndex, ms.length - prevIndex, x, baselineY);
        }

        /*
        if (ms.isEchoText) {
            return ms.colorIndex;
        }
        return colorIndex + (backIndex << 4) + (reverse ? 128 : 0);
        */
    }

    // basically, here I take care of doubling any instance of character 255,
    // as required by RFC 854 (telnet protocol)
    public synchronized void send(char src[]) {
        if (in == null) {
            return;
        }
        // since worst case is having all 255's, i.e., all doubled,
        // twice the original number of chars is guaranteed to be enough.
        byte dst[] = new byte[2 * src.length + 1];
        int dstIndex = 0;
        for (int i = 0; i < src.length; i++) {
            char c = src[i];
            if (c > 255) {
                c = ' ';
            }
            dst[dstIndex++] = (byte)c;
            if (c == 255) {
                dst[dstIndex++] = (byte)255;
            }
        }
        dst[dstIndex++] = (byte)'\n';
        in.send(dst, dstIndex);
        repaint();
    }

    public synchronized void send(String s) {
        add(s);
        send(s.toCharArray());
        repaint();
    }

    public void adjustmentValueChanged(AdjustmentEvent e) {
        int newOffset = scrolly.getValue();
        if (offset != newOffset) {
            repaint();
        }
    }

    public synchronized void pgUp() {
        scrolly.setValue(Math.max(0, scrolly.getValue() - getSize().height));
        repaint();
    }

    public synchronized void pgDown() {
        scrolly.setValue(Math.max(0, Math.min(numLines * lineHeight - getSize().height, scrolly.getValue() + getSize().height)));
        repaint();
    }
}