You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by gn...@apache.org on 2016/03/21 17:53:07 UTC

svn commit: r1735995 [4/4] - in /felix/trunk/gogo: ./ jline/ jline/doc/ jline/src/ jline/src/main/ jline/src/main/java/ jline/src/main/java/org/ jline/src/main/java/org/apache/ jline/src/main/java/org/apache/felix/ jline/src/main/java/org/apache/felix/...

Added: felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.gogo.jline.telnet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import org.apache.felix.gogo.jline.Shell;
+import org.apache.felix.gogo.jline.Shell.Context;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.jline.builtins.Options;
+import org.jline.terminal.Size;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.Terminal.Signal;
+import org.jline.terminal.TerminalBuilder;
+
+/*
+ * a very simple Telnet server.
+ * real remote access should be via ssh.
+ */
+public class Telnet {
+    public static final String[] functions = {"telnetd"};
+
+    private static final int defaultPort = 2019;
+    private final CommandProcessor processor;
+    private PortListener portListener;
+    private int port;
+    private String ip;
+
+    public Telnet(CommandProcessor procesor) {
+        this.processor = procesor;
+    }
+
+    public void telnetd(CommandSession session, String[] argv) throws IOException {
+        final String[] usage = {"telnetd - start simple telnet server",
+                "Usage: telnetd [-i ip] [-p port] start | stop | status",
+                "  -i --ip=INTERFACE        listen interface (default=127.0.0.1)",
+                "  -p --port=PORT           listen port (default=" + defaultPort + ")",
+                "  -? --help                show help"};
+
+        Options opt = Options.compile(usage).parse(argv);
+        List<String> args = opt.args();
+
+        if (opt.isSet("help") || args.isEmpty()) {
+            opt.usage(System.err);
+            return;
+        }
+
+        String command = args.get(0);
+
+        if ("start".equals(command)) {
+            if (portListener != null) {
+                throw new IllegalStateException("telnetd is already running on port " + port);
+            }
+            ip = opt.get("ip");
+            port = opt.getNumber("port");
+            start(session);
+            status();
+        } else if ("stop".equals(command)) {
+            if (portListener == null) {
+                throw new IllegalStateException("telnetd is not running.");
+            }
+            stop();
+        } else if ("status".equals(command)) {
+            status();
+        } else {
+            throw opt.usageError("bad command: " + command);
+        }
+    }
+
+    private void status() {
+        if (portListener != null) {
+            System.out.println("telnetd is running on " + ip + ":" + port);
+        } else {
+            System.out.println("telnetd is not running.");
+        }
+    }
+
+    private void start(CommandSession session) throws IOException {
+        ConnectionManager connectionManager = new ConnectionManager(1000, 5 * 60 * 1000, 5 * 60 * 1000, 60 * 1000, null, null, false) {
+            @Override
+            protected Connection createConnection(ThreadGroup threadGroup, ConnectionData newCD) {
+                return new Connection(threadGroup, newCD) {
+                    TelnetIO telnetIO;
+
+                    @Override
+                    protected void doRun() throws Exception {
+                        telnetIO = new TelnetIO();
+                        telnetIO.setConnection(this);
+                        telnetIO.initIO();
+
+                        InputStream in = new InputStream() {
+                            @Override
+                            public int read() throws IOException {
+                                return telnetIO.read();
+                            }
+                            @Override
+                            public int read(byte[] b, int off, int len) throws IOException {
+                                int r = read();
+                                if (r >= 0) {
+                                    b[off] = (byte) r;
+                                    return 1;
+                                } else {
+                                    return -1;
+                                }
+                            }
+                        };
+                        PrintStream out = new PrintStream(new OutputStream() {
+                            @Override
+                            public void write(int b) throws IOException {
+                                telnetIO.write(b);
+                            }
+                            @Override
+                            public void flush() throws IOException {
+                                telnetIO.flush();
+                            }
+                        });
+                        Terminal terminal = TerminalBuilder.builder()
+                                .type(getConnectionData().getNegotiatedTerminalType().toLowerCase())
+                                .streams(in, out)
+                                .system(false)
+                                .name("telnet")
+                                .build();
+                        terminal.setSize(new Size(getConnectionData().getTerminalColumns(), getConnectionData().getTerminalRows()));
+                        terminal.setAttributes(Shell.getTerminal(session).getAttributes());
+                        addConnectionListener(new ConnectionListener() {
+                            @Override
+                            public void connectionIdle(ConnectionEvent ce) {
+                            }
+
+                            @Override
+                            public void connectionTimedOut(ConnectionEvent ce) {
+                            }
+
+                            @Override
+                            public void connectionLogoutRequest(ConnectionEvent ce) {
+                            }
+
+                            @Override
+                            public void connectionSentBreak(ConnectionEvent ce) {
+                            }
+
+                            @Override
+                            public void connectionTerminalGeometryChanged(ConnectionEvent ce) {
+                                terminal.setSize(new Size(getConnectionData().getTerminalColumns(), getConnectionData().getTerminalRows()));
+                                terminal.raise(Signal.WINCH);
+                            }
+                        });
+                        PrintStream pout = new PrintStream(terminal.output());
+                        CommandSession session = processor.createSession(terminal.input(), pout, pout);
+                        Context context = new Context() {
+                            @Override
+                            public String getProperty(String name) {
+                                return System.getProperty(name);
+                            }
+                            @Override
+                            public void exit() throws Exception {
+                                close();
+                            }
+                        };
+                        new Shell(context, processor, terminal).gosh(session, new String[]{"--login"});
+                    }
+
+                    @Override
+                    protected void doClose() throws Exception {
+                        telnetIO.closeOutput();
+                        telnetIO.closeInput();
+                    }
+                };
+            }
+        };
+        portListener = new PortListener("gogo", port, 10);
+        portListener.setConnectionManager(connectionManager);
+        portListener.start();
+    }
+
+    private void stop() throws IOException {
+        portListener.stop();
+        portListener = null;
+    }
+
+}

