/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package net.sf.jftp.net.wrappers;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StreamTokenizer;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JOptionPane;
import net.sf.jftp.config.Settings;
import net.sf.jftp.net.BasicConnection;
import net.sf.jftp.net.ConnectionListener;
import net.sf.jftp.net.DataConnection;
import net.sf.jftp.net.FtpConnection;
import net.sf.jftp.net.Transfer;
import net.sf.jftp.system.StringUtils;
import net.sf.jftp.system.logging.Log;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.sshtools.j2ssh.sftp.SftpFile;
import com.sshtools.j2ssh.sftp.SftpFileInputStream;
import com.sshtools.j2ssh.sftp.SftpFileOutputStream;
import com.sshtools.j2ssh.sftp.SftpSubsystemClient;
public class Sftp2Connection implements BasicConnection
{
public static int smbBuffer = 32000;
private String path = "";
private String pwd = "/";
private Vector listeners = new Vector();
private String[] files;
private String[] size = new String[0];
private int[] perms = null;
private String user;
private String pass;
private String host;
private String baseFile;
private int fileCount;
private boolean isDirUpload = false;
private boolean shortProgress = false;
private int RW = SftpSubsystemClient.OPEN_CREATE |
SftpSubsystemClient.OPEN_WRITE;
private int W = SftpSubsystemClient.OPEN_CREATE;
private int R = SftpSubsystemClient.OPEN_READ;
private int port = 22;
private boolean connected = false;
private String keyfile = null;
private Session session;
private ChannelSftp channel;
public Sftp2Connection(String host, String port, String keyfile)
{
this.host = host;
this.port = Integer.parseInt(port);
this.keyfile = keyfile;
Log.debug("Using JSch wrapper...");
}
private boolean login()
{
try
{
JSch jsch = new JSch();
if(keyfile != null) {
jsch.addIdentity(keyfile);
}
session = jsch.getSession(user, host, this.port);
UserInfo ui = new MyUserInfo(pass);
session.setUserInfo(ui);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
Log.debug("Host: "+host+":"+port);
connected = true;
return true;
}
catch(Exception ex)
{
ex.printStackTrace();
Log.debug("Error: " + ex);
return false;
}
}
public int removeFileOrDir(String file)
{
file = toSFTP(file);
try
{
if(!file.endsWith("/"))
{
Log.out(">>>>>>>> remove file: " + file);
channel.rm(file);
}
else
{
Log.out(">>>>>>>> remove dir: " + file);
cleanSftpDir(file);
channel.rmdir(file);
}
}
catch(Exception ex)
{
ex.printStackTrace();
Log.debug("Removal failed (" + ex + ").");
ex.printStackTrace();
return -1;
}
return 1;
}
private void cleanSftpDir(String dir)
throws Exception
{
Log.out(">>>>>>>> cleanSftpDir: " + dir);
Vector v = channel.ls(dir);
String[] tmp = new String[v.size()];
Enumeration e = v.elements();
int x = 0;
while(e.hasMoreElements())
{
LsEntry entry = ((LsEntry)e.nextElement());
tmp[x] = entry.getFilename();
//Log.out("sftp delete: " + tmp[x]);
if(entry.getAttrs().isDir() && !tmp[x].endsWith("/"))
{
tmp[x] = tmp[x] + "/";
}
x++;
}
if(tmp == null)
{
return;
}
for(int i = 0; i < tmp.length; i++)
{
if(tmp[i].equals("./") || tmp[i].equals("../"))
{
continue;
}
Log.out(">>>>>>>> remove file/dir: " + dir + tmp[i]);
if(tmp[i].endsWith("/"))
{
cleanSftpDir(dir + tmp[i]);
channel.rmdir(dir + tmp[i]);
}
else
{
channel.rm(dir + tmp[i]);
}
}
}
public void sendRawCommand(String cmd)
{
}
public void disconnect()
{
try
{
channel.disconnect();
session.disconnect();
}
catch(Exception e)
{
e.printStackTrace();
Log.debug("Sftp2Connection.disconnect()" + e);
}
connected = false;
}
public boolean isConnected()
{
return connected;
}
public String getPWD()
{
//Log.debug("PWD: " + pwd);
return toSFTPDir(pwd);
}
public boolean mkdir(String dirName)
{
try
{
if(!dirName.endsWith("/"))
{
dirName = dirName + "/";
}
dirName = toSFTP(dirName);
channel.mkdir(dirName);
fireDirectoryUpdate();
return true;
}
catch(Exception ex)
{
Log.debug("Failed to create directory (" + ex + ").");
return false;
}
}
public void list() throws IOException
{
}
public boolean chdir(String p)
{
return chdir(p, true);
}
public boolean chdir(String p, boolean refresh)
{
String tmp = toSFTP(p);
try
{
if(!tmp.endsWith("/"))
{
tmp = tmp + "/";
}
if(tmp.endsWith("../"))
{
return cdup();
}
System.out.println("sftp path: "+tmp+", chan: "+channel);
channel.cd(tmp);
pwd = tmp;
//Log.debug("chdir: " + getPWD());
if(refresh)
{
fireDirectoryUpdate();
}
//System.out.println("chdir2: " + getPWD());
//Log.debug("Changed path to: " + tmp);
return true;
}
catch(Exception ex)
{
ex.printStackTrace();
//System.out.println(tmp);
Log.debug("Could not change directory (" + ex + ").");
return false;
}
}
public boolean cdup()
{
String tmp = pwd;
if(pwd.endsWith("/"))
{
tmp = pwd.substring(0, pwd.lastIndexOf("/"));
}
return chdir(tmp.substring(0, tmp.lastIndexOf("/") + 1));
}
public boolean chdirNoRefresh(String p)
{
return chdir(p, false);
}
public String getLocalPath()
{
return path;
}
public boolean setLocalPath(String p)
{
if(StringUtils.isRelative(p))
{
p = path + p;
}
p = p.replace('\\', '/');
//System.out.println(", local 2:" + p);
File f = new File(p);
if(f.exists())
{
try
{
path = f.getCanonicalPath();
path = path.replace('\\', '/');
if(!path.endsWith("/"))
{
path = path + "/";
}
//System.out.println("localPath: "+path);
}
catch(IOException ex)
{
Log.debug("Error: can not get pathname (local)!");
return false;
}
}
else
{
Log.debug("(local) No such path: \"" + p + "\"");
return false;
}
return true;
}
public String[] sortLs()
{
try
{
System.out.println(pwd);
Vector v = channel.ls(pwd);
String[] tmp = new String[v.size()];
files = new String[tmp.length];
size = new String[tmp.length];
perms = new int[tmp.length];
Enumeration e = v.elements();
int x = 0;
while(e.hasMoreElements())
{
LsEntry entry = ((LsEntry)e.nextElement());
tmp[x] = entry.getFilename();
size[x] = ""+entry.getAttrs().getSize();
//Log.debug("Perms: "+entry.getAttrs().getPermissionsString());
/*
if(!entry.getAttrs().getPermissionsString())
{
perms[x] = FtpConnection.DENIED;
}
else
{*/
perms[x] = FtpConnection.R;
//}
//Log.debugRaw(".");
if(entry.getAttrs().isDir() && !tmp[x].endsWith("/"))
{
tmp[x] = tmp[x] + "/";
}
x++;
}
for(int i = 0; i < tmp.length; i++)
{
files[i] = tmp[i];
}
return files;
}
catch(Exception ex)
{
ex.printStackTrace();
Log.debug(" Error while listing directory: " + ex);
return new String[0];
}
}
public String[] sortSize()
{
return size;
}
public int[] getPermissions()
{
return perms;
}
public int handleUpload(String f)
{
if(Settings.getEnableSftpMultiThreading())
{
Sftp2Transfer t = new Sftp2Transfer(getLocalPath(), getPWD(),
f, user, pass, listeners,
Transfer.UPLOAD, keyfile, host, ""+port);
}
else
{
upload(f);
}
return 0;
}
public int handleDownload(String f)
{
if(Settings.getEnableSftpMultiThreading())
{
Sftp2Transfer t = new Sftp2Transfer(getLocalPath(), getPWD(),
f, user, pass, listeners,
Transfer.DOWNLOAD, keyfile, host, ""+port);
}
else
{
download(f);
}
return 0;
}
public int upload(String f)
{
String file = toSFTP(f);
if(file.endsWith("/"))
{
String out = StringUtils.getDir(file);
uploadDir(file, getLocalPath() + out);
fireActionFinished(this);
}
else
{
String outfile = StringUtils.getFile(file);
//System.out.println("transfer: " + file + ", " + getLocalPath() + outfile);
work(getLocalPath() + outfile, file, true);
fireActionFinished(this);
}
return 0;
}
public int download(String f)
{
String file = toSFTP(f);
if(file.endsWith("/"))
{
String out = StringUtils.getDir(file);
downloadDir(file, getLocalPath() + out);
fireActionFinished(this);
}
else
{
String outfile = StringUtils.getFile(file);
//System.out.println("transfer: " + file + ", " + getLocalPath() + outfile);
work(file, getLocalPath() + outfile, false);
fireActionFinished(this);
}
return 0;
}
private void downloadDir(String dir, String out)
{
try
{
//System.out.println("downloadDir: " + dir + "," + out);
fileCount = 0;
shortProgress = true;
baseFile = StringUtils.getDir(dir);
Vector v = channel.ls(dir);
String[] tmp = new String[v.size()];
SftpFile[] f = new SftpFile[v.size()];
Enumeration e = v.elements();
int x = 0;
while(e.hasMoreElements())
{
LsEntry entry = ((LsEntry)e.nextElement());
tmp[x] = entry.getFilename();
if(entry.getAttrs().isDir() && !tmp[x].endsWith("/"))
{
tmp[x] = tmp[x] + "/";
}
x++;
}
File fx = new File(out);
fx.mkdir();
for(int i = 0; i < tmp.length; i++)
{
if(tmp[i].equals("./") || tmp[i].equals("../"))
{
continue;
}
tmp[i] = tmp[i].replace('\\', '/');
//System.out.println("1: " + dir+tmp[i] + ", " + out +tmp[i]);
if(tmp[i].endsWith("/"))
{
if(!tmp[i].endsWith("/"))
{
tmp[i] = tmp[i] + "/";
}
downloadDir(dir + tmp[i], out + tmp[i]);
}
else
{
fileCount++;
fireProgressUpdate(baseFile,
DataConnection.GETDIR + ":" + fileCount,
-1);
work(dir + tmp[i], out + tmp[i], false);
}
}
//System.out.println("enddir");
fireProgressUpdate(baseFile,
DataConnection.DFINISHED + ":" + fileCount, -1);
}
catch(Exception ex)
{
ex.printStackTrace();
System.out.println(dir + ", " + out);
Log.debug("Transfer error: " + ex);
fireProgressUpdate(baseFile,
DataConnection.FAILED + ":" + fileCount, -1);
}
shortProgress = false;
}
private void uploadDir(String dir, String out)
{
try
{
//System.out.println("uploadDir: " + dir + "," + out);
isDirUpload = true;
fileCount = 0;
shortProgress = true;
baseFile = StringUtils.getDir(dir);
File f2 = new File(out);
String[] tmp = f2.list();
if(tmp == null)
{
return;
}
channel.mkdir(dir);
//channel.chmod(744, dir);
for(int i = 0; i < tmp.length; i++)
{
if(tmp[i].equals("./") || tmp[i].equals("../"))
{
continue;
}
tmp[i] = tmp[i].replace('\\', '/');
//System.out.println("1: " + dir+tmp[i] + ", " + out +tmp[i]);
File f3 = new File(out + tmp[i]);
if(f3.isDirectory())
{
if(!tmp[i].endsWith("/"))
{
tmp[i] = tmp[i] + "/";
}
uploadDir(dir + tmp[i], out + tmp[i]);
}
else
{
fileCount++;
fireProgressUpdate(baseFile,
DataConnection.PUTDIR + ":" + fileCount,
-1);
work(out + tmp[i], dir + tmp[i], true);
}
}
fireProgressUpdate(baseFile,
DataConnection.DFINISHED + ":" + fileCount, -1);
}
catch(Exception ex)
{
ex.printStackTrace();
System.out.println(dir + ", " + out);
Log.debug("Transfer error: " + ex);
fireProgressUpdate(baseFile,
DataConnection.FAILED + ":" + fileCount, -1);
}
isDirUpload = false;
shortProgress = true;
}
private String toSFTP(String f)
{
String file;
if(f.startsWith("/"))
{
file = f;
}
else
{
file = getPWD() + f;
}
file = file.replace('\\', '/');
//System.out.println("file: "+file);
return file;
}
private String toSFTPDir(String f)
{
String file;
if(f.startsWith("/"))
{
file = f;
}
else
{
file = pwd + f;
}
file = file.replace('\\', '/');
if(!file.endsWith("/"))
{
file = file + "/";
}
//System.out.println("file: "+file);
return file;
}
private void work(String file, String outfile, boolean up)
{
BufferedInputStream in = null;
BufferedOutputStream out = null;
//System.out.println("work");
try
{
boolean outflag = false;
if(up)
{
in = new BufferedInputStream(new FileInputStream(file));
}
else
{
in = new BufferedInputStream(channel.get(file));
}
if(up)
{
outflag = true;
try {
channel.rm(outfile);
}
catch(Exception ex) {
}
out = new BufferedOutputStream(channel.put(outfile));
}
else
{
out = new BufferedOutputStream(new FileOutputStream(outfile));
}
//System.out.println("out: " + outfile + ", in: " + file);
byte[] buf = new byte[smbBuffer];
int len = 0;
int reallen = 0;
//System.out.println(file+":"+getLocalPath()+outfile);
while(true)
{
len = in.read(buf);
//System.out.print(".");
if(len == StreamTokenizer.TT_EOF)
{
break;
}
out.write(buf, 0, len);
reallen += len;
//System.out.println(file + ":" + StringUtils.getFile(file));
if(outflag)
{
fireProgressUpdate(StringUtils.getFile(outfile),
DataConnection.PUT, reallen);
}
else
{
fireProgressUpdate(StringUtils.getFile(file),
DataConnection.GET, reallen);
}
}
//if(up) {
// channel.chmod(744, outfile);
//}
fireProgressUpdate(file, DataConnection.FINISHED, -1);
}
catch(IOException ex)
{
ex.printStackTrace();
Log.debug("Error with file IO (" + ex + ")!");
fireProgressUpdate(file, DataConnection.FAILED, -1);
}
catch(SftpException ex)
{
ex.printStackTrace();
Log.debug("Error with SFTP IO (" + ex + ")!");
fireProgressUpdate(file, DataConnection.FAILED, -1);
}
finally
{
try
{
out.flush();
out.close();
in.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
public boolean rename(String oldName, String newName)
{
try
{
oldName = toSFTP(oldName);
newName = toSFTP(newName);
channel.rename(oldName, newName);
return true;
}
catch(Exception ex)
{
ex.printStackTrace();
Log.debug("Could rename file (" + ex + ").");
return false;
}
}
private void update(String file, String type, int bytes)
{
if(listeners == null)
{
return;
}
else
{
for(int i = 0; i < listeners.size(); i++)
{
ConnectionListener listener = (ConnectionListener) listeners.elementAt(i);
listener.updateProgress(file, type, bytes);
}
}
}
public void addConnectionListener(ConnectionListener l)
{
listeners.add(l);
}
public void setConnectionListeners(Vector l)
{
listeners = l;
}
/** remote directory has changed */
public void fireDirectoryUpdate()
{
if(listeners == null)
{
return;
}
else
{
for(int i = 0; i < listeners.size(); i++)
{
((ConnectionListener) listeners.elementAt(i)).updateRemoteDirectory(this);
}
}
}
public boolean login(String user, String pass)
{
this.user = user;
this.pass = pass;
if(!login())
{
Log.debug("Login failed.");
return false;
}
else
{
Log.debug("Authed successfully.");
//if(!chdir(getPWD())) chdir("/");
}
return true;
}
/** progress update */
public void fireProgressUpdate(String file, String type, int bytes)
{
if(listeners == null)
{
return;
}
for(int i = 0; i < listeners.size(); i++)
{
ConnectionListener listener = (ConnectionListener) listeners.elementAt(i);
if(shortProgress && Settings.shortProgress)
{
if(type.startsWith(DataConnection.DFINISHED))
{
listener.updateProgress(baseFile,
DataConnection.DFINISHED + ":" +
fileCount, bytes);
}
else if(isDirUpload)
{
listener.updateProgress(baseFile,
DataConnection.PUTDIR + ":" +
fileCount, bytes);
}
else
{
listener.updateProgress(baseFile,
DataConnection.GETDIR + ":" +
fileCount, bytes);
}
}
else
{
listener.updateProgress(file, type, bytes);
}
}
}
public void fireActionFinished(Sftp2Connection con)
{
if(listeners == null)
{
return;
}
else
{
for(int i = 0; i < listeners.size(); i++)
{
((ConnectionListener) listeners.elementAt(i)).actionFinished(con);
}
}
}
public int upload(String file, InputStream i)
{
BufferedOutputStream out = null;
BufferedInputStream in = null;
try
{
file = toSFTP(file);
out = new BufferedOutputStream(channel.put(file));
in = new BufferedInputStream(i);
//Log.debug(getLocalPath() + ":" + file+ ":"+getPWD());
byte[] buf = new byte[smbBuffer];
int len = 0;
int reallen = 0;
while(true)
{
len = in.read(buf);
//System.out.print(".");
if(len == StreamTokenizer.TT_EOF)
{
break;
}
out.write(buf, 0, len);
reallen += len;
fireProgressUpdate(StringUtils.getFile(file),
DataConnection.PUT, reallen);
}
//channel.chmod(744, file);
fireProgressUpdate(file, DataConnection.FINISHED, -1);
return 0;
}
catch(IOException ex)
{
ex.printStackTrace();
Log.debug("Error with file IO (" + ex + ")!");
fireProgressUpdate(file, DataConnection.FAILED, -1);
return -1;
}
catch(SftpException ex)
{
ex.printStackTrace();
Log.debug("Error with file SFTP IO (" + ex + ")!");
fireProgressUpdate(file, DataConnection.FAILED, -1);
return -1;
}
finally
{
try
{
out.flush();
out.close();
in.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
public InputStream getDownloadInputStream(String file)
{
try
{
return channel.get(file);
}
catch(SftpException ex)
{
ex.printStackTrace();
Log.debug(ex.toString() +
" @Sftp2Connection::getDownloadInputStream");
return null;
}
}
public Date[] sortDates()
{
return null;
}
}
class MyUserInfo implements UserInfo {
String password;
public MyUserInfo(String pass) {
this.password = pass;
}
public String getPassword(){ return password; }
public boolean promptYesNo(String str){
/*
Object[] options={ "yes", "no" };
int foo=JOptionPane.showOptionDialog(null,
str,
"Warning",
JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
return foo==0;
*/
return true;
}
public String getPassphrase(){ return password; }
public boolean promptPassphrase(String message){ return true; }
public boolean promptPassword(String message){
return true;
}
public void showMessage(String message){
//JOptionPane.showMessageDialog(null, message);
}
}