[jboss-cvs] JBossAS SVN: r88114 - in projects/fresh/trunk: fresh-ssh and 4 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Fri May 1 19:18:15 EDT 2009


Author: ctomc
Date: 2009-05-01 19:18:15 -0400 (Fri, 01 May 2009)
New Revision: 88114

Added:
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java
Removed:
   projects/fresh/trunk/fresh-ssh/etc/
   projects/fresh/trunk/fresh-ssh/src/main/java/com/
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/parsek/
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/
Modified:
   projects/fresh/trunk/etc/fresh/ssh/platform.xml
   projects/fresh/trunk/etc/fresh/ssh/server.xml
   projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java
Log:
FRESH-2 configuration for ssh is now loaded from classpath

Modified: projects/fresh/trunk/etc/fresh/ssh/platform.xml
===================================================================
--- projects/fresh/trunk/etc/fresh/ssh/platform.xml	2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/etc/fresh/ssh/platform.xml	2009-05-01 23:18:15 UTC (rev 88114)
@@ -4,9 +4,9 @@
 -->
 <PlatformConfiguration>
    <!-- The process provider for executing and redirecting a process -->
-   <NativeProcessProvider>org.jboss.fresh.ssh.cp2.SSHShell</NativeProcessProvider>
+   <NativeProcessProvider>org.jboss.fresh.ssh.SSHShell</NativeProcessProvider>
    <!-- The authentication provider for authenticating users and obtaining user information -->
-   <NativeAuthenticationProvider>org.jboss.fresh.ssh.cp2.Cp2AuthenticationProvider</NativeAuthenticationProvider>
+   <NativeAuthenticationProvider>org.jboss.fresh.ssh.Cp2AuthenticationProvider</NativeAuthenticationProvider>
    <!-- The file system provider for SFTP -->
    <NativeFileSystemProvider>org.jboss.fresh.vfs</NativeFileSystemProvider>
    <!-- Native settings which may be used by the process or authentication provider -->

Modified: projects/fresh/trunk/etc/fresh/ssh/server.xml
===================================================================
--- projects/fresh/trunk/etc/fresh/ssh/server.xml	2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/etc/fresh/ssh/server.xml	2009-05-01 23:18:15 UTC (rev 88114)
@@ -4,16 +4,16 @@
 -->
 <ServerConfiguration>
    <!-- Path to server private key file - you need to generate it in advance of course. -->
-   <ServerHostKey PrivateKeyFile="../fresh/ssh/priv.skk" />
+   <ServerHostKey PrivateKeyFile="priv.skk" />
 
    <!-- Possible values for these are: ... -->
    <!--Subsytem Type="" Name="" Provider="" /-->
    
    <!-- The file system provider for SFTP -->
-	<AuthenticationBanner>../fresh/ssh/hello.txt</AuthenticationBanner>
+	<!--AuthenticationBanner>hello.txt</AuthenticationBanner--> <!-- currently doesnt work becouse of issues with loading-->
 	<MaxConnections>3</MaxConnections>
 	<MaxAuthentications>3</MaxAuthentications>
-	<ListenAddress>192.168.2.35</ListenAddress>
+	<ListenAddress>127.0.0.1</ListenAddress>
 	<Port>2022</Port>
 	<CommandPort>2024</CommandPort>
 	<TerminalProvider>vt100</TerminalProvider>
@@ -25,7 +25,7 @@
 	
 	<RequiredAuthentication>password</RequiredAuthentication>
 
-	<AuthorizationFile>../fresh/ssh/authorization.xml</AuthorizationFile>
+	<AuthorizationFile>authorization.xml</AuthorizationFile>
 	<UserConfigDirectory>users</UserConfigDirectory>
 	<AllowTcpForwarding>false</AllowTcpForwarding>
    

Modified: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java	2009-05-01 23:01:46 UTC (rev 88113)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/deployer/SSHService.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -1,7 +1,11 @@
 package org.jboss.fresh.deployer;
 
+import org.jboss.fresh.ssh.DaemonStarter;
+import org.jboss.logging.Logger;
 
+
 public class SSHService extends ServiceModule implements SSHServiceMBean {
+    private static final Logger log =  Logger.getLogger(SSHService.class);
 	private Thread th = null;
 	private String home;
 	private String ssjndi;
@@ -32,11 +36,11 @@
 				//System.setProperty("sshtools.home", home);
 				//com.sshtools.j2ssh.SshServer.main(new String [] {"-start"});
 				try {
-					org.jboss.fresh.ssh.cp2.DaemonStarter.setConfigDir(home);
-					org.jboss.fresh.ssh.cp2.DaemonStarter.setSystemShellJNDI(ssjndi);
-					org.jboss.fresh.ssh.cp2.DaemonStarter.initialize();
+					DaemonStarter.setConfigDir(home);
+					DaemonStarter.setSystemShellJNDI(ssjndi);
+					DaemonStarter.initialize();
 				} catch (Exception ex) {
-					ex.printStackTrace();
+					log.error("could not start ssh service",ex);
 				}
 			}
 		};
