/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.ssh.term;
import org.crsh.console.jline.Terminal;
import org.crsh.console.jline.console.ConsoleReader;
import org.apache.sshd.server.Environment;
import org.crsh.console.jline.JLineProcessor;
import org.crsh.shell.Shell;
import org.crsh.util.Utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.security.Principal;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
public class CRaSHCommand extends AbstractCommand implements Runnable, Terminal {
/** . */
protected static final Logger log = Logger.getLogger(CRaSHCommand.class.getName());
/** . */
private final CRaSHCommandFactory factory;
/** . */
private Thread thread;
/** . */
private String encoding;
public CRaSHCommand(CRaSHCommandFactory factory) {
this.factory = factory;
}
/** . */
private SSHContext context;
/** . */
private JLineProcessor console;
public void start(Environment env) throws IOException {
context = new SSHContext(env);
encoding = context.encoding != null ? context.encoding.name() : factory.encoding.name();
thread = new Thread(this, "CRaSH");
//
thread.start();
}
public SSHContext getContext() {
return context;
}
public void destroy() {
Utils.close(console);
thread.interrupt();
}
public void run() {
final AtomicBoolean exited = new AtomicBoolean(false);
try {
final String userName = session.getAttribute(SSHLifeCycle.USERNAME);
Principal user = new Principal() {
public String getName() {
return userName;
}
};
Shell shell = factory.shellFactory.create(user);
ConsoleReader reader = new ConsoleReader(in, out, this) {
@Override
public void shutdown() {
exited.set(true);
callback.onExit(0);
super.shutdown();
}
};
JLineProcessor processor = new JLineProcessor(true, shell, reader, new PrintStream(out, false, encoding), "\r\n");
processor.run();
} catch (java.io.InterruptedIOException e) {
// Expected behavior because of the onExit callback in the shutdown above
// clear interrupted status on purpose
Thread.interrupted();
} catch (Exception e) {
log.log(Level.WARNING, "Error during execution", e);
} finally {
// Make sure we call it
if (!exited.get()) {
callback.onExit(0);
}
}
}
//
@Override
public String getOutputEncoding() {
return encoding;
}
@Override
public void init() throws Exception {
}
@Override
public void restore() throws Exception {
}
@Override
public void reset() throws Exception {
}
@Override
public boolean isSupported() {
return true;
}
@Override
public int getWidth() {
return context.getWidth();
}
@Override
public int getHeight() {
return context.getHeight();
}
@Override
public boolean isAnsiSupported() {
return true;
}
@Override
public OutputStream wrapOutIfNeeded(OutputStream out) {
return out;
}
@Override
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
return in;
}
@Override
public boolean hasWeirdWrap() {
return false;
}
@Override
public boolean isEchoEnabled() {
return false;
}
@Override
public void setEchoEnabled(boolean enabled) {
}
}