Fix ansi on windows

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@792818 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/EchoCommand.java b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/EchoCommand.java
index 4d575c7..e1d4163 100644
--- a/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/EchoCommand.java
+++ b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/EchoCommand.java
@@ -1,11 +1,37 @@
 package org.apache.felix.karaf.gshell.commands;
 
-/**
- * Created by IntelliJ IDEA.
- * User: gnodet
- * Date: Jul 9, 2009
- * Time: 1:06:45 AM
- * To change this template use File | Settings | File Templates.
- */
-public class EchoCommand {
-}
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Option;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
+
+@Command(scope = "shell", name = "echo", description="Echo or print arguments to STDOUT")
+public class EchoCommand extends OsgiCommandSupport
+{
+    @Option(name="-n", description="Do not print the trailing newline character")
+    private boolean trailingNewline = true;
+
+    @Argument(description="Arguments")
+    private List<String> args;
+
+    protected Object doExecute() throws Exception {
+        if (args != null) {
+            int c=0;
+
+            for (String arg : args) {
+                System.out.print(arg);
+                if (++c + 1 < args.size()) {
+                    System.out.print(" ");
+                }
+            }
+        }
+
+        if (trailingNewline) {
+            System.out.println();
+        }
+
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/InfoAction.java b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/InfoAction.java
index cd210eb..4f657bd 100644
--- a/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/InfoAction.java
+++ b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/InfoAction.java
@@ -16,8 +16,150 @@
  */
 package org.apache.felix.karaf.gshell.commands;
 
-/**
- * TODO
- */
-public class InfoAction {
+import java.util.Locale;
+import java.text.DecimalFormatSymbols;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.ThreadMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.reflect.Method;
+
+import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
+import org.apache.felix.gogo.commands.Command;
+
+@Command(scope = "shell", name = "info", description = "Print Karaf informations")
+public class InfoAction extends OsgiCommandSupport {
+
+    private NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
+    private NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));
+
+
+    protected Object doExecute() throws Exception {
+        int maxNameLen;
+
+        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+        OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+        ThreadMXBean threads = ManagementFactory.getThreadMXBean();
+        MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
+        ClassLoadingMXBean cl = ManagementFactory.getClassLoadingMXBean();
+
+        //
+        // print ServiceMix informations
+        //
+        maxNameLen = 25;
+        System.out.println("Karaf");
+        printValue("Karaf home", maxNameLen, System.getProperty("karaf.home"));
+        printValue("Karaf base", maxNameLen, System.getProperty("karaf.base"));
+        System.out.println();
+
+        System.out.println("JVM");
+        printValue("Java Virtual Machine", maxNameLen, runtime.getVmName() + " version " + runtime.getVmVersion());
+        printValue("Vendor", maxNameLen, runtime.getVmVendor());
+        printValue("Uptime", maxNameLen, printDuration(runtime.getUptime()));
+        try {
+            printValue("Process CPU time", maxNameLen, printDuration(getSunOsValueAsLong(os, "getProcessCpuTime") / 1000000));
+        } catch (Throwable t) {}
+        printValue("Total compile time", maxNameLen, printDuration(ManagementFactory.getCompilationMXBean().getTotalCompilationTime()));
+
+        System.out.println("Threads");
+        printValue("Live threads", maxNameLen, Integer.toString(threads.getThreadCount()));
+        printValue("Daemon threads", maxNameLen, Integer.toString(threads.getDaemonThreadCount()));
+        printValue("Peak", maxNameLen, Integer.toString(threads.getPeakThreadCount()));
+        printValue("Total started", maxNameLen, Long.toString(threads.getTotalStartedThreadCount()));
+
+        System.out.println("Memory");
+        printValue("Current heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getUsed()));
+        printValue("Maximum heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getMax()));
+        printValue("Committed heap size", maxNameLen, printSizeInKb(mem.getHeapMemoryUsage().getCommitted()));
+        printValue("Pending objects", maxNameLen, Integer.toString(mem.getObjectPendingFinalizationCount()));
+        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
+            String val = "Name = '" + gc.getName() + "', Collections = " + gc.getCollectionCount() + ", Time = " + printDuration(gc.getCollectionTime());
+            printValue("Garbage collector", maxNameLen, val);
+        }
+
+        System.out.println("Classes");
+        printValue("Current classes loaded", maxNameLen, printLong(cl.getLoadedClassCount()));
+        printValue("Total classes loaded", maxNameLen, printLong(cl.getTotalLoadedClassCount()));
+        printValue("Total classes unloaded", maxNameLen, printLong(cl.getUnloadedClassCount()));
+
+        System.out.println("Operating system");
+        printValue("Name", maxNameLen, os.getName() + " version " + os.getVersion());
+        printValue("Architecture", maxNameLen, os.getArch());
+        printValue("Processors", maxNameLen, Integer.toString(os.getAvailableProcessors()));
+        try {
+            printValue("Total physical memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getTotalPhysicalMemorySize")));
+            printValue("Free physical memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getFreePhysicalMemorySize")));
+            printValue("Committed virtual memory", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getCommittedVirtualMemorySize")));
+            printValue("Total swap space", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getTotalSwapSpaceSize")));
+            printValue("Free swap space", maxNameLen, printSizeInKb(getSunOsValueAsLong(os, "getFreeSwapSpaceSize")));
+        } catch (Throwable t) {}
+
+        return null;
+    }
+
+    private long getSunOsValueAsLong(OperatingSystemMXBean os, String name) throws Exception {
+        Method mth = os.getClass().getMethod(name);
+        return (Long) mth.invoke(os);
+    }
+
+    private String printLong(long i) {
+        return fmtI.format(i);
+    }
+
+    private String printSizeInKb(double size) {
+        return fmtI.format((long) (size / 1024)) + " kbytes";
+    }
+
+    private String printDuration(double uptime) {
+        uptime /= 1000;
+        if (uptime < 60) {
+            return fmtD.format(uptime) + " seconds";
+        }
+        uptime /= 60;
+        if (uptime < 60) {
+            long minutes = (long) uptime;
+            String s = fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
+            return s;
+        }
+        uptime /= 60;
+        if (uptime < 24) {
+            long hours = (long) uptime;
+            long minutes = (long) ((uptime - hours) * 60);
+            String s = fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
+            if (minutes != 0) {
+                s += " " + fmtI.format(minutes) + (minutes > 1 ? " minutes" : "minute");
+            }
+            return s;
+        }
+        uptime /= 24;
+        long days = (long) uptime;
+        long hours = (long) ((uptime - days) * 60);
+        String s = fmtI.format(days) + (days > 1 ? " days" : " day");
+        if (hours != 0) {
+            s += " " + fmtI.format(hours) + (hours > 1 ? " hours" : "hour");
+        }
+        return s;
+    }
+
+    void printSysValue(String prop, int pad) {
+        printValue(prop, pad, System.getProperty(prop));
+    }
+
+    void printValue(String name, int pad, String value) {
+        System.out.println("  @|bold " + name + spaces(pad - name.length()) + "|   " + value);
+    }
+
+    String spaces(int nb) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < nb; i++) {
+            sb.append(' ');
+        }
+        return sb.toString();
+    }
+
 }