Added: felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/TelnetIO.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/TelnetIO.java?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/TelnetIO.java (added)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/TelnetIO.java Mon Mar 21 16:53:06 2016
@@ -0,0 +1,1548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/***
+ * Java TelnetD library (embeddable telnet daemon)
+ * Copyright (c) 2000-2005 Dieter Wimberger
+ * All rights reserved.
+ * <p/>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * <p/>
+ * Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * <p/>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ***/
+
+package org.apache.felix.gogo.jline.telnet;
+
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.felix.gogo.jline.telnet.ConnectionEvent.Type;
+
+/**
+ * Class that represents the TelnetIO implementation. It contains
+ * an inner IACHandler class to handle the telnet protocol level
+ * communication.
+ * <p/>
+ * Although supposed to work full-duplex, we only process the telnet protocol
+ * layer communication in case of reading requests from the higher levels.
+ * This is the only way to meet the one thread per connection requirement.
+ * </p>
+ * <p/>
+ * The output is done via byte-oriented streams, definately suitable for the
+ * telnet protocol. The format of the  output is UTF-8 (Unicode), which is a
+ * standard and supported by any telnet client, including the ones included
+ * in Microsoft OS's.
+ * </p>
+ * <em>Notes:</em>
+ * <ul>
+ * <li>The underlying output is buffered, to ensure that all bytes written
+ * are send, the flush() method has to be called.
+ * <li>This low-level routines ensure nice multithreading behaviour on I/O.
+ * Neither large outputs, nor input sequences excuted by the connection thread
+ * can hog the system.
+ * </ul>
+ *
+ * @author Dieter Wimberger
+ * @version 2.0 (16/07/2006)
+ */
+public class TelnetIO {
+
+    /**
+     * Interpret As Command
+     */
+    protected static final int IAC = 255;
+    /**
+     * Go Ahead <BR> Newer Telnets do not make use of this option
+     * that allows a specific communication mode.
+     */
+    protected static final int GA = 249;
+    /**
+     * Negotiation: Will do option
+     */
+    protected static final int WILL = 251;
+    /**
+     * Negotiation: Wont do option
+     */
+    protected static final int WONT = 252;
+    /**
+     * Negotiation: Do option
+     */
+    protected static final int DO = 253;
+    /**
+     * Negotiation:  Dont do option
+     */
+    protected static final int DONT = 254;
+    /**
+     * Marks start of a subnegotiation.
+     */
+    protected static final int SB = 250;
+    /**
+     * Marks end of subnegotiation.
+     */
+    protected static final int SE = 240;
+    /**
+     * No operation
+     */
+    protected static final int NOP = 241;
+    /**
+     * Data mark its the data part of a SYNCH which helps to clean up the buffers between
+     * Telnet Server &lt;-&gt; Telnet Client. <BR>
+     * It should work like this we send a TCP urgent package and &lt;IAC&gt; &lt;DM&gt; the receiver
+     * should get the urgent package (SYNCH) and just discard everything until he receives
+     * our &lt;IAC&gt; &lt;DM&gt;.<BR>
+     * <EM>Remark</EM>:
+     * <OL>
+     * <LI>can we send a TCP urgent package?
+     * <LI>can we make use of the thing at all?
+     * </OL>
+     */
+    protected static final int DM = 242;
+    /**
+     * Break
+     */
+    protected static final int BRK = 243;
+    /**
+     * Interrupt Process
+     */
+    protected static final int IP = 244;
+    /**
+     * Abort Output
+     */
+    protected static final int AO = 245;
+
+    /**** Implementation of OutputStream ****************************************************/
+    /**
+     * Are You There
+     */
+    protected static final int AYT = 246;
+    /**
+     * Erase Char
+     */
+    protected static final int EC = 247;
+    /**
+     * Erase Line
+     */
+    protected static final int EL = 248;
+    /**
+     * Telnet Option: ECHO
+     */
+    protected static final int ECHO = 1;
+    /**
+     * Telnet Option: SUPress Go Ahead<br>
+     * This will be negotiated, all new telnet protocol implementations are
+     * recommended to do this.
+     */
+    protected static final int SUPGA = 3;
+    /**
+     * Telnet Option: Negotiate About Window Size<br>
+     * <ul>
+     * <li>Server request is IAC DO NAWS
+     * <li>Client response contains subnegotiation with data (columns, rows).
+     * </ul>
+     */
+    protected static final int NAWS = 31;
+    /**
+     * Telnet Option: Terminal TYPE <br>
+     * <ul>
+     * <li>Server request contains subnegotiation SEND
+     * <li>Client response contains subnegotiation with data IS,terminal type string
+     * </ul>
+     */
+    protected static final int TTYPE = 24;
+    /**
+     * TTYPE subnegotiation: IS
+     */
+    protected static final int IS = 0;
+    /**
+     * TTYPE subnegotiation: SEND
+     */
+    protected static final int SEND = 1;
+
+    /**** End implementation of OutputStream ***********************************************/
+
+
+    /**** Implementation of InputStream ****************************************************/
+    /**
+     * Telnet Option: Logout<br>
+     * This allows nice goodbye to time-outed or unwanted clients.
+     */
+    protected static final int LOGOUT = 18;
+    /**
+     * Telnet Option: Linemode
+     * <p/>
+     * The infamous line mode option.
+     */
+    protected static final int LINEMODE = 34;
+    protected static final int LM_MODE = 1;
+    protected static final int LM_EDIT = 1;
+    protected static final int LM_TRAPSIG = 2;
+
+    /**** Implementation of InputStream ****************************************************/
+
+
+    /****
+     * Following methods implement init/request/answer procedures for telnet
+     * protocol level communication.
+     */
+    protected static final int LM_MODEACK = 4;
+    protected static final int LM_FORWARDMASK = 2;
+    protected static final int LM_SLC = 3;
+    protected static final int LM_SLC_NOSUPPORT = 0;
+    protected static final int LM_SLC_DEFAULT = 3;
+
+
+    /**** End telnet protocol level communication methods *******************************/
+    protected static final int LM_SLC_VALUE = 2;
+
+
+    /** Constants declaration ***********************************************/
+
+//Telnet Protocoll Constants
+    protected static final int LM_SLC_CANTCHANGE = 1;
+    protected static final int LM_SLC_LEVELBITS = 3;
+    protected static final int LM_SLC_ACK = 128;
+    protected static final int LM_SLC_FLUSHIN = 64;
+    protected static final int LM_SLC_FLUSHOUT = 32;
+    protected static final int LM_SLC_SYNCH = 1;
+    protected static final int LM_SLC_BRK = 2;
+    protected static final int LM_SLC_IP = 3;
+    protected static final int LM_SLC_AO = 4;
+    protected static final int LM_SLC_AYT = 5;
+    protected static final int LM_SLC_EOR = 6;
+
+    /**
+     * The following implement the NVT (network virtual terminal) which offers the concept
+     * of a simple "printer". They are the basical meanings of control possibilities
+     * on a standard telnet implementation.
+     */
+    protected static final int LM_SLC_ABORT = 7;
+    protected static final int LM_SLC_EOF = 8;
+    protected static final int LM_SLC_SUSP = 9;
+    /**
+     * Telnet Option: Environment
+     */
+    protected static final int NEWENV = 39;
+    protected static final int NE_INFO = 2;
+
+    /**
+     * The following are constants for supported options,
+     * which can be negotiated based upon the telnet protocol
+     * specification.
+     */
+    protected static final int NE_VAR = 0;
+    protected static final int NE_VALUE = 1;
+
+    /**
+     * The following options are options for which we also support subnegotiation
+     * based upon the telnet protocol specification.
+     */
+    protected static final int NE_ESC = 2;
+    protected static final int NE_USERVAR = 3;
+    protected static final int NE_VAR_OK = 2;
+    protected static final int NE_VAR_DEFINED = 1;
+    protected static final int NE_VAR_DEFINED_EMPTY = 0;
+    protected static final int NE_VAR_UNDEFINED = -1;
+    protected static final int NE_IN_ERROR = -2;
+    protected static final int NE_IN_END = -3;
+    protected static final int NE_VAR_NAME_MAXLENGTH = 50;
+    protected static final int NE_VAR_VALUE_MAXLENGTH = 1000;
+    /**
+     * Unused
+     */
+    protected static final int EXT_ASCII = 17;        //Defines Extended ASCII
+    protected static final int SEND_LOC = 23;        //Defines Send Location
+    protected static final int AUTHENTICATION = 37;    //Defines Authentication
+    protected static final int ENCRYPT = 38;            //Defines Encryption
+    private static final Logger LOG = Logger.getLogger(TelnetIO.class.getName());
+    /**
+     * Window Size Constants
+     */
+    private static final int SMALLEST_BELIEVABLE_WIDTH = 20;
+    private static final int SMALLEST_BELIEVABLE_HEIGHT = 6;
+    private static final int DEFAULT_WIDTH = 80;
+    private static final int DEFAULT_HEIGHT = 25;
+    private Connection connection;                    //a reference to the connection this instance works for
+    private ConnectionData connectionData;            //holds all important information of the connection
+    private DataOutputStream out;                    //the byte oriented outputstream
+    private DataInputStream in;                        //the byte oriented input stream
+    //Aggregations
+    private IACHandler iacHandler;                    //holds a reference to the aggregated IACHandler
+    //Members
+    private InetAddress localAddress;                //address of the host the telnetd is running on
+    private boolean noIac = false;                    //describes if IAC was found and if its just processed
+    private boolean initializing;
+    private boolean crFlag;
+    /**
+     * Creates a TelnetIO object for the given connection.<br>
+     * Input- and OutputStreams are properly set and the primary telnet
+     * protocol initialization is carried out by the inner IACHandler class.<BR>
+     */
+    public TelnetIO() {
+    }//constructor
+
+    public void initIO() throws IOException {
+        //we make an instance of our inner class
+        iacHandler = new IACHandler();
+        //we setup underlying byte oriented streams
+        in = new DataInputStream(connectionData.getSocket().getInputStream());
+        out = new DataOutputStream(new BufferedOutputStream(connectionData.getSocket().getOutputStream()));
+
+        //we save the local address (necessary?)
+        localAddress = connectionData.getSocket().getLocalAddress();
+        crFlag = false;
+        //bootstrap telnet communication
+        initTelnetCommunication();
+    }//initIO
+
+    public void setConnection(Connection con) {
+        connection = con;
+        connectionData = connection.getConnectionData();
+    }//setConnection
+
+    /**
+     * Method to output a byte. Ensures that CR(\r) is never send
+     * alone,but CRLF(\r\n), which is a rule of the telnet protocol.
+     *
+     * @param b Byte to be written.
+     */
+    public void write(byte b) throws IOException {
+        //ensure CRLF(\r\n) is written for LF(\n) to adhere
+        //to the telnet protocol.
+        if (!crFlag && b == 10) {
+            out.write(13);
+        }
+
+        out.write(b);
+
+        if (b == 13) {
+            crFlag = true;
+        } else {
+            crFlag = false;
+        }
+    }//write(byte)
+
+    /**
+     * Method to output an int.
+     *
+     * @param i Integer to be written.
+     */
+    public void write(int i)
+            throws IOException {
+        write((byte) i);
+    }//write(int)
+
+    /**
+     * Method to write an array of bytes.
+     *
+     * @param sequence byte[] to be written.
+     */
+    public void write(byte[] sequence) throws IOException {
+        for (byte b : sequence) {
+            write(b);
+        }
+    }//write(byte[])
+
+    /**
+     * Method to output an array of int' s.
+     *
+     * @param sequence int [] to write
+     */
+    public void write(int[] sequence) throws IOException {
+        for (int i : sequence) {
+            write((byte) i);
+        }
+    }//write(int[])
+
+    /**
+     * Method to write a char.
+     *
+     * @param ch char to be written.
+     */
+    public void write(char ch) throws IOException {
+        write((byte) ch);
+    }//write(char)
+
+    /**
+     * Method to output a string.
+     *
+     * @param str String to be written.
+     */
+    public void write(String str) throws IOException {
+        write(str.getBytes());
+    }//write(String)
+
+    /**
+     * Method to flush all buffered output.
+     */
+    public void flush() throws IOException {
+        out.flush();
+    }//flush
+
+    /**
+     * Method to close the underlying output stream to free system resources.<br>
+     * Most likely only to be called by the ConnectionManager upon clean up of
+     * connections that ended or died.
+     */
+    public void closeOutput() {
+
+        try {
+            //sends telnetprotocol logout acknowledgement
+            write(IAC);
+            write(DO);
+            write(LOGOUT);
+            //and now close underlying outputstream
+
+            out.close();
+        } catch (IOException ex) {
+            LOG.log(Level.SEVERE, "closeOutput()", ex);
+            //handle?
+        }
+    }//close
+
+    private void rawWrite(int i) throws IOException {
+        out.write(i);
+    }//rawWrite
+
+    /**
+     * Method to read a byte from the InputStream.
+     * Invokes the IACHandler upon IAC (Byte=255).
+     *
+     * @return int read from stream.
+     */
+    public int read() throws IOException {
+        int c = rawread();
+        //if (c == 255) {
+        noIac = false;
+        while ((c == 255) && (!noIac)) {
+            /**
+             * Read next, and invoke
+             * the IACHandler he is taking care of the rest. Or at least he should :)
+             */
+            c = rawread();
+            if (c != 255) {
+                iacHandler.handleC(c);
+                c = rawread();
+            } else {
+                noIac = true;
+            }
+        }
+        return stripCRSeq(c);
+    }//read
+
+    /**
+     * Method to close the underlying inputstream to free system resources.<br>
+     * Most likely only to be called by the ConnectionManager upon clean up of
+     * connections that ended or died.
+     */
+    public void closeInput() {
+        try {
+            in.close();
+        } catch (IOException e) {
+            //handle?
+        }
+    }//closeInput
+
+    /**
+     * This method reads an unsigned 16bit Integer from the stream,
+     * its here for getting the NAWS Data Values for height and width.
+     */
+    private int read16int() throws IOException {
+        int c = in.readUnsignedShort();
+        return c;
+    }//read16int
+
+    /**
+     * The following options are options which might be of interest, but are not
+     * yet implemented or in use.
+     */
+
+    /**
+     * Method to read a raw byte from the InputStream.<br>
+     * Telnet protocol layer communication is filtered and processed here.
+     *
+     * @return int read from stream.
+     */
+    private int rawread() throws IOException {
+        int b = 0;
+
+        //try {
+        b = in.readUnsignedByte();
+        connectionData.activity();
+        return b;
+    }//rawread
+
+    /**
+     * Checks for the telnet protocol specified  CR followed by NULL or LF<BR>
+     * Subsequently reads for the next byte and forwards
+     * only a ENTER represented by LF internally.
+     */
+    private int stripCRSeq(int input) throws IOException {
+        if (input == 13) {
+            rawread();
+            return 10;
+        }
+        return input;
+    }//stripCRSeq
+
+    /**
+     * Method that initializes the telnet communication layer.
+     */
+    private void initTelnetCommunication() {
+
+        initializing = true;
+        try {
+            //start out, some clients just wait
+            if (connectionData.isLineMode()) {
+                iacHandler.doLineModeInit();
+                LOG.log(Level.FINE, "Line mode initialized.");
+            } else {
+                iacHandler.doCharacterModeInit();
+                LOG.log(Level.FINE, "Character mode initialized.");
+            }
+            //open for a defined timeout so we read incoming negotiation
+            connectionData.getSocket().setSoTimeout(1000);
+            read();
+
+        } catch (Exception e) {
+            //handle properly
+            //log.error("initTelnetCommunication()",e);
+        } finally {
+            //this is important, dont ask me why :)
+            try {
+                connectionData.getSocket().setSoTimeout(0);
+            } catch (Exception ex) {
+                LOG.log(Level.SEVERE, "initTelnetCommunication()", ex);
+            }
+        }
+        initializing = false;
+    }//initTelnetCommunication
+
+    /**
+     * Method that represents the answer to the
+     * AreYouThere question of the telnet protocol specification
+     * <p/>
+     * Output of the String [HostAdress:Yes]
+     */
+    private void IamHere() {
+        try {
+            write("[" + localAddress.toString() + ":Yes]");
+            flush();
+        } catch (Exception ex) {
+            LOG.log(Level.SEVERE, "IamHere()", ex);
+        }
+    }//IamHere
+
+    /**
+     * Network virtual terminal break.
+     */
+    private void nvtBreak() {
+        connection.processConnectionEvent(new ConnectionEvent(connection, ConnectionEvent.Type.CONNECTION_BREAK));
+    }//nvtBreak
+
+    /**
+     * Method that checks reported terminal sizes and sets the
+     * asserted values in the ConnectionData instance associated with
+     * the connection.
+     *
+     * @param width  Integer that represents the Window width in chars
+     * @param height Integer that represents the Window height in chars
+     */
+    private void setTerminalGeometry(int width, int height) {
+        if (width < SMALLEST_BELIEVABLE_WIDTH) {
+            width = DEFAULT_WIDTH;
+        }
+        if (height < SMALLEST_BELIEVABLE_HEIGHT) {
+            height = DEFAULT_HEIGHT;
+        }
+        //DEBUG: write("[New Window Size " + window_width + "x" + window_height + "]");
+        connectionData.setTerminalGeometry(width, height);
+        connection.processConnectionEvent(new ConnectionEvent(connection,
+                Type.CONNECTION_TERMINAL_GEOMETRY_CHANGED));
+    }//setTerminalGeometry
+
+    public void setEcho(boolean b) {
+    }//setEcho
+
+    /**
+     * An inner class for handling incoming option negotiations implementing the <B>telnet protocol</B>
+     * specification based upon following Standards and RFCs:
+     * <OL>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc854.txt">854 Telnet Protocol Specification</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc855.txt">855 Telnet Option Specifications</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc857.txt">857 Telnet Echo Option</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc858.txt">858 Telnet Supress Go Ahead Option</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc727.txt">727 Telnet Logout Option</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc1073.txt">1073 Telnet Window Size Option</A>
+     * <LI><A HREF="ftp://ds.internic.net/rfc/rfc1091.txt">1091 Telnet Terminal-Type Option</A>
+     * </OL>
+     * <p/>
+     * Furthermore there are some more, which helped to solve problems, or might be important
+     * for future enhancements:<BR>
+     * <A HREF="ftp://ds.internic.net/rfc/rfc1143.txt">1143 The Q Method of Implementing Option Negotiation</A><BR>
+     * <A HREF="ftp://ds.internic.net/rfc/rfc1416.txt">1416 Telnet Authentication Option</A><BR>
+     * <p/>
+     * After an intense study of the available material (mainly cryptical written RFCs,
+     * a telnet client implementation for the macintosh based upon NCSA telnet, and a server side
+     * implementation called key, a mud-like system completely written in Java) I realized
+     * the problems we are facing regarding to the telnet protocol:
+     * <OL>
+     * <LI> a minimal spread of invented options, which means there are a lot of invented options,
+     * but rarely they made it through to become a standard.
+     * <LI> Dependency on a special type of implementation is dangerous in our case.
+     * We are no kind of host that offers the user to run several processes at once,
+     * a BBS is intended to be a single process the user is interacting with.
+     * <LI> The <B>LAMER</B> has to be expected to log in with the standard Microsoft telnet
+     * implementation. This means forget every nice feature and most of the almost-standards.
+     * <p/>
+     * </OL>
+     * <BR>
+     *
+     * @author Dieter Wimberger
+     * @version 1.1 16/06/1998
+     * <p/>
+     * <p/>
+     * <B>To-Do</B>:<UL>
+     * <LI>UNIX conform new style TTYPE negotiation. Setting a list and selecting from it...
+     * </UL>
+     */
+    class IACHandler {
+
+        /**
+         * Telnet readin buffer
+         * Here its implemented guys. Open your eyes upon this solution.
+         * The others take a one byte solution :)
+         */
+        private int[] buffer = new int[2];
+
+        /**
+         * DO_ECHO or not
+         */
+        private boolean DO_ECHO = false;
+
+        /**
+         * DO_SUPGA or not
+         */
+        private boolean DO_SUPGA = false;
+
+        /**
+         * DO_NAWS or not
+         */
+        private boolean DO_NAWS = false;
+
+        /**
+         * DO_TTYPE or not
+         */
+        private boolean DO_TTYPE = false;
+
+        /**
+         * DO_LINEMODE or not
+         */
+        private boolean DO_LINEMODE = false;
+
+        /**
+         * DO_NEWENV or not
+         */
+        private boolean DO_NEWENV = false;
+
+        /**
+         * Are we waiting for a DO reply?
+         */
+        private boolean WAIT_DO_REPLY_SUPGA = false;
+        private boolean WAIT_DO_REPLY_ECHO = false;
+        private boolean WAIT_DO_REPLY_NAWS = false;
+        private boolean WAIT_DO_REPLY_TTYPE = false;
+        private boolean WAIT_DO_REPLY_LINEMODE = false;
+        private boolean WAIT_LM_MODE_ACK = false;
+        private boolean WAIT_LM_DO_REPLY_FORWARDMASK = false;
+        private boolean WAIT_DO_REPLY_NEWENV = false;
+        private boolean WAIT_NE_SEND_REPLY = false;
+
+        /**
+         * Are we waiting for a WILL reply?
+         */
+        private boolean WAIT_WILL_REPLY_SUPGA = false;
+        private boolean WAIT_WILL_REPLY_ECHO = false;
+        private boolean WAIT_WILL_REPLY_NAWS = false;
+        private boolean WAIT_WILL_REPLY_TTYPE = false;
+
+
+        public void doCharacterModeInit() throws IOException {
+            sendCommand(WILL, ECHO, true);
+            sendCommand(DONT, ECHO, true); //necessary for some clients
+            sendCommand(DO, NAWS, true);
+            sendCommand(WILL, SUPGA, true);
+            sendCommand(DO, SUPGA, true);
+            sendCommand(DO, TTYPE, true);
+            sendCommand(DO, NEWENV, true); //environment variables
+        }//doCharacterModeInit
+
+        public void doLineModeInit() throws IOException {
+            sendCommand(DO, NAWS, true);
+            sendCommand(WILL, SUPGA, true);
+            sendCommand(DO, SUPGA, true);
+            sendCommand(DO, TTYPE, true);
+            sendCommand(DO, LINEMODE, true);
+            sendCommand(DO, NEWENV, true);
+        }//doLineModeInit
+
+
+        /**
+         * Method to handle a IAC that came in over the line.
+         *
+         * @param i (int)ed byte that followed the IAC
+         */
+        public void handleC(int i) throws IOException {
+            buffer[0] = i;
+            if (!parseTWO(buffer)) {
+                buffer[1] = rawread();
+                parse(buffer);
+            }
+            buffer[0] = 0;
+            buffer[1] = 0;
+        }//handleC
+
+        /**
+         * Method that parses for options with two characters.
+         *
+         * @param buf int [] that represents the first byte that followed the IAC first.
+         * @return true when it was a two byte command (IAC OPTIONBYTE)
+         */
+        private boolean parseTWO(int[] buf) {
+            switch (buf[0]) {
+                case IAC:
+                    //doubled IAC to escape 255 is handled within the
+                    //read method.
+                    break;
+                case AYT:
+                    IamHere();
+                    break;
+                case AO:
+                case IP:
+                case EL:
+                case EC:
+                case NOP:
+                    break;
+                case BRK:
+                    nvtBreak();
+                    break;
+                default:
+                    return false;
+            }
+            return true;
+        }//parseTWO
+
+        /**
+         * Method that parses further on for options.
+         *
+         * @param buf that represents the first two bytes that followed the IAC.
+         */
+        private void parse(int[] buf) throws IOException {
+            switch (buf[0]) {
+        /* First switch on the Negotiation Option */
+                case WILL:
+                    if (supported(buf[1]) && isEnabled(buf[1])) {
+                        ;// do nothing
+                    } else {
+                        if (waitDOreply(buf[1]) && supported(buf[1])) {
+                            enable(buf[1]);
+                            setWait(DO, buf[1], false);
+                        } else {
+                            if (supported(buf[1])) {
+                                sendCommand(DO, buf[1], false);
+                                enable(buf[1]);
+                            } else {
+                                sendCommand(DONT, buf[1], false);
+                            }
+                        }
+                    }
+                    break;
+                case WONT:
+                    if (waitDOreply(buf[1]) && supported(buf[1])) {
+                        setWait(DO, buf[1], false);
+                    } else {
+                        if (supported(buf[1]) && isEnabled(buf[1])) {
+                            // eanable() Method disables an Option that is already enabled
+                            enable(buf[1]);
+                        }
+                    }
+                    break;
+                case DO:
+                    if (supported(buf[1]) && isEnabled(buf[1])) {
+                        ; // do nothing
+                    } else {
+                        if (waitWILLreply(buf[1]) && supported(buf[1])) {
+                            enable(buf[1]);
+                            setWait(WILL, buf[1], false);
+                        } else {
+                            if (supported(buf[1])) {
+                                sendCommand(WILL, buf[1], false);
+                                enable(buf[1]);
+                            } else {
+                                sendCommand(WONT, buf[1], false);
+                            }
+                        }
+                    }
+                    break;
+                case DONT:
+                    if (waitWILLreply(buf[1]) && supported(buf[1])) {
+                        setWait(WILL, buf[1], false);
+                    } else {
+                        if (supported(buf[1]) && isEnabled(buf[1])) {
+                            // enable() Method disables an Option that is already enabled
+                            enable(buf[1]);
+                        }
+                    }
+                    break;
+
+          /* Now about other two byte IACs */
+                case DM:    //How do I implement a SYNCH signal?
+                    break;
+                case SB: //handle subnegotiations
+                    if ((supported(buf[1])) && (isEnabled(buf[1]))) {
+                        switch (buf[1]) {
+                            case NAWS:
+                                handleNAWS();
+                                break;
+                            case TTYPE:
+                                handleTTYPE();
+                                break;
+                            case LINEMODE:
+                                handleLINEMODE();
+                                break;
+                            case NEWENV:
+                                handleNEWENV();
+                                break;
+                            default:
+                                ;
+                        }
+                    } else {
+                        //do nothing
+                    }
+                    break;
+                default:
+                    ;
+            }//switch
+        }//parse
+
+        /**
+         * Method that reads a NawsSubnegotiation that ends up with a IAC SE
+         * If the measurements are unbelieveable it switches to the defaults.
+         */
+        private void handleNAWS() throws IOException {
+            int width = read16int();
+            if (width == 255) {
+                width = read16int(); //handle doubled 255 value;
+            }
+            int height = read16int();
+            if (height == 255) {
+                height = read16int(); //handle doubled 255 value;
+            }
+            skipToSE();
+            setTerminalGeometry(width, height);
+        }//handleNAWS
+
+        /**
+         * Method that reads a TTYPE Subnegotiation String that ends up with a IAC SE
+         * If no Terminal is valid, we switch to the dumb "none" terminal.
+         */
+        private void handleTTYPE() throws IOException {
+            String tmpstr = "";
+            // The next read should be 0 which is IS by the protocol
+            // specs. hmmm?
+            rawread(); //that should be the is :)
+            tmpstr = readIACSETerminatedString(40);
+            LOG.log(Level.FINE, "Reported terminal name " + tmpstr);
+            connectionData.setNegotiatedTerminalType(tmpstr);
+        }//handleTTYPE
+
+        /**
+         * Method that handles LINEMODE subnegotiation.
+         */
+        public void handleLINEMODE() throws IOException {
+            int c = rawread();
+            switch (c) {
+                case LM_MODE:
+                    handleLMMode();
+                    break;
+                case LM_SLC:
+                    handleLMSLC();
+                    break;
+                case WONT:
+                case WILL:
+                    handleLMForwardMask(c);
+                    break;
+                default:
+                    //skip to (including) SE
+                    skipToSE();
+            }
+        }//handleLINEMODE
+
+        public void handleLMMode() throws IOException {
+            //we sent the default which no client might deny
+            //so we only wait the ACK
+            if (WAIT_LM_MODE_ACK) {
+                int mask = rawread();
+                if (mask != (LM_EDIT | LM_TRAPSIG | LM_MODEACK)) {
+                    LOG.log(Level.FINE, "Client violates linemodeack sent: " + mask);
+                }
+                WAIT_LM_MODE_ACK = false;
+            }
+            skipToSE();
+        }//handleLMMode
+
+        public void handleLMSLC() throws IOException {
+            int[] triple = new int[3];
+            if (!readTriple(triple)) return;
+
+            //SLC will be initiated by the client
+            //case 1. client requests set
+            //LINEMODE SLC 0 SLC_DEFAULT 0
+            if ((triple[0] == 0) && (triple[1] == LM_SLC_DEFAULT) && (triple[2] == 0)) {
+                skipToSE();
+                //reply with SLC xxx SLC_DEFAULT 0
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(LINEMODE);
+                rawWrite(LM_SLC);
+                //triples defaults for all
+                for (int i = 1; i < 12; i++) {
+                    rawWrite(i);
+                    rawWrite(LM_SLC_DEFAULT);
+                    rawWrite(0);
+                }
+                rawWrite(IAC);
+                rawWrite(SE);
+                flush();
+            } else {
+
+                //case 2: just acknowledge anything we get from the client
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(LINEMODE);
+                rawWrite(LM_SLC);
+                rawWrite(triple[0]);
+                rawWrite(triple[1] | LM_SLC_ACK);
+                rawWrite(triple[2]);
+                while (readTriple(triple)) {
+                    rawWrite(triple[0]);
+                    rawWrite(triple[1] | LM_SLC_ACK);
+                    rawWrite(triple[2]);
+                }
+                rawWrite(IAC);
+                rawWrite(SE);
+                flush();
+            }
+        }//handleLMSLC
+
+        public void handleLMForwardMask(int WHAT) throws IOException {
+            switch (WHAT) {
+                case WONT:
+                    if (WAIT_LM_DO_REPLY_FORWARDMASK) {
+                        WAIT_LM_DO_REPLY_FORWARDMASK = false;
+                    }
+                    break;
+            }
+            skipToSE();
+        }//handleLMForward
+
+        public void handleNEWENV() throws IOException {
+            LOG.log(Level.FINE, "handleNEWENV()");
+            int c = rawread();
+            switch (c) {
+                case IS:
+                    handleNEIs();
+                    break;
+                case NE_INFO:
+                    handleNEInfo();
+                    break;
+                default:
+                    //skip to (including) SE
+                    skipToSE();
+            }
+        }//handleNEWENV
+
+        /*
+          The characters following a "type" up to the next "type" or VALUE specify the
+          variable name.
+
+          If a "type" is not followed by a VALUE
+          (e.g., by another VAR, USERVAR, or IAC SE) then that variable is
+          undefined.
+         */
+        private int readNEVariableName(StringBuffer sbuf) throws IOException {
+            LOG.log(Level.FINE, "readNEVariableName()");
+            int i = -1;
+            do {
+                i = rawread();
+                if (i == -1) {
+                    return NE_IN_ERROR;
+                } else if (i == IAC) {
+                    i = rawread();
+                    if (i == IAC) {
+                        //duplicated IAC
+                        sbuf.append((char) i);
+                    } else if (i == SE) {
+                        return NE_IN_END;
+                    } else {
+                        //Error should have been duplicated
+                        return NE_IN_ERROR;
+                    }
+                } else if (i == NE_ESC) {
+                    i = rawread();
+                    if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                        sbuf.append((char) i);
+                    } else {
+                        return NE_IN_ERROR;
+                    }
+                } else if (i == NE_VAR || i == NE_USERVAR) {
+                    return NE_VAR_UNDEFINED;
+                } else if (i == NE_VALUE) {
+                    return NE_VAR_DEFINED;
+                } else {
+                    //check maximum length to prevent overflow
+                    if (sbuf.length() >= NE_VAR_NAME_MAXLENGTH) {
+                        //TODO: Log Overflow
+                        return NE_IN_ERROR;
+                    } else {
+                        sbuf.append((char) i);
+                    }
+                }
+            } while (true);
+        }//readNEVariableName
+
+
+        /*
+          The characters following a VALUE up to the next
+          "type" specify the value of the variable.
+          If a VALUE is immediately
+          followed by a "type" or IAC, then the variable is defined, but has
+          no value.
+          If an IAC is contained between the IS and the IAC SE,
+          it must be sent as IAC IAC.
+        */
+        private int readNEVariableValue(StringBuffer sbuf) throws IOException {
+            LOG.log(Level.FINE, "readNEVariableValue()");
+            //check conditions for first character after VALUE
+            int i = rawread();
+            if (i == -1) {
+                return NE_IN_ERROR;
+            } else if (i == IAC) {
+                i = rawread();
+                if (i == IAC) {
+                    //Double IAC
+                    return NE_VAR_DEFINED_EMPTY;
+                } else if (i == SE) {
+                    return NE_IN_END;
+                } else {
+                    //according to rule IAC has to be duplicated
+                    return NE_IN_ERROR;
+                }
+            } else if (i == NE_VAR || i == NE_USERVAR) {
+                return NE_VAR_DEFINED_EMPTY;
+            } else if (i == NE_ESC) {
+                //escaped value
+                i = rawread();
+                if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                    sbuf.append((char) i);
+                } else {
+                    return NE_IN_ERROR;
+                }
+            } else {
+                //character
+                sbuf.append((char) i);
+            }
+            //loop until end of value (IAC SE or TYPE)
+            do {
+                i = rawread();
+                if (i == -1) {
+                    return NE_IN_ERROR;
+                } else if (i == IAC) {
+                    i = rawread();
+                    if (i == IAC) {
+                        //duplicated IAC
+                        sbuf.append((char) i);
+                    } else if (i == SE) {
+                        return NE_IN_END;
+                    } else {
+                        //Error should have been duplicated
+                        return NE_IN_ERROR;
+                    }
+                } else if (i == NE_ESC) {
+                    i = rawread();
+                    if (i == NE_ESC || i == NE_VAR || i == NE_USERVAR || i == NE_VALUE) {
+                        sbuf.append((char) i);
+                    } else {
+                        return NE_IN_ERROR;
+                    }
+                } else if (i == NE_VAR || i == NE_USERVAR) {
+                    return NE_VAR_OK;
+                } else {
+                    //check maximum length to prevent overflow
+                    if (sbuf.length() > NE_VAR_VALUE_MAXLENGTH) {
+                        //TODO: LOG Overflow
+                        return NE_IN_ERROR;
+                    } else {
+                        sbuf.append((char) i);
+                    }
+                }
+            } while (true);
+        }//readNEVariableValue
+
+
+        public void readNEVariables() throws IOException {
+            LOG.log(Level.FINE, "readNEVariables()");
+            StringBuffer sbuf = new StringBuffer(50);
+            int i = rawread();
+            if (i == IAC) {
+                //invalid or empty response
+                skipToSE();
+                LOG.log(Level.FINE, "readNEVariables()::INVALID VARIABLE");
+                return;
+            }
+            boolean cont = true;
+            if (i == NE_VAR || i == NE_USERVAR) {
+                do {
+                    switch (readNEVariableName(sbuf)) {
+                        case NE_IN_ERROR:
+                            LOG.log(Level.FINE, "readNEVariables()::NE_IN_ERROR");
+                            return;
+                        case NE_IN_END:
+                            LOG.log(Level.FINE, "readNEVariables()::NE_IN_END");
+                            return;
+                        case NE_VAR_DEFINED:
+                            LOG.log(Level.FINE, "readNEVariables()::NE_VAR_DEFINED");
+                            String str = sbuf.toString();
+                            sbuf.delete(0, sbuf.length());
+                            switch (readNEVariableValue(sbuf)) {
+                                case NE_IN_ERROR:
+                                    LOG.log(Level.FINE, "readNEVariables()::NE_IN_ERROR");
+                                    return;
+                                case NE_IN_END:
+                                    LOG.log(Level.FINE, "readNEVariables()::NE_IN_END");
+                                    return;
+                                case NE_VAR_DEFINED_EMPTY:
+                                    LOG.log(Level.FINE, "readNEVariables()::NE_VAR_DEFINED_EMPTY");
+                                    break;
+                                case NE_VAR_OK:
+                                    //add variable
+                                    LOG.log(Level.FINE, "readNEVariables()::NE_VAR_OK:VAR=" + str + " VAL=" + sbuf.toString());
+                                    TelnetIO.this.connectionData.getEnvironment().put(str, sbuf.toString());
+                                    sbuf.delete(0, sbuf.length());
+                                    break;
+                            }
+                            break;
+                        case NE_VAR_UNDEFINED:
+                            LOG.log(Level.FINE, "readNEVariables()::NE_VAR_UNDEFINED");
+                            break;
+                    }
+                } while (cont);
+            }
+        }//readVariables
+
+        public void handleNEIs() throws IOException {
+            LOG.log(Level.FINE, "handleNEIs()");
+            if (isEnabled(NEWENV)) {
+                readNEVariables();
+            }
+        }//handleNEIs
+
+        public void handleNEInfo() throws IOException {
+            LOG.log(Level.FINE, "handleNEInfo()");
+            if (isEnabled(NEWENV)) {
+                readNEVariables();
+            }
+        }//handleNEInfo
+
+        /**
+         * Method that sends a TTYPE Subnegotiation Request.
+         * IAC SB TERMINAL-TYPE SEND
+         */
+        public void getTTYPE() throws IOException {
+            if (isEnabled(TTYPE)) {
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(TTYPE);
+                rawWrite(SEND);
+                rawWrite(IAC);
+                rawWrite(SE);
+                flush();
+            }
+        }//getTTYPE
+
+        /**
+         * Method that sends a LINEMODE MODE Subnegotiation request.
+         * IAC LINEMODE MODE MASK SE
+         */
+        public void negotiateLineMode() throws IOException {
+            if (isEnabled(LINEMODE)) {
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(LINEMODE);
+                rawWrite(LM_MODE);
+                rawWrite(LM_EDIT | LM_TRAPSIG);
+                rawWrite(IAC);
+                rawWrite(SE);
+                WAIT_LM_MODE_ACK = true;
+
+                //dont forwardmask
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(LINEMODE);
+                rawWrite(DONT);
+                rawWrite(LM_FORWARDMASK);
+                rawWrite(IAC);
+                rawWrite(SE);
+                WAIT_LM_DO_REPLY_FORWARDMASK = true;
+                flush();
+            }
+        }//negotiateLineMode
+
+        /**
+         * Method that sends a NEW-ENVIRON SEND subnegotiation request
+         * for default variables and user variables.
+         * IAC SB NEW-ENVIRON SEND VAR USERVAR IAC SE
+         */
+        private void negotiateEnvironment() throws IOException {
+            //log.debug("negotiateEnvironment()");
+            if (isEnabled(NEWENV)) {
+                rawWrite(IAC);
+                rawWrite(SB);
+                rawWrite(NEWENV);
+                rawWrite(SEND);
+                rawWrite(NE_VAR);
+                rawWrite(NE_USERVAR);
+                rawWrite(IAC);
+                rawWrite(SE);
+                WAIT_NE_SEND_REPLY = true;
+                flush();
+            }
+        }//negotiateEnvironment
+
+        /**
+         * Method that skips a subnegotiation response.
+         */
+        private void skipToSE() throws IOException {
+            while (rawread() != SE) ;
+        }//skipSubnegotiation
+
+        private boolean readTriple(int[] triple) throws IOException {
+            triple[0] = rawread();
+            triple[1] = rawread();
+            if ((triple[0] == IAC) && (triple[1] == SE)) {
+                return false;
+            } else {
+                triple[2] = rawread();
+                return true;
+            }
+        }//readTriple
+
+        /**
+         * Method that reads a subnegotiation String,
+         * one of those that end with a IAC SE combination.
+         * A maximum length is observed to prevent overflow.
+         *
+         * @return IAC SE terminated String
+         */
+        private String readIACSETerminatedString(int maxlength) throws IOException {
+            int where = 0;
+            char[] cbuf = new char[maxlength];
+            char b = ' ';
+            boolean cont = true;
+
+            do {
+                int i;
+                i = rawread();
+                switch (i) {
+                    case IAC:
+                        i = rawread();
+                        if (i == SE) {
+                            cont = false;
+                        }
+                        break;
+                    case -1:
+                        return (new String("default"));
+                    default:
+                }
+                if (cont) {
+                    b = (char) i;
+                    //Fix for overflow wimpi (10/06/2004)
+                    if (b == '\n' || b == '\r' || where == maxlength) {
+                        cont = false;
+                    } else {
+                        cbuf[where++] = b;
+                    }
+                }
+            } while (cont);
+
+            return (new String(cbuf, 0, where));
+        }//readIACSETerminatedString
+
+        /**
+         * Method that informs internally about the supported Negotiation Options
+         *
+         * @param i int that represents requested the Option
+         * @return Boolean that represents support status
+         */
+        private boolean supported(int i) {
+            switch (i) {
+                case SUPGA:
+                case ECHO:
+                case NAWS:
+                case TTYPE:
+                case NEWENV:
+                    return true;
+                case LINEMODE:
+                    return connectionData.isLineMode();
+                default:
+                    return false;
+            }
+        }//supported
+
+        /**
+         * Method that sends a Telnet IAC String with TelnetIO.write(byte b) method.
+         *
+         * @param i int that represents requested Command Type (DO,DONT,WILL,WONT)
+         * @param j int that represents the Option itself (e.g. ECHO, NAWS)
+         */
+        private void sendCommand(int i, int j, boolean westarted) throws IOException {
+            rawWrite(IAC);
+            rawWrite(i);
+            rawWrite(j);
+            // we started with DO OPTION and now wait for reply
+            if ((i == DO) && westarted) setWait(DO, j, true);
+            // we started with WILL OPTION and now wait for reply
+            if ((i == WILL) && westarted) setWait(WILL, j, true);
+            flush();
+        }//sendCommand
+
+        /**
+         * Method enables or disables a supported Option
+         *
+         * @param i int that represents the Option
+         */
+        private void enable(int i) throws IOException {
+            switch (i) {
+                case SUPGA:
+                    if (DO_SUPGA) {
+                        DO_SUPGA = false;
+                    } else {
+                        DO_SUPGA = true;
+                    }
+                    break;
+                case ECHO:
+                    if (DO_ECHO) {
+                        DO_ECHO = false;
+                    } else {
+                        DO_ECHO = true;
+                    }
+                    break;
+                case NAWS:
+                    if (DO_NAWS) {
+                        DO_NAWS = false;
+                    } else {
+                        DO_NAWS = true;
+                    }
+                    break;
+                case TTYPE:
+                    if (DO_TTYPE) {
+                        DO_TTYPE = false;
+                    } else {
+                        DO_TTYPE = true;
+                        getTTYPE();
+                    }
+                    break;
+                case LINEMODE:
+                    if (DO_LINEMODE) {
+                        DO_LINEMODE = false;
+                        //set false in connection data, so the application knows.
+                        connectionData.setLineMode(false);
+                    } else {
+                        DO_LINEMODE = true;
+                        negotiateLineMode();
+                    }
+                    break;
+                case NEWENV:
+                    if (DO_NEWENV) {
+                        DO_NEWENV = false;
+                    } else {
+                        DO_NEWENV = true;
+                        negotiateEnvironment();
+                    }
+                    break;
+            }
+        }//enable
+
+        /**
+         * Method that informs internally about the status of the supported
+         * Negotiation Options.
+         *
+         * @param i int that represents requested the Option
+         * @return Boolean that represents the enabled status
+         */
+        private boolean isEnabled(int i) {
+            switch (i) {
+                case SUPGA:
+                    return DO_SUPGA;
+                case ECHO:
+                    return DO_ECHO;
+                case NAWS:
+                    return DO_NAWS;
+                case TTYPE:
+                    return DO_TTYPE;
+                case LINEMODE:
+                    return DO_LINEMODE;
+                case NEWENV:
+                    return DO_NEWENV;
+                default:
+                    return false;
+            }
+        }//isEnabled
+
+        /**
+         * Method that informs internally about the WILL wait status
+         * of an option.
+         *
+         * @param i that represents requested the Option
+         * @return Boolean that represents WILL wait status of the Option
+         */
+        private boolean waitWILLreply(int i) {
+            switch (i) {
+                case SUPGA:
+                    return WAIT_WILL_REPLY_SUPGA;
+                case ECHO:
+                    return WAIT_WILL_REPLY_ECHO;
+                case NAWS:
+                    return WAIT_WILL_REPLY_NAWS;
+                case TTYPE:
+                    return WAIT_WILL_REPLY_TTYPE;
+                default:
+                    return false;
+            }
+        }//waitWILLreply
+
+        /**
+         * Method that informs internally about the DO wait status
+         * of an option.
+         *
+         * @param i Integer that represents requested the Option
+         * @return Boolean that represents DO wait status of the Option
+         */
+        private boolean waitDOreply(int i) {
+            switch (i) {
+                case SUPGA:
+                    return WAIT_DO_REPLY_SUPGA;
+                case ECHO:
+                    return WAIT_DO_REPLY_ECHO;
+                case NAWS:
+                    return WAIT_DO_REPLY_NAWS;
+                case TTYPE:
+                    return WAIT_DO_REPLY_TTYPE;
+                case LINEMODE:
+                    return WAIT_DO_REPLY_LINEMODE;
+                case NEWENV:
+                    return WAIT_DO_REPLY_NEWENV;
+                default:
+                    return false;
+            }
+        }//waitDOreply
+
+        /**
+         * Method that mutates the wait status of an option in
+         * negotiation. We need the wait status to keep track of
+         * negotiation in process. So we cant miss if we started out
+         * or the other and so on.
+         *
+         * @param WHAT   Integer values of  DO or WILL
+         * @param OPTION Integer that represents the Option
+         * @param WAIT   Boolean that represents the status of wait that should be set
+         */
+        private void setWait(int WHAT, int OPTION, boolean WAIT) {
+            switch (WHAT) {
+                case DO:
+                    switch (OPTION) {
+                        case SUPGA:
+                            WAIT_DO_REPLY_SUPGA = WAIT;
+                            break;
+                        case ECHO:
+                            WAIT_DO_REPLY_ECHO = WAIT;
+                            break;
+                        case NAWS:
+                            WAIT_DO_REPLY_NAWS = WAIT;
+                            break;
+                        case TTYPE:
+                            WAIT_DO_REPLY_TTYPE = WAIT;
+                            break;
+                        case LINEMODE:
+                            WAIT_DO_REPLY_LINEMODE = WAIT;
+                            break;
+                        case NEWENV:
+                            WAIT_DO_REPLY_NEWENV = WAIT;
+                            break;
+                    }
+                    break;
+                case WILL:
+                    switch (OPTION) {
+                        case SUPGA:
+                            WAIT_WILL_REPLY_SUPGA = WAIT;
+                            break;
+                        case ECHO:
+                            WAIT_WILL_REPLY_ECHO = WAIT;
+                            break;
+                        case NAWS:
+                            WAIT_WILL_REPLY_NAWS = WAIT;
+                            break;
+                        case TTYPE:
+                            WAIT_WILL_REPLY_TTYPE = WAIT;
+                            break;
+                    }
+                    break;
+            }
+        }//setWait
+
+    }//inner class IACHandler
+
+    /** end Constants declaration **************************************************/
+
+}//class TelnetIO

