package com.rectang.xsm.io;
import java.io.*;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import com.rectang.xsm.XSM;
import com.rectang.xsm.site.Site;
import com.jcraft.jsch.*;
public class SshPublishedFile
extends PublishedFile
{
private static int TIMEOUT = 60000;
private static JSch sshController;
public SshPublishedFile( Site site, String fileName )
{
super( site, fileName );
if ( sshController == null )
{
sshController = new JSch();
try
{
sshController.addIdentity( "/etc/xsm/id_rsa" );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
}
public OutputStream getOutputStream()
throws IOException
{
File tmp = XSM.getTempFile();
return new OutputStreamWrapper( tmp );
}
public String toString()
{
return "Ssh file: " + getSite().getRemoteHost() + ":" + file;
}
public boolean exists()
{
return exists( file );
}
private boolean exists( String f )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
return sshChannel.ls( f ).size() > 0;
}
catch ( SftpException e )
{
e.printStackTrace();
}
return false;
}
public boolean mkparentdirs()
{
String parent = (new File( file )).getParentFile().getPath();
return mkdir( parent ); /* this checks for existance */
}
public boolean mkdir()
{
return mkdir( file );
}
private boolean mkdir( String f )
{
if ( exists( f ) )
{
return true;
}
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
File parentFile = (new File( f )).getParentFile();
if ( parentFile != null )
{
String parent = parentFile.getPath();
mkdir( parent ); /* this checks for existance */
}
sshChannel.mkdir( f );
return true;
}
catch ( SftpException e )
{
e.printStackTrace();
}
return false;
}
public boolean delete()
{
return deleteDir( file );
}
private boolean delete( String rmFile )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
sshChannel.rm( rmFile );
return true;
}
catch ( SftpException e )
{
try
{
sshChannel.rmdir( rmFile );
return true;
}
catch ( SftpException e2 )
{
e2.printStackTrace();
}
}
return false;
}
private boolean deleteDir( String path )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
if ( !exists( path ) )
{
return true;
}
Vector files = null;
try
{
files = sshChannel.ls( path );
}
catch ( Exception e )
{
/* fall through to deleting the path */
}
if ( files != null && files.size() != 0 )
{
Iterator fileList = files.iterator();
while ( fileList.hasNext() )
{
String next = fileList.next().toString().trim();
int pos = next.lastIndexOf( ' ' );
String name = next.substring( pos + 1 );
if ( name.equals( "." ) || name.equals( ".." ) )
{
continue;
}
String subPath = path + "/" + name;
if ( isDirectory( subPath ) )
{
deleteDir( subPath );
}
else
{
delete( subPath );
}
}
}
return delete( path );
}
public boolean isDirectory()
{
return isDirectory( file );
}
private boolean isDirectory( String path )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
Vector list = sshChannel.ls( path );
if ( list == null || (list.size() == 1 /* 1 entry for non-directory */
/* if 1 entry make sure it is a file */
&& ((String) list.get( 0 )).trim().endsWith(
((new File( path )).getParentFile().getName()) )) )
{
return false;
}
return true;
}
catch ( Exception e )
{
return false;
}
}
public long length()
{
return length( file );
}
private long length( String path )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
SftpATTRS atts = sshChannel.lstat( path );
if ( atts == null )
{
return 0;
}
return atts.getSize();
}
catch ( Exception e )
{
return 0;
}
}
public boolean rename( String newName )
{
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
String oldPath = file;
setFile( newName );
mkparentdirs();
sshChannel.rename( oldPath, file );
return true;
}
catch ( SftpException e )
{
e.printStackTrace();
}
return false;
}
public void uploadFile( File f )
{
uploadFile( f, true );
}
public void uploadFile( File f, boolean delete )
{
try
{
if ( !f.exists() )
{
return;
}
mkparentdirs();
ChannelSftp sshChannel = getSftpChannel( getSite() );
try
{
sshChannel.put( new FileInputStream( f ), file );
if ( delete )
{
f.delete();
}
}
catch ( SftpException e )
{
e.printStackTrace();
}
}
catch ( Exception io )
{
io.printStackTrace();
}
}
class OutputStreamWrapper
extends FileOutputStream
{
private File f;
public OutputStreamWrapper( File f )
throws IOException
{
super( f );
this.f = f;
}
public void close()
throws IOException
{
super.close();
uploadFile( f, true );
}
}
private static Hashtable channelHash = new Hashtable();
public static ChannelSftp getSftpChannel( Site site )
{
TimeoutChannel chan = (TimeoutChannel) channelHash.get( site );
if ( chan != null )
{
if ( chan.timeout < System.currentTimeMillis() )
{
try
{
chan.channel.exit();
chan.channel.disconnect();
}
catch ( Exception e )
{
/* we ignore these */
}
chan = null;
}
}
if ( chan == null )
{
try
{
Session sess =
sshController.getSession( site.getRemoteUser(), site.getRemoteHost(), 22 );
java.util.Hashtable config = new java.util.Hashtable();
config.put( "StrictHostKeyChecking", "no" );
sess.setConfig( config );
sess.connect();
chan = new TimeoutChannel( (ChannelSftp) sess.openChannel( "sftp" ),
System.currentTimeMillis() + TIMEOUT );
chan.channel.connect();
channelHash.put( site, chan );
}
catch ( Exception e )
{
e.printStackTrace();
/* TODO better way of erroring... */
return null;
}
}
return chan.channel;
}
private static class TimeoutChannel
{
protected long timeout;
protected ChannelSftp channel;
public TimeoutChannel( ChannelSftp chan, long time )
{
this.channel = chan;
this.timeout = time;
}
}
}