You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2009/10/30 12:16:12 UTC

svn commit: r831265 - in /mina/sshd/trunk/sshd-core/src: main/java/org/apache/sshd/client/channel/ main/java/org/apache/sshd/common/ main/java/org/apache/sshd/common/util/ main/java/org/apache/sshd/server/ main/java/org/apache/sshd/server/channel/ test...

Author: gnodet
Date: Fri Oct 30 11:16:11 2009
New Revision: 831265

URL: http://svn.apache.org/viewvc?rev=831265&view=rev
Log:
SSHD-47: the pty terminal parameters are not available to the shell

Added:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/PtyMode.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/util/SttySupport.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/SttySupportTest.java
    mina/sshd/trunk/sshd-core/src/test/resources/org/
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-1.txt
    mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-2.txt
Modified:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java Fri Oct 30 11:16:11 2009
@@ -22,6 +22,9 @@
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.Buffer;
 
+import java.io.IOException;
+import java.io.InputStream;
+
 /**
  * TODO Add javadoc
  *
@@ -75,7 +78,7 @@
                 buffer.putInt(0);
                 int wpos2 = buffer.wpos(); // keep buffer position for data write
                 buffer.wpos(wpos2 + remoteWindow.getPacketSize()); // Make room
-                int len = in.read(buffer.array(), wpos2, remoteWindow.getPacketSize()); // read data into buffer
+                int len = securedRead(in, buffer.array(), wpos2, remoteWindow.getPacketSize()); // read data into buffer
                 if (len > 0) {
                     buffer.wpos(wpos1);
                     buffer.putInt(len);
@@ -86,7 +89,32 @@
                 }
             }
         } catch (Exception e) {
+            log.info("Caught exception", e);
             close(false);
         }
     }
+
+    //
+    // On some platforms, a call to System.in.read(new byte[65536], 0,32768) always throws an IOException.
+    // So we need to protect against that and chunk the call into smaller calls.
+    // This problem was found on Windows, JDK 1.6.0_03-b05.
+    //
+    protected int securedRead(InputStream in, byte[] buf, int off, int len) throws IOException {
+        int n = 0;
+        for (;;) {
+            int nread = in.read(buf, off + n, Math.min(1024, len - n));
+            if (nread <= 0) {
+                return (n == 0) ? nread : n;
+            }
+            n += nread;
+            if (n >= len) {
+                return n;
+            }
+            // if not closed but no bytes available, return
+            if (in != null && in.available() <= 0) {
+                return n;
+            }
+        }
+    }
+
 }

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java Fri Oct 30 11:16:11 2009
@@ -18,8 +18,13 @@
  */
 package org.apache.sshd.client.channel;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.SttySupport;
 
 /**
  * TODO Add javadoc
@@ -28,6 +33,96 @@
  */
 public class ChannelShell extends ChannelSession {
 
+    private String ptyType;
+    private int ptyColumns;
+    private int ptyLines;
+    private int ptyWidth;
+    private int ptyHeight;
+    private Map<PtyMode, Integer> ptyModes;
+
+    public ChannelShell() {
+        ptyType = System.getenv("TERM");
+        if (ptyType == null) {
+            ptyType = "dummy";
+        }
+        ptyColumns = 80;
+        ptyLines = 24;
+        ptyWidth = 640;
+        ptyHeight = 480;
+        // Set up default pty modes
+        ptyModes = new HashMap<PtyMode, Integer>();
+        ptyModes.put(PtyMode.ISIG, 1);
+        ptyModes.put(PtyMode.ICANON, 1);
+        ptyModes.put(PtyMode.ECHO, 1);
+        ptyModes.put(PtyMode.ECHOE, 1);
+        ptyModes.put(PtyMode.ECHOK, 1);
+        ptyModes.put(PtyMode.ECHONL, 0);
+        ptyModes.put(PtyMode.NOFLSH, 0);
+    }
+
+    public void setupSensibleDefaultPty() {
+        try {
+            String os = System.getProperty("os.name").toLowerCase();
+            if (os.indexOf("windows") < 0) {
+                ptyModes = SttySupport.getUnixPtyModes();
+                ptyColumns = SttySupport.getTerminalWidth();
+                ptyLines = SttySupport.getTerminalHeight();
+            } else {
+                ptyType = "windows";
+            }
+        } catch (Throwable t) {
+            // Ignore exceptions
+        }
+    }
+
+    public String getPtyType() {
+        return ptyType;
+    }
+
+    public void setPtyType(String ptyType) {
+        this.ptyType = ptyType;
+    }
+
+    public int getPtyColumns() {
+        return ptyColumns;
+    }
+
+    public void setPtyColumns(int ptyColumns) {
+        this.ptyColumns = ptyColumns;
+    }
+
+    public int getPtyLines() {
+        return ptyLines;
+    }
+
+    public void setPtyLines(int ptyLines) {
+        this.ptyLines = ptyLines;
+    }
+
+    public int getPtyWidth() {
+        return ptyWidth;
+    }
+
+    public void setPtyWidth(int ptyWidth) {
+        this.ptyWidth = ptyWidth;
+    }
+
+    public int getPtyHeight() {
+        return ptyHeight;
+    }
+
+    public void setPtyHeight(int ptyHeight) {
+        this.ptyHeight = ptyHeight;
+    }
+
+    public Map<PtyMode, Integer> getPtyModes() {
+        return ptyModes;
+    }
+
+    public void setPtyModes(Map<PtyMode, Integer> ptyModes) {
+        this.ptyModes = ptyModes;
+    }
+
     protected void doOpen() throws Exception {
         super.doOpen();
 
@@ -38,26 +133,16 @@
         buffer.putInt(recipient);
         buffer.putString("pty-req");
         buffer.putBoolean(false);
-        buffer.putString(System.getProperty("TERM", "dummy"));
-        buffer.putInt(80);
-        buffer.putInt(24);
-        buffer.putInt(640);
-        buffer.putInt(480);
+        buffer.putString(ptyType);
+        buffer.putInt(ptyColumns);
+        buffer.putInt(ptyLines);
+        buffer.putInt(ptyHeight);
+        buffer.putInt(ptyWidth);
         Buffer modes = new Buffer();
-        modes.putByte((byte) 50); // ISIG
-        modes.putInt(1);
-        modes.putByte((byte) 51); // ICANON
-        modes.putInt(1);
-        modes.putByte((byte) 53); // ECHO
-        modes.putInt(1);
-        modes.putByte((byte) 54); // ECHOE
-        modes.putInt(1);
-        modes.putByte((byte) 55); // ECHOK
-        modes.putInt(1);
-        modes.putByte((byte) 56); // ECHONL
-        modes.putInt(0);
-        modes.putByte((byte) 57); // NOFLSH
-        modes.putInt(0);
+        for (PtyMode mode : ptyModes.keySet()) {
+            modes.putByte((byte) mode.toInt());
+            modes.putInt(ptyModes.get(mode));
+        }
         modes.putByte((byte) 0);
         buffer.putBytes(modes.getCompactData());
         session.writePacket(buffer);
@@ -76,4 +161,5 @@
         session.writePacket(buffer);
 
     }
+
 }

Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/PtyMode.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/PtyMode.java?rev=831265&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/PtyMode.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/PtyMode.java Fri Oct 30 11:16:11 2009
@@ -0,0 +1,76 @@
+/*
+ * 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.sshd.common;
+
+import org.apache.sshd.server.ShellFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A enum describing the tty modes.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum PtyMode {
+
+    // Chars
+    VINTR(1), VQUIT(2), VERASE(3), VKILL(4), VEOF(5), VEOL(6), VEOL2(7), VSTART(8), VSTOP(9),
+    VSUSP(10), VDSUSP(11), VREPRINT(12), VWERASE(13), VLNEXT(14), VFLUSH(15), VSWTCH(16), VSTATUS(17), VDISCARD(18),
+
+    // I flags
+    IGNPAR(30), PARMRK(31), INPCK(32), ISTRIP(33), INLCR(34), IGNCR(35), ICRNL(36), IUCLC(37), IXON(38), IXANY(39),
+    IXOFF(40), IMAXBEL(41),
+
+    // L flags
+    ISIG(50), ICANON(51), XCASE(52), ECHO(53), ECHOE(54), ECHOK(55), ECHONL(56), NOFLSH(57), TOSTOP(58), IEXTEN(59),
+    ECHOCTL(60), ECHOKE(61), PENDIN(62),
+
+    // O flags
+    OPOST(70), OLCUC(71), ONLCR(72), OCRNL(73), ONOCR(74), ONLRET(75),
+
+    // C flags
+    CS7(90), CS8(91), PARENB(92), PARODD(93),
+
+    // Speeed
+    TTY_OP_ISPEED(128), TTY_OP_OSPEED(129);
+
+    private int v;
+
+    private PtyMode(int v) {
+        this.v = v;
+    }
+
+    public int toInt() {
+        return v;
+    }
+
+    static Map<Integer, PtyMode> commands;
+
+    static {
+        commands = new HashMap<Integer, PtyMode>();
+        for (PtyMode c : PtyMode.values()) {
+            commands.put(c.toInt(), c);
+        }
+    }
+
+    public static PtyMode fromInt(int b) {
+        return commands.get(0x00FF & (b + 256));
+    }
+}

Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/util/SttySupport.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/util/SttySupport.java?rev=831265&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/util/SttySupport.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/util/SttySupport.java Fri Oct 30 11:16:11 2009
@@ -0,0 +1,274 @@
+/*
+ * 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.sshd.common.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import org.apache.sshd.common.PtyMode;
+
+/**
+ * Support for stty command on unix
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SttySupport {
+
+    private static String sttyCommand = System.getProperty("sshd.sttyCommand", "stty");
+    private static String ttyProps;
+    private static long ttyPropsLastFetched;
+
+    public static Map<PtyMode, Integer> getUnixPtyModes() throws IOException, InterruptedException {
+        return parsePtyModes(getTtyProps());
+    }
+
+    public static Map<PtyMode, Integer> parsePtyModes(String stty) {
+        Map<PtyMode, Integer> modes = new TreeMap<PtyMode, Integer>();
+        for (PtyMode mode : PtyMode.values()) {
+            if (mode == PtyMode.TTY_OP_ISPEED || mode == PtyMode.TTY_OP_OSPEED) {
+
+            } else {
+                String str = mode.name().toLowerCase();
+                // Are we looking for a character?
+                if (str.charAt(0) == 'v') {
+                    str = str.substring(1);
+                    int v = findChar(stty, str);
+                    if (v < 0 && "reprint".equals(str)) {
+                        v = findChar(stty, "rprnt");
+                    }
+                    if (v >= 0) {
+                        modes.put(mode, v);
+                    }
+                } else {
+                    int v = findFlag(stty, str);
+                    if (v >= 0) {
+                        modes.put(mode, v);
+                    }
+                }
+            }
+        }
+        return modes;
+    }
+
+    private static int findFlag(String stty, String name) {
+        int cur = 0;
+        while (cur < stty.length()) {
+            int idx1 = stty.indexOf(name, cur);
+            int idx2 = idx1 + name.length();
+            if (idx1 < 0) {
+                return -1;
+            }
+            if (idx1 > 0 && Character.isLetterOrDigit(stty.charAt(idx1 - 1))
+                    || (idx2 < stty.length() && Character.isLetterOrDigit(stty.charAt(idx2)))) {
+                cur = idx2;
+                continue;
+            }
+            return idx1 == 0 ? 1 : stty.charAt(idx1 - 1) == '-' ? 0 : 1;
+        }
+        return -1;
+    }
+
+    private static int findChar(String stty, String name) {
+        int cur = 0;
+        while (cur < stty.length()) {
+            int idx1 = stty.indexOf(name, cur);
+            int idx2 = stty.indexOf('=', idx1);
+            int idx3 = stty.indexOf(';', idx1);
+            if (idx1 < 0 || idx2 < 0 || idx3 < idx2) {
+                // Invalid syntax
+                return -1;
+            }
+            if (idx1 > 0 && Character.isLetterOrDigit(stty.charAt(idx1 - 1))
+                    || (idx2 < stty.length() && Character.isLetterOrDigit(stty.charAt(idx2)))) {
+                cur = idx1 + name.length();
+                continue;
+            }
+            String val = stty.substring(idx2 + 1, idx3 < 0 ? stty.length() : idx3).trim();
+            if (val.indexOf("undef") >= 0) {
+                return -1;
+            }
+            if (val.length() == 2 && val.charAt(0) == '^') {
+                int v = (val.charAt(1) - 'A' + 129) % 128;
+                return v;
+            } else {
+                try {
+                    return Integer.parseInt(val);
+                } catch (NumberFormatException e) {
+                    // what else ?
+                }
+            }
+            return -1;
+        }
+        return -1;
+    }
+
+    /**
+     *  Returns the value of "stty size" width param.
+     *
+     *  <strong>Note</strong>: this method caches the value from the
+     *  first time it is called in order to increase speed, which means
+     *  that changing to size of the terminal will not be reflected
+     *  in the console.
+     */
+    public static int getTerminalWidth() {
+        int val = -1;
+
+        try {
+            val = getTerminalProperty("columns");
+        } catch (Exception e) {
+        }
+
+        if (val == -1) {
+            val = 80;
+        }
+
+        return val;
+    }
+
+    /**
+     *  Returns the value of "stty size" height param.
+     *
+     *  <strong>Note</strong>: this method caches the value from the
+     *  first time it is called in order to increase speed, which means
+     *  that changing to size of the terminal will not be reflected
+     *  in the console.
+     */
+    public static int getTerminalHeight() {
+        int val = -1;
+
+        try {
+            val = getTerminalProperty("rows");
+        } catch (Exception e) {
+        }
+
+        if (val == -1) {
+            val = 24;
+        }
+
+        return val;
+    }
+
+    private static int getTerminalProperty(String prop)
+                                    throws IOException, InterruptedException {
+        // need to be able handle both output formats:
+        // speed 9600 baud; 24 rows; 140 columns;
+        // and:
+        // speed 38400 baud; rows = 49; columns = 111; ypixels = 0; xpixels = 0;
+        for (StringTokenizer tok = new StringTokenizer(getTtyProps(), ";\n");
+                 tok.hasMoreTokens();) {
+            String str = tok.nextToken().trim();
+
+            if (str.startsWith(prop)) {
+                int index = str.lastIndexOf(" ");
+
+                return Integer.parseInt(str.substring(index).trim());
+            } else if (str.endsWith(prop)) {
+                int index = str.indexOf(" ");
+
+                return Integer.parseInt(str.substring(0, index).trim());
+            }
+        }
+
+        return -1;
+    }
+
+    public static String getTtyProps() throws IOException, InterruptedException {
+        // tty properties are cached so we don't have to worry too much about getting term widht/height
+        if (ttyProps == null || System.currentTimeMillis() - ttyPropsLastFetched > 1000) {
+            ttyProps = stty("-a");
+            ttyPropsLastFetched = System.currentTimeMillis();
+        }
+        return ttyProps;
+    }
+
+
+    /**
+     *  Execute the stty command with the specified arguments
+     *  against the current active terminal.
+     */
+    public static String stty(final String args)
+                        throws IOException, InterruptedException {
+        return exec("stty " + args + " < /dev/tty").trim();
+    }
+
+    /**
+     *  Execute the specified command and return the output
+     *  (both stdout and stderr).
+     */
+    public static String exec(final String cmd)
+                        throws IOException, InterruptedException {
+        return exec(new String[] {
+                        "sh",
+                        "-c",
+                        cmd
+                    });
+    }
+
+    /**
+     *  Execute the specified command and return the output
+     *  (both stdout and stderr).
+     */
+    private static String exec(final String[] cmd)
+                        throws IOException, InterruptedException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+        Process p = Runtime.getRuntime().exec(cmd);
+        int c;
+        InputStream in;
+
+        in = p.getInputStream();
+
+        while ((c = in.read()) != -1) {
+            bout.write(c);
+        }
+
+        in = p.getErrorStream();
+
+        while ((c = in.read()) != -1) {
+            bout.write(c);
+        }
+
+        p.waitFor();
+
+        String result = new String(bout.toByteArray());
+
+        return result;
+    }
+
+    /**
+     *  The command to use to set the terminal options. Defaults
+     *  to "stty", or the value of the system property "jline.sttyCommand".
+     */
+    public static void setSttyCommand(String cmd) {
+        sttyCommand = cmd;
+    }
+
+    /**
+     *  The command to use to set the terminal options. Defaults
+     *  to "stty", or the value of the system property "jline.sttyCommand".
+     */
+    public static String getSttyCommand() {
+        return sttyCommand;
+    }
+
+}

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ShellFactory.java Fri Oct 30 11:16:11 2009
@@ -24,6 +24,7 @@
 import java.util.Map;
 import java.util.EnumSet;
 
