//***************************************************************************** //* //* (c) Copyright 2002. Glub Tech, Incorporated. All Rights Reserved. //* //* $Id: FTPWrite.java 37 2009-05-11 22:46:15Z gary $ //* //***************************************************************************** package com.glub.secureftp.bean; import java.io.*; import java.net.*; import java.util.zip.*; import com.glub.util.*; /** * The <code>FTPWrite</code> class is responsible for writing data from the * FTP server. * * @author Brian Knight * @version $Revision: 47 $, $Date: 2009-05-16 10:10:12 -0700 (Sat, 16 May 2009) $ * @since 2.5.19 */ public class FTPWrite implements FTPData { /** The control socket */ private Socket control = null; /** The socket to write to (passive). */ private Socket sock = null; /** The socket to write to (active). */ private ServerSocket servsock = null; /** The input stream stream from the socket. */ private InputStream input = null; /** The output stream from the socket. */ private OutputStream output = null; /** Used to read in an ascii transfer. */ private BufferedReader reader = null; /** Used to set the ascii encoding. */ private String encoding = null; /** Used to write in an ascii transfer. */ private PrintWriter writer = null; /** A reference to a Progress object. */ private Progress progress = null; /** The start size of the data being transferred. */ private long startsize = 0; /** The filesize of the data being transferred. */ private long filesize = 0; /** If the transfer is aborted, this will be true */ private boolean aborted = false; /** Do we have to wait for the aborted process to cleanup? **/ private boolean waitForAbort = false; /** Is the stream zlib compressed (mode z)? **/ private boolean zLibCompressed = false; /** * Create a new <code>FTPWrite</code> object to be used to send binary * data passively. * * @param s the data socket. * @param is the data stream. */ public FTPWrite( Socket s, InputStream is ) { this( s, is, null, 0, 0 ); } /** * Create a new <code>FTPWrite</code> object to be used to send binary * data with progress information passively. * * @param s the data socket. * @param is the data stream. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). */ public FTPWrite( Socket s, InputStream is, Progress p, long start, long stop ) { sock = s; input = is; progress = p; startsize = start; filesize = stop; } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data passively. * * @param s the data socket. * @param r the data reader. */ public FTPWrite( Socket s, BufferedReader r ) { this( s, r, null, 0, 0 ); } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data with progress information passively. * * @param s the data socket. * @param r the data reader. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). */ public FTPWrite( Socket s, BufferedReader r, Progress p, long start, long stop ) { sock = s; reader = r; progress = p; startsize = start; filesize = stop; } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data with progress information passively. * * @param s the data socket. * @param r the data reader. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). * @param e the data encoding. */ public FTPWrite( Socket s, BufferedReader r, Progress p, long start, long stop, String e ) { sock = s; reader = r; progress = p; startsize = start; filesize = stop; encoding = e; } /** * Create a new <code>FTPWrite</code> object to be used to send binary * data actively. * * @param ss the data server socket. * @param is the data stream. */ public FTPWrite( ServerSocket ss, InputStream is ) { this( ss, is, null, 0, 0 ); } /** * Create a new <code>FTPWrite</code> object to be used to send binary * data with progress information actively. * * @param ss the data server socket. * @param is the data stream. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). */ public FTPWrite( ServerSocket ss, InputStream is, Progress p, long start, long stop ) { servsock = ss; input = is; progress = p; startsize = start; filesize = stop; } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data actively. * * @param ss the data server socket. * @param r the data reader. */ public FTPWrite( ServerSocket ss, BufferedReader r ) { this( ss, r, null, 0, 0 ); } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data with progress information actively. * * @param ss the data server socket. * @param r the data reader. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). */ public FTPWrite( ServerSocket ss, BufferedReader r, Progress p, long start, long stop ) { servsock = ss; reader = r; progress = p; startsize = start; filesize = stop; } /** * Create a new <code>FTPWrite</code> object to be used to send ascii * data with progress information actively. * * @param ss the data server socket. * @param r the data reader. * @param p a <code>Progress</code> object which is used to update * upload status. * @param start the start size of the file being uploaded (used in progress). * @param stop the stop size of the file being uploaded (used in progress). * @param e the data encoding. */ public FTPWrite( ServerSocket ss, BufferedReader r, Progress p, long start, long stop, String e ) { servsock = ss; reader = r; progress = p; startsize = start; filesize = stop; encoding = e; } /** * Set stream as zLib compressed (mode z). * * @param compressed true if compressed */ public void setZLibCompressed( boolean compressed ) { zLibCompressed = compressed; } /** * Set the control socket (used for abort). * * @param control the control socket */ public void setControlSocket( Socket control ) { this.control = control; } /** * Get the control socket (used for abort). * * @return the control socket. */ public Socket getControlSocket() { return control; } /** * Handle the data transfer. * * @throws FTPException if the FTP server returns an error. */ public void doTransfer() throws FTPException { _doTransfer(); } /** * Abort the data transfer. * * @throws FTPException if the FTP server returns an error. */ public void abortTransfer() throws FTPException { aborted = true; waitForAbort = true; _abortSockets(); //cleanup(); } /** * Called when an aborted transfer is complete. This should not be * called directly. */ public void abortComplete() { waitForAbort = false; } /** * Housekeeping for the data socket. */ protected void cleanup() { _cleanup(); } /* * * The methods below are here for obfuscation purposes. * */ private void _doTransfer() throws FTPException { //Socket s = null; OutputStream output = null; PrintWriter writer = null; boolean debug = GTOverride.getBoolean("glub.debug"); if ((input == null && reader == null) || (sock == null && servsock == null)) { return; } try { if (sock == null) { sock = servsock.accept(); Util.close( servsock ); servsock = null; } output = sock.getOutputStream(); if ( zLibCompressed ) { output = new DeflaterOutputStream( output, new Deflater(), 1024 ); } long nbytes = startsize; if (progress != null) progress.startProgress(); if (input != null) { byte[] b = new byte[1024]; boolean wroteData = false; int len = 0; while ((len = input.read( b )) >= 0) { output.write( b, 0, len ); wroteData = true; nbytes += len; if (progress != null) progress.updateProgress( nbytes, filesize ); } // there seems to be a bug where an empty file that doesn't write // anything to the stream causes an exception, so write nothing if (!wroteData) { output.write( new byte[1], 0, 0 ); } output.flush(); if ( output instanceof DeflaterOutputStream ) { ((DeflaterOutputStream)output).finish(); } } else { String line = null; OutputStreamWriter osw = null; if ( encoding != null ) osw = new OutputStreamWriter( output, encoding ); else osw = new OutputStreamWriter( output ); writer = new PrintWriter( new BufferedWriter( osw ) ); if ( debug ) { System.out.println( "Output Encoding = " + osw.getEncoding() ); } while ((line = reader.readLine()) != null) { writer.print( line + "\r\n" ); // no println, writing to remote system nbytes += (line.length() + 1); if (progress != null) progress.updateProgress( nbytes, filesize ); } writer.flush(); if ( output instanceof DeflaterOutputStream ) { ((DeflaterOutputStream)output).finish(); } } if (progress != null) progress.finishProgress(); } catch (IOException ioe) { if ( aborted ) { throw new FTPAbortException( "ABOR command successful." ); } else { throw new FTPException( ioe.getMessage() ); } } finally { if ( !aborted ) { cleanup(); } else { while ( waitForAbort ) { try { Thread.sleep(100); //System.out.println("waiting for abort"); } catch ( InterruptedException ie ) { //ie.printStackTrace(); } } cleanup(); throw new FTPAbortException( "ABOR command successful." ); } } } private void _abortSockets() { // wait 10 seconds just in case the server doesn't drop you... try { Thread.sleep(10000); } catch ( InterruptedException ie ) { //ie.printStackTrace(); } Util.close( sock ); Util.close( servsock ); } private void _cleanup() { Util.close( input ); Util.close( output ); Util.close( reader ); Util.close( writer ); Util.close( sock ); Util.close( servsock ); } }