Added: felix/trunk/gogo/jline/src/main/resources/gosh_profile
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/resources/gosh_profile?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/resources/gosh_profile (added)
+++ felix/trunk/gogo/jline/src/main/resources/gosh_profile Mon Mar 21 16:53:06 2016
@@ -0,0 +1,247 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# default gosh_profile
+# only read if etc/gosh_profile doesn't exist relative to the System property
+# gosh.home or failing that the current directory.
+
+# catch all exceptions from this script to avoid it aborting startup
+try {
+
+  # ensure gogo commands are found first
+  SCOPE = gogo:*
+
+  # add methods on BundleContext object as commands
+  addcommand context ${.context}
+
+  # add methods on System object as commands
+  #addcommand system (((${.context} getClass) getClassLoader) loadClass java.lang.System)
+
+  # alias to print full stack trace
+  e = { $exception printStackTrace }
+
+  ## disable console auto-formatting of each result
+  #  you will then need to explicitly use the 'format' command
+  #  to print the result of commands that don't write to stdout.
+  #.Gogo.format = false
+
+  ## disable printing the formatted result of a command into pipelines
+  #.Format.Pipe = false
+
+  # set prompt
+  prompt = 'g! '
+  \#rprompt = { (new java.text.SimpleDateFormat "HH:mm:ss") format (new Date) }
+
+
+  __option_not_present = {
+      res = true
+      opts = ([ $args ] get 0)
+      each $opts {
+          arg = $it
+          each ($.commandLine words) {
+              if { ($it toString) contentEquals ($arg toString) } {
+                  res = false
+              }
+          }
+      }
+      $res
+  }
+
+  __load_class = {
+      (($.reader class) classLoader) loadClass $1
+  }
+
+  __as_list = {
+      (__load_class java.util.Arrays) asList $1
+  }
+
+  __set_unset_arguments = {
+      is_setopt = (($.commandLine words) get 0) equals "setopt"
+      enums = ((__load_class 'org.jline.ConsoleReader$Option') enumConstants)
+      candidates = new ArrayList
+      each (__as_list $enums) {
+          name = ((($it name) toLowerCase) replace '_' '-')
+          is_set = ($.reader isSet $it)
+          neg = %(( if(is_setopt, is_set, not(is_set)) ))
+          if { $neg } {
+              name = "no-${name}"
+          }
+          if { not  { (($.commandLine words) subList 1 ($.commandLine wordIndex)) contains $name } } {
+              $candidates add (new org.jline.Candidate $name $name (if { $neg } { "unset" } { "set" }) null null null true)
+          }
+      }
+      $candidates
+  }
+
+  setopt pad-prompts
+  setopt group
+
+  complete -c gogo:complete -e
+  complete -c gogo:complete -d "Edit command specific completions"
+  complete -c gogo:complete -s c -l command --description "Command to add completion to" -n '__option_not_present -c --command' -a '$.commands'
+  complete -c gogo:complete -s s -l short-option --description "Posix-style option to complete" -n '__option_not_present -s --short-option'
+  complete -c gogo:complete -s l -l long-option --description "GNU-style option to complete" -n '__option_not_present -l --long-option'
+  complete -c gogo:complete -s a -l arguments --description "A list of possible arguments" -n '__option_not_present -a --argument'
+  complete -c gogo:complete -s d -l description --description "Description of this completions" -n '__option_not_present -d --description'
+  complete -c gogo:complete -s h -l help --description "Display help and exit" -n '__option_not_present -h --help'
+  complete -c gogo:complete -s n -l condition --description "The completion should only be used if the specified command has a zero exit status"  -n '__option_not_present -n --condition'
+  complete -c gogo:complete -s e -l erase --description "Remove completion"  -n '__option_not_present -e --erase'
+
+  complete -c gogo:history -e
+  complete -c gogo:history -d "Show and manipulate command history"
+  complete -c gogo:history -l clear --description "Clear history" -n '__option_not_present --clear'
+  complete -c gogo:history -l save --description "Save history" -n '__option_not_present --save'
+
+  complete -c gogo:setopt -e
+  complete -c gogo:setopt -d "Set or view set shell options"
+  complete -c gogo:setopt -a '__set_unset_arguments'
+
+  complete -c gogo:unsetopt -e
+  complete -c gogo:unsetopt -d "Unset or view unset shell options"
+  complete -c gogo:unsetopt -a '__set_unset_arguments'
+
+  complete -c gogo:cat -e
+  complete -c gogo:cat -d "Concatenate and print files"
+  complete -c gogo:cat -s n "Number the output lines, starting at 1"
+  complete -c gogo:cat -a '__files'
+
+  complete -c gogo:pwd -e
+  complete -c gogo:pwd -d "Get current directory"
+
+  complete -c gogo:ls -e
+  complete -c gogo:ls -d "List files"
+
+  complete -c gogo:cd -e
+  complete -c gogo:cd -d "Change current directory"
+  complete -c gogo:cd -a '__directories'
+
+  complete -c gogo:sleep -e
+  complete -c gogo:sleep -d "Pause execution for the specified amount of time"
+
+  complete -c gogo:echo -e
+  complete -c gogo:echo -d "Write arguments to the standard output"
+  complete -c gogo:echo -s n -d "No trailing new line"
+
+  complete -c gogo:grep -e
+  complete -c gogo:grep -d "File pattern searcher"
+  # TODO
+
+  complete -c gogo:sort -e
+  complete -c gogo:sort -d "Sort lines of text files"
+  # TODO
+
+  complete -c gogo:gosh -e
+  complete -c gogo:gosh -d "Execute script with arguments in a new session"
+  # TODO
+
+  complete -c gogo:sh -e
+  complete -c gogo:sh -d "Execute script with arguments in a new session"
+  # TODO
+
+  complete -c gogo:source -e
+  complete -c gogo:source -d "Execute script with arguments"
+  # TODO
+
+  # TODO: format getopt new set tac type addcommand removeCommand eval
+
+  complete -c gogo:each -e
+  complete -c gogo:each -d "Loop and execute script on the specified elements"
+
+  complete -c gogo:if -e
+  complete -c gogo:if -d "Conditionaly execute a script"
+
+  complete -c gogo:not -e
+  complete -c gogo:not -d "Negates the result of a script"
+
+  complete -c gogo:throw -e
+  complete -c gogo:throw -d "Throws an exception"
+
+  complete -c gogo:try -e
+  complete -c gogo:try -d "Try executing a script and catch any exception"
+
+  complete -c gogo:until -e
+  complete -c gogo:until -d "Loop and execute script until a condition is satisfied"
+
+  complete -c gogo:while -e
+  complete -c gogo:while -d "Loop and execute script while a condition is satisfied"
+
+  complete -c gogo:less -e
+  complete -c gogo:less -d "File pager"
+  complete -c gogo:less -s e -l quit-at-eof --description "Exit on second EOF"
+  complete -c gogo:less -s E -l QUIT-AT-EOF --description "Exit on EOF"
+  complete -c gogo:less -s q -l quiet -l silent --description "Silent mode"
+  complete -c gogo:less -s Q -l QUIET -l SILENT --description "Completely  silent"
+  complete -c gogo:less -s S -l chop-long-lines --description "Do not fold long lines"
+  complete -c gogo:less -s i -l ignore-case --description "Search ignores lowercase case"
+  complete -c gogo:less -s I -l IGNORE-CASE --description "Search ignores all case"
+  complete -c gogo:less -s x -l tabs --description "Set tab stops"
+  complete -c gogo:less -s N -l LINE-NUMBERS --description "Display line number for each line"
+  complete -c gogo:less -a '__files'
+
+  complete -c gogo:nano -e
+  complete -c gogo:nano -d "File editor"
+  complete -c gogo:nano -a '__files'
+
+  complete -c gogo:keymap -e
+  complete -c gogo:keymap -d "Manipulate keymaps"
+  complete -c gogo:keymap -s N --description "Create a new keymap" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s d --description "Delete existing keymaps and reset to default state" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s D --description "Delete named keymaps" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s l --description "List existing keymap names" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s r --description "Unbind specified in-strings" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s s --description "Bind each in-string to each out-string" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s A --description "Create alias to keymap" -n '__option_not_present -N -d -D -l -r -s -A'
+  complete -c gogo:keymap -s e --description "Select emacs keymap and bind it to main" -n '__option_not_present -e -a -v -M'
+  complete -c gogo:keymap -s v --description "Select viins keymap and bind it to main" -n '__option_not_present -e -a -v -M'
+  complete -c gogo:keymap -s a --description "Select vicmd keymap" -n '__option_not_present -e -a -v -M'
+  complete -c gogo:keymap -s M --description "Specify keymap to select" -n '__option_not_present -e -a -v -M' -a '(keymap -l | tac) split " "'
+  complete -c gogo:keymap -s R --description "Interpret in-strings as ranges"
+  complete -c gogo:keymap -s p --description "List bindings which have given key sequence as a a prefix"
+  complete -c gogo:keymap -s L --description "Output in form of keymap commands"
+
+  complete -c gogo:widget -e
+  complete -c gogo:widget -d "Manipulate widgets"
+  complete -c gogo:widget -s N --description "Create a new widget" -n '__option_not_present -N -A -D -U -l'
+  complete -c gogo:widget -s A --description "Create alias to widget" -n '__option_not_present -N -A -D -U -l'
+  complete -c gogo:widget -s D --description "Delete widgets" -n '__option_not_present -N -A -D -U -l'
+  complete -c gogo:widget -s U --description "Push characters to the stack" -n '__option_not_present -N -A -D -U -l'
+  complete -c gogo:widget -s l --description "List user-defined widgets" -n '__option_not_present -N -A -D -U -l'
+  complete -c gogo:widget -s a --description "With -l, list all widgets" -n '__option_not_present -l'
+
+  complete -c gogo:telnetd -e
+  complete -c gogo:telnetd -d "Telnet daemon"
+  complete -c gogo:telnetd -s i -l ip --description "Listening IP interface" -n '__option_not_present -i --ip'
+  complete -c gogo:telnetd -s p -l port --description "Listening IP port" -n '__option_not_present -p --port'
+  complete -c gogo:telnetd -a '[start stop status]'
+
+  complete -c gogo:sshd -e
+  complete -c gogo:sshd -d "SSH daemon"
+  complete -c gogo:sshd -s i -l ip --description "Listening IP interface" -n '__option_not_present -i --ip'
+  complete -c gogo:sshd -s p -l port --description "Listening IP port" -n '__option_not_present -p --port'
+  complete -c gogo:sshd -a '[start stop status]'
+
+  complete -c gogo:tmux -e
+  complete -c gogo:tmux -d "Terminal multiplexer"
+
+  # print welcome message
+  cat ($0 resolve motd)
+} {
+    echo "$0: ERROR: $exception"
+}
+
+# end

Added: felix/trunk/gogo/jline/src/main/resources/motd
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/resources/motd?rev=1735995&view=auto
==============================================================================
--- felix/trunk/gogo/jline/src/main/resources/motd (added)
+++ felix/trunk/gogo/jline/src/main/resources/motd Mon Mar 21 16:53:06 2016
@@ -0,0 +1,3 @@
+____________________________
+Welcome to Apache Felix Gogo
+

Modified: felix/trunk/gogo/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/pom.xml?rev=1735995&r1=1735994&r2=1735995&view=diff
==============================================================================
--- felix/trunk/gogo/pom.xml (original)
+++ felix/trunk/gogo/pom.xml Mon Mar 21 16:53:06 2016
@@ -40,6 +40,7 @@
     <modules>
     	<module>gogo-parent</module>
         <module>runtime</module>
+        <module>jline</module>
         <module>shell</module>
         <module>command</module>
     </modules>