001/*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019package org.crsh.ssh.term;
020
021import org.crsh.console.jline.Terminal;
022import org.crsh.console.jline.console.ConsoleReader;
023import org.apache.sshd.server.Environment;
024import org.crsh.console.jline.JLineProcessor;
025import org.crsh.shell.Shell;
026import org.crsh.util.Utils;
027
028import java.io.IOException;
029import java.io.InputStream;
030import java.io.OutputStream;
031import java.io.PrintStream;
032import java.security.Principal;
033import java.util.concurrent.atomic.AtomicBoolean;
034
035public class CRaSHCommand extends AbstractCommand implements Runnable, Terminal {
036
037  /** . */
038  private final CRaSHCommandFactory factory;
039
040  /** . */
041  private Thread thread;
042
043  public CRaSHCommand(CRaSHCommandFactory factory) {
044    this.factory = factory;
045  }
046
047  /** . */
048  private SSHContext context;
049
050  /** . */
051  private JLineProcessor console;
052
053  public void start(Environment env) throws IOException {
054
055    //
056    context = new SSHContext(env);
057
058    //
059    thread = new Thread(this, "CRaSH");
060    thread.start();
061  }
062
063  public SSHContext getContext() {
064    return context;
065  }
066
067  public void destroy() {
068    Utils.close(console);
069    thread.interrupt();
070  }
071
072  public void run() {
073    final AtomicBoolean exited = new AtomicBoolean(false);
074    try {
075      final String userName = session.getAttribute(SSHLifeCycle.USERNAME);
076      Principal user = new Principal() {
077        public String getName() {
078          return userName;
079        }
080      };
081      Shell shell = factory.shellFactory.create(user);
082      ConsoleReader reader = new ConsoleReader(in, out, this) {
083        @Override
084        public void shutdown() {
085          exited.set(true);
086          callback.onExit(0);
087          super.shutdown();
088        }
089      };
090      JLineProcessor processor = new JLineProcessor(shell, reader, new PrintStream(out), "\r\n");
091      processor.run();
092    } catch (java.io.InterruptedIOException e) {
093      // Expected behavior because of the onExit callback in the shutdown above
094    } catch (Exception e) {
095      e.printStackTrace();
096    } finally {
097      // Make sure we call it
098      if (!exited.get()) {
099        callback.onExit(0);
100      }
101    }
102  }
103
104  //
105
106  @Override
107  public void init() throws Exception {
108  }
109
110  @Override
111  public void restore() throws Exception {
112  }
113
114  @Override
115  public void reset() throws Exception {
116  }
117
118  @Override
119  public boolean isSupported() {
120    return true;
121  }
122
123  @Override
124  public int getWidth() {
125    return context.getWidth();
126  }
127
128  @Override
129  public int getHeight() {
130    return context.getHeight();
131  }
132
133  @Override
134  public boolean isAnsiSupported() {
135    return true;
136  }
137
138  @Override
139  public OutputStream wrapOutIfNeeded(OutputStream out) {
140    return out;
141  }
142
143  @Override
144  public InputStream wrapInIfNeeded(InputStream in) throws IOException {
145    return in;
146  }
147
148  @Override
149  public boolean hasWeirdWrap() {
150    return false;
151  }
152
153  @Override
154  public boolean isEchoEnabled() {
155    return false;
156  }
157
158  @Override
159  public void setEchoEnabled(boolean enabled) {
160  }
161}
162
163