Package com.enterprisedt.net.ftp

Source Code of com.enterprisedt.net.ftp.FTPClient

/**
*
*  Java FTP client library.
*
*  Copyright (C) 2000-2003  Enterprise Distributed Technologies Ltd
*
*  www.enterprisedt.com
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library 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
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*  Bug fixes, suggestions and comments should be sent to bruce@enterprisedt.com
*
*  Change Log:
*
*        $Log: FTPClient.java,v $
*        Revision 1.1.1.1  2005/06/23 15:23:01  smontoro
*        hipergate backend
*
*        Revision 1.1  2004/02/07 03:15:20  hipergate
*        v2.0 pre-alpha
*
*        Revision 1.6  2003/05/31 14:53:44  bruceb
*        1.2.2 changes
*
*        Revision 1.5  2003/01/29 22:46:08  bruceb
*        minor changes
*
*        Revision 1.4  2002/11/19 22:01:25  bruceb
*        changes for 1.2
*
*        Revision 1.3  2001/10/09 20:53:46  bruceb
*        Active mode changes
*
*        Revision 1.1  2001/10/05 14:42:03  bruceb
*        moved from old project
*
*/

package com.enterprisedt.net.ftp;

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.File;

import java.text.SimpleDateFormat;
import java.text.ParsePosition;

import java.net.InetAddress;
import java.util.Date;
import java.util.Vector;
import java.util.Properties;

/**
*  Supports client-side FTP. Most common
*  FTP operations are present in this class.
*
@author      Bruce Blackshaw
@version     $Revision: 1.1.1.1 $
*
*/
public class FTPClient {

    /**
     *  Revision control id
     */
    private static String cvsId = "@(#)$Id: FTPClient.java,v 1.1.1.1 2005/06/23 15:23:01 smontoro Exp $";

    /**
     *  Format to interpret MTDM timestamp
     */
    private SimpleDateFormat tsFormat =
        new SimpleDateFormat("yyyyMMddHHmmss");

    /**
     *  Socket responsible for controlling
     *  the connection
     */
    private FTPControlSocket control = null;

    /**
     *  Socket responsible for transferring
     *  the data
     */
    private FTPDataSocket data = null;

    /**
     *  Socket timeout for both data and control. In
     *  milliseconds
     */
    private int timeout = 0;

    /**
     *  Record of the transfer type - make the default ASCII
     */
    private FTPTransferType transferType = FTPTransferType.ASCII;

    /**
     *  Record of the connect mode - make the default PASV (as this was
     *  the original mode supported)
     */
    private FTPConnectMode connectMode = FTPConnectMode.PASV;