+import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.server.session.ServerSession;
 
 /**
@@ -129,7 +130,13 @@
          * Retrieve the environment map
          * @return the environment map
          */
-    	Map<String,String> getEnv();
+    	Map<String, String> getEnv();
+
+        /**
+         * Retrieve the pty modes
+         * @return the map of pty modes
+         */
+        Map<PtyMode, Integer> getPtyModes();
 
         /**
          * Add a qualified listener for the specific signal

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java Fri Oct 30 11:16:11 2009
@@ -21,10 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
 import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -32,6 +29,7 @@
 
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.channel.ChannelPipedInputStream;
@@ -71,11 +69,13 @@
     protected static class StandardEnvironment implements Environment {
 
         private final Map<Signal, Set<SignalListener>> listeners;
-        private final Map<String,String> env;
+        private final Map<String, String> env;
+        private final Map<PtyMode, Integer> ptyModes;
 
         public StandardEnvironment() {
             listeners = new ConcurrentHashMap<Signal, Set<SignalListener>>(3);
             env = new ConcurrentHashMap<String, String>();
+            ptyModes = new ConcurrentHashMap<PtyMode, Integer>();
         }
 
         public void addSignalListener(SignalListener listener, Signal... signals) {
@@ -105,6 +105,10 @@
             return env;
         }
 
+        public Map<PtyMode, Integer> getPtyModes() {
+            return ptyModes;
+        }
+
         public void removeSignalListener(SignalListener listener) {
             if (listener == null) {
                 throw new IllegalArgumentException("listener may not be null");
@@ -136,7 +140,7 @@
             // TODO: listening for property changes would be nice too.
             getEnv().put(key, value);
         }
-        
+
         protected Set<SignalListener> getSignalListeners(Signal signal, boolean create) {
             Set<SignalListener> ls = listeners.get(signal);
             if (ls == null && create) {
@@ -154,60 +158,7 @@
 
     }
 
-    protected static enum PtyMode {
-        // Chars
-        VINTR(1), VQUIT(2), VERASE(3), VKILL(4), VEOF(5), VEOL(6), VEOL2(7), VSTART(8), VSTOP(9),
-        VSUSP(10), VDSUSP(11), VREPRINT(12), VWERASE(13), VLNEXT(14), VFLUSH(15), VSWTCH(16), VSTATUS(17), VDISCARD(18),
-        // I flags
-        IGNPAR(30), PARMRK(31), INPCK(32), ISTRIP(33), INCLR(34), IGNCR(35), ICRNL(36), IUCLC(37), IXON(38), IXANY(39),
-        IXOFF(40), IMAXBEL(41),
-        // L flags
-        ISIG(50), ICANON(51), XCASE(52), ECHO(53), ECHOE(54), ECHOK(55), ECHONL(56), NOFLSH(57), TOSTOP(58), IEXTEN(59),
-        ECHOCTL(60), ECHOKE(61), PENDIN(62),
-        // O flags
-        OPOST(70), OLCUC(71), ONLCR(72), OCRNL(73), ONOCR(74), ONLRET(75),
-        // C flags
-        CS7(90), CS8(91), PARENB(92), PARODD(93),
-        // Speeed
-        TTY_OP_ISPEED(128), TTY_OP_OSPEED(129);
-
-        private int v;
-        private PtyMode(int v) {
-            this.v = v;
-        }
-
-        public int toInt() {
-            return v;
-        }
-
-        static Map<Integer,PtyMode> commands;
-        static {
-            commands = new HashMap<Integer, PtyMode>();
-            for (PtyMode c : PtyMode.values()) {
-                commands.put(c.toInt(), c);
-            }
-        }
-        public static PtyMode fromInt(int b) {
-            return commands.get(0x00FF & (b + 256));
-        }
-    }
-
-    protected static class PtyModeValue {
-        public final PtyMode mode;
-        public final int value;
-
-        public PtyModeValue(PtyMode mode, int value) {
-            this.mode = mode;
-            this.value = value;
-        }
-
-        public String toString() {
-            return mode + "(" + mode.toInt() + ") =" + value;
-        }
-    }
-
     protected String type;
-    protected PtyModeValue[] ptyModes;
     protected InputStream in;
     protected OutputStream out;
     protected OutputStream err;
@@ -340,31 +291,20 @@
         int tWidth = buffer.getInt();
         int tHeight = buffer.getInt();
         byte[] modes = buffer.getBytes();
-        List<PtyModeValue> modeList = new ArrayList<PtyModeValue>();
         for (int i = 0; i < modes.length && modes[i] != 0;) {
             PtyMode mode = PtyMode.fromInt(modes[i++]);
             int val  = ((modes[i++] << 24) & 0xff000000) |
                        ((modes[i++] << 16) & 0x00ff0000) |
                        ((modes[i++] <<  8) & 0x0000ff00) |
                        ((modes[i++]      ) & 0x000000ff);
-            PtyModeValue m = new PtyModeValue(mode, val);
-            modeList.add(m);
+            getEnvironment().getPtyModes().put(mode, val);
         }
-        ptyModes = modeList.toArray(new PtyModeValue[0]);
         if (log.isDebugEnabled()) {
-            StringBuffer strModes = new StringBuffer();
-            for (PtyModeValue m : ptyModes) {
-                if (strModes.length() > 0) {
-                    strModes.append(", ");
-                }
-                strModes.append(m);
-            }
-            log.debug("pty for channel {}: term={}, size=({} - {}), pixels=({}, {}), modes=[{}]", new Object[] { id, term, tColumns, tRows, tWidth, tHeight, strModes.toString() });
+            log.debug("pty for channel {}: term={}, size=({} - {}), pixels=({}, {}), modes=[{}]", new Object[] { id, term, tColumns, tRows, tWidth, tHeight, getEnvironment().getPtyModes() });
         }
         addEnvVariable(Environment.ENV_TERM, term);
         addEnvVariable(Environment.ENV_COLUMNS, Integer.toString(tColumns));
         addEnvVariable(Environment.ENV_LINES, Integer.toString(tRows));
-        // TODO: handle pty request correctly
         if (wantReply) {
             buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS);
             buffer.putInt(recipient);
@@ -464,14 +404,8 @@
     }
 
     protected int getPtyModeValue(PtyMode mode) {
-        if (ptyModes != null) {
-            for (PtyModeValue m : ptyModes) {
-                if (m.mode == mode) {
-                    return m.value;
-                }
-            }
-        }
-        return 0;
+        Integer v = getEnvironment().getPtyModes().get(mode);
+        return v != null ? v : 0;
     }
 
     protected boolean handleExec(Buffer buffer) throws IOException {

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java Fri Oct 30 11:16:11 2009
@@ -191,7 +191,7 @@
         authFuture.await();
         closeFuture.await();
         assertNotNull(authFuture.getException());
-
+        assertTrue(closeFuture.isClosed());
     }
 
     @Test
@@ -209,7 +209,7 @@
         openFuture.await();
         closeFuture.await();
         assertNotNull(openFuture.isOpened());
-        assertNotNull(closeFuture.isClosed());
+        assertTrue(closeFuture.isClosed());
     }
 
     @Test
@@ -227,7 +227,7 @@
         openFuture.await();
         closeFuture.await();
         assertNotNull(openFuture.getException());
-        assertNotNull(closeFuture.isClosed());
+        assertTrue(closeFuture.isClosed());
     }
 
     public static void main(String[] args) throws Exception {

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java?rev=831265&r1=831264&r2=831265&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java Fri Oct 30 11:16:11 2009
@@ -109,32 +109,32 @@
         String data = "0123456789\n";
 
         File root = new File("target/scp");
-        File target = new File("target/scp/o ut.txt");
+        File target = new File("target/scp/out.txt");
         root.mkdirs();
         assertTrue(root.exists());
 
         target.delete();
         assertFalse(target.exists());
-        sendFile("target/scp/o ut.txt", "out.txt", data);
+        sendFile("target/scp/out.txt", "out.txt", data);
         assertFileLength(target, data.length(), 5000);
 
         target.delete();
         assertFalse(target.exists());
-        sendFile("target/scp", "o ut.txt", data);
+        sendFile("target/scp", "out.txt", data);
         assertFileLength(target, data.length(), 5000);
 
         sendFileError("target", "scp", "0123456789\n");
 
         readFileError("target/scp");
 
-        assertEquals(data, readFile("target/scp/o ut.txt"));
+        assertEquals(data, readFile("target/scp/out.txt"));
 
         assertEquals(data, readDir("target/scp"));
 
         target.delete();
         root.delete();
 
-        sendDir("target", "scp", "o ut.txt", data);
+        sendDir("target", "scp", "out.txt", data);
         assertFileLength(target, data.length(), 5000);
     }
 
@@ -164,7 +164,7 @@
         OutputStream os = c.getOutputStream();
         InputStream is = c.getInputStream();
         String header = readLine(is);
-        assertEquals("C0644 11 o ut.txt", header);
+        assertEquals("C0644 11 out.txt", header);
         int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
         os.write(0);
         os.flush();
@@ -191,7 +191,7 @@
         os.write(0);
         os.flush();
         header = readLine(is);
-        assertEquals("C0644 11 o ut.txt", header);
+        assertEquals("C0644 11 out.txt", header);
         int length = Integer.parseInt(header.substring(6, header.indexOf(' ', 6)));
         os.write(0);
         os.flush();

Added: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/SttySupportTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/SttySupportTest.java?rev=831265&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/SttySupportTest.java (added)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/SttySupportTest.java Fri Oct 30 11:16:11 2009
@@ -0,0 +1,55 @@
+/*
+ * 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.sshd.util;
+
+import org.apache.sshd.common.PtyMode;
+import org.apache.sshd.common.util.SttySupport;
+import org.junit.Test;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Map;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SttySupportTest {
+
+    @Test
+    public void parseOutput1() throws Exception {
+        Reader r = new InputStreamReader(getClass().getResourceAsStream("stty-output-1.txt"));
+        char[] buf = new char[8192];
+        int len = r.read(buf);
+        String stty = new String(buf, 0, len);
+        Map<PtyMode, Integer> modes = SttySupport.parsePtyModes(stty);
+        System.err.println(modes);
+    }
+
+    @Test
+    public void parseOutput2() throws Exception {
+        Reader r = new InputStreamReader(getClass().getResourceAsStream("stty-output-2.txt"));
+        char[] buf = new char[8192];
+        int len = r.read(buf);
+        String stty = new String(buf, 0, len);
+        Map<PtyMode, Integer> modes = SttySupport.parsePtyModes(stty);
+        System.err.println(modes);
+    }
+}

Added: mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-1.txt
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-1.txt?rev=831265&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-1.txt (added)
+++ mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-1.txt Fri Oct 30 11:16:11 2009
@@ -0,0 +1,10 @@
+speed 38400 baud; rows 25; columns 80; line = 0;
+intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
+eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
+werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
+-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
+-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
+-iuclc -ixany -imaxbel -iutf8
+opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
+isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
+echoctl echoke

Added: mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-2.txt
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-2.txt?rev=831265&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-2.txt (added)
+++ mina/sshd/trunk/sshd-core/src/test/resources/org/apache/sshd/client/channel/stty-output-2.txt Fri Oct 30 11:16:11 2009
@@ -0,0 +1,13 @@
+speed 9600 baud; 50 rows; 160 columns;
+lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
+	-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
+	-extproc
+iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
+	-ignbrk brkint -inpck -ignpar -parmrk
+oflags: opost onlcr -oxtabs -onocr -onlret
+cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
+	-dtrflow -mdmbuf
+cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;
+	eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
+	min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
+	stop = ^S; susp = ^Z; time = 0; werase = ^W;