@@ -45,7 +49,7 @@
 
 	public void doStop() {
 		try {
-			org.jboss.fresh.ssh.cp2.DaemonStarter.stop("Stop command issued");
+			DaemonStarter.stop("Stop command issued");
 		} catch (java.io.IOException ex) {
 			throw new RuntimeException(ex);
 		}

Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/Cp2AuthenticationProvider.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2AuthenticationProvider.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,80 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.NativeAuthenticationProvider;
+import org.apache.log4j.Logger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * @version 1.0
+ */
+
+public class Cp2AuthenticationProvider extends NativeAuthenticationProvider {
+
+    private static Logger log = Logger.getLogger(Cp2AuthenticationProvider.class);
+    private static Cp2AuthenticationProvider instance;
+    private Properties p = new Properties();
+
+
+    public Cp2AuthenticationProvider() {
+        super();
+
+        File users = null;
+        try {
+            users = new File(System.getProperty("sshtools.home") + File.separator + "conf" + File.separator + "users.conf");
+            p.load(new FileInputStream(users));
+        } catch (Exception ex) {
+            log.warn("Could not open users file: " + users);
+        }
+    }
+
+    public String getHomeDirectory(String username) {
+        return "/";
+    }
+
+    //for now a hard coded path is returned
+    public String getHomeDirectory(String username, Map tokens) {
+        return System.getProperty("sshtools.home");
+    }
+
+    public boolean logonUser(String username, String password, Map tokens) {
+
+//    if (username.equals("root") && password.equals("root")){
+//      log.info(username + " has passed authentication");
+//      return true;
+        String reguserpass = p.getProperty(username);
+        if (reguserpass != null && reguserpass.equals(password)) {
+            return true;
+        } else {
+            log.info(username + " has failed authentication");
+            return false;
+        }
+    }
+
+    public boolean logonUser(String username, Map tokens) {
+        return true;
+    }
+
+
+    public boolean changePassword(String username, String oldpass, String newpass) {
+        return false;
+    }
+
+    public void logoffUser() {
+
+    }
+
+    public boolean logonUser(String user) {
+        return true;
+    }
+
+    public boolean logonUser(String user, String pass) {
+        return true;
+    }
+
+
+}
\ No newline at end of file

Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/Cp2VFSProvider.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/Cp2VFSProvider.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,463 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.InvalidHandleException;
+import com.sshtools.daemon.platform.NativeFileSystemProvider;
+import com.sshtools.daemon.platform.PermissionDeniedException;
+import com.sshtools.daemon.platform.UnsupportedFileOperationException;
+import com.sshtools.j2ssh.io.UnsignedInteger32;
+import com.sshtools.j2ssh.io.UnsignedInteger64;
+import com.sshtools.j2ssh.sftp.FileAttributes;
+import com.sshtools.j2ssh.sftp.SftpFile;
+import org.apache.log4j.Logger;
+import org.jboss.fresh.registry.RegistryContext;
+import org.jboss.fresh.shell.SystemShell;
+import org.jboss.fresh.vfs.*;
+
+import java.io.EOFException;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class Cp2VFSProvider extends NativeFileSystemProvider {
+
+    private static final Logger log = Logger.getLogger(Cp2VFSProvider.class);
+
+    private int fileid = 1;
+    private DecimalFormat fmt;
+
+    HashMap openfiles = new HashMap();
+    VFS vfs;
+
+    FileName root;
+
+    private synchronized String getKey() {
+        return fmt.format(fileid++);
+    }
+
+    public Cp2VFSProvider() {
+
+
+        try {
+            fmt = new DecimalFormat("00000000");
+
+            RegistryContext ctx = new RegistryContext();
+            SystemShell ssh = (SystemShell) ctx.lookup("java:/CP2/SystemShell");
+            vfs = ssh.getVFS();
+            log.info("Successfully initialized vfs: " + vfs);
+
+            root = new FileName("/");
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            throw new RuntimeException(e);
+        }
+
+    }
+
+
+    /**
+     * true if file exists, false otherwise
+     */
+    public boolean fileExists(String path) throws IOException {
+        //log.error("fileExists : " + path);
+        return true;
+    }
+
+
+    /**
+     * Ugibam ampak mislim da pomeni to:
+     * in:  ../../boo/foo		out:  /boo/foo
+     * in:  tmp/../dev		out:  dev
+     */
+    public String getCanonicalPath(String path) throws IOException, FileNotFoundException {
+        //log.error("getCanonicalPath : " + path);
+        FileName fname = new FileName(path);
+        return fname.toString();
+    }
+
+
+    /**
+     * Ugibam ampak mislim da pomeni to:
+     * in:  ../../boo/foo		out:  /home/user/../../boo/foo
+     * in:  tmp/../dev		out:  /root/tmp/../dev
+     */
+    public String getRealPath(String path) throws FileNotFoundException {
+        //log.error("getRealPath : " + path);
+        FileName fname = root.absolutize(path);
+        return fname.toString();
+    }
+
+
+    /**
+     * creates the specified directory and returns true or false depending on success
+     */
+    public boolean makeDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("makeDirectory : " + path);
+        return true;
+    }
+
+
+    /**
+     * FileAttributes je zelo o�itno struktura z datote�nimi atributi.
+     * <p/>
+     * From http://www.openssh.org/txt/draft-ietf-secsh-filexfer-02.txt
+     * <p/>
+     * When
+     * sending it to the server, the flags field specifies which attributes
+     * are included, and the server will use default values for the
+     * remaining attributes (or will not modify the values of remaining
+     * attributes).  When receiving attributes from the server, the flags
+     * specify which attributes are included in the returned data.  The
+     * server normally returns all attributes it knows about.
+     * <p/>
+     * uint32   flags
+     * uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
+     * uint32   uid            present only if flag SSH_FILEXFER_ATTR_UIDGID
+     * uint32   gid            present only if flag SSH_FILEXFER_ATTR_UIDGID
+     * uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+     * uint32   atime          present only if flag SSH_FILEXFER_ACMODTIME
+     * uint32   mtime          present only if flag SSH_FILEXFER_ACMODTIME
+     * uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+     * string   extended_type
+     * string   extended_data
+     * ...      more extended data (extended_type - extended_data pairs),
+     * so that number of pairs equals extended_count
+     */
+    public FileAttributes getFileAttributes(String path) throws IOException, FileNotFoundException {
+        //log.error("getFileAttributes : " + path);
+
+        FileInfo inf = vfs.getFileInfo(null, new FileName(path), true);
+        if (inf == null) throw new FileNotFoundException(path);
+
+        return info2Attrs(inf);
+    }
+
+
+    /**
+     * FileAttributes je zelo o�itno struktura z datote�nimi atributi. Vsak file ima o�itno file descriptor ki je v obliki byte [].
+     */
+    public FileAttributes getFileAttributes(byte[] handle) throws IOException, InvalidHandleException {
+        //log.error("getFileAttributes 2 : " + new String(handle));
+
+        String shandle = new String(handle);
+
+        FileData data = (FileData) openfiles.get(shandle);
+        if (data == null) throw new FileNotFoundException(String.valueOf(data.name));
+
+
+        return info2Attrs(data.info);
+    }
+
+
+    /**
+     * Dobi file handle za directory path
+     */
+    public byte[] openDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("openDirectory : " + path);
+
+        byte[] key = getKey().getBytes();
+
+        FileData data = new FileData();
+        data.originalName = path;
+        data.name = root.absolutize(path);
+        data.info = vfs.getFileInfo(null, data.name, false);
+
+        if (data.info == null) throw new FileNotFoundException(String.valueOf(data.name));
+
+        openfiles.put(new String(key), data);
+        return key;
+    }
+
+
+    /**
+     * Zlistaj vsebino direktorijev. Posamezen file predstavi z SftpFile strukturo. Za input poda handle, ki enozna�no identificira
+     */
+    public SftpFile[] readDirectory(byte[] handle) throws InvalidHandleException, EOFException, IOException {
+
+        String shandle = new String(handle);
+
+        //log.error("readDirectory : " + shandle);
+
+        FileData data = (FileData) openfiles.get(shandle);
+//log.error("chkp: 2");
+        if (data == null) throw new InvalidHandleException(shandle);
+//log.error("chkp: 3");
+        if (data.done) throw new EOFException();
+//log.error("chkp: 4");
+        List ls = vfs.list(null, data.name, false);
+        if (ls == null) return null;
+//log.error("chkp: 5");
+
+
+        SftpFile[] lesfiches = new SftpFile[ls.size()];
+
+        Iterator it = ls.iterator();
+        for (int i = 0; it.hasNext(); i++) {
+            FileInfo finfo = (FileInfo) it.next();
+            lesfiches[i] = new SftpFile(finfo.getFileName().getName(), info2Attrs(finfo));
+        }
+
+        data.done = true;
+
+        return lesfiches;
+    }
+
+
+    /**
+     * Odpri file. Flags opredeljujejo ali samo za branje ali tudi za pisanje. FileAttributes ne vem �emu slu�ijo
+     * Vrnjen handle predstavlja odprt file.
+     */
+    public byte[] openFile(String path, UnsignedInteger32 flags, FileAttributes attrs) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("openFile : " + path + ", flags: " + flags + ", attrs: " + attrs);
+
+        byte[] key = getKey().getBytes();
+
+        try {
+            FileData data = new FileData();
+            data.originalName = path;
+            data.name = new FileName(path);
+            data.info = vfs.getFileInfo(null, data.name, false);
+
+//log.error("info = " + data.info);
+
+            if ((flags.intValue() & 0x01) == 0x01) {
+                // read
+                if (data.info == null) throw new FileNotFoundException(String.valueOf(data.name));
+            } else {
+                // write
+                if (data.info == null) {
+                    FileInfo finf = new FileInfo(data.name, FileInfo.TYPE_FILE);
+                    finf.setMime("x-application/octet-stream");
+                    Date date = new Date();
+                    finf.setCreateDate(date);
+                    finf.setLastModified(date);
+//log.error("creating file: " + finf);
+                    String tag = vfs.createFile(null, finf);
+                    finf.setTag(tag);
+                    data.info = finf;
+                }
+            }
+//log.error("Putting key: " + new String(key) + " : " + data.info);
+            openfiles.put(new String(key), data);
+        } catch (VFSException ex) {
+            if (ex.getCause() instanceof IOException) throw (IOException) ex.getCause();
+            if (ex.getCause() instanceof RuntimeException) throw (RuntimeException) ex.getCause();
+            IOException e = new IOException("Operation failed");
+            e.initCause(ex);
+            throw e;
+        }
+
+        return key;
+    }
+
+
+    /**
+     * Beri iz odprtega file - specificiran je offset v file in dol�ina. Vrne�
+     * Vrnjen byte[] vsebuje podatke iz file-a
+     */
+    public byte[] readFile(byte[] handle, UnsignedInteger64 offset, UnsignedInteger32 len) throws InvalidHandleException, EOFException, IOException {
+
+        String shandle = new String(handle);
+
+        //log.error("readFile +++ : " + shandle + ", offs: " + offset + ", len: " + len);
+
+        long loffset = offset.longValue();
+        int ilen = len.intValue();
+
+        FileData data = (FileData) openfiles.get(shandle);
+//log.error("chkp: 2");
+        if (data == null) throw new InvalidHandleException(shandle);
+//log.error("chkp: 3");
+        if (data.done) throw new EOFException();
+//log.error("chkp: 4");
+        FileOpInfo op = new FileOpInfo();
+        op.filename = data.name;
+        op.offset = loffset;
+        op.tag = data.info.getTag();
+
+        FileReadInfo read = vfs.read(null, op);
+
+        if (read == null) throw new EOFException();
+
+        if (read.buf.length > ilen) {
+            byte[] buf = new byte[ilen];
+            System.arraycopy(read.buf, 0, buf, 0, ilen);
+        }
+
+        if (loffset + ilen >= data.info.getLength())
+            data.done = true;
+
+        return read.buf;
+    }
+
+
+    /**
+     * Pi�i v odprti file - specificiran je offset v file kjer za�ni, buffer, offset v bufferju in dol�ina v bufferju
+     */
+    public void writeFile(byte[] handle, UnsignedInteger64 offset, byte[] data, int off, int len) throws InvalidHandleException, IOException {
+
+        String shandle = new String(handle);
+
+        //log.error("writeFile: " + shandle + ", offs: " + offset + ", off: " + off + ", len: " + len);
+        //log.error("data: " + new String(data));
+        //log.error("payload: " + new String(data, off, len));
+
+        FileData dat = (FileData) openfiles.get(shandle);
+        if (dat == null) throw new InvalidHandleException(shandle);
+
+        FileOpInfo op = new FileOpInfo();
+
+        op.filename = dat.name;
+        op.offset = offset.longValue();
+        op.tag = dat.info.getTag();
+
+        byte[] buf = null;
+
+        if (off == 0 && len == data.length) {
+            buf = data;
+        } else {
+            buf = new byte[len];
+            System.arraycopy(data, off, buf, 0, len);
+        }
+
+        op.buf = buf;
+
+        try {
+            vfs.write(null, op);
+
+        } catch (VFSException ex) {
+            if (ex.getCause() instanceof IOException) throw (IOException) ex.getCause();
+            if (ex.getCause() instanceof RuntimeException) throw (RuntimeException) ex.getCause();
+            IOException iox = new IOException();
+            iox.initCause(ex);
+            throw iox;
+        }
+    }
+
+
+    /**
+     * Zapri odprt file - sprosti resurse
+     */
+    public void closeFile(byte[] handle) throws InvalidHandleException, IOException {
+        //log.error("closeFile: " + new String(handle));
+    }
+
+
+    /**
+     * Izbri�i file
+     */
+    public void removeFile(String path) throws PermissionDeniedException, IOException, FileNotFoundException {
+        //log.error("removeFile: " + path);
+    }
+
+
+    /**
+     * Preimenuj file
+     */
+    public void renameFile(String oldpath, String newpath) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("renameFile: " + oldpath + "  to  " + newpath);
+    }
+
+
+    /**
+     * Odstrani direktorij
+     */
+    public void removeDirectory(String path) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("removeDirectory: " + path);
+    }
+
+
+    /**
+     * Nastavi atribute file-a
+     */
+    public void setFileAttributes(String path, FileAttributes attrs) throws PermissionDeniedException, IOException, FileNotFoundException {
+        //log.error("setFileAttributes: " + path + ", attrs: " + attrs);
+    }
+
+
+    /**
+     * Nastavi atribute odprtega file-a
+     */
+    public void setFileAttributes(byte[] handle, FileAttributes attrs) throws PermissionDeniedException, IOException, InvalidHandleException {
+        //log.error("setFileAttributes: " + new String(handle) + ", attrs: " + attrs);
+    }
+
+
+    /**
+     * Resolvaj symbolic link
+     */
+    public SftpFile readSymbolicLink(String path) throws UnsupportedFileOperationException, FileNotFoundException, IOException, PermissionDeniedException {
+        //log.error("readSymbolicLink: " + path);
+        SftpFile file = new SftpFile("/hokuspokus3");
+        return file;
+    }
+
+
+    /**
+     * Ustvari simboli�en link
+     */
+    public void createSymbolicLink(String link, String target) throws UnsupportedFileOperationException, FileNotFoundException, IOException, PermissionDeniedException {
+        //log.error("createSymbolicLink: " + link + " -> " + target);
+    }
+
+
+    public String getDefaultPath(String username) {
+        //log.error("getDefaultPath: " + username);
+        return "/";
+    }
+
+
+    /**
+     * Preveri, ali lahko user dostopa s specificiranimi permissioni do specificiranega file-a
+     */
+    public void verifyPermissions(String username, String path, String permissions) throws PermissionDeniedException, FileNotFoundException, IOException {
+        //log.error("verifyPermissions: user:" + username + ", path: " + path + ", perms: " + permissions);
+    }
+
+
+    static class FileData {
+        String originalName;
+        FileName name;
+        FileInfo info;
+        boolean done;
+    }
+
+
+    static FileAttributes info2Attrs(FileInfo inf) {
+        FileAttributes attrs = new FileAttributes();
+        attrs.setSize(new UnsignedInteger64(String.valueOf(inf.getLength())));
+        //log.error("set size: " + attrs.getSize());
+
+        //long permissions = 0;
+        //if(inf.isFile()) {
+        //	permissions |= FileAttributes.S_IFREG;
+        //} else if(inf.isDirectory()) {
+        //	permissions |= FileAttributes.S_IFDIR;
+        //}
+
+        //attrs.setPermissions(new UnsignedInteger32(permissions));
+        attrs.setPermissionsFromMaskString("0777");
+        //log.error("set permissions: " + attrs.getPermissions());
+
+        long perms = attrs.getPermissions().longValue();
+        if (inf.isFile()) {
+            perms |= FileAttributes.S_IFREG;
+        } else if (inf.isDirectory()) {
+            perms |= FileAttributes.S_IFDIR;
+        } else if (inf.isLink()) {
+            perms |= FileAttributes.S_IFLNK;
+        }
+
+        attrs.setPermissions(new UnsignedInteger32(String.valueOf(perms)));
+
+
+		UnsignedInteger32 time = new UnsignedInteger32(String.valueOf(inf.getLastModified().getTime()/1000L));
+		attrs.setTimes(time, time);
+
+		return attrs;
+
+	}
+}
\ No newline at end of file

Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/DaemonStarter.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/DaemonStarter.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,63 @@
+/*
+ * Created on 2004.5.9
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.SshDaemon;
+import com.sshtools.common.configuration.XmlConfigurationContext;
+import com.sshtools.daemon.configuration.XmlServerConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationLoader;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+
+import java.io.IOException;
+
+
+/**
+ * @author Marko Strukelj
+ * @author Tomaz Cerar
+ *
+ */
+public class DaemonStarter extends SshDaemon {
+
+	private static String rootDir = "";
+	private static String systemShellJNDI = "";
+
+	public static void setConfigDir(String dir) {
+		rootDir = dir;
+	}
+
+	public static void setSystemShellJNDI(String ss){
+ 		systemShellJNDI = ss;
+ 	}
+
+	public static void initialize() throws IOException, ConfigurationException {
+
+		FreshXmlServerConfigurationContext context = new FreshXmlServerConfigurationContext();
+        context.setServerConfigurationResource("server.xml");
+		context.setPlatformConfigurationResource("platform.xml");
+		ConfigurationLoader.initialize(false, context);
+
+
+
+
+		FreshXmlConfigurationContext context2 = new FreshXmlConfigurationContext();
+		context2.setFailOnError(false);
+		context2.setAPIConfigurationResource("sshtools.xml");
+		context2.setAutomationConfigurationResource("automation.xml");
+		ConfigurationLoader.initialize(false, context2);
+
+
+
+
+		if(systemShellJNDI!=null && !systemShellJNDI.trim().equals(""))
+			SSHShell.setSystemShellJNDI(systemShellJNDI);
+
+		start();
+	}
+	
+
+}

Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshPlatformConfiguration.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,23 @@
+package org.jboss.fresh.ssh;
+
+import org.jboss.logging.Logger;
+import org.xml.sax.SAXException;
+import com.sshtools.daemon.configuration.PlatformConfiguration;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:01
+ * @modifiedBy $Author$
+ */
+public class FreshPlatformConfiguration extends PlatformConfiguration {
+    private static final Logger log = Logger.getLogger(FreshPlatformConfiguration.class);
+
+    public FreshPlatformConfiguration(InputStream inputStream) throws SAXException, ParserConfigurationException, IOException {
+        super(inputStream);
+    }
+}

Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshServerConfiguration.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,113 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.configuration.ServerConfiguration;
+import com.sshtools.j2ssh.transport.publickey.InvalidSshKeyException;
+import com.sshtools.j2ssh.transport.publickey.SshPrivateKey;
+import com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile;
+import org.jboss.fresh.io.IOUtils;
+import org.jboss.logging.Logger;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:32
+ * @modifiedBy $Author$
+ */
+public class FreshServerConfiguration extends ServerConfiguration {
+    private static final Logger log = Logger.getLogger(FreshServerConfiguration.class);
+    private String currentElement;
+    private Map<String, SshPrivateKey> serverKeys;
+
+    public FreshServerConfiguration(InputStream in) throws SAXException, ParserConfigurationException, IOException {
+        super(in);
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qname, Attributes attrs) throws SAXException {
+        if (currentElement != null) {
+            if (currentElement.equals("ServerConfiguration")) {
+
+                if (qname.equals("ServerHostKey")) {
+                    String privateKey = attrs.getValue("PrivateKeyFile");
+
+                    if (privateKey == null) {
+                        throw new SAXException(
+                                "Required attributes missing from <ServerHostKey> element");
+                    }
+
+                    log.debug("ServerHostKey PrivateKeyFile=" + privateKey);
+
+
+                    /*File f = new File(privateKey);
+
+                    if (!f.exists()) {
+                        privateKey = ConfigurationLoader.getConfigurationDirectory() +
+                            privateKey;
+                        f = new File(privateKey);
+                    }*/
+
+                    try {
+                        InputStream keyStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(privateKey);
+
+
+                        if (keyStream != null) {
+                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                            IOUtils.copy(keyStream, baos);
+                            byte[] keyBytes = baos.toByteArray();
+                            keyStream.close();
+                            baos.close();
+                            SshPrivateKeyFile pkf = SshPrivateKeyFile.parse(keyBytes);
+                            SshPrivateKey key = pkf.toPrivateKey(null);
+                            serverKeys.put(key.getAlgorithmName(), key);
+                        } else {
+                            log.warn("Private key file '" + privateKey +
+                                    "' could not be found");
+                        }
+                    } catch (InvalidSshKeyException ex) {
+                        log.warn("Failed to load private key '" + privateKey, ex);
+                    } catch (IOException ioe) {
+                        log.warn("Failed to load private key '" + privateKey,
+                                ioe);
+                    }
+                } else {
+                    super.startElement(uri, localName, qname, attrs);
+                }
+            }
+        } else {
+            super.startElement(uri, localName, qname, attrs);
+        }
+
+        currentElement = qname;
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qname) throws SAXException {
+        if (currentElement != null) {
+            if (!currentElement.endsWith("ServerHostKey")) {
+                super.endElement(uri, localName, qname);
+            }
+            currentElement = null;
+        }
+    }
+
+    @Override
+    public void reload(InputStream in) throws SAXException, ParserConfigurationException, IOException {
+        serverKeys = new HashMap<String, SshPrivateKey>();
+        super.reload(in);
+        currentElement = null;
+    }
+
+    public Map getServerHostKeys() {
+        return serverKeys;
+    }
+}
+

Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlConfigurationContext.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,114 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.common.automate.AutomationConfiguration;
+import com.sshtools.common.configuration.SshAPIConfiguration;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import com.sshtools.j2ssh.configuration.ConfigurationLoader;
+
+import org.jboss.logging.Logger;
+
+import java.util.HashMap;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-01 23:52
+ * @modifiedBy $Author$
+ */
+public class FreshXmlConfigurationContext implements ConfigurationContext {
+    private static final Logger log = Logger.getLogger(FreshXmlConfigurationContext.class);
+
+
+    HashMap<Class, Object> configurations = new HashMap<Class, Object>();
+    String apiResource = "sshtools.xml";
+    String automationResource = "automation.xml";
+    private boolean failOnError = false;
+
+    /**
+     * Creates a new XmlConfigurationContext object.
+     */
+    public FreshXmlConfigurationContext() {
+    }
+
+    /**
+     * @param apiResource
+     */
+    public void setAPIConfigurationResource(String apiResource) {
+        this.apiResource = apiResource;
+    }
+
+    /**
+     * @param automationResource
+     */
+    public void setAutomationConfigurationResource(String automationResource) {
+        this.automationResource = automationResource;
+    }
+
+    /**
+     * @param failOnError
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * @throws ConfigurationException
+     */
+    public void initialize() throws ConfigurationException {
+
+        if (apiResource != null) {
+            try {
+                SshAPIConfiguration x = new SshAPIConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+                        apiResource));
+                configurations.put(com.sshtools.j2ssh.configuration.SshAPIConfiguration.class,
+                        x);
+            } catch (Exception ex) {
+                if (failOnError) {
+                    throw new ConfigurationException(ex.getMessage());
+                } else {
+                    log.info(apiResource + " could not be found: " +
+                            ex.getMessage());
+                }
+            }
+        }
+
+        if (automationResource != null) {
+            try {
+                AutomationConfiguration y = new AutomationConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+                        automationResource));
+                configurations.put(com.sshtools.common.automate.AutomationConfiguration.class,
+                        y);
+            } catch (Exception ex) {
+                if (failOnError) {
+                    throw new ConfigurationException(ex.getMessage());
+                } else {
+                    log.info(automationResource + " could not be found: " +
+                            ex.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * @param cls
+     * @return
+     */
+    public boolean isConfigurationAvailable(Class cls) {
+        return configurations.containsKey(cls);
+    }
+
+    /**
+     * @param cls
+     * @return
+     * @throws ConfigurationException
+     */
+    public Object getConfiguration(Class cls) throws ConfigurationException {
+        if (configurations.containsKey(cls)) {
+            return configurations.get(cls);
+        } else {
+            throw new ConfigurationException(cls.getName() +
+                    " configuration not available");
+        }
+    }
+}

Added: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/FreshXmlServerConfigurationContext.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,100 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.configuration.PlatformConfiguration;
+import com.sshtools.daemon.configuration.ServerConfiguration;
+import com.sshtools.j2ssh.configuration.ConfigurationContext;
+import com.sshtools.j2ssh.configuration.ConfigurationException;
+import org.jboss.logging.Logger;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.HashMap;
+
+/**
+ * @author Tomaz Cerar
+ * @version $Revision$
+ * @created 2009-05-02 00:00
+ * @modifiedBy $Author$
+ */
+public class FreshXmlServerConfigurationContext implements ConfigurationContext {
+    private static final Logger log = Logger.getLogger(FreshXmlServerConfigurationContext.class);
+
+    HashMap<Class, DefaultHandler> configurations = new HashMap<Class, DefaultHandler>();
+    String serverResource = null;
+    String platformResource = null;
+    boolean failOnError = true;
+
+
+    /**
+     * @param serverResource
+     */
+    public void setServerConfigurationResource(String serverResource) {
+        this.serverResource = serverResource;
+    }
+
+    /**
+     * @param platformResource
+     */
+    public void setPlatformConfigurationResource(String platformResource) {
+        this.platformResource = platformResource;
+    }
+
+    /**
+     * @param failOnError
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * @throws ConfigurationException
+     */
+    public void initialize() throws ConfigurationException {
+        if (serverResource != null) {
+            try {
+                ServerConfiguration y = new FreshServerConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+                        serverResource));
+                configurations.put(ServerConfiguration.class, y);
+            } catch (Exception ex) {
+                log.error("could not init server configuration ", ex);
+                if (failOnError) {
+
+                    throw new ConfigurationException(ex.getMessage());
+                }
+            }
+        }
+
+        if (platformResource != null) {
+            try {
+                PlatformConfiguration z = new FreshPlatformConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream(
+                        platformResource));
+                configurations.put(PlatformConfiguration.class, z);
+            } catch (Exception ex) {
+                if (failOnError) {
+                    throw new ConfigurationException(ex.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * @param cls
+     * @return
+     */
+    public boolean isConfigurationAvailable(Class cls) {
+        return configurations.containsKey(cls);
+    }
+
+    /**
+     * @param cls
+     * @return
+     * @throws ConfigurationException
+     */
+    public Object getConfiguration(Class cls) throws ConfigurationException {
+        if (configurations.containsKey(cls)) {
+            return configurations.get(cls);
+        } else {
+            throw new ConfigurationException(cls.getName() +
+                    " configuration not available");
+        }
+    }
+}

Copied: projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java (from rev 88108, projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/cp2/SSHShell.java)
===================================================================
--- projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java	                        (rev 0)
+++ projects/fresh/trunk/fresh-ssh/src/main/java/org/jboss/fresh/ssh/SSHShell.java	2009-05-01 23:18:15 UTC (rev 88114)
@@ -0,0 +1,1772 @@
+package org.jboss.fresh.ssh;
+
+import com.sshtools.daemon.platform.NativeProcessProvider;
+import com.sshtools.j2ssh.SshThread;
+import org.apache.log4j.Logger;
+import org.jboss.fresh.cpii.services.PoolRunner;
+import org.jboss.fresh.io.Buffer;
+import org.jboss.fresh.io.BufferInputStream;
+import org.jboss.fresh.io.EOLFixInputStream;
+import org.jboss.fresh.io.PrintWriter2;
+import org.jboss.fresh.registry.RegistryContext;
+import org.jboss.fresh.shell.ProcessInfo;
+import org.jboss.fresh.shell.ShellException;
+import org.jboss.fresh.shell.ShellOutputStream;
+import org.jboss.fresh.shell.SystemShell;
+import org.jboss.fresh.shell.impl.ShellImpl;
+
+import javax.naming.NamingException;
+import java.io.*;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class SSHShell extends NativeProcessProvider {
+
+    static final int SHELL_MODE = 0;
+    static final int PROCESS_MODE = 1;
+
+    static final int OVERWRITE = 0;
+    static final int INSERT = 1;
+
+    static private String ssjndi = "java:/FRESH/SystemShell";
+    static private String homeDir = "../fresh/users";
+    static private int MAX_HISTORY_SIZE = 200;
+
+    static final Logger log = Logger.getLogger(SSHShell.class);
+
+    // default mode
+    int mode = SHELL_MODE;
+    boolean mustExit = false;
+    int insMode = INSERT;
+
+    Throwable lastError;
+
+    // processes command line input of this shell
+    LineEditor editor;
+    InMasterOutputStream masterIn;
+    OutMasterInputStream masterOut;
+    StdErrorInputStream stdErr;
+
+    ShellImpl shell;
+
+    ProcessInfo iproc;
+
+    String user = "unknown";
+    String host = "localhost";
+
+    int screen_rows;
+    int screen_cols;
+
+    //static PoolImpl pool;
+
+    public static void setSystemShellJNDI(String name) {
+        ssjndi = name;
+    }
+
+
+    public SSHShell() {
+
+        try {
+            user = SshThread.getCurrentThread().getUsername();
+        } catch (Throwable th) {
+            log.error("Failed to retrieve username: ", th);
+        }
+
+        try {
+            host = InetAddress.getLocalHost().getHostName();
+            int dot = host.indexOf(".");
+            if (dot != -1) host = host.substring(0, dot);
+        } catch (UnknownHostException ex) {
+            log.error("Failed to retrieve hostname: ", ex);
+        }
+
+        StringBuffer errMessage = new StringBuffer();
+
+        try {
+            RegistryContext ctx = new RegistryContext();
+            SystemShell ssh = (SystemShell) ctx.lookup(ssjndi);
+            shell = (ShellImpl) ssh.startSession(null, false);
+
+            // go to root directory
+            try {
+                shell.executeAsObject("cd /");
+            } catch (ShellException ex) {
+                log.warn("Error while setting current dir to /: ", ex);
+                errMessage.append("Failed to set current dir to /\r\n");
+            }
+
+
+            File profile = getHomeFile(".profile");
+            try {
+                if (profile != null)
+                    shell.executeAsObject("exec --ex &< " + profile.getAbsolutePath());
+            } catch (ShellException e) {
+                log.warn("Error while executing .profile: " + profile, e);
+                errMessage.append("Failed to execute .profile\r\n");
+            }
+
+            log.info("Successfully initialized shell: " + shell);
+
+        } catch (NamingException e) {
+            log.error("Exception while initializin SSHShell: ", e);
+            throw new RuntimeException(e);
+        } catch (ShellException e) {
+            log.error("Exception while initializin SSHShell: ", e);
+            throw new RuntimeException(e);
+        }
+
+
+        masterIn = new InMasterOutputStream();
+        masterOut = new OutMasterInputStream();
+        stdErr = new StdErrorInputStream();
+
+        editor = new LineEditor();
+
+        //setupThreadPool();
+
+        if (errMessage.length() > 0)
+            masterOut.addBytes(errMessage.toString().getBytes());
+    }
+
+
+    public File getHomeFile(String fname) {
+
+        String hUser = user;
+        if (hUser == null || hUser.length() == 0)
+            hUser = "root";
+
+        File userDir = new File(homeDir, hUser);
+        if (!userDir.isDirectory()) {
+            if (!userDir.mkdirs())
+                log.warn("Home directory for user " + user + " does not exist and could not be created.");
+        }
+
+        if (userDir.isDirectory()) {
+            File tfile = new File(userDir, fname);
+            if (tfile.isFile())
+                return tfile;
+        }
+
+        return null;
+    }
+
+
+    public InputStream getInputStream() throws IOException {
+        return masterOut;
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        return masterIn;
+    }
+
+    public InputStream getStderrInputStream() throws IOException {
+        return stdErr;
+    }
+
+    public void kill() {
+        log.info("####  kill called");
+        closeShell();
+    }
+
+    public boolean stillActive() {
+        // active until shell is closed
+        log.debug("stillActive ? " + (!mustExit && !masterOut.isClosed()));
+        return !mustExit && !masterOut.isClosed();
+
+    }
+
+    public int waitForExitCode() {
+        // this thread needs to block until we are closed
+        synchronized (this) {
+            while (true) {
+                if (stillActive()) {
+                    try {
+                        log.debug("Exit WAIT");
+                        wait();
+                        log.debug("Exit WAKEUP");
+                    } catch (InterruptedException ex) {
+                        log.info("ExitCode 1");
+                        return 1;
+                    }
+                } else {
+                    log.info("ExitCode 0");
+                    return 0;
+                }
+            }
+        }
+    }
+
+    public void closeShell() {
+        mustExit = true;
+
+        if (masterOut != null) masterOut.close();
+        if (stdErr != null) stdErr.close();
+
+        synchronized (this) {
+            notifyAll();
+        }
+
+        //pool.stop();
+    }
+
+    public String getDefaultTerminalProvider() {
+        return "VT320";
+    }
+
+    public boolean createProcess(String command, Map environment) throws IOException {
+        return true;
+    }
+
+    public void start() throws IOException {
+        // we are fully input driven and input is pushed to us - so we are event driven
+        // no thread required
+    }
+
+    public boolean supportsPseudoTerminal(String term) {
+        return true;
+    }
+
+    public boolean allocatePseudoTerminal(
+            String term,
+            int cols,
+            int rows,
+            int width,
+            int height,
+            String modes) {
+
+        setTerminalDimensions(cols, rows, width, height);
+        return true;
+    }
+
+    public void setTerminalDimensions(int cols, int rows, int width, int height) {
+
+        screen_rows = rows;
+        screen_cols = cols;
+
+        if (shell != null) try {
+            shell.setEnvProperty("SCREEN_ROWS", String.valueOf(screen_rows));
+            shell.setEnvProperty("SCREEN_COLS", String.valueOf(screen_cols));
+        } catch (Exception ex) {
+            log.warn("Failed to set new screen size to shell's ENV: ", ex);
+        }
+
+    }
+
+    public InputStream getProcessInputStream() {
+        log.debug("getProcessInputStream called");
+        return null;
+    }
+
+    public OutputStream getProcessOutputStream() {
+        log.debug("getProcessOutputStream called");
+        return null;
+    }
+
+
+    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
+
+    void prompt() {
+        StringBuffer prompt = new StringBuffer();
+
+        if (masterOut.lastChar != 10) {
+            prompt.append("\r\n");
+            masterOut.lastChar = 0;
+        }
+
+        prompt.append("[").append(sdf.format(new Date())).append("] ").append(user).append("@").append(host).append(" ");
+        String fullname = "#err#";
+        try {
+            fullname = shell.getEnvProperty("PWD");
+        } catch (Throwable ex) {
+            log.error("Failed to get PWD:", ex);
+        }
+
+        int lidx = fullname.lastIndexOf("/");
+        if (lidx != -1 && fullname.length() > 1) fullname = fullname.substring(lidx + 1);
+        prompt.append(fullname).append(" ").append("# ");
+
+        masterOut.addBytes(prompt.toString().getBytes());
+    }
+
+
+    void cancelProcess() {
+        if (iproc == null) return;
+        Buffer buf = null;
+
+        try {
+            buf = shell.getBuffer(iproc.procid, 1);
+            if (buf != null) buf.close();
+        } catch (Exception ex) {
+            log.info("Exception while closing stdin buffer for: " + iproc.procid, ex);
+        }
+
+        try {
+            buf = shell.getBuffer(iproc.procid, 2);
+            if (buf != null) buf.close();
+        } catch (Exception ex) {
+            log.info("Exception while closing stdout buffer for: " + iproc.procid, ex);
+        }
+
+    }
+
+
+    void writeError(Throwable th) {
+        if (th instanceof org.jboss.fresh.shell.SessionTimeoutException) {
+            closeShell();
+            return;
+        }
+
+        lastError = th;
+
+        while (th.getCause() != null) th = th.getCause();
+
+        masterOut.addBytes(th.toString().getBytes());
+        masterOut.addBytes("\r\n".getBytes());
+    }
+
+    void writeStackTrace(Throwable th) {
+        StringWriter sw = new StringWriter();
+        PrintWriter2 pw = new PrintWriter2(sw);
+        th.printStackTrace(pw);
+        pw.println();
+        pw.close();
+
+        masterOut.addBytes(sw.toString().getBytes());
+        //masterOut.addBytes("\r\n".getBytes());
+        prompt();
+    }
+
+    class LineEditor {
+
+        // history list
+        ArrayList<StringBuffer> history = new ArrayList<StringBuffer>();
+
+        // actively edited history items - modified during up down and edit
+        HashMap<Integer, StringBuffer> activeEdit = new HashMap<Integer, StringBuffer>();
+
+        // history item being edited. the last is always a current line
+        int hidx = 0;
+
+        // contains current state of the line being edited
+        StringBuffer linebuf = new StringBuffer();
+
+        // carret position - from 0 (before first character) to linebuf.length()
+        // (after last character)
+        int carret = 0;
+
+        // if we don't receive a complete character code we end processing at
+        // the next event and keep intermediary state in here
+        byte[] unprocessed = new byte[5];
+
+        //position in the unprocessed buffer where the next character will be added
+        // it is normally 0, only if in previous run possible incomplete byte sequence
+        // was identified this value will be > 0
+        int charsPos = 0;
+
+        private String multilineEOF;
+
+        private StringBuffer multilineBuffer;
+
+        private boolean foundEOF;
+
+        LineEditor() {
+
+            // load history from file - file to use is dependent on username used
+            File historyFile = getHomeFile(".history");
+            if (historyFile != null) {
+                BufferedReader rd = null;
+                try {
+                    LinkedList<StringBuffer> nuHistory = new LinkedList<StringBuffer>();
+                    rd = new BufferedReader(new InputStreamReader(new FileInputStream(historyFile), "UTF-8"));
+                    for (String line = rd.readLine(); line != null; line = rd.readLine()) {
+                        if (line.trim().length() != 0) {
+                            nuHistory.add(new StringBuffer(line));
+                            if (nuHistory.size() > MAX_HISTORY_SIZE)
+                                nuHistory.removeFirst();
+                        }
+                    }
+                    history.addAll(nuHistory);
+                } catch (Exception ex) {
+                    log.warn("Failed to read .history file");
+                }
+            }
+
+            // current line is always also the last history item
+            addHistory(linebuf);
+            hidx = history.size() - 1;
+
+            prompt();
+        }
+
+
+        private void addHistory(StringBuffer val) {
+            history.add(val);
+            // if history size iz greater than max, cut off the head
+            int clearSize = (int) (MAX_HISTORY_SIZE * 0.2);
+            if (history.size() > MAX_HISTORY_SIZE + clearSize) {
+                ArrayList<StringBuffer> nuHistory = new ArrayList<StringBuffer>(MAX_HISTORY_SIZE + clearSize + 1);
+                for (int i = 0; i < MAX_HISTORY_SIZE; i++)
+                    nuHistory.add(history.get(clearSize + i));
+                history = nuHistory;
+            }
+        }
+
+        private void setOverwriteMode() {
+            insMode = OVERWRITE;
+        }
+
+        private void setInsertMode() {
+            insMode = INSERT;
+        }
+
+        // this method returns necessary bytes to the client to reflect user's input
+        private void addChar(byte val) {
+            // we need to check carret location
+            // if carret is at the end of the line then we just send back the char
+            // otherwise we need to rewrite the whole line with the character
+            // and position back the carret
+            try {
+                byte[] aval = new byte[]{val};
+                int diff = linebuf.length() - carret;
+                if (diff > 0) {
+                    if (insMode == OVERWRITE) {
+                        linebuf.setCharAt(carret, new String(aval, "ISO8859_1").charAt(0));
+                    } else {
+                        linebuf.insert(carret, new String(aval, "ISO8859_1"));
+                    }
+
+                    byte[] bcv = linebuf.substring(carret, linebuf.length()).getBytes("ISO8859_1");
+
+                    byte[] bf = new byte[bcv.length - 1];
+                    for (int i = 0; i < bf.length; i++) {
+                        bf[i] = 0x08;
+                    }
+
+                    carret++;
+                    masterOut.addBytes(bcv);
+                    masterOut.addBytes(bf);
+                } else {
+                    if (insMode != INSERT)
+                        setInsertMode();
+                    linebuf.append(new String(aval, "ISO8859_1"));
+                    carret++;
+                    // write to out
+                    masterOut.addBytes(aval);
+                }
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        }
+
+        private void shiftChars(int len) {
+            System.arraycopy(unprocessed, len, unprocessed, 0, unprocessed.length - len);
+            charsPos -= len;
+        }
+
+        // this method scans unprocessed buffer and tries to identify any control
+        // byte sequences it reacts accordingly
+        private void processInput() {
+            // if buffer starts with 1b then it's a control sequence
+            // if it's already longer than 3 then it ends with 7e
+            int i = 0;
+
+            while (charsPos > i) {
+                if (unprocessed[i] == (byte) 0x1b) {
+                    if (charsPos > i + 1) {
+                        if (unprocessed[i + 1] == (byte) 0x5b) {
+                            if (charsPos > i + 2) {
+                                if (unprocessed[i + 2] == (byte) 0x44) {
+                                    // 1b 5b 44 : LEFT ARROW
+                                    leftArrow();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x43) {
+                                    // 1b 5b 43 : RIGHT ARROW
+                                    rightArrow();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x41) {
+                                    // 1b 5b 41 : UP ARROW
+                                    upArrow();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x42) {
+                                    // 1b 5b 42 : DOWN ARROW
+                                    downArrow();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x46) {
+                                    // 1b 5b 46 : END
+                                    end();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x48) {
+                                    // 1b 5b 48 : HOME
+                                    home();
+                                    shiftChars(3);
+                                } else if (unprocessed[i + 2] == (byte) 0x32) {
+                                    if (charsPos > i + 3) {
+                                        //if(unprocessed[i+3] == (byte) 0x7e) {
+                                        // INSERT
+                                        // ignore it
+                                        shiftChars(4);
+                                        //}
+                                        //} else {
+                                        //	i += 4;
+                                    }
+                                } else if (unprocessed[i + 2] == (byte) 0x33) {
+                                    if (charsPos > i + 3) {
+                                        if (unprocessed[i + 3] == (byte) 0x7e) {
+                                            del();
+                                            shiftChars(4);
+                                        } else {
+                                            shiftChars(4); // ignore
+                                        }
+                                    } else {
+                                        i += 4;
+                                    }
+                                } else if (unprocessed[i + 2] == (byte) 0x34) {
+                                    if (charsPos > i + 3) {
+                                        if (unprocessed[i + 3] == (byte) 0x7e) {
+                                            end();
+                                            shiftChars(4);
+                                        } else {
+                                            shiftChars(4); // ignore
+                                        }
+                                    } else {
+                                        i += 4;
+                                    }
+                                } else if (unprocessed[i + 2] == (byte) 0x31) {
+                                    if (charsPos > i + 3) {
+                                        if (unprocessed[i + 3] == (byte) 0x7e) {
+                                            home();
+                                            shiftChars(4);
+                                        } else {
+                                            shiftChars(4); // ignore
+                                        }
+                                    } else {
+                                        i += 4;
+                                    }
+                                } else if (unprocessed[i + 2] == (byte) 0x35) {
+                                    if (charsPos > i + 3) {
+                                        if (unprocessed[i + 3] == (byte) 0x7e) {
+                                            pgup();
+                                            shiftChars(4);
+                                        } else {
+                                            shiftChars(4); // ignore
+                                        }
+                                    } else {
+                                        i += 4;
+                                    }
+                                } else if (unprocessed[i + 2] == (byte) 0x36) {
+                                    if (charsPos > i + 3) {
+                                        if (unprocessed[i + 3] == (byte) 0x7e) {
+                                            pgdown();
+                                            shiftChars(4);
+                                        } else {
+                                            shiftChars(4); // ignore
+                                        }
+                                    } else {
+                                        i += 4;
+                                    }
+                                } else {
+                                    // treat them as regular chars
+                                    // wait for the next round
+                                    //addChar(unprocessed[i]);
+                                    //addChar(unprocessed[i+1]);
+                                    //addChar(unprocessed[i+2]);
+                                    i += 3;
+                                }
+                            } else {
+                                // wait for the next pass
+                                i += 2;
+                            }
+                        } else if (unprocessed[i + 1] == (byte) 0x4f) {
+                            // function keys
+                            // just ignore
+                            shiftChars(2);
+                        } else {
+                            // we don't know about it - just ignore
+                            shiftChars(2);
+                        }
+                    } else {
+                        // wait for the next pass
+                        i += 1;
+                    }
+                } else if (unprocessed[i] == (byte) 0x7f) {
+                    backspace();
+                    shiftChars(1);
+                } else if (unprocessed[i] == (byte) 0x0d) {
+//						if(charsPos > i+1 && unprocessed[i+1] == (byte) 0x0a) {
+//							shiftChars(2);
+//						} else {
+                    shiftChars(1);
+//						}
+                    ret();
+//					} else if(unprocessed[i] == (byte) 0x0a) {
+
+                } else if (unprocessed[i] == (byte) 0x08) {
+                    // this is left_arrow with overwrite
+                    // meaning that any characters added are not inserted but
+                    // overwrite the previous characters
+                    // when it comes to the end of line normal insert is restored
+                    setOverwriteMode();
+                    leftArrow();
+                    shiftChars(1);
+                } else if (unprocessed[i] == (byte) 0x04) {  // ctrl-D
+                    shiftChars(1);
+                    foundEOF = true;
+                    ret();
+                } else {
+                    // for all we know this is a regular character
+                    // and move carret
+                    log.debug("char: " + unprocessed[i]);
+                    addChar(unprocessed[i]);
+                    shiftChars(1);
+                }
+
+            }
+        }
+
+        void leftArrow() {
+            if (carret > 0) {
+                carret -= 1;
+                masterOut.addByte(0x08);
+            } else {
+                masterOut.addByte(0x07);
+            }
+        }
+
+        void rightArrow() {
+            if (carret < linebuf.length()) {
+                //carret+=1;
+                try {
+                    masterOut.addBytes(String.valueOf(linebuf.charAt(carret++)).getBytes("ISO8859_1"));
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            } else {
+                masterOut.addByte(0x07);
+            }
+        }
+
+        void upArrow() {
+
+            if (hidx == 0) return;
+
+            if (hidx < history.size() - 1) {
+                activeEdit.put(new Integer(hidx), linebuf);
+            }
+
+            hidx--;
+            if (hidx >= history.size())
+                hidx = history.size() - 1;
+
+            StringBuffer prev = activeEdit.get(new Integer(hidx));
+            if (prev == null) {
+                prev = new StringBuffer(history.get(hidx).toString());
+            }
+
+            byte[] buf = new byte[carret + 3 + prev.length()];
+            int i = 0;
+            // back to beginning of line
+            for (; i < carret; i++) {
+                buf[i] = 0x08;
+            }
+
+            // end of line
+            buf[i++] = 0x1b;
+            buf[i++] = 0x5b;
+            buf[i++] = 0x4b;
+
+            linebuf = prev;
+
+            try {
+                // new string
+                System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+            carret = linebuf.length();
+            masterOut.addBytes(buf);
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+            //masterOut.addBytes(new byte[] {0x0a});
+        }
+
+        void downArrow() {
+            if (hidx >= history.size() - 1) return;
+
+            activeEdit.put(new Integer(hidx), linebuf);
+            hidx++;
+
+            StringBuffer next = null;
+
+            if (hidx == history.size() - 1) {
+                next = history.get(hidx);
+            } else {
+                next = activeEdit.get(new Integer(hidx));
+                if (next == null) {
+                    next = new StringBuffer(history.get(hidx).toString());
+                }
+            }
+
+            byte[] buf = new byte[carret + 3 + next.length()];
+            int i = 0;
+            // back to beginning of line
+            for (; i < carret; i++) {
+                buf[i] = 0x08;
+            }
+
+            // end of line
+            buf[i++] = 0x1b;
+            buf[i++] = 0x5b;
+            buf[i++] = 0x4b;
+
+            linebuf = next;
+
+            // new string
+            try {
+                System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+            carret = linebuf.length();
+            masterOut.addBytes(buf);
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+            //masterOut.addBytes(new byte[] {0x0a});
+        }
+
+        void pgup() {
+            if (hidx == 0) return;
+
+            if (hidx < history.size() - 1) {
+                activeEdit.put(new Integer(hidx), linebuf);
+            }
+
+            hidx = 0;
+
+            StringBuffer prev = activeEdit.get(new Integer(hidx));
+            if (prev == null) {
+                prev = new StringBuffer(history.get(hidx).toString());
+            }
+
+            byte[] buf = new byte[carret + 3 + prev.length()];
+            int i = 0;
+            // back to beginning of line
+            for (; i < carret; i++) {
+                buf[i] = 0x08;
+            }
+
+            // end of line
+            buf[i++] = 0x1b;
+            buf[i++] = 0x5b;
+            buf[i++] = 0x4b;
+
+            linebuf = prev;
+
+            try {
+                // new string
+                System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+            carret = linebuf.length();
+            masterOut.addBytes(buf);
+        }
+
+        void pgdown() {
+            if (hidx >= history.size() - 1) return;
+
+            activeEdit.put(new Integer(hidx), linebuf);
+            hidx = history.size() - 1;
+
+            StringBuffer next = null;
+
+            if (hidx == history.size() - 1) {
+                next = history.get(hidx);
+            } else {
+                next = activeEdit.get(new Integer(hidx));
+                if (next == null) {
+                    next = new StringBuffer(history.get(hidx).toString());
+                }
+            }
+
+            byte[] buf = new byte[carret + 3 + next.length()];
+            int i = 0;
+            // back to beginning of line
+            for (; i < carret; i++) {
+                buf[i] = 0x08;
+            }
+
+            // end of line
+            buf[i++] = 0x1b;
+            buf[i++] = 0x5b;
+            buf[i++] = 0x4b;
+
+            linebuf = next;
+
+            // new string
+            try {
+                System.arraycopy(linebuf.toString().getBytes("ISO8859_1"), 0, buf, i, linebuf.length());
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+            carret = linebuf.length();
+            masterOut.addBytes(buf);
+        }
+
+        void end() {
+            // redraw from carret to end
+            int ocarret = carret;
+            carret = linebuf.length();
+            try {
+                masterOut.addBytes(linebuf.substring(ocarret, carret).getBytes("ISO8859_1"));
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+        }
+
+        void home() {
+            // go from carret to beginning of line
+            byte[] buf = new byte[carret];
+
+            // back to beginning of line
+            for (int i = 0; i < carret; i++) {
+                buf[i] = 0x08;
+            }
+
+            carret = 0;
+            masterOut.addBytes(buf);
+        }
+
+        void backspace() {
+
+            if (carret == 0) return;
+
+            int diff = linebuf.length() - carret;
+            byte[] buf = new byte[diff * 2 + 4];
+
+            buf[0] = 0x08;
+            try {
+                System.arraycopy(linebuf.substring(carret).getBytes("ISO8859_1"), 0, buf, 1, diff);
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+            buf[diff + 1] = 0x1b;
+            buf[diff + 2] = 0x5b;
+            buf[diff + 3] = 0x4b;
+
+            for (int i = diff + 4; i < buf.length; i++) {
+                buf[i] = 0x08;
+            }
+
+            carret--;
+
+            // linebuf also needs to be modified
+            linebuf.deleteCharAt(carret);
+
+            masterOut.addBytes(buf);
+        }
+
+        void del() {
+            // write back from carret+1 to the end stop then back
+            if (carret == linebuf.length()) return;
+
+            linebuf.deleteCharAt(carret);
+
+            int diff = linebuf.length() - carret;
+            byte[] buf = new byte[diff * 2 + 3];
+
+            try {
+                System.arraycopy(linebuf.substring(carret).getBytes("ISO8859_1"), 0, buf, 0, diff);
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+
+            buf[diff] = 0x1b;
+            buf[diff + 1] = 0x5b;
+            buf[diff + 2] = 0x4b;
+
+            for (int i = diff + 3; i < buf.length; i++) {
+                buf[i] = 0x08;
+            }
+
+            masterOut.addBytes(buf);
+        }
+
+        void ret() {
+            // for now only cmdline editing is supported - no stdin multiline editing
+            //home();
+
+            end();
+            boolean multiLineFinished = false;
+            boolean multiLineStarted = false;
+
+            String cmd = linebuf.toString().trim();
+            if (multilineEOF != null) {
+                // check if this is the last line - equal to multilineEOF
+                if (cmd.equals(multilineEOF)) {
+                    // found it - don't add it to buffer
+                    multiLineFinished = true;
+                    cmd = multilineBuffer.toString();
+                } else if (foundEOF) {
+                    // CTRL-D was pressed
+                    foundEOF = false;
+                    multiLineFinished = true;
+                    multilineBuffer.append(cmd);
+                    cmd = multilineBuffer.toString();
+                } else {
+                    // add line to multiline buffer
+                    multilineBuffer.append(cmd).append("\r\n");
+                    // print a newline prompt
+                    //printNewLinePrompt(masterOut);
+                }
+            } else {
+                // see if the line ends with << something
+                multilineEOF = checkMultiline(cmd);
+
+                if (multilineEOF != null) {
+                    multiLineStarted = true;
+                    multilineBuffer = new StringBuffer(cmd).append("\r\n");
+                    //printNewLinePrompt(masterOut);
+                }
+            }
+
+            if (hidx != history.size() - 1) {
+                StringBuffer sb = history.get(history.size() - 1);
+                sb.setLength(0);
+                sb.append(linebuf);
+            }
+
+            // this line prevents empty lines in history and repetition
+
+            if (multilineEOF == null || multiLineStarted) {
+                if ((history.size() > 1 && cmd.equals(history.get(history.size() - 2).toString())) || "".equals(cmd))
+                    history.remove(history.size() - 1);
+                else
+                    logHistory(cmd);
+
+                linebuf = new StringBuffer();
+                addHistory(linebuf);
+                hidx = history.size() - 1;
+            } else {
+                linebuf = new StringBuffer();
+            }
+
+            activeEdit.clear();
+            carret = 0;
+
+
+            //masterOut.addBytes(new byte [] {0x1b, 0x5b, 0x4b});
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4b}); // delete to the end-of-line
+            masterOut.addBytes(new byte[]{0x1b, 0x5b, 0x4a}); // delete to the bottom of page
+            //masterOut.addBytes(new byte[] {0x0d, 0x0a});
+            masterOut.addBytes(new byte[]{0x0d, 0x0a});
+            masterOut.lastChar = 10;
+
+            if (multilineEOF == null) {
+
+                if ("exit".equals(cmd)) {
+                    /*
+                    try {
+                        masterOut.close();
+                    } catch(Exception ex) {
+                        log.warn("Failed to close masterOut: ", ex);
+                    }
+
+                    try {
+                        masterIn.close();
+                    } catch(Exception ex) {
+                        log.warn("Failed to close masterIn: ", ex);
+                    }
+                    */
+
+                    closeShell();
+                    return;
+                } else if ("err".equals(cmd)) {
+                    if (lastError != null) writeStackTrace(lastError);
+                    return;
+                }
+            }
+
+            if (multilineEOF == null || multiLineFinished) {
+                multilineEOF = null;
+                log.debug("call processCommand: " + cmd);
+                try {
+                    processCommand(cmd);
+                    log.debug("done calling: " + cmd);
+                } catch (Throwable th) {
+                    writeError(th);
+                    prompt();
+                }
+
+            } else {
+                printNewLinePrompt(masterOut);
+            }
+            //prompt();
+        }
+
+        private String checkMultiline(String cmd) {
+            int pos = cmd.lastIndexOf("<<");
+            if (pos == -1)
+                return null;
+
+            // we found it. Now we need to check if it's inside quotes
+            // it's a simple and incomplete check but should suffice
+            String ending = cmd.substring(pos + 2).trim();
+            if (ending.indexOf("\"") != -1 || ending.indexOf("'") != -1)
+                return null;
+
+            return ending;
+        }
+
+        private void printNewLinePrompt(OutMasterInputStream masterOut) {
+            masterOut.addBytes(new byte[]{0x3e, 0x20});   // for now hardcoded to "> "
+        }
+
+
+        /**
+         * @param cmd
+         */
+        private void logHistory(String cmd) {
+
+            if ("exit".trim().equals(cmd))
+                return;
+
+            String hUser = user;
+            if (hUser == null || hUser.length() == 0)
+                hUser = "root";
+
+            File userDir = new File(homeDir, hUser);
+            File historyFile = new File(userDir, ".history");
+
+            RandomAccessFile raf = null;
+            try {
+                raf = new RandomAccessFile(historyFile, "rw");
+            } catch (Exception ex) {
+                if (!userDir.isDirectory()) {
+                    if (!userDir.mkdirs())
+                        return;
+                }
+            }
+
+            if (raf == null) {
+                log.warn("Failed to open .history");
+                return;
+            }
+
+            try {
+                raf.seek(raf.length());
+                raf.write(new String(cmd + System.getProperty("line.separator")).getBytes("UTF-8"));
+            } catch (Exception ex) {
+                log.warn("Failed to write to .history");
+            } finally {
+                try {
+                    raf.close();
+                } catch (Exception ex) {
+                }
+            }
+        }
+
+
+        PoolRunner runner;
+        RunnerJob rjob = new RunnerJob();
+        ProcessInfo pinf;
+
+        class RunnerJob implements Runnable {
+
+            String cmd;
+            boolean phaseTwo;
+            boolean onePhased;
+            boolean ready = true;
+
+            RunnerJob() {
+            }
+
+            public void setCommand(String cmd) {
+                this.cmd = cmd;
+                phaseTwo = false;
+                onePhased = false;
+                ready = false;
+            }
+
+            public void toPhaseTwo() {
+                phaseTwo = true;
+            }
+
+            public boolean ready() {
+                return ready;
+            }
+
+            public void run() {
+                try {
+                    start(cmd);
+                } catch (Throwable th) {
+                    //new Exception("Run CATCH").printStackTrace();
+                    ready = true;
+                    onePhased = true;
+                    writeError(th);
+                    prompt();
+                }
+            }
+
+            public void start(String cmd) throws Exception {
+//System.out.println("    Start ENTERED : " + cmd);	    		
+                if (!phaseTwo) {
+                    pinf = shell.prepareExecution(cmd);
+                    if (pinf == null) {
+                        onePhased = true;
+                        ready = true;
+                        prompt();
+                        return;
+                    }
+
+                    BufferInputStream ins = new BufferInputStream(shell.getBuffer(pinf.procid, 1));
+                    //ins.setTimeout(250);
+                    ins.setAsyncMode(true);
+
+                    //InputStream ins = new ShellInputStream(shell, pinf.procid);
+                    OutputStream outs = new ShellOutputStream(shell, pinf.procid);
+
+                    iproc = pinf;
+                    masterOut.setInputStream(ins);
+                    masterIn.setOutputStream(outs);
+                } else {
+//System.out.println("      >>Complete execution : " + cmd);
+                    shell.completeExecution();
+                    ready = true;
+//System.out.println("      <<Complete execution : " + cmd);
+                }
+//System.out.println("    Start EXITED : " + cmd);
+            }
+        }
+
+
+        void processCommand(String cmd) throws Exception {
+
+//			if("SINGLE".equals(shell.getEnvProperty("TMODE"))) {
+            /*
+                   if(runner != null)
+                       throw new RuntimeException("Internal error: overlapping execution");
+                    */
+
+
+            /*
+
+                   runner = (PoolRunner) pool.checkout();
+                   runner.setPoolAutoReturn(false);
+                   try {
+                       rjob.setCommand(cmd);
+                       runner.joinJob(rjob, "SSH Thread");
+                       rjob.toPhaseTwo();
+
+                       runner.setPoolAutoReturn(true);
+                       runner.runJob(rjob, "SSH Thread");
+                   } catch(Exception ex) {
+                       runner.returnToPool();
+                       ex.printStackTrace();
+                   } finally {
+                       runner = null;
+                   }
+
+                   */
+
+
+            /*
+
+                   runner = (PoolRunner) pool.checkout();
+                   try {
+                       rjob.setCommand(cmd);
+                       runner.joinJob(rjob, "SSH Thread");
+                       rjob.toPhaseTwo();
+
+                       runner = (PoolRunner) pool.checkout();
+                       runner.runJob(rjob, "SSH Thread");
+
+                   } catch(Exception ex) {
+                       ex.printStackTrace();
+                   } finally {
+                       runner = null;
+                   }
+
+                   */
+
+            if (runner == null) {
+                runner = new PoolRunner();
+            }
+
+            //while(!rjob.ready() || masterOut.isDelegateMode()) {  //
+            //	Thread.sleep(200);
+            //	shell.getBuffer(pinf.procid, 1).put("A", 10000);
+            //}
+
+            rjob.setCommand(cmd);
+            runner.joinJob(rjob, "SSH Thread");
+            if (!rjob.onePhased) {
+                rjob.toPhaseTwo();
+                runner.runJob(rjob, "SSH Thread");
+                //runner.joinJob(rjob, "SSH Thread");
+            }
+
+            // FIXED: - uncommenting the following line causes clients to freeze
+            // The reason is that this code is executed inside j2ssh callback method that sends bytes that client typed into
+            // the console. Only one callback is executed at a time, until this method returns there will be no other callbacks called.
+            // But masterOut needs to have it's callback called to determine if executable has completed. Threrefore the following
+            // line will block forever since completion will never be detected.
+            //masterOut.waitCompletion();
+/*				
+				runner = (PoolRunner) pool.checkout();
+System.out.println("Runner CHECKOUT: " + runner);
+				runner.setPoolAutoReturn(false);
+				try {
+					rjob.setCommand(cmd);
+					runner.joinJob(rjob, "SSH Thread");
+					
+					//runner = (PoolRunner) pool.checkout();
+System.out.println("Runner CHECKOUT: " + runner);
+
+					rjob.toPhaseTwo();
+					
+					// it's a tricky thing. A part of you wants to use returnToPool() in finally
+					// But you shouldn't because it's only to be used in combination
+					// with joinJob() - if you use runJob() you have to set
+					// autoreturn to true before running runJob to make it be
+					// returned to pool afterwards
+					// if exception occurs - it's due to our error - but in this case
+					// runner won't be returned to pool so we have to do it explicitly
+					runner.setPoolAutoReturn(true);
+					runner.runJob(rjob, "SSH Thread");
+
+				} catch(Exception ex) {
+					runner.returnToPool();
+					ex.printStackTrace();
+				} finally {
+					runner = null;
+				}
+//			}
+*/
+        }
+
+
+        // this is input from stdin
+        // we are in command mode otherwise we wouldn't receive this
+        public void addByte(int b) {
+            // buffer should never be full here - that would be an internal error
+            // add it to buffer first
+            unprocessed[charsPos++] = (byte) b;
+
+            // check if it's a control character or something else
+            processInput();
+
+            // process chars
+            //linebuf.append(new String(new byte[] {(byte)b}, "ISO8859_1"));
+        }
+
+        public void addBytes(byte[] buf, int offs, int len) {
+            //
+            for (int i = 0; i < len;) {
+                // in bounds for destination
+                int free = unprocessed.length - charsPos;
+                if (free > len) free = len;
+
+                // in bounds for source
+                if (free > buf.length - offs - i) free = buf.length - offs - i;
+
+                System.arraycopy(buf, offs + i, unprocessed, charsPos, free);
+                i += free;
+                charsPos += free;
+
+                processInput();
+            }
+        }
+    }
+
+
+    /*
+      *  This one also decides whether to put a charater on to editor or not
+      *	based on current shell mode - command or process
+      *  If CTRL-C and process mode - then it tries to kill the process
+      *  If CTRL-D and process mode - then it switches to command mode
+      */
+    class InMasterOutputStream extends OutputStream {
+
+        boolean closed = false;
+        boolean delegateMode = false;
+        OutputStream delegate;
+        long lastCheck = 0;
+
+        public void setOutputStream(OutputStream out) {
+            delegate = out;
+            delegateMode = out != null;
+        }
+
+        public boolean toBufferMode() {
+            boolean wasOn = delegateMode;
+            delegateMode = false;
+            delegate = null;
+            return wasOn;
+        }
+
+        public void write(int b) throws IOException {
+            if (log.isDebugEnabled()) log.debug("write: " + b);
+            if (closed) throw new EOFException();
+            if (delegateMode) {
+                log.debug("   --- delegateMode on");
+                try {
+                    if (b == 3) { // ESC
+                        delegate.close();
+                        cancelProcess();
+                        toBufferMode();
+                        return;
+                    }
+
+                    delegate.write(b);
+                } catch (EOFException ex) {
+                    toBufferMode();
+                } catch (Throwable ex) {
+                    writeError(ex);
+                }
+                return;
+            }
+
+            checkLastUsed();
+            editor.addByte(b);
+        }
+
+        public void write(byte[] buf) throws IOException {
+            write(buf, 0, buf.length);
+        }
+
+        public void write(byte[] buf, int offs, int len) throws IOException {
+            if (log.isDebugEnabled()) log.debug("write: " + new String(buf, offs, len));
+            if (closed) throw new EOFException();
+
+            if (delegateMode) {
+                log.debug("   --- delegateMode on");
+                try {
+                    for (int i = 0; i < len; i++) {
+                        if (buf[i + offs] == 3) { // ESC
+                            if (i > 0) {
+                                delegate.write(buf, offs, i);
+                            }
+                            delegate.close();
+                            cancelProcess();
+                            toBufferMode();
+                            return;
+                        }
+                    }
+
+                    delegate.write(buf, offs, len);
+                } catch (EOFException ex) {
+                    toBufferMode();
+                } catch (Throwable ex) {
+                    writeError(ex);
+                }
+
+                return;
+            }
+            checkLastUsed();
+            editor.addBytes(buf, offs, len);
+        }
+
+        public void flush() throws IOException {
+            log.debug("flush");
+            if (delegateMode) {
+                log.debug("   --- delegateMode on");
+                try {
+                    delegate.flush();
+                } catch (EOFException ex) {
+                    toBufferMode();
+                } catch (Throwable ex) {
+                    writeError(ex);
+                }
+
+            }
+        }
+
+        public void close() throws IOException {
+            log.debug("close");
+            if (closed) return;
+
+            if (delegateMode) {
+                log.debug("   --- delegateMode on");
+                try {
+                    delegate.close();
+                } catch (EOFException ex) {
+                    toBufferMode();
+                } catch (Throwable ex) {
+                    writeError(ex);
+                }
+
+            }
+
+            closed = true;
+
+            closeShell();
+
+        }
+
+        private void checkLastUsed() {
+            long now = System.currentTimeMillis();
+            if (now - lastCheck > 10000) {
+                try {
+                    shell.using();
+                } catch (Exception ex) {
+                    try {
+                        close();
+                    } catch (Exception e) {
+                        log.warn("Exception occured while closing due to session timeout", e);
+                    }
+                }
+                lastCheck = now;
+            }
+        }
+
+        public boolean isClosed() {
+            return closed;
+        }
+    }
+
+
+    class OutMasterInputStream extends InputStream {
+
+        boolean closed = false;
+        boolean delegateMode = false;
+        BufferInputStream delegate;
+        InputStream delegateReal;
+
+        int lastChar = -1;
+
+        // output buffer - client can stop reading occasionally so it's best
+        // to have a buffer zone for line editor's output
+        byte[] buff = new byte[8192];
+
+        // position where the next read from buffer will occur
+        int offs = 0;
+
+        // position where the next write to buffer will occur
+        int len = 0;
+
+        boolean waiting = false;
+
+
+        // put this master out to delegate mode - will not read line editor's output
+        // but process's output
+        public void setInputStream(BufferInputStream in) {
+            delegate = in;
+            delegateReal = new EOLFixInputStream(in);
+            delegateMode = in != null;
+        }
+
+        boolean isDelegateMode() {
+            return delegateMode;
+        }
+
+        public boolean toBufferMode() {
+            boolean wasOn = delegateMode;
+            delegateMode = false;
+            delegate = null;
+            delegateReal = null;
+            prompt();
+            masterIn.toBufferMode();
+            return wasOn;
+        }
+
+        private void shrink() {
+            if (len > 0 && len == offs) {
+                offs = 0;
+                len = 0;
+            }
+        }
+
+        synchronized void addByte(int aval) {
+            shrink();
+            int togo = buff.length - len;    // togo is how many bytes can be written
+
+            if (togo > 0) {
+                buff[len++] = (byte) aval;
+            }
+
+            notify();
+        }
+
+        void addBytes(byte[] abuf) {
+            addBytes(abuf, 0, abuf.length);
+        }
+
+        // this method writes to the buffer at the end of current content
+        synchronized void addBytes(byte[] abuf, int aoffs, int alen) {
+
+            shrink();
+            int togo = buff.length - len;    // togo is how many bytes can be written
+            // to buffer before it is full
+            if (togo > alen) {
+                togo = alen;
+            }
+
+            System.arraycopy(abuf, aoffs, buff, len, togo);
+
+            len += togo;            // adjust buffer's length to reflect ...
+            notify();                // notify a possible thread waiting on read
+        }
+
+        public int read() throws IOException {
+            log.debug("read");
+            while (!closed) {
+                if (delegateMode) {
+                    log.debug("   --- delegateMode on");
+
+                    synchronized (this) {
+                        if (offs < len) {
+
+                            //System.out.println(new String(new byte [] { buff[offs] }) + " :: " + StringUtils.toBytesString(new byte [] { buff[offs] }));
+                            return (int) buff[offs++];
+                        }
+                    }
+
+                    try {
+                        // since we have nothing to return and we read one byte
+                        // we will wait indefinately
+                        delegate.setTimeout(Integer.MAX_VALUE);
+                        delegate.setAsyncMode(false);
+                        int b = delegateReal.read();
+                        if (b != -1) {
+                            lastChar = b;
+                            //System.out.println(new String("" + (char)b) + " :: " + StringUtils.toBytesString(new byte [] {(byte)b}));
+                            return b;
+                        }
+                        toBufferMode();
+                    } catch (Exception ex) {
+                        writeError(ex);
+                        toBufferMode();
+                        //ex.printStackTrace();
+                    }
+                }
+
+                synchronized (this) {
+                    if (offs < len) {                    // there is something to read
+                        return (int) buff[offs++];
+                    }
+
+                    try {
+                        waiting = true;
+                        wait();
+                    } catch (InterruptedException ex) {
+                        ex.printStackTrace();
+                    } finally {
+                        waiting = false;
+                    }
+                }
+            }
+
+            return -1;
+        }
+
+        public int read(byte[] buf) throws IOException {
+            return read(buf, 0, buf.length);
+        }
+
+        //
+        // com.sshtools.j2ssh.io.IOStreamConnector calls this method but always
+        // with aoffs==0 and alen==1, which is ridiculous from our point of view
+        // but makes sense because this way there is no issue with buffers
+        // In order to have performance, we must do our buffering in here
+        // when reading from delegate InputStream
+        //
+        public int read(byte[] abuf, int aoffs, int alen) throws IOException {
+            log.debug("read byte[]");
+            while (!closed) {
+
+                if (delegateMode) {
+                    log.debug("   --- delegateMode on");
+
+                    synchronized (this) {
+                        shrink();
+                        if (offs == len) {
+                            int togo = buff.length - len;    // togo is how many bytes can be written
+                            try {
+                                // read as much as you can in quarter second
+                                //delegate.setTimeout(250);
+                                delegate.setAsyncMode(true);
+
+                                int rb = 0;
+                                while (rb == 0) {
+                                    log.debug("Delegate read");
+                                    rb = delegateReal.read(buff, offs, togo);
+                                }
+
+                                if (rb == -1) {
+                                    toBufferMode();
+                                } else {
+                                    len += rb;
+                                    lastChar = buff[offs + rb - 1];
+                                }
+                            } catch (Exception ex) {
+                                writeError(ex);
+                                toBufferMode();
+                                //ex.printStackTrace();
+                            }
+                        }
+
+                        int togo = len - offs;
+                        if (togo > 0) {
+                            togo = togo < alen ? togo : alen;
+
+                            System.arraycopy(buff, offs, abuf, aoffs, togo);
+                            if (log.isDebugEnabled())
+                                log.debug("read " + togo + " bytes. (" + offs + " : " + len + ") -> " + (offs + togo));
+                            if (log.isDebugEnabled())
+                                log.debug(new String(buff, offs, togo) + " [" + org.jboss.fresh.util.StringUtils.toBytesString(new String(buff, offs, togo)) + "]");
+
+// UNCOMMENT HERE FOR DEBUGGING
+//log.error(" #### " + new String(abuf, aoffs, togo) + " [\n\n" + org.jboss.fresh.util.StringUtils.toBytesString(new String(abuf, aoffs, togo)) + "\n\n]");
+                            offs += togo;
+                            //System.out.println(new String(abuf, aoffs, togo) + " :: " + StringUtils.toBytesString(abuf, aoffs, togo));
+
+                            return togo;
+                        }
+                    }
+/*
+					try {
+						int b = delegate.read(abuf, aoffs, alen);
+log.error("read " + b + " bytes (aoffs: " + aoffs + ", alen: " + alen + ")");
+log.error("Stack trace: ", new Exception("Throw me out"));
+						if(b!=-1) return b;
+						toBufferMode();
+					} catch(Exception ex) {
+						ex.printStackTrace();
+					}
+*/
+                }
+
+                synchronized (this) {
+                    if (offs < len) {
+                        int diff = len - offs;        // new available output
+                        if (alen > diff) alen = diff;    // min(alen, diff)
+                        System.arraycopy(buff, offs, abuf, aoffs, alen);
+                        if (log.isDebugEnabled())
+                            log.debug("read " + alen + " bytes. (" + offs + " : " + len + ") -> " + (offs + alen));
+                        if (log.isDebugEnabled())
+                            log.debug(new String(buff, offs, alen) + " [" + org.jboss.fresh.util.StringUtils.toBytesString(new String(buff, offs, alen)) + "]");
+// UNCOMMENT HERE FOR DEBUGGING
+//log.error(" #### " + new String(abuf, aoffs, alen) + " [\r\n\r\n" + org.jboss.fresh.util.StringUtils.toBytesString(new String(abuf, aoffs, alen)) + "\r\n\r\n]");
+                        offs += alen;
+                        return alen;
+                    }
+
+                    try {
+                        waiting = true;
+                        wait();
+                    } catch (InterruptedException ex) {
+                        ex.printStackTrace();
+                    } finally {
+                        waiting = false;
+                    }
+                }
+            }
+
+            return -1;
+        }
+
+        public int available() throws IOException {
+            log.debug("available");
+            if (closed) throw new EOFException();
+
+            if (delegateMode) {
+                log.debug("   --- delegateMode on");
+                if (len - offs > 0) return len - offs;
+                return delegateReal.available();
+            }
+
+            return len - offs;
+        }
+
+        public void waitCompletion() throws IOException {
+            // make sure client reads everything available
+            while (available() > 0 || delegateMode) {
+                try {
+                    synchronized (this) {
+                        if (waiting)
+                            notify();
+                    }
+                    Thread.sleep(200);
+                } catch (InterruptedException ex) {
+                    throw (IOException) new java.io.InterruptedIOException().initCause(ex);
+                }
+            }
+        }
+
+        public synchronized void close() {
+            closed = true;
+            notifyAll();
+        }
+
+        public boolean isClosed() {
+            return closed;
+        }
+
+    }
+
+/*
+    static class StdErrorInputStream extends InputStream {
+
+        public int read() {
+            return -1;
+        }
+
+        public int read(byte [] buf) {
+            return -1;
+        }
+
+        public int read(byte [] bug, int offs, int len) {
+            return -1;
+        }
+
+        public int available() {
+            return 0;
+        }
+
+        public void close() {
+        }
+    }
+*/
+
+    static class StdErrorInputStream extends InputStream {
+
+        boolean closed = false;
+
+        public synchronized int read() {
+            try {
+                if (!closed) wait();
+            } catch (InterruptedException ex) {
+            }
+
+            return -1;
+        }
+
+        public synchronized int read(byte[] buf) {
+            return read(buf, 0, buf.length);
+        }
+
+        public synchronized int read(byte[] bug, int offs, int len) {
+            try {
+                if (!closed) wait();
+            } catch (InterruptedException ex) {
+            }
+            return -1;
+        }
+
+        public int available() {
+            return 0;
+        }
+
+        public synchronized void close() {
+            closed = true;
+            notifyAll();
+        }
+    }
+
+}
\ No newline at end of file




More information about the jboss-cvs-commits mailing list