diff --git a/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/MoreAction.java b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/MoreAction.java
new file mode 100644
index 0000000..d5d0e62
--- /dev/null
+++ b/karaf/gshell/gshell-commands/src/main/java/org/apache/felix/karaf/gshell/commands/MoreAction.java
@@ -0,0 +1,7 @@
+package org.apache.felix.karaf.gshell.commands;
+
+import org.apache.felix.gogo.commands.Command;
+
+@Command(scope = "shell", name = "more", description = "")
+public class MoreAction {
+}
diff --git a/karaf/gshell/gshell-console/pom.xml b/karaf/gshell/gshell-console/pom.xml
index 546145e..eec4ff2 100644
--- a/karaf/gshell/gshell-console/pom.xml
+++ b/karaf/gshell/gshell-console/pom.xml
@@ -39,8 +39,12 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.jline</artifactId>
+            <groupId>jline</groupId>
+            <artifactId>jline</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.fusesource.jansi</groupId>
+            <artifactId>jansi</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>
@@ -98,11 +102,23 @@
                         <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
                         <Import-Package>
                             !javax.swing,
+                            !org.apache.felix.karaf.gshell.console*,
+                            !org.fusesource.jansi*,
+                            !org.apache.felix.gogo.commands*,
+                            !jline,
+                            com.sun.jna*;resolution:=optional,
                             *
                         </Import-Package>
                         <Export-Package>
