package org.smartly.commons.network.sftp;
import com.jcraft.jsch.*;
import org.smartly.commons.logging.Level;
import org.smartly.commons.logging.Logger;
import org.smartly.commons.logging.util.LoggingUtils;
import org.smartly.commons.network.sftp.impl.SFTPProgressMonitor;
import org.smartly.commons.network.sftp.impl.SFTPUserInfo;
import org.smartly.commons.util.StringUtils;
import java.io.File;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
/**
* SFTP client implementation.
*/
public class SFTPClient {
private final JSch _jsch;
private String _username;
private String _password;
private String _host;
private int _port;
private Session _session;
private ChannelSftp _channel;
public SFTPClient() {
_jsch = new JSch();
}
public SFTPClient(final String host, final int port) {
this();
_host = host;
_port = port;
}
public SFTPClient(final String host, final int port, final String username, final String password) {
this();
_host = host;
_port = port;
_username = username;
_password = password;
}
public String getUsername() {
return _username;
}
public void setUsername(final String username) {
this._username = username;
}
public String getPassword() {
return _password;
}
public void setPassword(final String password) {
this._password = password;
}
public String getHost() {
return _host;
}
public void setHost(final String host) {
this._host = host;
}
public int getPort() {
return _port;
}
public void setPort(final int port) {
this._port = port;
}
public boolean isConnected() {
return null != _session
&& _session.isConnected()
&& null != _channel
&& _channel.isConnected();
}
public void disconnect() {
if (this.isConnected()) {
_session.disconnect();
_channel.disconnect();
}
}
public SFTPClient connect() throws Exception {
// disconnect if already connected
this.disconnect();
// connect
if (StringUtils.hasText(_host) && _port > 0) {
final SFTPUserInfo ui = new SFTPUserInfo(_password);
_session = this.getSession();
_session.setUserInfo(ui);
_session.connect();
_channel = (ChannelSftp) _session.openChannel("sftp");
_channel.connect();
}
return this;
}
// --------------------------------------------------------------------
// c o m m a n d s
// --------------------------------------------------------------------
public Set<String> list() {
return this.list(null);
}
/**
* Returns current Remote directory
*
* @return current Remote dir
*/
public String pwd() {
try {
return _channel.pwd();
} catch (Exception e) {
return null;
}
}
/**
* Returns current Local directory
*
* @return current Local dir
*/
public String lpwd() {
return _channel.lpwd();
}
/**
* List remote path
*
* @param opt_path
* @return
*/
public Set<String> list(final String opt_path) {
final Set<String> result = new HashSet<String>();
final String path = StringUtils.hasText(opt_path) ? opt_path : ".";
try {
final Vector vv = _channel.ls(path);
if (vv != null) {
for (int ii = 0; ii < vv.size(); ii++) {
Object obj = vv.elementAt(ii);
if (obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry) {
result.add(((com.jcraft.jsch.ChannelSftp.LsEntry) obj).getFilename());
}
}
}
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return result;
}
/**
* List local path
*
* @param opt_path
* @return
*/
public Set<String> llist(final String opt_path) {
final Set<String> result = new HashSet<String>();
final String path = StringUtils.hasText(opt_path) ? opt_path : ".";
try {
final File file = new File(path);
if (file.exists() && file.isDirectory()) {
String[] list = file.list();
for (int ii = 0; ii < list.length; ii++) {
result.add(list[ii]);
}
}
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return result;
}
/**
* Change Remote directory
*
* @param path
*/
public void cd(final String path) {
if (!StringUtils.hasText(path)) return;
try {
_channel.cd(path);
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
}
/**
* Change Local directory
*
* @param path
*/
public void lcd(final String path) {
if (!StringUtils.hasText(path)) return;
try {
_channel.lcd(path);
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
}
/**
* @param p1 Source
* @param opt_p2 Destination
* @return
*/
public File get(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.OVERWRITE;
_channel.get(p1, p2, new SFTPProgressMonitor(), mode);
return this.toFile(p2);
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
public File getResume(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.RESUME;
_channel.get(p1, p2, new SFTPProgressMonitor(), mode);
return this.toFile(p2);
} catch (SftpException e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
public File getAppend(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.APPEND;
_channel.get(p1, p2, new SFTPProgressMonitor(), mode);
return this.toFile(p2);
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
public String put(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.OVERWRITE;
_channel.put(p1, p2, new SFTPProgressMonitor(), mode);
return p2;
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
public String putResume(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.RESUME;
_channel.put(p1, p2, new SFTPProgressMonitor(), mode);
return p2;
} catch (SftpException e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
public String putAppend(final String p1, final String opt_p2) {
final String p2 = StringUtils.hasText(opt_p2) ? opt_p2 : ".";
try {
final int mode = ChannelSftp.APPEND;
_channel.put(p1, p2, new SFTPProgressMonitor(), mode);
return p2;
} catch (Exception e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return null;
}
/**
* Remove file
*
* @param path
* @throws Exception
*/
public void rm(final String path) throws Exception {
if (StringUtils.hasText(path)) {
_channel.rm(path);
}
}
/**
* Remove directory
*
* @param path
* @throws Exception
*/
public void rmdir(final String path) throws Exception {
if (StringUtils.hasText(path)) {
_channel.rmdir(path);
}
}
/**
* Create directory
*
* @param path
* @throws Exception
*/
public void mkdir(final String path) throws Exception {
if (StringUtils.hasText(path)) {
_channel.mkdir(path);
}
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private Logger getLogger() {
return LoggingUtils.getLogger(this);
}
private Session getSession() throws JSchException {
return _jsch.getSession(_username, _host, _port);
}
private File toFile(final String path) {
final File result = new File(path);
return result.exists() ? result : null;
}
private void parseCommand(final String cmd, final Vector<String> cmds) throws Exception {
int level = 0;
String str = "";
PrintStream out = System.out;
if (cmd.equals("quit")) {
_channel.quit();
return;
}
if (cmd.equals("exit")) {
_channel.exit();
return;
}
if (cmd.equals("rekey")) {
_session.rekey();
}
if (cmd.equals("compression")) {
if (cmds.size() < 2) {
out.println("compression level: " + level);
return;
}
try {
level = Integer.parseInt((String) cmds.elementAt(1));
if (level == 0) {
_session.setConfig("compression.s2c", "none");
_session.setConfig("compression.c2s", "none");
} else {
_session.setConfig("compression.s2c", "zlib@openssh.com,zlib,none");
_session.setConfig("compression.c2s", "zlib@openssh.com,zlib,none");
}
} catch (Exception e) {
}
_session.rekey();
return;
}
if (cmd.equals("cd") || cmd.equals("lcd")) {
if (cmds.size() < 2) return;
String path = (String) cmds.elementAt(1);
try {
if (cmd.equals("cd")) _channel.cd(path);
else _channel.lcd(path);
} catch (SftpException e) {
this.getLogger().log(Level.SEVERE, null, e);
}
return;
}
if (cmd.equals("rm") || cmd.equals("rmdir") || cmd.equals("mkdir")) {
if (cmds.size() < 2) return;
String path = (String) cmds.elementAt(1);
try {
if (cmd.equals("rm"))
_channel.rm(path);
else if (cmd.equals("rmdir"))
_channel.rmdir(path);
else
_channel.mkdir(path);
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("chgrp") || cmd.equals("chown") || cmd.equals("chmod")) {
if (cmds.size() != 3) return;
String path = (String) cmds.elementAt(2);
int foo = 0;
if (cmd.equals("chmod")) {
byte[] bar = ((String) cmds.elementAt(1)).getBytes();
int k;
for (int j = 0; j < bar.length; j++) {
k = bar[j];
if (k < '0' || k > '7') {
foo = -1;
break;
}
foo <<= 3;
foo |= (k - '0');
}
if (foo == -1) return;
} else {
try {
foo = Integer.parseInt((String) cmds.elementAt(1));
} catch (Exception e) {
return;
}
}
try {
if (cmd.equals("chgrp")) {
_channel.chgrp(foo, path);
} else if (cmd.equals("chown")) {
_channel.chown(foo, path);
} else if (cmd.equals("chmod")) {
_channel.chmod(foo, path);
}
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("pwd") || cmd.equals("lpwd")) {
str = (cmd.equals("pwd") ? "Remote" : "Local");
str += " working directory: ";
if (cmd.equals("pwd")) str += _channel.pwd();
else str += _channel.lpwd();
out.println(str);
return;
}
if (cmd.equals("ls") || cmd.equals("dir")) {
String path = ".";
if (cmds.size() == 2) path = (String) cmds.elementAt(1);
try {
java.util.Vector vv = _channel.ls(path);
if (vv != null) {
for (int ii = 0; ii < vv.size(); ii++) {
// out.println(vv.elementAt(ii).toString());
Object obj = vv.elementAt(ii);
if (obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry) {
out.println(((com.jcraft.jsch.ChannelSftp.LsEntry) obj).getLongname());
}
}
}
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("lls") || cmd.equals("ldir")) {
String path = ".";
if (cmds.size() == 2) path = (String) cmds.elementAt(1);
try {
java.io.File file = new java.io.File(path);
if (!file.exists()) {
out.println(path + ": No such file or directory");
return;
}
if (file.isDirectory()) {
String[] list = file.list();
for (int ii = 0; ii < list.length; ii++) {
out.println(list[ii]);
}
return;
}
out.println(path);
} catch (Exception e) {
System.out.println(e);
}
return;
}
if (cmd.equals("get") ||
cmd.equals("get-resume") || cmd.equals("get-append") ||
cmd.equals("put") ||
cmd.equals("put-resume") || cmd.equals("put-append")
) {
if (cmds.size() != 2 && cmds.size() != 3) return;
String p1 = (String) cmds.elementAt(1);
// String p2=p1;
String p2 = ".";
if (cmds.size() == 3) p2 = (String) cmds.elementAt(2);
try {
final SftpProgressMonitor monitor = new SFTPProgressMonitor();
if (cmd.startsWith("get")) {
int mode = ChannelSftp.OVERWRITE;
if (cmd.equals("get-resume")) {
mode = ChannelSftp.RESUME;
} else if (cmd.equals("get-append")) {
mode = ChannelSftp.APPEND;
}
_channel.get(p1, p2, monitor, mode);
} else {
int mode = ChannelSftp.OVERWRITE;
if (cmd.equals("put-resume")) {
mode = ChannelSftp.RESUME;
} else if (cmd.equals("put-append")) {
mode = ChannelSftp.APPEND;
}
_channel.put(p1, p2, monitor, mode);
}
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("ln") || cmd.equals("symlink") || cmd.equals("rename")) {
if (cmds.size() != 3) return;
String p1 = (String) cmds.elementAt(1);
String p2 = (String) cmds.elementAt(2);
try {
if (cmd.equals("rename")) _channel.rename(p1, p2);
else _channel.symlink(p1, p2);
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("stat") || cmd.equals("lstat")) {
if (cmds.size() != 2) return;
String p1 = (String) cmds.elementAt(1);
SftpATTRS attrs = null;
try {
if (cmd.equals("stat")) attrs = _channel.stat(p1);
else attrs = _channel.lstat(p1);
} catch (SftpException e) {
System.out.println(e.toString());
}
if (attrs != null) {
out.println(attrs);
} else {
}
return;
}
if (cmd.equals("readlink")) {
if (cmds.size() != 2) return;
String p1 = (String) cmds.elementAt(1);
String filename = null;
try {
filename = _channel.readlink(p1);
out.println(filename);
} catch (SftpException e) {
System.out.println(e.toString());
}
return;
}
if (cmd.equals("realpath")) {
if (cmds.size() != 2) return;
String p1 = (String) cmds.elementAt(1);
String filename = null;
try {
filename = _channel.realpath(p1);
out.println(filename);
} catch (SftpException e) {
System.out.println(e.toString());
}
}
if (cmd.equals("version")) {
out.println("SFTP protocol version " + _channel.version());
}
}
private static String help =
" Available commands:\n" +
" * means unimplemented command.\n" +
"cd path Change remote directory to 'path'\n" +
"lcd path Change local directory to 'path'\n" +
"chgrp grp path Change group of file 'path' to 'grp'\n" +
"chmod mode path Change permissions of file 'path' to 'mode'\n" +
"chown own path Change owner of file 'path' to 'own'\n" +
"help Display this help text\n" +
"get remote-path [local-path] Download file\n" +
"get-resume remote-path [local-path] Resume to download file.\n" +
"get-append remote-path [local-path] Append remote file to local file\n" +
"*lls [ls-options [path]] Display local directory listing\n" +
"ln oldpath newpath Symlink remote file\n" +
"*lmkdir path Create local directory\n" +
"lpwd Print local working directory\n" +
"ls [path] Display remote directory listing\n" +
"*lumask umask Set local umask to 'umask'\n" +
"mkdir path Create remote directory\n" +
"put local-path [remote-path] Upload file\n" +
"put-resume local-path [remote-path] Resume to upload file\n" +
"put-append local-path [remote-path] Append local file to remote file.\n" +
"pwd Display remote working directory\n" +
"stat path Display info about path\n" +
"exit Quit sftp\n" +
"quit Quit sftp\n" +
"rename oldpath newpath Rename remote file\n" +
"rmdir path Remove remote directory\n" +
"rm path Delete remote file\n" +
"symlink oldpath newpath Symlink remote file\n" +
"readlink path Check the target of a symbolic link\n" +
"realpath path Canonicalize the path\n" +
"rekey Key re-exchanging\n" +
"compression level Packet compression will be enabled\n" +
"version Show SFTP version\n" +
"? Synonym for help";
}