/*
* ftp4j - A pure Java FTP client library
*
* Copyright (C) 2008-2010 Carlo Pelliccia (www.sauronsoftware.it)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version
* 2.1, as published by the Free Software Foundation.
*
* 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 Lesser General Public License 2.1 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License version 2.1 along with this program.
* If not, see
* client.rename("oldname", "newname"); // This one renames ** *
* client.rename("the/old/path/oldname", "/a/new/path/newname"); // This one moves ** * @param oldPath * The current path of the file (or directory). * @param newPath * The new path for the file (or directory). * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public void rename(String oldPath, String newPath) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the RNFR command. communication.sendFTPCommand("RNFR " + oldPath); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 350) { throw new FTPException(r); } // Sends the RNFR command. communication.sendFTPCommand("RNTO " + newPath); r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } } } /** * This method deletes a remote file. * * @param path * The path to the file. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public void deleteFile(String path) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the DELE command. communication.sendFTPCommand("DELE " + path); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } } } /** * This method deletes a remote directory. * * @param path * The path to the directory. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public void deleteDirectory(String path) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the RMD command. communication.sendFTPCommand("RMD " + path); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } } } /** * This method creates a new remote directory in the current working one. * * @param directoryName * The name of the new directory. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public void createDirectory(String directoryName) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the MKD command. communication.sendFTPCommand("MKD " + directoryName); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } } } /** * This method calls the HELP command on the remote server, returning a list * of lines with the help contents. * * @return The help contents, splitted by line. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public String[] help() throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the HELP command. communication.sendFTPCommand("HELP"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } return r.getMessages(); } } /** * This method returns the remote server status, as the result of a FTP STAT * command. * * @return The remote server status, splitted by line. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. */ public String[] serverStatus() throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Sends the STAT command. communication.sendFTPCommand("STAT"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } return r.getMessages(); } } /** * This method lists the entries of the current working directory parsing * the reply to a FTP LIST command. * * The response to the LIST command is parsed through the FTPListParser * objects registered on the client. The distribution of ftp4j contains some * standard parsers already registered on every FTPClient object created. If * they don't work in your case (a FTPListParseException is thrown), you can * build your own parser implementing the FTPListParser interface and add it * to the client by calling its addListParser() method. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The list() method will break with a * FTPAbortedException. * * @param fileSpec * A file filter string. Depending on the server implementation, * wildcard characters could be accepted. * @return The list of the files (and directories) in the current working * directory. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @throws FTPListParseException * If none of the registered parsers can handle the response * sent by the server. * @see FTPListParser * @see FTPClient#addListParser(FTPListParser) * @see FTPClient#getListParsers() * @see FTPClient#abortCurrentDataTransfer(boolean) * @see FTPClient#listNames() * @since 1.2 */ public FTPFile[] list(String fileSpec) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException, FTPListParseException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // ASCII, please! communication.sendFTPCommand("TYPE A"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Prepares the connection for the data transfer. FTPDataTransferConnectionProvider provider = openDataTransferChannel(); // MLSD or LIST command? boolean mlsdCommand; if (mlsdPolicy == MLSD_IF_SUPPORTED) { mlsdCommand = mlsdSupported; } else if (mlsdPolicy == MLSD_ALWAYS) { mlsdCommand = true; } else { mlsdCommand = false; } String command = mlsdCommand ? "MLSD" : "LIST"; // Adds the file/directory selector. if (fileSpec != null && fileSpec.length() > 0) { command += " " + fileSpec; } // Prepares the lines array. ArrayList lines = new ArrayList(); // Local abort state. boolean wasAborted = false; // Sends the command. communication.sendFTPCommand(command); try { Socket dtConnection; try { dtConnection = provider.openDataTransferConnection(); } finally { provider.dispose(); } // Change the operation status. synchronized (abortLock) { ongoingDataTransfer = true; aborted = false; consumeAborCommandReply = false; } // Fetch the list from the data transfer connection. NVTASCIIReader dataReader = null; try { // Opens the data transfer connection. dataTransferInputStream = dtConnection.getInputStream(); // MODE Z enabled? if (modezEnabled) { dataTransferInputStream = new InflaterInputStream(dataTransferInputStream); } // Let's do it! dataReader = new NVTASCIIReader(dataTransferInputStream, mlsdCommand ? "UTF-8" : pickCharset()); String line; while ((line = dataReader.readLine()) != null) { if (line.length() > 0) { lines.add(line); } } } catch (IOException e) { synchronized (abortLock) { if (aborted) { throw new FTPAbortedException(); } else { throw new FTPDataTransferException( "I/O error in data transfer", e); } } } finally { if (dataReader != null) { try { dataReader.close(); } catch (Throwable t) { ; } } try { dtConnection.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferInputStream = null; // Change the operation status. synchronized (abortLock) { wasAborted = aborted; ongoingDataTransfer = false; aborted = false; } } } finally { r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 150 && r.getCode() != 125) { throw new FTPException(r); } // Consumes the result reply of the transfer. r = communication.readFTPReply(); if (!wasAborted && r.getCode() != 226) { throw new FTPException(r); } // ABOR command response (if needed). if (consumeAborCommandReply) { communication.readFTPReply(); consumeAborCommandReply = false; } } // Build an array of lines. int size = lines.size(); String[] list = new String[size]; for (int i = 0; i < size; i++) { list[i] = (String) lines.get(i); } // Parse the list. FTPFile[] ret = null; if (mlsdCommand) { // Forces the MLSDListParser. MLSDListParser parser = new MLSDListParser(); ret = parser.parse(list); } else { // Is there any already successful parser? if (parser != null) { // Yes, let's try with it. try { ret = parser.parse(list); } catch (FTPListParseException e) { // That parser doesn't work anymore. parser = null; } } // Is there an available result? if (ret == null) { // Try to parse the list with every available parser. for (Iterator i = listParsers.iterator(); i.hasNext();) { FTPListParser aux = (FTPListParser) i.next(); try { // Let's try! ret = aux.parse(list); // This parser smells good! parser = aux; // Leave the loop. break; } catch (FTPListParseException e) { // Let's try the next one. continue; } } } } if (ret == null) { // None of the parsers can handle the list response. throw new FTPListParseException(); } else { // Return the parsed list. return ret; } } } /** * This method lists the entries of the current working directory parsing * the reply to a FTP LIST command. * * The response to the LIST command is parsed through the FTPListParser * objects registered on the client. The distribution of ftp4j contains some * standard parsers already registered on every FTPClient object created. If * they don't work in your case (a FTPListParseException is thrown), you can * build your own parser implementing the FTPListParser interface and add it * to the client by calling its addListParser() method. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The list() method will break with a * FTPAbortedException. * * @return The list of the files (and directories) in the current working * directory. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @throws FTPListParseException * If none of the registered parsers can handle the response * sent by the server. * @see FTPListParser * @see FTPClient#addListParser(FTPListParser) * @see FTPClient#getListParsers() * @see FTPClient#abortCurrentDataTransfer(boolean) * @see FTPClient#listNames() */ public FTPFile[] list() throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException, FTPListParseException { return list(null); } /** * This method lists the entries of the current working directory with a FTP * NLST command. * * The response consists in an array of string, each one reporting the name * of a file or a directory placed in the current working directory. For a * more detailed directory listing procedure look at the list() method. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The listNames() method will break with a * FTPAbortedException. * * @return The list of the files (and directories) in the current working * directory. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @throws FTPListParseException * If none of the registered parsers can handle the response * sent by the server. * @see FTPClient#abortCurrentDataTransfer(boolean) * @see FTPClient#list() */ public String[] listNames() throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException, FTPListParseException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // ASCII, please! communication.sendFTPCommand("TYPE A"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Prepares the lines array. ArrayList lines = new ArrayList(); // Local abort state. boolean wasAborted = false; // Prepares the connection for the data transfer. FTPDataTransferConnectionProvider provider = openDataTransferChannel(); // Send the NLST command. communication.sendFTPCommand("NLST"); try { Socket dtConnection; try { dtConnection = provider.openDataTransferConnection(); } finally { provider.dispose(); } // Change the operation status. synchronized (abortLock) { ongoingDataTransfer = true; aborted = false; consumeAborCommandReply = false; } // Fetch the list from the data transfer connection. NVTASCIIReader dataReader = null; try { // Opens the data transfer connection. dataTransferInputStream = dtConnection.getInputStream(); // MODE Z enabled? if (modezEnabled) { dataTransferInputStream = new InflaterInputStream(dataTransferInputStream); } // Let's do it! dataReader = new NVTASCIIReader(dataTransferInputStream, pickCharset()); String line; while ((line = dataReader.readLine()) != null) { if (line.length() > 0) { lines.add(line); } } } catch (IOException e) { synchronized (abortLock) { if (aborted) { throw new FTPAbortedException(); } else { throw new FTPDataTransferException( "I/O error in data transfer", e); } } } finally { if (dataReader != null) { try { dataReader.close(); } catch (Throwable t) { ; } } try { dtConnection.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferInputStream = null; // Change the operation status. synchronized (abortLock) { wasAborted = aborted; ongoingDataTransfer = false; aborted = false; } } } finally { r = communication.readFTPReply(); if (r.getCode() != 150 && r.getCode() != 125) { throw new FTPException(r); } // Consumes the result reply of the transfer. r = communication.readFTPReply(); if (!wasAborted && r.getCode() != 226) { throw new FTPException(r); } // ABOR command response (if needed). if (consumeAborCommandReply) { communication.readFTPReply(); consumeAborCommandReply = false; } } // Build an array. int size = lines.size(); String[] list = new String[size]; for (int i = 0; i < size; i++) { list[i] = (String) lines.get(i); } return list; } } /** * This method uploads a file to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The file to upload. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void upload(File file) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { upload(file, 0, null); } /** * This method uploads a file to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The file to upload. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void upload(File file, FTPDataTransferListener listener) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { upload(file, 0, listener); } /** * This method uploads a file to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The file to upload. * @param restartAt * The restart point (number of bytes already uploaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void upload(File file, long restartAt) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { upload(file, restartAt, null); } /** * This method uploads a file to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The file to upload. * @param restartAt * The restart point (number of bytes already uploaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void upload(File file, long restartAt, FTPDataTransferListener listener) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath()); } InputStream inputStream = null; try { inputStream = new FileInputStream(file); } catch (IOException e) { throw new FTPDataTransferException(e); } try { upload(file.getName(), inputStream, restartAt, restartAt, listener); } catch (IllegalStateException e) { throw e; } catch (IOException e) { throw e; } catch (FTPIllegalReplyException e) { throw e; } catch (FTPException e) { throw e; } catch (FTPDataTransferException e) { throw e; } catch (FTPAbortedException e) { throw e; } finally { if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ; } } } } /** * This method uploads a content to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param fileName * The name of the remote file. * @param inputStream * The source of data. * @param restartAt * The restart point (number of bytes already uploaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @param streamOffset * The offset to skip in the stream. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void upload(String fileName, InputStream inputStream, long restartAt, long streamOffset, FTPDataTransferListener listener) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Select the type of contents. int tp = type; if (tp == TYPE_AUTO) { tp = detectType(fileName); } if (tp == TYPE_TEXTUAL) { communication.sendFTPCommand("TYPE A"); } else if (tp == TYPE_BINARY) { communication.sendFTPCommand("TYPE I"); } FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Prepares the connection for the data transfer. FTPDataTransferConnectionProvider provider = openDataTransferChannel(); // REST command (if supported and/or requested). if (restSupported || restartAt > 0) { boolean done = false; try { communication.sendFTPCommand("REST " + restartAt); r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 350 && ((r.getCode() != 501 && r.getCode() != 502) || restartAt > 0)) { throw new FTPException(r); } done = true; } finally { if (!done) { provider.dispose(); } } } // Local abort state. boolean wasAborted = false; // Send the STOR command. communication.sendFTPCommand("STOR " + fileName); try { Socket dtConnection; try { dtConnection = provider.openDataTransferConnection(); } finally { provider.dispose(); } // Change the operation status. synchronized (abortLock) { ongoingDataTransfer = true; aborted = false; consumeAborCommandReply = false; } // Upload the stream. try { // Skips. inputStream.skip(streamOffset); // Opens the data transfer connection. dataTransferOutputStream = dtConnection.getOutputStream(); // MODE Z enabled? if (modezEnabled) { dataTransferOutputStream = new DeflaterOutputStream(dataTransferOutputStream); } // Listeners. if (listener != null) { listener.started(); } // Let's do it! if (tp == TYPE_TEXTUAL) { Reader reader = new InputStreamReader(inputStream); Writer writer = new OutputStreamWriter( dataTransferOutputStream, pickCharset()); char[] buffer = new char[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = reader.read(buffer)) != -1) { writer.write(buffer, 0, l); writer.flush(); if (listener != null) { listener.transferred(l); } } } else if (tp == TYPE_BINARY) { byte[] buffer = new byte[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = inputStream.read(buffer)) != -1) { dataTransferOutputStream.write(buffer, 0, l); dataTransferOutputStream.flush(); if (listener != null) { listener.transferred(l); } } } } catch (IOException e) { synchronized (abortLock) { if (aborted) { if (listener != null) { listener.aborted(); } throw new FTPAbortedException(); } else { if (listener != null) { listener.failed(); } throw new FTPDataTransferException( "I/O error in data transfer", e); } } } finally { // Closing stream and data connection. if (dataTransferOutputStream != null) { try { dataTransferOutputStream.close(); } catch (Throwable t) { ; } } try { dtConnection.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferOutputStream = null; // Change the operation status. synchronized (abortLock) { wasAborted = aborted; ongoingDataTransfer = false; aborted = false; } } } finally { // Data transfer command reply. r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 150 && r.getCode() != 125) { throw new FTPException(r); } // Consumes the result reply of the transfer. r = communication.readFTPReply(); if (!wasAborted && r.getCode() != 226) { throw new FTPException(r); } // ABOR command response (if needed). if (consumeAborCommandReply) { communication.readFTPReply(); consumeAborCommandReply = false; } } // Listener notification. if (listener != null) { listener.completed(); } } } /** * This method appends the contents of a local file to an existing file on * the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The local file whose contents will be appended to the remote * file. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) * @since 1.6 */ public void append(File file) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { append(file, null); } /** * This method uploads a file to the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param file * The local file whose contents will be appended to the remote * file. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) * @since 1.6 */ public void append(File file, FTPDataTransferListener listener) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath()); } InputStream inputStream = null; try { inputStream = new FileInputStream(file); } catch (IOException e) { throw new FTPDataTransferException(e); } try { append(file.getName(), inputStream, 0, listener); } catch (IllegalStateException e) { throw e; } catch (IOException e) { throw e; } catch (FTPIllegalReplyException e) { throw e; } catch (FTPException e) { throw e; } catch (FTPDataTransferException e) { throw e; } catch (FTPAbortedException e) { throw e; } finally { if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ; } } } } /** * This method appends data to an existing file on the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param fileName * The name of the remote file. * @param inputStream * The source of data. * @param streamOffset * The offset to skip in the stream. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) * @since 1.6 */ public void append(String fileName, InputStream inputStream, long streamOffset, FTPDataTransferListener listener) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Select the type of contents. int tp = type; if (tp == TYPE_AUTO) { tp = detectType(fileName); } if (tp == TYPE_TEXTUAL) { communication.sendFTPCommand("TYPE A"); } else if (tp == TYPE_BINARY) { communication.sendFTPCommand("TYPE I"); } FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Local abort state. boolean wasAborted = false; // Prepares the connection for the data transfer. FTPDataTransferConnectionProvider provider = openDataTransferChannel(); // Send the STOR command. communication.sendFTPCommand("APPE " + fileName); try { Socket dtConnection; try { dtConnection = provider.openDataTransferConnection(); } finally { provider.dispose(); } // Change the operation status. synchronized (abortLock) { ongoingDataTransfer = true; aborted = false; consumeAborCommandReply = false; } // Upload the stream. try { // Skips. inputStream.skip(streamOffset); // Opens the data transfer connection. dataTransferOutputStream = dtConnection.getOutputStream(); // MODE Z enabled? if (modezEnabled) { dataTransferOutputStream = new DeflaterOutputStream(dataTransferOutputStream); } // Listeners. if (listener != null) { listener.started(); } // Let's do it! if (tp == TYPE_TEXTUAL) { Reader reader = new InputStreamReader(inputStream); Writer writer = new OutputStreamWriter( dataTransferOutputStream, pickCharset()); char[] buffer = new char[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = reader.read(buffer)) != -1) { writer.write(buffer, 0, l); writer.flush(); if (listener != null) { listener.transferred(l); } } } else if (tp == TYPE_BINARY) { byte[] buffer = new byte[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = inputStream.read(buffer)) != -1) { dataTransferOutputStream.write(buffer, 0, l); dataTransferOutputStream.flush(); if (listener != null) { listener.transferred(l); } } } } catch (IOException e) { synchronized (abortLock) { if (aborted) { if (listener != null) { listener.aborted(); } throw new FTPAbortedException(); } else { if (listener != null) { listener.failed(); } throw new FTPDataTransferException( "I/O error in data transfer", e); } } } finally { // Closing stream and data connection. if (dataTransferOutputStream != null) { try { dataTransferOutputStream.close(); } catch (Throwable t) { ; } } try { dtConnection.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferOutputStream = null; // Change the operation status. synchronized (abortLock) { wasAborted = aborted; ongoingDataTransfer = false; aborted = false; } } } finally { r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 150 && r.getCode() != 125) { throw new FTPException(r); } // Consumes the result reply of the transfer. r = communication.readFTPReply(); if (!wasAborted && r.getCode() != 226) { throw new FTPException(r); } // ABOR command response (if needed). if (consumeAborCommandReply) { communication.readFTPReply(); consumeAborCommandReply = false; } } // Notifies the listener. if (listener != null) { listener.completed(); } } } /** * This method downloads a remote file from the server to a local file. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param remoteFileName * The name of the file to download. * @param localFile * The local file. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void download(String remoteFileName, File localFile) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { download(remoteFileName, localFile, 0, null); } /** * This method downloads a remote file from the server to a local file. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param remoteFileName * The name of the file to download. * @param localFile * The local file. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void download(String remoteFileName, File localFile, FTPDataTransferListener listener) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { download(remoteFileName, localFile, 0, listener); } /** * This method resumes a download operation from the remote server to a * local file. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param remoteFileName * The name of the file to download. * @param localFile * The local file. * @param restartAt * The restart point (number of bytes already downloaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void download(String remoteFileName, File localFile, long restartAt) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { download(remoteFileName, localFile, restartAt, null); } /** * This method resumes a download operation from the remote server to a * local file. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param remoteFileName * The name of the file to download. * @param localFile * The local file. * @param restartAt * The restart point (number of bytes already downloaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws FileNotFoundException * If the supplied file cannot be found. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void download(String remoteFileName, File localFile, long restartAt, FTPDataTransferListener listener) throws IllegalStateException, FileNotFoundException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { OutputStream outputStream = null; try { outputStream = new FileOutputStream(localFile, restartAt > 0); } catch (IOException e) { throw new FTPDataTransferException(e); } try { download(remoteFileName, outputStream, restartAt, listener); } catch (IllegalStateException e) { throw e; } catch (IOException e) { throw e; } catch (FTPIllegalReplyException e) { throw e; } catch (FTPException e) { throw e; } catch (FTPDataTransferException e) { throw e; } catch (FTPAbortedException e) { throw e; } finally { if (outputStream != null) { try { outputStream.close(); } catch (Throwable t) { ; } } } } /** * This method resumes a download operation from the remote server. * * Calling this method blocks the current thread until the operation is * completed. The operation could be interrupted by another thread calling * abortCurrentDataTransfer(). The method will break with a * FTPAbortedException. * * @param fileName * The name of the remote file. * @param outputStream * The destination stream of data read during the download. * @param restartAt * The restart point (number of bytes already downloaded). Use * {@link FTPClient#isResumeSupported()} to check if the server * supports resuming of broken data transfers. * @param listener * The listener for the operation. Could be null. * @throws IllegalStateException * If the client is not connected or not authenticated. * @throws IOException * If an I/O error occurs. * @throws FTPIllegalReplyException * If the server replies in an illegal way. * @throws FTPException * If the operation fails. * @throws FTPDataTransferException * If a I/O occurs in the data transfer connection. If you * receive this exception the transfer failed, but the main * connection with the remote FTP server is in theory still * working. * @throws FTPAbortedException * If operation is aborted by another thread. * @see FTPClient#abortCurrentDataTransfer(boolean) */ public void download(String fileName, OutputStream outputStream, long restartAt, FTPDataTransferListener listener) throws IllegalStateException, IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException, FTPAbortedException { synchronized (lock) { // Is this client connected? if (!connected) { throw new IllegalStateException("Client not connected"); } // Is this client authenticated? if (!authenticated) { throw new IllegalStateException("Client not authenticated"); } // Select the type of contents. int tp = type; if (tp == TYPE_AUTO) { tp = detectType(fileName); } if (tp == TYPE_TEXTUAL) { communication.sendFTPCommand("TYPE A"); } else if (tp == TYPE_BINARY) { communication.sendFTPCommand("TYPE I"); } FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Prepares the connection for the data transfer. FTPDataTransferConnectionProvider provider = openDataTransferChannel(); // REST command (if supported and/or requested). if (restSupported || restartAt > 0) { boolean done = false; try { communication.sendFTPCommand("REST " + restartAt); r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 350 && ((r.getCode() != 501 && r.getCode() != 502) || restartAt > 0)) { throw new FTPException(r); } done = true; } finally { if (!done) { provider.dispose(); } } } // Local abort state. boolean wasAborted = false; // Send the RETR command. communication.sendFTPCommand("RETR " + fileName); try { Socket dtConnection; try { dtConnection = provider.openDataTransferConnection(); } finally { provider.dispose(); } // Change the operation status. synchronized (abortLock) { ongoingDataTransfer = true; aborted = false; consumeAborCommandReply = false; } // Download the stream. try { // Opens the data transfer connection. dataTransferInputStream = dtConnection.getInputStream(); // MODE Z enabled? if (modezEnabled) { dataTransferInputStream = new InflaterInputStream(dataTransferInputStream); } // Listeners. if (listener != null) { listener.started(); } // Let's do it! if (tp == TYPE_TEXTUAL) { Reader reader = new InputStreamReader( dataTransferInputStream, pickCharset()); Writer writer = new OutputStreamWriter(outputStream); char[] buffer = new char[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = reader.read(buffer, 0, buffer.length)) != -1) { writer.write(buffer, 0, l); writer.flush(); if (listener != null) { listener.transferred(l); } } } else if (tp == TYPE_BINARY) { byte[] buffer = new byte[SEND_AND_RECEIVE_BUFFER_SIZE]; int l; while ((l = dataTransferInputStream.read(buffer, 0, buffer.length)) != -1) { outputStream.write(buffer, 0, l); if (listener != null) { listener.transferred(l); } } } } catch (IOException e) { synchronized (abortLock) { if (aborted) { if (listener != null) { listener.aborted(); } throw new FTPAbortedException(); } else { if (listener != null) { listener.failed(); } throw new FTPDataTransferException( "I/O error in data transfer", e); } } } finally { // Closing stream and data connection. if (dataTransferInputStream != null) { try { dataTransferInputStream.close(); } catch (Throwable t) { ; } } try { dtConnection.close(); } catch (Throwable t) { ; } // Set to null the instance-level input stream. dataTransferInputStream = null; // Change the operation status. synchronized (abortLock) { wasAborted = aborted; ongoingDataTransfer = false; aborted = false; } } } finally { r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.getCode() != 150 && r.getCode() != 125) { throw new FTPException(r); } // Consumes the result reply of the transfer. r = communication.readFTPReply(); if (!wasAborted && r.getCode() != 226) { throw new FTPException(r); } // ABOR command response (if needed). if (consumeAborCommandReply) { communication.readFTPReply(); consumeAborCommandReply = false; } } // Notifies the listener. if (listener != null) { listener.completed(); } } } /** * This method detects the type for a file transfer. */ private int detectType(String fileName) throws IOException, FTPIllegalReplyException, FTPException { int start = fileName.lastIndexOf('.') + 1; int stop = fileName.length(); if (start > 0 && start < stop - 1) { String ext = fileName.substring(start, stop); ext = ext.toLowerCase(); if (textualExtensionRecognizer.isTextualExt(ext)) { return TYPE_TEXTUAL; } else { return TYPE_BINARY; } } else { return TYPE_BINARY; } } /** * This method opens a data transfer channel. */ private FTPDataTransferConnectionProvider openDataTransferChannel() throws IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException { // MODE Z? if (modezSupported && compressionEnabled) { if (!modezEnabled) { // Sends the MODE Z command. communication.sendFTPCommand("MODE Z"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.isSuccessCode()) { modezEnabled = true; } } } else { if (modezEnabled) { // Sends the MODE S command. communication.sendFTPCommand("MODE S"); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (r.isSuccessCode()) { modezEnabled = false; } } } // Active or passive? if (passive) { return openPassiveDataTransferChannel(); } else { return openActiveDataTransferChannel(); } } /** * This method opens a data transfer channel in active mode. */ private FTPDataTransferConnectionProvider openActiveDataTransferChannel() throws IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException { // Create a FTPDataTransferServer object. FTPDataTransferServer server = new FTPDataTransferServer() { public Socket openDataTransferConnection() throws FTPDataTransferException { Socket socket = super.openDataTransferConnection(); if (dataChannelEncrypted) { try { socket = ssl(socket, socket.getInetAddress().getHostName(), socket.getPort()); } catch (IOException e) { try { socket.close(); } catch (Throwable t) { } throw new FTPDataTransferException(e); } } return socket; } }; int port = server.getPort(); int p1 = port >>> 8; int p2 = port & 0xff; int[] addr = pickLocalAddress(); // Send the port command. communication.sendFTPCommand("PORT " + addr[0] + "," + addr[1] + "," + addr[2] + "," + addr[3] + "," + p1 + "," + p2); FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { // Disposes. server.dispose(); // Closes the already open connection (if any). try { Socket aux = server.openDataTransferConnection(); aux.close(); } catch (Throwable t) { ; } // Throws the exception. throw new FTPException(r); } return server; } /** * This method opens a data transfer channel in passive mode. */ private FTPDataTransferConnectionProvider openPassiveDataTransferChannel() throws IOException, FTPIllegalReplyException, FTPException, FTPDataTransferException { // Send the PASV command. communication.sendFTPCommand("PASV"); // Read the reply. FTPReply r = communication.readFTPReply(); touchAutoNoopTimer(); if (!r.isSuccessCode()) { throw new FTPException(r); } // Use a regexp to extract the remote address and port. String addressAndPort = null; String[] messages = r.getMessages(); for (int i = 0; i < messages.length; i++) { Matcher m = PASV_PATTERN.matcher(messages[i]); if (m.find()) { int start = m.start(); int end = m.end(); addressAndPort = messages[i].substring(start, end); break; } } if (addressAndPort == null) { // The remote server has not sent the coordinates for the // data transfer connection. throw new FTPIllegalReplyException(); } // Parse the string extracted from the reply. StringTokenizer st = new StringTokenizer(addressAndPort, ","); int b1 = Integer.parseInt(st.nextToken()); int b2 = Integer.parseInt(st.nextToken()); int b3 = Integer.parseInt(st.nextToken()); int b4 = Integer.parseInt(st.nextToken()); int p1 = Integer.parseInt(st.nextToken()); int p2 = Integer.parseInt(st.nextToken()); final String pasvHost = b1 + "." + b2 + "." + b3 + "." + b4; final int pasvPort = (p1 << 8) | p2; FTPDataTransferConnectionProvider provider = new FTPDataTransferConnectionProvider() { public Socket openDataTransferConnection() throws FTPDataTransferException { // Establish the connection. Socket dtConnection; try { String selectedHost = connector.getUseSuggestedAddressForDataConnections() ? pasvHost : host; dtConnection = connector.connectForDataTransferChannel(selectedHost, pasvPort); if (dataChannelEncrypted) { dtConnection = ssl(dtConnection, selectedHost, pasvPort); } } catch (IOException e) { throw new FTPDataTransferException("Cannot connect to the remote server", e); } return dtConnection; } public void dispose() { // nothing to do } }; return provider; } /** * If there's any ongoing data transfer operation, this method aborts it. * * @param sendAborCommand * If true the client will negotiate the abort procedure with the * server, through the standard FTP ABOR command. Otherwise the * open data transfer connection will be closed without any * advise has sent to the server. * @throws IOException * If the ABOR command cannot be sent due to any I/O error. This * could happen only if force is false. * @throws FTPIllegalReplyException * If the server reply to the ABOR command is illegal. This * could happen only if force is false. */ public void abortCurrentDataTransfer(boolean sendAborCommand) throws IOException, FTPIllegalReplyException { synchronized (abortLock) { if (ongoingDataTransfer && !aborted) { if (sendAborCommand) { communication.sendFTPCommand("ABOR"); touchAutoNoopTimer(); consumeAborCommandReply = true; } if (dataTransferInputStream != null) { try { dataTransferInputStream.close(); } catch (Throwable t) { ; } } if (dataTransferOutputStream != null) { try { dataTransferOutputStream.close(); } catch (Throwable t) { ; } } aborted = true; } } } /** * Returns the name of the charset that should be used in textual * transmissions. * * @return The name of the charset that should be used in textual * transmissions. */ private String pickCharset() { if (charset != null) { return charset; } else if (utf8Supported) { return "UTF-8"; } else { return System.getProperty("file.encoding"); } } /** * Picks the local address for an active data transfer operation. * * @return The local address as a 4 integer values array. * @throws IOException * If an unexpected I/O error occurs while trying to resolve the * local address. */ private int[] pickLocalAddress() throws IOException { // Forced address? int[] ret = pickForcedLocalAddress(); // Auto-detect? if (ret == null) { ret = pickAutoDetectedLocalAddress(); } // Returns. return ret; } /** * If a local address for active data transfers has been supplied through * the {@link FTPKeys#ACTIVE_DT_HOST_ADDRESS}, it returns it as a 4 elements * integer array; otherwise it returns null. * * @return The forced local address, or null. */ private int[] pickForcedLocalAddress() { int[] ret = null; String aux = System.getProperty(FTPKeys.ACTIVE_DT_HOST_ADDRESS); if (aux != null) { boolean valid = false; StringTokenizer st = new StringTokenizer(aux, "."); if (st.countTokens() == 4) { valid = true; int[] arr = new int[4]; for (int i = 0; i < 4; i++) { String tk = st.nextToken(); try { arr[i] = Integer.parseInt(tk); } catch (NumberFormatException e) { arr[i] = -1; } if (arr[i] < 0 || arr[i] > 255) { valid = false; break; } } if (valid) { ret = arr; } } if (!valid) { // warning to the developer logger.warning("WARNING: invalid value \"" + aux + "\" for the " + FTPKeys.ACTIVE_DT_HOST_ADDRESS + " system property. The value should " + "be in the x.x.x.x form."); } } return ret; } /** * Auto-detects the local network address, and returns it in the form of a 4 * elements integer array. * * @return The detected local address. * @throws IOException * If an unexpected I/O error occurs while trying to resolve the * local address. */ private int[] pickAutoDetectedLocalAddress() throws IOException { InetAddress addressObj = InetAddress.getLocalHost(); byte[] addr = addressObj.getAddress(); int b1 = addr[0] & 0xff; int b2 = addr[1] & 0xff; int b3 = addr[2] & 0xff; int b4 = addr[3] & 0xff; int[] ret = { b1, b2, b3, b4 }; return ret; } public String toString() { synchronized (lock) { StringBuffer buffer = new StringBuffer(); buffer.append(getClass().getName()); buffer.append(" [connected="); buffer.append(connected); if (connected) { buffer.append(", host="); buffer.append(host); buffer.append(", port="); buffer.append(port); } buffer.append(", connector="); buffer.append(connector); buffer.append(", security="); switch (security) { case SECURITY_FTP: buffer.append("SECURITY_FTP"); break; case SECURITY_FTPS: buffer.append("SECURITY_FTPS"); break; case SECURITY_FTPES: buffer.append("SECURITY_FTPES"); break; } buffer.append(", authenticated="); buffer.append(authenticated); if (authenticated) { buffer.append(", username="); buffer.append(username); buffer.append(", password="); StringBuffer buffer2 = new StringBuffer(); for (int i = 0; i < password.length(); i++) { buffer2.append('*'); } buffer.append(buffer2); buffer.append(", restSupported="); buffer.append(restSupported); buffer.append(", utf8supported="); buffer.append(utf8Supported); buffer.append(", mlsdSupported="); buffer.append(mlsdSupported); buffer.append(", mode=modezSupported"); buffer.append(modezSupported); buffer.append(", mode=modezEnabled"); buffer.append(modezEnabled); } buffer.append(", transfer mode="); buffer.append(passive ? "passive" : "active"); buffer.append(", transfer type="); switch (type) { case TYPE_AUTO: buffer.append("TYPE_AUTO"); break; case TYPE_BINARY: buffer.append("TYPE_BINARY"); break; case TYPE_TEXTUAL: buffer.append("TYPE_TEXTUAL"); break; } buffer.append(", textualExtensionRecognizer="); buffer.append(textualExtensionRecognizer); FTPListParser[] listParsers = getListParsers(); if (listParsers.length > 0) { buffer.append(", listParsers="); for (int i = 0; i < listParsers.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(listParsers[i]); } } FTPCommunicationListener[] communicationListeners = getCommunicationListeners(); if (communicationListeners.length > 0) { buffer.append(", communicationListeners="); for (int i = 0; i < communicationListeners.length; i++) { if (i > 0) { buffer.append(", "); } buffer.append(communicationListeners[i]); } } buffer.append(", autoNoopTimeout="); buffer.append(autoNoopTimeout); buffer.append("]"); return buffer.toString(); } } /** * Starts the auto-noop timer thread. */ private void startAutoNoopTimer() { if (autoNoopTimeout > 0) { autoNoopTimer = new AutoNoopTimer(); autoNoopTimer.start(); } } /** * Stops the auto-noop timer thread. * * @since 1.5 */ private void stopAutoNoopTimer() { if (autoNoopTimer != null) { autoNoopTimer.interrupt(); autoNoopTimer = null; } } /** * Resets the auto noop timer. */ private void touchAutoNoopTimer() { if (autoNoopTimer != null) { nextAutoNoopTime = System.currentTimeMillis() + autoNoopTimeout; } } /** * The auto noop timer thread. */ private class AutoNoopTimer extends Thread { public void run() { synchronized (lock) { if (nextAutoNoopTime <= 0 && autoNoopTimeout > 0) { nextAutoNoopTime = System.currentTimeMillis() + autoNoopTimeout; } while (!Thread.interrupted() && autoNoopTimeout > 0) { // Sleep till the next NOOP. long delay = nextAutoNoopTime - System.currentTimeMillis(); if (delay > 0) { try { lock.wait(delay); } catch (InterruptedException e) { break; } } // Is it really time to NOOP? if (System.currentTimeMillis() >= nextAutoNoopTime) { // Yes! try { noop(); } catch (Throwable t) { ; // ignore... } } } } } } }