diff --git a/maverick-synergy-server/pom.xml b/maverick-synergy-server/pom.xml
index 552d7615..f1d94643 100644
--- a/maverick-synergy-server/pom.xml
+++ b/maverick-synergy-server/pom.xml
@@ -4,7 +4,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-synergy-server
Server API
diff --git a/maverick-synergy-server/src/main/java/com/sshtools/server/SessionChannelNG.java b/maverick-synergy-server/src/main/java/com/sshtools/server/SessionChannelNG.java
index 01e8d889..e35566a1 100644
--- a/maverick-synergy-server/src/main/java/com/sshtools/server/SessionChannelNG.java
+++ b/maverick-synergy-server/src/main/java/com/sshtools/server/SessionChannelNG.java
@@ -50,6 +50,7 @@
import com.sshtools.common.util.Utils;
import com.sshtools.synergy.ssh.ChannelNG;
import com.sshtools.synergy.ssh.ChannelOutputStream;
+import com.sshtools.synergy.ssh.TerminalModes;
/**
*
@@ -109,7 +110,6 @@ public abstract class SessionChannelNG extends ChannelNG imple
boolean haltIncomingData = false;
long lastActivity = System.currentTimeMillis();
boolean agentForwardingRequested;
- boolean rawMode = false;
boolean singleSession = false;
ChannelOutputStream stderrOutputStream = new ChannelOutputStream(this, SSH_EXTENDED_DATA_STDERR);
@@ -141,14 +141,6 @@ protected void onChannelClosed() {
}
}
- public void enableRawMode() {
- rawMode = true;
- }
-
- public void disableRawMode() {
- rawMode = false;
- }
-
public Subsystem getSubsystem() {
return subsystem;
}
@@ -166,6 +158,13 @@ public boolean isAgentForwardingRequested() {
return agentForwardingRequested;
}
+ public void pauseDataCaching() {
+ paused = true;
+ }
+
+ public void resumeDataCaching() {
+ paused = false;
+ }
/**
* Implement this method to support agent forwarding.
*
@@ -178,6 +177,9 @@ protected boolean requestAgentForwarding(String requestType) {
/**
* If the client requests a pseudo terminal for the session this method will
* be invoked before the shell, exec or subsystem is started.
+ *
+ * Deprecated, at version 3.2.0 {@link #allocatePseudoTerminal(String, int, int, int, int, TerminalModes)}.
+ * will be made abstract and this method will be removed.
*
* @param term
* @param cols
@@ -187,8 +189,28 @@ protected boolean requestAgentForwarding(String requestType) {
* @param modes
* @return boolean
*/
- protected abstract boolean allocatePseudoTerminal(String term, int cols,
- int rows, int width, int height, byte[] modes);
+ @Deprecated(forRemoval = true, since = "3.1.2")
+ protected boolean allocatePseudoTerminal(String term, int cols,
+ int rows, int width, int height, byte[] modes) {
+ throw new UnsupportedOperationException("No longer used, instead call allocatePseudoTerminal() with TerminalModes.");
+ }
+
+ /**
+ * If the client requests a pseudo terminal for the session this method will
+ * be invoked before the shell, exec or subsystem is started.
+ *
+ * @param term
+ * @param cols
+ * @param rows
+ * @param width
+ * @param height
+ * @param modes
+ * @return boolean
+ */
+ protected boolean allocatePseudoTerminal(String term, int cols,
+ int rows, int width, int height, TerminalModes modes) {
+ return allocatePseudoTerminal(term, cols, width, width, height, modes.toByteArray());
+ }
/**
* When the window (terminal) size changes on the client side, it MAY send
@@ -314,10 +336,10 @@ protected void onChannelRequest(String type, boolean wantreply,
int rows = (int) bar.readInt();
int width = (int) bar.readInt();
int height = (int) bar.readInt();
- byte[] modes = bar.readBinaryString();
success = allocatePseudoTerminal(term, cols, rows, width,
- height, modes);
+ height, new TerminalModes.TerminalModesBuilder().fromBytes(bar.readBinaryString()).build());
+
if(Log.isDebugEnabled())
Log.debug(term + " pseudo terminal requested");
if(Log.isDebugEnabled())
diff --git a/maverick-synergy-server/src/main/java/com/sshtools/server/UnsupportedSession.java b/maverick-synergy-server/src/main/java/com/sshtools/server/UnsupportedSession.java
index 61bb2e04..e659a3e2 100644
--- a/maverick-synergy-server/src/main/java/com/sshtools/server/UnsupportedSession.java
+++ b/maverick-synergy-server/src/main/java/com/sshtools/server/UnsupportedSession.java
@@ -10,12 +10,12 @@
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
- *
+ *
* This program 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 General Lesser Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
@@ -27,19 +27,20 @@
import com.sshtools.common.logger.Log;
import com.sshtools.common.ssh.ConnectionAwareTask;
import com.sshtools.common.ssh.SshConnection;
+import com.sshtools.synergy.ssh.TerminalModes;
/**
* This is a basic session that provides a message to the user to inform them
* that a shell or command cannot be executed because the server does not
* support an interactive session.
- *
- *
+ *
+ *
*/
public class UnsupportedSession extends SessionChannelNG {
String message = "This server does not support an interactive session.\r\nGoodbye.\r\n";
-
+
public UnsupportedSession(SshConnection con) {
super(con);
}
@@ -48,10 +49,11 @@ protected boolean executeCommand(String cmd) {
return false;
}
- protected boolean startShell() {
-
+ @Override
+ protected boolean startShell() {
+
con.executeTask(new ConnectionAwareTask(con) {
-
+
@Override
protected void doTask() {
try {
@@ -66,17 +68,19 @@ protected void doTask() {
}
}
});
-
-
+
+
return true;
}
- protected boolean allocatePseudoTerminal(String parm1, int parm2, int parm3, int parm4, int parm5, byte[] parm6) {
+ @Override
+ protected boolean allocatePseudoTerminal(String parm1, int parm2, int parm3, int parm4, int parm5, TerminalModes parm6) {
return true;
}
-
- public boolean setEnvironmentVariable(String name, String value) {
+
+ @Override
+ public boolean setEnvironmentVariable(String name, String value) {
return false;
}
@@ -92,6 +96,6 @@ protected void onLocalEOF() {
@Override
protected void processSignal(String signal) {
-
+
}
}
diff --git a/maverick-synergy/pom.xml b/maverick-synergy/pom.xml
index 797f877a..74648a73 100644
--- a/maverick-synergy/pom.xml
+++ b/maverick-synergy/pom.xml
@@ -6,7 +6,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-synergy
Unified API
diff --git a/maverick-utils/pom.xml b/maverick-utils/pom.xml
index 7657da5f..84a3d92e 100644
--- a/maverick-utils/pom.xml
+++ b/maverick-utils/pom.xml
@@ -5,7 +5,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-utils
Utils
diff --git a/maverick-virtual-filesystem-tests/pom.xml b/maverick-virtual-filesystem-tests/pom.xml
index 0d21deba..0cb82935 100644
--- a/maverick-virtual-filesystem-tests/pom.xml
+++ b/maverick-virtual-filesystem-tests/pom.xml
@@ -3,7 +3,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-virtual-filesystem-tests
Virtual File System Tests
diff --git a/maverick-virtual-filesystem/pom.xml b/maverick-virtual-filesystem/pom.xml
index 85a8fe53..21a8bfeb 100644
--- a/maverick-virtual-filesystem/pom.xml
+++ b/maverick-virtual-filesystem/pom.xml
@@ -4,7 +4,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-virtual-filesystem
Virtual File System
diff --git a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/AbstractMount.java b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/AbstractMount.java
index b8a0c556..274c728d 100644
--- a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/AbstractMount.java
+++ b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/AbstractMount.java
@@ -51,7 +51,11 @@ public int hashCode() {
private boolean filesystemRoot;
private boolean isDefault;
protected boolean isImaginary;
-
+ protected String username = "unknown";
+ protected String group = "unknown";
+ protected int uid = 0;
+ protected int gid = 0;
+
protected AbstractMount(String mount, String path) {
this(mount, path, false, false);
}
@@ -121,4 +125,20 @@ public void setAttribute(String key, Object value) {
public String toString() {
return getMount() + " on " + getRoot();
}
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public int getUid() {
+ return uid;
+ }
+
+ public int getGid() {
+ return gid;
+ }
}
diff --git a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualFileFactory.java b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualFileFactory.java
index e87e7538..851c02bc 100644
--- a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualFileFactory.java
+++ b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualFileFactory.java
@@ -249,7 +249,7 @@ public Map resolveChildren(VirtualFile parent) throws Permis
if(intermediate = !childPaths.isEmpty()) {
childPath = FileUtils.checkEndsWithNoSlash(childPaths.get(0));
}
- files.put(childPath, new VirtualMountFile(currentPath + childPath, parent.getMount(), this, intermediate));
+ files.put(childPath, new VirtualMountFile(currentPath + childPath, m, this, intermediate));
}
}
diff --git a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMount.java b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMount.java
index a77699f3..350e118d 100644
--- a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMount.java
+++ b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMount.java
@@ -60,6 +60,11 @@ public class VirtualMount extends AbstractMount {
AbstractFile f = actualFileFactory.getFile(path);
this.path = f.getAbsolutePath();
}
+
+ this.uid = mountTemplate.getUid();
+ this.gid = mountTemplate.getGid();
+ this.username = mountTemplate.getUsername();
+ this.group = mountTemplate.getGroup();
}
diff --git a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountFile.java b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountFile.java
index b60cb574..d9f8abb7 100644
--- a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountFile.java
+++ b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountFile.java
@@ -123,10 +123,10 @@ public SftpFileAttributes getAttributes() throws FileNotFoundException,
bldr.withPermissions(builder.build());
- bldr.withUid(0);
- bldr.withGid(0);
- bldr.withUsername(System.getProperty("maverick.unknownUsername", "unknown"));
- bldr.withGroup(System.getProperty("maverick.unknownUsername", "unknown"));
+ bldr.withUid(parentMount.getUid());
+ bldr.withGid(parentMount.getGid());
+ bldr.withUsername(System.getProperty("maverick.unknownUsername", parentMount.getUsername()));
+ bldr.withGroup(System.getProperty("maverick.unknownUsername", parentMount.getGroup()));
bldr.withLastAccessTime(parentMount.lastModified());
bldr.withLastModifiedTime(parentMount.lastModified());
bldr.withCreateTime(parentMount.lastModified());
diff --git a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountTemplate.java b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountTemplate.java
index 8e36fca6..ecd128b5 100644
--- a/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountTemplate.java
+++ b/maverick-virtual-filesystem/src/main/java/com/sshtools/common/files/vfs/VirtualMountTemplate.java
@@ -77,4 +77,24 @@ public boolean isChildOf(VirtualMountTemplate o2) {
public long lastModified() {
return lastModified;
}
+
+ public VirtualMountTemplate setUsername(String username) {
+ this.username = username;
+ return this;
+ }
+
+ public VirtualMountTemplate setGroup(String group) {
+ this.group = group;
+ return this;
+ }
+
+ public VirtualMountTemplate setUid(int uid) {
+ this.uid = uid;
+ return this;
+ }
+
+ public VirtualMountTemplate setGid(int gid) {
+ this.gid = gid;
+ return this;
+ }
}
diff --git a/maverick-virtual-session-tests/pom.xml b/maverick-virtual-session-tests/pom.xml
index c1f0a8d3..932c46a0 100644
--- a/maverick-virtual-session-tests/pom.xml
+++ b/maverick-virtual-session-tests/pom.xml
@@ -4,7 +4,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-virtual-session-tests
Virtual Sessions Tests
diff --git a/maverick-virtual-session/pom.xml b/maverick-virtual-session/pom.xml
index ce782c45..b62a5e28 100644
--- a/maverick-virtual-session/pom.xml
+++ b/maverick-virtual-session/pom.xml
@@ -7,7 +7,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-virtual-session
Virtual Sessions
diff --git a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualConsole.java b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualConsole.java
index d274dff5..0139f36e 100644
--- a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualConsole.java
+++ b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualConsole.java
@@ -38,6 +38,7 @@
import com.sshtools.common.ssh.Context;
import com.sshtools.common.ssh.SessionChannelServer;
import com.sshtools.common.ssh.SshConnection;
+import com.sshtools.synergy.ssh.TerminalModes;
public class VirtualConsole {
@@ -49,10 +50,11 @@ public class VirtualConsole {
Msh shell;
AbstractFile cwd;
AbstractFileFactory> fileFactory;
+ TerminalModes modes;
static ThreadLocal threadConsoles = new ThreadLocal<>();
- public VirtualConsole(SessionChannelServer channel, Environment env, Terminal terminal, LineReader reader, Msh shell) throws IOException, PermissionDeniedException {
+ public VirtualConsole(SessionChannelServer channel, Environment env, Terminal terminal, LineReader reader, Msh shell, TerminalModes modes) throws IOException, PermissionDeniedException {
this.channel = channel;
this.con = channel.getConnection();
this.env = env;
@@ -61,6 +63,11 @@ public VirtualConsole(SessionChannelServer channel, Environment env, Terminal te
this.shell = shell;
this.fileFactory = getContext().getPolicy(FileSystemPolicy.class)
.getFileFactory().getFileFactory(con);
+ this.modes = modes;
+ }
+
+ public TerminalModes getPseudoTerminalModes() {
+ return modes;
}
public SshConnection getConnection() {
diff --git a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualSessionPolicy.java b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualSessionPolicy.java
index 6d435962..8fb1c43f 100644
--- a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualSessionPolicy.java
+++ b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualSessionPolicy.java
@@ -68,6 +68,10 @@ public Map getShellEnvironment() {
return shellEnvironment;
}
+ public void setShellEnvironment(Map shellEnvironment) {
+ this.shellEnvironment = shellEnvironment;
+ }
+
public File getShellDirectory() {
return shellDirectory;
}
diff --git a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualShellNG.java b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualShellNG.java
index 1a06a346..92e5f0f3 100644
--- a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualShellNG.java
+++ b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/VirtualShellNG.java
@@ -10,12 +10,12 @@
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
- *
+ *
* This program 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 General Lesser Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
@@ -24,7 +24,6 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
-import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
@@ -47,33 +46,30 @@
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
-import org.jline.terminal.impl.AbstractPosixTerminal;
-import org.jline.terminal.impl.ExternalTerminal;
import com.sshtools.common.files.nio.AbstractFileURI;
import com.sshtools.common.logger.Log;
import com.sshtools.common.permissions.PermissionDeniedException;
import com.sshtools.common.policy.ClassLoaderPolicy;
-import com.sshtools.common.ssh.Channel;
-import com.sshtools.common.ssh.ChannelEventListener;
import com.sshtools.common.ssh.SshConnection;
import com.sshtools.common.util.Utils;
import com.sshtools.server.AgentForwardingChannel;
import com.sshtools.server.SessionChannelNG;
+import com.sshtools.synergy.ssh.TerminalModes;
public class VirtualShellNG extends SessionChannelNG {
String shellCommand = null;
Environment env = new Environment();
Set protectedEnvironmentVars = new HashSet<>();
-
+
public VirtualShellNG(SshConnection con,
- ShellCommandFactory commandFactory,
+ ShellCommandFactory commandFactory,
String shellCommand) {
this(con, commandFactory);
this.shellCommand = shellCommand;
}
-
+
public interface WindowSizeChangeListener {
void newSize(int rows, int cols);
}
@@ -82,37 +78,15 @@ public interface WindowSizeChangeListener {
protected VirtualConsole console;
protected ShellCommandFactory commandFactory;
- boolean rawMode = false;
-
- List listeners = new ArrayList();
+ List listeners = new ArrayList<>();
+
private Terminal terminal;
-
+ private TerminalModes modes;
+
public VirtualShellNG(SshConnection con,
ShellCommandFactory commandFactory) {
super(con);
this.commandFactory = commandFactory;
- addEventListener(new ChannelEventListener() {
- @Override
- public void onChannelDataIn(Channel channel, ByteBuffer data) {
-
- byte[] tmp = new byte[data.remaining()];
- data.get(tmp);
-
- try {
- if(terminal instanceof AbstractPosixTerminal) {
- ((AbstractPosixTerminal)terminal).getPty().getMasterOutput().write(tmp);
- ((AbstractPosixTerminal)terminal).getPty().getMasterOutput().flush();
- }
- else {
- ((ExternalTerminal)terminal).processInputBytes(tmp, 0, tmp.length);
- }
- evaluateWindowSpace();
- } catch (Exception e) {
- Log.error("Failed to send input to terminal.", e);
- close();
- }
- }
- });
}
public void addWindowSizeChangeListener(WindowSizeChangeListener listener) {
@@ -122,26 +96,28 @@ public void addWindowSizeChangeListener(WindowSizeChangeListener listener) {
public void removeWindowSizeChangeListener(WindowSizeChangeListener listener) {
listeners.remove(listener);
}
-
+
public void addProtectedEnvironmentVar(String name) {
protectedEnvironmentVars.add(name.toUpperCase());
}
protected boolean executeCommand(String cmd) {
-
+
try {
shell = commandFactory.createShell(con);
shell.execCommand(getInputStream(), console = createConsole(), cmd);
return true;
} catch (Exception e) {
- if(Log.isErrorEnabled())
+ if(Log.isErrorEnabled()) {
Log.error("Failed to execute command " + cmd, e);
- }
+ }
+ }
return false;
}
+ @Override
protected void changeWindowDimensions(int cols, int rows, int width, int height) {
-
+
console.getTerminal().setSize(new Size(cols, rows));
for (WindowSizeChangeListener l : listeners) {
@@ -149,33 +125,35 @@ protected void changeWindowDimensions(int cols, int rows, int width, int height)
}
}
+ @Override
public void onSessionOpen() {
-
+
shell.start();
}
+ @Override
protected boolean startShell() {
-
+
if(Utils.isNotBlank(shellCommand)) {
return executeCommand(shellCommand);
}
-
+
try {
- shell = createShell(con);
+ shell = createShell(con);
shell.startShell(null, console = createConsole());
return true;
} catch (Throwable t) {
Log.warn("Failed to start shell.", t);
- }
+ }
return false;
}
protected RootShell createShell(SshConnection con) throws PermissionDeniedException, IOException {
return commandFactory.createShell(con);
}
-
+
private VirtualConsole createConsole() throws IOException, PermissionDeniedException {
-
+
Attributes attrs = new Attributes();
attrs.setInputFlag(InputFlag.ICRNL, true);
terminal = TerminalBuilder.builder().
@@ -185,47 +163,50 @@ private VirtualConsole createConsole() throws IOException, PermissionDeniedExcep
size(new Size(env.getOrDefault("COLS", 80), env.getOrDefault("ROWS", 80))).
encoding(Charset.forName("UTF-8")).
attributes(attrs).build();
-
+
Map env = new HashMap<>();
env.put("connection", getConnection());
FileSystem fs = FileSystems.newFileSystem(
- AbstractFileURI.create(getConnection(), ""),
+ AbstractFileURI.create(getConnection(), ""),
env,
getContext().getPolicy(ClassLoaderPolicy.class).getClassLoader());
-
+
final LineReaderBuilder lineReaderBuilder = LineReaderBuilder.builder()
.terminal(terminal)
.completer(new VirtualShellCompletor())
.variable(LineReader.HISTORY_SIZE, 1000)
.variable(LineReader.HISTORY_FILE, fs.getPath(".history"));
- return new VirtualConsole(this, this.env, terminal, lineReaderBuilder.build(), shell);
+ return new VirtualConsole(this, this.env, terminal, lineReaderBuilder.build(), shell, modes);
}
@Override
protected boolean requestAgentForwarding(String requestType) {
-
+
try {
if(!getConnection().containsProperty(AgentForwardingChannel.SSH_AGENT_CLIENT)) {
connection.openChannel(new AgentForwardingChannel(requestType, this));
- }
+ }
return true;
} catch (IOException e) {
return false;
}
-
+
}
- protected boolean allocatePseudoTerminal(String term, int cols, int rows, int width, int height, byte[] modes) {
-
+ @Override
+ protected boolean allocatePseudoTerminal(String term, int cols, int rows, int width, int height, TerminalModes modes) {
+
env.put("TERM", term);
env.put("COLS", cols);
env.put("ROWS", rows);
env.put("PTYMODES", modes);
-
+ this.modes = modes;
+
return true;
}
+ @Override
public boolean setEnvironmentVariable(String name, String value) {
if(protectedEnvironmentVars.contains(name.toUpperCase())) {
return false;
@@ -234,6 +215,7 @@ public boolean setEnvironmentVariable(String name, String value) {
return true;
}
+ @Override
protected void onChannelOpenFailure() {
}
@@ -241,25 +223,25 @@ protected void onChannelOpenFailure() {
@Override
protected void processSignal(String signal) {
-
+
}
@Override
protected void onLocalEOF() {
-
+
}
@Override
- public void enableRawMode() {
+ public void pauseDataCaching() {
console.getTerminal().pause();
- super.enableRawMode();
-
+ super.pauseDataCaching();
}
@Override
- public void disableRawMode() {
+ public void resumeDataCaching() {
+ super.resumeDataCaching();
console.getTerminal().resume();
- super.disableRawMode();
+
}
class VirtualShellCompletor implements Completer, MshListener {
@@ -269,17 +251,17 @@ class VirtualShellCompletor implements Completer, MshListener {
VirtualShellCompletor() {
shell.addListener(this);
}
-
+
@Override
public void complete(LineReader reader, ParsedLine line, List candidates) {
-
+
if(!inCommand.get()) {
processShellCompletion(reader, line, candidates);
} else {
processInCommandCompletion(reader, line, candidates);
}
}
-
+
private void processInCommandCompletion(LineReader reader, ParsedLine line, List candidates) {
@SuppressWarnings("unchecked")
List tmp = (List) console.getEnvironment().get("_COMPLETIONS");
@@ -289,7 +271,7 @@ private void processInCommandCompletion(LineReader reader, ParsedLine line, List
}
private void processShellCompletion(LineReader reader, ParsedLine line, List candidates) {
-
+
switch(line.wordIndex()) {
case 0:
/**
@@ -318,12 +300,12 @@ public void commandStarted(Command cmd, String[] args, VirtualConsole console) {
inCommand.set(true);
this.currentCommand = cmd;
}
-
+
@Override
public void commandFinished(Command cmd, String[] args, VirtualConsole console) {
inCommand.set(false);
this.currentCommand = null;
}
-
+
}
}
diff --git a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/commands/os/AbstractOSCommand.java b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/commands/os/AbstractOSCommand.java
index ab582c6b..5ae1f441 100644
--- a/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/commands/os/AbstractOSCommand.java
+++ b/maverick-virtual-session/src/main/java/com/sshtools/server/vsession/commands/os/AbstractOSCommand.java
@@ -100,7 +100,7 @@ private void runCommand(String cmd, List cmdArgs,
if(directory != null)
builder.setDirectory(directory.getAbsolutePath());
builder.setConsole(false);
- builder.setEnvironment(env);
+ builder.setEnvironment(penv);
pty = builder.start();
final InputStream in = pty.getInputStream();
@@ -119,13 +119,13 @@ public void newSize(int rows, int cols) {
shell.addWindowSizeChangeListener(listener);
- console.getSessionChannel().enableRawMode();
+ console.getSessionChannel().pauseDataCaching();
- console.getSessionChannel().addEventListener(new ChannelEventListener() {
+ ChannelEventListener l = new ChannelEventListener() {
@Override
public void onChannelDataIn(Channel channel, ByteBuffer buffer) {
-
+
byte[] tmp = new byte[buffer.remaining()];
buffer.get(tmp);
@@ -138,7 +138,8 @@ public void onChannelDataIn(Channel channel, ByteBuffer buffer) {
IOUtils.closeStream(in);
}
}
- });
+ };
+ console.getSessionChannel().addEventListener(l);
try {
IOUtils.copy(in, console.getSessionChannel().getOutputStream());
@@ -150,7 +151,12 @@ public void onChannelDataIn(Channel channel, ByteBuffer buffer) {
}
} catch (Exception e) {
} finally {
- console.getSessionChannel().disableRawMode();
+ try {
+ console.getSessionChannel().resumeDataCaching();
+ }
+ finally {
+ console.getSessionChannel().removeEventListener(l);
+ }
}
}
diff --git a/maverick-virtual-session/src/main/java/com/sshtools/vsession/commands/ssh/SshClientCommand.java b/maverick-virtual-session/src/main/java/com/sshtools/vsession/commands/ssh/SshClientCommand.java
index ca9bf5ca..57c9780a 100644
--- a/maverick-virtual-session/src/main/java/com/sshtools/vsession/commands/ssh/SshClientCommand.java
+++ b/maverick-virtual-session/src/main/java/com/sshtools/vsession/commands/ssh/SshClientCommand.java
@@ -23,10 +23,12 @@
*/
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
+import com.sshtools.client.PseudoTerminalModes.PseudoTerminalModesBuilder;
import com.sshtools.client.SessionChannelNG;
import com.sshtools.client.SshClient;
import com.sshtools.client.SshClientContext;
@@ -34,7 +36,10 @@
import com.sshtools.client.tasks.CommandTask.CommandTaskBuilder;
import com.sshtools.client.tasks.ShellTask.ShellTaskBuilder;
import com.sshtools.client.tasks.Task;
+import com.sshtools.common.logger.Log;
import com.sshtools.common.permissions.PermissionDeniedException;
+import com.sshtools.common.ssh.Channel;
+import com.sshtools.common.ssh.ChannelEventListener;
import com.sshtools.common.util.IOUtils;
import com.sshtools.server.vsession.VirtualConsole;
import com.sshtools.server.vsession.VirtualShellNG;
@@ -54,10 +59,11 @@ public SshClientCommand() {
@Override
public void runCommand(SshClient sshClient, SshClientArguments arguments, VirtualConsole console) {
-
- console.getSessionChannel().enableRawMode();
-
+
try {
+
+ console.getSessionChannel().pauseDataCaching();
+
Connection connection = sshClient.getConnection();
AbstractSessionTask> task;
@@ -65,7 +71,8 @@ public void runCommand(SshClient sshClient, SshClientArguments arguments, Virtua
if (CommandUtil.isNotEmpty(arguments.getCommand())) {
String command = arguments.getCommand();
- task = CommandTaskBuilder.create()
+ var builder = CommandTaskBuilder.create()
+ .withConnection(connection)
.withCommand(command)
.withTermType(console.getTerminal().getType())
.withColumns(console.getTerminal().getWidth())
@@ -79,12 +86,18 @@ public void runCommand(SshClient sshClient, SshClientArguments arguments, Virtua
IOUtils.copy(session.getInputStream(), console.getSessionChannel().getOutputStream());
})
- .onClose((t, session) -> ((VirtualShellNG)console.getSessionChannel()).removeWindowSizeChangeListener(listener))
- .build();
+ .onClose((t, session) -> ((VirtualShellNG)console.getSessionChannel()).removeWindowSizeChangeListener(listener));
+ if(console.getPseudoTerminalModes() != null) {
+ try {
+ builder.withModes(PseudoTerminalModesBuilder.create().build());
+ } catch (IOException e) {
+ }
+ }
+ task = builder.build();
} else {
- task = ShellTaskBuilder.create().
+ var builder = ShellTaskBuilder.create().
withConnection(connection).
withTermType(console.getTerminal().getType()).
withColumns(console.getTerminal().getWidth()).
@@ -92,12 +105,44 @@ public void runCommand(SshClient sshClient, SshClientArguments arguments, Virtua
onBeforeTask((t, session) -> {
listener.session = session;
((VirtualShellNG)console.getSessionChannel()).addWindowSizeChangeListener(listener);
+
+ ChannelEventListener l = new ChannelEventListener() {
+
+ @Override
+ public void onChannelDataIn(Channel channel, ByteBuffer buffer) {
+
+ byte[] tmp = new byte[buffer.remaining()];
+ buffer.get(tmp);
+
+ try {
+ session.getOutputStream().write(tmp);
+ session.getOutputStream().flush();
+ } catch (IOException e) {
+ Log.error("Error writing data from console", e);
+ }
+ }
+ };
+ console.getSessionChannel().addEventListener(l);
+
+ session.addEventListener(new ChannelEventListener() {
+ @Override
+ public void onChannelClose(Channel channel) {
+ if(Log.isDebugEnabled()) {
+ Log.debug("Detected close of child command so removing channel data listeners");
+ }
+ console.getSessionChannel().removeEventListener(l);
+ session.removeEventListener(this);
+ }
+ });
})
.onTask((t, session)-> {
- connection.addTask(Task.ofRunnable(connection, (c) -> IOUtils.copy(console.getSessionChannel().getInputStream(), session.getOutputStream())));
IOUtils.copy(session.getInputStream(), console.getSessionChannel().getOutputStream());
}).
- onClose((t, session) -> ((VirtualShellNG)console.getSessionChannel()).removeWindowSizeChangeListener(listener)).
+ onClose((t, session) -> ((VirtualShellNG)console.getSessionChannel()).removeWindowSizeChangeListener(listener));
+ if(console.getPseudoTerminalModes() != null) {
+ builder.withModes(console.getPseudoTerminalModes());
+ }
+ task = builder.
build();
}
@@ -105,7 +150,8 @@ public void runCommand(SshClient sshClient, SshClientArguments arguments, Virtua
task.waitForever();
} finally {
- console.getSessionChannel().disableRawMode();
+
+ console.getSessionChannel().resumeDataCaching();
console.println();
}
diff --git a/maverick-x509/pom.xml b/maverick-x509/pom.xml
index 3964b1f5..37a1156f 100644
--- a/maverick-x509/pom.xml
+++ b/maverick-x509/pom.xml
@@ -5,7 +5,7 @@
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
maverick-x509
X509 Certificate Support
diff --git a/pom.xml b/pom.xml
index e2657c0a..c020b3a3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.sshtools
maverick-synergy-group
- 3.1.1
+ 3.1.2
Maverick Synergy
Open source Java SSH API
http://www.jadaptive.com