-                            org.apache.felix.karaf.gshell.console*;version=${pom.version}
+                            org.apache.felix.gogo.commands*;version=${felix.gogo.version},
+                            org.apache.felix.karaf.gshell.console*;version=${pom.version},
+                            org.fusesource.jansi;version=${jansi.version},
+                            jline;version=${jline.version},
+
                         </Export-Package>
+                        <Private-Package>
+                            org.fusesource.jansi.internal
+                        </Private-Package>
                         <_versionpolicy>${bnd.version.policy}</_versionpolicy>
                     </instructions>
                     <unpackBundle>true</unpackBundle>
diff --git a/karaf/gshell/gshell-console/src/main/filtered-resources/org/apache/felix/karaf/gshell/console/branding.properties b/karaf/gshell/gshell-console/src/main/filtered-resources/org/apache/felix/karaf/gshell/console/branding.properties
index dbaa2f7..6331c02 100644
--- a/karaf/gshell/gshell-console/src/main/filtered-resources/org/apache/felix/karaf/gshell/console/branding.properties
+++ b/karaf/gshell/gshell-console/src/main/filtered-resources/org/apache/felix/karaf/gshell/console/branding.properties
@@ -18,15 +18,15 @@
 ##
 
 welcome = \
-@|cyan        __ __                  ____  |\n\
-@|cyan       / //_/____ __________ _/ __/  |\n\
-@|cyan      / ,<  / __ `/ ___/ __ `/ /_    |\n\
-@|cyan     / /\\| \\|/ /_/ / /  / /_/ / __/    |\n\
-@|cyan    /_/ \\|_\\|\\__,_/_/   \\__,_/_/     |\n\
+\u001B[36m        __ __                  ____      \u001B[0m\n\
+\u001B[36m       / //_/____ __________ _/ __/      \u001B[0m\n\
+\u001B[36m      / ,<  / __ `/ ___/ __ `/ /_        \u001B[0m\n\
+\u001B[36m     / /| |/ /_/ / /  / /_/ / __/        \u001B[0m\n\
+\u001B[36m    /_/ |_|\\__,_/_/   \\__,_/_/         \u001B[0m\n\
 \n\
- @|bold Apache Felix Karaf| (${pom.version})\n\
+\u001B[1m  Apache Felix Karaf\u001B[0m (${pom.version})\n\
 \n\
-Type '@|bold help|' for more information.\n
+Type '\u001B[1mhelp\u001B[0m' for more information.\n
 
 
 
diff --git a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiCode.java b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiCode.java
deleted file mode 100644
index 04f2790..0000000
--- a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiCode.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.felix.karaf.gshell.console.ansi;
-
-public enum AnsiCode
-{
-    OFF(0),
-    BOLD(1),
-    UNDERSCORE(4),
-    BLINK(5),
-    REVERSE(7),
-    CONCEALED(8),
-
-    FG_BLACK(30),
-    FG_RED(31),
-    FG_GREEN(32),
-    FG_YELLOW(33),
-    FG_BLUE(34),
-    FG_MAGENTA(35),
-    FG_CYAN(36),
-    FG_WHITE(37),
-
-    BLACK(FG_BLACK),
-    RED(FG_RED),
-    GREEN(FG_GREEN),
-    YELLOW(FG_YELLOW),
-    BLUE(FG_BLUE),
-    MAGENTA(FG_MAGENTA),
-    CYAN(FG_CYAN),
-    WHITE(FG_WHITE),
-
-    BG_BLACK(40),
-    BG_RED(41),
-    BG_GREEN(42),
-    BG_YELLOW(43),
-    BG_BLUE(44),
-    BG_MAGENTA(45),
-    BG_CYAN(46),
-    BG_WHITE(47);
-
-    final int code;
-
-    private AnsiCode(final int code) {
-        this.code = code;
-    }
-
-    private AnsiCode(final AnsiCode code) {
-        this(code.code);
-    }
-
-}
diff --git a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiOutputStream.java b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiOutputStream.java
deleted file mode 100644
index ed04c8b..0000000
--- a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/ansi/AnsiOutputStream.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.apache.felix.karaf.gshell.console.ansi;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-
-public class AnsiOutputStream extends FilterOutputStream
-{
-    char[] buf = new char[16];
-    int count = 0;
-    int ansiCodeState;
-
-    public AnsiOutputStream(OutputStream out)
-    {
-        super(out);
-    }
-
-    @Override
-    public void write(int b) throws IOException
-    {
-        if (ansiCodeState == 0) {
-            if (b == '@') {
-                ansiCodeState = 1;
-            } else {
-                super.write(b);
-            }
-        } else if (ansiCodeState == 1) {
-            if (b == '|') {
-                ansiCodeState = 2;
-                count = 0;
-            } else {
-                super.write('@');
-                super.write(b);
-                ansiCodeState = 0;
-            }
-        } else if (ansiCodeState == 2) {
-            if (b == ',') {
-                write(AnsiCode.valueOf(new String(buf, 0, count).toUpperCase()));
-                count = 0;
-            } else if (b == ' ') {
-                write(AnsiCode.valueOf(new String(buf, 0, count).toUpperCase()));
-                ansiCodeState = 3;
-            } else if (count < buf.length) {
-                buf[count++] = (char) b;
-            } else {
-                throw new IOException("Unknown ANSI code (too long): " + new String(buf, 0, count));
-            }
-        } else if (ansiCodeState == 3) {
-            if (b == '|') {
-                write(AnsiCode.OFF);
-                ansiCodeState = 0;
-            } else if (b == '\\') {
-                ansiCodeState = 4;
-            } else {
-                super.write(b);
-            }
-        } else if (ansiCodeState == 4) {
-            if (b != '|') {
-                super.write('\\');
-            }
-            super.write(b);
-            ansiCodeState = 3;
-        } else {
-            throw new IllegalStateException();
-        }
-    }
-
-    protected void write(AnsiCode code) throws IOException {
-        super.write(27); // ESC
-        super.write('[');
-        if (code.code >= 10) {
-            super.write((code.code / 10) + '0');
-        }
-        super.write((code.code % 10) + '0');
-        super.write('m');
-    }
-
-    public static String decode(String str) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        AnsiOutputStream aos = new AnsiOutputStream(baos);
-        aos.write(str.getBytes());
-        aos.close();
-        return baos.toString();
-    }
-
-}
diff --git a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/Console.java b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/Console.java
index 22bc4dd..deb13e0 100644
--- a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/Console.java
+++ b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/Console.java
@@ -22,15 +22,14 @@
 import org.osgi.service.command.CommandSession;
 import org.osgi.service.command.Converter;
 import org.osgi.service.command.CommandProcessor;
-import org.apache.felix.karaf.gshell.console.ansi.AnsiOutputStream;
 import org.apache.felix.karaf.gshell.console.Completer;
+import org.fusesource.jansi.Ansi;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.PrintWriter;
 import java.io.PrintStream;
-import java.lang.reflect.Method;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.Properties;
@@ -39,7 +38,8 @@
 {
 
     public static final String PROMPT = "PROMPT";
-    public static final String DEFAULT_PROMPT = "\"@|bold ${USER}|@${APPLICATION}:@|bold ${SCOPE}|> \"";
+    public static final String DEFAULT_PROMPT =
+             "\"\u001B\\[1m${USER}\u001B\\[0m@${APPLICATION}> \"";
 
     private CommandSession session;
     private ConsoleReader reader;
@@ -99,8 +99,7 @@
         welcome();
         while (running) {
             try {
-                String prompt = AnsiOutputStream.decode(getPrompt());
-                String line = reader.readLine(prompt);
+                String line = reader.readLine(getPrompt());
                 if (line == null)
                 {
                     break;
@@ -136,11 +135,7 @@
         loadProps(props, "/org/apache/felix/karaf/branding/branding.properties");
         String welcome = props.getProperty("welcome");
         if (welcome != null && welcome.length() > 0) {
-            try {
-                session.getConsole().println(AnsiOutputStream.decode(welcome));
-            } catch (IOException e) {
-                //
-            }
+            session.getConsole().println(welcome);
         }
     }
 
@@ -192,7 +187,6 @@
 
     private void interrupt() {
         interrupt = true;
-        //System.err.println("Interrupt ^C");
     }
 
     private class ConsoleInputStream extends InputStream
diff --git a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/ConsoleFactory.java b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/ConsoleFactory.java
index 81373eb..7cff958 100644
--- a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/ConsoleFactory.java
+++ b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/ConsoleFactory.java
@@ -20,15 +20,16 @@
 
 import java.io.InputStream;
 import java.io.PrintStream;
+import java.io.OutputStream;
 import java.lang.reflect.Method;
 import java.util.List;
 
-import org.apache.felix.karaf.gshell.console.ansi.AnsiOutputStream;
 import org.apache.felix.karaf.gshell.console.Completer;
 import org.apache.felix.karaf.gshell.console.completer.AggregateCompleter;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.command.CommandProcessor;
 import org.osgi.service.command.CommandSession;
+import org.fusesource.jansi.AnsiConsole;
 import jline.Terminal;
 
 public class ConsoleFactory {
@@ -80,7 +81,13 @@
                     }
                 }
             };
-            this.console = new Console(commandProcessor, in, out, err, terminal, new AggregateCompleter(completers), callback);
+            this.console = new Console(commandProcessor,
+                                       in,
+                                       wrap(out),
+                                       wrap(err),
+                                       terminal,
+                                       new AggregateCompleter(completers),
+                                       callback);
             CommandSession session = console.getSession();
             session.put("USER", "karaf");
             session.put("APPLICATION", System.getProperty("karaf.name", "root"));
@@ -94,6 +101,15 @@
         }
     }
 
+    private static PrintStream wrap(PrintStream stream) {
+        OutputStream o = AnsiConsole.wrapOutputStream(stream);
+        if (o instanceof PrintStream) {
+            return ((PrintStream) o);
+        } else {
+            return new PrintStream(o);
+        }
+    }
+
     private static <T> T unwrap(T stream) {
         try {
             Method mth = stream.getClass().getMethod("getRoot");
diff --git a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/TerminalFactory.java b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/TerminalFactory.java
index 55d4324..693a3ea 100644
--- a/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/TerminalFactory.java
+++ b/karaf/gshell/gshell-console/src/main/java/org/apache/felix/karaf/gshell/console/jline/TerminalFactory.java
@@ -12,7 +12,6 @@
 public class TerminalFactory {
 
     private Terminal term;
-    private Thread hook;
 
     public Terminal getTerminal() throws Exception {
         if (term == null) {
@@ -25,7 +24,7 @@
         boolean windows = System.getProperty("os.name").toLowerCase().contains("windows");
         try {
             if (windows) {
-                WindowsTerminal t = new WindowsTerminal();
+                AnsiWindowsTerminal t = new AnsiWindowsTerminal();
                 t.setDirectConsole(true);
                 t.initializeTerminal();
                 term = t;
@@ -40,12 +39,17 @@
     }
 
     public synchronized void destroy() throws Exception {
-        if (term instanceof UnixTerminal) {
-            ((UnixTerminal) term).restoreTerminal();
-        }
+        term.restoreTerminal();
         term = null;
     }
 
+    public static class AnsiWindowsTerminal extends WindowsTerminal {
+        @Override
+        public boolean isANSISupported() {
+            return true;
+        }
+    }
+
     public static class NoInterruptUnixTerminal extends UnixTerminal {
         @Override
         public void initializeTerminal() throws IOException, InterruptedException {
@@ -59,23 +63,6 @@
             super.restoreTerminal();
         }
 
-        protected static String stty(final String args) throws IOException, InterruptedException {
-            try {
-                try {
-                    Method mth = UnixTerminal.class.getDeclaredMethod("stty", String.class);
-                    mth.setAccessible(true);
-                    return (String) mth.invoke(null, args);
-                } catch (InvocationTargetException e) {
-                    throw e.getTargetException();
-                }
-            } catch (IOException e) {
-                throw e;
-            } catch (InterruptedException e) {
-                throw e;
-            } catch (Throwable e) {
-                throw new RuntimeException(e);
-            }
-        }
     }
 
 }
diff --git a/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshAction.java b/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshAction.java
index 4627a03..a93a16e 100644
--- a/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshAction.java
+++ b/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshAction.java
@@ -1,156 +1,142 @@
-///*
-// * 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.karaf.gshell.ssh;
-//
-//import org.apache.sshd.ClientChannel;
-//import org.apache.sshd.ClientSession;
-//import org.apache.sshd.SshClient;
-//import org.apache.sshd.client.future.ConnectFuture;
-//import org.apache.sshd.common.util.NoCloseInputStream;
-//import org.apache.sshd.common.util.NoCloseOutputStream;
-//import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
-//import org.apache.felix.karaf.gshell.console.BlueprintContainerAware;
-//import org.apache.felix.gogo.commands.Option;
-//import org.apache.felix.gogo.commands.Argument;
-//import org.slf4j.Logger;
-//import org.slf4j.LoggerFactory;
-//import org.osgi.service.blueprint.container.BlueprintContainer;
-//
-///**
-// * Connect to a SSH server.
-// *
-// * @version $Rev: 721244 $ $Date: 2008-11-27 18:19:56 +0100 (Thu, 27 Nov 2008) $
-// */
-//public class SshAction
-//    extends OsgiCommandSupport implements BlueprintContainerAware
-//{
-//    private final Logger log = LoggerFactory.getLogger(getClass());
-//
-//    @Option(name="-l", aliases={"--username"}, description = "Username")
-//    private String username;
-//
-//    @Option(name="-P", aliases={"--password"}, description = "Password")
-//    private String password;
-//
-//    @Argument(required=true, description = "Host")
-//    private String hostname;
-//
-//    @Option(name="-p", aliases={"--port"}, description = "Port")
-//    private int port = 22;
-//
-//    private BlueprintContainer container;
-//
-//	private ClientSession session;
-//
-//    public void setBlueprintContainer(final BlueprintContainer container) {
-//        assert container != null;
-//        this.container = container;
-//    }
-//
-//    /**
-//     * Helper to validate that prompted username or password is not null or empty.
-//     */
-//    private class UsernamePasswordValidator
-//        implements PromptReader.Validator
-//    {
-//        private String type;
-//
-//        private int count = 0;
-//
-//        private int max = 3;
-//
-//        public UsernamePasswordValidator(final String type) {
-//            assert type != null;
-//
-//            this.type = type;
-//        }
-//
-//        public boolean isValid(final String value) {
-//            count++;
-//
-//            if (value != null && value.trim().length() > 0) {
-//                return true;
-//            }
-//
-//            if (count >= max) {
-//                throw new RuntimeException("Too many attempts; failed to prompt user for " + type + " after " + max + " tries");
-//            }
-//
-//            return false;
-//        }
-//    }
-//
-//    @Override
-//    protected Object doExecute() throws Exception {
-//
-//        //
-//        // TODO: Parse hostname for <username>@<hostname>
-//        //
-//
-//        System.out.println("Connecting to host " + hostname + " on port " + port);
-//
-//        // If the username/password was not configured via cli, then prompt the user for the values
-//        if (username == null || password == null) {
-//            PromptReader prompter = new PromptReader(io);
-//            log.debug("Prompting user for credentials");
-//            if (username == null) {
-//                username = prompter.readLine("Login: ", new UsernamePasswordValidator("login"));
-//            }
-//            if (password == null) {
-//                text = messages.getMessage("prompt.password");
-//                password = prompter.readPassword("Password: ", new UsernamePasswordValidator("password"));
-//            }
-//        }
-//
-//        // Create the client from prototype
-//        SshClient client = (SshClient) container.getComponentInstance(SshClient.class.getName());
-//        log.debug("Created client: {}", client);
-//        client.start();;
-//
-//        try {
-//            ConnectFuture future = client.connect(hostname, port);
-//            future.await();
-//            session = future.getSession();
-//            try {
-//                System.out.println("Connected");
-//
-//                session.authPassword(username, password);
-//                int ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
-//                if ((ret & ClientSession.AUTHED) == 0) {
-//                    System.err.println("Authentication failed");
-//                    return null;
-//                }
-//
-//                ClientChannel channel = session.createChannel("shell");
-//                channel.setIn(new NoCloseInputStream(System.in));
-//                channel.setOut(new NoCloseOutputStream(System.out));
-//                channel.setErr(new NoCloseOutputStream(System.err));
-//                channel.open();
-//                channel.waitFor(ClientChannel.CLOSED, 0);
-//            } finally {
-//                session.close(false);
-//            }
-//        } finally {
-//            client.stop();
-//        }
-//
-//        return null;
-//    }
-//}
+/*
+ * 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.karaf.gshell.ssh;
+
+import java.io.IOException;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.common.util.NoCloseInputStream;
+import org.apache.sshd.common.util.NoCloseOutputStream;
+import org.apache.felix.karaf.gshell.console.OsgiCommandSupport;
+import org.apache.felix.karaf.gshell.console.BlueprintContainerAware;
+import org.apache.felix.gogo.commands.Option;
+import org.apache.felix.gogo.commands.Argument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+
+/**
+ * Connect to a SSH server.
+ *
+ * @version $Rev: 721244 $ $Date: 2008-11-27 18:19:56 +0100 (Thu, 27 Nov 2008) $
+ */
+public class SshAction
+    extends OsgiCommandSupport implements BlueprintContainerAware
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Option(name="-l", aliases={"--username"}, description = "Username")
+    private String username;
+
+    @Option(name="-P", aliases={"--password"}, description = "Password")
+    private String password;
+
+    @Argument(required=true, description = "Host")
+    private String hostname;
+
+    @Option(name="-p", aliases={"--port"}, description = "Port")
+    private int port = 22;
+
+    private BlueprintContainer container;
+
+	private ClientSession session;
+
+    public void setBlueprintContainer(final BlueprintContainer container) {
+        assert container != null;
+        this.container = container;
+    }
+
+    @Override
+    protected Object doExecute() throws Exception {
+
+        //
+        // TODO: Parse hostname for <username>@<hostname>
+        //
+
+        System.out.println("Connecting to host " + hostname + " on port " + port);
+
+        // If the username/password was not configured via cli, then prompt the user for the values
+        if (username == null || password == null) {
+            log.debug("Prompting user for credentials");
+            if (username == null) {
+                username = readLine("Login: ");
+            }
+            if (password == null) {
+                password = readLine("Password: ");
+            }
+        }
+
+        // Create the client from prototype
+        SshClient client = (SshClient) container.getComponentInstance(SshClient.class.getName());
+        log.debug("Created client: {}", client);
+        client.start();;
+
+        try {
+            ConnectFuture future = client.connect(hostname, port);
+            future.await();
+            session = future.getSession();
+            try {
+                System.out.println("Connected");
+
+                session.authPassword(username, password);
+                int ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
+                if ((ret & ClientSession.AUTHED) == 0) {
+                    System.err.println("Authentication failed");
+                    return null;
+                }
+
+                ClientChannel channel = session.createChannel("shell");
+                channel.setIn(new NoCloseInputStream(System.in));
+                channel.setOut(new NoCloseOutputStream(System.out));
+                channel.setErr(new NoCloseOutputStream(System.err));
+                channel.open();
+                channel.waitFor(ClientChannel.CLOSED, 0);
+            } finally {
+                session.close(false);
+            }
+        } finally {
+            client.stop();
+        }
+
+        return null;
+    }
+
+    public String readLine(String msg) throws IOException {
+        StringBuffer sb = new StringBuffer();
+        System.err.print(msg);
+        System.err.flush();
+        for (;;) {
+            int c = super.session.getKeyboard().read();
+            if (c < 0) {
+                return null;
+            }
+            System.err.print((char) c);
+            if (c == '\r' || c == '\n') {
+                break;
+            }
+            sb.append((char) c);
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshTerminal.java b/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshTerminal.java
index 819f205..601c6b0 100644
--- a/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshTerminal.java
+++ b/karaf/gshell/gshell-ssh/src/main/java/org/apache/felix/karaf/gshell/ssh/SshTerminal.java
@@ -33,6 +33,9 @@
     public void initializeTerminal() throws Exception {
     }
 
+    public void restoreTerminal() throws Exception {
+    }
+
     public int getTerminalWidth() {
         return Integer.valueOf(this.environment.getEnv().get("COLUMNS"));
     }
diff --git a/karaf/gshell/gshell-ssh/src/main/resources/OSGI-INF/blueprint/gshell-ssh.xml b/karaf/gshell/gshell-ssh/src/main/resources/OSGI-INF/blueprint/gshell-ssh.xml
index 0af6137..e0147a5 100644
--- a/karaf/gshell/gshell-ssh/src/main/resources/OSGI-INF/blueprint/gshell-ssh.xml
+++ b/karaf/gshell/gshell-ssh/src/main/resources/OSGI-INF/blueprint/gshell-ssh.xml
@@ -33,12 +33,10 @@
     </cm:property-placeholder>
 
     <command-bundle xmlns="http://felix.apache.org/karaf/xmlns/gshell/v1.0.0">
-        <!--
         <command name="ssh/ssh">
             <action class="org.apache.felix.karaf.gshell.ssh.SshAction">
             </action>
         </command>
-        -->
         <command name="ssh/sshd">
             <action class="org.apache.felix.karaf.gshell.ssh.SshServerAction">
                 <property name="sshServerId">