package com.ghostsq.commander.adapters; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.UnknownHostException; import java.util.Date; import com.ghostsq.commander.Commander; import com.ghostsq.commander.R; import com.ghostsq.commander.adapters.FTPAdapter.FTPCredentials; import com.ghostsq.commander.utils.ForwardCompat; import com.ghostsq.commander.utils.LsItem; import com.ghostsq.commander.utils.FTP; import com.ghostsq.commander.utils.Utils; import android.content.Context; import android.net.Uri; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.util.Log; public final class FTPEngines { private static abstract class FTPEngine extends Engine { protected Context ctx; protected FTPCredentials crd; protected FTP ftp; protected Uri uri; FTPEngine( Context ctx_, FTPCredentials crd_, Uri uri_, boolean active ) { ctx = ctx_; crd = crd_; uri = uri_; if( crd == null ) { crd = new FTPCredentials( uri.getUserInfo() ); } ftp = new FTP(); ftp.setActiveMode( active ); } } private static abstract class CopyEngine extends FTPEngine implements FTP.ProgressSink { private long startTime; private long curFileLen = 0, curFileDone = 0, secDone = 0; protected WifiLock wifiLock; protected String progressMessage = null; CopyEngine( Context ctx_, FTPCredentials crd_, Uri uri_, boolean active ) { super( ctx_, crd_, uri_, active ); startTime = System.currentTimeMillis(); WifiManager manager = (WifiManager)ctx.getSystemService( Context.WIFI_SERVICE ); wifiLock = manager.createWifiLock( android.os.Build.VERSION.SDK_INT >= 12 ? 3 : WifiManager.WIFI_MODE_FULL, TAG ); wifiLock.setReferenceCounted( false ); } protected void setCurFileLength( long len ) { curFileDone = 0; curFileLen = len; } @Override public boolean completed( long size, boolean done ) throws InterruptedException { if( curFileLen > 0 ) { curFileDone += size; secDone += size; long cur_time = System.currentTimeMillis(); long time_delta = cur_time - startTime; if( done || time_delta > DELAY ) { // once a sec. only int speed = (int)( MILLI * secDone / time_delta ); sendProgress( progressMessage, (int)( curFileDone * 100 / curFileLen ), -1, speed ); startTime = cur_time; secDone = 0; } } //Log.v( TAG, progressMessage + " " + size ); if( isStopReq() ) { error( ctx.getString( R.string.canceled ) ); return false; } Thread.sleep( 1 ); return true; } } // --- CopyFromEngine --- public static class CopyFromEngine extends CopyEngine { private LsItem[] mList; private File dest_folder; private boolean move; private Commander commander; CopyFromEngine( Commander c, FTPCredentials crd_, Uri uri_, LsItem[] list, File dest, boolean move_, Engines.IReciever recipient_, boolean active ) { super( c.getContext(), crd_, uri_, active ); commander = c; mList = list; dest_folder = dest; move = move_; recipient = recipient_; } @Override public void run() { try { if( crd == null || crd.isNotSet() ) crd = new FTPCredentials( uri.getUserInfo() ); if( ftp.connectAndLogin( uri, crd.getUserName(), crd.getPassword(), true ) < 0 ) { error( ctx.getString( R.string.ftp_nologin ) ); sendResult( "" ); return; } wifiLock.acquire(); int total = copyFiles( mList, "" ); wifiLock.release(); if( recipient != null ) { sendReceiveReq( dest_folder ); return; } sendResult( Utils.getOpReport( ctx, total, R.string.downloaded ) ); } catch( InterruptedException e ) { sendResult( ctx.getString( R.string.canceled ) ); } catch( Exception e ) { error( ctx.getString( R.string.failed ) + e.getLocalizedMessage() ); e.printStackTrace(); } super.run(); } private final int copyFiles( LsItem[] list, String path ) throws InterruptedException { int counter = 0; try { for( int i = 0; i < list.length; i++ ) { if( stop || isInterrupted() ) { error( ctx.getString( R.string.interrupted ) ); break; } LsItem f = list[i]; if( f != null ) { String pathName = path + f.getName(); File dest = new File( dest_folder, pathName ); if( f.isDirectory() ) { if( !dest.mkdir() ) { if( !dest.exists() || !dest.isDirectory() ) { errMsg = "Can't create folder \"" + dest.getCanonicalPath() + "\""; break; } } LsItem[] subItems = ftp.getDirList( pathName, true ); if( subItems == null ) { errMsg = "Failed to get the file list of the subfolder '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog(); break; } counter += copyFiles( subItems, pathName + File.separator ); if( errMsg != null ) break; if( move && !ftp.rmDir( pathName ) ) { errMsg = "Failed to remove folder '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog(); break; } } else { if( dest.exists() ) { int res = askOnFileExist( ctx.getString( R.string.file_exist, dest.getAbsolutePath() ), commander ); if( res == Commander.ABORT ) break; if( res == Commander.SKIP ) continue; if( res == Commander.REPLACE ) { if( !dest.delete() ) { error( ctx.getString( R.string.cant_del, dest.getAbsoluteFile() ) ); break; } } } int pnl = pathName.length(); progressMessage = ctx.getString( R.string.retrieving, pnl > CUT_LEN ? "\u2026" + pathName.substring( pnl - CUT_LEN ) : pathName ); sendProgress( progressMessage, 0 ); setCurFileLength( f.length() ); FileOutputStream out = new FileOutputStream( dest ); ftp.clearLog(); if( !ftp.retrieve( pathName, out, this ) ) { error( "Can't download file '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog() ); dest.delete(); break; } else if( move ) { if( !ftp.delete( pathName ) ) { error( "Can't delete file '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog() ); break; } } progressMessage = ""; } Date ftp_file_date = f.getDate(); if( ftp_file_date != null ) dest.setLastModified( ftp_file_date.getTime() ); final int GINGERBREAD = 9; if( android.os.Build.VERSION.SDK_INT >= GINGERBREAD ) ForwardCompat.setFullPermissions( dest ); counter++; } } } catch( RuntimeException e ) { error( "Runtime Exception: " + e.getMessage() ); Log.e( TAG, "", e ); } catch( IOException e ) { error( "Input-Output Exception: " + e.getMessage() ); Log.e( TAG, "", e ); } return counter; } } // --- CopyToEngine --- public static class CopyToEngine extends CopyEngine { private File[] mList; private int basePathLen; private boolean move = false; private boolean del_src_dir = false; CopyToEngine( Context ctx_, FTPCredentials crd_, Uri uri_, File[] list, boolean move_, boolean del_src_dir_, boolean active ) { super( ctx_, crd_, uri_, active ); mList = list; basePathLen = list[0].getParent().length(); if( basePathLen > 1 ) basePathLen++; move = move_; del_src_dir = del_src_dir_; } @Override public void run() { try { if( ftp.connectAndLogin( uri, crd.getUserName(), crd.getPassword(), true ) < 0 ) { error( ctx.getString( R.string.ftp_nologin ) ); sendResult( "" ); return; } wifiLock.acquire(); int total = copyFiles( mList ); wifiLock.release(); if( del_src_dir ) { File src_dir = mList[0].getParentFile(); if( src_dir != null ) src_dir.delete(); } sendResult( Utils.getOpReport( ctx, total, R.string.uploaded ) ); return; } catch( Exception e ) { error( e.getLocalizedMessage() ); } finally { super.run(); } sendResult( "" ); } private final int copyFiles( File[] list ) throws InterruptedException { if( list == null ) return 0; int counter = 0; try { for( int i = 0; i < list.length; i++ ) { if( stop || isInterrupted() ) { error( ctx.getString( R.string.interrupted ) ); break; } File f = list[i]; if( f != null && f.exists() ) { if( f.isFile() ) { String pathName = f.getAbsolutePath(); int pnl = pathName.length(); progressMessage = ctx.getString( R.string.uploading, pnl > CUT_LEN ? "\u2026" + pathName.substring( pnl - CUT_LEN ) : pathName ); sendProgress( progressMessage, 0 ); String fn = f.getAbsolutePath().substring( basePathLen ); FileInputStream in = new FileInputStream( f ); setCurFileLength( f.length() ); ftp.clearLog(); if( !ftp.store( fn, in, this ) ) { error( ctx.getString( R.string.ftp_upload_failed, f.getName(), ftp.getLog() ) ); break; } progressMessage = ""; } else if( f.isDirectory() ) { ftp.clearLog(); String toCreate = f.getAbsolutePath().substring( basePathLen ); if( !ftp.makeDir( toCreate ) ) { error( ctx.getString( R.string.ftp_mkdir_failed, toCreate, ftp.getLog() ) ); break; } counter += copyFiles( f.listFiles() ); if( errMsg != null ) break; } counter++; if( move && !f.delete() ) { error( ctx.getString( R.string.cant_del, f.getCanonicalPath() ) ); break; } } } } catch( IOException e ) { error( "IOException: " + e.getMessage() ); Log.e( TAG, "", e ); } return counter; } } // --- DelEngine --- static class DelEngine extends FTPEngine { LsItem[] mList; DelEngine( Context ctx_, FTPCredentials crd_, Uri uri_, LsItem[] list, boolean active ) { super( ctx_, crd_, uri_, active ); mList = list; } @Override public void run() { try { if( ftp.connectAndLogin( uri, crd.getUserName(), crd.getPassword(), true ) < 0 ) { error( ctx.getString( R.string.ftp_nologin ) ); sendResult( "" ); return; } int total = delFiles( mList, "" ); sendResult( Utils.getOpReport( ctx, total, R.string.deleted ) ); super.run(); } catch( Exception e ) { Log.e( TAG, "", e ); } } private final int delFiles( LsItem[] list, String path ) { int counter = 0; try { for( int i = 0; i < list.length; i++ ) { if( stop || isInterrupted() ) { error( ctx.getString( R.string.interrupted ) ); break; } LsItem f = list[i]; if( f != null ) { String pathName = path + f.getName(); if( f.isDirectory() ) { LsItem[] subItems = ftp.getDirList( pathName, true ); counter += delFiles( subItems, pathName + File.separator ); if( errMsg != null ) break; ftp.clearLog(); if( !ftp.rmDir( pathName ) ) { error( "Failed to remove folder '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog() ); break; } } else { sendProgress( ctx.getString( R.string.deleting, pathName ), i * 100 / list.length ); ftp.clearLog(); if( !ftp.delete( pathName ) ) { error( "Failed to delete file '" + pathName + "'.\n FTP log:\n\n" + ftp.getLog() ); break; } } counter++; } } } catch( Exception e ) { Log.e( TAG, "delFiles()", e ); error( e.getLocalizedMessage() ); } return counter; } } // --- RenEngine --- static class RenEngine extends FTPEngine { private String oldName, newName; RenEngine( Context ctx_, FTPCredentials crd_, Uri uri_, String oldName_, String newName_, boolean active ) { super( ctx_, crd_, uri_, active ); oldName = oldName_; newName = newName_; } @Override public void run() { try { if( ftp.connectAndLogin( uri, crd.getUserName(), crd.getPassword(), true ) < 0 ) { error( ctx.getString( R.string.ftp_nologin ) ); sendResult( "" ); return; } if( !ftp.rename( oldName, newName ) ) error( ctx.getString( R.string.failed ) + ftp.getLog() ); sendResult( "" ); super.run(); } catch( Exception e ) { Log.e( TAG, "", e ); } } } static class ChmodEngine extends FTPEngine { private String chmod; ChmodEngine( Context ctx_, Uri uri_, String chmod_ ) { super( ctx_, null, uri_, false ); chmod = chmod_; } @Override public void run() { try { if( ftp.connectAndLogin( uri, crd.getUserName(), crd.getPassword(), true ) < 0 ) { error( ctx.getString( R.string.ftp_nologin ) ); sendResult( "" ); return; } if( !ftp.site( chmod ) ) error( ctx.getString( R.string.failed ) + ftp.getLog() ); sendResult( "" ); super.run(); } catch( Exception e ) { Log.e( TAG, "", e ); } } } }