    /**
     *  Holds the last valid reply from the server on the control socket
     */
    private FTPReply lastValidReply;

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteHost  the remote hostname
     */
    public FTPClient(String remoteHost)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteHost,
                                       FTPControlSocket.CONTROL_PORT,
                                       null, 0);
    }

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteHost  the remote hostname
     *  @param   controlPort  port for control stream
     */
    public FTPClient(String remoteHost, int controlPort)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteHost, controlPort, null, 0);
    }

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteAddr  the address of the
     *                       remote host
     */
    public FTPClient(InetAddress remoteAddr)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteAddr,
                                       FTPControlSocket.CONTROL_PORT,
                                       null, 0);
    }

    /**
     *  Constructor. Creates the control
     *  socket. Allows setting of control port (normally
     *  set by default to 21).
     *
     *  @param   remoteAddr  the address of the
     *                       remote host
     *  @param   controlPort  port for control stream
     */
    public FTPClient(InetAddress remoteAddr, int controlPort)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteAddr, controlPort,
                                       null, 0);
    }

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteHost  the remote hostname
     *  @param  millis       the length of the timeout, in milliseconds
     */
    public FTPClient(String remoteHost, PrintWriter log, int timeout)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteHost,
                                       FTPControlSocket.CONTROL_PORT,
                                       log, timeout);
    }

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteHost  the remote hostname
     *  @param   controlPort  port for control stream
     *  @param  millis       the length of the timeout, in milliseconds
     */
    public FTPClient(String remoteHost, int controlPort,
                     PrintWriter log, int timeout)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteHost, controlPort,
                                       log, timeout);
    }

    /**
     *  Constructor. Creates the control
     *  socket
     *
     *  @param   remoteAddr  the address of the
     *                       remote host
     *  @param  millis       the length of the timeout, in milliseconds
     */
    public FTPClient(InetAddress remoteAddr, PrintWriter log,
                     int timeout)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteAddr,
                                       FTPControlSocket.CONTROL_PORT,
                                       log, timeout);
    }

    /**
     *  Constructor. Creates the control
     *  socket. Allows setting of control port (normally
     *  set by default to 21).
     *
     *  @param   remoteAddr  the address of the
     *                       remote host
     *  @param   controlPort port for control stream
     *  @param  millis       the length of the timeout, in milliseconds
     */
    public FTPClient(InetAddress remoteAddr, int controlPort,
                     PrintWriter log, int timeout)
        throws IOException, FTPException {

        control = new FTPControlSocket(remoteAddr, controlPort,
                                       log, timeout);
    }

    /**
     *   Set the TCP timeout on the underlying socket.
     *
     *   If a timeout is set, then any operation which
     *   takes longer than the timeout value will be
     *   killed with a java.io.InterruptedException. We
     *   set both the control and data connections
     *
     *   @param millis The length of the timeout, in milliseconds
     */
    public void setTimeout(int millis)
        throws IOException {

        this.timeout = millis;
        control.setTimeout(millis);
    }

    /**
     *  Set the connect mode
     *
     *  @param  mode  ACTIVE or PASV mode
     */
    public void setConnectMode(FTPConnectMode mode) {
        connectMode = mode;
    }

    /**
     *  Login into an account on the FTP server. This
     *  call completes the entire login process
     *
     *  @param   user       user name
     *  @param   password   user's password
     */
    public void login(String user, String password)
        throws IOException, FTPException {

        String response = control.sendCommand("USER " + user);
        lastValidReply = control.validateReply(response, "331");
        response = control.sendCommand("PASS " + password);
        lastValidReply = control.validateReply(response, "230");
    }


    /**
     *  Supply the user name to log into an account
     *  on the FTP server. Must be followed by the
     *  password() method - but we allow for
     *
     *  @param   user       user name
     *  @param   password   user's password
     */
    public void user(String user)
        throws IOException, FTPException {

        String reply = control.sendCommand("USER " + user);

        // we allow for a site with no password - 230 response
        String[] validCodes = {"230", "331"};
        lastValidReply = control.validateReply(reply, validCodes);
    }


    /**
     *  Supplies the password for a previously supplied
     *  username to log into the FTP server. Must be
     *  preceeded by the user() method
     *
     *  @param   user       user name
     *  @param   password   user's password
     */
    public void password(String password)
        throws IOException, FTPException {

        String reply = control.sendCommand("PASS " + password);

        // we allow for a site with no passwords (202)
        String[] validCodes = {"230", "202"};
        lastValidReply = control.validateReply(reply, validCodes);
    }

    /**
     *  Set up SOCKS v4/v5 proxy settings. This can be used if there
     *  is a SOCKS proxy server in place that must be connected thru.
     *  Note that setting these properties directs <b>all</b> TCP
     *  sockets in this JVM to the SOCKS proxy
     *
     *  @param  port  SOCKS proxy port
     *  @param  host  SOCKS proxy hostname
     */
    public static void initSOCKS(String port, String host) {
        Properties props = System.getProperties();
        props.put("socksProxyPort", port);
        props.put("socksProxyHost", host);
        System.setProperties(props);
    }

    /**
     *  Set up SOCKS username and password for SOCKS username/password
     *  authentication. Often, no authentication will be required
     *  but the SOCKS server may be configured to request these.
     *
     *  @param  username   the SOCKS username
     *  @param  password   the SOCKS password
     */
    public static void initSOCKSAuthentication(String username,
                                               String password) {
        Properties props = System.getProperties();
        props.put("java.net.socks.username", username);
        props.put("java.net.socks.password", password);
        System.setProperties(props);
    }

    /**
     *  Get the name of the remote host
     *
     *  @return  remote host name
     */
    String getRemoteHostName() {
        return control.getRemoteHostName();
    }


    /**
     *  Issue arbitrary ftp commands to the FTP server.
     *
     *  @param command     ftp command to be sent to server
     *  @param validCodes  valid return codes for this command
     */
    public void quote(String command, String[] validCodes)
        throws IOException, FTPException {

        String reply = control.sendCommand(command);

        // allow for no validation to be supplied
        if (validCodes != null && validCodes.length > 0)
            lastValidReply = control.validateReply(reply, validCodes);
    }


    /**
     *  Put a local file onto the FTP server. It
     *  is placed in the current directory.
     *
     *  @param  localPath   path of the local file
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public void put(String localPath, String remoteFile)
        throws IOException, FTPException {

        put(localPath, remoteFile, false);
    }

    /**
     *  Put a stream of data onto the FTP server. It
     *  is placed in the current directory.
     *
     *  @param  srcStream   input stream of data to put
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public void put(InputStream srcStream, String remoteFile)
        throws IOException, FTPException {

        put(srcStream, remoteFile, false);
    }


    /**
     *  Put a local file onto the FTP server. It
     *  is placed in the current directory. Allows appending
     *  if current file exists
     *
     *  @param  localPath   path of the local file
     *  @param  remoteFile  name of remote file in
     *                      current directory
     *  @param  append      true if appending, false otherwise
     */
    public void put(String localPath, String remoteFile,
                    boolean append)
        throws IOException, FTPException {

        // get according to set type
        if (getType() == FTPTransferType.ASCII) {
            putASCII(localPath, remoteFile, append);
        }
        else {
            putBinary(localPath, remoteFile, append);
        }
        validateTransfer();
     }

    /**
     *  Put a stream of data onto the FTP server. It
     *  is placed in the current directory. Allows appending
     *  if current file exists
     *
     *  @param  srcStream   input stream of data to put
     *  @param  remoteFile  name of remote file in
     *                      current directory
     *  @param  append      true if appending, false otherwise
     */
    public void put(InputStream srcStream, String remoteFile,
                    boolean append)
        throws IOException, FTPException {

        // get according to set type
        if (getType() == FTPTransferType.ASCII) {
            putASCII(srcStream, remoteFile, append);
        }
        else {
            putBinary(srcStream, remoteFile, append);
        }
        validateTransfer();
    }

    /**
     *  Validate that the put() or get() was successful
     */
    private void validateTransfer()
        throws IOException, FTPException {

        // check the control response
        String[] validCodes = {"226", "250"};
        String reply = control.readReply();
        lastValidReply = control.validateReply(reply, validCodes);
    }

    /**
     *  Request the server to set up the put
     *
     *  @param  remoteFile  name of remote file in
     *                      current directory
     *  @param  append      true if appending, false otherwise
     */
    private void initPut(String remoteFile, boolean append)
        throws IOException, FTPException {

        // set up data channel
        data = control.createDataSocket(connectMode);
        data.setTimeout(timeout);

        // send the command to store
        String cmd = append ? "APPE " : "STOR ";
        String reply = control.sendCommand(cmd + remoteFile);

        // Can get a 125 or a 150
        String[] validCodes = {"125", "150"};
        lastValidReply = control.validateReply(reply, validCodes);
    }


    /**
     *  Put as ASCII, i.e. read a line at a time and write
     *  inserting the correct FTP separator
     *
     *  @param localPath   full path of local file to read from
     *  @param remoteFile  name of remote file we are writing to
     *  @param  append      true if appending, false otherwise
     */
    private void putASCII(String localPath, String remoteFile, boolean append)
        throws IOException, FTPException {

        // create an inputstream & pass to common method
        InputStream srcStream = new FileInputStream(localPath);
        putASCII(srcStream, remoteFile, append);
    }

    /**
     *  Put as ASCII, i.e. read a line at a time and write
     *  inserting the correct FTP separator
     *
     *  @param  srcStream   input stream of data to put
     *  @param  remoteFile  name of remote file we are writing to
     *  @param  append      true if appending, false otherwise
     */
    private void putASCII(InputStream srcStream, String remoteFile,
                          boolean append)
        throws IOException, FTPException {

        // need to read line by line ...
        LineNumberReader in
            = new LineNumberReader(new InputStreamReader(srcStream));

        initPut(remoteFile, append);

        // get an character output stream to write to ... AFTER we
        // have the ok to go ahead AND AFTER we've successfully opened a
        // stream for the local file
        BufferedWriter out =
            new BufferedWriter(
                new OutputStreamWriter(data.getOutputStream()));

        // write line by line, writing \r\n as required by RFC959 after
        // each line
        String line = null;
        while ((line = in.readLine()) != null) {
            out.write(line, 0, line.length());
            out.write(FTPControlSocket.EOL, 0, FTPControlSocket.EOL.length());
        }
        in.close();
        out.flush();
        out.close();

        // and close the data socket
        try {
            data.close();
        }
        catch (IOException ignore) {}
    }


    /**
     *  Put as binary, i.e. read and write raw bytes
     *
     *  @param localPath   full path of local file to read from
     *  @param remoteFile  name of remote file we are writing to
     *  @param  append      true if appending, false otherwise
     */
    private void putBinary(String localPath, String remoteFile,
                           boolean append)
        throws IOException, FTPException {

        // open input stream to read source file ... do this
        // BEFORE opening output stream to server, so if file not
        // found, an exception is thrown
        InputStream srcStream = new FileInputStream(localPath);
        putBinary(srcStream, remoteFile, append);
    }

    /**
     *  Put as binary, i.e. read and write raw bytes
     *
     *  @param  srcStream   input stream of data to put
     *  @param  remoteFile  name of remote file we are writing to
     *  @param  append      true if appending, false otherwise
     */
    private void putBinary(InputStream srcStream, String remoteFile,
                           boolean append)
        throws IOException, FTPException {

        BufferedInputStream in =
            new BufferedInputStream(srcStream);

        initPut(remoteFile, append);

        // get an output stream
        BufferedOutputStream out =
            new BufferedOutputStream(
                new DataOutputStream(data.getOutputStream()));

        byte[] buf = new byte[512];

        // read a chunk at a time and write to the data socket
        long size = 0;
        int count = 0;
        while ((count = in.read(buf)) > 0) {
            out.write(buf, 0, count);
            size += count;
        }
       
        in.close();

        // flush and clean up
        out.flush();
        out.close();

        // and close the data socket
        try {
            data.close();
        }
        catch (IOException ignore) {}
       
    // log bytes transferred
    control.log("Transferred " + size + " bytes to remote host");
    }


    /**
     *  Put data onto the FTP server. It
     *  is placed in the current directory.
     *
     *  @param  data        array of bytes
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public void put(byte[] bytes, String remoteFile)
        throws IOException, FTPException {

        put(bytes, remoteFile, false);
    }

    /**
     *  Put data onto the FTP server. It
     *  is placed in the current directory. Allows
     *  appending if current file exists
     *
     *  @param  data        array of bytes
     *  @param  remoteFile  name of remote file in
     *                      current directory
     *  @param  append      true if appending, false otherwise
     */
    public void put(byte[] bytes, String remoteFile, boolean append)
        throws IOException, FTPException {

        initPut(remoteFile, append);

        // get an output stream
        BufferedOutputStream out =
            new BufferedOutputStream(
                new DataOutputStream(data.getOutputStream()));

        // write array
        out.write(bytes, 0, bytes.length);

        // flush and clean up
        out.flush();
        out.close();

        // and close the data socket
        try {
            data.close();
        }
        catch (IOException ignore) {}

        validateTransfer();
    }


    /**
     *  Get data from the FTP server. Uses the currently
     *  set transfer mode.
     *
     *  @param  localPath   local file to put data in
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public void get(String localPath, String remoteFile)
        throws IOException, FTPException {

        // get according to set type
        if (getType() == FTPTransferType.ASCII) {
            getASCII(localPath, remoteFile);
        }
        else {
            getBinary(localPath, remoteFile);
        }
        validateTransfer();
    }

    /**
     *  Get data from the FTP server. Uses the currently
     *  set transfer mode.
     *
     *  @param  destStream  data stream to write data to
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public void get(OutputStream destStream, String remoteFile)
        throws IOException, FTPException {

        // get according to set type
        if (getType() == FTPTransferType.ASCII) {
            getASCII(destStream, remoteFile);
        }
        else {
            getBinary(destStream, remoteFile);
        }
        validateTransfer();
    }


    /**
     *  Request to the server that the get is set up
     *
     *  @param  remoteFile  name of remote file
     */
    private void initGet(String remoteFile)
        throws IOException, FTPException {

        // set up data channel
        data = control.createDataSocket(connectMode);
        data.setTimeout(timeout);

        // send the retrieve command
        String reply = control.sendCommand("RETR " + remoteFile);

        // Can get a 125 or a 150
        String[] validCodes1 = {"125", "150"};
        lastValidReply = control.validateReply(reply, validCodes1);
    }


    /**
     *  Get as ASCII, i.e. read a line at a time and write
     *  using the correct newline separator for the OS
     *
     *  @param localPath   full path of local file to write to
     *  @param remoteFile  name of remote file
     */
    private void getASCII(String localPath, String remoteFile)
        throws IOException, FTPException {

        // B.McKeown:
        // Call initGet() before creating the FileOutputStream.
        // This will prevent being left with an empty file if a FTPException
        // is thrown by initGet().
        initGet(remoteFile);

        // B. McKeown: Need to store the local file name so the file can be
        // deleted if necessary.
        File localFile = new File(localPath);

        // create the buffered stream for writing
        BufferedWriter out =
            new BufferedWriter(
                new FileWriter(localPath));

        // get an character input stream to read data from ... AFTER we
        // have the ok to go ahead AND AFTER we've successfully opened a
        // stream for the local file
        LineNumberReader in =
            new LineNumberReader(
                new InputStreamReader(data.getInputStream()));

        // B. McKeown:
        // If we are in active mode we have to set the timeout of the passive
        // socket. We can achieve this by calling setTimeout() again.
        // If we are in passive mode then we are merely setting the value twice
        // which does no harm anyway. Doing this simplifies any logic changes.
        data.setTimeout(timeout);

        // read/write a line at a time
        IOException storedEx = null;
        String line = null;
        try {
            while ((line = in.readLine()) != null) {
                out.write(line, 0, line.length());
                out.newLine();
            }
        }
        catch (IOException ex) {
            storedEx = ex;
            localFile.delete();
        }
        finally {
            out.close();
        }

        try {
            in.close();
            data.close();
        }
        catch (IOException ignore) {}

        // if we failed to write the file, rethrow the exception
        if (storedEx != null)
            throw storedEx;
    }

    /**
     *  Get as ASCII, i.e. read a line at a time and write
     *  using the correct newline separator for the OS
     *
     *  @param destStream  data stream to write data to
     *  @param remoteFile  name of remote file
     */
    private void getASCII(OutputStream destStream, String remoteFile)
        throws IOException, FTPException {

        initGet(remoteFile);

        // create the buffered stream for writing
        BufferedWriter out =
            new BufferedWriter(
                new OutputStreamWriter(destStream));

        // get an character input stream to read data from ... AFTER we
        // have the ok to go ahead
        LineNumberReader in =
            new LineNumberReader(
                new InputStreamReader(data.getInputStream()));

        // B. McKeown:
        // If we are in active mode we have to set the timeout of the passive
        // socket. We can achieve this by calling setTimeout() again.
        // If we are in passive mode then we are merely setting the value twice
        // which does no harm anyway. Doing this simplifies any logic changes.
        data.setTimeout(timeout);

        // read/write a line at a time
        IOException storedEx = null;
        String line = null;
        try {
            while ((line = in.readLine()) != null) {
                out.write(line, 0, line.length());
                out.newLine();
            }
        }
        catch (IOException ex) {
            storedEx = ex;
        }
        finally {
            out.close();
        }

        try {
            in.close();
            data.close();
        }
        catch (IOException ignore) {}

        // if we failed to write the file, rethrow the exception
        if (storedEx != null)
            throw storedEx;
    }


    /**
     *  Get as binary file, i.e. straight transfer of data
     *
     *  @param localPath   full path of local file to write to
     *  @param remoteFile  name of remote file
     */
    private void getBinary(String localPath, String remoteFile)
        throws IOException, FTPException {

        // B.McKeown:
        // Call initGet() before creating the FileOutputStream.
        // This will prevent being left with an empty file if a FTPException
        // is thrown by initGet().
        initGet(remoteFile);

        // B. McKeown: Need to store the local file name so the file can be
        // deleted if necessary.
        File localFile = new File(localPath);

        // create the buffered output stream for writing the file
        BufferedOutputStream out =
            new BufferedOutputStream(
                new FileOutputStream(localPath, false));

        // get an input stream to read data from ... AFTER we have
        // the ok to go ahead AND AFTER we've successfully opened a
        // stream for the local file
        BufferedInputStream in =
            new BufferedInputStream(
                new DataInputStream(data.getInputStream()));

        // B. McKeown:
        // If we are in active mode we have to set the timeout of the passive
        // socket. We can achieve this by calling setTimeout() again.
        // If we are in passive mode then we are merely setting the value twice
        // which does no harm anyway. Doing this simplifies any logic changes.
        data.setTimeout(timeout);

        // do the retrieving
        long size = 0;
        int chunksize = 4096;
        byte [] chunk = new byte[chunksize];
        int count;
        IOException storedEx = null;

        // read from socket & write to file in chunks
        try {
            while ((count = in.read(chunk, 0, chunksize)) >= 0) {
                out.write(chunk, 0, count);
                size += count;
            }
        }
        catch (IOException ex) {
            storedEx = ex;
            localFile.delete();
        }
        finally {
            out.close();
        }

        // close streams
        try {
            in.close();
            data.close();
        }
        catch (IOException ignore) {}

        // if we failed to write the file, rethrow the exception
        if (storedEx != null)
            throw storedEx;
           
      // log bytes transferred
      control.log("Transferred " + size + " bytes from remote host");
    }

    /**
     *  Get as binary file, i.e. straight transfer of data
     *
     *  @param destStream  stream to write to
     *  @param remoteFile  name of remote file
     */
    private void getBinary(OutputStream destStream, String remoteFile)
        throws IOException, FTPException {

        initGet(remoteFile);

        // create the buffered output stream for writing the file
        BufferedOutputStream out =
            new BufferedOutputStream(destStream);

        // get an input stream to read data from ... AFTER we have
        // the ok to go ahead AND AFTER we've successfully opened a
        // stream for the local file
        BufferedInputStream in =
            new BufferedInputStream(
                new DataInputStream(data.getInputStream()));

        // B. McKeown:
        // If we are in active mode we have to set the timeout of the passive
        // socket. We can achieve this by calling setTimeout() again.
        // If we are in passive mode then we are merely setting the value twice
        // which does no harm anyway. Doing this simplifies any logic changes.
        data.setTimeout(timeout);

        // do the retrieving
    long size = 0;
        int chunksize = 4096;
        byte [] chunk = new byte[chunksize];
        int count;
        IOException storedEx = null;

        // read from socket & write to file in chunks
        try {
            while ((count = in.read(chunk, 0, chunksize)) >= 0) {
                out.write(chunk, 0, count);
        size += count;
            }
        }
        catch (IOException ex) {
            storedEx = ex;
        }
        finally {
            out.close();
        }

        // close streams
        try {
            in.close();
            data.close();
        }
        catch (IOException ignore) {}

        // if we failed to write to the stream, rethrow the exception
        if (storedEx != null)
            throw storedEx;
           
    // log bytes transferred
    control.log("Transferred " + size + " bytes from remote host");           
    }


    /**
     *  Get data from the FTP server. Transfers in
     *  whatever mode we are in. Retrieve as a byte array. Note
     *  that we may experience memory limitations as the
     *  entire file must be held in memory at one time.
     *
     *  @param  remoteFile  name of remote file in
     *                      current directory
     */
    public byte[] get(String remoteFile)
        throws IOException, FTPException {

        initGet(remoteFile);

        // get an input stream to read data from
        BufferedInputStream in =
            new BufferedInputStream(
                new DataInputStream(data.getInputStream()));

        // B. McKeown:
        // If we are in active mode we have to set the timeout of the passive
        // socket. We can achieve this by calling setTimeout() again.
        // If we are in passive mode then we are merely setting the value twice
        // which does no harm anyway. Doing this simplifies any logic changes.
        data.setTimeout(timeout);

        // do the retrieving
        int chunksize = 4096;
        byte [] chunk = new byte[chunksize]// read chunks into
        byte [] resultBuf = null; // where we place result
        ByteArrayOutputStream temp =
            new ByteArrayOutputStream(chunksize); // temp swap buffer
        int count;  // size of chunk read

        // read from socket & write to file
        while ((count = in.read(chunk, 0, chunksize)) >= 0) {
            temp.write(chunk, 0, count);
        }
        temp.close();

        // get the bytes from the temp buffer
        resultBuf = temp.toByteArray();

        // close streams
        try {
            in.close();
            data.close();
        }
        catch (IOException ignore) {}
       
        validateTransfer();

        return resultBuf;
    }


    /**
     *  Run a site-specific command on the
     *  server. Support for commands is dependent
     *  on the server
     *
     *  @param  command   the site command to run
     *  @return true if command ok, false if
     *          command not implemented
     */
    public boolean site(String command)
        throws IOException, FTPException {

        // send the retrieve command
        String reply = control.sendCommand("SITE " + command);

        // Can get a 200 (ok) or 202 (not impl). Some
        // FTP servers return 502 (not impl)
        String[] validCodes = {"200", "202", "502"};
        lastValidReply = control.validateReply(reply, validCodes);

        // return true or false? 200 is ok, 202/502 not
        // implemented
        if (reply.substring(0, 3).equals("200"))
            return true;
        else
            return false;
    }


    /**
     *  List a directory's contents
     *
     *  @param  dirname  the name of the directory (<b>not</b> a file mask)
     *  @return a string containing the line separated
     *          directory listing
     *  @deprecated  As of FTP 1.1, replaced by {@link #dir(String)}
     */
    public String list(String dirname)
        throws IOException, FTPException {

        return list(dirname, false);
    }


    /**
     *  List a directory's contents as one string. A detailed
     *  listing is available, otherwise just filenames are provided.
     *  The detailed listing varies in details depending on OS and
     *  FTP server.
     *
     *  @param  dirname  the name of the directory(<b>not</b> a file mask)
     *  @param  full     true if detailed listing required
     *                   false otherwise
     *  @return a string containing the line separated
     *          directory listing
     *  @deprecated  As of FTP 1.1, replaced by {@link #dir(String,boolean)}
     */
    public String list(String dirname, boolean full)
        throws IOException, FTPException {

        String[] list = dir(dirname, full);

        StringBuffer result = new StringBuffer();
        String sep = System.getProperty("line.separator");

        // loop thru results and make into one string
        for (int i = 0; i < list.length; i++) {
            result.append(list[i]);
            result.append(sep);
        }

        return result.toString();
    }

    /**
     *  List current directory's contents as an array of strings of
     *  filenames.
     *
     *  @return  an array of current directory listing strings
     */
    public String[] dir()
        throws IOException, FTPException {

        return dir(null, false);
    }

    /**
     *  List a directory's contents as an array of strings of filenames.
     *
     *  @param   dirname  name of directory(<b>not</b> a file mask)
     *  @return  an array of directory listing strings
     */
    public String[] dir(String dirname)
        throws IOException, FTPException {

        return dir(dirname, false);
    }


    /**
     *  List a directory's contents as an array of strings. A detailed
     *  listing is available, otherwise just filenames are provided.
     *  The detailed listing varies in details depending on OS and
     *  FTP server. Note that a full listing can be used on a file
     *  name to obtain information about a file
     *
     *  @param  dirname  name of directory (<b>not</b> a file mask)
     *  @param  full     true if detailed listing required
     *                   false otherwise
     *  @return  an array of directory listing strings
     */
    public String[] dir(String dirname, boolean full)
        throws IOException, FTPException {

        // set up data channel
        data = control.createDataSocket(connectMode);
        data.setTimeout(timeout);

        // send the retrieve command
        String command = full ? "LIST ":"NLST ";
        if (dirname != null)
            command += dirname;

        // some FTP servers bomb out if NLST has whitespace appended
        command = command.trim();
        String reply = control.sendCommand(command);

        // check the control response. wu-ftp returns 550 if the
        // directory is empty, so we handle 550 appropriately. Similarly
        // proFTPD returns 450
        String[] validCodes1 = {"125", "150", "450", "550"};
        lastValidReply = control.validateReply(reply, validCodes1)

        // an empty array of files for 450/550
        String[] result = new String[0];

        // a normal reply ... extract the file list
        String replyCode = lastValidReply.getReplyCode();
        if (!replyCode.equals("450") && !replyCode.equals("550")) {
            // get an character input stream to read data from .
            LineNumberReader in =
                new LineNumberReader(
                     new InputStreamReader(data.getInputStream()));

            // read a line at a time
            Vector lines = new Vector();   
            String line = null;
            while ((line = in.readLine()) != null) {
                lines.add(line);
            }       
            try {
                in.close();
                data.close();
            }
            catch (IOException ignore) {}
               
            // check the control response
            String[] validCodes2 = {"226", "250"};
            reply = control.readReply();
            lastValidReply = control.validateReply(reply, validCodes2);

            // empty array is default
            if (!lines.isEmpty())
                result = (String[])lines.toArray(result);
        }
        return result;
    }

    /**
     *  Gets the latest valid reply from the server
     *
     *  @return  reply object encapsulating last valid server response
     */
    public FTPReply getLastValidReply() {
        return lastValidReply;
    }


    /**
     *  Switch debug of responses on or off
     *
     *  @param  on  true if you wish to have responses to
     *              the log stream, false otherwise
     */
    public void debugResponses(boolean on) {
        control.debugResponses(on);
    }

     /**
      *  Set the logging stream, replacing
      *  stdout
      *
      *  @param log  the new logging stream
      */
     public void setLogStream(PrintWriter log) {
         control.setLogStream(log);        
     }

    /**
     *  Get the current transfer type
     *
     *  @return  the current type of the transfer,
     *           i.e. BINARY or ASCII
     */
    public FTPTransferType getType() {
        return transferType;
    }

    /**
     *  Set the transfer type
     *
     *  @param  type  the transfer type to
     *                set the server to
     */
    public void setType(FTPTransferType type)
        throws IOException, FTPException {

        // determine the character to send
        String typeStr = FTPTransferType.ASCII_CHAR;
        if (type.equals(FTPTransferType.BINARY))
            typeStr = FTPTransferType.BINARY_CHAR;

        // send the command
        String reply = control.sendCommand("TYPE " + typeStr);
        lastValidReply = control.validateReply(reply, "200");

        // record the type
        transferType = type;
    }


    /**
     *  Delete the specified remote file
     *
     *  @param  remoteFile  name of remote file to
     *                      delete
     */
    public void delete(String remoteFile)
        throws IOException, FTPException {

        String reply = control.sendCommand("DELE " + remoteFile);
        lastValidReply = control.validateReply(reply, "250");
    }


    /**
     *  Rename a file or directory
     *
     * @param from  name of file or directory to rename
     * @param to    intended name
     */
    public void rename(String from, String to)
        throws IOException, FTPException {

        String reply = control.sendCommand("RNFR " + from);
        lastValidReply = control.validateReply(reply, "350");

        reply = control.sendCommand("RNTO " + to);
        lastValidReply = control.validateReply(reply, "250");
    }


    /**
     *  Delete the specified remote working directory
     *
     *  @param  dir  name of remote directory to
     *               delete
     */
    public void rmdir(String dir)
        throws IOException, FTPException {

        String reply = control.sendCommand("RMD " + dir);

        // some servers return 257, technically incorrect but
        // we cater for it ...
        String[] validCodes = {"250", "257"};
        lastValidReply = control.validateReply(reply, validCodes);
    }


    /**
     *  Create the specified remote working directory
     *
     *  @param  dir  name of remote directory to
     *               create
     */
    public void mkdir(String dir)
        throws IOException, FTPException {

        String reply = control.sendCommand("MKD " + dir);
        lastValidReply = control.validateReply(reply, "257");
    }


    /**
     *  Change the remote working directory to
     *  that supplied
     *
     *  @param  dir  name of remote directory to
     *               change to
     */
    public void chdir(String dir)
        throws IOException, FTPException {

        String reply = control.sendCommand("CWD " + dir);
        lastValidReply = control.validateReply(reply, "250");
    }

    /**
     *  Get modification time for a remote file
     *
     *  @param    remoteFile   name of remote file
     *  @return   modification time of file as a date
     */
    public Date modtime(String remoteFile)
        throws IOException, FTPException {

        String reply = control.sendCommand("MDTM " + remoteFile);
        lastValidReply = control.validateReply(reply, "213");

        // parse the reply string ...
        Date ts = tsFormat.parse(lastValidReply.getReplyText(),
                                 new ParsePosition(0));
        return ts;
    }

    /**
     *  Get the current remote working directory
     *
     *  @return   the current working directory
     */
    public String pwd()
        throws IOException, FTPException {

        String reply = control.sendCommand("PWD");
        lastValidReply = control.validateReply(reply, "257");

        // get the reply text and extract the dir
        // listed in quotes, if we can find it. Otherwise
        // just return the whole reply string
        String text = lastValidReply.getReplyText();
        int start = text.indexOf('"');
        int end = text.lastIndexOf('"');
        if (start >= 0 && end > start)
            return text.substring(start+1, end);
        else
            return text;
    }

    /**
     *  Get the type of the OS at the server
     *
     *  @return   the type of server OS
     */
    public String system()
        throws IOException, FTPException {

        String reply = control.sendCommand("SYST");
        lastValidReply = control.validateReply(reply, "215");
        return lastValidReply.getReplyText();
    }

    /**
     *  Get the help text for the specified command
     *
     *  @param  command  name of the command to get help on
     *  @return help text from the server for the supplied command
     */
    public String help(String command)
        throws IOException, FTPException {

        String reply = control.sendCommand("HELP " + command);
        String[] validCodes = {"211", "214"};
        lastValidReply = control.validateReply(reply, validCodes);
        return lastValidReply.getReplyText();
    }

    /**
     *  Quit the FTP session
     *
     */
    public void quit()
        throws IOException, FTPException {

        try {
            String reply = control.sendCommand("QUIT");
            String[] validCodes = {"221", "226"};
            lastValidReply = control.validateReply(reply, validCodes);
        }
        finally { // ensure we clean up the connection
            control.logout();
            control = null;
        }
    }

}



TOP

Related Classes of com.enterprisedt.net.ftp.FTPClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.