import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.io.File; import java.io.InputStream; import java.io.PrintStream; import java.util.Vector; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import javax.swing.ProgressMonitor; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpProgressMonitor; import com.jcraft.jsch.SftpStatVFS; import com.jcraft.jsch.UIKeyboardInteractive; import com.jcraft.jsch.UserInfo; public class Sftp { public static void main(String[] args) { try { JSch jsch = new JSch(); String host = null; if (args.length > 0) { host = args[0]; } else { host = JOptionPane.showInputDialog("Enter username@hostname", System.getProperty("user.name") + "@localhost"); } String user = host.substring(0, host.indexOf('@')); host = host.substring(host.indexOf('@') + 1); int port = 22; Session session = jsch.getSession(user, host, port); UserInfo userinfo = new MyUserInfo(); session.setUserInfo(userinfo); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); ChannelSftp channelSftp = (ChannelSftp)channel; InputStream in = System.in; PrintStream out = System.out; Vector cmds = new Vector(); byte[] buf = new byte[1024]; int i; String str; int level = 0; while (true) { out.print("sftp> "); cmds.removeAllElements(); i = in.read(buf, 0, 1024); if (i <= 0) { break; } i--; if (i > 0 && buf[i-1] == 0x0d) { i--; } int s = 0; for (int ii = 0; ii < i; ii++) { if (' ' == buf[ii]) { if (ii - s > 0) { cmds.addElement(new String(buf, s, ii - s)); } while (ii < i) { if (' ' != buf[ii]) { break; } ii++; } s = ii; } } if (s < i) { cmds.addElement(new String(buf, s, i - s)); } if (0 == cmds.size()) { continue; } String cmd = (String) cmds.elementAt(0); if (cmd.equals("quit")) { channelSftp.quit(); break; } if (cmd.equals("exit")) { channelSftp.exit(); break; } if (cmd.equals("rekey")) { session.rekey(); continue; } if (cmd.equals("compression")) { if (cmds.size() < 2) { out.println("compression level: " + level); continue; } try { level = Integer.parseInt((String)cmds.elementAt(1)); if (0 == level) { 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(); continue; } if (cmd.equals("cd") || cmd.equals("lcd")) { if (cmds.size() < 2) { continue; } String path = (String)cmds.elementAt(1); try { if (cmd.equals("cd")) { channelSftp.cd(path); } else { channelSftp.lcd(path); } } catch (Exception e) { System.out.println(e.toString()); } continue; } if (cmd.equals("rm") || cmd.equals("rmdir") || cmd.equals("mkdir")) { if (cmds.size() < 2) { continue; } String path = (String)cmds.elementAt(1); try { if (cmd.equals("rm")) { channelSftp.rm(path); } else if (cmd.equals("rmdir")) { channelSftp.rmdir(path); } else { channelSftp.mkdir(path); } } catch (Exception e) { System.out.println(e.toString()); } continue; } if (cmd.equals("chgrp") || cmd.equals("chown") || cmd.equals("chmod")) { if (3 != cmds.size()) { continue; } 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 (-1 == foo) { continue; } } else { try { foo = Integer.parseInt((String)cmds.elementAt(1)); } catch (Exception e) { continue; } } try { if (cmd.equals("chgrp")) { channelSftp.chgrp(foo, path); } else if (cmd.equals("chown")) { channelSftp.chown(foo, path); } else if (cmd.equals("chmod")) { channelSftp.chmod(foo, path); } } catch (Exception e) { System.out.println(e.toString()); } continue; } if (cmd.equals("pwd") || cmd.equals("lpwd")) { str = (cmd.equals("pwd") ? "Remote" : "Local"); str += " working directory: "; if (cmd.equals("pwd")) { str += channelSftp.pwd(); } else { str += channelSftp.lpwd(); } out.println(str); continue; } if (cmd.equals("ls") || cmd.equals("dir")) { String path = "."; if (2 == cmds.size()) { path = (String)cmds.elementAt(1); } try { Vector vv = channelSftp.ls(path); if (null != vv) { for (int ii = 0; ii < vv.size(); ii++) { Object object = vv.elementAt(ii); if (object instanceof LsEntry) { out.println(((LsEntry)object).getLongname()); } } } } catch (Exception e) { System.out.println(e.toString()); } continue; } if (cmds.equals("lls") || cmds.equals("ldir")) { String path = "."; if (2 == cmds.size()) { path = (String)cmds.elementAt(1); } try { File file = new File(path); if (!file.exists()) { out.println(path + ": No such file or directory"); continue; } if (file.isDirectory()) { String[] list = file.list(); for (int ii = 0; ii < list.length; ii++) { out.println(list[ii]); } continue; } out.println(path); } catch (Exception e) { // TODO: handle exception out.println(path); } continue; } if (cmd.equals("get") || cmd.equals("get-resume") || cmd.equals("get-append") || cmd.equals("put") || cmd.equals("put-resume") || cmd.equals("put-append")) { if (2 != cmds.size() && 3 != cmds.size()) { continue; } String p1 = (String)cmds.elementAt(1); String p2 = "."; if (3 == cmds.size()) { p2 = (String)cmds.elementAt(2); } try { SftpProgressMonitor monitor = new MyProgressMonitor(); 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; } channelSftp.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; } channelSftp.put(p1, p2, monitor, mode); } } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()); } continue; } if (cmd.equals("ln") || cmd.equals("symlink") || cmd.equals("rename") || cmd.equals("hardlink")) { if (3 != cmds.size()) { continue; } String p1 = (String)cmds.elementAt(1); String p2 = (String)cmds.elementAt(2); try { if (cmd.equals("hardlink")) { channelSftp.hardlink(p1, p2); } else if (cmd.equals("rename")) { channelSftp.rename(p1, p2); } else { channelSftp.symlink(p1, p2); } } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()); } continue; } if (cmd.equals("df")) { if (cmds.size() > 2) { continue; } String p1 = 1 == cmds.size() ? "." : (String)cmds.elementAt(1); SftpStatVFS stat = channelSftp.statVFS(p1); long size = stat.getSize(); long used = stat.getUsed(); long avail = stat.getAvailForNonRoot(); long root_avail = stat.getAvail(); long capacity = stat.getCapacity(); System.out.println("Size: " + size); System.out.println("Used: " + used); System.out.println("Avail: " + avail); System.out.println("(root): " + root_avail); System.out.println("%Capacity: " + capacity); continue; } if (cmd.equals("stat") || cmd.equals("lstat")) { if (2 != cmds.size()) { continue; } String p1 = (String)cmds.elementAt(1); SftpATTRS attrs = null; try { if (cmd.equals("stat")) { attrs = channelSftp.stat(p1); } else { attrs = channelSftp.lstat(p1); } } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()); } if (null != attrs) { out.println(attrs); } continue; } if (cmd.equals("readlink")) { if (2 != cmds.size()) { continue; } String p1 = (String)cmds.elementAt(1); String filename = null; try { filename = channelSftp.readlink(p1); out.println(filename); } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()); } continue; } if (cmd.equals("realpath")) { if (2 != cmds.size()) { continue; } String p1 = (String)cmds.elementAt(1); String filename = null; try { filename = channelSftp.realpath(p1); out.println(filename); } catch (Exception e) { // TODO: handle exception System.out.println(e.toString()); } continue; } if (cmd.equals("version")) { out.println("SFTP protocol version " + channelSftp.version()); continue; } if (cmd.equals("help") || cmd.equals("?")) { out.println(help); continue; } out.println("unimplemented command: " + cmd); } session.disconnect(); } catch (Exception e) { // TODO: handle exception System.out.println(e); } System.exit(0); } public static class MyUserInfo implements UserInfo, UIKeyboardInteractive { String passwd; JTextField passwordField = (JTextField)new JPasswordField(20); final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); Container panel; @Override public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) { panel = new JPanel(); panel.setLayout(new GridBagLayout()); gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridx = 0; panel.add(new JLabel(instruction), gbc); gbc.gridy++; gbc.gridwidth = GridBagConstraints.RELATIVE; JTextField[] texts = new JTextField[prompt.length]; for (int i = 0; i < prompt.length; i++) { gbc.fill = GridBagConstraints.NONE; gbc.gridx = 0; gbc.weightx = 1; panel.add(new JLabel(prompt[i]), gbc); gbc.gridx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weighty = 1; if (echo[i]) { texts[i] = new JTextField(20); } else { texts[i] = new JPasswordField(20); } panel.add(texts[i], gbc); gbc.gridy++; } if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(null, panel, destination + ": " + name, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE)) { String[] response = new String[prompt.length]; for (int i = 0; i < prompt.length; i++) { response[i] = texts[i].getText(); } return response; } else { return null; // cancel } } @Override public String getPassphrase() { // TODO Auto-generated method stub return null; } @Override public String getPassword() { // TODO Auto-generated method stub return passwd; } @Override public boolean promptPassphrase(String message) { // TODO Auto-generated method stub return true; } @Override public boolean promptPassword(String message) { Object[] ob = { passwordField }; int result = JOptionPane.showConfirmDialog(null, ob, message, JOptionPane.OK_CANCEL_OPTION); if (JOptionPane.OK_OPTION == result) { passwd = passwordField.getText(); return true; } else { return false; } } @Override public boolean promptYesNo(String message) { Object[] options = { "yes", "no" }; int foo = JOptionPane.showOptionDialog(null, message, "warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); return 0 == foo; } @Override public void showMessage(String message) { // TODO Auto-generated method stub JOptionPane.showMessageDialog(null, message); } } public static class MyProgressMonitor implements SftpProgressMonitor { ProgressMonitor monitor; long count = 0; long max = 0; private long percent = -1; @Override public boolean count(long count) { this.count += count; if (percent >= this.count * 100 / max) { return true; } percent = this.count * 100 / max; monitor.setNote("Completed " + this.count + "(" + percent + "%) out of " + max + "."); monitor.setProgress((int)this.count); return !(monitor.isCanceled()); } @Override public void end() { monitor.close(); } @Override public void init(int op, String src, String dest, long max) { this.max = max; monitor = new ProgressMonitor(null, ((SftpProgressMonitor.PUT == op) ? "put" : "get" + ": " + src), "", 0, (int)max); count = 0; percent = -1; monitor.setProgress((int)this.count); monitor.setMillisToDecideToPopup(1000); } } private static String help = " Available commands: "+ " * means unimplemented command. "+ "cd path Change remote directory to 'path' "+ "lcd path Change local directory to 'path' "+ "chgrp grp path Change group of file 'path' to 'grp' "+ "chmod mode path Change permissions of file 'path' to 'mode' "+ "chown own path Change owner of file 'path' to 'own' "+ "df [path] Display statistics for current directory or "+ " filesystem containing 'path' "+ "help Display this help text "+ "get remote-path [local-path] Download file "+ "get-resume remote-path [local-path] Resume to download file. "+ "get-append remote-path [local-path] Append remote file to local file "+ "hardlink oldpath newpath Hardlink remote file "+ "*lls [ls-options [path]] Display local directory listing "+ "ln oldpath newpath Symlink remote file "+ "*lmkdir path Create local directory "+ "lpwd Print local working directory "+ "ls [path] Display remote directory listing "+ "*lumask umask Set local umask to 'umask' "+ "mkdir path Create remote directory "+ "put local-path [remote-path] Upload file "+ "put-resume local-path [remote-path] Resume to upload file "+ "put-append local-path [remote-path] Append local file to remote file. "+ "pwd Display remote working directory "+ "stat path Display info about path "+ "exit Quit sftp "+ "quit Quit sftp "+ "rename oldpath newpath Rename remote file "+ "rmdir path Remove remote directory "+ "rm path Delete remote file "+ "symlink oldpath newpath Symlink remote file "+ "readlink path Check the target of a symbolic link "+ "realpath path Canonicalize the path "+ "rekey Key re-exchanging "+ "compression level Packet compression will be enabled "+ "version Show SFTP version "+ "? Synonym for help"; }