commit
102d3ba0f6
@ -1 +0,0 @@ |
||||
/build |
@ -1,11 +0,0 @@ |
||||
apply plugin: 'com.novoda.bintray-release' |
||||
publish { |
||||
artifactId = 'aria-ftp-plug' |
||||
userOrg = rootProject.ext.userOrg |
||||
groupId = rootProject.ext.groupId |
||||
uploadName = 'FtpPlug' |
||||
publishVersion = rootProject.ext.publishVersion |
||||
desc = rootProject.ext.desc |
||||
website = rootProject.ext.website |
||||
licences = rootProject.ext.licences |
||||
} |
@ -1,14 +0,0 @@ |
||||
apply plugin: 'java' |
||||
|
||||
tasks.withType(JavaCompile) { |
||||
options.encoding = "UTF-8" |
||||
} |
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_1_7 |
||||
targetCompatibility = JavaVersion.VERSION_1_7 |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
} |
||||
|
||||
//apply from: 'bintray-release.gradle' |
@ -1,25 +0,0 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# By default, the flags in this file are appended to flags specified |
||||
# in E:\sdk/tools/proguard/proguard-android.txt |
||||
# You can edit the include path and order by changing the proguardFiles |
||||
# directive in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# Add any project specific keep options here: |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
@ -1,287 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.net.DatagramSocket; |
||||
import java.net.InetAddress; |
||||
import java.net.SocketException; |
||||
import java.nio.charset.Charset; |
||||
|
||||
/*** |
||||
* The DatagramSocketClient provides the basic operations that are required |
||||
* of client objects accessing datagram sockets. It is meant to be |
||||
* subclassed to avoid having to rewrite the same code over and over again |
||||
* to open a socket, close a socket, set timeouts, etc. Of special note |
||||
* is the {@link #setDatagramSocketFactory setDatagramSocketFactory } |
||||
* method, which allows you to control the type of DatagramSocket the |
||||
* DatagramSocketClient creates for network communications. This is |
||||
* especially useful for adding things like proxy support as well as better |
||||
* support for applets. For |
||||
* example, you could create a |
||||
* {@link DatagramSocketFactory} |
||||
* that |
||||
* requests browser security capabilities before creating a socket. |
||||
* All classes derived from DatagramSocketClient should use the |
||||
* {@link #_socketFactory_ _socketFactory_ } member variable to |
||||
* create DatagramSocket instances rather than instantiating |
||||
* them by directly invoking a constructor. By honoring this contract |
||||
* you guarantee that a user will always be able to provide his own |
||||
* Socket implementations by substituting his own SocketFactory. |
||||
* |
||||
* |
||||
* @see DatagramSocketFactory |
||||
***/ |
||||
|
||||
public abstract class DatagramSocketClient { |
||||
/*** |
||||
* The default DatagramSocketFactory shared by all DatagramSocketClient |
||||
* instances. |
||||
***/ |
||||
private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = |
||||
new DefaultDatagramSocketFactory(); |
||||
|
||||
/** |
||||
* Charset to use for byte IO. |
||||
*/ |
||||
private Charset charset = Charset.defaultCharset(); |
||||
|
||||
/*** The timeout to use after opening a socket. ***/ |
||||
protected int _timeout_; |
||||
|
||||
/*** The datagram socket used for the connection. ***/ |
||||
protected DatagramSocket _socket_; |
||||
|
||||
/*** |
||||
* A status variable indicating if the client's socket is currently open. |
||||
***/ |
||||
protected boolean _isOpen_; |
||||
|
||||
/*** The datagram socket's DatagramSocketFactory. ***/ |
||||
protected DatagramSocketFactory _socketFactory_; |
||||
|
||||
/*** |
||||
* Default constructor for DatagramSocketClient. Initializes |
||||
* _socket_ to null, _timeout_ to 0, and _isOpen_ to false. |
||||
***/ |
||||
public DatagramSocketClient() { |
||||
_socket_ = null; |
||||
_timeout_ = 0; |
||||
_isOpen_ = false; |
||||
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
||||
} |
||||
|
||||
/*** |
||||
* Opens a DatagramSocket on the local host at the first available port. |
||||
* Also sets the timeout on the socket to the default timeout set |
||||
* by {@link #setDefaultTimeout setDefaultTimeout() }. |
||||
* <p> |
||||
* _isOpen_ is set to true after calling this method and _socket_ |
||||
* is set to the newly opened socket. |
||||
* |
||||
* @throws SocketException If the socket could not be opened or the |
||||
* timeout could not be set. |
||||
***/ |
||||
public void open() throws SocketException { |
||||
_socket_ = _socketFactory_.createDatagramSocket(); |
||||
_socket_.setSoTimeout(_timeout_); |
||||
_isOpen_ = true; |
||||
} |
||||
|
||||
/*** |
||||
* Opens a DatagramSocket on the local host at a specified port. |
||||
* Also sets the timeout on the socket to the default timeout set |
||||
* by {@link #setDefaultTimeout setDefaultTimeout() }. |
||||
* <p> |
||||
* _isOpen_ is set to true after calling this method and _socket_ |
||||
* is set to the newly opened socket. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @throws SocketException If the socket could not be opened or the |
||||
* timeout could not be set. |
||||
***/ |
||||
public void open(int port) throws SocketException { |
||||
_socket_ = _socketFactory_.createDatagramSocket(port); |
||||
_socket_.setSoTimeout(_timeout_); |
||||
_isOpen_ = true; |
||||
} |
||||
|
||||
/*** |
||||
* Opens a DatagramSocket at the specified address on the local host |
||||
* at a specified port. |
||||
* Also sets the timeout on the socket to the default timeout set |
||||
* by {@link #setDefaultTimeout setDefaultTimeout() }. |
||||
* <p> |
||||
* _isOpen_ is set to true after calling this method and _socket_ |
||||
* is set to the newly opened socket. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @param laddr The local address to use. |
||||
* @throws SocketException If the socket could not be opened or the |
||||
* timeout could not be set. |
||||
***/ |
||||
public void open(int port, InetAddress laddr) throws SocketException { |
||||
_socket_ = _socketFactory_.createDatagramSocket(port, laddr); |
||||
_socket_.setSoTimeout(_timeout_); |
||||
_isOpen_ = true; |
||||
} |
||||
|
||||
/*** |
||||
* Closes the DatagramSocket used for the connection. |
||||
* You should call this method after you've finished using the class
|
||||
* instance and also before you call {@link #open open() } |
||||
* again. _isOpen_ is set to false and _socket_ is set to null. |
||||
***/ |
||||
public void close() { |
||||
if (_socket_ != null) { |
||||
_socket_.close(); |
||||
} |
||||
_socket_ = null; |
||||
_isOpen_ = false; |
||||
} |
||||
|
||||
/*** |
||||
* Returns true if the client has a currently open socket. |
||||
* |
||||
* @return True if the client has a currently open socket, false otherwise. |
||||
***/ |
||||
public boolean isOpen() { |
||||
return _isOpen_; |
||||
} |
||||
|
||||
/*** |
||||
* Set the default timeout in milliseconds to use when opening a socket. |
||||
* After a call to open, the timeout for the socket is set using this value. |
||||
* This method should be used prior to a call to {@link #open open()} |
||||
* and should not be confused with {@link #setSoTimeout setSoTimeout()} |
||||
* which operates on the currently open socket. _timeout_ contains |
||||
* the new timeout value. |
||||
* |
||||
* @param timeout The timeout in milliseconds to use for the datagram socket |
||||
* connection. |
||||
***/ |
||||
public void setDefaultTimeout(int timeout) { |
||||
_timeout_ = timeout; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the default timeout in milliseconds that is used when |
||||
* opening a socket. |
||||
* |
||||
* @return The default timeout in milliseconds that is used when |
||||
* opening a socket. |
||||
***/ |
||||
public int getDefaultTimeout() { |
||||
return _timeout_; |
||||
} |
||||
|
||||
/*** |
||||
* Set the timeout in milliseconds of a currently open connection. |
||||
* Only call this method after a connection has been opened |
||||
* by {@link #open open()}. |
||||
* |
||||
* @param timeout The timeout in milliseconds to use for the currently |
||||
* open datagram socket connection. |
||||
* @throws SocketException if an error setting the timeout |
||||
***/ |
||||
public void setSoTimeout(int timeout) throws SocketException { |
||||
_socket_.setSoTimeout(timeout); |
||||
} |
||||
|
||||
/*** |
||||
* Returns the timeout in milliseconds of the currently opened socket. |
||||
* If you call this method when the client socket is not open, |
||||
* a NullPointerException is thrown. |
||||
* |
||||
* @return The timeout in milliseconds of the currently opened socket. |
||||
* @throws SocketException if an error getting the timeout |
||||
***/ |
||||
public int getSoTimeout() throws SocketException { |
||||
return _socket_.getSoTimeout(); |
||||
} |
||||
|
||||
/*** |
||||
* Returns the port number of the open socket on the local host used |
||||
* for the connection. If you call this method when the client socket |
||||
* is not open, a NullPointerException is thrown. |
||||
* |
||||
* @return The port number of the open socket on the local host used |
||||
* for the connection. |
||||
***/ |
||||
public int getLocalPort() { |
||||
return _socket_.getLocalPort(); |
||||
} |
||||
|
||||
/*** |
||||
* Returns the local address to which the client's socket is bound. |
||||
* If you call this method when the client socket is not open, a |
||||
* NullPointerException is thrown. |
||||
* |
||||
* @return The local address to which the client's socket is bound. |
||||
***/ |
||||
public InetAddress getLocalAddress() { |
||||
return _socket_.getLocalAddress(); |
||||
} |
||||
|
||||
/*** |
||||
* Sets the DatagramSocketFactory used by the DatagramSocketClient |
||||
* to open DatagramSockets. If the factory value is null, then a default |
||||
* factory is used (only do this to reset the factory after having |
||||
* previously altered it). |
||||
* |
||||
* @param factory The new DatagramSocketFactory the DatagramSocketClient |
||||
* should use. |
||||
***/ |
||||
public void setDatagramSocketFactory(DatagramSocketFactory factory) { |
||||
if (factory == null) { |
||||
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
||||
} else { |
||||
_socketFactory_ = factory; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the charset name. |
||||
* |
||||
* @return the charset name. |
||||
* @since 3.3 |
||||
* TODO Will be deprecated once the code requires Java 1.6 as a mininmum |
||||
*/ |
||||
public String getCharsetName() { |
||||
return charset.name(); |
||||
} |
||||
|
||||
/** |
||||
* Gets the charset. |
||||
* |
||||
* @return the charset. |
||||
* @since 3.3 |
||||
*/ |
||||
public Charset getCharset() { |
||||
return charset; |
||||
} |
||||
|
||||
/** |
||||
* Sets the charset. |
||||
* |
||||
* @param charset the charset. |
||||
* @since 3.3 |
||||
*/ |
||||
public void setCharset(Charset charset) { |
||||
this.charset = charset; |
||||
} |
||||
} |
@ -1,67 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.net.DatagramSocket; |
||||
import java.net.InetAddress; |
||||
import java.net.SocketException; |
||||
|
||||
/*** |
||||
* The DatagramSocketFactory interface provides a means for the |
||||
* programmer to control the creation of datagram sockets and |
||||
* provide his own DatagramSocket implementations for use by all |
||||
* classes derived from |
||||
* {@link DatagramSocketClient} |
||||
* . |
||||
* This allows you to provide your own DatagramSocket implementations and |
||||
* to perform security checks or browser capability requests before |
||||
* creating a DatagramSocket. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public interface DatagramSocketFactory { |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket on the local host at the first available port. |
||||
* @return the socket |
||||
* |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
public DatagramSocket createDatagramSocket() throws SocketException; |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket on the local host at a specified port. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @return the socket |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
public DatagramSocket createDatagramSocket(int port) throws SocketException; |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket at the specified address on the local host |
||||
* at a specified port. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @param laddr The local address to use. |
||||
* @return the socket |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException; |
||||
} |
@ -1,72 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.net.DatagramSocket; |
||||
import java.net.InetAddress; |
||||
import java.net.SocketException; |
||||
|
||||
/*** |
||||
* DefaultDatagramSocketFactory implements the DatagramSocketFactory |
||||
* interface by simply wrapping the java.net.DatagramSocket |
||||
* constructors. It is the default DatagramSocketFactory used by |
||||
* {@link DatagramSocketClient} |
||||
* implementations. |
||||
* |
||||
* |
||||
* @see DatagramSocketFactory |
||||
* @see DatagramSocketClient |
||||
* @see DatagramSocketClient#setDatagramSocketFactory |
||||
***/ |
||||
|
||||
public class DefaultDatagramSocketFactory implements DatagramSocketFactory { |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket on the local host at the first available port. |
||||
* @return a new DatagramSocket |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
@Override public DatagramSocket createDatagramSocket() throws SocketException { |
||||
return new DatagramSocket(); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket on the local host at a specified port. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @return a new DatagramSocket |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
@Override public DatagramSocket createDatagramSocket(int port) throws SocketException { |
||||
return new DatagramSocket(port); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a DatagramSocket at the specified address on the local host |
||||
* at a specified port. |
||||
* |
||||
* @param port The port to use for the socket. |
||||
* @param laddr The local address to use. |
||||
* @return a new DatagramSocket |
||||
* @throws SocketException If the socket could not be created. |
||||
***/ |
||||
@Override public DatagramSocket createDatagramSocket(int port, InetAddress laddr) |
||||
throws SocketException { |
||||
return new DatagramSocket(port, laddr); |
||||
} |
||||
} |
@ -1,204 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.InetAddress; |
||||
import java.net.InetSocketAddress; |
||||
import java.net.Proxy; |
||||
import java.net.ServerSocket; |
||||
import java.net.Socket; |
||||
import java.net.UnknownHostException; |
||||
|
||||
import javax.net.SocketFactory; |
||||
|
||||
/*** |
||||
* DefaultSocketFactory implements the SocketFactory interface by |
||||
* simply wrapping the java.net.Socket and java.net.ServerSocket |
||||
* constructors. It is the default SocketFactory used by |
||||
* {@link SocketClient} |
||||
* implementations. |
||||
* |
||||
* |
||||
* @see SocketFactory |
||||
* @see SocketClient |
||||
* @see SocketClient#setSocketFactory |
||||
***/ |
||||
|
||||
public class DefaultSocketFactory extends SocketFactory { |
||||
/** The proxy to use when creating new sockets. */ |
||||
private final Proxy connProxy; |
||||
|
||||
/** |
||||
* The default constructor. |
||||
*/ |
||||
public DefaultSocketFactory() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* A constructor for sockets with proxy support. |
||||
* |
||||
* @param proxy The Proxy to use when creating new Sockets. |
||||
* @since 3.2 |
||||
*/ |
||||
public DefaultSocketFactory(Proxy proxy) { |
||||
connProxy = proxy; |
||||
} |
||||
|
||||
/** |
||||
* Creates an unconnected Socket. |
||||
* |
||||
* @return A new unconnected Socket. |
||||
* @throws IOException If an I/O error occurs while creating the Socket. |
||||
* @since 3.2 |
||||
*/ |
||||
@Override public Socket createSocket() throws IOException { |
||||
if (connProxy != null) { |
||||
return new Socket(connProxy); |
||||
} |
||||
return new Socket(); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a Socket connected to the given host and port. |
||||
* |
||||
* @param host The hostname to connect to. |
||||
* @param port The port to connect to. |
||||
* @return A Socket connected to the given host and port. |
||||
* @throws UnknownHostException If the hostname cannot be resolved. |
||||
* @throws IOException If an I/O error occurs while creating the Socket. |
||||
***/ |
||||
@Override public Socket createSocket(String host, int port) |
||||
throws UnknownHostException, IOException { |
||||
if (connProxy != null) { |
||||
Socket s = new Socket(connProxy); |
||||
s.connect(new InetSocketAddress(host, port)); |
||||
return s; |
||||
} |
||||
return new Socket(host, port); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a Socket connected to the given host and port. |
||||
* |
||||
* @param address The address of the host to connect to. |
||||
* @param port The port to connect to. |
||||
* @return A Socket connected to the given host and port. |
||||
* @throws IOException If an I/O error occurs while creating the Socket. |
||||
***/ |
||||
@Override public Socket createSocket(InetAddress address, int port) throws IOException { |
||||
if (connProxy != null) { |
||||
Socket s = new Socket(connProxy); |
||||
s.connect(new InetSocketAddress(address, port)); |
||||
return s; |
||||
} |
||||
return new Socket(address, port); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a Socket connected to the given host and port and |
||||
* originating from the specified local address and port. |
||||
* |
||||
* @param host The hostname to connect to. |
||||
* @param port The port to connect to. |
||||
* @param localAddr The local address to use. |
||||
* @param localPort The local port to use. |
||||
* @return A Socket connected to the given host and port. |
||||
* @throws UnknownHostException If the hostname cannot be resolved. |
||||
* @throws IOException If an I/O error occurs while creating the Socket. |
||||
***/ |
||||
@Override public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) |
||||
throws UnknownHostException, IOException { |
||||
if (connProxy != null) { |
||||
Socket s = new Socket(connProxy); |
||||
s.bind(new InetSocketAddress(localAddr, localPort)); |
||||
s.connect(new InetSocketAddress(host, port)); |
||||
return s; |
||||
} |
||||
return new Socket(host, port, localAddr, localPort); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a Socket connected to the given host and port and |
||||
* originating from the specified local address and port. |
||||
* |
||||
* @param address The address of the host to connect to. |
||||
* @param port The port to connect to. |
||||
* @param localAddr The local address to use. |
||||
* @param localPort The local port to use. |
||||
* @return A Socket connected to the given host and port. |
||||
* @throws IOException If an I/O error occurs while creating the Socket. |
||||
***/ |
||||
@Override public Socket createSocket(InetAddress address, int port, InetAddress localAddr, |
||||
int localPort) throws IOException { |
||||
if (connProxy != null) { |
||||
Socket s = new Socket(connProxy); |
||||
s.bind(new InetSocketAddress(localAddr, localPort)); |
||||
s.connect(new InetSocketAddress(address, port)); |
||||
return s; |
||||
} |
||||
return new Socket(address, port, localAddr, localPort); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a ServerSocket bound to a specified port. A port |
||||
* of 0 will create the ServerSocket on a system-determined free port. |
||||
* |
||||
* @param port The port on which to listen, or 0 to use any free port. |
||||
* @return A ServerSocket that will listen on a specified port. |
||||
* @throws IOException If an I/O error occurs while creating |
||||
* the ServerSocket. |
||||
***/ |
||||
public ServerSocket createServerSocket(int port) throws IOException { |
||||
return new ServerSocket(port); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a ServerSocket bound to a specified port with a given |
||||
* maximum queue length for incoming connections. A port of 0 will |
||||
* create the ServerSocket on a system-determined free port. |
||||
* |
||||
* @param port The port on which to listen, or 0 to use any free port. |
||||
* @param backlog The maximum length of the queue for incoming connections. |
||||
* @return A ServerSocket that will listen on a specified port. |
||||
* @throws IOException If an I/O error occurs while creating |
||||
* the ServerSocket. |
||||
***/ |
||||
public ServerSocket createServerSocket(int port, int backlog) throws IOException { |
||||
return new ServerSocket(port, backlog); |
||||
} |
||||
|
||||
/*** |
||||
* Creates a ServerSocket bound to a specified port on a given local |
||||
* address with a given maximum queue length for incoming connections. |
||||
* A port of 0 will |
||||
* create the ServerSocket on a system-determined free port. |
||||
* |
||||
* @param port The port on which to listen, or 0 to use any free port. |
||||
* @param backlog The maximum length of the queue for incoming connections. |
||||
* @param bindAddr The local address to which the ServerSocket should bind. |
||||
* @return A ServerSocket that will listen on a specified port. |
||||
* @throws IOException If an I/O error occurs while creating |
||||
* the ServerSocket. |
||||
***/ |
||||
public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr) |
||||
throws IOException { |
||||
return new ServerSocket(port, backlog, bindAddr); |
||||
} |
||||
} |
@ -1,52 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/*** |
||||
* This exception is used to indicate that the reply from a server |
||||
* could not be interpreted. Most of the NetComponents classes attempt |
||||
* to be as lenient as possible when receiving server replies. Many |
||||
* server implementations deviate from IETF protocol specifications, making |
||||
* it necessary to be as flexible as possible. However, there will be |
||||
* certain situations where it is not possible to continue an operation |
||||
* because the server reply could not be interpreted in a meaningful manner. |
||||
* In these cases, a MalformedServerReplyException should be thrown. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public class MalformedServerReplyException extends IOException { |
||||
|
||||
private static final long serialVersionUID = 6006765264250543945L; |
||||
|
||||
/*** Constructs a MalformedServerReplyException with no message ***/ |
||||
public MalformedServerReplyException() { |
||||
super(); |
||||
} |
||||
|
||||
/*** |
||||
* Constructs a MalformedServerReplyException with a specified message. |
||||
* |
||||
* @param message The message explaining the reason for the exception. |
||||
***/ |
||||
public MalformedServerReplyException(String message) { |
||||
super(message); |
||||
} |
||||
} |
@ -1,190 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.io.PrintStream; |
||||
import java.io.PrintWriter; |
||||
|
||||
/*** |
||||
* This is a support class for some of the example programs. It is |
||||
* a sample implementation of the ProtocolCommandListener interface
|
||||
* which just prints out to a specified stream all command/reply traffic. |
||||
* |
||||
* @since 2.0 |
||||
***/ |
||||
|
||||
public class PrintCommandListener implements ProtocolCommandListener { |
||||
private final PrintWriter __writer; |
||||
private final boolean __nologin; |
||||
private final char __eolMarker; |
||||
private final boolean __directionMarker; |
||||
|
||||
/** |
||||
* Create the default instance which prints everything. |
||||
* |
||||
* @param stream where to write the commands and responses |
||||
* e.g. System.out |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintStream stream) { |
||||
this(new PrintWriter(stream)); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text |
||||
* and indicates where the EOL starts with the specified character. |
||||
* |
||||
* @param stream where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintStream stream, boolean suppressLogin) { |
||||
this(new PrintWriter(stream), suppressLogin); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text |
||||
* and indicates where the EOL starts with the specified character. |
||||
* |
||||
* @param stream where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @param eolMarker if non-zero, add a marker just before the EOL. |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) { |
||||
this(new PrintWriter(stream), suppressLogin, eolMarker); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text |
||||
* and indicates where the EOL starts with the specified character. |
||||
* |
||||
* @param stream where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @param eolMarker if non-zero, add a marker just before the EOL. |
||||
* @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the |
||||
* output |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker, |
||||
boolean showDirection) { |
||||
this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection); |
||||
} |
||||
|
||||
/** |
||||
* Create the default instance which prints everything. |
||||
* |
||||
* @param writer where to write the commands and responses |
||||
*/ |
||||
public PrintCommandListener(PrintWriter writer) { |
||||
this(writer, false); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text. |
||||
* |
||||
* @param writer where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintWriter writer, boolean suppressLogin) { |
||||
this(writer, suppressLogin, (char) 0); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text |
||||
* and indicates where the EOL starts with the specified character. |
||||
* |
||||
* @param writer where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @param eolMarker if non-zero, add a marker just before the EOL. |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) { |
||||
this(writer, suppressLogin, eolMarker, false); |
||||
} |
||||
|
||||
/** |
||||
* Create an instance which optionally suppresses login command text |
||||
* and indicates where the EOL starts with the specified character. |
||||
* |
||||
* @param writer where to write the commands and responses |
||||
* @param suppressLogin if {@code true}, only print command name for login |
||||
* @param eolMarker if non-zero, add a marker just before the EOL. |
||||
* @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the |
||||
* output |
||||
* @since 3.0 |
||||
*/ |
||||
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker, |
||||
boolean showDirection) { |
||||
__writer = writer; |
||||
__nologin = suppressLogin; |
||||
__eolMarker = eolMarker; |
||||
__directionMarker = showDirection; |
||||
} |
||||
|
||||
@Override public void protocolCommandSent(ProtocolCommandEvent event) { |
||||
if (__directionMarker) { |
||||
__writer.print("> "); |
||||
} |
||||
if (__nologin) { |
||||
String cmd = event.getCommand(); |
||||
if ("PASS".equalsIgnoreCase(cmd) || "USER".equalsIgnoreCase(cmd)) { |
||||
__writer.print(cmd); |
||||
__writer.println(" *******"); // Don't bother with EOL marker for this!
|
||||
} else { |
||||
final String IMAP_LOGIN = "LOGIN"; |
||||
if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP
|
||||
String msg = event.getMessage(); |
||||
msg = msg.substring(0, msg.indexOf(IMAP_LOGIN) + IMAP_LOGIN.length()); |
||||
__writer.print(msg); |
||||
__writer.println(" *******"); // Don't bother with EOL marker for this!
|
||||
} else { |
||||
__writer.print(getPrintableString(event.getMessage())); |
||||
} |
||||
} |
||||
} else { |
||||
__writer.print(getPrintableString(event.getMessage())); |
||||
} |
||||
__writer.flush(); |
||||
} |
||||
|
||||
private String getPrintableString(String msg) { |
||||
if (__eolMarker == 0) { |
||||
return msg; |
||||
} |
||||
int pos = msg.indexOf(SocketClient.NETASCII_EOL); |
||||
if (pos > 0) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.append(msg.substring(0, pos)); |
||||
sb.append(__eolMarker); |
||||
sb.append(msg.substring(pos)); |
||||
return sb.toString(); |
||||
} |
||||
return msg; |
||||
} |
||||
|
||||
@Override public void protocolReplyReceived(ProtocolCommandEvent event) { |
||||
if (__directionMarker) { |
||||
__writer.print("< "); |
||||
} |
||||
__writer.print(event.getMessage()); |
||||
__writer.flush(); |
||||
} |
||||
} |
||||
|
@ -1,139 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.util.EventObject; |
||||
|
||||
/*** |
||||
* There exists a large class of IETF protocols that work by sending an |
||||
* ASCII text command and arguments to a server, and then receiving an |
||||
* ASCII text reply. For debugging and other purposes, it is extremely |
||||
* useful to log or keep track of the contents of the protocol messages. |
||||
* The ProtocolCommandEvent class coupled with the |
||||
* {@link ProtocolCommandListener} |
||||
* interface facilitate this process. |
||||
* |
||||
* |
||||
* @see ProtocolCommandListener |
||||
* @see ProtocolCommandSupport |
||||
***/ |
||||
|
||||
public class ProtocolCommandEvent extends EventObject { |
||||
private static final long serialVersionUID = 403743538418947240L; |
||||
|
||||
private final int __replyCode; |
||||
private final boolean __isCommand; |
||||
private final String __message, __command; |
||||
|
||||
/*** |
||||
* Creates a ProtocolCommandEvent signalling a command was sent to |
||||
* the server. ProtocolCommandEvents created with this constructor |
||||
* should only be sent after a command has been sent, but before the |
||||
* reply has been received. |
||||
* |
||||
* @param source The source of the event. |
||||
* @param command The string representation of the command type sent, not |
||||
* including the arguments (e.g., "STAT" or "GET"). |
||||
* @param message The entire command string verbatim as sent to the server, |
||||
* including all arguments. |
||||
***/ |
||||
public ProtocolCommandEvent(Object source, String command, String message) { |
||||
super(source); |
||||
__replyCode = 0; |
||||
__message = message; |
||||
__isCommand = true; |
||||
__command = command; |
||||
} |
||||
|
||||
/*** |
||||
* Creates a ProtocolCommandEvent signalling a reply to a command was |
||||
* received. ProtocolCommandEvents created with this constructor |
||||
* should only be sent after a complete command reply has been received |
||||
* fromt a server. |
||||
* |
||||
* @param source The source of the event. |
||||
* @param replyCode The integer code indicating the natureof the reply. |
||||
* This will be the protocol integer value for protocols |
||||
* that use integer reply codes, or the reply class constant |
||||
* corresponding to the reply for protocols like POP3 that use |
||||
* strings like OK rather than integer codes (i.e., POP3Repy.OK). |
||||
* @param message The entire reply as received from the server. |
||||
***/ |
||||
public ProtocolCommandEvent(Object source, int replyCode, String message) { |
||||
super(source); |
||||
__replyCode = replyCode; |
||||
__message = message; |
||||
__isCommand = false; |
||||
__command = null; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the string representation of the command type sent (e.g., "STAT" |
||||
* or "GET"). If the ProtocolCommandEvent is a reply event, then null |
||||
* is returned. |
||||
* |
||||
* @return The string representation of the command type sent, or null |
||||
* if this is a reply event. |
||||
***/ |
||||
public String getCommand() { |
||||
return __command; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the reply code of the received server reply. Undefined if |
||||
* this is not a reply event. |
||||
* |
||||
* @return The reply code of the received server reply. Undefined if |
||||
* not a reply event. |
||||
***/ |
||||
public int getReplyCode() { |
||||
return __replyCode; |
||||
} |
||||
|
||||
/*** |
||||
* Returns true if the ProtocolCommandEvent was generated as a result |
||||
* of sending a command. |
||||
* |
||||
* @return true If the ProtocolCommandEvent was generated as a result |
||||
* of sending a command. False otherwise. |
||||
***/ |
||||
public boolean isCommand() { |
||||
return __isCommand; |
||||
} |
||||
|
||||
/*** |
||||
* Returns true if the ProtocolCommandEvent was generated as a result |
||||
* of receiving a reply. |
||||
* |
||||
* @return true If the ProtocolCommandEvent was generated as a result |
||||
* of receiving a reply. False otherwise. |
||||
***/ |
||||
public boolean isReply() { |
||||
return !isCommand(); |
||||
} |
||||
|
||||
/*** |
||||
* Returns the entire message sent to or received from the server. |
||||
* Includes the line terminator. |
||||
* |
||||
* @return The entire message sent to or received from the server. |
||||
***/ |
||||
public String getMessage() { |
||||
return __message; |
||||
} |
||||
} |
@ -1,58 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClient; |
||||
import java.util.EventListener; |
||||
|
||||
/*** |
||||
* There exists a large class of IETF protocols that work by sending an |
||||
* ASCII text command and arguments to a server, and then receiving an |
||||
* ASCII text reply. For debugging and other purposes, it is extremely |
||||
* useful to log or keep track of the contents of the protocol messages. |
||||
* The ProtocolCommandListener interface coupled with the |
||||
* {@link ProtocolCommandEvent} class facilitate this process. |
||||
* <p> |
||||
* To receive ProtocolCommandEvents, you merely implement the |
||||
* ProtocolCommandListener interface and register the class as a listener |
||||
* with a ProtocolCommandEvent source such as |
||||
* {@link FTPClient}. |
||||
* |
||||
* |
||||
* @see ProtocolCommandEvent |
||||
* @see ProtocolCommandSupport |
||||
***/ |
||||
|
||||
public interface ProtocolCommandListener extends EventListener { |
||||
|
||||
/*** |
||||
* This method is invoked by a ProtocolCommandEvent source after |
||||
* sending a protocol command to a server. |
||||
* |
||||
* @param event The ProtocolCommandEvent fired. |
||||
***/ |
||||
public void protocolCommandSent(ProtocolCommandEvent event); |
||||
|
||||
/*** |
||||
* This method is invoked by a ProtocolCommandEvent source after |
||||
* receiving a reply from a server. |
||||
* |
||||
* @param event The ProtocolCommandEvent fired. |
||||
***/ |
||||
public void protocolReplyReceived(ProtocolCommandEvent event); |
||||
} |
@ -1,123 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.EventListener; |
||||
|
||||
import aria.apache.commons.net.util.ListenerList; |
||||
|
||||
/*** |
||||
* ProtocolCommandSupport is a convenience class for managing a list of |
||||
* ProtocolCommandListeners and firing ProtocolCommandEvents. You can |
||||
* simply delegate ProtocolCommandEvent firing and listener |
||||
* registering/unregistering tasks to this class. |
||||
* |
||||
* |
||||
* @see ProtocolCommandEvent |
||||
* @see ProtocolCommandListener |
||||
***/ |
||||
|
||||
public class ProtocolCommandSupport implements Serializable { |
||||
private static final long serialVersionUID = -8017692739988399978L; |
||||
|
||||
private final Object __source; |
||||
private final ListenerList __listeners; |
||||
|
||||
/*** |
||||
* Creates a ProtocolCommandSupport instance using the indicated source |
||||
* as the source of ProtocolCommandEvents. |
||||
* |
||||
* @param source The source to use for all generated ProtocolCommandEvents. |
||||
***/ |
||||
public ProtocolCommandSupport(Object source) { |
||||
__listeners = new ListenerList(); |
||||
__source = source; |
||||
} |
||||
|
||||
/*** |
||||
* Fires a ProtocolCommandEvent signalling the sending of a command to all |
||||
* registered listeners, invoking their |
||||
* {@link ProtocolCommandListener#protocolCommandSent protocolCommandSent() } |
||||
* methods. |
||||
* |
||||
* @param command The string representation of the command type sent, not |
||||
* including the arguments (e.g., "STAT" or "GET"). |
||||
* @param message The entire command string verbatim as sent to the server, |
||||
* including all arguments. |
||||
***/ |
||||
public void fireCommandSent(String command, String message) { |
||||
ProtocolCommandEvent event; |
||||
|
||||
event = new ProtocolCommandEvent(__source, command, message); |
||||
|
||||
for (EventListener listener : __listeners) { |
||||
((ProtocolCommandListener) listener).protocolCommandSent(event); |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Fires a ProtocolCommandEvent signalling the reception of a command reply |
||||
* to all registered listeners, invoking their |
||||
* {@link ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } |
||||
* methods. |
||||
* |
||||
* @param replyCode The integer code indicating the natureof the reply. |
||||
* This will be the protocol integer value for protocols |
||||
* that use integer reply codes, or the reply class constant |
||||
* corresponding to the reply for protocols like POP3 that use |
||||
* strings like OK rather than integer codes (i.e., POP3Repy.OK). |
||||
* @param message The entire reply as received from the server. |
||||
***/ |
||||
public void fireReplyReceived(int replyCode, String message) { |
||||
ProtocolCommandEvent event; |
||||
event = new ProtocolCommandEvent(__source, replyCode, message); |
||||
|
||||
for (EventListener listener : __listeners) { |
||||
((ProtocolCommandListener) listener).protocolReplyReceived(event); |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Adds a ProtocolCommandListener. |
||||
* |
||||
* @param listener The ProtocolCommandListener to add. |
||||
***/ |
||||
public void addProtocolCommandListener(ProtocolCommandListener listener) { |
||||
__listeners.addListener(listener); |
||||
} |
||||
|
||||
/*** |
||||
* Removes a ProtocolCommandListener. |
||||
* |
||||
* @param listener The ProtocolCommandListener to remove. |
||||
***/ |
||||
public void removeProtocolCommandListener(ProtocolCommandListener listener) { |
||||
__listeners.removeListener(listener); |
||||
} |
||||
|
||||
/*** |
||||
* Returns the number of ProtocolCommandListeners currently registered. |
||||
* |
||||
* @return The number of ProtocolCommandListeners currently registered. |
||||
***/ |
||||
public int getListenerCount() { |
||||
return __listeners.getListenerCount(); |
||||
} |
||||
} |
||||
|
@ -1,869 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.net.InetAddress; |
||||
import java.net.InetSocketAddress; |
||||
import java.net.Proxy; |
||||
import java.net.Socket; |
||||
import java.net.SocketException; |
||||
import java.nio.charset.Charset; |
||||
|
||||
import javax.net.ServerSocketFactory; |
||||
import javax.net.SocketFactory; |
||||
|
||||
/** |
||||
* The SocketClient provides the basic operations that are required of |
||||
* client objects accessing sockets. It is meant to be |
||||
* subclassed to avoid having to rewrite the same code over and over again |
||||
* to open a socket, close a socket, set timeouts, etc. Of special note |
||||
* is the {@link #setSocketFactory setSocketFactory } |
||||
* method, which allows you to control the type of Socket the SocketClient |
||||
* creates for initiating network connections. This is especially useful |
||||
* for adding SSL or proxy support as well as better support for applets. For |
||||
* example, you could create a |
||||
* {@link SocketFactory} that |
||||
* requests browser security capabilities before creating a socket. |
||||
* All classes derived from SocketClient should use the |
||||
* {@link #_socketFactory_ _socketFactory_ } member variable to |
||||
* create Socket and ServerSocket instances rather than instantiating |
||||
* them by directly invoking a constructor. By honoring this contract |
||||
* you guarantee that a user will always be able to provide his own |
||||
* Socket implementations by substituting his own SocketFactory. |
||||
* |
||||
* @see SocketFactory |
||||
*/ |
||||
public abstract class SocketClient { |
||||
/** |
||||
* The end of line character sequence used by most IETF protocols. That |
||||
* is a carriage return followed by a newline: "\r\n" |
||||
*/ |
||||
public static final String NETASCII_EOL = "\r\n"; |
||||
|
||||
/** The default SocketFactory shared by all SocketClient instances. */ |
||||
private static final SocketFactory __DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault(); |
||||
|
||||
/** The default {@link ServerSocketFactory} */ |
||||
private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = |
||||
ServerSocketFactory.getDefault(); |
||||
|
||||
/** |
||||
* A ProtocolCommandSupport object used to manage the registering of |
||||
* ProtocolCommandListeners and the firing of ProtocolCommandEvents. |
||||
*/ |
||||
private ProtocolCommandSupport __commandSupport; |
||||
|
||||
/** The timeout to use after opening a socket. */ |
||||
protected int _timeout_; |
||||
|
||||
/** The socket used for the connection. */ |
||||
protected Socket _socket_; |
||||
|
||||
/** The hostname used for the connection (null = no hostname supplied). */ |
||||
protected String _hostname_; |
||||
|
||||
/** The default port the client should connect to. */ |
||||
protected int _defaultPort_; |
||||
|
||||
/** The socket's InputStream. */ |
||||
protected InputStream _input_; |
||||
|
||||
/** The socket's OutputStream. */ |
||||
protected OutputStream _output_; |
||||
|
||||
/** The socket's SocketFactory. */ |
||||
protected SocketFactory _socketFactory_; |
||||
|
||||
/** The socket's ServerSocket Factory. */ |
||||
protected ServerSocketFactory _serverSocketFactory_; |
||||
|
||||
/** The socket's connect timeout (0 = infinite timeout) */ |
||||
private static final int DEFAULT_CONNECT_TIMEOUT = 0; |
||||
protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; |
||||
|
||||
/** Hint for SO_RCVBUF size */ |
||||
private int receiveBufferSize = -1; |
||||
|
||||
/** Hint for SO_SNDBUF size */ |
||||
private int sendBufferSize = -1; |
||||
|
||||
/** The proxy to use when connecting. */ |
||||
private Proxy connProxy; |
||||
|
||||
/** |
||||
* Charset to use for byte IO. |
||||
*/ |
||||
private Charset charset = Charset.defaultCharset(); |
||||
|
||||
/** |
||||
* Default constructor for SocketClient. Initializes |
||||
* _socket_ to null, _timeout_ to 0, _defaultPort to 0, |
||||
* _isConnected_ to false, charset to {@code Charset.defaultCharset()} |
||||
* and _socketFactory_ to a shared instance of |
||||
* {@link DefaultSocketFactory}. |
||||
*/ |
||||
public SocketClient() { |
||||
_socket_ = null; |
||||
_hostname_ = null; |
||||
_input_ = null; |
||||
_output_ = null; |
||||
_timeout_ = 0; |
||||
_defaultPort_ = 0; |
||||
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
||||
_serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; |
||||
} |
||||
|
||||
/** |
||||
* Because there are so many connect() methods, the _connectAction_() |
||||
* method is provided as a means of performing some action immediately |
||||
* after establishing a connection, rather than reimplementing all |
||||
* of the connect() methods. The last action performed by every |
||||
* connect() method after opening a socket is to call this method. |
||||
* <p> |
||||
* This method sets the timeout on the just opened socket to the default |
||||
* timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, |
||||
* sets _input_ and _output_ to the socket's InputStream and OutputStream |
||||
* respectively, and sets _isConnected_ to true. |
||||
* <p> |
||||
* Subclasses overriding this method should start by calling |
||||
* <code> super._connectAction_() </code> first to ensure the |
||||
* initialization of the aforementioned protected variables. |
||||
* |
||||
* @throws IOException (SocketException) if a problem occurs with the socket |
||||
*/ |
||||
protected void _connectAction_() throws IOException { |
||||
_socket_.setSoTimeout(_timeout_); |
||||
_input_ = _socket_.getInputStream(); |
||||
_output_ = _socket_.getOutputStream(); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the specified port and |
||||
* originating from the current host at a system assigned port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param host The remote host. |
||||
* @param port The port to connect to on the remote host. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
*/ |
||||
public void connect(InetAddress host, int port) throws SocketException, IOException { |
||||
_hostname_ = null; |
||||
_connect(host, port, null, -1); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the specified port and |
||||
* originating from the current host at a system assigned port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param hostname The name of the remote host. |
||||
* @param port The port to connect to on the remote host. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
* @throws java.net.UnknownHostException If the hostname cannot be resolved. |
||||
*/ |
||||
public void connect(String hostname, int port) throws SocketException, IOException { |
||||
_hostname_ = hostname; |
||||
_connect(InetAddress.getByName(hostname), port, null, -1); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the specified port and |
||||
* originating from the specified local address and port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param host The remote host. |
||||
* @param port The port to connect to on the remote host. |
||||
* @param localAddr The local address to use. |
||||
* @param localPort The local port to use. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
*/ |
||||
public void connect(InetAddress host, int port, InetAddress localAddr, int localPort) |
||||
throws SocketException, IOException { |
||||
_hostname_ = null; |
||||
_connect(host, port, localAddr, localPort); |
||||
} |
||||
|
||||
// helper method to allow code to be shared with connect(String,...) methods
|
||||
private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort) |
||||
throws SocketException, IOException { |
||||
_socket_ = _socketFactory_.createSocket(); |
||||
if (receiveBufferSize != -1) { |
||||
_socket_.setReceiveBufferSize(receiveBufferSize); |
||||
} |
||||
if (sendBufferSize != -1) { |
||||
_socket_.setSendBufferSize(sendBufferSize); |
||||
} |
||||
if (localAddr != null) { |
||||
_socket_.bind(new InetSocketAddress(localAddr, localPort)); |
||||
} |
||||
_socket_.connect(new InetSocketAddress(host, port), connectTimeout); |
||||
_connectAction_(); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the specified port and |
||||
* originating from the specified local address and port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param hostname The name of the remote host. |
||||
* @param port The port to connect to on the remote host. |
||||
* @param localAddr The local address to use. |
||||
* @param localPort The local port to use. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
* @throws java.net.UnknownHostException If the hostname cannot be resolved. |
||||
*/ |
||||
public void connect(String hostname, int port, InetAddress localAddr, int localPort) |
||||
throws SocketException, IOException { |
||||
_hostname_ = hostname; |
||||
_connect(InetAddress.getByName(hostname), port, localAddr, localPort); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the current default port |
||||
* and originating from the current host at a system assigned port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param host The remote host. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
*/ |
||||
public void connect(InetAddress host) throws SocketException, IOException { |
||||
_hostname_ = null; |
||||
connect(host, _defaultPort_); |
||||
} |
||||
|
||||
/** |
||||
* Opens a Socket connected to a remote host at the current default |
||||
* port and originating from the current host at a system assigned port. |
||||
* Before returning, {@link #_connectAction_ _connectAction_() } |
||||
* is called to perform connection initialization actions. |
||||
* <p> |
||||
* |
||||
* @param hostname The name of the remote host. |
||||
* @throws SocketException If the socket timeout could not be set. |
||||
* @throws IOException If the socket could not be opened. In most |
||||
* cases you will only want to catch IOException since SocketException is |
||||
* derived from it. |
||||
* @throws java.net.UnknownHostException If the hostname cannot be resolved. |
||||
*/ |
||||
public void connect(String hostname) throws SocketException, IOException { |
||||
connect(hostname, _defaultPort_); |
||||
} |
||||
|
||||
/** |
||||
* Disconnects the socket connection. |
||||
* You should call this method after you've finished using the class
|
||||
* instance and also before you call |
||||
* {@link #connect connect() } |
||||
* again. _isConnected_ is set to false, _socket_ is set to null, |
||||
* _input_ is set to null, and _output_ is set to null. |
||||
* <p> |
||||
* |
||||
* @throws IOException If there is an error closing the socket. |
||||
*/ |
||||
public void disconnect() throws IOException { |
||||
closeQuietly(_socket_); |
||||
closeQuietly(_input_); |
||||
closeQuietly(_output_); |
||||
_socket_ = null; |
||||
_hostname_ = null; |
||||
_input_ = null; |
||||
_output_ = null; |
||||
} |
||||
|
||||
private void closeQuietly(Socket socket) { |
||||
if (socket != null) { |
||||
try { |
||||
socket.close(); |
||||
} catch (IOException e) { |
||||
// Ignored
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private void closeQuietly(Closeable close) { |
||||
if (close != null) { |
||||
try { |
||||
close.close(); |
||||
} catch (IOException e) { |
||||
// Ignored
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the client is currently connected to a server. |
||||
* <p> |
||||
* Delegates to {@link Socket#isConnected()} |
||||
* |
||||
* @return True if the client is currently connected to a server, |
||||
* false otherwise. |
||||
*/ |
||||
public boolean isConnected() { |
||||
if (_socket_ == null) { |
||||
return false; |
||||
} |
||||
|
||||
return _socket_.isConnected(); |
||||
} |
||||
|
||||
/** |
||||
* Make various checks on the socket to test if it is available for use. |
||||
* Note that the only sure test is to use it, but these checks may help |
||||
* in some cases. |
||||
* |
||||
* @return {@code true} if the socket appears to be available for use |
||||
* @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a> |
||||
* @since 3.0 |
||||
*/ |
||||
public boolean isAvailable() { |
||||
if (isConnected()) { |
||||
try { |
||||
if (_socket_.getInetAddress() == null) { |
||||
return false; |
||||
} |
||||
if (_socket_.getPort() == 0) { |
||||
return false; |
||||
} |
||||
if (_socket_.getRemoteSocketAddress() == null) { |
||||
return false; |
||||
} |
||||
if (_socket_.isClosed()) { |
||||
return false; |
||||
} |
||||
/* these aren't exact checks (a Socket can be half-open), |
||||
but since we usually require two-way data transfer, |
||||
we check these here too: */ |
||||
if (_socket_.isInputShutdown()) { |
||||
return false; |
||||
} |
||||
if (_socket_.isOutputShutdown()) { |
||||
return false; |
||||
} |
||||
/* ignore the result, catch exceptions: */ |
||||
_socket_.getInputStream(); |
||||
_socket_.getOutputStream(); |
||||
} catch (IOException ioex) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the default port the SocketClient should connect to when a port |
||||
* is not specified. The {@link #_defaultPort_ _defaultPort_ } |
||||
* variable stores this value. If never set, the default port is equal |
||||
* to zero. |
||||
* <p> |
||||
* |
||||
* @param port The default port to set. |
||||
*/ |
||||
public void setDefaultPort(int port) { |
||||
_defaultPort_ = port; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current value of the default port (stored in |
||||
* {@link #_defaultPort_ _defaultPort_ }). |
||||
* <p> |
||||
* |
||||
* @return The current value of the default port. |
||||
*/ |
||||
public int getDefaultPort() { |
||||
return _defaultPort_; |
||||
} |
||||
|
||||
/** |
||||
* Set the default timeout in milliseconds to use when opening a socket. |
||||
* This value is only used previous to a call to |
||||
* {@link #connect connect()} |
||||
* and should not be confused with {@link #setSoTimeout setSoTimeout()} |
||||
* which operates on an the currently opened socket. _timeout_ contains |
||||
* the new timeout value. |
||||
* <p> |
||||
* |
||||
* @param timeout The timeout in milliseconds to use for the socket |
||||
* connection. |
||||
*/ |
||||
public void setDefaultTimeout(int timeout) { |
||||
_timeout_ = timeout; |
||||
} |
||||
|
||||
/** |
||||
* Returns the default timeout in milliseconds that is used when |
||||
* opening a socket. |
||||
* <p> |
||||
* |
||||
* @return The default timeout in milliseconds that is used when |
||||
* opening a socket. |
||||
*/ |
||||
public int getDefaultTimeout() { |
||||
return _timeout_; |
||||
} |
||||
|
||||
/** |
||||
* Set the timeout in milliseconds of a currently open connection. |
||||
* Only call this method after a connection has been opened |
||||
* by {@link #connect connect()}. |
||||
* <p> |
||||
* To set the initial timeout, use {@link #setDefaultTimeout(int)} instead. |
||||
* |
||||
* @param timeout The timeout in milliseconds to use for the currently |
||||
* open socket connection. |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public void setSoTimeout(int timeout) throws SocketException { |
||||
_socket_.setSoTimeout(timeout); |
||||
} |
||||
|
||||
/** |
||||
* Set the underlying socket send buffer size. |
||||
* <p> |
||||
* |
||||
* @param size The size of the buffer in bytes. |
||||
* @throws SocketException never thrown, but subclasses might want to do so |
||||
* @since 2.0 |
||||
*/ |
||||
public void setSendBufferSize(int size) throws SocketException { |
||||
sendBufferSize = size; |
||||
} |
||||
|
||||
/** |
||||
* Get the current sendBuffer size |
||||
* |
||||
* @return the size, or -1 if not initialised |
||||
* @since 3.0 |
||||
*/ |
||||
protected int getSendBufferSize() { |
||||
return sendBufferSize; |
||||
} |
||||
|
||||
/** |
||||
* Sets the underlying socket receive buffer size. |
||||
* <p> |
||||
* |
||||
* @param size The size of the buffer in bytes. |
||||
* @throws SocketException never (but subclasses may wish to do so) |
||||
* @since 2.0 |
||||
*/ |
||||
public void setReceiveBufferSize(int size) throws SocketException { |
||||
receiveBufferSize = size; |
||||
} |
||||
|
||||
/** |
||||
* Get the current receivedBuffer size |
||||
* |
||||
* @return the size, or -1 if not initialised |
||||
* @since 3.0 |
||||
*/ |
||||
protected int getReceiveBufferSize() { |
||||
return receiveBufferSize; |
||||
} |
||||
|
||||
/** |
||||
* Returns the timeout in milliseconds of the currently opened socket. |
||||
* <p> |
||||
* |
||||
* @return The timeout in milliseconds of the currently opened socket. |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public int getSoTimeout() throws SocketException { |
||||
return _socket_.getSoTimeout(); |
||||
} |
||||
|
||||
/** |
||||
* Enables or disables the Nagle's algorithm (TCP_NODELAY) on the |
||||
* currently opened socket. |
||||
* <p> |
||||
* |
||||
* @param on True if Nagle's algorithm is to be enabled, false if not. |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public void setTcpNoDelay(boolean on) throws SocketException { |
||||
_socket_.setTcpNoDelay(on); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if Nagle's algorithm is enabled on the currently opened |
||||
* socket. |
||||
* <p> |
||||
* |
||||
* @return True if Nagle's algorithm is enabled on the currently opened |
||||
* socket, false otherwise. |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public boolean getTcpNoDelay() throws SocketException { |
||||
return _socket_.getTcpNoDelay(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the SO_KEEPALIVE flag on the currently opened socket. |
||||
* |
||||
* From the Javadocs, the default keepalive time is 2 hours (although this is |
||||
* implementation dependent). It looks as though the Windows WSA sockets implementation |
||||
* allows a specific keepalive value to be set, although this seems not to be the case on |
||||
* other systems. |
||||
* |
||||
* @param keepAlive If true, keepAlive is turned on |
||||
* @throws SocketException if there is a problem with the socket |
||||
* @throws NullPointerException if the socket is not currently open |
||||
* @since 2.2 |
||||
*/ |
||||
public void setKeepAlive(boolean keepAlive) throws SocketException { |
||||
_socket_.setKeepAlive(keepAlive); |
||||
} |
||||
|
||||
/** |
||||
* Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. |
||||
* Delegates to {@link Socket#getKeepAlive()} |
||||
* |
||||
* @return True if SO_KEEPALIVE is enabled. |
||||
* @throws SocketException if there is a problem with the socket |
||||
* @throws NullPointerException if the socket is not currently open |
||||
* @since 2.2 |
||||
*/ |
||||
public boolean getKeepAlive() throws SocketException { |
||||
return _socket_.getKeepAlive(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the SO_LINGER timeout on the currently opened socket. |
||||
* <p> |
||||
* |
||||
* @param on True if linger is to be enabled, false if not. |
||||
* @param val The linger timeout (in hundredths of a second?) |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public void setSoLinger(boolean on, int val) throws SocketException { |
||||
_socket_.setSoLinger(on, val); |
||||
} |
||||
|
||||
/** |
||||
* Returns the current SO_LINGER timeout of the currently opened socket. |
||||
* <p> |
||||
* |
||||
* @return The current SO_LINGER timeout. If SO_LINGER is disabled returns |
||||
* -1. |
||||
* @throws SocketException If the operation fails. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public int getSoLinger() throws SocketException { |
||||
return _socket_.getSoLinger(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the port number of the open socket on the local host used |
||||
* for the connection. |
||||
* Delegates to {@link Socket#getLocalPort()} |
||||
* <p> |
||||
* |
||||
* @return The port number of the open socket on the local host used |
||||
* for the connection. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public int getLocalPort() { |
||||
return _socket_.getLocalPort(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the local address to which the client's socket is bound. |
||||
* Delegates to {@link Socket#getLocalAddress()} |
||||
* <p> |
||||
* |
||||
* @return The local address to which the client's socket is bound. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public InetAddress getLocalAddress() { |
||||
return _socket_.getLocalAddress(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the port number of the remote host to which the client is |
||||
* connected. |
||||
* Delegates to {@link Socket#getPort()} |
||||
* <p> |
||||
* |
||||
* @return The port number of the remote host to which the client is |
||||
* connected. |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public int getRemotePort() { |
||||
return _socket_.getPort(); |
||||
} |
||||
|
||||
/** |
||||
* @return The remote address to which the client is connected. |
||||
* Delegates to {@link Socket#getInetAddress()} |
||||
* @throws NullPointerException if the socket is not currently open |
||||
*/ |
||||
public InetAddress getRemoteAddress() { |
||||
return _socket_.getInetAddress(); |
||||
} |
||||
|
||||
/** |
||||
* Verifies that the remote end of the given socket is connected to the |
||||
* the same host that the SocketClient is currently connected to. This |
||||
* is useful for doing a quick security check when a client needs to |
||||
* accept a connection from a server, such as an FTP data connection or |
||||
* a BSD R command standard error stream. |
||||
* <p> |
||||
* |
||||
* @param socket the item to check against |
||||
* @return True if the remote hosts are the same, false if not. |
||||
*/ |
||||
public boolean verifyRemote(Socket socket) { |
||||
InetAddress host1, host2; |
||||
|
||||
host1 = socket.getInetAddress(); |
||||
host2 = getRemoteAddress(); |
||||
|
||||
return host1.equals(host2); |
||||
} |
||||
|
||||
/** |
||||
* Sets the SocketFactory used by the SocketClient to open socket |
||||
* connections. If the factory value is null, then a default |
||||
* factory is used (only do this to reset the factory after having |
||||
* previously altered it). |
||||
* Any proxy setting is discarded. |
||||
* <p> |
||||
* |
||||
* @param factory The new SocketFactory the SocketClient should use. |
||||
*/ |
||||
public void setSocketFactory(SocketFactory factory) { |
||||
if (factory == null) { |
||||
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; |
||||
} else { |
||||
_socketFactory_ = factory; |
||||
} |
||||
// re-setting the socket factory makes the proxy setting useless,
|
||||
// so set the field to null so that getProxy() doesn't return a
|
||||
// Proxy that we're actually not using.
|
||||
connProxy = null; |
||||
} |
||||
|
||||
/** |
||||
* Sets the ServerSocketFactory used by the SocketClient to open ServerSocket |
||||
* connections. If the factory value is null, then a default |
||||
* factory is used (only do this to reset the factory after having |
||||
* previously altered it). |
||||
* <p> |
||||
* |
||||
* @param factory The new ServerSocketFactory the SocketClient should use. |
||||
* @since 2.0 |
||||
*/ |
||||
public void setServerSocketFactory(ServerSocketFactory factory) { |
||||
if (factory == null) { |
||||
_serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; |
||||
} else { |
||||
_serverSocketFactory_ = factory; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} |
||||
* object's |
||||
* connect() method. |
||||
* |
||||
* @param connectTimeout The connection timeout to use (in ms) |
||||
* @since 2.0 |
||||
*/ |
||||
public void setConnectTimeout(int connectTimeout) { |
||||
this.connectTimeout = connectTimeout; |
||||
} |
||||
|
||||
/** |
||||
* Get the underlying socket connection timeout. |
||||
* |
||||
* @return timeout (in ms) |
||||
* @since 2.0 |
||||
*/ |
||||
public int getConnectTimeout() { |
||||
return connectTimeout; |
||||
} |
||||
|
||||
/** |
||||
* Get the underlying {@link ServerSocketFactory} |
||||
* |
||||
* @return The server socket factory |
||||
* @since 2.2 |
||||
*/ |
||||
public ServerSocketFactory getServerSocketFactory() { |
||||
return _serverSocketFactory_; |
||||
} |
||||
|
||||
/** |
||||
* Adds a ProtocolCommandListener. |
||||
* |
||||
* @param listener The ProtocolCommandListener to add. |
||||
* @since 3.0 |
||||
*/ |
||||
public void addProtocolCommandListener(ProtocolCommandListener listener) { |
||||
getCommandSupport().addProtocolCommandListener(listener); |
||||
} |
||||
|
||||
/** |
||||
* Removes a ProtocolCommandListener. |
||||
* |
||||
* @param listener The ProtocolCommandListener to remove. |
||||
* @since 3.0 |
||||
*/ |
||||
public void removeProtocolCommandListener(ProtocolCommandListener listener) { |
||||
getCommandSupport().removeProtocolCommandListener(listener); |
||||
} |
||||
|
||||
/** |
||||
* If there are any listeners, send them the reply details. |
||||
* |
||||
* @param replyCode the code extracted from the reply |
||||
* @param reply the full reply text |
||||
* @since 3.0 |
||||
*/ |
||||
protected void fireReplyReceived(int replyCode, String reply) { |
||||
if (getCommandSupport().getListenerCount() > 0) { |
||||
getCommandSupport().fireReplyReceived(replyCode, reply); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* If there are any listeners, send them the command details. |
||||
* |
||||
* @param command the command name |
||||
* @param message the complete message, including command name |
||||
* @since 3.0 |
||||
*/ |
||||
protected void fireCommandSent(String command, String message) { |
||||
if (getCommandSupport().getListenerCount() > 0) { |
||||
getCommandSupport().fireCommandSent(command, message); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create the CommandSupport instance if required |
||||
*/ |
||||
protected void createCommandSupport() { |
||||
__commandSupport = new ProtocolCommandSupport(this); |
||||
} |
||||
|
||||
/** |
||||
* Subclasses can override this if they need to provide their own |
||||
* instance field for backwards compatibilty. |
||||
* |
||||
* @return the CommandSupport instance, may be {@code null} |
||||
* @since 3.0 |
||||
*/ |
||||
protected ProtocolCommandSupport getCommandSupport() { |
||||
return __commandSupport; |
||||
} |
||||
|
||||
/** |
||||
* Sets the proxy for use with all the connections. |
||||
* The proxy is used for connections established after the |
||||
* call to this method. |
||||
* |
||||
* @param proxy the new proxy for connections. |
||||
* @since 3.2 |
||||
*/ |
||||
public void setProxy(Proxy proxy) { |
||||
setSocketFactory(new DefaultSocketFactory(proxy)); |
||||
connProxy = proxy; |
||||
} |
||||
|
||||
/** |
||||
* Gets the proxy for use with all the connections. |
||||
* |
||||
* @return the current proxy for connections. |
||||
*/ |
||||
public Proxy getProxy() { |
||||
return connProxy; |
||||
} |
||||
|
||||
/** |
||||
* Gets the charset name. |
||||
* |
||||
* @return the charset. |
||||
* @since 3.3 |
||||
* @deprecated Since the code now requires Java 1.6 as a mininmum |
||||
*/ |
||||
@Deprecated public String getCharsetName() { |
||||
return charset.name(); |
||||
} |
||||
|
||||
/** |
||||
* Gets the charset. |
||||
* |
||||
* @return the charset. |
||||
* @since 3.3 |
||||
*/ |
||||
public Charset getCharset() { |
||||
return charset; |
||||
} |
||||
|
||||
/** |
||||
* Sets the charset. |
||||
* |
||||
* @param charset the charset. |
||||
* @since 3.3 |
||||
*/ |
||||
public void setCharset(Charset charset) { |
||||
this.charset = charset; |
||||
} |
||||
|
||||
/* |
||||
* N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility, |
||||
* so the abstract method is needed to pass the instance to the methods which were moved here. |
||||
*/ |
||||
} |
||||
|
||||
|
@ -1,34 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* This interface adds the aspect of configurability by means of |
||||
* a supplied FTPClientConfig object to other classes in the |
||||
* system, especially listing parsers. |
||||
*/ |
||||
public interface Configurable { |
||||
|
||||
/** |
||||
* @param config the object containing the configuration data |
||||
* @throws IllegalArgumentException if the elements of the |
||||
* <code>config</code> are somehow inadequate to configure the |
||||
* Configurable object. |
||||
*/ |
||||
public void configure(FTPClientConfig config); |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,713 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import aria.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl; |
||||
import aria.apache.commons.net.ftp.parser.FTPTimestampParserImpl; |
||||
import java.text.DateFormatSymbols; |
||||
import java.util.Collection; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.StringTokenizer; |
||||
import java.util.TreeMap; |
||||
|
||||
/** |
||||
* <p> |
||||
* This class implements an alternate means of configuring the |
||||
* {@link FTPClient FTPClient} object and |
||||
* also subordinate objects which it uses. Any class implementing the |
||||
* {@link Configurable Configurable } |
||||
* interface can be configured by this object. |
||||
* </p><p> |
||||
* In particular this class was designed primarily to support configuration |
||||
* of FTP servers which express file timestamps in formats and languages |
||||
* other than those for the US locale, which although it is the most common |
||||
* is not universal. Unfortunately, nothing in the FTP spec allows this to |
||||
* be determined in an automated way, so manual configuration such as this |
||||
* is necessary. |
||||
* </p><p> |
||||
* This functionality was designed to allow existing clients to work exactly |
||||
* as before without requiring use of this component. This component should |
||||
* only need to be explicitly invoked by the user of this package for problem |
||||
* cases that previous implementations could not solve. |
||||
* </p> |
||||
* <h3>Examples of use of FTPClientConfig</h3> |
||||
* Use cases: |
||||
* You are trying to access a server that |
||||
* <ul> |
||||
* <li>lists files with timestamps that use month names in languages other |
||||
* than English</li> |
||||
* <li>lists files with timestamps that use date formats other |
||||
* than the American English "standard" <code>MM dd yyyy</code></li> |
||||
* <li>is in different timezone and you need accurate timestamps for |
||||
* dependency checking as in Ant</li> |
||||
* </ul> |
||||
* <p> |
||||
* Unpaged (whole list) access on a UNIX server that uses French month names |
||||
* but uses the "standard" <code>MMM d yyyy</code> date formatting |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); |
||||
* conf.setServerLanguageCode("fr"); |
||||
* f.configure(conf); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = listFiles(directory); |
||||
* </pre> |
||||
* <p> |
||||
* Paged access on a UNIX server that uses Danish month names |
||||
* and "European" date formatting in Denmark's time zone, when you |
||||
* are in some other time zone. |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); |
||||
* conf.setServerLanguageCode("da"); |
||||
* conf.setDefaultDateFormat("d MMM yyyy"); |
||||
* conf.setRecentDateFormat("d MMM HH:mm"); |
||||
* conf.setTimeZoneId("Europe/Copenhagen"); |
||||
* f.configure(conf); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPListParseEngine engine = |
||||
* f.initiateListParsing("com.whatever.YourOwnParser", directory); |
||||
* |
||||
* while (engine.hasNext()) { |
||||
* FTPFile[] files = engine.getNext(25); // "page size" you want
|
||||
* //do whatever you want with these files, display them, etc.
|
||||
* //expensive FTPFile objects not created until needed.
|
||||
* } |
||||
* </pre> |
||||
* <p> |
||||
* Unpaged (whole list) access on a VMS server that uses month names |
||||
* in a language not {@link #getSupportedLanguageCodes() supported} by the system. |
||||
* but uses the "standard" <code>MMM d yyyy</code> date formatting |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS); |
||||
* conf.setShortMonthNames( |
||||
* "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des"); |
||||
* f.configure(conf); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = listFiles(directory); |
||||
* </pre> |
||||
* <p> |
||||
* Unpaged (whole list) access on a Windows-NT server in a different time zone. |
||||
* (Note, since the NT Format uses numeric date formatting, language issues |
||||
* are irrelevant here). |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT); |
||||
* conf.setTimeZoneId("America/Denver"); |
||||
* f.configure(conf); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = listFiles(directory); |
||||
* </pre> |
||||
* Unpaged (whole list) access on a Windows-NT server in a different time zone |
||||
* but which has been configured to use a unix-style listing format. |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); |
||||
* conf.setTimeZoneId("America/Denver"); |
||||
* f.configure(conf); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = listFiles(directory); |
||||
* </pre> |
||||
* |
||||
* @see Configurable |
||||
* @see FTPClient |
||||
* @see FTPTimestampParserImpl#configure(FTPClientConfig) |
||||
* @see ConfigurableFTPFileEntryParserImpl |
||||
* @since 1.4 |
||||
*/ |
||||
public class FTPClientConfig { |
||||
|
||||
/** |
||||
* Identifier by which a unix-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_UNIX = "UNIX"; |
||||
|
||||
/** |
||||
* Identifier for alternate UNIX parser; same as {@link #SYST_UNIX} but leading spaces are |
||||
* trimmed from file names. This is to maintain backwards compatibility with |
||||
* the original behaviour of the parser which ignored multiple spaces between the date |
||||
* and the start of the file name. |
||||
* |
||||
* @since 3.4 |
||||
*/ |
||||
public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; |
||||
|
||||
/** |
||||
* Identifier by which a vms-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_VMS = "VMS"; |
||||
|
||||
/** |
||||
* Identifier by which a WindowsNT-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_NT = "WINDOWS"; |
||||
|
||||
/** |
||||
* Identifier by which an OS/2-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_OS2 = "OS/2"; |
||||
|
||||
/** |
||||
* Identifier by which an OS/400-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_OS400 = "OS/400"; |
||||
|
||||
/** |
||||
* Identifier by which an AS/400-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_AS400 = "AS/400"; |
||||
|
||||
/** |
||||
* Identifier by which an MVS-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
*/ |
||||
public static final String SYST_MVS = "MVS"; |
||||
|
||||
/** |
||||
* Some servers return an "UNKNOWN Type: L8" message |
||||
* in response to the SYST command. We set these to be a Unix-type system. |
||||
* This may happen if the ftpd in question was compiled without system |
||||
* information. |
||||
* |
||||
* NET-230 - Updated to be UPPERCASE so that the check done in |
||||
* createFileEntryParser will succeed. |
||||
* |
||||
* @since 1.5 |
||||
*/ |
||||
public static final String SYST_L8 = "TYPE: L8"; |
||||
|
||||
/** |
||||
* Identifier by which an Netware-based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
* |
||||
* @since 1.5 |
||||
*/ |
||||
public static final String SYST_NETWARE = "NETWARE"; |
||||
|
||||
/** |
||||
* Identifier by which a Mac pre OS-X -based ftp server is known throughout |
||||
* the commons-net ftp system. |
||||
* |
||||
* @since 3.1 |
||||
*/ |
||||
// Full string is "MACOS Peter's Server"; the substring below should be enough
|
||||
public static final String SYST_MACOS_PETER = "MACOS PETER"; // NET-436
|
||||
|
||||
private final String serverSystemKey; |
||||
private String defaultDateFormatStr = null; |
||||
private String recentDateFormatStr = null; |
||||
private boolean lenientFutureDates = true; // NET-407
|
||||
private String serverLanguageCode = null; |
||||
private String shortMonthNames = null; |
||||
private String serverTimeZoneId = null; |
||||
private boolean saveUnparseableEntries = false; |
||||
|
||||
/** |
||||
* The main constructor for an FTPClientConfig object |
||||
* |
||||
* @param systemKey key representing system type of the server being |
||||
* connected to. See {@link #getServerSystemKey() serverSystemKey} |
||||
* If set to the empty string, then FTPClient uses the system type returned by the server. |
||||
* However this is not recommended for general use; |
||||
* the correct system type should be set if it is known. |
||||
*/ |
||||
public FTPClientConfig(String systemKey) { |
||||
this.serverSystemKey = systemKey; |
||||
} |
||||
|
||||
/** |
||||
* Convenience constructor mainly for use in testing. |
||||
* Constructs a UNIX configuration. |
||||
*/ |
||||
public FTPClientConfig() { |
||||
this(SYST_UNIX); |
||||
} |
||||
|
||||
/** |
||||
* Constructor which allows setting of the format string member fields |
||||
* |
||||
* @param systemKey key representing system type of the server being |
||||
* connected to. See |
||||
* {@link #getServerSystemKey() serverSystemKey} |
||||
* @param defaultDateFormatStr See |
||||
* {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} |
||||
* @param recentDateFormatStr See |
||||
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} |
||||
* @since 3.6 |
||||
*/ |
||||
public FTPClientConfig(String systemKey, String defaultDateFormatStr, |
||||
String recentDateFormatStr) { |
||||
this(systemKey); |
||||
this.defaultDateFormatStr = defaultDateFormatStr; |
||||
this.recentDateFormatStr = recentDateFormatStr; |
||||
} |
||||
|
||||
/** |
||||
* Constructor which allows setting of most member fields |
||||
* |
||||
* @param systemKey key representing system type of the server being |
||||
* connected to. See |
||||
* {@link #getServerSystemKey() serverSystemKey} |
||||
* @param defaultDateFormatStr See |
||||
* {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} |
||||
* @param recentDateFormatStr See |
||||
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} |
||||
* @param serverLanguageCode See |
||||
* {@link #setServerLanguageCode(String) serverLanguageCode} |
||||
* @param shortMonthNames See |
||||
* {@link #setShortMonthNames(String) shortMonthNames} |
||||
* @param serverTimeZoneId See |
||||
* {@link #setServerTimeZoneId(String) serverTimeZoneId} |
||||
*/ |
||||
public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr, |
||||
String serverLanguageCode, String shortMonthNames, String serverTimeZoneId) { |
||||
this(systemKey); |
||||
this.defaultDateFormatStr = defaultDateFormatStr; |
||||
this.recentDateFormatStr = recentDateFormatStr; |
||||
this.serverLanguageCode = serverLanguageCode; |
||||
this.shortMonthNames = shortMonthNames; |
||||
this.serverTimeZoneId = serverTimeZoneId; |
||||
} |
||||
|
||||
/** |
||||
* Constructor which allows setting of all member fields |
||||
* |
||||
* @param systemKey key representing system type of the server being |
||||
* connected to. See |
||||
* {@link #getServerSystemKey() serverSystemKey} |
||||
* @param defaultDateFormatStr See |
||||
* {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} |
||||
* @param recentDateFormatStr See |
||||
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} |
||||
* @param serverLanguageCode See |
||||
* {@link #setServerLanguageCode(String) serverLanguageCode} |
||||
* @param shortMonthNames See |
||||
* {@link #setShortMonthNames(String) shortMonthNames} |
||||
* @param serverTimeZoneId See |
||||
* {@link #setServerTimeZoneId(String) serverTimeZoneId} |
||||
* @param lenientFutureDates See |
||||
* {@link #setLenientFutureDates(boolean) lenientFutureDates} |
||||
* @param saveUnparseableEntries See |
||||
* {@link #setUnparseableEntries(boolean) saveUnparseableEntries} |
||||
*/ |
||||
public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr, |
||||
String serverLanguageCode, String shortMonthNames, String serverTimeZoneId, |
||||
boolean lenientFutureDates, boolean saveUnparseableEntries) { |
||||
this(systemKey); |
||||
this.defaultDateFormatStr = defaultDateFormatStr; |
||||
this.lenientFutureDates = lenientFutureDates; |
||||
this.recentDateFormatStr = recentDateFormatStr; |
||||
this.saveUnparseableEntries = saveUnparseableEntries; |
||||
this.serverLanguageCode = serverLanguageCode; |
||||
this.shortMonthNames = shortMonthNames; |
||||
this.serverTimeZoneId = serverTimeZoneId; |
||||
} |
||||
|
||||
// Copy constructor, intended for use by FTPClient only
|
||||
FTPClientConfig(String systemKey, FTPClientConfig config) { |
||||
this.serverSystemKey = systemKey; |
||||
this.defaultDateFormatStr = config.defaultDateFormatStr; |
||||
this.lenientFutureDates = config.lenientFutureDates; |
||||
this.recentDateFormatStr = config.recentDateFormatStr; |
||||
this.saveUnparseableEntries = config.saveUnparseableEntries; |
||||
this.serverLanguageCode = config.serverLanguageCode; |
||||
this.serverTimeZoneId = config.serverTimeZoneId; |
||||
this.shortMonthNames = config.shortMonthNames; |
||||
} |
||||
|
||||
/** |
||||
* Copy constructor |
||||
* |
||||
* @param config source |
||||
* @since 3.6 |
||||
*/ |
||||
public FTPClientConfig(FTPClientConfig config) { |
||||
this.serverSystemKey = config.serverSystemKey; |
||||
this.defaultDateFormatStr = config.defaultDateFormatStr; |
||||
this.lenientFutureDates = config.lenientFutureDates; |
||||
this.recentDateFormatStr = config.recentDateFormatStr; |
||||
this.saveUnparseableEntries = config.saveUnparseableEntries; |
||||
this.serverLanguageCode = config.serverLanguageCode; |
||||
this.serverTimeZoneId = config.serverTimeZoneId; |
||||
this.shortMonthNames = config.shortMonthNames; |
||||
} |
||||
|
||||
private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<String, Object>(); |
||||
|
||||
static { |
||||
|
||||
// if there are other commonly used month name encodings which
|
||||
// correspond to particular locales, please add them here.
|
||||
|
||||
// many locales code short names for months as all three letters
|
||||
// these we handle simply.
|
||||
LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); |
||||
LANGUAGE_CODE_MAP.put("de", Locale.GERMAN); |
||||
LANGUAGE_CODE_MAP.put("it", Locale.ITALIAN); |
||||
LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish
|
||||
LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese
|
||||
LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish
|
||||
LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish
|
||||
LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian
|
||||
LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch
|
||||
LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian
|
||||
LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian
|
||||
LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian
|
||||
LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak
|
||||
LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian
|
||||
|
||||
// some don't
|
||||
LANGUAGE_CODE_MAP.put("fr", |
||||
"jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french
|
||||
} |
||||
|
||||
/** |
||||
* Getter for the serverSystemKey property. This property |
||||
* specifies the general type of server to which the client connects. |
||||
* Should be either one of the <code>FTPClientConfig.SYST_*</code> codes |
||||
* or else the fully qualified class name of a parser implementing both |
||||
* the <code>FTPFileEntryParser</code> and <code>Configurable</code> |
||||
* interfaces. |
||||
* |
||||
* @return Returns the serverSystemKey property. |
||||
*/ |
||||
public String getServerSystemKey() { |
||||
return serverSystemKey; |
||||
} |
||||
|
||||
/** |
||||
* getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} |
||||
* property. |
||||
* |
||||
* @return Returns the defaultDateFormatStr property. |
||||
*/ |
||||
public String getDefaultDateFormatStr() { |
||||
return defaultDateFormatStr; |
||||
} |
||||
|
||||
/** |
||||
* getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. |
||||
* |
||||
* @return Returns the recentDateFormatStr property. |
||||
*/ |
||||
|
||||
public String getRecentDateFormatStr() { |
||||
return recentDateFormatStr; |
||||
} |
||||
|
||||
/** |
||||
* getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. |
||||
* |
||||
* @return Returns the serverTimeZoneId property. |
||||
*/ |
||||
public String getServerTimeZoneId() { |
||||
return serverTimeZoneId; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* getter for the {@link #setShortMonthNames(String) shortMonthNames} |
||||
* property. |
||||
* </p> |
||||
* |
||||
* @return Returns the shortMonthNames. |
||||
*/ |
||||
public String getShortMonthNames() { |
||||
return shortMonthNames; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. |
||||
* </p> |
||||
* |
||||
* @return Returns the serverLanguageCode property. |
||||
*/ |
||||
public String getServerLanguageCode() { |
||||
return serverLanguageCode; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. |
||||
* </p> |
||||
* |
||||
* @return Returns the lenientFutureDates. |
||||
* @since 1.5 |
||||
*/ |
||||
public boolean isLenientFutureDates() { |
||||
return lenientFutureDates; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the defaultDateFormatStr property. This property |
||||
* specifies the main date format that will be used by a parser configured |
||||
* by this configuration to parse file timestamps. If this is not |
||||
* specified, such a parser will use as a default value, the most commonly |
||||
* used format which will be in as used in <code>en_US</code> locales. |
||||
* </p><p> |
||||
* This should be in the format described for |
||||
* <code>java.text.SimpleDateFormat</code>. |
||||
* property. |
||||
* </p> |
||||
* |
||||
* @param defaultDateFormatStr The defaultDateFormatStr to set. |
||||
*/ |
||||
public void setDefaultDateFormatStr(String defaultDateFormatStr) { |
||||
this.defaultDateFormatStr = defaultDateFormatStr; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the recentDateFormatStr property. This property |
||||
* specifies a secondary date format that will be used by a parser |
||||
* configured by this configuration to parse file timestamps, typically |
||||
* those less than a year old. If this is not specified, such a parser |
||||
* will not attempt to parse using an alternate format. |
||||
* </p> |
||||
* <p> |
||||
* This is used primarily in unix-based systems. |
||||
* </p> |
||||
* <p> |
||||
* This should be in the format described for |
||||
* <code>java.text.SimpleDateFormat</code>. |
||||
* </p> |
||||
* |
||||
* @param recentDateFormatStr The recentDateFormatStr to set. |
||||
*/ |
||||
public void setRecentDateFormatStr(String recentDateFormatStr) { |
||||
this.recentDateFormatStr = recentDateFormatStr; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the lenientFutureDates property. This boolean property |
||||
* (default: false) only has meaning when a |
||||
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} property |
||||
* has been set. In that case, if this property is set true, then the |
||||
* parser, when it encounters a listing parseable with the recent date |
||||
* format, will only consider a date to belong to the previous year if |
||||
* it is more than one day in the future. This will allow all |
||||
* out-of-synch situations (whether based on "slop" - i.e. servers simply |
||||
* out of synch with one another or because of time zone differences - |
||||
* but in the latter case it is highly recommended to use the |
||||
* {@link #setServerTimeZoneId(String) serverTimeZoneId} property |
||||
* instead) to resolve correctly. |
||||
* </p><p> |
||||
* This is used primarily in unix-based systems. |
||||
* </p> |
||||
* |
||||
* @param lenientFutureDates set true to compensate for out-of-synch |
||||
* conditions. |
||||
*/ |
||||
public void setLenientFutureDates(boolean lenientFutureDates) { |
||||
this.lenientFutureDates = lenientFutureDates; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the serverTimeZoneId property. This property |
||||
* allows a time zone to be specified corresponding to that known to be |
||||
* used by an FTP server in file listings. This might be particularly |
||||
* useful to clients such as Ant that try to use these timestamps for |
||||
* dependency checking. |
||||
* </p><p> |
||||
* This should be one of the identifiers used by |
||||
* <code>java.util.TimeZone</code> to refer to time zones, for example, |
||||
* <code>America/Chicago</code> or <code>Asia/Rangoon</code>. |
||||
* </p> |
||||
* |
||||
* @param serverTimeZoneId The serverTimeZoneId to set. |
||||
*/ |
||||
public void setServerTimeZoneId(String serverTimeZoneId) { |
||||
this.serverTimeZoneId = serverTimeZoneId; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the shortMonthNames property. |
||||
* This property allows the user to specify a set of month names |
||||
* used by the server that is different from those that may be |
||||
* specified using the {@link #setServerLanguageCode(String) serverLanguageCode} |
||||
* property. |
||||
* </p><p> |
||||
* This should be a string containing twelve strings each composed of |
||||
* three characters, delimited by pipe (|) characters. Currently, |
||||
* only 8-bit ASCII characters are known to be supported. For example, |
||||
* a set of month names used by a hypothetical Icelandic FTP server might |
||||
* conceivably be specified as |
||||
* <code>"jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des"</code>. |
||||
* </p> |
||||
* |
||||
* @param shortMonthNames The value to set to the shortMonthNames property. |
||||
*/ |
||||
public void setShortMonthNames(String shortMonthNames) { |
||||
this.shortMonthNames = shortMonthNames; |
||||
} |
||||
|
||||
/** |
||||
* <p> |
||||
* setter for the serverLanguageCode property. This property allows |
||||
* user to specify a |
||||
* <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt"> |
||||
* two-letter ISO-639 language code</a> that will be used to |
||||
* configure the set of month names used by the file timestamp parser. |
||||
* If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} |
||||
* is specified, parsing will assume English month names, which may or |
||||
* may not be significant, depending on whether the date format(s) |
||||
* specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} |
||||
* and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using |
||||
* numeric or alphabetic month names. |
||||
* </p> |
||||
* <p>If the code supplied is not supported here, <code>en_US</code> |
||||
* month names will be used. We are supporting here those language |
||||
* codes which, when a <code> java.util.Locale</code> is constucted |
||||
* using it, and a <code>java.text.SimpleDateFormat</code> is |
||||
* constructed using that Locale, the array returned by the |
||||
* SimpleDateFormat's <code>getShortMonths()</code> method consists |
||||
* solely of three 8-bit ASCII character strings. Additionally, |
||||
* languages which do not meet this requirement are included if a |
||||
* common alternative set of short month names is known to be used. |
||||
* This means that users who can tell us of additional such encodings |
||||
* may get them added to the list of supported languages by contacting |
||||
* the Apache Commons Net team. |
||||
* </p> |
||||
* <p><strong> |
||||
* Please note that this attribute will NOT be used to determine a |
||||
* locale-based date format for the language. </strong> |
||||
* Experience has shown that many if not most FTP servers outside the |
||||
* United States employ the standard <code>en_US</code> date format |
||||
* orderings of <code>MMM d yyyy</code> and <code>MMM d HH:mm</code> |
||||
* and attempting to deduce this automatically here would cause more |
||||
* problems than it would solve. The date format must be changed |
||||
* via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or |
||||
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. |
||||
* </p> |
||||
* |
||||
* @param serverLanguageCode The value to set to the serverLanguageCode property. |
||||
*/ |
||||
public void setServerLanguageCode(String serverLanguageCode) { |
||||
this.serverLanguageCode = serverLanguageCode; |
||||
} |
||||
|
||||
/** |
||||
* Looks up the supplied language code in the internally maintained table of |
||||
* language codes. Returns a DateFormatSymbols object configured with |
||||
* short month names corresponding to the code. If there is no corresponding |
||||
* entry in the table, the object returned will be that for |
||||
* <code>Locale.US</code> |
||||
* |
||||
* @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} |
||||
* @return a DateFormatSymbols object configured with short month names |
||||
* corresponding to the supplied code, or with month names for |
||||
* <code>Locale.US</code> if there is no corresponding entry in the internal |
||||
* table. |
||||
*/ |
||||
public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) { |
||||
Object lang = LANGUAGE_CODE_MAP.get(languageCode); |
||||
if (lang != null) { |
||||
if (lang instanceof Locale) { |
||||
return new DateFormatSymbols((Locale) lang); |
||||
} else if (lang instanceof String) { |
||||
return getDateFormatSymbols((String) lang); |
||||
} |
||||
} |
||||
return new DateFormatSymbols(Locale.US); |
||||
} |
||||
|
||||
/** |
||||
* Returns a DateFormatSymbols object configured with short month names |
||||
* as in the supplied string |
||||
* |
||||
* @param shortmonths This should be as described in |
||||
* {@link #setShortMonthNames(String) shortMonthNames} |
||||
* @return a DateFormatSymbols object configured with short month names |
||||
* as in the supplied string |
||||
*/ |
||||
public static DateFormatSymbols getDateFormatSymbols(String shortmonths) { |
||||
String[] months = splitShortMonthString(shortmonths); |
||||
DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); |
||||
dfs.setShortMonths(months); |
||||
return dfs; |
||||
} |
||||
|
||||
private static String[] splitShortMonthString(String shortmonths) { |
||||
StringTokenizer st = new StringTokenizer(shortmonths, "|"); |
||||
int monthcnt = st.countTokens(); |
||||
if (12 != monthcnt) { |
||||
throw new IllegalArgumentException("expecting a pipe-delimited string containing 12 tokens"); |
||||
} |
||||
String[] months = new String[13]; |
||||
int pos = 0; |
||||
while (st.hasMoreTokens()) { |
||||
months[pos++] = st.nextToken(); |
||||
} |
||||
months[pos] = ""; |
||||
return months; |
||||
} |
||||
|
||||
/** |
||||
* Returns a Collection of all the language codes currently supported |
||||
* by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} |
||||
* for a functional descrption of language codes within this system. |
||||
* |
||||
* @return a Collection of all the language codes currently supported |
||||
* by this class
|
||||
*/ |
||||
public static Collection<String> getSupportedLanguageCodes() { |
||||
return LANGUAGE_CODE_MAP.keySet(); |
||||
} |
||||
|
||||
/** |
||||
* Allow list parsing methods to create basic FTPFile entries if parsing fails. |
||||
* <p> |
||||
* In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} |
||||
* and {@link FTPFile#isValid()} will return {@code false} |
||||
* |
||||
* @param saveUnparseable if true, then create FTPFile entries if parsing fails |
||||
* @since 3.4 |
||||
*/ |
||||
public void setUnparseableEntries(boolean saveUnparseable) { |
||||
this.saveUnparseableEntries = saveUnparseable; |
||||
} |
||||
|
||||
/** |
||||
* @return true if list parsing should return FTPFile entries even for unparseable response lines |
||||
* <p> |
||||
* If true, the FTPFile for any unparseable entries will contain only the unparsed entry |
||||
* {@link FTPFile#getRawListing()} and {@link FTPFile#isValid()} will return {@code false} |
||||
* @since 3.4 |
||||
*/ |
||||
public boolean getUnparseableEntries() { |
||||
return this.saveUnparseableEntries; |
||||
} |
||||
} |
@ -1,75 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* @since 3.3 |
||||
*/ |
||||
public enum FTPCmd { |
||||
ABOR, ACCT, ALLO, APPE, CDUP, CWD, DELE, EPRT, EPSV, FEAT, HELP, LIST, MDTM, MFMT, MKD, MLSD, MLST, MODE, NLST, NOOP, PASS, PASV, PORT, PWD, QUIT, REIN, REST, RETR, RMD, RNFR, RNTO, SITE, SMNT, STAT, STOR, STOU, STRU, SYST, TYPE, USER,; |
||||
|
||||
// Aliases
|
||||
|
||||
public static final FTPCmd ABORT = ABOR; |
||||
public static final FTPCmd ACCOUNT = ACCT; |
||||
public static final FTPCmd ALLOCATE = ALLO; |
||||
public static final FTPCmd APPEND = APPE; |
||||
public static final FTPCmd CHANGE_TO_PARENT_DIRECTORY = CDUP; |
||||
public static final FTPCmd CHANGE_WORKING_DIRECTORY = CWD; |
||||
public static final FTPCmd DATA_PORT = PORT; |
||||
public static final FTPCmd DELETE = DELE; |
||||
public static final FTPCmd FEATURES = FEAT; |
||||
public static final FTPCmd FILE_STRUCTURE = STRU; |
||||
public static final FTPCmd GET_MOD_TIME = MDTM; |
||||
public static final FTPCmd LOGOUT = QUIT; |
||||
public static final FTPCmd MAKE_DIRECTORY = MKD; |
||||
public static final FTPCmd MOD_TIME = MDTM; |
||||
public static final FTPCmd NAME_LIST = NLST; |
||||
public static final FTPCmd PASSIVE = PASV; |
||||
public static final FTPCmd PASSWORD = PASS; |
||||
public static final FTPCmd PRINT_WORKING_DIRECTORY = PWD; |
||||
public static final FTPCmd REINITIALIZE = REIN; |
||||
public static final FTPCmd REMOVE_DIRECTORY = RMD; |
||||
public static final FTPCmd RENAME_FROM = RNFR; |
||||
public static final FTPCmd RENAME_TO = RNTO; |
||||
public static final FTPCmd REPRESENTATION_TYPE = TYPE; |
||||
public static final FTPCmd RESTART = REST; |
||||
public static final FTPCmd RETRIEVE = RETR; |
||||
public static final FTPCmd SET_MOD_TIME = MFMT; |
||||
public static final FTPCmd SITE_PARAMETERS = SITE; |
||||
public static final FTPCmd STATUS = STAT; |
||||
public static final FTPCmd STORE = STOR; |
||||
public static final FTPCmd STORE_UNIQUE = STOU; |
||||
public static final FTPCmd STRUCTURE_MOUNT = SMNT; |
||||
public static final FTPCmd SYSTEM = SYST; |
||||
public static final FTPCmd TRANSFER_MODE = MODE; |
||||
public static final FTPCmd USERNAME = USER; |
||||
|
||||
/** |
||||
* Retrieve the FTP protocol command string corresponding to a specified |
||||
* command code. |
||||
* |
||||
* @return The FTP protcol command string corresponding to a specified |
||||
* command code. |
||||
*/ |
||||
public final String getCommand() { |
||||
return this.name(); |
||||
} |
||||
|
||||
} |
@ -1,170 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* FTPCommand stores a set of constants for FTP command codes. To interpret |
||||
* the meaning of the codes, familiarity with RFC 959 is assumed. |
||||
* The mnemonic constant names are transcriptions from the code descriptions |
||||
* of RFC 959. For those who think in terms of the actual FTP commands, |
||||
* a set of constants such as {@link #USER USER } are provided |
||||
* where the constant name is the same as the FTP command. |
||||
* |
||||
* @deprecated use {@link FTPCmd} instead |
||||
*/ |
||||
@Deprecated public final class FTPCommand { |
||||
|
||||
public static final int USER = 0; |
||||
public static final int PASS = 1; |
||||
public static final int ACCT = 2; |
||||
public static final int CWD = 3; |
||||
public static final int CDUP = 4; |
||||
public static final int SMNT = 5; |
||||
public static final int REIN = 6; |
||||
public static final int QUIT = 7; |
||||
public static final int PORT = 8; |
||||
public static final int PASV = 9; |
||||
public static final int TYPE = 10; |
||||
public static final int STRU = 11; |
||||
public static final int MODE = 12; |
||||
public static final int RETR = 13; |
||||
public static final int STOR = 14; |
||||
public static final int STOU = 15; |
||||
public static final int APPE = 16; |
||||
public static final int ALLO = 17; |
||||
public static final int REST = 18; |
||||
public static final int RNFR = 19; |
||||
public static final int RNTO = 20; |
||||
public static final int ABOR = 21; |
||||
public static final int DELE = 22; |
||||
public static final int RMD = 23; |
||||
public static final int MKD = 24; |
||||
public static final int PWD = 25; |
||||
public static final int LIST = 26; |
||||
public static final int NLST = 27; |
||||
public static final int SITE = 28; |
||||
public static final int SYST = 29; |
||||
public static final int STAT = 30; |
||||
public static final int HELP = 31; |
||||
public static final int NOOP = 32; |
||||
/** @since 2.0 */ |
||||
public static final int MDTM = 33; |
||||
/** @since 2.2 */ |
||||
public static final int FEAT = 34; |
||||
/** @since 2.2 */ |
||||
public static final int MFMT = 35; |
||||
/** @since 2.2 */ |
||||
public static final int EPSV = 36; |
||||
/** @since 2.2 */ |
||||
public static final int EPRT = 37; |
||||
|
||||
/** |
||||
* Machine parseable list for a directory |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public static final int MLSD = 38; |
||||
|
||||
/** |
||||
* Machine parseable list for a single file |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public static final int MLST = 39; |
||||
|
||||
// Must agree with final entry above; used to check array size
|
||||
private static final int LAST = MLST; |
||||
|
||||
public static final int USERNAME = USER; |
||||
public static final int PASSWORD = PASS; |
||||
public static final int ACCOUNT = ACCT; |
||||
public static final int CHANGE_WORKING_DIRECTORY = CWD; |
||||
public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; |
||||
public static final int STRUCTURE_MOUNT = SMNT; |
||||
public static final int REINITIALIZE = REIN; |
||||
public static final int LOGOUT = QUIT; |
||||
public static final int DATA_PORT = PORT; |
||||
public static final int PASSIVE = PASV; |
||||
public static final int REPRESENTATION_TYPE = TYPE; |
||||
public static final int FILE_STRUCTURE = STRU; |
||||
public static final int TRANSFER_MODE = MODE; |
||||
public static final int RETRIEVE = RETR; |
||||
public static final int STORE = STOR; |
||||
public static final int STORE_UNIQUE = STOU; |
||||
public static final int APPEND = APPE; |
||||
public static final int ALLOCATE = ALLO; |
||||
public static final int RESTART = REST; |
||||
public static final int RENAME_FROM = RNFR; |
||||
public static final int RENAME_TO = RNTO; |
||||
public static final int ABORT = ABOR; |
||||
public static final int DELETE = DELE; |
||||
public static final int REMOVE_DIRECTORY = RMD; |
||||
public static final int MAKE_DIRECTORY = MKD; |
||||
public static final int PRINT_WORKING_DIRECTORY = PWD; |
||||
// public static final int LIST = LIST;
|
||||
public static final int NAME_LIST = NLST; |
||||
public static final int SITE_PARAMETERS = SITE; |
||||
public static final int SYSTEM = SYST; |
||||
public static final int STATUS = STAT; |
||||
//public static final int HELP = HELP;
|
||||
//public static final int NOOP = NOOP;
|
||||
|
||||
/** @since 2.0 */ |
||||
public static final int MOD_TIME = MDTM; |
||||
|
||||
/** @since 2.2 */ |
||||
public static final int FEATURES = FEAT; |
||||
/** @since 2.2 */ |
||||
public static final int GET_MOD_TIME = MDTM; |
||||
/** @since 2.2 */ |
||||
public static final int SET_MOD_TIME = MFMT; |
||||
|
||||
// Cannot be instantiated
|
||||
private FTPCommand() { |
||||
} |
||||
|
||||
private static final String[] _commands = { |
||||
"USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "PASV", "TYPE", "STRU", |
||||
"MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", |
||||
"MKD", "PWD", "LIST", "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", |
||||
"EPSV", "EPRT", "MLSD", "MLST" |
||||
}; |
||||
|
||||
// default access needed for Unit test
|
||||
static void checkArray() { |
||||
int expectedLength = LAST + 1; |
||||
if (_commands.length != expectedLength) { |
||||
throw new RuntimeException("Incorrect _commands array. Should have length " |
||||
+ expectedLength |
||||
+ " found " |
||||
+ _commands.length); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Retrieve the FTP protocol command string corresponding to a specified |
||||
* command code. |
||||
* |
||||
* @param command The command code. |
||||
* @return The FTP protcol command string corresponding to a specified |
||||
* command code. |
||||
*/ |
||||
public static final String getCommand(int command) { |
||||
return _commands[command]; |
||||
} |
||||
} |
@ -1,52 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/*** |
||||
* FTPConnectionClosedException is used to indicate the premature or |
||||
* unexpected closing of an FTP connection resulting from a |
||||
* {@link FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } |
||||
* response (FTP reply code 421) to a |
||||
* failed FTP command. This exception is derived from IOException and |
||||
* therefore may be caught either as an IOException or specifically as an |
||||
* FTPConnectionClosedException. |
||||
* |
||||
* @see FTP |
||||
* @see FTPClient |
||||
***/ |
||||
|
||||
public class FTPConnectionClosedException extends IOException { |
||||
|
||||
private static final long serialVersionUID = 3500547241659379952L; |
||||
|
||||
/*** Constructs a FTPConnectionClosedException with no message ***/ |
||||
public FTPConnectionClosedException() { |
||||
super(); |
||||
} |
||||
|
||||
/*** |
||||
* Constructs a FTPConnectionClosedException with a specified message. |
||||
* |
||||
* @param message The message explaining the reason for the exception. |
||||
***/ |
||||
public FTPConnectionClosedException(String message) { |
||||
super(message); |
||||
} |
||||
} |
@ -1,493 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
import java.util.Formatter; |
||||
import java.util.TimeZone; |
||||
|
||||
/*** |
||||
* The FTPFile class is used to represent information about files stored |
||||
* on an FTP server. |
||||
* |
||||
* @see FTPFileEntryParser |
||||
* @see FTPClient#listFiles |
||||
***/ |
||||
|
||||
public class FTPFile implements Serializable { |
||||
private static final long serialVersionUID = 9010790363003271996L; |
||||
|
||||
/** A constant indicating an FTPFile is a file. ***/ |
||||
public static final int FILE_TYPE = 0; |
||||
/** A constant indicating an FTPFile is a directory. ***/ |
||||
public static final int DIRECTORY_TYPE = 1; |
||||
/** A constant indicating an FTPFile is a symbolic link. ***/ |
||||
public static final int SYMBOLIC_LINK_TYPE = 2; |
||||
/** A constant indicating an FTPFile is of unknown type. ***/ |
||||
public static final int UNKNOWN_TYPE = 3; |
||||
|
||||
/** A constant indicating user access permissions. ***/ |
||||
public static final int USER_ACCESS = 0; |
||||
/** A constant indicating group access permissions. ***/ |
||||
public static final int GROUP_ACCESS = 1; |
||||
/** A constant indicating world access permissions. ***/ |
||||
public static final int WORLD_ACCESS = 2; |
||||
|
||||
/** A constant indicating file/directory read permission. ***/ |
||||
public static final int READ_PERMISSION = 0; |
||||
/** A constant indicating file/directory write permission. ***/ |
||||
public static final int WRITE_PERMISSION = 1; |
||||
/** |
||||
* A constant indicating file execute permission or directory listing |
||||
* permission. |
||||
***/ |
||||
public static final int EXECUTE_PERMISSION = 2; |
||||
|
||||
private int _type, _hardLinkCount; |
||||
private long _size; |
||||
private String _rawListing, _user, _group, _name, _link; |
||||
private Calendar _date; |
||||
// If this is null, then list entry parsing failed
|
||||
private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION]
|
||||
|
||||
/*** Creates an empty FTPFile. ***/ |
||||
public FTPFile() { |
||||
_permissions = new boolean[3][3]; |
||||
_type = UNKNOWN_TYPE; |
||||
// init these to values that do not occur in listings
|
||||
// so can distinguish which fields are unset
|
||||
_hardLinkCount = 0; // 0 is invalid as a link count
|
||||
_size = -1; // 0 is valid, so use -1
|
||||
_user = ""; |
||||
_group = ""; |
||||
_date = null; |
||||
_name = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructor for use by {@link FTPListParseEngine} only. |
||||
* Used to create FTPFile entries for failed parses |
||||
* |
||||
* @param rawListing line that could not be parsed. |
||||
* @since 3.4 |
||||
*/ |
||||
FTPFile(String rawListing) { |
||||
_permissions = null; // flag that entry is invalid
|
||||
_rawListing = rawListing; |
||||
_type = UNKNOWN_TYPE; |
||||
// init these to values that do not occur in listings
|
||||
// so can distinguish which fields are unset
|
||||
_hardLinkCount = 0; // 0 is invalid as a link count
|
||||
_size = -1; // 0 is valid, so use -1
|
||||
_user = ""; |
||||
_group = ""; |
||||
_date = null; |
||||
_name = null; |
||||
} |
||||
|
||||
/*** |
||||
* Set the original FTP server raw listing from which the FTPFile was |
||||
* created. |
||||
* |
||||
* @param rawListing The raw FTP server listing. |
||||
***/ |
||||
public void setRawListing(String rawListing) { |
||||
_rawListing = rawListing; |
||||
} |
||||
|
||||
/*** |
||||
* Get the original FTP server raw listing used to initialize the FTPFile. |
||||
* |
||||
* @return The original FTP server raw listing used to initialize the |
||||
* FTPFile. |
||||
***/ |
||||
public String getRawListing() { |
||||
return _rawListing; |
||||
} |
||||
|
||||
/*** |
||||
* Determine if the file is a directory. |
||||
* |
||||
* @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if |
||||
* not. |
||||
***/ |
||||
public boolean isDirectory() { |
||||
return (_type == DIRECTORY_TYPE); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if the file is a regular file. |
||||
* |
||||
* @return True if the file is of type <code>FILE_TYPE</code>, false if |
||||
* not. |
||||
***/ |
||||
public boolean isFile() { |
||||
return (_type == FILE_TYPE); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if the file is a symbolic link. |
||||
* |
||||
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if |
||||
* not. |
||||
***/ |
||||
public boolean isSymbolicLink() { |
||||
return (_type == SYMBOLIC_LINK_TYPE); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if the type of the file is unknown. |
||||
* |
||||
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if |
||||
* not. |
||||
***/ |
||||
public boolean isUnknown() { |
||||
return (_type == UNKNOWN_TYPE); |
||||
} |
||||
|
||||
/** |
||||
* Used to indicate whether an entry is valid or not. |
||||
* If the entry is invalid, only the {@link #getRawListing()} method will be useful. |
||||
* Other methods may fail. |
||||
* |
||||
* Used in conjunction with list parsing that preseverves entries that failed to parse. |
||||
* |
||||
* @return true if the entry is valid |
||||
* @see FTPClientConfig#setUnparseableEntries(boolean) |
||||
* @since 3.4 |
||||
*/ |
||||
public boolean isValid() { |
||||
return (_permissions != null); |
||||
} |
||||
|
||||
/*** |
||||
* Set the type of the file (<code>DIRECTORY_TYPE</code>, |
||||
* <code>FILE_TYPE</code>, etc.). |
||||
* |
||||
* @param type The integer code representing the type of the file. |
||||
***/ |
||||
public void setType(int type) { |
||||
_type = type; |
||||
} |
||||
|
||||
/*** |
||||
* Return the type of the file (one of the <code>_TYPE</code> constants), |
||||
* e.g., if it is a directory, a regular file, or a symbolic link. |
||||
* |
||||
* @return The type of the file. |
||||
***/ |
||||
public int getType() { |
||||
return _type; |
||||
} |
||||
|
||||
/*** |
||||
* Set the name of the file. |
||||
* |
||||
* @param name The name of the file. |
||||
***/ |
||||
public void setName(String name) { |
||||
_name = name; |
||||
} |
||||
|
||||
/*** |
||||
* Return the name of the file. |
||||
* |
||||
* @return The name of the file. |
||||
***/ |
||||
public String getName() { |
||||
return _name; |
||||
} |
||||
|
||||
/** |
||||
* Set the file size in bytes. |
||||
* |
||||
* @param size The file size in bytes. |
||||
*/ |
||||
public void setSize(long size) { |
||||
_size = size; |
||||
} |
||||
|
||||
/*** |
||||
* Return the file size in bytes. |
||||
* |
||||
* @return The file size in bytes. |
||||
***/ |
||||
public long getSize() { |
||||
return _size; |
||||
} |
||||
|
||||
/*** |
||||
* Set the number of hard links to this file. This is not to be |
||||
* confused with symbolic links. |
||||
* |
||||
* @param links The number of hard links to this file. |
||||
***/ |
||||
public void setHardLinkCount(int links) { |
||||
_hardLinkCount = links; |
||||
} |
||||
|
||||
/*** |
||||
* Return the number of hard links to this file. This is not to be |
||||
* confused with symbolic links. |
||||
* |
||||
* @return The number of hard links to this file. |
||||
***/ |
||||
public int getHardLinkCount() { |
||||
return _hardLinkCount; |
||||
} |
||||
|
||||
/*** |
||||
* Set the name of the group owning the file. This may be |
||||
* a string representation of the group number. |
||||
* |
||||
* @param group The name of the group owning the file. |
||||
***/ |
||||
public void setGroup(String group) { |
||||
_group = group; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the name of the group owning the file. Sometimes this will be |
||||
* a string representation of the group number. |
||||
* |
||||
* @return The name of the group owning the file. |
||||
***/ |
||||
public String getGroup() { |
||||
return _group; |
||||
} |
||||
|
||||
/*** |
||||
* Set the name of the user owning the file. This may be |
||||
* a string representation of the user number; |
||||
* |
||||
* @param user The name of the user owning the file. |
||||
***/ |
||||
public void setUser(String user) { |
||||
_user = user; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the name of the user owning the file. Sometimes this will be |
||||
* a string representation of the user number. |
||||
* |
||||
* @return The name of the user owning the file. |
||||
***/ |
||||
public String getUser() { |
||||
return _user; |
||||
} |
||||
|
||||
/*** |
||||
* If the FTPFile is a symbolic link, use this method to set the name of the |
||||
* file being pointed to by the symbolic link. |
||||
* |
||||
* @param link The file pointed to by the symbolic link. |
||||
***/ |
||||
public void setLink(String link) { |
||||
_link = link; |
||||
} |
||||
|
||||
/*** |
||||
* If the FTPFile is a symbolic link, this method returns the name of the |
||||
* file being pointed to by the symbolic link. Otherwise it returns null. |
||||
* |
||||
* @return The file pointed to by the symbolic link (null if the FTPFile |
||||
* is not a symbolic link). |
||||
***/ |
||||
public String getLink() { |
||||
return _link; |
||||
} |
||||
|
||||
/*** |
||||
* Set the file timestamp. This usually the last modification time. |
||||
* The parameter is not cloned, so do not alter its value after calling |
||||
* this method. |
||||
* |
||||
* @param date A Calendar instance representing the file timestamp. |
||||
***/ |
||||
public void setTimestamp(Calendar date) { |
||||
_date = date; |
||||
} |
||||
|
||||
/*** |
||||
* Returns the file timestamp. This usually the last modification time. |
||||
* |
||||
* @return A Calendar instance representing the file timestamp. |
||||
***/ |
||||
public Calendar getTimestamp() { |
||||
return _date; |
||||
} |
||||
|
||||
/*** |
||||
* Set if the given access group (one of the <code> _ACCESS </code> |
||||
* constants) has the given access permission (one of the |
||||
* <code> _PERMISSION </code> constants) to the file. |
||||
* |
||||
* @param access The access group (one of the <code> _ACCESS </code> |
||||
* constants) |
||||
* @param permission The access permission (one of the |
||||
* <code> _PERMISSION </code> constants) |
||||
* @param value True if permission is allowed, false if not. |
||||
* @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range |
||||
***/ |
||||
public void setPermission(int access, int permission, boolean value) { |
||||
_permissions[access][permission] = value; |
||||
} |
||||
|
||||
/*** |
||||
* Determines if the given access group (one of the <code> _ACCESS </code> |
||||
* constants) has the given access permission (one of the |
||||
* <code> _PERMISSION </code> constants) to the file. |
||||
* |
||||
* @param access The access group (one of the <code> _ACCESS </code> |
||||
* constants) |
||||
* @param permission The access permission (one of the |
||||
* <code> _PERMISSION </code> constants) |
||||
* @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range |
||||
* @return true if {@link #isValid()} is {@code true &&} the associated permission is set; |
||||
* {@code false} otherwise. |
||||
***/ |
||||
public boolean hasPermission(int access, int permission) { |
||||
if (_permissions == null) { |
||||
return false; |
||||
} |
||||
return _permissions[access][permission]; |
||||
} |
||||
|
||||
/*** |
||||
* Returns a string representation of the FTPFile information. |
||||
* |
||||
* @return A string representation of the FTPFile information. |
||||
*/ |
||||
@Override public String toString() { |
||||
return getRawListing(); |
||||
} |
||||
|
||||
/*** |
||||
* Returns a string representation of the FTPFile information. |
||||
* This currently mimics the Unix listing format. |
||||
* This method uses the timezone of the Calendar entry, which is |
||||
* the server time zone (if one was provided) otherwise it is |
||||
* the local time zone. |
||||
* <p> |
||||
* Note: if the instance is not valid {@link #isValid()}, no useful |
||||
* information can be returned. In this case, use {@link #getRawListing()} |
||||
* instead. |
||||
* |
||||
* @return A string representation of the FTPFile information. |
||||
* @since 3.0 |
||||
*/ |
||||
public String toFormattedString() { |
||||
return toFormattedString(null); |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representation of the FTPFile information. |
||||
* This currently mimics the Unix listing format. |
||||
* This method allows the Calendar time zone to be overridden. |
||||
* <p> |
||||
* Note: if the instance is not valid {@link #isValid()}, no useful |
||||
* information can be returned. In this case, use {@link #getRawListing()} |
||||
* instead. |
||||
* |
||||
* @param timezone the timezone to use for displaying the time stamp |
||||
* If {@code null}, then use the Calendar entry timezone |
||||
* @return A string representation of the FTPFile information. |
||||
* @since 3.4 |
||||
*/ |
||||
public String toFormattedString(final String timezone) { |
||||
|
||||
if (!isValid()) { |
||||
return "[Invalid: could not parse file entry]"; |
||||
} |
||||
StringBuilder sb = new StringBuilder(); |
||||
Formatter fmt = new Formatter(sb); |
||||
sb.append(formatType()); |
||||
sb.append(permissionToString(USER_ACCESS)); |
||||
sb.append(permissionToString(GROUP_ACCESS)); |
||||
sb.append(permissionToString(WORLD_ACCESS)); |
||||
fmt.format(" %4d", Integer.valueOf(getHardLinkCount())); |
||||
fmt.format(" %-8s %-8s", getUser(), getGroup()); |
||||
fmt.format(" %8d", Long.valueOf(getSize())); |
||||
Calendar timestamp = getTimestamp(); |
||||
if (timestamp != null) { |
||||
if (timezone != null) { |
||||
TimeZone newZone = TimeZone.getTimeZone(timezone); |
||||
if (!newZone.equals(timestamp.getTimeZone())) { |
||||
Date original = timestamp.getTime(); |
||||
Calendar newStamp = Calendar.getInstance(newZone); |
||||
newStamp.setTime(original); |
||||
timestamp = newStamp; |
||||
} |
||||
} |
||||
fmt.format(" %1$tY-%1$tm-%1$td", timestamp); |
||||
// Only display time units if they are present
|
||||
if (timestamp.isSet(Calendar.HOUR_OF_DAY)) { |
||||
fmt.format(" %1$tH", timestamp); |
||||
if (timestamp.isSet(Calendar.MINUTE)) { |
||||
fmt.format(":%1$tM", timestamp); |
||||
if (timestamp.isSet(Calendar.SECOND)) { |
||||
fmt.format(":%1$tS", timestamp); |
||||
if (timestamp.isSet(Calendar.MILLISECOND)) { |
||||
fmt.format(".%1$tL", timestamp); |
||||
} |
||||
} |
||||
} |
||||
fmt.format(" %1$tZ", timestamp); |
||||
} |
||||
} |
||||
sb.append(' '); |
||||
sb.append(getName()); |
||||
fmt.close(); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
private char formatType() { |
||||
switch (_type) { |
||||
case FILE_TYPE: |
||||
return '-'; |
||||
case DIRECTORY_TYPE: |
||||
return 'd'; |
||||
case SYMBOLIC_LINK_TYPE: |
||||
return 'l'; |
||||
default: |
||||
return '?'; |
||||
} |
||||
} |
||||
|
||||
private String permissionToString(int access) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
if (hasPermission(access, READ_PERMISSION)) { |
||||
sb.append('r'); |
||||
} else { |
||||
sb.append('-'); |
||||
} |
||||
if (hasPermission(access, WRITE_PERMISSION)) { |
||||
sb.append('w'); |
||||
} else { |
||||
sb.append('-'); |
||||
} |
||||
if (hasPermission(access, EXECUTE_PERMISSION)) { |
||||
sb.append('x'); |
||||
} else { |
||||
sb.append('-'); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -1,129 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* FTPFileEntryParser defines the interface for parsing a single FTP file |
||||
* listing and converting that information into an |
||||
* {@link FTPFile} instance. |
||||
* Sometimes you will want to parse unusual listing formats, in which |
||||
* case you would create your own implementation of FTPFileEntryParser and |
||||
* if necessary, subclass FTPFile. |
||||
* <p> |
||||
* Here are some examples showing how to use one of the classes that |
||||
* implement this interface. |
||||
* <p> |
||||
* |
||||
* The first example uses the <code>FTPClient.listFiles()</code> |
||||
* API to pull the whole list from the subfolder <code>subfolder</code> in |
||||
* one call, attempting to automatically detect the parser type. This |
||||
* method, without a parserKey parameter, indicates that autodection should |
||||
* be used. |
||||
* |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = f.listFiles("subfolder"); |
||||
* </pre> |
||||
* |
||||
* The second example uses the <code>FTPClient.listFiles()</code> |
||||
* API to pull the whole list from the current working directory in one call, |
||||
* but specifying by classname the parser to be used. For this particular |
||||
* parser class, this approach is necessary since there is no way to |
||||
* autodetect this server type. |
||||
* |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = f.listFiles( |
||||
* "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser", |
||||
* "."); |
||||
* </pre> |
||||
* |
||||
* The third example uses the <code>FTPClient.listFiles()</code> |
||||
* API to pull a single file listing in an arbitrary directory in one call, |
||||
* specifying by KEY the parser to be used, in this case, VMS. |
||||
* |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java"); |
||||
* </pre> |
||||
* |
||||
* For an alternative approach, see the {@link FTPListParseEngine} class
|
||||
* which provides iterative access. |
||||
* |
||||
* @version $Id: FTPFileEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ |
||||
* @see FTPFile |
||||
* @see FTPClient#listFiles() |
||||
*/ |
||||
public interface FTPFileEntryParser { |
||||
/** |
||||
* Parses a line of an FTP server file listing and converts it into a usable |
||||
* format in the form of an <code> FTPFile </code> instance. If the |
||||
* file listing line doesn't describe a file, <code> null </code> should be |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* |
||||
* @param listEntry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
FTPFile parseFTPEntry(String listEntry); |
||||
|
||||
/** |
||||
* Reads the next entry using the supplied BufferedReader object up to |
||||
* whatever delemits one entry from the next. Implementors must define |
||||
* this for the particular ftp system being parsed. In many but not all |
||||
* cases, this can be defined simply by calling BufferedReader.readLine(). |
||||
* |
||||
* @param reader The BufferedReader object from which entries are to be |
||||
* read. |
||||
* @return A string representing the next ftp entry or null if none found. |
||||
* @throws IOException thrown on any IO Error reading from the reader. |
||||
*/ |
||||
String readNextEntry(BufferedReader reader) throws IOException; |
||||
|
||||
/** |
||||
* This method is a hook for those implementors (such as |
||||
* VMSVersioningFTPEntryParser, and possibly others) which need to |
||||
* perform some action upon the FTPFileList after it has been created |
||||
* from the server stream, but before any clients see the list. |
||||
* |
||||
* The default implementation can be a no-op. |
||||
* |
||||
* @param original Original list after it has been created from the server stream |
||||
* @return Original list as processed by this method. |
||||
*/ |
||||
List<String> preParse(List<String> original); |
||||
} |
||||
|
||||
|
||||
/* Emacs configuration |
||||
* Local variables: ** |
||||
* mode: java ** |
||||
* c-basic-offset: 4 ** |
||||
* indent-tabs-mode: nil ** |
||||
* End: ** |
||||
*/ |
@ -1,72 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* This abstract class implements both the older FTPFileListParser and |
||||
* newer FTPFileEntryParser interfaces with default functionality. |
||||
* All the classes in the parser subpackage inherit from this. |
||||
*/ |
||||
public abstract class FTPFileEntryParserImpl implements FTPFileEntryParser { |
||||
/** |
||||
* The constructor for a FTPFileEntryParserImpl object. |
||||
*/ |
||||
public FTPFileEntryParserImpl() { |
||||
} |
||||
|
||||
/** |
||||
* Reads the next entry using the supplied BufferedReader object up to |
||||
* whatever delimits one entry from the next. This default implementation |
||||
* simply calls BufferedReader.readLine(). |
||||
* |
||||
* @param reader The BufferedReader object from which entries are to be |
||||
* read. |
||||
* @return A string representing the next ftp entry or null if none found. |
||||
* @throws IOException thrown on any IO Error reading from the reader. |
||||
*/ |
||||
@Override public String readNextEntry(BufferedReader reader) throws IOException { |
||||
return reader.readLine(); |
||||
} |
||||
|
||||
/** |
||||
* This method is a hook for those implementors (such as |
||||
* VMSVersioningFTPEntryParser, and possibly others) which need to |
||||
* perform some action upon the FTPFileList after it has been created |
||||
* from the server stream, but before any clients see the list. |
||||
* |
||||
* This default implementation does nothing. |
||||
* |
||||
* @param original Original list after it has been created from the server stream |
||||
* @return <code>original</code> unmodified. |
||||
*/ |
||||
@Override public List<String> preParse(List<String> original) { |
||||
return original; |
||||
} |
||||
} |
||||
|
||||
/* Emacs configuration |
||||
* Local variables: ** |
||||
* mode: java ** |
||||
* c-basic-offset: 4 ** |
||||
* indent-tabs-mode: nil ** |
||||
* End: ** |
||||
*/ |
@ -1,34 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* Perform filtering on FTPFile entries. |
||||
* |
||||
* @since 2.2 |
||||
*/ |
||||
public interface FTPFileFilter { |
||||
/** |
||||
* Checks if an FTPFile entry should be included or not. |
||||
* |
||||
* @param file entry to be checked for inclusion. May be <code>null</code>. |
||||
* @return <code>true</code> if the file is to be included, <code>false</code> otherwise |
||||
*/ |
||||
public boolean accept(FTPFile file); |
||||
} |
@ -1,54 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* Implements some simple FTPFileFilter classes. |
||||
* |
||||
* @since 2.2 |
||||
*/ |
||||
public class FTPFileFilters { |
||||
|
||||
/** |
||||
* Accepts all FTPFile entries, including null. |
||||
*/ |
||||
public static final FTPFileFilter ALL = new FTPFileFilter() { |
||||
@Override public boolean accept(FTPFile file) { |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Accepts all non-null FTPFile entries. |
||||
*/ |
||||
public static final FTPFileFilter NON_NULL = new FTPFileFilter() { |
||||
@Override public boolean accept(FTPFile file) { |
||||
return file != null; |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Accepts all (non-null) FTPFile directory entries. |
||||
*/ |
||||
public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() { |
||||
@Override public boolean accept(FTPFile file) { |
||||
return file != null && file.isDirectory(); |
||||
} |
||||
}; |
||||
} |
@ -1,194 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.OutputStream; |
||||
import java.io.Reader; |
||||
import java.io.UnsupportedEncodingException; |
||||
import java.net.Inet6Address; |
||||
import java.net.Socket; |
||||
import java.net.SocketException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import aria.apache.commons.net.util.Base64; |
||||
|
||||
/** |
||||
* Experimental attempt at FTP client that tunnels over an HTTP proxy connection. |
||||
* |
||||
* @since 2.2 |
||||
*/ |
||||
public class FTPHTTPClient extends FTPClient { |
||||
private final String proxyHost; |
||||
private final int proxyPort; |
||||
private final String proxyUsername; |
||||
private final String proxyPassword; |
||||
|
||||
private static final byte[] CRLF = { '\r', '\n' }; |
||||
private final Base64 base64 = new Base64(); |
||||
|
||||
private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV)
|
||||
|
||||
public FTPHTTPClient(String proxyHost, int proxyPort, String proxyUser, String proxyPass) { |
||||
this.proxyHost = proxyHost; |
||||
this.proxyPort = proxyPort; |
||||
this.proxyUsername = proxyUser; |
||||
this.proxyPassword = proxyPass; |
||||
this.tunnelHost = null; |
||||
} |
||||
|
||||
public FTPHTTPClient(String proxyHost, int proxyPort) { |
||||
this(proxyHost, proxyPort, null, null); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* @throws IllegalStateException if connection mode is not passive |
||||
* @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead |
||||
*/ |
||||
// Kept to maintain binary compatibility
|
||||
// Not strictly necessary, but Clirr complains even though there is a super-impl
|
||||
@Override @Deprecated protected Socket _openDataConnection_(int command, String arg) |
||||
throws IOException { |
||||
return super._openDataConnection_(command, arg); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* @throws IllegalStateException if connection mode is not passive |
||||
* @since 3.1 |
||||
*/ |
||||
@Override protected Socket _openDataConnection_(String command, String arg) throws IOException { |
||||
//Force local passive mode, active mode not supported by through proxy
|
||||
if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { |
||||
throw new IllegalStateException("Only passive connection mode supported"); |
||||
} |
||||
|
||||
final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; |
||||
String passiveHost = null; |
||||
|
||||
boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; |
||||
if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) { |
||||
_parseExtendedPassiveModeReply(_replyLines.get(0)); |
||||
passiveHost = this.tunnelHost; |
||||
} else { |
||||
if (isInet6Address) { |
||||
return null; // Must use EPSV for IPV6
|
||||
} |
||||
// If EPSV failed on IPV4, revert to PASV
|
||||
if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { |
||||
return null; |
||||
} |
||||
_parsePassiveModeReply(_replyLines.get(0)); |
||||
passiveHost = this.getPassiveHost(); |
||||
} |
||||
|
||||
Socket socket = _socketFactory_.createSocket(proxyHost, proxyPort); |
||||
InputStream is = socket.getInputStream(); |
||||
OutputStream os = socket.getOutputStream(); |
||||
tunnelHandshake(passiveHost, this.getPassivePort(), is, os); |
||||
if ((getRestartOffset() > 0) && !restart(getRestartOffset())) { |
||||
socket.close(); |
||||
return null; |
||||
} |
||||
|
||||
if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { |
||||
socket.close(); |
||||
return null; |
||||
} |
||||
|
||||
return socket; |
||||
} |
||||
|
||||
@Override public void connect(String host, int port) throws SocketException, IOException { |
||||
|
||||
_socket_ = _socketFactory_.createSocket(proxyHost, proxyPort); |
||||
_input_ = _socket_.getInputStream(); |
||||
_output_ = _socket_.getOutputStream(); |
||||
Reader socketIsReader; |
||||
try { |
||||
socketIsReader = tunnelHandshake(host, port, _input_, _output_); |
||||
} catch (Exception e) { |
||||
IOException ioe = new IOException("Could not connect to " + host + " using port " + port); |
||||
ioe.initCause(e); |
||||
throw ioe; |
||||
} |
||||
super._connectAction_(socketIsReader); |
||||
} |
||||
|
||||
private BufferedReader tunnelHandshake(String host, int port, InputStream input, |
||||
OutputStream output) throws IOException, UnsupportedEncodingException { |
||||
final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; |
||||
final String hostString = "Host: " + host + ":" + port; |
||||
|
||||
this.tunnelHost = host; |
||||
output.write(connectString.getBytes("UTF-8")); // TODO what is the correct encoding?
|
||||
output.write(CRLF); |
||||
output.write(hostString.getBytes("UTF-8")); |
||||
output.write(CRLF); |
||||
|
||||
if (proxyUsername != null && proxyPassword != null) { |
||||
final String auth = proxyUsername + ":" + proxyPassword; |
||||
final String header = |
||||
"Proxy-Authorization: Basic " + base64.encodeToString(auth.getBytes("UTF-8")); |
||||
output.write(header.getBytes("UTF-8")); |
||||
} |
||||
output.write(CRLF); |
||||
|
||||
List<String> response = new ArrayList<String>(); |
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, getCharset())); |
||||
|
||||
for (String line = reader.readLine(); line != null && line.length() > 0; |
||||
line = reader.readLine()) { |
||||
response.add(line); |
||||
} |
||||
|
||||
int size = response.size(); |
||||
if (size == 0) { |
||||
throw new IOException("No response from proxy"); |
||||
} |
||||
|
||||
String code = null; |
||||
String resp = response.get(0); |
||||
if (resp.startsWith("HTTP/") && resp.length() >= 12) { |
||||
code = resp.substring(9, 12); |
||||
} else { |
||||
throw new IOException("Invalid response from proxy: " + resp); |
||||
} |
||||
|
||||
if (!"200".equals(code)) { |
||||
StringBuilder msg = new StringBuilder(); |
||||
msg.append("HTTPTunnelConnector: connection failed\r\n"); |
||||
msg.append("Response received from the proxy:\r\n"); |
||||
for (String line : response) { |
||||
msg.append(line); |
||||
msg.append("\r\n"); |
||||
} |
||||
throw new IOException(msg.toString()); |
||||
} |
||||
return reader; |
||||
} |
||||
} |
||||
|
||||
|
@ -1,311 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.util.ArrayList; |
||||
import java.util.Iterator; |
||||
import java.util.LinkedList; |
||||
import java.util.List; |
||||
import java.util.ListIterator; |
||||
|
||||
import aria.apache.commons.net.util.Charsets; |
||||
|
||||
/** |
||||
* This class handles the entire process of parsing a listing of |
||||
* file entries from the server. |
||||
* <p> |
||||
* This object defines a two-part parsing mechanism. |
||||
* <p> |
||||
* The first part is comprised of reading the raw input into an internal |
||||
* list of strings. Every item in this list corresponds to an actual |
||||
* file. All extraneous matter emitted by the server will have been |
||||
* removed by the end of this phase. This is accomplished in conjunction |
||||
* with the FTPFileEntryParser associated with this engine, by calling |
||||
* its methods <code>readNextEntry()</code> - which handles the issue of |
||||
* what delimits one entry from another, usually but not always a line |
||||
* feed and <code>preParse()</code> - which handles removal of |
||||
* extraneous matter such as the preliminary lines of a listing, removal |
||||
* of duplicates on versioning systems, etc. |
||||
* <p> |
||||
* The second part is composed of the actual parsing, again in conjunction |
||||
* with the particular parser used by this engine. This is controlled |
||||
* by an iterator over the internal list of strings. This may be done |
||||
* either in block mode, by calling the <code>getNext()</code> and |
||||
* <code>getPrevious()</code> methods to provide "paged" output of less |
||||
* than the whole list at one time, or by calling the |
||||
* <code>getFiles()</code> method to return the entire list. |
||||
* <p> |
||||
* Examples: |
||||
* <p> |
||||
* Paged access: |
||||
* <pre> |
||||
* FTPClient f=FTPClient(); |
||||
* f.connect(server); |
||||
* f.login(username, password); |
||||
* FTPListParseEngine engine = f.initiateListParsing(directory); |
||||
* |
||||
* while (engine.hasNext()) { |
||||
* FTPFile[] files = engine.getNext(25); // "page size" you want
|
||||
* //do whatever you want with these files, display them, etc.
|
||||
* //expensive FTPFile objects not created until needed.
|
||||
* } |
||||
* </pre> |
||||
* <p> |
||||
* For unpaged access, simply use FTPClient.listFiles(). That method |
||||
* uses this class transparently. |
||||
* |
||||
* @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $ |
||||
*/ |
||||
public class FTPListParseEngine { |
||||
private List<String> entries = new LinkedList<String>(); |
||||
private ListIterator<String> _internalIterator = entries.listIterator(); |
||||
|
||||
private final FTPFileEntryParser parser; |
||||
// Should invalid files (parse failures) be allowed?
|
||||
private final boolean saveUnparseableEntries; |
||||
|
||||
public FTPListParseEngine(FTPFileEntryParser parser) { |
||||
this(parser, null); |
||||
} |
||||
|
||||
/** |
||||
* Intended for use by FTPClient only |
||||
* |
||||
* @since 3.4 |
||||
*/ |
||||
FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) { |
||||
this.parser = parser; |
||||
if (configuration != null) { |
||||
this.saveUnparseableEntries = configuration.getUnparseableEntries(); |
||||
} else { |
||||
this.saveUnparseableEntries = false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* handle the initial reading and preparsing of the list returned by |
||||
* the server. After this method has completed, this object will contain |
||||
* a list of unparsed entries (Strings) each referring to a unique file |
||||
* on the server. |
||||
* |
||||
* @param stream input stream provided by the server socket. |
||||
* @param encoding the encoding to be used for reading the stream |
||||
* @throws IOException thrown on any failure to read from the sever. |
||||
*/ |
||||
public void readServerList(InputStream stream, String encoding) throws IOException { |
||||
this.entries = new LinkedList<String>(); |
||||
readStream(stream, encoding); |
||||
this.parser.preParse(this.entries); |
||||
resetIterator(); |
||||
} |
||||
|
||||
/** |
||||
* Internal method for reading the input into the <code>entries</code> list. |
||||
* After this method has completed, <code>entries</code> will contain a |
||||
* collection of entries (as defined by |
||||
* <code>FTPFileEntryParser.readNextEntry()</code>), but this may contain |
||||
* various non-entry preliminary lines from the server output, duplicates, |
||||
* and other data that will not be part of the final listing. |
||||
* |
||||
* @param stream The socket stream on which the input will be read. |
||||
* @param encoding The encoding to use. |
||||
* @throws IOException thrown on any failure to read the stream |
||||
*/ |
||||
private void readStream(InputStream stream, String encoding) throws IOException { |
||||
BufferedReader reader = |
||||
new BufferedReader(new InputStreamReader(stream, Charsets.toCharset(encoding))); |
||||
|
||||
String line = this.parser.readNextEntry(reader); |
||||
|
||||
while (line != null) { |
||||
this.entries.add(line); |
||||
line = this.parser.readNextEntry(reader); |
||||
} |
||||
reader.close(); |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of at most <code>quantityRequested</code> FTPFile |
||||
* objects starting at this object's internal iterator's current position. |
||||
* If fewer than <code>quantityRequested</code> such |
||||
* elements are available, the returned array will have a length equal |
||||
* to the number of entries at and after after the current position. |
||||
* If no such entries are found, this array will have a length of 0. |
||||
* |
||||
* After this method is called this object's internal iterator is advanced |
||||
* by a number of positions equal to the size of the array returned. |
||||
* |
||||
* @param quantityRequested the maximum number of entries we want to get. |
||||
* @return an array of at most <code>quantityRequested</code> FTPFile |
||||
* objects starting at the current position of this iterator within its |
||||
* list and at least the number of elements which exist in the list at |
||||
* and after its current position. |
||||
* <p><b> |
||||
* NOTE:</b> This array may contain null members if any of the |
||||
* individual file listings failed to parse. The caller should |
||||
* check each entry for null before referencing it. |
||||
*/ |
||||
public FTPFile[] getNext(int quantityRequested) { |
||||
List<FTPFile> tmpResults = new LinkedList<FTPFile>(); |
||||
int count = quantityRequested; |
||||
while (count > 0 && this._internalIterator.hasNext()) { |
||||
String entry = this._internalIterator.next(); |
||||
FTPFile temp = this.parser.parseFTPEntry(entry); |
||||
if (temp == null && saveUnparseableEntries) { |
||||
temp = new FTPFile(entry); |
||||
} |
||||
tmpResults.add(temp); |
||||
count--; |
||||
} |
||||
return tmpResults.toArray(new FTPFile[tmpResults.size()]); |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of at most <code>quantityRequested</code> FTPFile |
||||
* objects starting at this object's internal iterator's current position, |
||||
* and working back toward the beginning. |
||||
* |
||||
* If fewer than <code>quantityRequested</code> such |
||||
* elements are available, the returned array will have a length equal |
||||
* to the number of entries at and after after the current position. |
||||
* If no such entries are found, this array will have a length of 0. |
||||
* |
||||
* After this method is called this object's internal iterator is moved |
||||
* back by a number of positions equal to the size of the array returned. |
||||
* |
||||
* @param quantityRequested the maximum number of entries we want to get. |
||||
* @return an array of at most <code>quantityRequested</code> FTPFile |
||||
* objects starting at the current position of this iterator within its |
||||
* list and at least the number of elements which exist in the list at |
||||
* and after its current position. This array will be in the same order |
||||
* as the underlying list (not reversed). |
||||
* <p><b> |
||||
* NOTE:</b> This array may contain null members if any of the |
||||
* individual file listings failed to parse. The caller should |
||||
* check each entry for null before referencing it. |
||||
*/ |
||||
public FTPFile[] getPrevious(int quantityRequested) { |
||||
List<FTPFile> tmpResults = new LinkedList<FTPFile>(); |
||||
int count = quantityRequested; |
||||
while (count > 0 && this._internalIterator.hasPrevious()) { |
||||
String entry = this._internalIterator.previous(); |
||||
FTPFile temp = this.parser.parseFTPEntry(entry); |
||||
if (temp == null && saveUnparseableEntries) { |
||||
temp = new FTPFile(entry); |
||||
} |
||||
tmpResults.add(0, temp); |
||||
count--; |
||||
} |
||||
return tmpResults.toArray(new FTPFile[tmpResults.size()]); |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of FTPFile objects containing the whole list of |
||||
* files returned by the server as read by this object's parser. |
||||
* |
||||
* @return an array of FTPFile objects containing the whole list of |
||||
* files returned by the server as read by this object's parser. |
||||
* None of the entries will be null |
||||
* @throws IOException - not ever thrown, may be removed in a later release |
||||
*/ |
||||
public FTPFile[] getFiles() throws IOException // TODO remove; not actually thrown
|
||||
{ |
||||
return getFiles(FTPFileFilters.NON_NULL); |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of FTPFile objects containing the whole list of |
||||
* files returned by the server as read by this object's parser. |
||||
* The files are filtered before being added to the array. |
||||
* |
||||
* @param filter FTPFileFilter, must not be <code>null</code>. |
||||
* @return an array of FTPFile objects containing the whole list of |
||||
* files returned by the server as read by this object's parser. |
||||
* <p><b> |
||||
* NOTE:</b> This array may contain null members if any of the |
||||
* individual file listings failed to parse. The caller should |
||||
* check each entry for null before referencing it, or use the |
||||
* a filter such as {@link FTPFileFilters#NON_NULL} which does not |
||||
* allow null entries. |
||||
* @throws IOException - not ever thrown, may be removed in a later release |
||||
* @since 2.2 |
||||
*/ |
||||
public FTPFile[] getFiles(FTPFileFilter filter) |
||||
throws IOException // TODO remove; not actually thrown
|
||||
{ |
||||
List<FTPFile> tmpResults = new ArrayList<FTPFile>(); |
||||
Iterator<String> iter = this.entries.iterator(); |
||||
while (iter.hasNext()) { |
||||
String entry = iter.next(); |
||||
FTPFile temp = this.parser.parseFTPEntry(entry); |
||||
if (temp == null && saveUnparseableEntries) { |
||||
temp = new FTPFile(entry); |
||||
} |
||||
if (filter.accept(temp)) { |
||||
tmpResults.add(temp); |
||||
} |
||||
} |
||||
return tmpResults.toArray(new FTPFile[tmpResults.size()]); |
||||
} |
||||
|
||||
/** |
||||
* convenience method to allow clients to know whether this object's |
||||
* internal iterator's current position is at the end of the list. |
||||
* |
||||
* @return true if internal iterator is not at end of list, false |
||||
* otherwise. |
||||
*/ |
||||
public boolean hasNext() { |
||||
return _internalIterator.hasNext(); |
||||
} |
||||
|
||||
/** |
||||
* convenience method to allow clients to know whether this object's |
||||
* internal iterator's current position is at the beginning of the list. |
||||
* |
||||
* @return true if internal iterator is not at beginning of list, false |
||||
* otherwise. |
||||
*/ |
||||
public boolean hasPrevious() { |
||||
return _internalIterator.hasPrevious(); |
||||
} |
||||
|
||||
/** |
||||
* resets this object's internal iterator to the beginning of the list. |
||||
*/ |
||||
public void resetIterator() { |
||||
this._internalIterator = this.entries.listIterator(); |
||||
} |
||||
|
||||
// DEPRECATED METHODS - for API compatibility only - DO NOT USE
|
||||
|
||||
/** |
||||
* Do not use. |
||||
* |
||||
* @param stream the stream from which to read |
||||
* @throws IOException on error |
||||
* @deprecated use {@link #readServerList(InputStream, String)} instead |
||||
*/ |
||||
@Deprecated public void readServerList(InputStream stream) throws IOException { |
||||
readServerList(stream, null); |
||||
} |
||||
} |
@ -1,193 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/*** |
||||
* FTPReply stores a set of constants for FTP reply codes. To interpret |
||||
* the meaning of the codes, familiarity with RFC 959 is assumed. |
||||
* The mnemonic constant names are transcriptions from the code descriptions |
||||
* of RFC 959. |
||||
* <p> |
||||
* TODO replace with an enum |
||||
***/ |
||||
|
||||
public final class FTPReply { |
||||
|
||||
public static final int RESTART_MARKER = 110; |
||||
public static final int SERVICE_NOT_READY = 120; |
||||
public static final int DATA_CONNECTION_ALREADY_OPEN = 125; |
||||
public static final int FILE_STATUS_OK = 150; |
||||
public static final int COMMAND_OK = 200; |
||||
public static final int COMMAND_IS_SUPERFLUOUS = 202; |
||||
public static final int SYSTEM_STATUS = 211; |
||||
public static final int DIRECTORY_STATUS = 212; |
||||
public static final int FILE_STATUS = 213; |
||||
public static final int HELP_MESSAGE = 214; |
||||
public static final int NAME_SYSTEM_TYPE = 215; |
||||
public static final int SERVICE_READY = 220; |
||||
public static final int SERVICE_CLOSING_CONTROL_CONNECTION = 221; |
||||
public static final int DATA_CONNECTION_OPEN = 225; |
||||
public static final int CLOSING_DATA_CONNECTION = 226; |
||||
public static final int ENTERING_PASSIVE_MODE = 227; |
||||
/** @since 2.2 */ |
||||
public static final int ENTERING_EPSV_MODE = 229; |
||||
public static final int USER_LOGGED_IN = 230; |
||||
public static final int FILE_ACTION_OK = 250; |
||||
public static final int PATHNAME_CREATED = 257; |
||||
public static final int NEED_PASSWORD = 331; |
||||
public static final int NEED_ACCOUNT = 332; |
||||
public static final int FILE_ACTION_PENDING = 350; |
||||
public static final int SERVICE_NOT_AVAILABLE = 421; |
||||
public static final int CANNOT_OPEN_DATA_CONNECTION = 425; |
||||
public static final int TRANSFER_ABORTED = 426; |
||||
public static final int FILE_ACTION_NOT_TAKEN = 450; |
||||
public static final int ACTION_ABORTED = 451; |
||||
public static final int INSUFFICIENT_STORAGE = 452; |
||||
public static final int UNRECOGNIZED_COMMAND = 500; |
||||
public static final int SYNTAX_ERROR_IN_ARGUMENTS = 501; |
||||
public static final int COMMAND_NOT_IMPLEMENTED = 502; |
||||
public static final int BAD_COMMAND_SEQUENCE = 503; |
||||
public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = 504; |
||||
public static final int NOT_LOGGED_IN = 530; |
||||
public static final int NEED_ACCOUNT_FOR_STORING_FILES = 532; |
||||
public static final int FILE_UNAVAILABLE = 550; |
||||
public static final int PAGE_TYPE_UNKNOWN = 551; |
||||
public static final int STORAGE_ALLOCATION_EXCEEDED = 552; |
||||
public static final int FILE_NAME_NOT_ALLOWED = 553; |
||||
|
||||
// FTPS Reply Codes
|
||||
|
||||
/** @since 2.0 */ |
||||
public static final int SECURITY_DATA_EXCHANGE_COMPLETE = 234; |
||||
/** @since 2.0 */ |
||||
public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = 235; |
||||
/** @since 2.0 */ |
||||
public static final int SECURITY_MECHANISM_IS_OK = 334; |
||||
/** @since 2.0 */ |
||||
public static final int SECURITY_DATA_IS_ACCEPTABLE = 335; |
||||
/** @since 2.0 */ |
||||
public static final int UNAVAILABLE_RESOURCE = 431; |
||||
/** @since 2.2 */ |
||||
public static final int BAD_TLS_NEGOTIATION_OR_DATA_ENCRYPTION_REQUIRED = 522; |
||||
/** @since 2.0 */ |
||||
public static final int DENIED_FOR_POLICY_REASONS = 533; |
||||
/** @since 2.0 */ |
||||
public static final int REQUEST_DENIED = 534; |
||||
/** @since 2.0 */ |
||||
public static final int FAILED_SECURITY_CHECK = 535; |
||||
/** @since 2.0 */ |
||||
public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = 536; |
||||
|
||||
// IPv6 error codes
|
||||
// Note this is also used as an FTPS error code reply
|
||||
/** @since 2.2 */ |
||||
public static final int EXTENDED_PORT_FAILURE = 522; |
||||
|
||||
// Cannot be instantiated
|
||||
private FTPReply() { |
||||
} |
||||
|
||||
/*** |
||||
* Determine if a reply code is a positive preliminary response. All |
||||
* codes beginning with a 1 are positive preliminary responses. |
||||
* Postitive preliminary responses are used to indicate tentative success. |
||||
* No further commands can be issued to the FTP server after a positive |
||||
* preliminary response until a follow up response is received from the |
||||
* server. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a postive preliminary response, false |
||||
* if not. |
||||
***/ |
||||
public static boolean isPositivePreliminary(int reply) { |
||||
return (reply >= 100 && reply < 200); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if a reply code is a positive completion response. All |
||||
* codes beginning with a 2 are positive completion responses. |
||||
* The FTP server will send a positive completion response on the final |
||||
* successful completion of a command. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a postive completion response, false |
||||
* if not. |
||||
***/ |
||||
public static boolean isPositiveCompletion(int reply) { |
||||
return (reply >= 200 && reply < 300); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if a reply code is a positive intermediate response. All |
||||
* codes beginning with a 3 are positive intermediate responses. |
||||
* The FTP server will send a positive intermediate response on the |
||||
* successful completion of one part of a multi-part sequence of |
||||
* commands. For example, after a successful USER command, a positive |
||||
* intermediate response will be sent to indicate that the server is |
||||
* ready for the PASS command. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a postive intermediate response, false |
||||
* if not. |
||||
***/ |
||||
public static boolean isPositiveIntermediate(int reply) { |
||||
return (reply >= 300 && reply < 400); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if a reply code is a negative transient response. All |
||||
* codes beginning with a 4 are negative transient responses. |
||||
* The FTP server will send a negative transient response on the |
||||
* failure of a command that can be reattempted with success. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a negative transient response, false |
||||
* if not. |
||||
***/ |
||||
public static boolean isNegativeTransient(int reply) { |
||||
return (reply >= 400 && reply < 500); |
||||
} |
||||
|
||||
/*** |
||||
* Determine if a reply code is a negative permanent response. All |
||||
* codes beginning with a 5 are negative permanent responses. |
||||
* The FTP server will send a negative permanent response on the |
||||
* failure of a command that cannot be reattempted with success. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a negative permanent response, false |
||||
* if not. |
||||
***/ |
||||
public static boolean isNegativePermanent(int reply) { |
||||
return (reply >= 500 && reply < 600); |
||||
} |
||||
|
||||
/** |
||||
* Determine if a reply code is a protected response. |
||||
* |
||||
* @param reply The reply code to test. |
||||
* @return True if a reply code is a protected response, false |
||||
* if not. |
||||
* @since 3.0 |
||||
*/ |
||||
public static boolean isProtectedReplyCode(int reply) { |
||||
// actually, only 3 protected reply codes are
|
||||
// defined in RFC 2228: 631, 632 and 633.
|
||||
return (reply >= 600 && reply < 700); |
||||
} |
||||
} |
@ -1,931 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import aria.apache.commons.net.SocketClient; |
||||
import aria.apache.commons.net.util.KeyManagerUtils; |
||||
import java.io.BufferedReader; |
||||
import java.io.BufferedWriter; |
||||
import java.io.IOException; |
||||
import java.io.InputStreamReader; |
||||
import java.io.OutputStreamWriter; |
||||
import java.net.Socket; |
||||
|
||||
import javax.net.ssl.HostnameVerifier; |
||||
import javax.net.ssl.KeyManager; |
||||
import javax.net.ssl.SSLContext; |
||||
import javax.net.ssl.SSLException; |
||||
import javax.net.ssl.SSLHandshakeException; |
||||
import javax.net.ssl.SSLSocket; |
||||
import javax.net.ssl.SSLSocketFactory; |
||||
import javax.net.ssl.TrustManager; |
||||
|
||||
import aria.apache.commons.net.util.Base64; |
||||
import aria.apache.commons.net.util.SSLContextUtils; |
||||
import aria.apache.commons.net.util.SSLSocketUtils; |
||||
import aria.apache.commons.net.util.TrustManagerUtils; |
||||
|
||||
/** |
||||
* FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to |
||||
* see wire-level SSL details. |
||||
* |
||||
* Warning: the hostname is not verified against the certificate by default, use |
||||
* {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} |
||||
* (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. |
||||
* |
||||
* @version $Id: FTPSClient.java 1747829 2016-06-11 00:57:57Z sebb $ |
||||
* @since 2.0 |
||||
*/ |
||||
public class FTPSClient extends FTPClient { |
||||
|
||||
// From http://www.iana.org/assignments/port-numbers
|
||||
|
||||
// ftps-data 989/tcp ftp protocol, data, over TLS/SSL
|
||||
// ftps-data 989/udp ftp protocol, data, over TLS/SSL
|
||||
// ftps 990/tcp ftp protocol, control, over TLS/SSL
|
||||
// ftps 990/udp ftp protocol, control, over TLS/SSL
|
||||
|
||||
public static final int DEFAULT_FTPS_DATA_PORT = 989; |
||||
public static final int DEFAULT_FTPS_PORT = 990; |
||||
|
||||
/** The value that I can set in PROT command (C = Clear, P = Protected) */ |
||||
private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" }; |
||||
/** Default PROT Command */ |
||||
private static final String DEFAULT_PROT = "C"; |
||||
/** Default secure socket protocol name, i.e. TLS */ |
||||
private static final String DEFAULT_PROTOCOL = "TLS"; |
||||
|
||||
/** The AUTH (Authentication/Security Mechanism) command. */ |
||||
private static final String CMD_AUTH = "AUTH"; |
||||
/** The ADAT (Authentication/Security Data) command. */ |
||||
private static final String CMD_ADAT = "ADAT"; |
||||
/** The PROT (Data Channel Protection Level) command. */ |
||||
private static final String CMD_PROT = "PROT"; |
||||
/** The PBSZ (Protection Buffer Size) command. */ |
||||
private static final String CMD_PBSZ = "PBSZ"; |
||||
/** The MIC (Integrity Protected Command) command. */ |
||||
private static final String CMD_MIC = "MIC"; |
||||
/** The CONF (Confidentiality Protected Command) command. */ |
||||
private static final String CMD_CONF = "CONF"; |
||||
/** The ENC (Privacy Protected Command) command. */ |
||||
private static final String CMD_ENC = "ENC"; |
||||
/** The CCC (Clear Command Channel) command. */ |
||||
private static final String CMD_CCC = "CCC"; |
||||
|
||||
/** The security mode. (True - Implicit Mode / False - Explicit Mode) */ |
||||
private final boolean isImplicit; |
||||
/** The secure socket protocol to be used, e.g. SSL/TLS. */ |
||||
private final String protocol; |
||||
/** The AUTH Command value */ |
||||
private String auth = DEFAULT_PROTOCOL; |
||||
/** The context object. */ |
||||
private SSLContext context; |
||||
/** The socket object. */ |
||||
private Socket plainSocket; |
||||
/** Controls whether a new SSL session may be established by this socket. Default true. */ |
||||
private boolean isCreation = true; |
||||
/** The use client mode flag. */ |
||||
private boolean isClientMode = true; |
||||
/** The need client auth flag. */ |
||||
private boolean isNeedClientAuth = false; |
||||
/** The want client auth flag. */ |
||||
private boolean isWantClientAuth = false; |
||||
/** The cipher suites */ |
||||
private String[] suites = null; |
||||
/** The protocol versions */ |
||||
private String[] protocols = null; |
||||
|
||||
/** |
||||
* The FTPS {@link TrustManager} implementation, default validate only |
||||
* {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. |
||||
*/ |
||||
private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); |
||||
|
||||
/** The {@link KeyManager}, default null (i.e. use system default). */ |
||||
private KeyManager keyManager = null; |
||||
|
||||
/** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ |
||||
private HostnameVerifier hostnameVerifier = null; |
||||
|
||||
/** Use Java 1.7+ HTTPS Endpoint Identification Algorithim. */ |
||||
private boolean tlsEndpointChecking; |
||||
|
||||
/** |
||||
* Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. |
||||
* |
||||
* Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit |
||||
* (isImplicit = false) |
||||
*/ |
||||
public FTPSClient() { |
||||
this(DEFAULT_PROTOCOL, false); |
||||
} |
||||
|
||||
/** |
||||
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS |
||||
* Calls {@link #FTPSClient(String, boolean)} |
||||
* |
||||
* @param isImplicit The security mode (Implicit/Explicit). |
||||
*/ |
||||
public FTPSClient(boolean isImplicit) { |
||||
this(DEFAULT_PROTOCOL, isImplicit); |
||||
} |
||||
|
||||
/** |
||||
* Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}. |
||||
* |
||||
* @param protocol the protocol to use |
||||
*/ |
||||
public FTPSClient(String protocol) { |
||||
this(protocol, false); |
||||
} |
||||
|
||||
/** |
||||
* Constructor for FTPSClient allowing specification of protocol |
||||
* and security mode. If isImplicit is true, the port is set to |
||||
* {@link #DEFAULT_FTPS_PORT} i.e. 990. |
||||
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} |
||||
* |
||||
* @param protocol the protocol |
||||
* @param isImplicit The security mode(Implicit/Explicit). |
||||
*/ |
||||
public FTPSClient(String protocol, boolean isImplicit) { |
||||
super(); |
||||
this.protocol = protocol; |
||||
this.isImplicit = isImplicit; |
||||
if (isImplicit) { |
||||
setDefaultPort(DEFAULT_FTPS_PORT); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS |
||||
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} |
||||
* |
||||
* @param isImplicit The security mode(Implicit/Explicit). |
||||
* @param context A pre-configured SSL Context |
||||
*/ |
||||
public FTPSClient(boolean isImplicit, SSLContext context) { |
||||
this(DEFAULT_PROTOCOL, isImplicit); |
||||
this.context = context; |
||||
} |
||||
|
||||
/** |
||||
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS |
||||
* and isImplicit {@code false} |
||||
* Calls {@link #FTPSClient(boolean, SSLContext)} |
||||
* |
||||
* @param context A pre-configured SSL Context |
||||
*/ |
||||
public FTPSClient(SSLContext context) { |
||||
this(false, context); |
||||
} |
||||
|
||||
/** |
||||
* Set AUTH command use value. |
||||
* This processing is done before connected processing. |
||||
* |
||||
* @param auth AUTH command use value. |
||||
*/ |
||||
public void setAuthValue(String auth) { |
||||
this.auth = auth; |
||||
} |
||||
|
||||
/** |
||||
* Return AUTH command use value. |
||||
* |
||||
* @return AUTH command use value. |
||||
*/ |
||||
public String getAuthValue() { |
||||
return this.auth; |
||||
} |
||||
|
||||
/** |
||||
* Because there are so many connect() methods, |
||||
* the _connectAction_() method is provided as a means of performing |
||||
* some action immediately after establishing a connection, |
||||
* rather than reimplementing all of the connect() methods. |
||||
* |
||||
* @throws IOException If it throw by _connectAction_. |
||||
* @see SocketClient#_connectAction_() |
||||
*/ |
||||
@Override protected void _connectAction_() throws IOException { |
||||
// Implicit mode.
|
||||
if (isImplicit) { |
||||
sslNegotiation(); |
||||
} |
||||
super._connectAction_(); |
||||
// Explicit mode.
|
||||
if (!isImplicit) { |
||||
execAUTH(); |
||||
sslNegotiation(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* AUTH command. |
||||
* |
||||
* @throws SSLException If it server reply code not equal "234" and "334". |
||||
* @throws IOException If an I/O error occurs while either sending |
||||
* the command. |
||||
*/ |
||||
protected void execAUTH() throws SSLException, IOException { |
||||
int replyCode = sendCommand(CMD_AUTH, auth); |
||||
if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { |
||||
// replyCode = 334
|
||||
// I carry out an ADAT command.
|
||||
} else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { |
||||
throw new SSLException(getReplyString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Performs a lazy init of the SSL context |
||||
* |
||||
* @throws IOException |
||||
*/ |
||||
private void initSslContext() throws IOException { |
||||
if (context == null) { |
||||
context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* SSL/TLS negotiation. Acquires an SSL socket of a control |
||||
* connection and carries out handshake processing. |
||||
* |
||||
* @throws IOException If server negotiation fails |
||||
*/ |
||||
protected void sslNegotiation() throws IOException { |
||||
plainSocket = _socket_; |
||||
initSslContext(); |
||||
|
||||
SSLSocketFactory ssf = context.getSocketFactory(); |
||||
String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress(); |
||||
int port = _socket_.getPort(); |
||||
SSLSocket socket = (SSLSocket) ssf.createSocket(_socket_, host, port, false); |
||||
socket.setEnableSessionCreation(isCreation); |
||||
socket.setUseClientMode(isClientMode); |
||||
|
||||
// client mode
|
||||
if (isClientMode) { |
||||
if (tlsEndpointChecking) { |
||||
SSLSocketUtils.enableEndpointNameVerification(socket); |
||||
} |
||||
} else { // server mode
|
||||
socket.setNeedClientAuth(isNeedClientAuth); |
||||
socket.setWantClientAuth(isWantClientAuth); |
||||
} |
||||
|
||||
if (protocols != null) { |
||||
socket.setEnabledProtocols(protocols); |
||||
} |
||||
if (suites != null) { |
||||
socket.setEnabledCipherSuites(suites); |
||||
} |
||||
socket.startHandshake(); |
||||
|
||||
// TODO the following setup appears to duplicate that in the super class methods
|
||||
_socket_ = socket; |
||||
_controlInput_ = |
||||
new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); |
||||
_controlOutput_ = |
||||
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding())); |
||||
|
||||
if (isClientMode) { |
||||
if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { |
||||
throw new SSLHandshakeException("Hostname doesn't match certificate"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Get the {@link KeyManager} instance. |
||||
* |
||||
* @return The {@link KeyManager} instance |
||||
*/ |
||||
private KeyManager getKeyManager() { |
||||
return keyManager; |
||||
} |
||||
|
||||
/** |
||||
* Set a {@link KeyManager} to use |
||||
* |
||||
* @param keyManager The KeyManager implementation to set. |
||||
* @see KeyManagerUtils |
||||
*/ |
||||
public void setKeyManager(KeyManager keyManager) { |
||||
this.keyManager = keyManager; |
||||
} |
||||
|
||||
/** |
||||
* Controls whether a new SSL session may be established by this socket. |
||||
* |
||||
* @param isCreation The established socket flag. |
||||
*/ |
||||
public void setEnabledSessionCreation(boolean isCreation) { |
||||
this.isCreation = isCreation; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if new SSL sessions may be established by this socket. |
||||
* When the underlying {@link Socket} instance is not SSL-enabled (i.e. an |
||||
* instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) |
||||
* enabled, |
||||
* this returns False. |
||||
* |
||||
* @return true - Indicates that sessions may be created; |
||||
* this is the default. |
||||
* false - indicates that an existing session must be resumed. |
||||
*/ |
||||
public boolean getEnableSessionCreation() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getEnableSessionCreation(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Configures the socket to require client authentication. |
||||
* |
||||
* @param isNeedClientAuth The need client auth flag. |
||||
*/ |
||||
public void setNeedClientAuth(boolean isNeedClientAuth) { |
||||
this.isNeedClientAuth = isNeedClientAuth; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the socket will require client authentication. |
||||
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. |
||||
* |
||||
* @return true - If the server mode socket should request |
||||
* that the client authenticate itself. |
||||
*/ |
||||
public boolean getNeedClientAuth() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getNeedClientAuth(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Configures the socket to request client authentication, |
||||
* but only if such a request is appropriate to the cipher |
||||
* suite negotiated. |
||||
* |
||||
* @param isWantClientAuth The want client auth flag. |
||||
*/ |
||||
public void setWantClientAuth(boolean isWantClientAuth) { |
||||
this.isWantClientAuth = isWantClientAuth; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the socket will request client authentication. |
||||
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. |
||||
* |
||||
* @return true - If the server mode socket should request |
||||
* that the client authenticate itself. |
||||
*/ |
||||
public boolean getWantClientAuth() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getWantClientAuth(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Configures the socket to use client (or server) mode in its first |
||||
* handshake. |
||||
* |
||||
* @param isClientMode The use client mode flag. |
||||
*/ |
||||
public void setUseClientMode(boolean isClientMode) { |
||||
this.isClientMode = isClientMode; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the socket is set to use client mode |
||||
* in its first handshake. |
||||
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. |
||||
* |
||||
* @return true - If the socket should start its first handshake |
||||
* in "client" mode. |
||||
*/ |
||||
public boolean getUseClientMode() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getUseClientMode(); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Controls which particular cipher suites are enabled for use on this |
||||
* connection. Called before server negotiation. |
||||
* |
||||
* @param cipherSuites The cipher suites. |
||||
*/ |
||||
public void setEnabledCipherSuites(String[] cipherSuites) { |
||||
suites = new String[cipherSuites.length]; |
||||
System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); |
||||
} |
||||
|
||||
/** |
||||
* Returns the names of the cipher suites which could be enabled |
||||
* for use on this connection. |
||||
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. |
||||
* |
||||
* @return An array of cipher suite names, or <code>null</code> |
||||
*/ |
||||
public String[] getEnabledCipherSuites() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getEnabledCipherSuites(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Controls which particular protocol versions are enabled for use on this |
||||
* connection. I perform setting before a server negotiation. |
||||
* |
||||
* @param protocolVersions The protocol versions. |
||||
*/ |
||||
public void setEnabledProtocols(String[] protocolVersions) { |
||||
protocols = new String[protocolVersions.length]; |
||||
System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); |
||||
} |
||||
|
||||
/** |
||||
* Returns the names of the protocol versions which are currently |
||||
* enabled for use on this connection. |
||||
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. |
||||
* |
||||
* @return An array of protocols, or <code>null</code> |
||||
*/ |
||||
public String[] getEnabledProtocols() { |
||||
if (_socket_ instanceof SSLSocket) { |
||||
return ((SSLSocket) _socket_).getEnabledProtocols(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. |
||||
* |
||||
* @param pbsz Protection Buffer Size. |
||||
* @throws SSLException If the server reply code does not equal "200". |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @see #parsePBSZ(long) |
||||
*/ |
||||
public void execPBSZ(long pbsz) throws SSLException, IOException { |
||||
if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
|
||||
throw new IllegalArgumentException(); |
||||
} |
||||
int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); |
||||
if (FTPReply.COMMAND_OK != status) { |
||||
throw new SSLException(getReplyString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. |
||||
* Issues the command and parses the response to return the negotiated value. |
||||
* |
||||
* @param pbsz Protection Buffer Size. |
||||
* @return the negotiated value. |
||||
* @throws SSLException If the server reply code does not equal "200". |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @see #execPBSZ(long) |
||||
* @since 3.0 |
||||
*/ |
||||
public long parsePBSZ(long pbsz) throws SSLException, IOException { |
||||
execPBSZ(pbsz); |
||||
long minvalue = pbsz; |
||||
String remainder = extractPrefixedData("PBSZ=", getReplyString()); |
||||
if (remainder != null) { |
||||
long replysz = Long.parseLong(remainder); |
||||
if (replysz < minvalue) { |
||||
minvalue = replysz; |
||||
} |
||||
} |
||||
return minvalue; |
||||
} |
||||
|
||||
/** |
||||
* PROT command. |
||||
* <ul> |
||||
* <li>C - Clear</li> |
||||
* <li>S - Safe(SSL protocol only)</li> |
||||
* <li>E - Confidential(SSL protocol only)</li> |
||||
* <li>P - Private</li> |
||||
* </ul> |
||||
* <b>N.B.</b> the method calls |
||||
* {@link #setSocketFactory(javax.net.SocketFactory)} and |
||||
* {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} |
||||
* |
||||
* @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. |
||||
* @throws SSLException If the server reply code does not equal {@code 200}. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
*/ |
||||
public void execPROT(String prot) throws SSLException, IOException { |
||||
if (prot == null) { |
||||
prot = DEFAULT_PROT; |
||||
} |
||||
if (!checkPROTValue(prot)) { |
||||
throw new IllegalArgumentException(); |
||||
} |
||||
if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { |
||||
throw new SSLException(getReplyString()); |
||||
} |
||||
if (DEFAULT_PROT.equals(prot)) { |
||||
setSocketFactory(null); |
||||
setServerSocketFactory(null); |
||||
} else { |
||||
setSocketFactory(new FTPSSocketFactory(context)); |
||||
setServerSocketFactory(new FTPSServerSocketFactory(context)); |
||||
initSslContext(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Check the value that can be set in PROT Command value. |
||||
* |
||||
* @param prot Data Channel Protection Level. |
||||
* @return True - A set point is right / False - A set point is not right |
||||
*/ |
||||
private boolean checkPROTValue(String prot) { |
||||
for (String element : PROT_COMMAND_VALUE) { |
||||
if (element.equals(prot)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Send an FTP command. |
||||
* A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} |
||||
* instance to be assigned to a plain {@link Socket} |
||||
* |
||||
* @param command The FTP command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending the command. |
||||
* @throws SSLException if a CCC command fails |
||||
* @see FTP#sendCommand(String) |
||||
*/ |
||||
// Would like to remove this method, but that will break any existing clients that are using CCC
|
||||
@Override public int sendCommand(String command, String args) throws IOException { |
||||
int repCode = super.sendCommand(command, args); |
||||
/* If CCC is issued, restore socket i/o streams to unsecured versions */ |
||||
if (CMD_CCC.equals(command)) { |
||||
if (FTPReply.COMMAND_OK == repCode) { |
||||
_socket_.close(); |
||||
_socket_ = plainSocket; |
||||
_controlInput_ = new BufferedReader( |
||||
new InputStreamReader(_socket_.getInputStream(), getControlEncoding())); |
||||
_controlOutput_ = new BufferedWriter( |
||||
new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding())); |
||||
} else { |
||||
throw new SSLException(getReplyString()); |
||||
} |
||||
} |
||||
return repCode; |
||||
} |
||||
|
||||
/** |
||||
* Returns a socket of the data connection. |
||||
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. |
||||
* |
||||
* @param command The int representation of the FTP command to send. |
||||
* @param arg The arguments to the FTP command. |
||||
* If this parameter is set to null, then the command is sent with |
||||
* no arguments. |
||||
* @return corresponding to the established data connection. |
||||
* Null is returned if an FTP protocol error is reported at any point |
||||
* during the establishment and initialization of the connection. |
||||
* @throws IOException If there is any problem with the connection. |
||||
* @see FTPClient#_openDataConnection_(int, String) |
||||
* @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead |
||||
*/ |
||||
@Override |
||||
// Strictly speaking this is not needed, but it works round a Clirr bug
|
||||
// So rather than invoke the parent code, we do it here
|
||||
@Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException { |
||||
return _openDataConnection_(FTPCommand.getCommand(command), arg); |
||||
} |
||||
|
||||
/** |
||||
* Returns a socket of the data connection. |
||||
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. |
||||
* |
||||
* @param command The textual representation of the FTP command to send. |
||||
* @param arg The arguments to the FTP command. |
||||
* If this parameter is set to null, then the command is sent with |
||||
* no arguments. |
||||
* @return corresponding to the established data connection. |
||||
* Null is returned if an FTP protocol error is reported at any point |
||||
* during the establishment and initialization of the connection. |
||||
* @throws IOException If there is any problem with the connection. |
||||
* @see FTPClient#_openDataConnection_(int, String) |
||||
* @since 3.2 |
||||
*/ |
||||
@Override protected Socket _openDataConnection_(String command, String arg) throws IOException { |
||||
Socket socket = super._openDataConnection_(command, arg); |
||||
_prepareDataSocket_(socket); |
||||
if (socket instanceof SSLSocket) { |
||||
SSLSocket sslSocket = (SSLSocket) socket; |
||||
|
||||
sslSocket.setUseClientMode(isClientMode); |
||||
sslSocket.setEnableSessionCreation(isCreation); |
||||
|
||||
// server mode
|
||||
if (!isClientMode) { |
||||
sslSocket.setNeedClientAuth(isNeedClientAuth); |
||||
sslSocket.setWantClientAuth(isWantClientAuth); |
||||
} |
||||
if (suites != null) { |
||||
sslSocket.setEnabledCipherSuites(suites); |
||||
} |
||||
if (protocols != null) { |
||||
sslSocket.setEnabledProtocols(protocols); |
||||
} |
||||
sslSocket.startHandshake(); |
||||
} |
||||
|
||||
return socket; |
||||
} |
||||
|
||||
/** |
||||
* Performs any custom initialization for a newly created SSLSocket (before |
||||
* the SSL handshake happens). |
||||
* Called by {@link #_openDataConnection_(int, String)} immediately |
||||
* after creating the socket. |
||||
* The default implementation is a no-op |
||||
* |
||||
* @param socket the socket to set up |
||||
* @throws IOException on error |
||||
* @since 3.1 |
||||
*/ |
||||
protected void _prepareDataSocket_(Socket socket) throws IOException { |
||||
} |
||||
|
||||
/** |
||||
* Get the currently configured {@link TrustManager}. |
||||
* |
||||
* @return A TrustManager instance. |
||||
*/ |
||||
public TrustManager getTrustManager() { |
||||
return trustManager; |
||||
} |
||||
|
||||
/** |
||||
* Override the default {@link TrustManager} to use; if set to {@code null}, |
||||
* the default TrustManager from the JVM will be used. |
||||
* |
||||
* @param trustManager The TrustManager implementation to set, may be {@code null} |
||||
* @see TrustManagerUtils |
||||
*/ |
||||
public void setTrustManager(TrustManager trustManager) { |
||||
this.trustManager = trustManager; |
||||
} |
||||
|
||||
/** |
||||
* Get the currently configured {@link HostnameVerifier}. |
||||
* The verifier is only used on client mode connections. |
||||
* |
||||
* @return A HostnameVerifier instance. |
||||
* @since 3.4 |
||||
*/ |
||||
public HostnameVerifier getHostnameVerifier() { |
||||
return hostnameVerifier; |
||||
} |
||||
|
||||
/** |
||||
* Override the default {@link HostnameVerifier} to use. |
||||
* The verifier is only used on client mode connections. |
||||
* |
||||
* @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to |
||||
* disable. |
||||
* @since 3.4 |
||||
*/ |
||||
public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) { |
||||
hostnameVerifier = newHostnameVerifier; |
||||
} |
||||
|
||||
/** |
||||
* Return whether or not endpoint identification using the HTTPS algorithm |
||||
* on Java 1.7+ is enabled. The default behaviour is for this to be disabled. |
||||
* |
||||
* This check is only performed on client mode connections. |
||||
* |
||||
* @return True if enabled, false if not. |
||||
* @since 3.4 |
||||
*/ |
||||
public boolean isEndpointCheckingEnabled() { |
||||
return tlsEndpointChecking; |
||||
} |
||||
|
||||
/** |
||||
* Automatic endpoint identification checking using the HTTPS algorithm |
||||
* is supported on Java 1.7+. The default behaviour is for this to be disabled. |
||||
* |
||||
* This check is only performed on client mode connections. |
||||
* |
||||
* @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on |
||||
* Java 1.7+. |
||||
* @since 3.4 |
||||
*/ |
||||
public void setEndpointCheckingEnabled(boolean enable) { |
||||
tlsEndpointChecking = enable; |
||||
} |
||||
|
||||
/** |
||||
* Closes the connection to the FTP server and restores |
||||
* connection parameters to the default values. |
||||
* <p> |
||||
* Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} |
||||
* to reset the factories that may have been changed during the session, |
||||
* e.g. by {@link #execPROT(String)} |
||||
* |
||||
* @throws IOException If an error occurs while disconnecting. |
||||
* @since 3.0 |
||||
*/ |
||||
@Override public void disconnect() throws IOException { |
||||
super.disconnect(); |
||||
if (plainSocket != null) { |
||||
plainSocket.close(); |
||||
} |
||||
setSocketFactory(null); |
||||
setServerSocketFactory(null); |
||||
} |
||||
|
||||
/** |
||||
* Send the AUTH command with the specified mechanism. |
||||
* |
||||
* @param mechanism The mechanism name to send with the command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execAUTH(String mechanism) throws IOException { |
||||
return sendCommand(CMD_AUTH, mechanism); |
||||
} |
||||
|
||||
/** |
||||
* Send the ADAT command with the specified authentication data. |
||||
* |
||||
* @param data The data to send with the command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execADAT(byte[] data) throws IOException { |
||||
if (data != null) { |
||||
return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); |
||||
} else { |
||||
return sendCommand(CMD_ADAT); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Send the CCC command to the server. |
||||
* The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be |
||||
* assigned |
||||
* to a plain {@link Socket} instances |
||||
* |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execCCC() throws IOException { |
||||
int repCode = sendCommand(CMD_CCC); |
||||
// This will be performed by sendCommand(String, String)
|
||||
// if (FTPReply.isPositiveCompletion(repCode)) {
|
||||
// _socket_.close();
|
||||
// _socket_ = plainSocket;
|
||||
// _controlInput_ = new BufferedReader(
|
||||
// new InputStreamReader(
|
||||
// _socket_.getInputStream(), getControlEncoding()));
|
||||
// _controlOutput_ = new BufferedWriter(
|
||||
// new OutputStreamWriter(
|
||||
// _socket_.getOutputStream(), getControlEncoding()));
|
||||
// }
|
||||
return repCode; |
||||
} |
||||
|
||||
/** |
||||
* Send the MIC command with the specified data. |
||||
* |
||||
* @param data The data to send with the command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execMIC(byte[] data) throws IOException { |
||||
if (data != null) { |
||||
return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); |
||||
} else { |
||||
return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Send the CONF command with the specified data. |
||||
* |
||||
* @param data The data to send with the command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execCONF(byte[] data) throws IOException { |
||||
if (data != null) { |
||||
return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); |
||||
} else { |
||||
return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Send the ENC command with the specified data. |
||||
* |
||||
* @param data The data to send with the command. |
||||
* @return server reply. |
||||
* @throws IOException If an I/O error occurs while sending |
||||
* the command. |
||||
* @since 3.0 |
||||
*/ |
||||
public int execENC(byte[] data) throws IOException { |
||||
if (data != null) { |
||||
return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); |
||||
} else { |
||||
return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parses the given ADAT response line and base64-decodes the data. |
||||
* |
||||
* @param reply The ADAT reply to parse. |
||||
* @return the data in the reply, base64-decoded. |
||||
* @since 3.0 |
||||
*/ |
||||
public byte[] parseADATReply(String reply) { |
||||
if (reply == null) { |
||||
return null; |
||||
} else { |
||||
return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 |
||||
* |
||||
* @param prefix the prefix to find |
||||
* @param reply where to find the prefix |
||||
* @return the remainder of the string after the prefix, or null if the prefix was not present. |
||||
*/ |
||||
private String extractPrefixedData(String prefix, String reply) { |
||||
int idx = reply.indexOf(prefix); |
||||
if (idx == -1) { |
||||
return null; |
||||
} |
||||
// N.B. Cannot use trim before substring as leading space would affect the offset.
|
||||
return reply.substring(idx + prefix.length()).trim(); |
||||
} |
||||
|
||||
// DEPRECATED - for API compatibility only - DO NOT USE
|
||||
|
||||
/** @deprecated - not used - may be removed in a future release */ |
||||
@Deprecated public static String KEYSTORE_ALGORITHM; |
||||
|
||||
/** @deprecated - not used - may be removed in a future release */ |
||||
@Deprecated public static String TRUSTSTORE_ALGORITHM; |
||||
|
||||
/** @deprecated - not used - may be removed in a future release */ |
||||
@Deprecated public static String PROVIDER; |
||||
|
||||
/** @deprecated - not used - may be removed in a future release */ |
||||
@Deprecated public static String STORE_TYPE; |
||||
} |
||||
/* kate: indent-width 4; replace-tabs on; */ |
@ -1,52 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
/** |
||||
* FTPS-specific commands. |
||||
* |
||||
* @since 2.0 |
||||
* @deprecated 3.0 DO NOT USE |
||||
*/ |
||||
@Deprecated public final class FTPSCommand { |
||||
public static final int AUTH = 0; |
||||
public static final int ADAT = 1; |
||||
public static final int PBSZ = 2; |
||||
public static final int PROT = 3; |
||||
public static final int CCC = 4; |
||||
|
||||
public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; |
||||
public static final int AUTHENTICATION_SECURITY_DATA = ADAT; |
||||
public static final int PROTECTION_BUFFER_SIZE = PBSZ; |
||||
public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; |
||||
public static final int CLEAR_COMMAND_CHANNEL = CCC; |
||||
|
||||
private static final String[] _commands = { "AUTH", "ADAT", "PBSZ", "PROT", "CCC" }; |
||||
|
||||
/** |
||||
* Retrieve the FTPS command string corresponding to a specified |
||||
* command code. |
||||
* |
||||
* @param command The command code. |
||||
* @return The FTPS command string corresponding to a specified |
||||
* command code. |
||||
*/ |
||||
public static final String getCommand(int command) { |
||||
return _commands[command]; |
||||
} |
||||
} |
@ -1,72 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.InetAddress; |
||||
import java.net.ServerSocket; |
||||
|
||||
import javax.net.ServerSocketFactory; |
||||
import javax.net.ssl.SSLContext; |
||||
import javax.net.ssl.SSLServerSocket; |
||||
|
||||
/** |
||||
* Server socket factory for FTPS connections. |
||||
* |
||||
* @since 2.2 |
||||
*/ |
||||
public class FTPSServerSocketFactory extends ServerSocketFactory { |
||||
|
||||
/** Factory for secure socket factories */ |
||||
private final SSLContext context; |
||||
|
||||
public FTPSServerSocketFactory(SSLContext context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
// Override the default superclass method
|
||||
@Override public ServerSocket createServerSocket() throws IOException { |
||||
return init(this.context.getServerSocketFactory().createServerSocket()); |
||||
} |
||||
|
||||
@Override public ServerSocket createServerSocket(int port) throws IOException { |
||||
return init(this.context.getServerSocketFactory().createServerSocket(port)); |
||||
} |
||||
|
||||
@Override public ServerSocket createServerSocket(int port, int backlog) throws IOException { |
||||
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); |
||||
} |
||||
|
||||
@Override public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) |
||||
throws IOException { |
||||
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); |
||||
} |
||||
|
||||
/** |
||||
* Sets the socket so newly accepted connections will use SSL client mode. |
||||
* |
||||
* @param socket the SSLServerSocket to initialise |
||||
* @return the socket |
||||
* @throws ClassCastException if socket is not an instance of SSLServerSocket |
||||
*/ |
||||
public ServerSocket init(ServerSocket socket) { |
||||
((SSLServerSocket) socket).setUseClientMode(true); |
||||
return socket; |
||||
} |
||||
} |
||||
|
@ -1,116 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.InetAddress; |
||||
import java.net.Socket; |
||||
import java.net.UnknownHostException; |
||||
|
||||
import javax.net.SocketFactory; |
||||
import javax.net.ssl.SSLContext; |
||||
|
||||
/** |
||||
* Implementation of org.apache.commons.net.SocketFactory |
||||
* |
||||
* @since 2.0 |
||||
*/ |
||||
public class FTPSSocketFactory extends SocketFactory { |
||||
|
||||
private final SSLContext context; |
||||
|
||||
public FTPSSocketFactory(SSLContext context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
// Override the default implementation
|
||||
@Override public Socket createSocket() throws IOException { |
||||
return this.context.getSocketFactory().createSocket(); |
||||
} |
||||
|
||||
@Override public Socket createSocket(String address, int port) |
||||
throws UnknownHostException, IOException { |
||||
return this.context.getSocketFactory().createSocket(address, port); |
||||
} |
||||
|
||||
@Override public Socket createSocket(InetAddress address, int port) throws IOException { |
||||
return this.context.getSocketFactory().createSocket(address, port); |
||||
} |
||||
|
||||
@Override |
||||
public Socket createSocket(String address, int port, InetAddress localAddress, int localPort) |
||||
throws UnknownHostException, IOException { |
||||
return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); |
||||
} |
||||
|
||||
@Override |
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) |
||||
throws IOException { |
||||
return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); |
||||
} |
||||
|
||||
// DEPRECATED METHODS - for API compatibility only - DO NOT USE
|
||||
|
||||
/** |
||||
* @param port the port |
||||
* @return the socket |
||||
* @throws IOException on error |
||||
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead} |
||||
*/ |
||||
@Deprecated public java.net.ServerSocket createServerSocket(int port) throws IOException { |
||||
return this.init(this.context.getServerSocketFactory().createServerSocket(port)); |
||||
} |
||||
|
||||
/** |
||||
* @param port the port |
||||
* @param backlog the backlog |
||||
* @return the socket |
||||
* @throws IOException on error |
||||
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead} |
||||
*/ |
||||
@Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog) |
||||
throws IOException { |
||||
return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); |
||||
} |
||||
|
||||
/** |
||||
* @param port the port |
||||
* @param backlog the backlog |
||||
* @param ifAddress the interface
|
||||
* @return the socket |
||||
* @throws IOException on error |
||||
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress) |
||||
* instead} |
||||
*/ |
||||
@Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog, |
||||
InetAddress ifAddress) throws IOException { |
||||
return this.init( |
||||
this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); |
||||
} |
||||
|
||||
/** |
||||
* @param socket the socket |
||||
* @return the socket |
||||
* @throws IOException on error |
||||
* @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)} |
||||
*/ |
||||
@Deprecated public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException { |
||||
((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true); |
||||
return socket; |
||||
} |
||||
} |
@ -1,54 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import aria.apache.commons.net.util.TrustManagerUtils; |
||||
import java.security.cert.CertificateException; |
||||
import java.security.cert.X509Certificate; |
||||
|
||||
import javax.net.ssl.X509TrustManager; |
||||
|
||||
/** |
||||
* Do not use. |
||||
* |
||||
* @since 2.0 |
||||
* @deprecated 3.0 use |
||||
* {@link TrustManagerUtils#getValidateServerCertificateTrustManager() |
||||
* TrustManagerUtils#getValidateServerCertificateTrustManager()} instead |
||||
*/ |
||||
@Deprecated public class FTPSTrustManager implements X509TrustManager { |
||||
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {}; |
||||
|
||||
/** |
||||
* No-op |
||||
*/ |
||||
@Override public void checkClientTrusted(X509Certificate[] certificates, String authType) { |
||||
return; |
||||
} |
||||
|
||||
@Override public void checkServerTrusted(X509Certificate[] certificates, String authType) |
||||
throws CertificateException { |
||||
for (X509Certificate certificate : certificates) { |
||||
certificate.checkValidity(); |
||||
} |
||||
} |
||||
|
||||
@Override public X509Certificate[] getAcceptedIssuers() { |
||||
return EMPTY_X509CERTIFICATE_ARRAY; |
||||
} |
||||
} |
@ -1,33 +0,0 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package aria.apache.commons.net.ftp; |
||||
|
||||
import aria.apache.commons.net.io.CopyStreamListener; |
||||
|
||||
/** |
||||
* Created by AriaL on 2017/9/26. |
||||
* ftp 上传文件流事件监听 |
||||
*/ |
||||
public interface OnFtpInputStreamListener { |
||||
/** |
||||
* {@link CopyStreamListener#bytesTransferred(long, int, long)} |
||||
* |
||||
* @param totalBytesTransferred 已经上传的文件长度 |
||||
* @param bytesTransferred 上传byte长度 |
||||
*/ |
||||
void onFtpInputStream(FTPClient client, long totalBytesTransferred, int bytesTransferred, |
||||
long streamSize); |
||||
} |
@ -1,21 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
/** |
||||
* FTP and FTPS support classes |
||||
*/ |
||||
package aria.apache.commons.net.ftp; |
@ -1,59 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; |
||||
|
||||
/** |
||||
* This implementation allows to pack some FileEntryParsers together |
||||
* and handle the case where to returned dirstyle isnt clearly defined. |
||||
* The matching parser will be cached. |
||||
* If the cached parser wont match due to the server changed the dirstyle, |
||||
* a new matching parser will be searched. |
||||
*/ |
||||
public class CompositeFileEntryParser extends FTPFileEntryParserImpl { |
||||
private final FTPFileEntryParser[] ftpFileEntryParsers; |
||||
private FTPFileEntryParser cachedFtpFileEntryParser; |
||||
|
||||
public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) { |
||||
super(); |
||||
|
||||
this.cachedFtpFileEntryParser = null; |
||||
this.ftpFileEntryParsers = ftpFileEntryParsers; |
||||
} |
||||
|
||||
@Override public FTPFile parseFTPEntry(String listEntry) { |
||||
if (cachedFtpFileEntryParser != null) { |
||||
FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); |
||||
if (matched != null) { |
||||
return matched; |
||||
} |
||||
} else { |
||||
for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers) { |
||||
FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); |
||||
if (matched != null) { |
||||
cachedFtpFileEntryParser = ftpFileEntryParser; |
||||
return matched; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -1,123 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.Configurable; |
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import java.text.ParseException; |
||||
import java.util.Calendar; |
||||
|
||||
/** |
||||
* <p> |
||||
* This abstract class implements the common timestamp parsing |
||||
* algorithm for all the concrete parsers. Classes derived from |
||||
* this one will parse file listings via a supplied regular expression |
||||
* that pulls out the date portion as a separate string which is |
||||
* passed to the underlying {@link FTPTimestampParser delegate} to |
||||
* handle parsing of the file timestamp. |
||||
* <p> |
||||
* This class also implements the {@link Configurable Configurable} |
||||
* interface to allow the parser to be configured from the outside. |
||||
* |
||||
* @since 1.4 |
||||
*/ |
||||
public abstract class ConfigurableFTPFileEntryParserImpl extends RegexFTPFileEntryParserImpl |
||||
implements Configurable { |
||||
|
||||
private final FTPTimestampParser timestampParser; |
||||
|
||||
/** |
||||
* constructor for this abstract class. |
||||
* |
||||
* @param regex Regular expression used main parsing of the |
||||
* file listing. |
||||
*/ |
||||
public ConfigurableFTPFileEntryParserImpl(String regex) { |
||||
super(regex); |
||||
this.timestampParser = new FTPTimestampParserImpl(); |
||||
} |
||||
|
||||
/** |
||||
* constructor for this abstract class. |
||||
* |
||||
* @param regex Regular expression used main parsing of the |
||||
* file listing. |
||||
* @param flags the flags to apply, see |
||||
* {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for |
||||
* none. |
||||
* @since 3.4 |
||||
*/ |
||||
public ConfigurableFTPFileEntryParserImpl(String regex, int flags) { |
||||
super(regex, flags); |
||||
this.timestampParser = new FTPTimestampParserImpl(); |
||||
} |
||||
|
||||
/** |
||||
* This method is called by the concrete parsers to delegate |
||||
* timestamp parsing to the timestamp parser. |
||||
* |
||||
* @param timestampStr the timestamp string pulled from the |
||||
* file listing by the regular expression parser, to be submitted |
||||
* to the <code>timestampParser</code> for extracting the timestamp. |
||||
* @return a <code>java.util.Calendar</code> containing results of the |
||||
* timestamp parse. |
||||
* @throws ParseException on parse error |
||||
*/ |
||||
public Calendar parseTimestamp(String timestampStr) throws ParseException { |
||||
return this.timestampParser.parseTimestamp(timestampStr); |
||||
} |
||||
|
||||
/** |
||||
* Implementation of the {@link Configurable Configurable} |
||||
* interface. Configures this parser by delegating to the |
||||
* underlying Configurable FTPTimestampParser implementation, ' |
||||
* passing it the supplied {@link FTPClientConfig FTPClientConfig} |
||||
* if that is non-null or a default configuration defined by |
||||
* each concrete subclass. |
||||
* |
||||
* @param config the configuration to be used to configure this parser. |
||||
* If it is null, a default configuration defined by |
||||
* each concrete subclass is used instead. |
||||
*/ |
||||
@Override public void configure(FTPClientConfig config) { |
||||
if (this.timestampParser instanceof Configurable) { |
||||
FTPClientConfig defaultCfg = getDefaultConfiguration(); |
||||
if (config != null) { |
||||
if (null == config.getDefaultDateFormatStr()) { |
||||
config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); |
||||
} |
||||
if (null == config.getRecentDateFormatStr()) { |
||||
config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); |
||||
} |
||||
((Configurable) this.timestampParser).configure(config); |
||||
} else { |
||||
((Configurable) this.timestampParser).configure(defaultCfg); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Each concrete subclass must define this member to create |
||||
* a default configuration to be used when that subclass is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for the subclass. |
||||
*/ |
||||
protected abstract FTPClientConfig getDefaultConfiguration(); |
||||
} |
@ -1,254 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.Configurable; |
||||
import aria.apache.commons.net.ftp.FTPClient; |
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* This is the default implementation of the |
||||
* FTPFileEntryParserFactory interface. This is the |
||||
* implementation that will be used by |
||||
* FTPClient.listFiles() |
||||
* if no other implementation has been specified. |
||||
* |
||||
* @see FTPClient#listFiles |
||||
* @see FTPClient#setParserFactory |
||||
*/ |
||||
public class DefaultFTPFileEntryParserFactory implements FTPFileEntryParserFactory { |
||||
|
||||
// Match a plain Java Identifier
|
||||
private static final String JAVA_IDENTIFIER = |
||||
"\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart})*"; |
||||
// Match a qualified name, e.g. a.b.c.Name - but don't allow the default package as that would allow "VMS"/"UNIX" etc.
|
||||
private static final String JAVA_QUALIFIED_NAME = |
||||
"(" + JAVA_IDENTIFIER + "\\.)+" + JAVA_IDENTIFIER; |
||||
// Create the pattern, as it will be reused many times
|
||||
private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME); |
||||
|
||||
/** |
||||
* This default implementation of the FTPFileEntryParserFactory |
||||
* interface works according to the following logic: |
||||
* First it attempts to interpret the supplied key as a fully |
||||
* qualified classname (default package is not allowed) of a class implementing the |
||||
* FTPFileEntryParser interface. If that succeeds, a parser |
||||
* object of this class is instantiated and is returned; |
||||
* otherwise it attempts to interpret the key as an identirier |
||||
* commonly used by the FTP SYST command to identify systems. |
||||
* <p> |
||||
* If <code>key</code> is not recognized as a fully qualified |
||||
* classname known to the system, this method will then attempt |
||||
* to see whether it <b>contains</b> a string identifying one of |
||||
* the known parsers. This comparison is <b>case-insensitive</b>. |
||||
* The intent here is where possible, to select as keys strings |
||||
* which are returned by the SYST command on the systems which |
||||
* the corresponding parser successfully parses. This enables |
||||
* this factory to be used in the auto-detection system. |
||||
* |
||||
* @param key should be a fully qualified classname corresponding to |
||||
* a class implementing the FTPFileEntryParser interface<br> |
||||
* OR<br> |
||||
* a string containing (case-insensitively) one of the |
||||
* following keywords: |
||||
* <ul> |
||||
* <li>{@link FTPClientConfig#SYST_UNIX UNIX}</li> |
||||
* <li>{@link FTPClientConfig#SYST_NT WINDOWS}</li> |
||||
* <li>{@link FTPClientConfig#SYST_OS2 OS/2}</li> |
||||
* <li>{@link FTPClientConfig#SYST_OS400 OS/400}</li> |
||||
* <li>{@link FTPClientConfig#SYST_AS400 AS/400}</li> |
||||
* <li>{@link FTPClientConfig#SYST_VMS VMS}</li> |
||||
* <li>{@link FTPClientConfig#SYST_MVS MVS}</li> |
||||
* <li>{@link FTPClientConfig#SYST_NETWARE NETWARE}</li> |
||||
* <li>{@link FTPClientConfig#SYST_L8 TYPE:L8}</li> |
||||
* </ul> |
||||
* @return the FTPFileEntryParser corresponding to the supplied key. |
||||
* @throws ParserInitializationException thrown if for any reason the factory cannot resolve |
||||
* the supplied key into an FTPFileEntryParser. |
||||
* @see FTPFileEntryParser |
||||
*/ |
||||
@Override public FTPFileEntryParser createFileEntryParser(String key) { |
||||
if (key == null) { |
||||
throw new ParserInitializationException("Parser key cannot be null"); |
||||
} |
||||
return createFileEntryParser(key, null); |
||||
} |
||||
|
||||
// Common method to process both key and config parameters.
|
||||
private FTPFileEntryParser createFileEntryParser(String key, FTPClientConfig config) { |
||||
FTPFileEntryParser parser = null; |
||||
|
||||
// Is the key a possible class name?
|
||||
if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) { |
||||
try { |
||||
Class<?> parserClass = Class.forName(key); |
||||
try { |
||||
parser = (FTPFileEntryParser) parserClass.newInstance(); |
||||
} catch (ClassCastException e) { |
||||
throw new ParserInitializationException(parserClass.getName() |
||||
+ " does not implement the interface " |
||||
+ "FTPFileEntryParser.", e); |
||||
} catch (Exception e) { |
||||
throw new ParserInitializationException("Error initializing parser", e); |
||||
} catch (ExceptionInInitializerError e) { |
||||
throw new ParserInitializationException("Error initializing parser", e); |
||||
} |
||||
} catch (ClassNotFoundException e) { |
||||
// OK, assume it is an alias
|
||||
} |
||||
} |
||||
|
||||
if (parser == null) { // Now try for aliases
|
||||
String ukey = key.toUpperCase(java.util.Locale.ENGLISH); |
||||
if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) { |
||||
parser = new UnixFTPEntryParser(config, true); |
||||
} |
||||
// must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it
|
||||
else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) { |
||||
parser = new UnixFTPEntryParser(config, false); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) { |
||||
parser = new VMSVersioningFTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) { |
||||
parser = createNTFTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) { |
||||
parser = new OS2FTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 |
||||
|| ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) { |
||||
parser = createOS400FTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) { |
||||
parser = new MVSFTPEntryParser(); // Does not currently support config parameter
|
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) { |
||||
parser = new NetwareFTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0) { |
||||
parser = new MacOsPeterFTPEntryParser(config); |
||||
} else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0) { |
||||
// L8 normally means Unix, but move it to the end for some L8 systems that aren't.
|
||||
// This check should be last!
|
||||
parser = new UnixFTPEntryParser(config); |
||||
} else { |
||||
throw new ParserInitializationException("Unknown parser type: " + key); |
||||
} |
||||
} |
||||
|
||||
if (parser instanceof Configurable) { |
||||
((Configurable) parser).configure(config); |
||||
} |
||||
return parser; |
||||
} |
||||
|
||||
/** |
||||
* <p>Implementation extracts a key from the supplied |
||||
* {@link FTPClientConfig FTPClientConfig} |
||||
* parameter and creates an object implementing the |
||||
* interface FTPFileEntryParser and uses the supplied configuration |
||||
* to configure it. |
||||
* </p><p> |
||||
* Note that this method will generally not be called in scenarios |
||||
* that call for autodetection of parser type but rather, for situations |
||||
* where the user knows that the server uses a non-default configuration |
||||
* and knows what that configuration is. |
||||
* </p> |
||||
* |
||||
* @param config A {@link FTPClientConfig FTPClientConfig} |
||||
* used to configure the parser created |
||||
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. |
||||
* @throws ParserInitializationException Thrown on any exception in instantiation |
||||
* @throws NullPointerException if {@code config} is {@code null} |
||||
* @since 1.4 |
||||
*/ |
||||
@Override public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) |
||||
throws ParserInitializationException { |
||||
String key = config.getServerSystemKey(); |
||||
return createFileEntryParser(key, config); |
||||
} |
||||
|
||||
public FTPFileEntryParser createUnixFTPEntryParser() { |
||||
return new UnixFTPEntryParser(); |
||||
} |
||||
|
||||
public FTPFileEntryParser createVMSVersioningFTPEntryParser() { |
||||
return new VMSVersioningFTPEntryParser(); |
||||
} |
||||
|
||||
public FTPFileEntryParser createNetwareFTPEntryParser() { |
||||
return new NetwareFTPEntryParser(); |
||||
} |
||||
|
||||
public FTPFileEntryParser createNTFTPEntryParser() { |
||||
return createNTFTPEntryParser(null); |
||||
} |
||||
|
||||
/** |
||||
* Creates an NT FTP parser: if the config exists, and the system key equals |
||||
* {@link FTPClientConfig.SYST_NT} then a plain {@link NTFTPEntryParser} is used, |
||||
* otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used. |
||||
* |
||||
* @param config the config to use, may be {@code null} |
||||
* @return the parser |
||||
*/ |
||||
private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) { |
||||
if (config != null && FTPClientConfig.SYST_NT.equals(config.getServerSystemKey())) { |
||||
return new NTFTPEntryParser(config); |
||||
} else { |
||||
// clone the config as it may be changed by the parsers (NET-602)
|
||||
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; |
||||
return new CompositeFileEntryParser(new FTPFileEntryParser[] { |
||||
new NTFTPEntryParser(config), new UnixFTPEntryParser(config2, |
||||
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals( |
||||
config2.getServerSystemKey())) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
public FTPFileEntryParser createOS2FTPEntryParser() { |
||||
return new OS2FTPEntryParser(); |
||||
} |
||||
|
||||
public FTPFileEntryParser createOS400FTPEntryParser() { |
||||
return createOS400FTPEntryParser(null); |
||||
} |
||||
|
||||
/** |
||||
* Creates an OS400 FTP parser: if the config exists, and the system key equals |
||||
* {@link FTPClientConfig.SYST_OS400} then a plain {@link OS400FTPEntryParser} is used, |
||||
* otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used. |
||||
* |
||||
* @param config the config to use, may be {@code null} |
||||
* @return the parser |
||||
*/ |
||||
private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) { |
||||
if (config != null && FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) { |
||||
return new OS400FTPEntryParser(config); |
||||
} else { |
||||
// clone the config as it may be changed by the parsers (NET-602)
|
||||
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; |
||||
return new CompositeFileEntryParser(new FTPFileEntryParser[] { |
||||
new OS400FTPEntryParser(config), new UnixFTPEntryParser(config2, |
||||
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals( |
||||
config2.getServerSystemKey())) |
||||
}); |
||||
} |
||||
} |
||||
|
||||
public FTPFileEntryParser createMVSEntryParser() { |
||||
return new MVSFTPEntryParser(); |
||||
} |
||||
} |
||||
|
@ -1,159 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.util.Calendar; |
||||
|
||||
/** |
||||
* Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. |
||||
* Here is a sample of the sort of output line this parser processes: |
||||
* "-C--E-----FTP B QUA1I1 18128 41 Aug 12 13:56 QUADTEST" |
||||
* <P><B> |
||||
* Note: EnterpriseUnixFTPEntryParser can only be instantiated through the |
||||
* DefaultFTPParserFactory by classname. It will not be chosen |
||||
* by the autodetection scheme. |
||||
* </B> |
||||
* |
||||
* @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
* @see DefaultFTPFileEntryParserFactory |
||||
*/ |
||||
public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl { |
||||
|
||||
/** |
||||
* months abbreviations looked for by this parser. Also used |
||||
* to determine <b>which</b> month has been matched by the parser. |
||||
*/ |
||||
private static final String MONTHS = "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; |
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
*/ |
||||
private static final String REGEX = |
||||
"(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" |
||||
+ "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" |
||||
+ "(\\S*)\\s*" |
||||
// 12
|
||||
+ "(\\S+)\\s*" |
||||
// 13
|
||||
+ "(\\S*)\\s*" |
||||
// 14 user
|
||||
+ "(\\d*)\\s*" |
||||
// 15 group
|
||||
+ "(\\d*)\\s*" |
||||
// 16 filesize
|
||||
+ MONTHS |
||||
// 17 month
|
||||
+ "\\s*" |
||||
// TODO should the space be optional?
|
||||
// TODO \\d* should be \\d? surely ? Otherwise 01111 is allowed
|
||||
+ "((?:[012]\\d*)|(?:3[01]))\\s*" |
||||
// 18 date [012]\d* or 3[01]
|
||||
+ "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" |
||||
// 20 \d\d\d\d = year OR
|
||||
// 21 [01]\d or 2[0123] hour + ':'
|
||||
// 22 [012345]\d = minute
|
||||
+ "(\\S*)(\\s*.*)"; // 23 name
|
||||
|
||||
/** |
||||
* The sole constructor for a EnterpriseUnixFTPEntryParser object. |
||||
*/ |
||||
public EnterpriseUnixFTPEntryParser() { |
||||
super(REGEX); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of a unix FTP server file listing and converts it into a |
||||
* usable format in the form of an <code> FTPFile </code> instance. If |
||||
* the file listing line doesn't describe a file, <code> null </code> is |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
|
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
|
||||
if (matches(entry)) { |
||||
String usr = group(14); |
||||
String grp = group(15); |
||||
String filesize = group(16); |
||||
String mo = group(17); |
||||
String da = group(18); |
||||
String yr = group(20); |
||||
String hr = group(21); |
||||
String min = group(22); |
||||
String name = group(23); |
||||
|
||||
file.setType(FTPFile.FILE_TYPE); |
||||
file.setUser(usr); |
||||
file.setGroup(grp); |
||||
try { |
||||
file.setSize(Long.parseLong(filesize)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
Calendar cal = Calendar.getInstance(); |
||||
cal.set(Calendar.MILLISECOND, 0); |
||||
cal.set(Calendar.SECOND, 0); |
||||
cal.set(Calendar.MINUTE, 0); |
||||
cal.set(Calendar.HOUR_OF_DAY, 0); |
||||
|
||||
int pos = MONTHS.indexOf(mo); |
||||
int month = pos / 4; |
||||
final int missingUnit; // the first missing unit
|
||||
try { |
||||
|
||||
if (yr != null) { |
||||
// it's a year; there are no hours and minutes
|
||||
cal.set(Calendar.YEAR, Integer.parseInt(yr)); |
||||
missingUnit = Calendar.HOUR_OF_DAY; |
||||
} else { |
||||
// it must be hour/minute or we wouldn't have matched
|
||||
missingUnit = Calendar.SECOND; |
||||
int year = cal.get(Calendar.YEAR); |
||||
|
||||
// if the month we're reading is greater than now, it must
|
||||
// be last year
|
||||
if (cal.get(Calendar.MONTH) < month) { |
||||
year--; |
||||
} |
||||
cal.set(Calendar.YEAR, year); |
||||
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hr)); |
||||
cal.set(Calendar.MINUTE, Integer.parseInt(min)); |
||||
} |
||||
cal.set(Calendar.MONTH, month); |
||||
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da)); |
||||
cal.clear(missingUnit); |
||||
file.setTimestamp(cal); |
||||
} catch (NumberFormatException e) { |
||||
// do nothing, date will be uninitialized
|
||||
} |
||||
file.setName(name); |
||||
|
||||
return file; |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -1,63 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
|
||||
/** |
||||
* The interface describes a factory for creating FTPFileEntryParsers. |
||||
* |
||||
* @since 1.2 |
||||
*/ |
||||
public interface FTPFileEntryParserFactory { |
||||
/** |
||||
* Implementation should be a method that decodes the |
||||
* supplied key and creates an object implementing the |
||||
* interface FTPFileEntryParser. |
||||
* |
||||
* @param key A string that somehow identifies an |
||||
* FTPFileEntryParser to be created. |
||||
* @return the FTPFileEntryParser created. |
||||
* @throws ParserInitializationException Thrown on any exception in instantiation |
||||
*/ |
||||
public FTPFileEntryParser createFileEntryParser(String key) throws ParserInitializationException; |
||||
|
||||
/** |
||||
* <p> |
||||
* Implementation should be a method that extracts |
||||
* a key from the supplied {@link FTPClientConfig FTPClientConfig} |
||||
* parameter and creates an object implementing the |
||||
* interface FTPFileEntryParser and uses the supplied configuration |
||||
* to configure it. |
||||
* </p><p> |
||||
* Note that this method will generally not be called in scenarios |
||||
* that call for autodetection of parser type but rather, for situations |
||||
* where the user knows that the server uses a non-default configuration |
||||
* and knows what that configuration is. |
||||
* </p> |
||||
* |
||||
* @param config A {@link FTPClientConfig FTPClientConfig} |
||||
* used to configure the parser created |
||||
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. |
||||
* @throws ParserInitializationException Thrown on any exception in instantiation |
||||
* @since 1.4 |
||||
*/ |
||||
public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) |
||||
throws ParserInitializationException; |
||||
} |
@ -1,53 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import java.text.ParseException; |
||||
import java.util.Calendar; |
||||
|
||||
/** |
||||
* This interface specifies the concept of parsing an FTP server's |
||||
* timestamp. |
||||
* |
||||
* @since 1.4 |
||||
*/ |
||||
public interface FTPTimestampParser { |
||||
|
||||
/** |
||||
* the default default date format. |
||||
*/ |
||||
public static final String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; |
||||
/** |
||||
* the default recent date format. |
||||
*/ |
||||
public static final String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; |
||||
|
||||
/** |
||||
* Parses the supplied datestamp parameter. This parameter typically would |
||||
* have been pulled from a longer FTP listing via the regular expression |
||||
* mechanism |
||||
* |
||||
* @param timestampStr - the timestamp portion of the FTP directory listing |
||||
* to be parsed |
||||
* @return a <code>java.util.Calendar</code> object initialized to the date |
||||
* parsed by the parser |
||||
* @throws ParseException if none of the parser mechanisms belonging to |
||||
* the implementor can parse the input. |
||||
*/ |
||||
public Calendar parseTimestamp(String timestampStr) throws ParseException; |
||||
} |
@ -1,403 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.Configurable; |
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import java.text.DateFormatSymbols; |
||||
import java.text.ParseException; |
||||
import java.text.ParsePosition; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
import java.util.TimeZone; |
||||
|
||||
/** |
||||
* Default implementation of the {@link FTPTimestampParser FTPTimestampParser} |
||||
* interface also implements the {@link Configurable Configurable} |
||||
* interface to allow the parsing to be configured from the outside. |
||||
* |
||||
* @see ConfigurableFTPFileEntryParserImpl |
||||
* @since 1.4 |
||||
*/ |
||||
public class FTPTimestampParserImpl implements FTPTimestampParser, Configurable { |
||||
|
||||
/** The date format for all dates, except possibly recent dates. Assumed to include the year. */ |
||||
private SimpleDateFormat defaultDateFormat; |
||||
/* The index in CALENDAR_UNITS of the smallest time unit in defaultDateFormat */ |
||||
private int defaultDateSmallestUnitIndex; |
||||
|
||||
/** The format used for recent dates (which don't have the year). May be null. */ |
||||
private SimpleDateFormat recentDateFormat; |
||||
/* The index in CALENDAR_UNITS of the smallest time unit in recentDateFormat */ |
||||
private int recentDateSmallestUnitIndex; |
||||
|
||||
private boolean lenientFutureDates = false; |
||||
|
||||
/* |
||||
* List of units in order of increasing significance. |
||||
* This allows the code to clear all units in the Calendar until it |
||||
* reaches the least significant unit in the parse string. |
||||
* The date formats are analysed to find the least significant |
||||
* unit (e.g. Minutes or Milliseconds) and the appropriate index to |
||||
* the array is saved. |
||||
* This is done by searching the array for the unit specifier, |
||||
* and returning the index. When clearing the Calendar units, |
||||
* the code loops through the array until the previous entry. |
||||
* e.g. for MINUTE it would clear MILLISECOND and SECOND |
||||
*/ |
||||
private static final int[] CALENDAR_UNITS = { |
||||
Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, |
||||
Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR |
||||
}; |
||||
|
||||
/* |
||||
* Return the index to the array representing the least significant |
||||
* unit found in the date format. |
||||
* Default is 0 (to avoid dropping precision) |
||||
*/ |
||||
private static int getEntry(SimpleDateFormat dateFormat) { |
||||
if (dateFormat == null) { |
||||
return 0; |
||||
} |
||||
final String FORMAT_CHARS = "SsmHdM"; |
||||
final String pattern = dateFormat.toPattern(); |
||||
for (char ch : FORMAT_CHARS.toCharArray()) { |
||||
if (pattern.indexOf(ch) != -1) { // found the character
|
||||
switch (ch) { |
||||
case 'S': |
||||
return indexOf(Calendar.MILLISECOND); |
||||
case 's': |
||||
return indexOf(Calendar.SECOND); |
||||
case 'm': |
||||
return indexOf(Calendar.MINUTE); |
||||
case 'H': |
||||
return indexOf(Calendar.HOUR_OF_DAY); |
||||
case 'd': |
||||
return indexOf(Calendar.DAY_OF_MONTH); |
||||
case 'M': |
||||
return indexOf(Calendar.MONTH); |
||||
} |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/* |
||||
* Find the entry in the CALENDAR_UNITS array. |
||||
*/ |
||||
private static int indexOf(int calendarUnit) { |
||||
int i; |
||||
for (i = 0; i < CALENDAR_UNITS.length; i++) { |
||||
if (calendarUnit == CALENDAR_UNITS[i]) { |
||||
return i; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
/* |
||||
* Sets the Calendar precision (used by FTPFile#toFormattedDate) by clearing |
||||
* the immediately preceeding unit (if any). |
||||
* Unfortunately the clear(int) method results in setting all other units. |
||||
*/ |
||||
private static void setPrecision(int index, Calendar working) { |
||||
if (index <= 0) { // e.g. MILLISECONDS
|
||||
return; |
||||
} |
||||
final int field = CALENDAR_UNITS[index - 1]; |
||||
// Just in case the analysis is wrong, stop clearing if
|
||||
// field value is not the default.
|
||||
final int value = working.get(field); |
||||
if (value != 0) { // don't reset if it has a value
|
||||
// new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG
|
||||
} else { |
||||
working.clear(field); // reset just the required field
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The only constructor for this class. |
||||
*/ |
||||
public FTPTimestampParserImpl() { |
||||
setDefaultDateFormat(DEFAULT_SDF, null); |
||||
setRecentDateFormat(DEFAULT_RECENT_SDF, null); |
||||
} |
||||
|
||||
/** |
||||
* Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} |
||||
* in the {@link FTPTimestampParser FTPTimestampParser} interface
|
||||
* according to this algorithm: |
||||
* |
||||
* If the recentDateFormat member has been defined, try to parse the |
||||
* supplied string with that. If that parse fails, or if the recentDateFormat |
||||
* member has not been defined, attempt to parse with the defaultDateFormat |
||||
* member. If that fails, throw a ParseException. |
||||
* |
||||
* This method assumes that the server time is the same as the local time. |
||||
* |
||||
* @param timestampStr The timestamp to be parsed |
||||
* @return a Calendar with the parsed timestamp |
||||
* @see FTPTimestampParserImpl#parseTimestamp(String, Calendar) |
||||
*/ |
||||
@Override public Calendar parseTimestamp(String timestampStr) throws ParseException { |
||||
Calendar now = Calendar.getInstance(); |
||||
return parseTimestamp(timestampStr, now); |
||||
} |
||||
|
||||
/** |
||||
* If the recentDateFormat member has been defined, try to parse the |
||||
* supplied string with that. If that parse fails, or if the recentDateFormat |
||||
* member has not been defined, attempt to parse with the defaultDateFormat |
||||
* member. If that fails, throw a ParseException. |
||||
* |
||||
* This method allows a {@link Calendar} instance to be passed in which represents the |
||||
* current (system) time. |
||||
* |
||||
* @param timestampStr The timestamp to be parsed |
||||
* @param serverTime The current time for the server |
||||
* @return the calendar |
||||
* @throws ParseException if timestamp cannot be parsed |
||||
* @see FTPTimestampParser#parseTimestamp(String) |
||||
* @since 1.5 |
||||
*/ |
||||
public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { |
||||
Calendar working = (Calendar) serverTime.clone(); |
||||
working.setTimeZone(getServerTimeZone()); // is this needed?
|
||||
|
||||
Date parsed = null; |
||||
|
||||
if (recentDateFormat != null) { |
||||
Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it
|
||||
now.setTimeZone(this.getServerTimeZone()); |
||||
if (lenientFutureDates) { |
||||
// add a day to "now" so that "slop" doesn't cause a date
|
||||
// slightly in the future to roll back a full year. (Bug 35181 => NET-83)
|
||||
now.add(Calendar.DAY_OF_MONTH, 1); |
||||
} |
||||
// The Java SimpleDateFormat class uses the epoch year 1970 if not present in the input
|
||||
// As 1970 was not a leap year, it cannot parse "Feb 29" correctly.
|
||||
// Java 1.5+ returns Mar 1 1970
|
||||
// Temporarily add the current year to the short date time
|
||||
// to cope with short-date leap year strings.
|
||||
// Since Feb 29 is more that 6 months from the end of the year, this should be OK for
|
||||
// all instances of short dates which are +- 6 months from current date.
|
||||
// TODO this won't always work for systems that use short dates +0/-12months
|
||||
// e.g. if today is Jan 1 2001 and the short date is Feb 29
|
||||
String year = Integer.toString(now.get(Calendar.YEAR)); |
||||
String timeStampStrPlusYear = timestampStr + " " + year; |
||||
SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", |
||||
recentDateFormat.getDateFormatSymbols()); |
||||
hackFormatter.setLenient(false); |
||||
hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); |
||||
ParsePosition pp = new ParsePosition(0); |
||||
parsed = hackFormatter.parse(timeStampStrPlusYear, pp); |
||||
// Check if we parsed the full string, if so it must have been a short date originally
|
||||
if (parsed != null && pp.getIndex() == timeStampStrPlusYear.length()) { |
||||
working.setTime(parsed); |
||||
if (working.after(now)) { // must have been last year instead
|
||||
working.add(Calendar.YEAR, -1); |
||||
} |
||||
setPrecision(recentDateSmallestUnitIndex, working); |
||||
return working; |
||||
} |
||||
} |
||||
|
||||
ParsePosition pp = new ParsePosition(0); |
||||
parsed = defaultDateFormat.parse(timestampStr, pp); |
||||
// note, length checks are mandatory for us since
|
||||
// SimpleDateFormat methods will succeed if less than
|
||||
// full string is matched. They will also accept,
|
||||
// despite "leniency" setting, a two-digit number as
|
||||
// a valid year (e.g. 22:04 will parse as 22 A.D.)
|
||||
// so could mistakenly confuse an hour with a year,
|
||||
// if we don't insist on full length parsing.
|
||||
if (parsed != null && pp.getIndex() == timestampStr.length()) { |
||||
working.setTime(parsed); |
||||
} else { |
||||
throw new ParseException("Timestamp '" |
||||
+ timestampStr |
||||
+ "' could not be parsed using a server time of " |
||||
+ serverTime.getTime().toString(), pp.getErrorIndex()); |
||||
} |
||||
setPrecision(defaultDateSmallestUnitIndex, working); |
||||
return working; |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the defaultDateFormat. |
||||
*/ |
||||
public SimpleDateFormat getDefaultDateFormat() { |
||||
return defaultDateFormat; |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the defaultDateFormat pattern string. |
||||
*/ |
||||
public String getDefaultDateFormatString() { |
||||
return defaultDateFormat.toPattern(); |
||||
} |
||||
|
||||
/** |
||||
* @param format The defaultDateFormat to be set. |
||||
* @param dfs the symbols to use (may be null) |
||||
*/ |
||||
private void setDefaultDateFormat(String format, DateFormatSymbols dfs) { |
||||
if (format != null) { |
||||
if (dfs != null) { |
||||
this.defaultDateFormat = new SimpleDateFormat(format, dfs); |
||||
} else { |
||||
this.defaultDateFormat = new SimpleDateFormat(format); |
||||
} |
||||
this.defaultDateFormat.setLenient(false); |
||||
} else { |
||||
this.defaultDateFormat = null; |
||||
} |
||||
this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat); |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the recentDateFormat. |
||||
*/ |
||||
public SimpleDateFormat getRecentDateFormat() { |
||||
return recentDateFormat; |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the recentDateFormat. |
||||
*/ |
||||
public String getRecentDateFormatString() { |
||||
return recentDateFormat.toPattern(); |
||||
} |
||||
|
||||
/** |
||||
* @param format The recentDateFormat to set. |
||||
* @param dfs the symbols to use (may be null) |
||||
*/ |
||||
private void setRecentDateFormat(String format, DateFormatSymbols dfs) { |
||||
if (format != null) { |
||||
if (dfs != null) { |
||||
this.recentDateFormat = new SimpleDateFormat(format, dfs); |
||||
} else { |
||||
this.recentDateFormat = new SimpleDateFormat(format); |
||||
} |
||||
this.recentDateFormat.setLenient(false); |
||||
} else { |
||||
this.recentDateFormat = null; |
||||
} |
||||
this.recentDateSmallestUnitIndex = getEntry(this.recentDateFormat); |
||||
} |
||||
|
||||
/** |
||||
* @return returns an array of 12 strings representing the short |
||||
* month names used by this parse. |
||||
*/ |
||||
public String[] getShortMonths() { |
||||
return defaultDateFormat.getDateFormatSymbols().getShortMonths(); |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the serverTimeZone used by this parser. |
||||
*/ |
||||
public TimeZone getServerTimeZone() { |
||||
return this.defaultDateFormat.getTimeZone(); |
||||
} |
||||
|
||||
/** |
||||
* sets a TimeZone represented by the supplied ID string into all |
||||
* of the parsers used by this server. |
||||
* |
||||
* @param serverTimeZone Time Id java.util.TimeZone id used by |
||||
* the ftp server. If null the client's local time zone is assumed. |
||||
*/ |
||||
private void setServerTimeZone(String serverTimeZoneId) { |
||||
TimeZone serverTimeZone = TimeZone.getDefault(); |
||||
if (serverTimeZoneId != null) { |
||||
serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); |
||||
} |
||||
this.defaultDateFormat.setTimeZone(serverTimeZone); |
||||
if (this.recentDateFormat != null) { |
||||
this.recentDateFormat.setTimeZone(serverTimeZone); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Implementation of the {@link Configurable Configurable} |
||||
* interface. Configures this <code>FTPTimestampParser</code> according |
||||
* to the following logic: |
||||
* <p> |
||||
* Set up the {@link FTPClientConfig#setDefaultDateFormatStr(String) defaultDateFormat} |
||||
* and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} |
||||
* to values supplied in the config based on month names configured as follows: |
||||
* </p> |
||||
* <ul> |
||||
* <li>If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} |
||||
* has been supplied in the <code>config</code>, use that to parse parse timestamps.</li> |
||||
* <li>Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} |
||||
* has been supplied in the <code>config</code>, use the month names represented |
||||
* by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} |
||||
* to parse timestamps.</li> |
||||
* <li>otherwise use default English month names</li> |
||||
* </ul><p> |
||||
* Finally if a {@link FTPClientConfig#setServerTimeZoneId(String) |
||||
* serverTimeZoneId} |
||||
* has been supplied via the config, set that into all date formats that have |
||||
* been configured. |
||||
* </p> |
||||
*/ |
||||
@Override public void configure(FTPClientConfig config) { |
||||
DateFormatSymbols dfs = null; |
||||
|
||||
String languageCode = config.getServerLanguageCode(); |
||||
String shortmonths = config.getShortMonthNames(); |
||||
if (shortmonths != null) { |
||||
dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); |
||||
} else if (languageCode != null) { |
||||
dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); |
||||
} else { |
||||
dfs = FTPClientConfig.lookupDateFormatSymbols("en"); |
||||
} |
||||
|
||||
String recentFormatString = config.getRecentDateFormatStr(); |
||||
setRecentDateFormat(recentFormatString, dfs); |
||||
|
||||
String defaultFormatString = config.getDefaultDateFormatStr(); |
||||
if (defaultFormatString == null) { |
||||
throw new IllegalArgumentException("defaultFormatString cannot be null"); |
||||
} |
||||
setDefaultDateFormat(defaultFormatString, dfs); |
||||
|
||||
setServerTimeZone(config.getServerTimeZoneId()); |
||||
|
||||
this.lenientFutureDates = config.isLenientFutureDates(); |
||||
} |
||||
|
||||
/** |
||||
* @return Returns the lenientFutureDates. |
||||
*/ |
||||
boolean isLenientFutureDates() { |
||||
return lenientFutureDates; |
||||
} |
||||
|
||||
/** |
||||
* @param lenientFutureDates The lenientFutureDates to set. |
||||
*/ |
||||
void setLenientFutureDates(boolean lenientFutureDates) { |
||||
this.lenientFutureDates = lenientFutureDates; |
||||
} |
||||
} |
@ -1,260 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; |
||||
import java.text.ParsePosition; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
import java.util.GregorianCalendar; |
||||
import java.util.HashMap; |
||||
import java.util.Locale; |
||||
import java.util.TimeZone; |
||||
|
||||
/** |
||||
* Parser class for MSLT and MLSD replies. See RFC 3659. |
||||
* <p> |
||||
* Format is as follows: |
||||
* <pre> |
||||
* entry = [ facts ] SP pathname |
||||
* facts = 1*( fact ";" ) |
||||
* fact = factname "=" value |
||||
* factname = "Size" / "Modify" / "Create" / |
||||
* "Type" / "Unique" / "Perm" / |
||||
* "Lang" / "Media-Type" / "CharSet" / |
||||
* os-depend-fact / local-fact |
||||
* os-depend-fact = {IANA assigned OS name} "." token |
||||
* local-fact = "X." token |
||||
* value = *SCHAR |
||||
* |
||||
* Sample os-depend-fact: |
||||
* UNIX.group=0;UNIX.mode=0755;UNIX.owner=0; |
||||
* </pre> |
||||
* A single control response entry (MLST) is returned with a leading space; |
||||
* multiple (data) entries are returned without any leading spaces. |
||||
* The parser requires that the leading space from the MLST entry is removed. |
||||
* MLSD entries can begin with a single space if there are no facts. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public class MLSxEntryParser extends FTPFileEntryParserImpl { |
||||
// This class is immutable, so a single instance can be shared.
|
||||
private static final MLSxEntryParser PARSER = new MLSxEntryParser(); |
||||
|
||||
private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<String, Integer>(); |
||||
|
||||
static { |
||||
TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE)); |
||||
TYPE_TO_INT.put("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // listed directory
|
||||
TYPE_TO_INT.put("pdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // a parent dir
|
||||
TYPE_TO_INT.put("dir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // dir or sub-dir
|
||||
} |
||||
|
||||
private static int UNIX_GROUPS[] = { // Groups in order of mode digits
|
||||
FTPFile.USER_ACCESS, FTPFile.GROUP_ACCESS, FTPFile.WORLD_ACCESS, |
||||
}; |
||||
|
||||
private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value
|
||||
/* 0 */ {}, |
||||
/* 1 */ { FTPFile.EXECUTE_PERMISSION }, |
||||
/* 2 */ { FTPFile.WRITE_PERMISSION }, |
||||
/* 3 */ { FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION }, |
||||
/* 4 */ { FTPFile.READ_PERMISSION }, |
||||
/* 5 */ { FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION }, |
||||
/* 6 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION }, |
||||
/* 7 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION }, |
||||
}; |
||||
|
||||
/** |
||||
* Create the parser for MSLT and MSLD listing entries |
||||
* This class is immutable, so one can use {@link #getInstance()} instead. |
||||
*/ |
||||
public MLSxEntryParser() { |
||||
super(); |
||||
} |
||||
|
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
if (entry.startsWith(" ")) {// leading space means no facts are present
|
||||
if (entry.length() > 1) { // is there a path name?
|
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
file.setName(entry.substring(1)); |
||||
return file; |
||||
} else { |
||||
return null; // Invalid - no pathname
|
||||
} |
||||
} |
||||
String parts[] = entry.split(" ", 2); // Path may contain space
|
||||
if (parts.length != 2 || parts[1].length() == 0) { |
||||
return null; // no space found or no file name
|
||||
} |
||||
final String factList = parts[0]; |
||||
if (!factList.endsWith(";")) { |
||||
return null; |
||||
} |
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
file.setName(parts[1]); |
||||
String[] facts = factList.split(";"); |
||||
boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode="); |
||||
for (String fact : facts) { |
||||
String[] factparts = fact.split("=", -1); // Don't drop empty values
|
||||
// Sample missing permission
|
||||
// drwx------ 2 mirror mirror 4096 Mar 13 2010 subversion
|
||||
// modify=20100313224553;perm=;type=dir;unique=811U282598;UNIX.group=500;UNIX.mode=0700;UNIX.owner=500; subversion
|
||||
if (factparts.length != 2) { |
||||
return null; // invalid - there was no "=" sign
|
||||
} |
||||
String factname = factparts[0].toLowerCase(Locale.ENGLISH); |
||||
String factvalue = factparts[1]; |
||||
if (factvalue.length() == 0) { |
||||
continue; // nothing to see here
|
||||
} |
||||
String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH); |
||||
if ("size".equals(factname)) { |
||||
file.setSize(Long.parseLong(factvalue)); |
||||
} else if ("sizd".equals(factname)) { // Directory size
|
||||
file.setSize(Long.parseLong(factvalue)); |
||||
} else if ("modify".equals(factname)) { |
||||
final Calendar parsed = parseGMTdateTime(factvalue); |
||||
if (parsed == null) { |
||||
return null; |
||||
} |
||||
file.setTimestamp(parsed); |
||||
} else if ("type".equals(factname)) { |
||||
Integer intType = TYPE_TO_INT.get(valueLowerCase); |
||||
if (intType == null) { |
||||
file.setType(FTPFile.UNKNOWN_TYPE); |
||||
} else { |
||||
file.setType(intType.intValue()); |
||||
} |
||||
} else if (factname.startsWith("unix.")) { |
||||
String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH); |
||||
if ("group".equals(unixfact)) { |
||||
file.setGroup(factvalue); |
||||
} else if ("owner".equals(unixfact)) { |
||||
file.setUser(factvalue); |
||||
} else if ("mode".equals(unixfact)) { // e.g. 0[1]755
|
||||
int off = factvalue.length() - 3; // only parse last 3 digits
|
||||
for (int i = 0; i < 3; i++) { |
||||
int ch = factvalue.charAt(off + i) - '0'; |
||||
if (ch >= 0 && ch <= 7) { // Check it's valid octal
|
||||
for (int p : UNIX_PERMS[ch]) { |
||||
file.setPermission(UNIX_GROUPS[i], p, true); |
||||
} |
||||
} else { |
||||
// TODO should this cause failure, or can it be reported somehow?
|
||||
} |
||||
} // digits
|
||||
} // mode
|
||||
} // unix.
|
||||
else if (!hasUnixMode && "perm".equals(factname)) { // skip if we have the UNIX.mode
|
||||
doUnixPerms(file, valueLowerCase); |
||||
} // process "perm"
|
||||
} // each fact
|
||||
return file; |
||||
} |
||||
|
||||
/** |
||||
* Parse a GMT time stamp of the form YYYYMMDDHHMMSS[.sss] |
||||
* |
||||
* @param timestamp the date-time to parse |
||||
* @return a Calendar entry, may be {@code null} |
||||
* @since 3.4 |
||||
*/ |
||||
public static Calendar parseGMTdateTime(String timestamp) { |
||||
final SimpleDateFormat sdf; |
||||
final boolean hasMillis; |
||||
if (timestamp.contains(".")) { |
||||
sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); |
||||
hasMillis = true; |
||||
} else { |
||||
sdf = new SimpleDateFormat("yyyyMMddHHmmss"); |
||||
hasMillis = false; |
||||
} |
||||
TimeZone GMT = TimeZone.getTimeZone("GMT"); |
||||
// both timezones need to be set for the parse to work OK
|
||||
sdf.setTimeZone(GMT); |
||||
GregorianCalendar gc = new GregorianCalendar(GMT); |
||||
ParsePosition pos = new ParsePosition(0); |
||||
sdf.setLenient(false); // We want to parse the whole string
|
||||
final Date parsed = sdf.parse(timestamp, pos); |
||||
if (pos.getIndex() != timestamp.length()) { |
||||
return null; // did not fully parse the input
|
||||
} |
||||
gc.setTime(parsed); |
||||
if (!hasMillis) { |
||||
gc.clear(Calendar.MILLISECOND); // flag up missing ms units
|
||||
} |
||||
return gc; |
||||
} |
||||
|
||||
// perm-fact = "Perm" "=" *pvals
|
||||
// pvals = "a" / "c" / "d" / "e" / "f" /
|
||||
// "l" / "m" / "p" / "r" / "w"
|
||||
private void doUnixPerms(FTPFile file, String valueLowerCase) { |
||||
for (char c : valueLowerCase.toCharArray()) { |
||||
// TODO these are mostly just guesses at present
|
||||
switch (c) { |
||||
case 'a': // (file) may APPEnd
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
case 'c': // (dir) files may be created in the dir
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
case 'd': // deletable
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
case 'e': // (dir) can change to this dir
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); |
||||
break; |
||||
case 'f': // (file) renamable
|
||||
// ?? file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
|
||||
break; |
||||
case 'l': // (dir) can be listed
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, true); |
||||
break; |
||||
case 'm': // (dir) can create directory here
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
case 'p': // (dir) entries may be deleted
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
case 'r': // (files) file may be RETRieved
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); |
||||
break; |
||||
case 'w': // (files) file may be STORed
|
||||
file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
break; |
||||
default: |
||||
break; |
||||
// ignore unexpected flag for now.
|
||||
} // switch
|
||||
} // each char
|
||||
} |
||||
|
||||
public static FTPFile parseEntry(String entry) { |
||||
return PARSER.parseFTPEntry(entry); |
||||
} |
||||
|
||||
public static MLSxEntryParser getInstance() { |
||||
return PARSER; |
||||
} |
||||
} |
@ -1,537 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS |
||||
* Systems. |
||||
* |
||||
* @version $Id: MVSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for |
||||
* usage instructions) |
||||
*/ |
||||
public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
static final int UNKNOWN_LIST_TYPE = -1; |
||||
static final int FILE_LIST_TYPE = 0; |
||||
static final int MEMBER_LIST_TYPE = 1; |
||||
static final int UNIX_LIST_TYPE = 2; |
||||
static final int JES_LEVEL_1_LIST_TYPE = 3; |
||||
static final int JES_LEVEL_2_LIST_TYPE = 4; |
||||
|
||||
private int isType = UNKNOWN_LIST_TYPE; |
||||
|
||||
/** |
||||
* Fallback parser for Unix-style listings |
||||
*/ |
||||
private UnixFTPEntryParser unixFTPEntryParser; |
||||
|
||||
/** |
||||
* Dates are ignored for file lists, but are used for member lists where |
||||
* possible |
||||
*/ |
||||
static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18
|
||||
// 13:52
|
||||
|
||||
/** |
||||
* Matches these entries: |
||||
* <pre> |
||||
* Volume Unit Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname |
||||
* B10142 3390 2006/03/20 2 31 F 80 80 PS MDI.OKL.WORK |
||||
* </pre> |
||||
*/ |
||||
static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume
|
||||
// ignored
|
||||
"\\S+\\s+" + // unit - ignored
|
||||
"\\S+\\s+" + // access date - ignored
|
||||
"\\S+\\s+" + // extents -ignored
|
||||
"\\S+\\s+" + // used - ignored
|
||||
"[FV]\\S*\\s+" + // recfm - must start with F or V
|
||||
"\\S+\\s+" + // logical record length -ignored
|
||||
"\\S+\\s+" + // block size - ignored
|
||||
"(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist
|
||||
// but only support: PS, PO, PO-E
|
||||
"(\\S+)\\s*"; // Dataset Name (file name)
|
||||
|
||||
/** |
||||
* Matches these entries: |
||||
* <pre> |
||||
* Name VV.MM Created Changed Size Init Mod Id |
||||
* TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 0 KIL001 |
||||
* </pre> |
||||
*/ |
||||
static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name
|
||||
"\\S+\\s+" + // version, modification (ignored)
|
||||
"\\S+\\s+" + // create date (ignored)
|
||||
"(\\S+)\\s+" + // modification date
|
||||
"(\\S+)\\s+" + // modification time
|
||||
"\\S+\\s+" + // size in lines (ignored)
|
||||
"\\S+\\s+" + // size in lines at creation(ignored)
|
||||
"\\S+\\s+" + // lines modified (ignored)
|
||||
"\\S+\\s*"; // id of user who modified (ignored)
|
||||
|
||||
/** |
||||
* Matches these entries, note: no header: |
||||
* <pre> |
||||
* IBMUSER1 JOB01906 OUTPUT 3 Spool Files |
||||
* 012345678901234567890123456789012345678901234 |
||||
* 1 2 3 4 |
||||
* </pre> |
||||
*/ |
||||
static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
|
||||
"(\\S+)\\s+" + // job number
|
||||
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE)
|
||||
"(\\S+)\\s+" + // number of spool files
|
||||
"(\\S+)\\s+" + // Text "Spool" ignored
|
||||
"(\\S+)\\s*" // Text "Files" ignored
|
||||
; |
||||
|
||||
/** |
||||
* JES INTERFACE LEVEL 2 parser |
||||
* Matches these entries: |
||||
* <pre> |
||||
* JOBNAME JOBID OWNER STATUS CLASS |
||||
* IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files |
||||
* IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files |
||||
* </pre> |
||||
* Sample output from FTP session: |
||||
* <pre> |
||||
* ftp> quote site filetype=jes |
||||
* 200 SITE command was accepted |
||||
* ftp> ls |
||||
* 200 Port request OK. |
||||
* 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER |
||||
* JOBNAME JOBID OWNER STATUS CLASS |
||||
* IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files |
||||
* IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files |
||||
* 250 List completed successfully. |
||||
* ftp> ls job01906 |
||||
* 200 Port request OK. |
||||
* 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER |
||||
* JOBNAME JOBID OWNER STATUS CLASS |
||||
* IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 |
||||
* -------- |
||||
* ID STEPNAME PROCSTEP C DDNAME BYTE-COUNT |
||||
* 001 JES2 A JESMSGLG 858 |
||||
* 002 JES2 A JESJCL 128 |
||||
* 003 JES2 A JESYSMSG 443 |
||||
* 3 spool files |
||||
* 250 List completed successfully. |
||||
* </pre> |
||||
*/ |
||||
|
||||
static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
|
||||
"(\\S+)\\s+" + // job number
|
||||
"(\\S+)\\s+" + // owner ignored
|
||||
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored
|
||||
"(\\S+)\\s+" + // job class ignored
|
||||
"(\\S+).*" // rest ignored
|
||||
; |
||||
|
||||
/* |
||||
* --------------------------------------------------------------------- |
||||
* Very brief and incomplete description of the zOS/MVS-filesystem. (Note: |
||||
* "zOS" is the operating system on the mainframe, and is the new name for |
||||
* MVS) |
||||
* |
||||
* The filesystem on the mainframe does not have hierarchal structure as for |
||||
* example the unix filesystem. For a more comprehensive description, please |
||||
* refer to the IBM manuals |
||||
* |
||||
* @LINK: |
||||
* http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS
|
||||
* |
||||
* |
||||
* Dataset names ============= |
||||
* |
||||
* A dataset name consist of a number of qualifiers separated by '.', each |
||||
* qualifier can be at most 8 characters, and the total length of a dataset |
||||
* can be max 44 characters including the dots. |
||||
* |
||||
* |
||||
* Dataset organisation ==================== |
||||
* |
||||
* A dataset represents a piece of storage allocated on one or more disks. |
||||
* The structure of the storage is described with the field dataset |
||||
* organinsation (DSORG). There are a number of dataset organisations, but |
||||
* only two are usable for FTP transfer. |
||||
* |
||||
* DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: |
||||
* extended partitioned dataset |
||||
* |
||||
* The PS file is just a flat file, as you would find it on the unix file |
||||
* system. |
||||
* |
||||
* The PO and PO-E files, can be compared to a single level directory |
||||
* structure. A PO file consist of a number of dataset members, or files if |
||||
* you will. It is possible to CD into the file, and to retrieve the |
||||
* individual members. |
||||
* |
||||
* |
||||
* Dataset record format ===================== |
||||
* |
||||
* The physical layout of the dataset is described on the dataset itself. |
||||
* There are a number of record formats (RECFM), but just a few is relavant |
||||
* for the FTP transfer. |
||||
* |
||||
* Any one beginning with either F or V can safely used by FTP transfer. All |
||||
* others should only be used with great care, so this version will just |
||||
* ignore the other record formats. F means a fixed number of records per |
||||
* allocated storage, and V means a variable number of records. |
||||
* |
||||
* |
||||
* Other notes =========== |
||||
* |
||||
* The file system supports automatically backup and retrieval of datasets. |
||||
* If a file is backed up, the ftp LIST command will return: ARCIVE Not |
||||
* Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST |
||||
* |
||||
* |
||||
* Implementation notes ==================== |
||||
* |
||||
* Only datasets that have dsorg PS, PO or PO-E and have recfm beginning |
||||
* with F or V, is fully parsed. |
||||
* |
||||
* The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. |
||||
* FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name |
||||
* FTPFile.Timestamp: change time or null |
||||
* |
||||
* |
||||
* |
||||
* Additional information ====================== |
||||
* |
||||
* The MVS ftp server supports a number of features via the FTP interface. |
||||
* The features are controlled with the FTP command quote site filetype=<SEQ|JES|DB2> |
||||
* SEQ is the default and used for normal file transfer JES is used to |
||||
* interact with the Job Entry Subsystem (JES) similar to a job scheduler |
||||
* DB2 is used to interact with a DB2 subsystem |
||||
* |
||||
* This parser supports SEQ and JES. |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* |
||||
*/ |
||||
|
||||
/** |
||||
* The sole constructor for a MVSFTPEntryParser object. |
||||
*/ |
||||
public MVSFTPEntryParser() { |
||||
super(""); // note the regex is set in preParse.
|
||||
super.configure(null); // configure parser with default configurations
|
||||
} |
||||
|
||||
/** |
||||
* Parses a line of an z/OS - MVS FTP server file listing and converts it |
||||
* into a usable format in the form of an <code> FTPFile </code> instance. |
||||
* If the file listing line doesn't describe a file, then |
||||
* <code> null </code> is returned. Otherwise a <code> FTPFile </code> |
||||
* instance representing the file is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
boolean isParsed = false; |
||||
FTPFile f = new FTPFile(); |
||||
|
||||
if (isType == FILE_LIST_TYPE) { |
||||
isParsed = parseFileList(f, entry); |
||||
} else if (isType == MEMBER_LIST_TYPE) { |
||||
isParsed = parseMemberList(f, entry); |
||||
if (!isParsed) { |
||||
isParsed = parseSimpleEntry(f, entry); |
||||
} |
||||
} else if (isType == UNIX_LIST_TYPE) { |
||||
isParsed = parseUnixList(f, entry); |
||||
} else if (isType == JES_LEVEL_1_LIST_TYPE) { |
||||
isParsed = parseJeslevel1List(f, entry); |
||||
} else if (isType == JES_LEVEL_2_LIST_TYPE) { |
||||
isParsed = parseJeslevel2List(f, entry); |
||||
} |
||||
|
||||
if (!isParsed) { |
||||
f = null; |
||||
} |
||||
|
||||
return f; |
||||
} |
||||
|
||||
/** |
||||
* Parse entries representing a dataset list. Only datasets with DSORG PS or |
||||
* PO or PO-E and with RECFM F* or V* will be parsed. |
||||
* |
||||
* Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred |
||||
* Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 |
||||
* 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device |
||||
* KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO |
||||
* PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB |
||||
* |
||||
* ----------------------------------- Group within Regex [1] Volume [2] |
||||
* Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record |
||||
* format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: |
||||
* Dataset organisation. Many exists but only support: PS, PO, PO-E [10] |
||||
* Dsname: Dataset name |
||||
* |
||||
* Note: When volume is ARCIVE, it means the dataset is stored somewhere in |
||||
* a tape archive. These entries is currently not supported by this parser. |
||||
* A null value is returned. |
||||
* |
||||
* @param file will be updated with Name, Type, Timestamp if parsed. |
||||
* @param entry zosDirectoryEntry |
||||
* @return true: entry was parsed, false: entry was not parsed. |
||||
*/ |
||||
private boolean parseFileList(FTPFile file, String entry) { |
||||
if (matches(entry)) { |
||||
file.setRawListing(entry); |
||||
String name = group(2); |
||||
String dsorg = group(1); |
||||
file.setName(name); |
||||
|
||||
// DSORG
|
||||
if ("PS".equals(dsorg)) { |
||||
file.setType(FTPFile.FILE_TYPE); |
||||
} else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { |
||||
// regex already ruled out anything other than PO or PO-E
|
||||
file.setType(FTPFile.DIRECTORY_TYPE); |
||||
} else { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Parse entries within a partitioned dataset. |
||||
* |
||||
* Format of a memberlist within a PDS: |
||||
* <pre> |
||||
* 0 1 2 3 4 5 6 7 8 |
||||
* Name VV.MM Created Changed Size Init Mod Id |
||||
* TBSHELF 01.03 2002/09/12 2002/10/11 09:37 11 11 0 KIL001 |
||||
* TBTOOL 01.12 2002/09/12 2004/11/26 19:54 51 28 0 KIL001 |
||||
* |
||||
* ------------------------------------------- |
||||
* [1] Name |
||||
* [2] VV.MM: Version . modification |
||||
* [3] Created: yyyy / MM / dd |
||||
* [4,5] Changed: yyyy / MM / dd HH:mm |
||||
* [6] Size: number of lines |
||||
* [7] Init: number of lines when first created |
||||
* [8] Mod: number of modified lines a last save |
||||
* [9] Id: User id for last update |
||||
* </pre> |
||||
* |
||||
* @param file will be updated with Name, Type and Timestamp if parsed. |
||||
* @param entry zosDirectoryEntry |
||||
* @return true: entry was parsed, false: entry was not parsed. |
||||
*/ |
||||
private boolean parseMemberList(FTPFile file, String entry) { |
||||
if (matches(entry)) { |
||||
file.setRawListing(entry); |
||||
String name = group(1); |
||||
String datestr = group(2) + " " + group(3); |
||||
file.setName(name); |
||||
file.setType(FTPFile.FILE_TYPE); |
||||
try { |
||||
file.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
e.printStackTrace(); |
||||
// just ignore parsing errors.
|
||||
// TODO check this is ok
|
||||
return false; // this is a parsing failure too.
|
||||
} |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Assigns the name to the first word of the entry. Only to be used from a |
||||
* safe context, for example from a memberlist, where the regex for some |
||||
* reason fails. Then just assign the name field of FTPFile. |
||||
* |
||||
* @return true if the entry string is non-null and non-empty |
||||
*/ |
||||
private boolean parseSimpleEntry(FTPFile file, String entry) { |
||||
if (entry != null && entry.trim().length() > 0) { |
||||
file.setRawListing(entry); |
||||
String name = entry.split(" ")[0]; |
||||
file.setName(name); |
||||
file.setType(FTPFile.FILE_TYPE); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Parse the entry as a standard unix file. Using the UnixFTPEntryParser. |
||||
* |
||||
* @return true: entry is parsed, false: entry could not be parsed. |
||||
*/ |
||||
private boolean parseUnixList(FTPFile file, String entry) { |
||||
file = unixFTPEntryParser.parseFTPEntry(entry); |
||||
if (file == null) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Matches these entries, note: no header: |
||||
* <pre> |
||||
* [1] [2] [3] [4] [5] |
||||
* IBMUSER1 JOB01906 OUTPUT 3 Spool Files |
||||
* 012345678901234567890123456789012345678901234 |
||||
* 1 2 3 4 |
||||
* ------------------------------------------- |
||||
* Group in regex |
||||
* [1] Job name |
||||
* [2] Job number |
||||
* [3] Job status (INPUT,ACTIVE,OUTPUT) |
||||
* [4] Number of sysout files |
||||
* [5] The string "Spool Files" |
||||
* </pre> |
||||
* |
||||
* @param file will be updated with Name, Type and Timestamp if parsed. |
||||
* @param entry zosDirectoryEntry |
||||
* @return true: entry was parsed, false: entry was not parsed. |
||||
*/ |
||||
private boolean parseJeslevel1List(FTPFile file, String entry) { |
||||
if (matches(entry)) { |
||||
if (group(3).equalsIgnoreCase("OUTPUT")) { |
||||
file.setRawListing(entry); |
||||
String name = group(2); /* Job Number, used by GET */ |
||||
file.setName(name); |
||||
file.setType(FTPFile.FILE_TYPE); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Matches these entries: |
||||
* <pre> |
||||
* [1] [2] [3] [4] [5] |
||||
* JOBNAME JOBID OWNER STATUS CLASS |
||||
* IBMUSER1 JOB01906 IBMUSER OUTPUT A RC=0000 3 spool files |
||||
* IBMUSER TSU01830 IBMUSER OUTPUT TSU ABEND=522 3 spool files |
||||
* 012345678901234567890123456789012345678901234 |
||||
* 1 2 3 4 |
||||
* ------------------------------------------- |
||||
* Group in regex |
||||
* [1] Job name |
||||
* [2] Job number |
||||
* [3] Owner |
||||
* [4] Job status (INPUT,ACTIVE,OUTPUT) |
||||
* [5] Job Class |
||||
* [6] The rest |
||||
* </pre> |
||||
* |
||||
* @param file will be updated with Name, Type and Timestamp if parsed. |
||||
* @param entry zosDirectoryEntry |
||||
* @return true: entry was parsed, false: entry was not parsed. |
||||
*/ |
||||
private boolean parseJeslevel2List(FTPFile file, String entry) { |
||||
if (matches(entry)) { |
||||
if (group(4).equalsIgnoreCase("OUTPUT")) { |
||||
file.setRawListing(entry); |
||||
String name = group(2); /* Job Number, used by GET */ |
||||
file.setName(name); |
||||
file.setType(FTPFile.FILE_TYPE); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* preParse is called as part of the interface. Per definition is is called |
||||
* before the parsing takes place. |
||||
* Three kind of lists is recognize: |
||||
* z/OS-MVS File lists |
||||
* z/OS-MVS Member lists |
||||
* unix file lists |
||||
* |
||||
* @since 2.0 |
||||
*/ |
||||
@Override public List<String> preParse(List<String> orig) { |
||||
// simply remove the header line. Composite logic will take care of the
|
||||
// two different types of
|
||||
// list in short order.
|
||||
if (orig != null && orig.size() > 0) { |
||||
String header = orig.get(0); |
||||
if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { |
||||
setType(FILE_LIST_TYPE); |
||||
super.setRegex(FILE_LIST_REGEX); |
||||
} else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { |
||||
setType(MEMBER_LIST_TYPE); |
||||
super.setRegex(MEMBER_LIST_REGEX); |
||||
} else if (header.indexOf("total") == 0) { |
||||
setType(UNIX_LIST_TYPE); |
||||
unixFTPEntryParser = new UnixFTPEntryParser(); |
||||
} else if (header.indexOf("Spool Files") >= 30) { |
||||
setType(JES_LEVEL_1_LIST_TYPE); |
||||
super.setRegex(JES_LEVEL_1_LIST_REGEX); |
||||
} else if (header.indexOf("JOBNAME") == 0 |
||||
&& header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS
|
||||
setType(JES_LEVEL_2_LIST_TYPE); |
||||
super.setRegex(JES_LEVEL_2_LIST_REGEX); |
||||
} else { |
||||
setType(UNKNOWN_LIST_TYPE); |
||||
} |
||||
|
||||
if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary
|
||||
orig.remove(0); |
||||
} |
||||
} |
||||
|
||||
return orig; |
||||
} |
||||
|
||||
/** |
||||
* Explicitly set the type of listing being processed. |
||||
* |
||||
* @param type The listing type. |
||||
*/ |
||||
void setType(int type) { |
||||
isType = type; |
||||
} |
||||
|
||||
/* |
||||
* @return |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_MVS, DEFAULT_DATE_FORMAT, null); |
||||
} |
||||
} |
@ -1,245 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
|
||||
/** |
||||
* Implementation FTPFileEntryParser and FTPFileListParser for pre MacOS-X Systems. |
||||
* |
||||
* @version $Id: MacOsPeterFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
* @since 3.1 |
||||
*/ |
||||
public class
|
||||
MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
|
||||
|
||||
static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
|
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
* |
||||
* Permissions: |
||||
* r the file is readable |
||||
* w the file is writable |
||||
* x the file is executable |
||||
* - the indicated permission is not granted |
||||
* L mandatory locking occurs during access (the set-group-ID bit is |
||||
* on and the group execution bit is off) |
||||
* s the set-user-ID or set-group-ID bit is on, and the corresponding |
||||
* user or group execution bit is also on |
||||
* S undefined bit-state (the set-user-ID bit is on and the user |
||||
* execution bit is off) |
||||
* t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and |
||||
* execution is on |
||||
* T the 1000 bit is turned on, and execution is off (undefined bit- |
||||
* state) |
||||
* e z/OS external link bit |
||||
*/ |
||||
private static final String REGEX = "([bcdelfmpSs-])" |
||||
// type (1)
|
||||
+ "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" |
||||
// permission
|
||||
+ "(" |
||||
+ "(folder\\s+)" |
||||
+ "|" |
||||
+ "((\\d+)\\s+(\\d+)\\s+)" |
||||
// resource size & data size
|
||||
+ ")" |
||||
+ "(\\d+)\\s+" |
||||
// size
|
||||
/* |
||||
* numeric or standard format date: |
||||
* yyyy-mm-dd (expecting hh:mm to follow) |
||||
* MMM [d]d |
||||
* [d]d MMM |
||||
* N.B. use non-space for MMM to allow for languages such as German which use |
||||
* diacritics (e.g. umlaut) in some abbreviations. |
||||
*/ |
||||
+ "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S{3}\\s+\\d{1,2})|(?:\\d{1,2}\\s+\\S{3}))\\s+" |
||||
/* |
||||
year (for non-recent standard format) - yyyy |
||||
or time (for numeric or recent standard format) [h]h:mm |
||||
*/ |
||||
+ "(\\d+(?::\\d+)?)\\s+" |
||||
|
||||
+ "(\\S*)(\\s*.*)"; // the rest
|
||||
|
||||
/** |
||||
* The default constructor for a UnixFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public MacOsPeterFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of a UnixFTPEntryParser object with |
||||
* something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public MacOsPeterFTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX); |
||||
configure(config); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of a unix (standard) FTP server file listing and converts |
||||
* it into a usable format in the form of an <code> FTPFile </code> |
||||
* instance. If the file listing line doesn't describe a file, |
||||
* <code> null </code> is returned, otherwise a <code> FTPFile </code> |
||||
* instance representing the files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
int type; |
||||
boolean isDevice = false; |
||||
|
||||
if (matches(entry)) { |
||||
String typeStr = group(1); |
||||
String hardLinkCount = "0"; |
||||
String usr = null; |
||||
String grp = null; |
||||
String filesize = group(20); |
||||
String datestr = group(21) + " " + group(22); |
||||
String name = group(23); |
||||
String endtoken = group(24); |
||||
|
||||
try { |
||||
file.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
// A 'whiteout' file is an ARTIFICIAL entry in any of several types of
|
||||
// 'translucent' filesystems, of which a 'union' filesystem is one.
|
||||
|
||||
// bcdelfmpSs-
|
||||
switch (typeStr.charAt(0)) { |
||||
case 'd': |
||||
type = FTPFile.DIRECTORY_TYPE; |
||||
break; |
||||
case 'e': // NET-39 => z/OS external link
|
||||
type = FTPFile.SYMBOLIC_LINK_TYPE; |
||||
break; |
||||
case 'l': |
||||
type = FTPFile.SYMBOLIC_LINK_TYPE; |
||||
break; |
||||
case 'b': |
||||
case 'c': |
||||
isDevice = true; |
||||
type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented
|
||||
break; |
||||
case 'f': |
||||
case '-': |
||||
type = FTPFile.FILE_TYPE; |
||||
break; |
||||
default: // e.g. ? and w = whiteout
|
||||
type = FTPFile.UNKNOWN_TYPE; |
||||
} |
||||
|
||||
file.setType(type); |
||||
|
||||
int g = 4; |
||||
for (int access = 0; access < 3; access++, g += 4) { |
||||
// Use != '-' to avoid having to check for suid and sticky bits
|
||||
file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-"))); |
||||
file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-"))); |
||||
|
||||
String execPerm = group(g + 2); |
||||
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) { |
||||
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); |
||||
} else { |
||||
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); |
||||
} |
||||
} |
||||
|
||||
if (!isDevice) { |
||||
try { |
||||
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
} |
||||
|
||||
file.setUser(usr); |
||||
file.setGroup(grp); |
||||
|
||||
try { |
||||
file.setSize(Long.parseLong(filesize)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
if (null == endtoken) { |
||||
file.setName(name); |
||||
} else { |
||||
// oddball cases like symbolic links, file names
|
||||
// with spaces in them.
|
||||
name += endtoken; |
||||
if (type == FTPFile.SYMBOLIC_LINK_TYPE) { |
||||
|
||||
int end = name.indexOf(" -> "); |
||||
// Give up if no link indicator is present
|
||||
if (end == -1) { |
||||
file.setName(name); |
||||
} else { |
||||
file.setName(name.substring(0, end)); |
||||
file.setLink(name.substring(end + 4)); |
||||
} |
||||
} else { |
||||
file.setName(name); |
||||
} |
||||
} |
||||
return file; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT, |
||||
DEFAULT_RECENT_DATE_FORMAT); |
||||
} |
||||
} |
@ -1,142 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.Configurable; |
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. |
||||
* |
||||
* @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
*/ |
||||
public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy hh:mma"; //11-09-01 12:30PM
|
||||
|
||||
private static final String DEFAULT_DATE_FORMAT2 = "MM-dd-yy kk:mm"; //11-09-01 18:30
|
||||
|
||||
private final FTPTimestampParser timestampParser; |
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
*/ |
||||
private static final String REGEX = |
||||
"(\\S+)\\s+(\\S+)\\s+" // MM-dd-yy whitespace hh:mma|kk:mm; swallow trailing spaces
|
||||
+ "(?:(<DIR>)|([0-9]+))\\s+" // <DIR> or ddddd; swallow trailing spaces
|
||||
+ "(\\S.*)"; // First non-space followed by rest of line (name)
|
||||
|
||||
/** |
||||
* The sole constructor for an NTFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public NTFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of an NTFTPEntryParser object |
||||
* with something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public NTFTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX, Pattern.DOTALL); |
||||
configure(config); |
||||
FTPClientConfig config2 = |
||||
new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT2, null); |
||||
config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2); |
||||
this.timestampParser = new FTPTimestampParserImpl(); |
||||
((Configurable) this.timestampParser).configure(config2); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of an NT FTP server file listing and converts it into a |
||||
* usable format in the form of an <code> FTPFile </code> instance. If the |
||||
* file listing line doesn't describe a file, <code> null </code> is |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
FTPFile f = new FTPFile(); |
||||
f.setRawListing(entry); |
||||
|
||||
if (matches(entry)) { |
||||
String datestr = group(1) + " " + group(2); |
||||
String dirString = group(3); |
||||
String size = group(4); |
||||
String name = group(5); |
||||
try { |
||||
f.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// parsing fails, try the other date format
|
||||
try { |
||||
f.setTimestamp(timestampParser.parseTimestamp(datestr)); |
||||
} catch (ParseException e2) { |
||||
// intentionally do nothing
|
||||
} |
||||
} |
||||
|
||||
if (null == name || name.equals(".") || name.equals("..")) { |
||||
return (null); |
||||
} |
||||
f.setName(name); |
||||
|
||||
if ("<DIR>".equals(dirString)) { |
||||
f.setType(FTPFile.DIRECTORY_TYPE); |
||||
f.setSize(0); |
||||
} else { |
||||
f.setType(FTPFile.FILE_TYPE); |
||||
if (null != size) { |
||||
f.setSize(Long.parseLong(size)); |
||||
} |
||||
} |
||||
return (f); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override public FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT, null); |
||||
} |
||||
} |
@ -1,175 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
|
||||
/** |
||||
* Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of |
||||
* the proprietary |
||||
* extensions for Novell-specific operations are not supported. See |
||||
* <a href="http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html"> |
||||
* http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html</a>
|
||||
* for more details. |
||||
* |
||||
* @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
* @since 1.5 |
||||
*/ |
||||
public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
/** |
||||
* Default date format is e.g. Feb 22 2006 |
||||
*/ |
||||
private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; |
||||
|
||||
/** |
||||
* Default recent date format is e.g. Feb 22 17:32 |
||||
*/ |
||||
private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; |
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
* Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 |
||||
*/ |
||||
private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag
|
||||
+ "\\[([-A-Z]+)\\]\\s+" // Attributes RWCEAFMS or -
|
||||
+ "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size
|
||||
+ "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format
|
||||
+ "\\s+(.*)"; // Filename (incl. spaces)
|
||||
|
||||
/** |
||||
* The default constructor for a NetwareFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public NetwareFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of an NetwareFTPEntryParser object |
||||
* with something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public NetwareFTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX); |
||||
configure(config); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of an NetwareFTP server file listing and converts it into a |
||||
* usable format in the form of an <code> FTPFile </code> instance. If the |
||||
* file listing line doesn't describe a file, <code> null </code> is |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* <p> |
||||
* Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: |
||||
* <ul> |
||||
* <li><b>S</b> - Supervisor; All rights. |
||||
* <li><b>R</b> - Read; Right to open and read or execute. |
||||
* <li><b>W</b> - Write; Right to open and modify. |
||||
* <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be |
||||
* recovered. |
||||
* <li><b>E</b> - Erase; Right to delete. |
||||
* <li><b>M</b> - Modify; Right to rename a file and to change attributes. |
||||
* <li><b>F</b> - File Scan; Right to see directory or file listings. |
||||
* <li><b>A</b> - Access Control; Right to modify trustee assignments and the Inherited Rights |
||||
* Mask. |
||||
* </ul> |
||||
* |
||||
* See |
||||
* <a href="http://www.novell.com/documentation/nfap10/index.html?page=/documentation/nfap10/nfaubook/data/abxraws.html"> |
||||
* here</a> |
||||
* for more details |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
|
||||
FTPFile f = new FTPFile(); |
||||
if (matches(entry)) { |
||||
String dirString = group(1); |
||||
String attrib = group(2); |
||||
String user = group(3); |
||||
String size = group(4); |
||||
String datestr = group(5); |
||||
String name = group(9); |
||||
|
||||
try { |
||||
f.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
//is it a DIR or a file
|
||||
if (dirString.trim().equals("d")) { |
||||
f.setType(FTPFile.DIRECTORY_TYPE); |
||||
} else // Should be "-"
|
||||
{ |
||||
f.setType(FTPFile.FILE_TYPE); |
||||
} |
||||
|
||||
f.setUser(user); |
||||
|
||||
//set the name
|
||||
f.setName(name.trim()); |
||||
|
||||
//set the size
|
||||
f.setSize(Long.parseLong(size.trim())); |
||||
|
||||
// Now set the permissions (or at least a subset thereof - full permissions would probably require
|
||||
// subclassing FTPFile and adding extra metainformation there)
|
||||
if (attrib.indexOf("R") != -1) { |
||||
f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); |
||||
} |
||||
if (attrib.indexOf("W") != -1) { |
||||
f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); |
||||
} |
||||
|
||||
return (f); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_DATE_FORMAT, |
||||
DEFAULT_RECENT_DATE_FORMAT); |
||||
} |
||||
} |
@ -1,127 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
|
||||
/** |
||||
* Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. |
||||
* |
||||
* @version $Id: OS2FTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
*/ |
||||
public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl |
||||
|
||||
{ |
||||
|
||||
private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy HH:mm"; //11-09-01 12:30
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
*/ |
||||
private static final String REGEX = "\\s*([0-9]+)\\s*" |
||||
+ "(\\s+|[A-Z]+)\\s*" |
||||
+ "(DIR|\\s+)\\s*" |
||||
+ "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ |
||||
+ "(\\S.*)"; |
||||
|
||||
/** |
||||
* The default constructor for a OS2FTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public OS2FTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of an OS2FTPEntryParser object |
||||
* with something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public OS2FTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX); |
||||
configure(config); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of an OS2 FTP server file listing and converts it into a |
||||
* usable format in the form of an <code> FTPFile </code> instance. If the |
||||
* file listing line doesn't describe a file, <code> null </code> is |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
|
||||
FTPFile f = new FTPFile(); |
||||
if (matches(entry)) { |
||||
String size = group(1); |
||||
String attrib = group(2); |
||||
String dirString = group(3); |
||||
String datestr = group(4) + " " + group(5); |
||||
String name = group(6); |
||||
try { |
||||
f.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
//is it a DIR or a file
|
||||
if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) { |
||||
f.setType(FTPFile.DIRECTORY_TYPE); |
||||
} else { |
||||
f.setType(FTPFile.FILE_TYPE); |
||||
} |
||||
|
||||
//set the name
|
||||
f.setName(name.trim()); |
||||
|
||||
//set the size
|
||||
f.setSize(Long.parseLong(size.trim())); |
||||
|
||||
return (f); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_OS2, DEFAULT_DATE_FORMAT, null); |
||||
} |
||||
} |
@ -1,399 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import java.io.File; |
||||
import java.text.ParseException; |
||||
|
||||
/** |
||||
* @version $Id: OS400FTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* <pre> |
||||
* Example *FILE/*MEM FTP entries, when the current |
||||
* working directory is a file of file system QSYS: |
||||
* ------------------------------------------------ |
||||
* |
||||
* $ cwd /qsys.lib/rpgunit.lib/rpgunitc1.file |
||||
* 250-NAMEFMT set to 1. |
||||
* 250 "/QSYS.LIB/RPGUNIT.LIB/RPGUNITC1.FILE" is current directory. |
||||
* $ dir |
||||
* 227 Entering Passive Mode (10,200,36,33,40,249). |
||||
* 125 List started. |
||||
* QPGMR 135168 22.06.13 13:18:19 *FILE |
||||
* QPGMR *MEM MKCMD.MBR |
||||
* QPGMR *MEM RUCALLTST.MBR |
||||
* QPGMR *MEM RUCMDHLP.MBR |
||||
* QPGMR *MEM RUCRTTST.MBR |
||||
* 250 List completed. |
||||
* |
||||
* |
||||
* Example *FILE entry of an OS/400 save file: |
||||
* --------------------------------------------------- |
||||
* |
||||
* $ cwd /qsys.lib/rpgunit.lib |
||||
* 250 "/QSYS.LIB/RPGUNIT.LIB" is current library. |
||||
* $ dir rpgunit.file |
||||
* 227 Entering Passive Mode (10,200,36,33,188,106). |
||||
* 125 List started. |
||||
* QPGMR 16347136 29.06.13 15:45:09 *FILE RPGUNIT.SAVF |
||||
* 250 List completed. |
||||
* |
||||
* |
||||
* Example *STMF/*DIR FTP entries, when the |
||||
* current working directory is in file system "root": |
||||
* --------------------------------------------------- |
||||
* |
||||
* $ cwd /home/raddatz |
||||
* 250 "/home/raddatz" is current directory. |
||||
* $ dir test* |
||||
* 227 Entering Passive Mode (10,200,36,33,200,189). |
||||
* 125 List started. |
||||
* RADDATZ 200 21.05.11 12:31:18 *STMF TEST_RG_02_CRLF.properties |
||||
* RADDATZ 187 08.05.11 12:31:40 *STMF TEST_RG_02_LF.properties |
||||
* RADDATZ 187 08.05.11 12:31:52 *STMF TEST_RG_02_CR.properties |
||||
* RADDATZ 8192 04.07.13 09:04:14 *DIR testDir1/ |
||||
* RADDATZ 8192 04.07.13 09:04:17 *DIR testDir2/ |
||||
* 250 List completed. |
||||
* |
||||
* |
||||
* Example 1, using ANT to list specific members of a file: |
||||
* -------------------------------------------------------- |
||||
* |
||||
* <echo/> |
||||
* <echo>Listing members of a file:</echo> |
||||
* |
||||
* <ftp action="list" |
||||
* server="${ftp.server}" |
||||
* userid="${ftp.user}" |
||||
* password="${ftp.password}" |
||||
* binary="false" |
||||
* verbose="true" |
||||
* remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE" |
||||
* systemTypeKey="OS/400" |
||||
* listing="ftp-listing.txt" |
||||
* > |
||||
* <fileset dir="./i5-downloads-file" casesensitive="false"> |
||||
* <include name="run*.mbr" /> |
||||
* </fileset> |
||||
* </ftp> |
||||
* |
||||
* Output: |
||||
* ------- |
||||
* |
||||
* [echo] Listing members of a file: |
||||
* [ftp] listing files |
||||
* [ftp] listing RUN.MBR |
||||
* [ftp] listing RUNNER.MBR |
||||
* [ftp] listing RUNNERBND.MBR |
||||
* [ftp] 3 files listed |
||||
* |
||||
* |
||||
* Example 2, using ANT to list specific members of all files of a library: |
||||
* ------------------------------------------------------------------------ |
||||
* |
||||
* <echo/> |
||||
* <echo>Listing members of all files of a library:</echo> |
||||
* |
||||
* <ftp action="list" |
||||
* server="${ftp.server}" |
||||
* userid="${ftp.user}" |
||||
* password="${ftp.password}" |
||||
* binary="false" |
||||
* verbose="true" |
||||
* remotedir="/QSYS.LIB/RPGUNIT.LIB" |
||||
* systemTypeKey="OS/400" |
||||
* listing="ftp-listing.txt" |
||||
* > |
||||
* <fileset dir="./i5-downloads-lib" casesensitive="false"> |
||||
* <include name="**\run*.mbr" /> |
||||
* </fileset> |
||||
* </ftp> |
||||
* |
||||
* Output: |
||||
* ------- |
||||
* |
||||
* [echo] Listing members of all files of a library: |
||||
* [ftp] listing files |
||||
* [ftp] listing RPGUNIT1.FILE\RUN.MBR |
||||
* [ftp] listing RPGUNIT1.FILE\RUNRMT.MBR |
||||
* [ftp] listing RPGUNITT1.FILE\RUNT.MBR |
||||
* [ftp] listing RPGUNITY1.FILE\RUN.MBR |
||||
* [ftp] listing RPGUNITY1.FILE\RUNNER.MBR |
||||
* [ftp] listing RPGUNITY1.FILE\RUNNERBND.MBR |
||||
* [ftp] 6 files listed |
||||
* |
||||
* |
||||
* Example 3, using ANT to download specific members of a file: |
||||
* ------------------------------------------------------------ |
||||
* |
||||
* <echo/> |
||||
* <echo>Downloading members of a file:</echo> |
||||
* |
||||
* <ftp action="get" |
||||
* server="${ftp.server}" |
||||
* userid="${ftp.user}" |
||||
* password="${ftp.password}" |
||||
* binary="false" |
||||
* verbose="true" |
||||
* remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE" |
||||
* systemTypeKey="OS/400" |
||||
* > |
||||
* <fileset dir="./i5-downloads-file" casesensitive="false"> |
||||
* <include name="run*.mbr" /> |
||||
* </fileset> |
||||
* </ftp> |
||||
* |
||||
* Output: |
||||
* ------- |
||||
* |
||||
* [echo] Downloading members of a file: |
||||
* [ftp] getting files |
||||
* [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT - |
||||
* FTP\i5-downloads-file\RUN.MBR |
||||
* [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT - |
||||
* FTP\i5-downloads-file\RUNNER.MBR |
||||
* [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT - |
||||
* FTP\i5-downloads-file\RUNNERBND.MBR |
||||
* [ftp] 3 files retrieved |
||||
* |
||||
* |
||||
* Example 4, using ANT to download specific members of all files of a library: |
||||
* ---------------------------------------------------------------------------- |
||||
* |
||||
* <echo/> |
||||
* <echo>Downloading members of all files of a library:</echo> |
||||
* |
||||
* <ftp action="get" |
||||
* server="${ftp.server}" |
||||
* userid="${ftp.user}" |
||||
* password="${ftp.password}" |
||||
* binary="false" |
||||
* verbose="true" |
||||
* remotedir="/QSYS.LIB/RPGUNIT.LIB" |
||||
* systemTypeKey="OS/400" |
||||
* > |
||||
* <fileset dir="./i5-downloads-lib" casesensitive="false"> |
||||
* <include name="**\run*.mbr" /> |
||||
* </fileset> |
||||
* </ftp> |
||||
* |
||||
* Output: |
||||
* ------- |
||||
* |
||||
* [echo] Downloading members of all files of a library: |
||||
* [ftp] getting files |
||||
* [ftp] transferring RPGUNIT1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR |
||||
* [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR |
||||
* [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR |
||||
* [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR |
||||
* [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR |
||||
* [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT - |
||||
* FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR |
||||
* [ftp] 6 files retrieved |
||||
* |
||||
* |
||||
* Example 5, using ANT to download a save file of a library: |
||||
* ---------------------------------------------------------- |
||||
* |
||||
* <ftp action="get" |
||||
* server="${ftp.server}" |
||||
* userid="${ftp.user}" |
||||
* password="${ftp.password}" |
||||
* binary="true" |
||||
* verbose="true" |
||||
* remotedir="/QSYS.LIB/RPGUNIT.LIB" |
||||
* systemTypeKey="OS/400" |
||||
* > |
||||
* <fileset dir="./i5-downloads-savf" casesensitive="false"> |
||||
* <include name="RPGUNIT.SAVF" /> |
||||
* </fileset> |
||||
* </ftp> |
||||
* |
||||
* Output: |
||||
* ------- |
||||
* [echo] Downloading save file: |
||||
* [ftp] getting files |
||||
* [ftp] transferring RPGUNIT.SAVF to C:\workspaces\rdp_080\workspace\net-Test\i5-downloads-lib\RPGUNIT.SAVF |
||||
* [ftp] 1 files retrieved |
||||
* |
||||
* </pre> |
||||
*/ |
||||
public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
private static final String DEFAULT_DATE_FORMAT = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24
|
||||
|
||||
private static final String REGEX = "(\\S+)\\s+" // user
|
||||
+ "(?:(\\d+)\\s+)?" // size, empty for members
|
||||
+ "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members
|
||||
+ "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM
|
||||
+ "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE
|
||||
|
||||
/** |
||||
* The default constructor for a OS400FTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public OS400FTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of an OS400FTPEntryParser object |
||||
* with something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public OS400FTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX); |
||||
configure(config); |
||||
} |
||||
|
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
|
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
int type; |
||||
|
||||
if (matches(entry)) { |
||||
String usr = group(1); |
||||
String filesize = group(2); |
||||
String datestr = ""; |
||||
if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) { |
||||
datestr = group(3) + " " + group(4); |
||||
} |
||||
String typeStr = group(5); |
||||
String name = group(6); |
||||
|
||||
boolean mustScanForPathSeparator = true; |
||||
|
||||
try { |
||||
file.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
if (typeStr.equalsIgnoreCase("*STMF")) { |
||||
type = FTPFile.FILE_TYPE; |
||||
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) { |
||||
return null; |
||||
} |
||||
} else if (typeStr.equalsIgnoreCase("*DIR")) { |
||||
type = FTPFile.DIRECTORY_TYPE; |
||||
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) { |
||||
return null; |
||||
} |
||||
} else if (typeStr.equalsIgnoreCase("*FILE")) { |
||||
// File, defines the structure of the data (columns of a row)
|
||||
// but the data is stored in one or more members. Typically a
|
||||
// source file contains multiple members whereas it is
|
||||
// recommended (but not enforced) to use one member per data
|
||||
// file.
|
||||
// Save files are a special type of files which are used
|
||||
// to save objects, e.g. for backups.
|
||||
if (name != null && name.toUpperCase().endsWith(".SAVF")) { |
||||
mustScanForPathSeparator = false; |
||||
type = FTPFile.FILE_TYPE; |
||||
} else { |
||||
return null; |
||||
} |
||||
} else if (typeStr.equalsIgnoreCase("*MEM")) { |
||||
mustScanForPathSeparator = false; |
||||
type = FTPFile.FILE_TYPE; |
||||
|
||||
if (isNullOrEmpty(name)) { |
||||
return null; |
||||
} |
||||
if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) { |
||||
return null; |
||||
} |
||||
|
||||
// Quick and dirty bug fix to make SelectorUtils work.
|
||||
// Class SelectorUtils uses 'File.separator' to splitt
|
||||
// a given path into pieces. But actually it had to
|
||||
// use the separator of the FTP server, which is a forward
|
||||
// slash in case of an AS/400.
|
||||
name = name.replace('/', File.separatorChar); |
||||
} else { |
||||
type = FTPFile.UNKNOWN_TYPE; |
||||
} |
||||
|
||||
file.setType(type); |
||||
|
||||
file.setUser(usr); |
||||
|
||||
try { |
||||
file.setSize(Long.parseLong(filesize)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
if (name.endsWith("/")) { |
||||
name = name.substring(0, name.length() - 1); |
||||
} |
||||
if (mustScanForPathSeparator) { |
||||
int pos = name.lastIndexOf('/'); |
||||
if (pos > -1) { |
||||
name = name.substring(pos + 1); |
||||
} |
||||
} |
||||
|
||||
file.setName(name); |
||||
|
||||
return file; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* @param string String value that is checked for <code>null</code> |
||||
* or empty. |
||||
* @return <code>true</code> for <code>null</code> or empty values, |
||||
* else <code>false</code>. |
||||
*/ |
||||
private boolean isNullOrEmpty(String string) { |
||||
if (string == null || string.length() == 0) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_OS400, DEFAULT_DATE_FORMAT, null); |
||||
} |
||||
} |
@ -1,60 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
/** |
||||
* This class encapsulates all errors that may be thrown by |
||||
* the process of an FTPFileEntryParserFactory creating and |
||||
* instantiating an FTPFileEntryParser. |
||||
*/ |
||||
public class ParserInitializationException extends RuntimeException { |
||||
|
||||
private static final long serialVersionUID = 5563335279583210658L; |
||||
|
||||
/** |
||||
* Constucts a ParserInitializationException with just a message |
||||
* |
||||
* @param message Exception message |
||||
*/ |
||||
public ParserInitializationException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
/** |
||||
* Constucts a ParserInitializationException with a message |
||||
* and a root cause. |
||||
* |
||||
* @param message Exception message |
||||
* @param rootCause root cause throwable that caused |
||||
* this to be thrown |
||||
*/ |
||||
public ParserInitializationException(String message, Throwable rootCause) { |
||||
super(message, rootCause); |
||||
} |
||||
|
||||
/** |
||||
* returns the root cause of this exception or null |
||||
* if no root cause was specified. |
||||
* |
||||
* @return the root cause of this exception being thrown |
||||
* @deprecated use {@link #getCause()} instead |
||||
*/ |
||||
@Deprecated public Throwable getRootCause() { |
||||
return super.getCause(); |
||||
} |
||||
} |
@ -1,199 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; |
||||
import java.util.regex.MatchResult; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
import java.util.regex.PatternSyntaxException; |
||||
|
||||
/** |
||||
* This abstract class implements both the older FTPFileListParser and |
||||
* newer FTPFileEntryParser interfaces with default functionality. |
||||
* All the classes in the parser subpackage inherit from this. |
||||
* |
||||
* This is the base class for all regular expression based FTPFileEntryParser classes |
||||
*/ |
||||
public abstract class RegexFTPFileEntryParserImpl extends FTPFileEntryParserImpl { |
||||
/** |
||||
* internal pattern the matcher tries to match, representing a file |
||||
* entry |
||||
*/ |
||||
private Pattern pattern = null; |
||||
|
||||
/** |
||||
* internal match result used by the parser |
||||
*/ |
||||
private MatchResult result = null; |
||||
|
||||
/** |
||||
* Internal PatternMatcher object used by the parser. It has protected |
||||
* scope in case subclasses want to make use of it for their own purposes. |
||||
*/ |
||||
protected Matcher _matcher_ = null; |
||||
|
||||
/** |
||||
* The constructor for a RegexFTPFileEntryParserImpl object. |
||||
* The expression is compiled with flags = 0. |
||||
* |
||||
* @param regex The regular expression with which this object is |
||||
* initialized. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen in |
||||
* normal conditions. It it is seen, this is a sign that a subclass has |
||||
* been created with a bad regular expression. Since the parser must be |
||||
* created before use, this means that any bad parser subclasses created |
||||
* from this will bomb very quickly, leading to easy detection. |
||||
*/ |
||||
|
||||
public RegexFTPFileEntryParserImpl(String regex) { |
||||
super(); |
||||
compileRegex(regex, 0); |
||||
} |
||||
|
||||
/** |
||||
* The constructor for a RegexFTPFileEntryParserImpl object. |
||||
* |
||||
* @param regex The regular expression with which this object is |
||||
* initialized. |
||||
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen in |
||||
* normal conditions. It it is seen, this is a sign that a subclass has |
||||
* been created with a bad regular expression. Since the parser must be |
||||
* created before use, this means that any bad parser subclasses created |
||||
* from this will bomb very quickly, leading to easy detection. |
||||
* @since 3.4 |
||||
*/ |
||||
public RegexFTPFileEntryParserImpl(String regex, final int flags) { |
||||
super(); |
||||
compileRegex(regex, flags); |
||||
} |
||||
|
||||
/** |
||||
* Convenience method delegates to the internal MatchResult's matches() |
||||
* method. |
||||
* |
||||
* @param s the String to be matched |
||||
* @return true if s matches this object's regular expression. |
||||
*/ |
||||
|
||||
public boolean matches(String s) { |
||||
this.result = null; |
||||
_matcher_ = pattern.matcher(s); |
||||
if (_matcher_.matches()) { |
||||
this.result = _matcher_.toMatchResult(); |
||||
} |
||||
return null != this.result; |
||||
} |
||||
|
||||
/** |
||||
* Convenience method |
||||
* |
||||
* @return the number of groups() in the internal MatchResult. |
||||
*/ |
||||
|
||||
public int getGroupCnt() { |
||||
if (this.result == null) { |
||||
return 0; |
||||
} |
||||
return this.result.groupCount(); |
||||
} |
||||
|
||||
/** |
||||
* Convenience method delegates to the internal MatchResult's group() |
||||
* method. |
||||
* |
||||
* @param matchnum match group number to be retrieved |
||||
* @return the content of the <code>matchnum'th</code> group of the internal |
||||
* match or null if this method is called without a match having |
||||
* been made. |
||||
*/ |
||||
public String group(int matchnum) { |
||||
if (this.result == null) { |
||||
return null; |
||||
} |
||||
return this.result.group(matchnum); |
||||
} |
||||
|
||||
/** |
||||
* For debugging purposes - returns a string shows each match group by |
||||
* number. |
||||
* |
||||
* @return a string shows each match group by number. |
||||
*/ |
||||
|
||||
public String getGroupsAsString() { |
||||
StringBuilder b = new StringBuilder(); |
||||
for (int i = 1; i <= this.result.groupCount(); i++) { |
||||
b.append(i) |
||||
.append(") ") |
||||
.append(this.result.group(i)) |
||||
.append(System.getProperty("line.separator")); |
||||
} |
||||
return b.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Alter the current regular expression being utilised for entry parsing |
||||
* and create a new {@link Pattern} instance. |
||||
* |
||||
* @param regex The new regular expression |
||||
* @return true |
||||
* @throws IllegalArgumentException if the regex cannot be compiled |
||||
* @since 2.0 |
||||
*/ |
||||
public boolean setRegex(final String regex) { |
||||
compileRegex(regex, 0); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Alter the current regular expression being utilised for entry parsing |
||||
* and create a new {@link Pattern} instance. |
||||
* |
||||
* @param regex The new regular expression |
||||
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. |
||||
* @return true |
||||
* @throws IllegalArgumentException if the regex cannot be compiled |
||||
* @since 3.4 |
||||
*/ |
||||
public boolean setRegex(final String regex, final int flags) { |
||||
compileRegex(regex, flags); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Compile the regex and store the {@link Pattern}. |
||||
* |
||||
* This is an internal method to do the work so the constructor does not |
||||
* have to call an overrideable method. |
||||
* |
||||
* @param regex the expression to compile |
||||
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. |
||||
* @throws IllegalArgumentException if the regex cannot be compiled |
||||
*/ |
||||
private void compileRegex(final String regex, final int flags) { |
||||
try { |
||||
pattern = Pattern.compile(regex, flags); |
||||
} catch (PatternSyntaxException pse) { |
||||
throw new IllegalArgumentException("Unparseable regex supplied: " + regex); |
||||
} |
||||
} |
||||
} |
@ -1,335 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.text.ParseException; |
||||
import java.util.List; |
||||
import java.util.ListIterator; |
||||
|
||||
/** |
||||
* Implementation FTPFileEntryParser and FTPFileListParser for standard |
||||
* Unix Systems. |
||||
* |
||||
* This class is based on the logic of Daniel Savarese's |
||||
* DefaultFTPListParser, but adapted to use regular expressions and to fit the |
||||
* new FTPFileEntryParser interface. |
||||
* |
||||
* @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
*/ |
||||
public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
|
||||
|
||||
static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
|
||||
|
||||
static final String NUMERIC_DATE_FORMAT = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
|
||||
|
||||
// Suffixes used in Japanese listings after the numeric values
|
||||
private static final String JA_MONTH = "\u6708"; |
||||
private static final String JA_DAY = "\u65e5"; |
||||
private static final String JA_YEAR = "\u5e74"; |
||||
|
||||
private static final String DEFAULT_DATE_FORMAT_JA = |
||||
"M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年
|
||||
|
||||
private static final String DEFAULT_RECENT_DATE_FORMAT_JA = |
||||
"M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10
|
||||
|
||||
/** |
||||
* Some Linux distributions are now shipping an FTP server which formats |
||||
* file listing dates in an all-numeric format: |
||||
* <code>"yyyy-MM-dd HH:mm</code>. |
||||
* This is a very welcome development, and hopefully it will soon become |
||||
* the standard. However, since it is so new, for now, and possibly |
||||
* forever, we merely accomodate it, but do not make it the default. |
||||
* <p> |
||||
* For now end users may specify this format only via |
||||
* <code>UnixFTPEntryParser(FTPClientConfig)</code>. |
||||
* Steve Cohen - 2005-04-17 |
||||
*/ |
||||
public static final FTPClientConfig NUMERIC_DATE_CONFIG = |
||||
new FTPClientConfig(FTPClientConfig.SYST_UNIX, NUMERIC_DATE_FORMAT, null); |
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
* |
||||
* Permissions: |
||||
* r the file is readable |
||||
* w the file is writable |
||||
* x the file is executable |
||||
* - the indicated permission is not granted |
||||
* L mandatory locking occurs during access (the set-group-ID bit is |
||||
* on and the group execution bit is off) |
||||
* s the set-user-ID or set-group-ID bit is on, and the corresponding |
||||
* user or group execution bit is also on |
||||
* S undefined bit-state (the set-user-ID bit is on and the user |
||||
* execution bit is off) |
||||
* t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and |
||||
* execution is on |
||||
* T the 1000 bit is turned on, and execution is off (undefined bit- |
||||
* state) |
||||
* e z/OS external link bit |
||||
* Final letter may be appended: |
||||
* + file has extended security attributes (e.g. ACL) |
||||
* Note: local listings on MacOSX also use '@'; |
||||
* this is not allowed for here as does not appear to be shown by FTP servers |
||||
* {@code @} file has extended attributes |
||||
*/ |
||||
private static final String REGEX = "([bcdelfmpSs-])" // file type
|
||||
+ "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions
|
||||
|
||||
+ "\\s*" // separator TODO why allow it to be omitted??
|
||||
|
||||
+ "(\\d+)" // link count
|
||||
|
||||
+ "\\s+" // separator
|
||||
|
||||
+ "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces)
|
||||
+ "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces)
|
||||
+ "(\\d+(?:,\\s*\\d+)?)" // size or n,m
|
||||
|
||||
+ "\\s+" // separator
|
||||
|
||||
/* |
||||
* numeric or standard format date: |
||||
* yyyy-mm-dd (expecting hh:mm to follow) |
||||
* MMM [d]d |
||||
* [d]d MMM |
||||
* N.B. use non-space for MMM to allow for languages such as German which use |
||||
* diacritics (e.g. umlaut) in some abbreviations. |
||||
* Japanese uses numeric day and month with suffixes to distinguish them |
||||
* [d]dXX [d]dZZ |
||||
*/ + "(" + "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
|
||||
"|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d
|
||||
"|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM
|
||||
"|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")" + ")" |
||||
|
||||
+ "\\s+" // separator
|
||||
|
||||
/* |
||||
year (for non-recent standard format) - yyyy |
||||
or time (for numeric or recent standard format) [h]h:mm |
||||
or Japanese year - yyyyXX |
||||
*/ + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
|
||||
|
||||
+ "\\s" // separator
|
||||
|
||||
+ "(.*)"; // the rest (21)
|
||||
|
||||
// if true, leading spaces are trimmed from file names
|
||||
// this was the case for the original implementation
|
||||
final boolean trimLeadingSpaces; // package protected for access from test code
|
||||
|
||||
/** |
||||
* The default constructor for a UnixFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public UnixFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of a UnixFTPEntryParser object with |
||||
* something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public UnixFTPEntryParser(FTPClientConfig config) { |
||||
this(config, false); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of a UnixFTPEntryParser object with |
||||
* something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @param trimLeadingSpaces if {@code true}, trim leading spaces from file names |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 3.4 |
||||
*/ |
||||
public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) { |
||||
super(REGEX); |
||||
configure(config); |
||||
this.trimLeadingSpaces = trimLeadingSpaces; |
||||
} |
||||
|
||||
/** |
||||
* Preparse the list to discard "total nnn" lines |
||||
*/ |
||||
@Override public List<String> preParse(List<String> original) { |
||||
ListIterator<String> iter = original.listIterator(); |
||||
while (iter.hasNext()) { |
||||
String entry = iter.next(); |
||||
if (entry.matches("^total \\d+$")) { // NET-389
|
||||
iter.remove(); |
||||
} |
||||
} |
||||
return original; |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of a unix (standard) FTP server file listing and converts |
||||
* it into a usable format in the form of an <code> FTPFile </code> |
||||
* instance. If the file listing line doesn't describe a file, |
||||
* <code> null </code> is returned, otherwise a <code> FTPFile </code> |
||||
* instance representing the files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
FTPFile file = new FTPFile(); |
||||
file.setRawListing(entry); |
||||
int type; |
||||
boolean isDevice = false; |
||||
|
||||
if (matches(entry)) { |
||||
String typeStr = group(1); |
||||
String hardLinkCount = group(15); |
||||
String usr = group(16); |
||||
String grp = group(17); |
||||
String filesize = group(18); |
||||
String datestr = group(19) + " " + group(20); |
||||
String name = group(21); |
||||
if (trimLeadingSpaces) { |
||||
name = name.replaceFirst("^\\s+", ""); |
||||
} |
||||
|
||||
try { |
||||
if (group(19).contains(JA_MONTH)) { // special processing for Japanese format
|
||||
FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl(); |
||||
jaParser.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA, |
||||
DEFAULT_RECENT_DATE_FORMAT_JA)); |
||||
file.setTimestamp(jaParser.parseTimestamp(datestr)); |
||||
} else { |
||||
file.setTimestamp(super.parseTimestamp(datestr)); |
||||
} |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
// A 'whiteout' file is an ARTIFICIAL entry in any of several types of
|
||||
// 'translucent' filesystems, of which a 'union' filesystem is one.
|
||||
|
||||
// bcdelfmpSs-
|
||||
switch (typeStr.charAt(0)) { |
||||
case 'd': |
||||
type = FTPFile.DIRECTORY_TYPE; |
||||
break; |
||||
case 'e': // NET-39 => z/OS external link
|
||||
type = FTPFile.SYMBOLIC_LINK_TYPE; |
||||
break; |
||||
case 'l': |
||||
type = FTPFile.SYMBOLIC_LINK_TYPE; |
||||
break; |
||||
case 'b': |
||||
case 'c': |
||||
isDevice = true; |
||||
type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented
|
||||
break; |
||||
case 'f': |
||||
case '-': |
||||
type = FTPFile.FILE_TYPE; |
||||
break; |
||||
default: // e.g. ? and w = whiteout
|
||||
type = FTPFile.UNKNOWN_TYPE; |
||||
} |
||||
|
||||
file.setType(type); |
||||
|
||||
int g = 4; |
||||
for (int access = 0; access < 3; access++, g += 4) { |
||||
// Use != '-' to avoid having to check for suid and sticky bits
|
||||
file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-"))); |
||||
file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-"))); |
||||
|
||||
String execPerm = group(g + 2); |
||||
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) { |
||||
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); |
||||
} else { |
||||
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); |
||||
} |
||||
} |
||||
|
||||
if (!isDevice) { |
||||
try { |
||||
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
} |
||||
|
||||
file.setUser(usr); |
||||
file.setGroup(grp); |
||||
|
||||
try { |
||||
file.setSize(Long.parseLong(filesize)); |
||||
} catch (NumberFormatException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
// oddball cases like symbolic links, file names
|
||||
// with spaces in them.
|
||||
if (type == FTPFile.SYMBOLIC_LINK_TYPE) { |
||||
|
||||
int end = name.indexOf(" -> "); |
||||
// Give up if no link indicator is present
|
||||
if (end == -1) { |
||||
file.setName(name); |
||||
} else { |
||||
file.setName(name.substring(0, end)); |
||||
file.setLink(name.substring(end + 4)); |
||||
} |
||||
} else { |
||||
file.setName(name); |
||||
} |
||||
return file; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT, |
||||
DEFAULT_RECENT_DATE_FORMAT); |
||||
} |
||||
} |
@ -1,251 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFile; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import aria.apache.commons.net.ftp.FTPListParseEngine; |
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.text.ParseException; |
||||
import java.util.StringTokenizer; |
||||
|
||||
/** |
||||
* Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. |
||||
* This is a sample of VMS LIST output |
||||
* |
||||
* "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* <P><B> |
||||
* Note: VMSFTPEntryParser can only be instantiated through the |
||||
* DefaultFTPParserFactory by classname. It will not be chosen |
||||
* by the autodetection scheme. |
||||
* </B> |
||||
* <P> |
||||
* |
||||
* @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
* @see DefaultFTPFileEntryParserFactory |
||||
*/ |
||||
public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { |
||||
|
||||
private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
|
||||
|
||||
/** |
||||
* this is the regular expression used by this parser. |
||||
*/ |
||||
private static final String REGEX = |
||||
"(.*?;[0-9]+)\\s*" //1 file and version
|
||||
+ "(\\d+)/\\d+\\s*" //2 size/allocated
|
||||
+ "(\\S+)\\s+(\\S+)\\s+" //3+4 date and time
|
||||
+ "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner
|
||||
+ "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; |
||||
//9,10,11 Permissions (O,G,W)
|
||||
// TODO - perhaps restrict permissions to [RWED]* ?
|
||||
|
||||
/** |
||||
* Constructor for a VMSFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public VMSFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of a VMSFTPEntryParser object with |
||||
* something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public VMSFTPEntryParser(FTPClientConfig config) { |
||||
super(REGEX); |
||||
configure(config); |
||||
} |
||||
|
||||
/** |
||||
* Parses a line of a VMS FTP server file listing and converts it into a |
||||
* usable format in the form of an <code> FTPFile </code> instance. If the |
||||
* file listing line doesn't describe a file, <code> null </code> is |
||||
* returned, otherwise a <code> FTPFile </code> instance representing the |
||||
* files in the directory is returned. |
||||
* |
||||
* @param entry A line of text from the file listing |
||||
* @return An FTPFile instance corresponding to the supplied entry |
||||
*/ |
||||
@Override public FTPFile parseFTPEntry(String entry) { |
||||
//one block in VMS equals 512 bytes
|
||||
long longBlock = 512; |
||||
|
||||
if (matches(entry)) { |
||||
FTPFile f = new FTPFile(); |
||||
f.setRawListing(entry); |
||||
String name = group(1); |
||||
String size = group(2); |
||||
String datestr = group(3) + " " + group(4); |
||||
String owner = group(5); |
||||
String permissions[] = new String[3]; |
||||
permissions[0] = group(9); |
||||
permissions[1] = group(10); |
||||
permissions[2] = group(11); |
||||
try { |
||||
f.setTimestamp(super.parseTimestamp(datestr)); |
||||
} catch (ParseException e) { |
||||
// intentionally do nothing
|
||||
} |
||||
|
||||
String grp; |
||||
String user; |
||||
StringTokenizer t = new StringTokenizer(owner, ","); |
||||
switch (t.countTokens()) { |
||||
case 1: |
||||
grp = null; |
||||
user = t.nextToken(); |
||||
break; |
||||
case 2: |
||||
grp = t.nextToken(); |
||||
user = t.nextToken(); |
||||
break; |
||||
default: |
||||
grp = null; |
||||
user = null; |
||||
} |
||||
|
||||
if (name.lastIndexOf(".DIR") != -1) { |
||||
f.setType(FTPFile.DIRECTORY_TYPE); |
||||
} else { |
||||
f.setType(FTPFile.FILE_TYPE); |
||||
} |
||||
//set FTPFile name
|
||||
//Check also for versions to be returned or not
|
||||
if (isVersioning()) { |
||||
f.setName(name); |
||||
} else { |
||||
name = name.substring(0, name.lastIndexOf(";")); |
||||
f.setName(name); |
||||
} |
||||
//size is retreived in blocks and needs to be put in bytes
|
||||
//for us humans and added to the FTPFile array
|
||||
long sizeInBytes = Long.parseLong(size) * longBlock; |
||||
f.setSize(sizeInBytes); |
||||
|
||||
f.setGroup(grp); |
||||
f.setUser(user); |
||||
//set group and owner
|
||||
|
||||
//Set file permission.
|
||||
//VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
|
||||
//R (read) W (write) E (execute) D (delete)
|
||||
|
||||
//iterate for OWNER GROUP WORLD permissions
|
||||
for (int access = 0; access < 3; access++) { |
||||
String permission = permissions[access]; |
||||
|
||||
f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0); |
||||
f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0); |
||||
f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0); |
||||
} |
||||
|
||||
return f; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Reads the next entry using the supplied BufferedReader object up to |
||||
* whatever delemits one entry from the next. This parser cannot use |
||||
* the default implementation of simply calling BufferedReader.readLine(), |
||||
* because one entry may span multiple lines. |
||||
* |
||||
* @param reader The BufferedReader object from which entries are to be |
||||
* read. |
||||
* @return A string representing the next ftp entry or null if none found. |
||||
* @throws IOException thrown on any IO Error reading from the reader. |
||||
*/ |
||||
@Override public String readNextEntry(BufferedReader reader) throws IOException { |
||||
String line = reader.readLine(); |
||||
StringBuilder entry = new StringBuilder(); |
||||
while (line != null) { |
||||
if (line.startsWith("Directory") || line.startsWith("Total")) { |
||||
line = reader.readLine(); |
||||
continue; |
||||
} |
||||
|
||||
entry.append(line); |
||||
if (line.trim().endsWith(")")) { |
||||
break; |
||||
} |
||||
line = reader.readLine(); |
||||
} |
||||
return (entry.length() == 0 ? null : entry.toString()); |
||||
} |
||||
|
||||
protected boolean isVersioning() { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Defines a default configuration to be used when this class is |
||||
* instantiated without a {@link FTPClientConfig FTPClientConfig} |
||||
* parameter being specified. |
||||
* |
||||
* @return the default configuration for this parser. |
||||
*/ |
||||
@Override protected FTPClientConfig getDefaultConfiguration() { |
||||
return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null); |
||||
} |
||||
|
||||
// DEPRECATED METHODS - for API compatibility only - DO NOT USE
|
||||
|
||||
/** |
||||
* DO NOT USE |
||||
* |
||||
* @param listStream the stream |
||||
* @return the array of files |
||||
* @throws IOException on error |
||||
* @deprecated (2.2) No other FTPFileEntryParser implementations have this method. |
||||
*/ |
||||
@Deprecated public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException { |
||||
FTPListParseEngine engine = |
||||
new FTPListParseEngine(this); |
||||
engine.readServerList(listStream, null); |
||||
return engine.getFiles(); |
||||
} |
||||
} |
||||
|
||||
/* Emacs configuration |
||||
* Local variables: ** |
||||
* mode: java ** |
||||
* c-basic-offset: 4 ** |
||||
* indent-tabs-mode: nil ** |
||||
* End: ** |
||||
*/ |
@ -1,153 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.ftp.parser; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPClientConfig; |
||||
import aria.apache.commons.net.ftp.FTPFileEntryParser; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.ListIterator; |
||||
import java.util.regex.MatchResult; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
import java.util.regex.PatternSyntaxException; |
||||
|
||||
/** |
||||
* Special implementation VMSFTPEntryParser with versioning turned on. |
||||
* This parser removes all duplicates and only leaves the version with the highest |
||||
* version number for each filename. |
||||
* |
||||
* This is a sample of VMS LIST output |
||||
* |
||||
* "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] |
||||
* (RWED,RWED,RWED,RE)", |
||||
* <P> |
||||
* |
||||
* @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ |
||||
* @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) |
||||
*/ |
||||
public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser { |
||||
|
||||
private final Pattern _preparse_pattern_; |
||||
private static final String PRE_PARSE_REGEX = "(.*?);([0-9]+)\\s*.*"; |
||||
|
||||
/** |
||||
* Constructor for a VMSFTPEntryParser object. |
||||
* |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
*/ |
||||
public VMSVersioningFTPEntryParser() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* This constructor allows the creation of a VMSVersioningFTPEntryParser |
||||
* object with something other than the default configuration. |
||||
* |
||||
* @param config The {@link FTPClientConfig configuration} object used to |
||||
* configure this parser. |
||||
* @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not |
||||
* be seen |
||||
* under normal conditions. It it is seen, this is a sign that |
||||
* <code>REGEX</code> is not a valid regular expression. |
||||
* @since 1.4 |
||||
*/ |
||||
public VMSVersioningFTPEntryParser(FTPClientConfig config) { |
||||
super(); |
||||
configure(config); |
||||
try { |
||||
//_preparse_matcher_ = new Perl5Matcher();
|
||||
_preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); |
||||
} catch (PatternSyntaxException pse) { |
||||
throw new IllegalArgumentException("Unparseable regex supplied: " + PRE_PARSE_REGEX); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Implement hook provided for those implementers (such as |
||||
* VMSVersioningFTPEntryParser, and possibly others) which return |
||||
* multiple files with the same name to remove the duplicates .. |
||||
* |
||||
* @param original Original list |
||||
* @return Original list purged of duplicates |
||||
*/ |
||||
@Override public List<String> preParse(List<String> original) { |
||||
HashMap<String, Integer> existingEntries = new HashMap<String, Integer>(); |
||||
ListIterator<String> iter = original.listIterator(); |
||||
while (iter.hasNext()) { |
||||
String entry = iter.next().trim(); |
||||
MatchResult result = null; |
||||
Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); |
||||
if (_preparse_matcher_.matches()) { |
||||
result = _preparse_matcher_.toMatchResult(); |
||||
String name = result.group(1); |
||||
String version = result.group(2); |
||||
Integer nv = Integer.valueOf(version); |
||||
Integer existing = existingEntries.get(name); |
||||
if (null != existing) { |
||||
if (nv.intValue() < existing.intValue()) { |
||||
iter.remove(); // removes older version from original list.
|
||||
continue; |
||||
} |
||||
} |
||||
existingEntries.put(name, nv); |
||||
} |
||||
} |
||||
// we've now removed all entries less than with less than the largest
|
||||
// version number for each name that were listed after the largest.
|
||||
// we now must remove those with smaller than the largest version number
|
||||
// for each name that were found before the largest
|
||||
while (iter.hasPrevious()) { |
||||
String entry = iter.previous().trim(); |
||||
MatchResult result = null; |
||||
Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); |
||||
if (_preparse_matcher_.matches()) { |
||||
result = _preparse_matcher_.toMatchResult(); |
||||
String name = result.group(1); |
||||
String version = result.group(2); |
||||
Integer nv = Integer.valueOf(version); |
||||
Integer existing = existingEntries.get(name); |
||||
if (null != existing) { |
||||
if (nv.intValue() < existing.intValue()) { |
||||
iter.remove(); // removes older version from original list.
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
return original; |
||||
} |
||||
|
||||
@Override protected boolean isVersioning() { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
/* Emacs configuration |
||||
* Local variables: ** |
||||
* mode: java ** |
||||
* c-basic-offset: 4 ** |
||||
* indent-tabs-mode: nil ** |
||||
* End: ** |
||||
*/ |
@ -1,21 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
/** |
||||
* FTP file listing parser classes |
||||
*/ |
||||
package aria.apache.commons.net.ftp.parser; |
@ -1,75 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.Reader; |
||||
|
||||
/** |
||||
* CRLFLineReader implements a readLine() method that requires |
||||
* exactly CRLF to terminate an input line. |
||||
* This is required for IMAP, which allows bare CR and LF. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public final class CRLFLineReader extends BufferedReader { |
||||
private static final char LF = '\n'; |
||||
private static final char CR = '\r'; |
||||
|
||||
/** |
||||
* Creates a CRLFLineReader that wraps an existing Reader |
||||
* input source. |
||||
* |
||||
* @param reader The Reader input source. |
||||
*/ |
||||
public CRLFLineReader(Reader reader) { |
||||
super(reader); |
||||
} |
||||
|
||||
/** |
||||
* Read a line of text. |
||||
* A line is considered to be terminated by carriage return followed immediately by a linefeed. |
||||
* This contrasts with BufferedReader which also allows other combinations. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
@Override public String readLine() throws IOException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
int intch; |
||||
boolean prevWasCR = false; |
||||
synchronized (lock) { // make thread-safe (hopefully!)
|
||||
while ((intch = read()) != -1) { |
||||
if (prevWasCR && intch == LF) { |
||||
return sb.substring(0, sb.length() - 1); |
||||
} |
||||
if (intch == CR) { |
||||
prevWasCR = true; |
||||
} else { |
||||
prevWasCR = false; |
||||
} |
||||
sb.append((char) intch); |
||||
} |
||||
} |
||||
String string = sb.toString(); |
||||
if (string.length() == 0) { // immediate EOF
|
||||
return null; |
||||
} |
||||
return string; |
||||
} |
||||
} |
@ -1,111 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.util.EventListener; |
||||
|
||||
import aria.apache.commons.net.util.ListenerList; |
||||
|
||||
/** |
||||
* The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners |
||||
* when either of its bytesTransferred() methods are called. Its purpose |
||||
* is to facilitate the notification of the progress of a copy operation |
||||
* performed by one of the static copyStream() methods in |
||||
* org.apache.commons.io.Util to multiple listeners. The static |
||||
* copyStream() methods invoke the |
||||
* bytesTransfered(long, int) of a CopyStreamListener for performance |
||||
* reasons and also because multiple listeners cannot be registered given |
||||
* that the methods are static. |
||||
* |
||||
* @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $ |
||||
* @see CopyStreamEvent |
||||
* @see CopyStreamListener |
||||
* @see Util |
||||
*/ |
||||
public class CopyStreamAdapter implements CopyStreamListener { |
||||
private final ListenerList internalListeners; |
||||
|
||||
/** |
||||
* Creates a new copyStreamAdapter. |
||||
*/ |
||||
public CopyStreamAdapter() { |
||||
internalListeners = new ListenerList(); |
||||
} |
||||
|
||||
/** |
||||
* This method is invoked by a CopyStreamEvent source after copying |
||||
* a block of bytes from a stream. The CopyStreamEvent will contain |
||||
* the total number of bytes transferred so far and the number of bytes |
||||
* transferred in the last write. The CopyStreamAdapater will relay |
||||
* the event to all of its registered listeners, listing itself as the |
||||
* source of the event. |
||||
* |
||||
* @param event The CopyStreamEvent fired by the copying of a block of |
||||
* bytes. |
||||
*/ |
||||
@Override public void bytesTransferred(CopyStreamEvent event) { |
||||
for (EventListener listener : internalListeners) { |
||||
((CopyStreamListener) (listener)).bytesTransferred(event); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method is not part of the JavaBeans model and is used by the |
||||
* static methods in the org.apache.commons.io.Util class for efficiency. |
||||
* It is invoked after a block of bytes to inform the listener of the |
||||
* transfer. The CopyStreamAdapater will create a CopyStreamEvent |
||||
* from the arguments and relay the event to all of its registered |
||||
* listeners, listing itself as the source of the event. |
||||
* |
||||
* @param totalBytesTransferred The total number of bytes transferred |
||||
* so far by the copy operation. |
||||
* @param bytesTransferred The number of bytes copied by the most recent |
||||
* write. |
||||
* @param streamSize The number of bytes in the stream being copied. |
||||
* This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if |
||||
* the size is unknown. |
||||
*/ |
||||
@Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, |
||||
long streamSize) { |
||||
for (EventListener listener : internalListeners) { |
||||
((CopyStreamListener) (listener)).bytesTransferred(totalBytesTransferred, bytesTransferred, |
||||
streamSize); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Registers a CopyStreamListener to receive CopyStreamEvents. |
||||
* Although this method is not declared to be synchronized, it is |
||||
* implemented in a thread safe manner. |
||||
* |
||||
* @param listener The CopyStreamlistener to register. |
||||
*/ |
||||
public void addCopyStreamListener(CopyStreamListener listener) { |
||||
internalListeners.addListener(listener); |
||||
} |
||||
|
||||
/** |
||||
* Unregisters a CopyStreamListener. Although this method is not |
||||
* synchronized, it is implemented in a thread safe manner. |
||||
* |
||||
* @param listener The CopyStreamlistener to unregister. |
||||
*/ |
||||
public void removeCopyStreamListener(CopyStreamListener listener) { |
||||
internalListeners.removeListener(listener); |
||||
} |
||||
} |
@ -1,113 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.util.EventObject; |
||||
|
||||
/** |
||||
* A CopyStreamEvent is triggered after every write performed by a |
||||
* stream copying operation. The event stores the number of bytes |
||||
* transferred by the write triggering the event as well as the total |
||||
* number of bytes transferred so far by the copy operation. |
||||
* |
||||
* @version $Id: CopyStreamEvent.java 1652801 2015-01-18 17:10:05Z sebb $ |
||||
* @see CopyStreamListener |
||||
* @see CopyStreamAdapter |
||||
* @see Util |
||||
*/ |
||||
public class CopyStreamEvent extends EventObject { |
||||
private static final long serialVersionUID = -964927635655051867L; |
||||
|
||||
/** |
||||
* Constant used to indicate the stream size is unknown. |
||||
*/ |
||||
public static final long UNKNOWN_STREAM_SIZE = -1; |
||||
|
||||
private final int bytesTransferred; |
||||
private final long totalBytesTransferred; |
||||
private final long streamSize; |
||||
|
||||
/** |
||||
* Creates a new CopyStreamEvent instance. |
||||
* |
||||
* @param source The source of the event. |
||||
* @param totalBytesTransferred The total number of bytes transferred so |
||||
* far during a copy operation. |
||||
* @param bytesTransferred The number of bytes transferred during the |
||||
* write that triggered the CopyStreamEvent. |
||||
* @param streamSize The number of bytes in the stream being copied. |
||||
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the |
||||
* size is unknown. |
||||
*/ |
||||
public CopyStreamEvent(Object source, long totalBytesTransferred, int bytesTransferred, |
||||
long streamSize) { |
||||
super(source); |
||||
this.bytesTransferred = bytesTransferred; |
||||
this.totalBytesTransferred = totalBytesTransferred; |
||||
this.streamSize = streamSize; |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of bytes transferred by the write that triggered |
||||
* the event. |
||||
* |
||||
* @return The number of bytes transferred by the write that triggered |
||||
* the vent. |
||||
*/ |
||||
public int getBytesTransferred() { |
||||
return bytesTransferred; |
||||
} |
||||
|
||||
/** |
||||
* Returns the total number of bytes transferred so far by the copy |
||||
* operation. |
||||
* |
||||
* @return The total number of bytes transferred so far by the copy |
||||
* operation. |
||||
*/ |
||||
public long getTotalBytesTransferred() { |
||||
return totalBytesTransferred; |
||||
} |
||||
|
||||
/** |
||||
* Returns the size of the stream being copied. |
||||
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the |
||||
* size is unknown. |
||||
* |
||||
* @return The size of the stream being copied. |
||||
*/ |
||||
public long getStreamSize() { |
||||
return streamSize; |
||||
} |
||||
|
||||
/** |
||||
* @since 3.0 |
||||
*/ |
||||
@Override public String toString() { |
||||
return getClass().getName() |
||||
+ "[source=" |
||||
+ source |
||||
+ ", total=" |
||||
+ totalBytesTransferred |
||||
+ ", bytes=" |
||||
+ bytesTransferred |
||||
+ ", size=" |
||||
+ streamSize |
||||
+ "]"; |
||||
} |
||||
} |
@ -1,69 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* The CopyStreamException class is thrown by the org.apache.commons.io.Util |
||||
* copyStream() methods. It stores the number of bytes confirmed to |
||||
* have been transferred before an I/O error as well as the IOException |
||||
* responsible for the failure of a copy operation. |
||||
* |
||||
* @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $ |
||||
* @see Util |
||||
*/ |
||||
public class CopyStreamException extends IOException { |
||||
private static final long serialVersionUID = -2602899129433221532L; |
||||
|
||||
private final long totalBytesTransferred; |
||||
|
||||
/** |
||||
* Creates a new CopyStreamException instance. |
||||
* |
||||
* @param message A message describing the error. |
||||
* @param bytesTransferred The total number of bytes transferred before |
||||
* an exception was thrown in a copy operation. |
||||
* @param exception The IOException thrown during a copy operation. |
||||
*/ |
||||
public CopyStreamException(String message, long bytesTransferred, IOException exception) { |
||||
super(message); |
||||
initCause(exception); // merge this into super() call once we need 1.6+
|
||||
totalBytesTransferred = bytesTransferred; |
||||
} |
||||
|
||||
/** |
||||
* Returns the total number of bytes confirmed to have |
||||
* been transferred by a failed copy operation. |
||||
* |
||||
* @return The total number of bytes confirmed to have |
||||
* been transferred by a failed copy operation. |
||||
*/ |
||||
public long getTotalBytesTransferred() { |
||||
return totalBytesTransferred; |
||||
} |
||||
|
||||
/** |
||||
* Returns the IOException responsible for the failure of a copy operation. |
||||
* |
||||
* @return The IOException responsible for the failure of a copy operation. |
||||
*/ |
||||
public IOException getIOException() { |
||||
return (IOException) getCause(); // cast is OK because it was initialised with an IOException
|
||||
} |
||||
} |
@ -1,68 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.util.EventListener; |
||||
|
||||
/** |
||||
* The CopyStreamListener class can accept CopyStreamEvents to keep track |
||||
* of the progress of a stream copying operation. However, it is currently |
||||
* not used that way within NetComponents for performance reasons. Rather |
||||
* the bytesTransferred(long, int) method is called directly rather than |
||||
* passing an event to bytesTransferred(CopyStreamEvent), saving the creation |
||||
* of a CopyStreamEvent instance. Also, the only place where |
||||
* CopyStreamListener is currently used within NetComponents is in the |
||||
* static methods of the uninstantiable org.apache.commons.io.Util class, which |
||||
* would preclude the use of addCopyStreamListener and |
||||
* removeCopyStreamListener methods. However, future additions may use the |
||||
* JavaBean event model, which is why the hooks have been included from the |
||||
* beginning. |
||||
* |
||||
* @version $Id: CopyStreamListener.java 1652801 2015-01-18 17:10:05Z sebb $ |
||||
* @see CopyStreamEvent |
||||
* @see CopyStreamAdapter |
||||
* @see Util |
||||
*/ |
||||
public interface CopyStreamListener extends EventListener { |
||||
/** |
||||
* This method is invoked by a CopyStreamEvent source after copying |
||||
* a block of bytes from a stream. The CopyStreamEvent will contain |
||||
* the total number of bytes transferred so far and the number of bytes |
||||
* transferred in the last write. |
||||
* |
||||
* @param event The CopyStreamEvent fired by the copying of a block of |
||||
* bytes. |
||||
*/ |
||||
public void bytesTransferred(CopyStreamEvent event); |
||||
|
||||
/** |
||||
* This method is not part of the JavaBeans model and is used by the |
||||
* static methods in the org.apache.commons.io.Util class for efficiency. |
||||
* It is invoked after a block of bytes to inform the listener of the |
||||
* transfer. |
||||
* |
||||
* @param totalBytesTransferred The total number of bytes transferred |
||||
* so far by the copy operation. |
||||
* @param bytesTransferred The number of bytes copied by the most recent |
||||
* write. |
||||
* @param streamSize The number of bytes in the stream being copied. |
||||
* This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if |
||||
* the size is unknown. |
||||
*/ |
||||
public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize); |
||||
} |
@ -1,238 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.Reader; |
||||
|
||||
/** |
||||
* DotTerminatedMessageReader is a class used to read messages from a |
||||
* server that are terminated by a single dot followed by a |
||||
* <CR><LF> |
||||
* sequence and with double dots appearing at the begining of lines which |
||||
* do not signal end of message yet start with a dot. Various Internet |
||||
* protocols such as NNTP and POP3 produce messages of this type. |
||||
* <p> |
||||
* This class handles stripping of the duplicate period at the beginning |
||||
* of lines starting with a period, and ensures you cannot read past the end of the message. |
||||
* <p> |
||||
* Note: versions since 3.0 extend BufferedReader rather than Reader, |
||||
* and no longer change the CRLF into the local EOL. Also only DOT CR LF |
||||
* acts as EOF. |
||||
* |
||||
* @version $Id: DotTerminatedMessageReader.java 1747119 2016-06-07 02:22:24Z ggregory $ |
||||
*/ |
||||
public final class DotTerminatedMessageReader extends BufferedReader { |
||||
private static final char LF = '\n'; |
||||
private static final char CR = '\r'; |
||||
private static final int DOT = '.'; |
||||
|
||||
private boolean atBeginning; |
||||
private boolean eof; |
||||
private boolean seenCR; // was last character CR?
|
||||
|
||||
/** |
||||
* Creates a DotTerminatedMessageReader that wraps an existing Reader |
||||
* input source. |
||||
* |
||||
* @param reader The Reader input source containing the message. |
||||
*/ |
||||
public DotTerminatedMessageReader(Reader reader) { |
||||
super(reader); |
||||
// Assumes input is at start of message
|
||||
atBeginning = true; |
||||
eof = false; |
||||
} |
||||
|
||||
/** |
||||
* Reads and returns the next character in the message. If the end of the |
||||
* message has been reached, returns -1. Note that a call to this method |
||||
* may result in multiple reads from the underlying input stream to decode |
||||
* the message properly (removing doubled dots and so on). All of |
||||
* this is transparent to the programmer and is only mentioned for |
||||
* completeness. |
||||
* |
||||
* @return The next character in the message. Returns -1 if the end of the |
||||
* message has been reached. |
||||
* @throws IOException If an error occurs while reading the underlying |
||||
* stream. |
||||
*/ |
||||
@Override public int read() throws IOException { |
||||
synchronized (lock) { |
||||
if (eof) { |
||||
return -1; // Don't allow read past EOF
|
||||
} |
||||
int chint = super.read(); |
||||
if (chint == -1) { // True EOF
|
||||
eof = true; |
||||
return -1; |
||||
} |
||||
if (atBeginning) { |
||||
atBeginning = false; |
||||
if (chint == DOT) { // Have DOT
|
||||
mark(2); // need to check for CR LF or DOT
|
||||
chint = super.read(); |
||||
if (chint == -1) { // Should not happen
|
||||
// new Throwable("Trailing DOT").printStackTrace();
|
||||
eof = true; |
||||
return DOT; // return the trailing DOT
|
||||
} |
||||
if (chint == DOT) { // Have DOT DOT
|
||||
// no need to reset as we want to lose the first DOT
|
||||
return chint; // i.e. DOT
|
||||
} |
||||
if (chint == CR) { // Have DOT CR
|
||||
chint = super.read(); |
||||
if (chint == -1) { // Still only DOT CR - should not happen
|
||||
//new Throwable("Trailing DOT CR").printStackTrace();
|
||||
reset(); // So CR is picked up next time
|
||||
return DOT; // return the trailing DOT
|
||||
} |
||||
if (chint == LF) { // DOT CR LF
|
||||
atBeginning = true; |
||||
eof = true; |
||||
// Do we need to clear the mark somehow?
|
||||
return -1; |
||||
} |
||||
} |
||||
// Should not happen - lone DOT at beginning
|
||||
//new Throwable("Lone DOT followed by "+(char)chint).printStackTrace();
|
||||
reset(); |
||||
return DOT; |
||||
} // have DOT
|
||||
} // atBeginning
|
||||
|
||||
// Handle CRLF in normal flow
|
||||
if (seenCR) { |
||||
seenCR = false; |
||||
if (chint == LF) { |
||||
atBeginning = true; |
||||
} |
||||
} |
||||
if (chint == CR) { |
||||
seenCR = true; |
||||
} |
||||
return chint; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Reads the next characters from the message into an array and |
||||
* returns the number of characters read. Returns -1 if the end of the |
||||
* message has been reached. |
||||
* |
||||
* @param buffer The character array in which to store the characters. |
||||
* @return The number of characters read. Returns -1 if the |
||||
* end of the message has been reached. |
||||
* @throws IOException If an error occurs in reading the underlying |
||||
* stream. |
||||
*/ |
||||
@Override public int read(char[] buffer) throws IOException { |
||||
return read(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/** |
||||
* Reads the next characters from the message into an array and |
||||
* returns the number of characters read. Returns -1 if the end of the |
||||
* message has been reached. The characters are stored in the array |
||||
* starting from the given offset and up to the length specified. |
||||
* |
||||
* @param buffer The character array in which to store the characters. |
||||
* @param offset The offset into the array at which to start storing |
||||
* characters. |
||||
* @param length The number of characters to read. |
||||
* @return The number of characters read. Returns -1 if the |
||||
* end of the message has been reached. |
||||
* @throws IOException If an error occurs in reading the underlying |
||||
* stream. |
||||
*/ |
||||
@Override public int read(char[] buffer, int offset, int length) throws IOException { |
||||
if (length < 1) { |
||||
return 0; |
||||
} |
||||
int ch; |
||||
synchronized (lock) { |
||||
if ((ch = read()) == -1) { |
||||
return -1; |
||||
} |
||||
|
||||
int off = offset; |
||||
|
||||
do { |
||||
buffer[offset++] = (char) ch; |
||||
} while (--length > 0 && (ch = read()) != -1); |
||||
|
||||
return (offset - off); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Closes the message for reading. This doesn't actually close the |
||||
* underlying stream. The underlying stream may still be used for |
||||
* communicating with the server and therefore is not closed. |
||||
* <p> |
||||
* If the end of the message has not yet been reached, this method |
||||
* will read the remainder of the message until it reaches the end, |
||||
* so that the underlying stream may continue to be used properly |
||||
* for communicating with the server. If you do not fully read |
||||
* a message, you MUST close it, otherwise your program will likely |
||||
* hang or behave improperly. |
||||
* |
||||
* @throws IOException If an error occurs while reading the |
||||
* underlying stream. |
||||
*/ |
||||
@Override public void close() throws IOException { |
||||
synchronized (lock) { |
||||
if (!eof) { |
||||
while (read() != -1) { |
||||
// read to EOF
|
||||
} |
||||
} |
||||
eof = true; |
||||
atBeginning = false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Read a line of text. |
||||
* A line is considered to be terminated by carriage return followed immediately by a linefeed. |
||||
* This contrasts with BufferedReader which also allows other combinations. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
@Override public String readLine() throws IOException { |
||||
StringBuilder sb = new StringBuilder(); |
||||
int intch; |
||||
synchronized (lock) { // make thread-safe (hopefully!)
|
||||
while ((intch = read()) != -1) { |
||||
if (intch == LF && atBeginning) { |
||||
return sb.substring(0, sb.length() - 1); |
||||
} |
||||
sb.append((char) intch); |
||||
} |
||||
} |
||||
String string = sb.toString(); |
||||
if (string.length() == 0) { // immediate EOF
|
||||
return null; |
||||
} |
||||
// Should not happen - EOF without CRLF
|
||||
//new Throwable(string).printStackTrace();
|
||||
return string; |
||||
} |
||||
} |
@ -1,189 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.Writer; |
||||
|
||||
/*** |
||||
* DotTerminatedMessageWriter is a class used to write messages to a |
||||
* server that are terminated by a single dot followed by a |
||||
* <CR><LF> |
||||
* sequence and with double dots appearing at the begining of lines which |
||||
* do not signal end of message yet start with a dot. Various Internet |
||||
* protocols such as NNTP and POP3 produce messages of this type. |
||||
* <p> |
||||
* This class handles the doubling of line-starting periods, |
||||
* converts single linefeeds to NETASCII newlines, and on closing |
||||
* will send the final message terminator dot and NETASCII newline |
||||
* sequence. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public final class DotTerminatedMessageWriter extends Writer { |
||||
private static final int __NOTHING_SPECIAL_STATE = 0; |
||||
private static final int __LAST_WAS_CR_STATE = 1; |
||||
private static final int __LAST_WAS_NL_STATE = 2; |
||||
|
||||
private int __state; |
||||
private Writer __output; |
||||
|
||||
/*** |
||||
* Creates a DotTerminatedMessageWriter that wraps an existing Writer |
||||
* output destination. |
||||
* |
||||
* @param output The Writer output destination to write the message. |
||||
***/ |
||||
public DotTerminatedMessageWriter(Writer output) { |
||||
super(output); |
||||
__output = output; |
||||
__state = __NOTHING_SPECIAL_STATE; |
||||
} |
||||
|
||||
/*** |
||||
* Writes a character to the output. Note that a call to this method |
||||
* may result in multiple writes to the underling Writer in order to |
||||
* convert naked linefeeds to NETASCII line separators and to double |
||||
* line-leading periods. This is transparent to the programmer and |
||||
* is only mentioned for completeness. |
||||
* |
||||
* @param ch The character to write. |
||||
* @throws IOException If an error occurs while writing to the |
||||
* underlying output. |
||||
***/ |
||||
@Override public void write(int ch) throws IOException { |
||||
synchronized (lock) { |
||||
switch (ch) { |
||||
case '\r': |
||||
__state = __LAST_WAS_CR_STATE; |
||||
__output.write('\r'); |
||||
return; |
||||
case '\n': |
||||
if (__state != __LAST_WAS_CR_STATE) { |
||||
__output.write('\r'); |
||||
} |
||||
__output.write('\n'); |
||||
__state = __LAST_WAS_NL_STATE; |
||||
return; |
||||
case '.': |
||||
// Double the dot at the beginning of a line
|
||||
if (__state == __LAST_WAS_NL_STATE) { |
||||
__output.write('.'); |
||||
} |
||||
//$FALL-THROUGH$
|
||||
default: |
||||
__state = __NOTHING_SPECIAL_STATE; |
||||
__output.write(ch); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Writes a number of characters from a character array to the output |
||||
* starting from a given offset. |
||||
* |
||||
* @param buffer The character array to write. |
||||
* @param offset The offset into the array at which to start copying data. |
||||
* @param length The number of characters to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output. |
||||
***/ |
||||
@Override public void write(char[] buffer, int offset, int length) throws IOException { |
||||
synchronized (lock) { |
||||
while (length-- > 0) { |
||||
write(buffer[offset++]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Writes a character array to the output. |
||||
* |
||||
* @param buffer The character array to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output. |
||||
***/ |
||||
@Override public void write(char[] buffer) throws IOException { |
||||
write(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/*** |
||||
* Writes a String to the output. |
||||
* |
||||
* @param string The String to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output. |
||||
***/ |
||||
@Override public void write(String string) throws IOException { |
||||
write(string.toCharArray()); |
||||
} |
||||
|
||||
/*** |
||||
* Writes part of a String to the output starting from a given offset. |
||||
* |
||||
* @param string The String to write. |
||||
* @param offset The offset into the String at which to start copying data. |
||||
* @param length The number of characters to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output. |
||||
***/ |
||||
@Override public void write(String string, int offset, int length) throws IOException { |
||||
write(string.toCharArray(), offset, length); |
||||
} |
||||
|
||||
/*** |
||||
* Flushes the underlying output, writing all buffered output. |
||||
* |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output. |
||||
***/ |
||||
@Override public void flush() throws IOException { |
||||
synchronized (lock) { |
||||
__output.flush(); |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Flushes the underlying output, writing all buffered output, but doesn't |
||||
* actually close the underlying stream. The underlying stream may still |
||||
* be used for communicating with the server and therefore is not closed. |
||||
* |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* output or closing the Writer. |
||||
***/ |
||||
@Override public void close() throws IOException { |
||||
synchronized (lock) { |
||||
if (__output == null) { |
||||
return; |
||||
} |
||||
|
||||
if (__state == __LAST_WAS_CR_STATE) { |
||||
__output.write('\n'); |
||||
} else if (__state != __LAST_WAS_NL_STATE) { |
||||
__output.write("\r\n"); |
||||
} |
||||
|
||||
__output.write(".\r\n"); |
||||
|
||||
__output.flush(); |
||||
__output = null; |
||||
} |
||||
} |
||||
} |
@ -1,196 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.PushbackInputStream; |
||||
import java.io.UnsupportedEncodingException; |
||||
|
||||
/*** |
||||
* This class wraps an input stream, replacing all occurrences |
||||
* of <CR><LF> (carriage return followed by a linefeed), |
||||
* which is the NETASCII standard for representing a newline, with the |
||||
* local line separator representation. You would use this class to |
||||
* implement ASCII file transfers requiring conversion from NETASCII. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public final class FromNetASCIIInputStream extends PushbackInputStream { |
||||
static final boolean _noConversionRequired; |
||||
static final String _lineSeparator; |
||||
static final byte[] _lineSeparatorBytes; |
||||
|
||||
static { |
||||
_lineSeparator = System.getProperty("line.separator"); |
||||
_noConversionRequired = _lineSeparator.equals("\r\n"); |
||||
try { |
||||
_lineSeparatorBytes = _lineSeparator.getBytes("US-ASCII"); |
||||
} catch (UnsupportedEncodingException e) { |
||||
throw new RuntimeException("Broken JVM - cannot find US-ASCII charset!", e); |
||||
} |
||||
} |
||||
|
||||
private int __length = 0; |
||||
|
||||
/*** |
||||
* Returns true if the NetASCII line separator differs from the system |
||||
* line separator, false if they are the same. This method is useful |
||||
* to determine whether or not you need to instantiate a |
||||
* FromNetASCIIInputStream object. |
||||
* |
||||
* @return True if the NETASCII line separator differs from the local |
||||
* system line separator, false if they are the same. |
||||
***/ |
||||
public static final boolean isConversionRequired() { |
||||
return !_noConversionRequired; |
||||
} |
||||
|
||||
/*** |
||||
* Creates a FromNetASCIIInputStream instance that wraps an existing |
||||
* InputStream. |
||||
* @param input the stream to wrap |
||||
***/ |
||||
public FromNetASCIIInputStream(InputStream input) { |
||||
super(input, _lineSeparatorBytes.length + 1); |
||||
} |
||||
|
||||
private int __read() throws IOException { |
||||
int ch; |
||||
|
||||
ch = super.read(); |
||||
|
||||
if (ch == '\r') { |
||||
ch = super.read(); |
||||
if (ch == '\n') { |
||||
unread(_lineSeparatorBytes); |
||||
ch = super.read(); |
||||
// This is a kluge for read(byte[], ...) to read the right amount
|
||||
--__length; |
||||
} else { |
||||
if (ch != -1) { |
||||
unread(ch); |
||||
} |
||||
return '\r'; |
||||
} |
||||
} |
||||
|
||||
return ch; |
||||
} |
||||
|
||||
/*** |
||||
* Reads and returns the next byte in the stream. If the end of the |
||||
* message has been reached, returns -1. Note that a call to this method |
||||
* may result in multiple reads from the underlying input stream in order |
||||
* to convert NETASCII line separators to the local line separator format. |
||||
* This is transparent to the programmer and is only mentioned for |
||||
* completeness. |
||||
* |
||||
* @return The next character in the stream. Returns -1 if the end of the |
||||
* stream has been reached. |
||||
* @throws IOException If an error occurs while reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read() throws IOException { |
||||
if (_noConversionRequired) { |
||||
return super.read(); |
||||
} |
||||
|
||||
return __read(); |
||||
} |
||||
|
||||
/*** |
||||
* Reads the next number of bytes from the stream into an array and |
||||
* returns the number of bytes read. Returns -1 if the end of the |
||||
* stream has been reached. |
||||
* |
||||
* @param buffer The byte array in which to store the data. |
||||
* @return The number of bytes read. Returns -1 if the |
||||
* end of the message has been reached. |
||||
* @throws IOException If an error occurs in reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read(byte buffer[]) throws IOException { |
||||
return read(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/*** |
||||
* Reads the next number of bytes from the stream into an array and returns |
||||
* the number of bytes read. Returns -1 if the end of the |
||||
* message has been reached. The characters are stored in the array |
||||
* starting from the given offset and up to the length specified. |
||||
* |
||||
* @param buffer The byte array in which to store the data. |
||||
* @param offset The offset into the array at which to start storing data. |
||||
* @param length The number of bytes to read. |
||||
* @return The number of bytes read. Returns -1 if the |
||||
* end of the stream has been reached. |
||||
* @throws IOException If an error occurs while reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read(byte buffer[], int offset, int length) throws IOException { |
||||
if (_noConversionRequired) { |
||||
return super.read(buffer, offset, length); |
||||
} |
||||
|
||||
if (length < 1) { |
||||
return 0; |
||||
} |
||||
|
||||
int ch, off; |
||||
|
||||
ch = available(); |
||||
|
||||
__length = (length > ch ? ch : length); |
||||
|
||||
// If nothing is available, block to read only one character
|
||||
if (__length < 1) { |
||||
__length = 1; |
||||
} |
||||
|
||||
if ((ch = __read()) == -1) { |
||||
return -1; |
||||
} |
||||
|
||||
off = offset; |
||||
|
||||
do { |
||||
buffer[offset++] = (byte) ch; |
||||
} while (--__length > 0 && (ch = __read()) != -1); |
||||
|
||||
return (offset - off); |
||||
} |
||||
|
||||
// PushbackInputStream in JDK 1.1.3 returns the wrong thing
|
||||
// TODO - can we delete this override now?
|
||||
|
||||
/*** |
||||
* Returns the number of bytes that can be read without blocking EXCEPT |
||||
* when newline conversions have to be made somewhere within the |
||||
* available block of bytes. In other words, you really should not |
||||
* rely on the value returned by this method if you are trying to avoid |
||||
* blocking. |
||||
***/ |
||||
@Override public int available() throws IOException { |
||||
if (in == null) { |
||||
throw new IOException("Stream closed"); |
||||
} |
||||
return (buf.length - pos) + in.available(); |
||||
} |
||||
} |
@ -1,150 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.FilterOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/*** |
||||
* This class wraps an output stream, replacing all occurrences |
||||
* of <CR><LF> (carriage return followed by a linefeed), |
||||
* which is the NETASCII standard for representing a newline, with the |
||||
* local line separator representation. You would use this class to |
||||
* implement ASCII file transfers requiring conversion from NETASCII. |
||||
* <p> |
||||
* Because of the translation process, a call to <code>flush()</code> will |
||||
* not flush the last byte written if that byte was a carriage |
||||
* return. A call to {@link #close close() }, however, will |
||||
* flush the carriage return. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public final class FromNetASCIIOutputStream extends FilterOutputStream { |
||||
private boolean __lastWasCR; |
||||
|
||||
/*** |
||||
* Creates a FromNetASCIIOutputStream instance that wraps an existing |
||||
* OutputStream. |
||||
* |
||||
* @param output The OutputStream to wrap. |
||||
***/ |
||||
public FromNetASCIIOutputStream(OutputStream output) { |
||||
super(output); |
||||
__lastWasCR = false; |
||||
} |
||||
|
||||
private void __write(int ch) throws IOException { |
||||
switch (ch) { |
||||
case '\r': |
||||
__lastWasCR = true; |
||||
// Don't write anything. We need to see if next one is linefeed
|
||||
break; |
||||
case '\n': |
||||
if (__lastWasCR) { |
||||
out.write(FromNetASCIIInputStream._lineSeparatorBytes); |
||||
__lastWasCR = false; |
||||
break; |
||||
} |
||||
__lastWasCR = false; |
||||
out.write('\n'); |
||||
break; |
||||
default: |
||||
if (__lastWasCR) { |
||||
out.write('\r'); |
||||
__lastWasCR = false; |
||||
} |
||||
out.write(ch); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Writes a byte to the stream. Note that a call to this method |
||||
* might not actually write a byte to the underlying stream until a |
||||
* subsequent character is written, from which it can be determined if |
||||
* a NETASCII line separator was encountered. |
||||
* This is transparent to the programmer and is only mentioned for |
||||
* completeness. |
||||
* |
||||
* @param ch The byte to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(int ch) throws IOException { |
||||
if (FromNetASCIIInputStream._noConversionRequired) { |
||||
out.write(ch); |
||||
return; |
||||
} |
||||
|
||||
__write(ch); |
||||
} |
||||
|
||||
/*** |
||||
* Writes a byte array to the stream. |
||||
* |
||||
* @param buffer The byte array to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(byte buffer[]) throws IOException { |
||||
write(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/*** |
||||
* Writes a number of bytes from a byte array to the stream starting from |
||||
* a given offset. |
||||
* |
||||
* @param buffer The byte array to write. |
||||
* @param offset The offset into the array at which to start copying data. |
||||
* @param length The number of bytes to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(byte buffer[], int offset, int length) |
||||
throws IOException { |
||||
if (FromNetASCIIInputStream._noConversionRequired) { |
||||
// FilterOutputStream method is very slow.
|
||||
//super.write(buffer, offset, length);
|
||||
out.write(buffer, offset, length); |
||||
return; |
||||
} |
||||
|
||||
while (length-- > 0) { |
||||
__write(buffer[offset++]); |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Closes the stream, writing all pending data. |
||||
* |
||||
* @throws IOException If an error occurs while closing the stream. |
||||
***/ |
||||
@Override public synchronized void close() throws IOException { |
||||
if (FromNetASCIIInputStream._noConversionRequired) { |
||||
super.close(); |
||||
return; |
||||
} |
||||
|
||||
if (__lastWasCR) { |
||||
out.write('\r'); |
||||
} |
||||
super.close(); |
||||
} |
||||
} |
@ -1,64 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.FilterInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.net.Socket; |
||||
|
||||
/*** |
||||
* This class wraps an input stream, storing a reference to its originating |
||||
* socket. When the stream is closed, it will also close the socket |
||||
* immediately afterward. This class is useful for situations where you |
||||
* are dealing with a stream originating from a socket, but do not have |
||||
* a reference to the socket, and want to make sure it closes when the |
||||
* stream closes. |
||||
* |
||||
* |
||||
* @see SocketOutputStream |
||||
***/ |
||||
|
||||
public class SocketInputStream extends FilterInputStream { |
||||
private final Socket __socket; |
||||
|
||||
/*** |
||||
* Creates a SocketInputStream instance wrapping an input stream and |
||||
* storing a reference to a socket that should be closed on closing |
||||
* the stream. |
||||
* |
||||
* @param socket The socket to close on closing the stream. |
||||
* @param stream The input stream to wrap. |
||||
***/ |
||||
public SocketInputStream(Socket socket, InputStream stream) { |
||||
super(stream); |
||||
__socket = socket; |
||||
} |
||||
|
||||
/*** |
||||
* Closes the stream and immediately afterward closes the referenced |
||||
* socket. |
||||
* |
||||
* @throws IOException If there is an error in closing the stream |
||||
* or socket. |
||||
***/ |
||||
@Override public void close() throws IOException { |
||||
super.close(); |
||||
__socket.close(); |
||||
} |
||||
} |
@ -1,80 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.FilterOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.net.Socket; |
||||
|
||||
/*** |
||||
* This class wraps an output stream, storing a reference to its originating |
||||
* socket. When the stream is closed, it will also close the socket |
||||
* immediately afterward. This class is useful for situations where you |
||||
* are dealing with a stream originating from a socket, but do not have |
||||
* a reference to the socket, and want to make sure it closes when the |
||||
* stream closes. |
||||
* |
||||
* |
||||
* @see SocketInputStream |
||||
***/ |
||||
|
||||
public class SocketOutputStream extends FilterOutputStream { |
||||
private final Socket __socket; |
||||
|
||||
/*** |
||||
* Creates a SocketOutputStream instance wrapping an output stream and |
||||
* storing a reference to a socket that should be closed on closing |
||||
* the stream. |
||||
* |
||||
* @param socket The socket to close on closing the stream. |
||||
* @param stream The input stream to wrap. |
||||
***/ |
||||
public SocketOutputStream(Socket socket, OutputStream stream) { |
||||
super(stream); |
||||
__socket = socket; |
||||
} |
||||
|
||||
/*** |
||||
* Writes a number of bytes from a byte array to the stream starting from |
||||
* a given offset. This method bypasses the equivalent method in |
||||
* FilterOutputStream because the FilterOutputStream implementation is |
||||
* very inefficient. |
||||
* |
||||
* @param buffer The byte array to write. |
||||
* @param offset The offset into the array at which to start copying data. |
||||
* @param length The number of bytes to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public void write(byte buffer[], int offset, int length) throws IOException { |
||||
out.write(buffer, offset, length); |
||||
} |
||||
|
||||
/*** |
||||
* Closes the stream and immediately afterward closes the referenced |
||||
* socket. |
||||
* |
||||
* @throws IOException If there is an error in closing the stream |
||||
* or socket. |
||||
***/ |
||||
@Override public void close() throws IOException { |
||||
super.close(); |
||||
__socket.close(); |
||||
} |
||||
} |
@ -1,165 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.FilterInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/*** |
||||
* This class wraps an input stream, replacing all singly occurring |
||||
* <LF> (linefeed) characters with <CR><LF> (carriage return |
||||
* followed by linefeed), which is the NETASCII standard for representing |
||||
* a newline. |
||||
* You would use this class to implement ASCII file transfers requiring |
||||
* conversion to NETASCII. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public final class ToNetASCIIInputStream extends FilterInputStream { |
||||
private static final int __NOTHING_SPECIAL = 0; |
||||
private static final int __LAST_WAS_CR = 1; |
||||
private static final int __LAST_WAS_NL = 2; |
||||
private int __status; |
||||
|
||||
/*** |
||||
* Creates a ToNetASCIIInputStream instance that wraps an existing |
||||
* InputStream. |
||||
* |
||||
* @param input The InputStream to wrap. |
||||
***/ |
||||
public ToNetASCIIInputStream(InputStream input) { |
||||
super(input); |
||||
__status = __NOTHING_SPECIAL; |
||||
} |
||||
|
||||
/*** |
||||
* Reads and returns the next byte in the stream. If the end of the |
||||
* message has been reached, returns -1. |
||||
* |
||||
* @return The next character in the stream. Returns -1 if the end of the |
||||
* stream has been reached. |
||||
* @throws IOException If an error occurs while reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read() throws IOException { |
||||
int ch; |
||||
|
||||
if (__status == __LAST_WAS_NL) { |
||||
__status = __NOTHING_SPECIAL; |
||||
return '\n'; |
||||
} |
||||
|
||||
ch = in.read(); |
||||
|
||||
switch (ch) { |
||||
case '\r': |
||||
__status = __LAST_WAS_CR; |
||||
return '\r'; |
||||
case '\n': |
||||
if (__status != __LAST_WAS_CR) { |
||||
__status = __LAST_WAS_NL; |
||||
return '\r'; |
||||
} |
||||
//$FALL-THROUGH$
|
||||
default: |
||||
__status = __NOTHING_SPECIAL; |
||||
return ch; |
||||
} |
||||
// statement not reached
|
||||
//return ch;
|
||||
} |
||||
|
||||
/*** |
||||
* Reads the next number of bytes from the stream into an array and |
||||
* returns the number of bytes read. Returns -1 if the end of the |
||||
* stream has been reached. |
||||
* |
||||
* @param buffer The byte array in which to store the data. |
||||
* @return The number of bytes read. Returns -1 if the |
||||
* end of the message has been reached. |
||||
* @throws IOException If an error occurs in reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read(byte buffer[]) throws IOException { |
||||
return read(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/*** |
||||
* Reads the next number of bytes from the stream into an array and returns |
||||
* the number of bytes read. Returns -1 if the end of the |
||||
* message has been reached. The characters are stored in the array |
||||
* starting from the given offset and up to the length specified. |
||||
* |
||||
* @param buffer The byte array in which to store the data. |
||||
* @param offset The offset into the array at which to start storing data. |
||||
* @param length The number of bytes to read. |
||||
* @return The number of bytes read. Returns -1 if the |
||||
* end of the stream has been reached. |
||||
* @throws IOException If an error occurs while reading the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public int read(byte buffer[], int offset, int length) throws IOException { |
||||
int ch, off; |
||||
|
||||
if (length < 1) { |
||||
return 0; |
||||
} |
||||
|
||||
ch = available(); |
||||
|
||||
if (length > ch) { |
||||
length = ch; |
||||
} |
||||
|
||||
// If nothing is available, block to read only one character
|
||||
if (length < 1) { |
||||
length = 1; |
||||
} |
||||
|
||||
if ((ch = read()) == -1) { |
||||
return -1; |
||||
} |
||||
|
||||
off = offset; |
||||
|
||||
do { |
||||
buffer[offset++] = (byte) ch; |
||||
} while (--length > 0 && (ch = read()) != -1); |
||||
|
||||
return (offset - off); |
||||
} |
||||
|
||||
/*** Returns false. Mark is not supported. ***/ |
||||
@Override public boolean markSupported() { |
||||
return false; |
||||
} |
||||
|
||||
@Override public int available() throws IOException { |
||||
int result; |
||||
|
||||
result = in.available(); |
||||
|
||||
if (__status == __LAST_WAS_NL) { |
||||
return (result + 1); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
@ -1,105 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.FilterOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/*** |
||||
* This class wraps an output stream, replacing all singly occurring |
||||
* <LF> (linefeed) characters with <CR><LF> (carriage return |
||||
* followed by linefeed), which is the NETASCII standard for representing |
||||
* a newline. |
||||
* You would use this class to implement ASCII file transfers requiring |
||||
* conversion to NETASCII. |
||||
* |
||||
* |
||||
***/ |
||||
|
||||
public final class ToNetASCIIOutputStream extends FilterOutputStream { |
||||
private boolean __lastWasCR; |
||||
|
||||
/*** |
||||
* Creates a ToNetASCIIOutputStream instance that wraps an existing |
||||
* OutputStream. |
||||
* |
||||
* @param output The OutputStream to wrap. |
||||
***/ |
||||
public ToNetASCIIOutputStream(OutputStream output) { |
||||
super(output); |
||||
__lastWasCR = false; |
||||
} |
||||
|
||||
/*** |
||||
* Writes a byte to the stream. Note that a call to this method |
||||
* may result in multiple writes to the underlying input stream in order |
||||
* to convert naked newlines to NETASCII line separators. |
||||
* This is transparent to the programmer and is only mentioned for |
||||
* completeness. |
||||
* |
||||
* @param ch The byte to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(int ch) throws IOException { |
||||
switch (ch) { |
||||
case '\r': |
||||
__lastWasCR = true; |
||||
out.write('\r'); |
||||
return; |
||||
case '\n': |
||||
if (!__lastWasCR) { |
||||
out.write('\r'); |
||||
} |
||||
//$FALL-THROUGH$
|
||||
default: |
||||
__lastWasCR = false; |
||||
out.write(ch); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/*** |
||||
* Writes a byte array to the stream. |
||||
* |
||||
* @param buffer The byte array to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(byte buffer[]) throws IOException { |
||||
write(buffer, 0, buffer.length); |
||||
} |
||||
|
||||
/*** |
||||
* Writes a number of bytes from a byte array to the stream starting from |
||||
* a given offset. |
||||
* |
||||
* @param buffer The byte array to write. |
||||
* @param offset The offset into the array at which to start copying data. |
||||
* @param length The number of bytes to write. |
||||
* @throws IOException If an error occurs while writing to the underlying |
||||
* stream. |
||||
***/ |
||||
@Override public synchronized void write(byte buffer[], int offset, int length) |
||||
throws IOException { |
||||
while (length-- > 0) { |
||||
write(buffer[offset++]); |
||||
} |
||||
} |
||||
} |
@ -1,351 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.io; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.io.Reader; |
||||
import java.io.Writer; |
||||
import java.net.Socket; |
||||
|
||||
/*** |
||||
* The Util class cannot be instantiated and stores short static convenience |
||||
* methods that are often quite useful. |
||||
* |
||||
* |
||||
* @see CopyStreamException |
||||
* @see CopyStreamListener |
||||
* @see CopyStreamAdapter |
||||
***/ |
||||
|
||||
public final class Util { |
||||
/** |
||||
* The default buffer size ({@value}) used by |
||||
* {@link #copyStream copyStream } and {@link #copyReader copyReader} |
||||
* and by the copyReader/copyStream methods if a zero or negative buffer size is supplied. |
||||
*/ |
||||
public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; |
||||
|
||||
// Cannot be instantiated
|
||||
private Util() { |
||||
} |
||||
|
||||
/*** |
||||
* Copies the contents of an InputStream to an OutputStream using a |
||||
* copy buffer of a given size and notifies the provided |
||||
* CopyStreamListener of the progress of the copy operation by calling |
||||
* its bytesTransferred(long, int) method after each write to the |
||||
* destination. If you wish to notify more than one listener you should |
||||
* use a CopyStreamAdapter as the listener and register the additional |
||||
* listeners with the CopyStreamAdapter. |
||||
* <p> |
||||
* The contents of the InputStream are |
||||
* read until the end of the stream is reached, but neither the |
||||
* source nor the destination are closed. You must do this yourself |
||||
* outside of the method call. The number of bytes read/written is |
||||
* returned. |
||||
* |
||||
* @param source The source InputStream. |
||||
* @param dest The destination OutputStream. |
||||
* @param bufferSize The number of bytes to buffer during the copy. |
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. |
||||
* @param streamSize The number of bytes in the stream being copied. |
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. |
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} |
||||
* @param listener The CopyStreamListener to notify of progress. If |
||||
* this parameter is null, notification is not attempted. |
||||
* @param flush Whether to flush the output stream after every |
||||
* write. This is necessary for interactive sessions that rely on |
||||
* buffered streams. If you don't flush, the data will stay in |
||||
* the stream buffer. |
||||
* @return number of bytes read/written |
||||
* @throws CopyStreamException If an error occurs while reading from the |
||||
* source or writing to the destination. The CopyStreamException |
||||
* will contain the number of bytes confirmed to have been |
||||
* transferred before an |
||||
* IOException occurred, and it will also contain the IOException |
||||
* that caused the error. These values can be retrieved with |
||||
* the CopyStreamException getTotalBytesTransferred() and |
||||
* getIOException() methods. |
||||
***/ |
||||
public static final long copyStream(InputStream source, OutputStream dest, int bufferSize, |
||||
long streamSize, CopyStreamListener listener, boolean flush) throws CopyStreamException { |
||||
int numBytes; |
||||
long total = 0; |
||||
byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; |
||||
|
||||
try { |
||||
while (!Thread.currentThread().isInterrupted() && (numBytes = source.read(buffer)) != -1) { |
||||
// Technically, some read(byte[]) methods may return 0 and we cannot
|
||||
// accept that as an indication of EOF.
|
||||
|
||||
if (numBytes == 0) { |
||||
int singleByte = source.read(); |
||||
if (singleByte < 0) { |
||||
break; |
||||
} |
||||
dest.write(singleByte); |
||||
if (flush) { |
||||
dest.flush(); |
||||
} |
||||
++total; |
||||
if (listener != null) { |
||||
listener.bytesTransferred(total, 1, streamSize); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
dest.write(buffer, 0, numBytes); |
||||
if (flush) { |
||||
dest.flush(); |
||||
} |
||||
total += numBytes; |
||||
if (listener != null) { |
||||
listener.bytesTransferred(total, numBytes, streamSize); |
||||
} |
||||
} |
||||
} catch (IOException e) { |
||||
throw new CopyStreamException("IOException caught while copying.", total, e); |
||||
} |
||||
|
||||
return total; |
||||
} |
||||
|
||||
|
||||
/*** |
||||
* Copies the contents of an InputStream to an OutputStream using a |
||||
* copy buffer of a given size and notifies the provided |
||||
* CopyStreamListener of the progress of the copy operation by calling |
||||
* its bytesTransferred(long, int) method after each write to the |
||||
* destination. If you wish to notify more than one listener you should |
||||
* use a CopyStreamAdapter as the listener and register the additional |
||||
* listeners with the CopyStreamAdapter. |
||||
* <p> |
||||
* The contents of the InputStream are |
||||
* read until the end of the stream is reached, but neither the |
||||
* source nor the destination are closed. You must do this yourself |
||||
* outside of the method call. The number of bytes read/written is |
||||
* returned. |
||||
* |
||||
* @param source The source InputStream. |
||||
* @param dest The destination OutputStream. |
||||
* @param bufferSize The number of bytes to buffer during the copy. |
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. |
||||
* @param streamSize The number of bytes in the stream being copied. |
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. |
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} |
||||
* @param listener The CopyStreamListener to notify of progress. If |
||||
* this parameter is null, notification is not attempted. |
||||
* @return number of bytes read/written |
||||
* @throws CopyStreamException If an error occurs while reading from the |
||||
* source or writing to the destination. The CopyStreamException |
||||
* will contain the number of bytes confirmed to have been |
||||
* transferred before an |
||||
* IOException occurred, and it will also contain the IOException |
||||
* that caused the error. These values can be retrieved with |
||||
* the CopyStreamException getTotalBytesTransferred() and |
||||
* getIOException() methods. |
||||
***/ |
||||
public static final long copyStream(InputStream source, OutputStream dest, int bufferSize, |
||||
long streamSize, CopyStreamListener listener) throws CopyStreamException { |
||||
return copyStream(source, dest, bufferSize, streamSize, listener, true); |
||||
} |
||||
|
||||
/*** |
||||
* Copies the contents of an InputStream to an OutputStream using a |
||||
* copy buffer of a given size. The contents of the InputStream are |
||||
* read until the end of the stream is reached, but neither the |
||||
* source nor the destination are closed. You must do this yourself |
||||
* outside of the method call. The number of bytes read/written is |
||||
* returned. |
||||
* |
||||
* @param source The source InputStream. |
||||
* @param dest The destination OutputStream. |
||||
* @param bufferSize The number of bytes to buffer during the copy. |
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. |
||||
* @return The number of bytes read/written in the copy operation. |
||||
* @throws CopyStreamException If an error occurs while reading from the |
||||
* source or writing to the destination. The CopyStreamException |
||||
* will contain the number of bytes confirmed to have been |
||||
* transferred before an |
||||
* IOException occurred, and it will also contain the IOException |
||||
* that caused the error. These values can be retrieved with |
||||
* the CopyStreamException getTotalBytesTransferred() and |
||||
* getIOException() methods. |
||||
***/ |
||||
public static final long copyStream(InputStream source, OutputStream dest, int bufferSize) |
||||
throws CopyStreamException { |
||||
return copyStream(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); |
||||
} |
||||
|
||||
/*** |
||||
* Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code> |
||||
* @param source where to copy from |
||||
* @param dest where to copy to |
||||
* @return number of bytes copied |
||||
* @throws CopyStreamException on error |
||||
***/ |
||||
public static final long copyStream(InputStream source, OutputStream dest) |
||||
throws CopyStreamException { |
||||
return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); |
||||
} |
||||
|
||||
/*** |
||||
* Copies the contents of a Reader to a Writer using a |
||||
* copy buffer of a given size and notifies the provided |
||||
* CopyStreamListener of the progress of the copy operation by calling |
||||
* its bytesTransferred(long, int) method after each write to the |
||||
* destination. If you wish to notify more than one listener you should |
||||
* use a CopyStreamAdapter as the listener and register the additional |
||||
* listeners with the CopyStreamAdapter. |
||||
* <p> |
||||
* The contents of the Reader are |
||||
* read until its end is reached, but neither the source nor the |
||||
* destination are closed. You must do this yourself outside of the |
||||
* method call. The number of characters read/written is returned. |
||||
* |
||||
* @param source The source Reader. |
||||
* @param dest The destination writer. |
||||
* @param bufferSize The number of characters to buffer during the copy. |
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. |
||||
* @param streamSize The number of characters in the stream being copied. |
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. |
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} |
||||
* @param listener The CopyStreamListener to notify of progress. If |
||||
* this parameter is null, notification is not attempted. |
||||
* @return The number of characters read/written in the copy operation. |
||||
* @throws CopyStreamException If an error occurs while reading from the |
||||
* source or writing to the destination. The CopyStreamException |
||||
* will contain the number of bytes confirmed to have been |
||||
* transferred before an |
||||
* IOException occurred, and it will also contain the IOException |
||||
* that caused the error. These values can be retrieved with |
||||
* the CopyStreamException getTotalBytesTransferred() and |
||||
* getIOException() methods. |
||||
***/ |
||||
public static final long copyReader(Reader source, Writer dest, int bufferSize, long streamSize, |
||||
CopyStreamListener listener) throws CopyStreamException { |
||||
int numChars; |
||||
long total = 0; |
||||
char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; |
||||
|
||||
try { |
||||
while ((numChars = source.read(buffer)) != -1) { |
||||
// Technically, some read(char[]) methods may return 0 and we cannot
|
||||
// accept that as an indication of EOF.
|
||||
if (numChars == 0) { |
||||
int singleChar = source.read(); |
||||
if (singleChar < 0) { |
||||
break; |
||||
} |
||||
dest.write(singleChar); |
||||
dest.flush(); |
||||
++total; |
||||
if (listener != null) { |
||||
listener.bytesTransferred(total, 1, streamSize); |
||||
} |
||||
continue; |
||||
} |
||||
|
||||
dest.write(buffer, 0, numChars); |
||||
dest.flush(); |
||||
total += numChars; |
||||
if (listener != null) { |
||||
listener.bytesTransferred(total, numChars, streamSize); |
||||
} |
||||
} |
||||
} catch (IOException e) { |
||||
throw new CopyStreamException("IOException caught while copying.", total, e); |
||||
} |
||||
|
||||
return total; |
||||
} |
||||
|
||||
/*** |
||||
* Copies the contents of a Reader to a Writer using a |
||||
* copy buffer of a given size. The contents of the Reader are |
||||
* read until its end is reached, but neither the source nor the |
||||
* destination are closed. You must do this yourself outside of the |
||||
* method call. The number of characters read/written is returned. |
||||
* |
||||
* @param source The source Reader. |
||||
* @param dest The destination writer. |
||||
* @param bufferSize The number of characters to buffer during the copy. |
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. |
||||
* @return The number of characters read/written in the copy operation. |
||||
* @throws CopyStreamException If an error occurs while reading from the |
||||
* source or writing to the destination. The CopyStreamException |
||||
* will contain the number of bytes confirmed to have been |
||||
* transferred before an |
||||
* IOException occurred, and it will also contain the IOException |
||||
* that caused the error. These values can be retrieved with |
||||
* the CopyStreamException getTotalBytesTransferred() and |
||||
* getIOException() methods. |
||||
***/ |
||||
public static final long copyReader(Reader source, Writer dest, int bufferSize) |
||||
throws CopyStreamException { |
||||
return copyReader(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); |
||||
} |
||||
|
||||
/*** |
||||
* Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code> |
||||
* @param source where to copy from |
||||
* @param dest where to copy to |
||||
* @return number of bytes copied |
||||
* @throws CopyStreamException on error |
||||
***/ |
||||
public static final long copyReader(Reader source, Writer dest) throws CopyStreamException { |
||||
return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); |
||||
} |
||||
|
||||
/** |
||||
* Closes the object quietly, catching rather than throwing IOException. |
||||
* Intended for use from finally blocks. |
||||
* |
||||
* @param closeable the object to close, may be {@code null} |
||||
* @since 3.0 |
||||
*/ |
||||
public static void closeQuietly(Closeable closeable) { |
||||
if (closeable != null) { |
||||
try { |
||||
closeable.close(); |
||||
} catch (IOException e) { |
||||
// Ignored
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Closes the socket quietly, catching rather than throwing IOException. |
||||
* Intended for use from finally blocks. |
||||
* |
||||
* @param socket the socket to close, may be {@code null} |
||||
* @since 3.0 |
||||
*/ |
||||
public static void closeQuietly(Socket socket) { |
||||
if (socket != null) { |
||||
try { |
||||
socket.close(); |
||||
} catch (IOException e) { |
||||
// Ignored
|
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,21 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
/** |
||||
* Utility classes for IO support. |
||||
*/ |
||||
package aria.apache.commons.net.io; |
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.nio.charset.Charset; |
||||
|
||||
/** |
||||
* Helps dealing with Charsets. |
||||
* |
||||
* @since 3.3 |
||||
*/ |
||||
public class Charsets { |
||||
|
||||
/** |
||||
* Returns a charset object for the given charset name. |
||||
* |
||||
* @param charsetName The name of the requested charset; may be a canonical name, an alias, or |
||||
* null. If null, return the |
||||
* default charset. |
||||
* @return A charset object for the named charset |
||||
*/ |
||||
public static Charset toCharset(String charsetName) { |
||||
return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName); |
||||
} |
||||
|
||||
/** |
||||
* Returns a charset object for the given charset name. |
||||
* |
||||
* @param charsetName The name of the requested charset; may be a canonical name, an alias, or |
||||
* null. |
||||
* If null, return the default charset. |
||||
* @param defaultCharsetName the charset name to use if the requested charset is null |
||||
* @return A charset object for the named charset |
||||
*/ |
||||
public static Charset toCharset(String charsetName, String defaultCharsetName) { |
||||
return charsetName == null ? Charset.forName(defaultCharsetName) : Charset.forName(charsetName); |
||||
} |
||||
} |
@ -1,236 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import aria.apache.commons.net.io.Util; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.IOException; |
||||
import java.net.Socket; |
||||
import java.security.GeneralSecurityException; |
||||
import java.security.KeyStore; |
||||
import java.security.KeyStoreException; |
||||
import java.security.Principal; |
||||
import java.security.PrivateKey; |
||||
import java.security.cert.Certificate; |
||||
import java.security.cert.X509Certificate; |
||||
import java.util.Enumeration; |
||||
|
||||
import javax.net.ssl.KeyManager; |
||||
import javax.net.ssl.X509ExtendedKeyManager; |
||||
|
||||
/** |
||||
* General KeyManager utilities |
||||
* <p> |
||||
* How to use with a client certificate: |
||||
* <pre> |
||||
* KeyManager km = KeyManagerUtils.createClientKeyManager("JKS", |
||||
* "/path/to/privatekeystore.jks","storepassword", |
||||
* "privatekeyalias", "keypassword"); |
||||
* FTPSClient cl = new FTPSClient(); |
||||
* cl.setKeyManager(km); |
||||
* cl.connect(...); |
||||
* </pre> |
||||
* If using the default store type and the key password is the same as the |
||||
* store password, these parameters can be omitted. <br> |
||||
* If the desired key is the first or only key in the keystore, the keyAlias parameter |
||||
* can be omitted, in which case the code becomes: |
||||
* <pre> |
||||
* KeyManager km = KeyManagerUtils.createClientKeyManager( |
||||
* "/path/to/privatekeystore.jks","storepassword"); |
||||
* FTPSClient cl = new FTPSClient(); |
||||
* cl.setKeyManager(km); |
||||
* cl.connect(...); |
||||
* </pre> |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public final class KeyManagerUtils { |
||||
|
||||
private static final String DEFAULT_STORE_TYPE = KeyStore.getDefaultType(); |
||||
|
||||
private KeyManagerUtils() { |
||||
// Not instantiable
|
||||
} |
||||
|
||||
/** |
||||
* Create a client key manager which returns a particular key. |
||||
* Does not handle server keys. |
||||
* |
||||
* @param ks the keystore to use |
||||
* @param keyAlias the alias of the key to use, may be {@code null} in which case the first key |
||||
* entry alias is used |
||||
* @param keyPass the password of the key to use |
||||
* @return the customised KeyManager |
||||
* @throws GeneralSecurityException if there is a problem creating the keystore |
||||
*/ |
||||
public static KeyManager createClientKeyManager(KeyStore ks, String keyAlias, String keyPass) |
||||
throws GeneralSecurityException { |
||||
ClientKeyStore cks = |
||||
new ClientKeyStore(ks, keyAlias != null ? keyAlias : findAlias(ks), keyPass); |
||||
return new X509KeyManager(cks); |
||||
} |
||||
|
||||
/** |
||||
* Create a client key manager which returns a particular key. |
||||
* Does not handle server keys. |
||||
* |
||||
* @param storeType the type of the keyStore, e.g. "JKS" |
||||
* @param storePath the path to the keyStore |
||||
* @param storePass the keyStore password |
||||
* @param keyAlias the alias of the key to use, may be {@code null} in which case the first key |
||||
* entry alias is used |
||||
* @param keyPass the password of the key to use |
||||
* @return the customised KeyManager |
||||
* @throws GeneralSecurityException if there is a problem creating the keystore |
||||
* @throws IOException if there is a problem creating the keystore |
||||
*/ |
||||
public static KeyManager createClientKeyManager(String storeType, File storePath, |
||||
String storePass, String keyAlias, String keyPass) |
||||
throws IOException, GeneralSecurityException { |
||||
KeyStore ks = loadStore(storeType, storePath, storePass); |
||||
return createClientKeyManager(ks, keyAlias, keyPass); |
||||
} |
||||
|
||||
/** |
||||
* Create a client key manager which returns a particular key. |
||||
* Does not handle server keys. |
||||
* Uses the default store type and assumes the key password is the same as the store password |
||||
* |
||||
* @param storePath the path to the keyStore |
||||
* @param storePass the keyStore password |
||||
* @param keyAlias the alias of the key to use, may be {@code null} in which case the first key |
||||
* entry alias is used |
||||
* @return the customised KeyManager |
||||
* @throws IOException if there is a problem creating the keystore |
||||
* @throws GeneralSecurityException if there is a problem creating the keystore |
||||
*/ |
||||
public static KeyManager createClientKeyManager(File storePath, String storePass, String keyAlias) |
||||
throws IOException, GeneralSecurityException { |
||||
return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, keyAlias, storePass); |
||||
} |
||||
|
||||
/** |
||||
* Create a client key manager which returns a particular key. |
||||
* Does not handle server keys. |
||||
* Uses the default store type and assumes the key password is the same as the store password. |
||||
* The key alias is found by searching the keystore for the first private key entry |
||||
* |
||||
* @param storePath the path to the keyStore |
||||
* @param storePass the keyStore password |
||||
* @return the customised KeyManager |
||||
* @throws IOException if there is a problem creating the keystore |
||||
* @throws GeneralSecurityException if there is a problem creating the keystore |
||||
*/ |
||||
public static KeyManager createClientKeyManager(File storePath, String storePass) |
||||
throws IOException, GeneralSecurityException { |
||||
return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, null, storePass); |
||||
} |
||||
|
||||
private static KeyStore loadStore(String storeType, File storePath, String storePass) |
||||
throws KeyStoreException, IOException, GeneralSecurityException { |
||||
KeyStore ks = KeyStore.getInstance(storeType); |
||||
FileInputStream stream = null; |
||||
try { |
||||
stream = new FileInputStream(storePath); |
||||
ks.load(stream, storePass.toCharArray()); |
||||
} finally { |
||||
Util.closeQuietly(stream); |
||||
} |
||||
return ks; |
||||
} |
||||
|
||||
private static String findAlias(KeyStore ks) throws KeyStoreException { |
||||
Enumeration<String> e = ks.aliases(); |
||||
while (e.hasMoreElements()) { |
||||
String entry = e.nextElement(); |
||||
if (ks.isKeyEntry(entry)) { |
||||
return entry; |
||||
} |
||||
} |
||||
throw new KeyStoreException("Cannot find a private key entry"); |
||||
} |
||||
|
||||
private static class ClientKeyStore { |
||||
|
||||
private final X509Certificate[] certChain; |
||||
private final PrivateKey key; |
||||
private final String keyAlias; |
||||
|
||||
ClientKeyStore(KeyStore ks, String keyAlias, String keyPass) throws GeneralSecurityException { |
||||
this.keyAlias = keyAlias; |
||||
this.key = (PrivateKey) ks.getKey(this.keyAlias, keyPass.toCharArray()); |
||||
Certificate[] certs = ks.getCertificateChain(this.keyAlias); |
||||
X509Certificate[] X509certs = new X509Certificate[certs.length]; |
||||
for (int i = 0; i < certs.length; i++) { |
||||
X509certs[i] = (X509Certificate) certs[i]; |
||||
} |
||||
this.certChain = X509certs; |
||||
} |
||||
|
||||
final X509Certificate[] getCertificateChain() { |
||||
return this.certChain; |
||||
} |
||||
|
||||
final PrivateKey getPrivateKey() { |
||||
return this.key; |
||||
} |
||||
|
||||
final String getAlias() { |
||||
return this.keyAlias; |
||||
} |
||||
} |
||||
|
||||
private static class X509KeyManager extends X509ExtendedKeyManager { |
||||
|
||||
private final ClientKeyStore keyStore; |
||||
|
||||
X509KeyManager(final ClientKeyStore keyStore) { |
||||
this.keyStore = keyStore; |
||||
} |
||||
|
||||
// Call sequence: 1
|
||||
@Override public String chooseClientAlias(String[] keyType, Principal[] issuers, |
||||
Socket socket) { |
||||
return keyStore.getAlias(); |
||||
} |
||||
|
||||
// Call sequence: 2
|
||||
@Override public X509Certificate[] getCertificateChain(String alias) { |
||||
return keyStore.getCertificateChain(); |
||||
} |
||||
|
||||
@Override public String[] getClientAliases(String keyType, Principal[] issuers) { |
||||
return new String[] { keyStore.getAlias() }; |
||||
} |
||||
|
||||
// Call sequence: 3
|
||||
@Override public PrivateKey getPrivateKey(String alias) { |
||||
return keyStore.getPrivateKey(); |
||||
} |
||||
|
||||
@Override public String[] getServerAliases(String keyType, Principal[] issuers) { |
||||
return null; |
||||
} |
||||
|
||||
@Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -1,59 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.EventListener; |
||||
import java.util.Iterator; |
||||
import java.util.concurrent.CopyOnWriteArrayList; |
||||
|
||||
/** |
||||
*/ |
||||
|
||||
public class ListenerList implements Serializable, Iterable<EventListener> { |
||||
private static final long serialVersionUID = -1934227607974228213L; |
||||
|
||||
private final CopyOnWriteArrayList<EventListener> __listeners; |
||||
|
||||
public ListenerList() { |
||||
__listeners = new CopyOnWriteArrayList<EventListener>(); |
||||
} |
||||
|
||||
public void addListener(EventListener listener) { |
||||
__listeners.add(listener); |
||||
} |
||||
|
||||
public void removeListener(EventListener listener) { |
||||
__listeners.remove(listener); |
||||
} |
||||
|
||||
public int getListenerCount() { |
||||
return __listeners.size(); |
||||
} |
||||
|
||||
/** |
||||
* Return an {@link Iterator} for the {@link EventListener} instances. |
||||
* |
||||
* @return an {@link Iterator} for the {@link EventListener} instances |
||||
* @since 2.0 |
||||
* TODO Check that this is a good defensive strategy |
||||
*/ |
||||
@Override public Iterator<EventListener> iterator() { |
||||
return __listeners.iterator(); |
||||
} |
||||
} |
@ -1,77 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.io.IOException; |
||||
import java.security.GeneralSecurityException; |
||||
import javax.net.ssl.KeyManager; |
||||
import javax.net.ssl.SSLContext; |
||||
import javax.net.ssl.TrustManager; |
||||
|
||||
/** |
||||
* General utilities for SSLContext. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public class SSLContextUtils { |
||||
|
||||
private SSLContextUtils() { |
||||
// Not instantiable
|
||||
} |
||||
|
||||
/** |
||||
* Create and initialise an SSLContext. |
||||
* |
||||
* @param protocol the protocol used to instatiate the context |
||||
* @param keyManager the key manager, may be {@code null} |
||||
* @param trustManager the trust manager, may be {@code null} |
||||
* @return the initialised context. |
||||
* @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs |
||||
*/ |
||||
public static SSLContext createSSLContext(String protocol, KeyManager keyManager, |
||||
TrustManager trustManager) throws IOException { |
||||
return createSSLContext(protocol, keyManager == null ? null : new KeyManager[] { keyManager }, |
||||
trustManager == null ? null : new TrustManager[] { trustManager }); |
||||
} |
||||
|
||||
/** |
||||
* Create and initialise an SSLContext. |
||||
* |
||||
* @param protocol the protocol used to instatiate the context |
||||
* @param keyManagers the array of key managers, may be {@code null} but array entries must not be |
||||
* {@code null} |
||||
* @param trustManagers the array of trust managers, may be {@code null} but array entries must |
||||
* not be {@code null} |
||||
* @return the initialised context. |
||||
* @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs |
||||
*/ |
||||
public static SSLContext createSSLContext(String protocol, KeyManager[] keyManagers, |
||||
TrustManager[] trustManagers) throws IOException { |
||||
SSLContext ctx; |
||||
try { |
||||
ctx = SSLContext.getInstance(protocol); |
||||
ctx.init(keyManagers, trustManagers, /*SecureRandom*/ null); |
||||
} catch (GeneralSecurityException e) { |
||||
IOException ioe = new IOException("Could not initialize SSL context"); |
||||
ioe.initCause(e); |
||||
throw ioe; |
||||
} |
||||
return ctx; |
||||
} |
||||
} |
@ -1,68 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.lang.reflect.InvocationTargetException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
import javax.net.ssl.SSLSocket; |
||||
|
||||
/** |
||||
* General utilities for SSLSocket. |
||||
* |
||||
* @since 3.4 |
||||
*/ |
||||
public class SSLSocketUtils { |
||||
private SSLSocketUtils() { |
||||
// Not instantiable
|
||||
} |
||||
|
||||
/** |
||||
* Enable the HTTPS endpoint identification algorithm on an SSLSocket. |
||||
* |
||||
* @param socket the SSL socket |
||||
* @return {@code true} on success (this is only supported on Java 1.7+) |
||||
*/ |
||||
public static boolean enableEndpointNameVerification(SSLSocket socket) { |
||||
try { |
||||
Class<?> cls = Class.forName("javax.net.ssl.SSLParameters"); |
||||
Method setEndpointIdentificationAlgorithm = |
||||
cls.getDeclaredMethod("setEndpointIdentificationAlgorithm", String.class); |
||||
Method getSSLParameters = SSLSocket.class.getDeclaredMethod("getSSLParameters"); |
||||
Method setSSLParameters = SSLSocket.class.getDeclaredMethod("setSSLParameters", cls); |
||||
if (setEndpointIdentificationAlgorithm != null |
||||
&& getSSLParameters != null |
||||
&& setSSLParameters != null) { |
||||
Object sslParams = getSSLParameters.invoke(socket); |
||||
if (sslParams != null) { |
||||
setEndpointIdentificationAlgorithm.invoke(sslParams, "HTTPS"); |
||||
setSSLParameters.invoke(socket, sslParams); |
||||
return true; |
||||
} |
||||
} |
||||
} catch (SecurityException e) { // Ignored
|
||||
} catch (ClassNotFoundException e) { // Ignored
|
||||
} catch (NoSuchMethodException e) { // Ignored
|
||||
} catch (IllegalArgumentException e) { // Ignored
|
||||
} catch (IllegalAccessException e) { // Ignored
|
||||
} catch (InvocationTargetException e) { // Ignored
|
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -1,395 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* A class that performs some subnet calculations given a network address and a subnet mask. |
||||
* |
||||
* @see "http://www.faqs.org/rfcs/rfc1519.html" |
||||
* @since 2.0 |
||||
*/ |
||||
public class SubnetUtils { |
||||
|
||||
private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; |
||||
private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,3})"; |
||||
private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); |
||||
private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); |
||||
private static final int NBITS = 32; |
||||
|
||||
private int netmask = 0; |
||||
private int address = 0; |
||||
private int network = 0; |
||||
private int broadcast = 0; |
||||
|
||||
/** Whether the broadcast/network address are included in host count */ |
||||
private boolean inclusiveHostCount = false; |
||||
|
||||
/** |
||||
* Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" |
||||
* |
||||
* @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" |
||||
* @throws IllegalArgumentException if the parameter is invalid, |
||||
* i.e. does not match n.n.n.n/m where n=1-3 decimal digits, m = 1-3 decimal digits in range 1-32 |
||||
*/ |
||||
public SubnetUtils(String cidrNotation) { |
||||
calculate(cidrNotation); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that takes a dotted decimal address and a dotted decimal mask. |
||||
* |
||||
* @param address An IP address, e.g. "192.168.0.1" |
||||
* @param mask A dotted decimal netmask e.g. "255.255.0.0" |
||||
* @throws IllegalArgumentException if the address or mask is invalid, |
||||
* i.e. does not match n.n.n.n where n=1-3 decimal digits and the mask is not all zeros |
||||
*/ |
||||
public SubnetUtils(String address, String mask) { |
||||
calculate(toCidrNotation(address, mask)); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> if the return value of {@link SubnetInfo#getAddressCount()} |
||||
* includes the network and broadcast addresses. |
||||
* |
||||
* @return true if the hostcount includes the network and broadcast addresses |
||||
* @since 2.2 |
||||
*/ |
||||
public boolean isInclusiveHostCount() { |
||||
return inclusiveHostCount; |
||||
} |
||||
|
||||
/** |
||||
* Set to <code>true</code> if you want the return value of {@link SubnetInfo#getAddressCount()} |
||||
* to include the network and broadcast addresses. |
||||
* |
||||
* @param inclusiveHostCount true if network and broadcast addresses are to be included |
||||
* @since 2.2 |
||||
*/ |
||||
public void setInclusiveHostCount(boolean inclusiveHostCount) { |
||||
this.inclusiveHostCount = inclusiveHostCount; |
||||
} |
||||
|
||||
/** |
||||
* Convenience container for subnet summary information. |
||||
*/ |
||||
public final class SubnetInfo { |
||||
/* Mask to convert unsigned int to a long (i.e. keep 32 bits) */ |
||||
private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; |
||||
|
||||
private SubnetInfo() { |
||||
} |
||||
|
||||
private int netmask() { |
||||
return netmask; |
||||
} |
||||
|
||||
private int network() { |
||||
return network; |
||||
} |
||||
|
||||
private int address() { |
||||
return address; |
||||
} |
||||
|
||||
private int broadcast() { |
||||
return broadcast; |
||||
} |
||||
|
||||
// long versions of the values (as unsigned int) which are more suitable for range checking
|
||||
private long networkLong() { |
||||
return network & UNSIGNED_INT_MASK; |
||||
} |
||||
|
||||
private long broadcastLong() { |
||||
return broadcast & UNSIGNED_INT_MASK; |
||||
} |
||||
|
||||
private int low() { |
||||
return (isInclusiveHostCount() ? network() |
||||
: broadcastLong() - networkLong() > 1 ? network() + 1 : 0); |
||||
} |
||||
|
||||
private int high() { |
||||
return (isInclusiveHostCount() ? broadcast() |
||||
: broadcastLong() - networkLong() > 1 ? broadcast() - 1 : 0); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the parameter <code>address</code> is in the |
||||
* range of usable endpoint addresses for this subnet. This excludes the |
||||
* network and broadcast adresses. |
||||
* |
||||
* @param address A dot-delimited IPv4 address, e.g. "192.168.0.1" |
||||
* @return True if in range, false otherwise |
||||
*/ |
||||
public boolean isInRange(String address) { |
||||
return isInRange(toInteger(address)); |
||||
} |
||||
|
||||
/** |
||||
* @param address the address to check |
||||
* @return true if it is in range |
||||
* @since 3.4 (made public) |
||||
*/ |
||||
public boolean isInRange(int address) { |
||||
long addLong = address & UNSIGNED_INT_MASK; |
||||
long lowLong = low() & UNSIGNED_INT_MASK; |
||||
long highLong = high() & UNSIGNED_INT_MASK; |
||||
return addLong >= lowLong && addLong <= highLong; |
||||
} |
||||
|
||||
public String getBroadcastAddress() { |
||||
return format(toArray(broadcast())); |
||||
} |
||||
|
||||
public String getNetworkAddress() { |
||||
return format(toArray(network())); |
||||
} |
||||
|
||||
public String getNetmask() { |
||||
return format(toArray(netmask())); |
||||
} |
||||
|
||||
public String getAddress() { |
||||
return format(toArray(address())); |
||||
} |
||||
|
||||
/** |
||||
* Return the low address as a dotted IP address. |
||||
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. |
||||
* |
||||
* @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address |
||||
*/ |
||||
public String getLowAddress() { |
||||
return format(toArray(low())); |
||||
} |
||||
|
||||
/** |
||||
* Return the high address as a dotted IP address. |
||||
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. |
||||
* |
||||
* @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address |
||||
*/ |
||||
public String getHighAddress() { |
||||
return format(toArray(high())); |
||||
} |
||||
|
||||
/** |
||||
* Get the count of available addresses. |
||||
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. |
||||
* |
||||
* @return the count of addresses, may be zero. |
||||
* @throws RuntimeException if the correct count is greater than {@code Integer.MAX_VALUE} |
||||
* @deprecated (3.4) use {@link #getAddressCountLong()} instead |
||||
*/ |
||||
@Deprecated public int getAddressCount() { |
||||
long countLong = getAddressCountLong(); |
||||
if (countLong > Integer.MAX_VALUE) { |
||||
throw new RuntimeException("Count is larger than an integer: " + countLong); |
||||
} |
||||
// N.B. cannot be negative
|
||||
return (int) countLong; |
||||
} |
||||
|
||||
/** |
||||
* Get the count of available addresses. |
||||
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. |
||||
* |
||||
* @return the count of addresses, may be zero. |
||||
* @since 3.4 |
||||
*/ |
||||
public long getAddressCountLong() { |
||||
long b = broadcastLong(); |
||||
long n = networkLong(); |
||||
long count = b - n + (isInclusiveHostCount() ? 1 : -1); |
||||
return count < 0 ? 0 : count; |
||||
} |
||||
|
||||
public int asInteger(String address) { |
||||
return toInteger(address); |
||||
} |
||||
|
||||
public String getCidrSignature() { |
||||
return toCidrNotation(format(toArray(address())), format(toArray(netmask()))); |
||||
} |
||||
|
||||
public String[] getAllAddresses() { |
||||
int ct = getAddressCount(); |
||||
String[] addresses = new String[ct]; |
||||
if (ct == 0) { |
||||
return addresses; |
||||
} |
||||
for (int add = low(), j = 0; add <= high(); ++add, ++j) { |
||||
addresses[j] = format(toArray(add)); |
||||
} |
||||
return addresses; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* @since 2.2 |
||||
*/ |
||||
@Override public String toString() { |
||||
final StringBuilder buf = new StringBuilder(); |
||||
buf.append("CIDR Signature:\t[") |
||||
.append(getCidrSignature()) |
||||
.append("]") |
||||
.append(" Netmask: [") |
||||
.append(getNetmask()) |
||||
.append("]\n") |
||||
.append("Network:\t[") |
||||
.append(getNetworkAddress()) |
||||
.append("]\n") |
||||
.append("Broadcast:\t[") |
||||
.append(getBroadcastAddress()) |
||||
.append("]\n") |
||||
.append("First Address:\t[") |
||||
.append(getLowAddress()) |
||||
.append("]\n") |
||||
.append("Last Address:\t[") |
||||
.append(getHighAddress()) |
||||
.append("]\n") |
||||
.append("# Addresses:\t[") |
||||
.append(getAddressCount()) |
||||
.append("]\n"); |
||||
return buf.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link SubnetInfo} instance that contains subnet-specific statistics |
||||
* |
||||
* @return new instance |
||||
*/ |
||||
public final SubnetInfo getInfo() { |
||||
return new SubnetInfo(); |
||||
} |
||||
|
||||
/* |
||||
* Initialize the internal fields from the supplied CIDR mask |
||||
*/ |
||||
private void calculate(String mask) { |
||||
Matcher matcher = cidrPattern.matcher(mask); |
||||
|
||||
if (matcher.matches()) { |
||||
address = matchAddress(matcher); |
||||
|
||||
/* Create a binary netmask from the number of bits specification /x */ |
||||
int cidrPart = rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS); |
||||
for (int j = 0; j < cidrPart; ++j) { |
||||
netmask |= (1 << 31 - j); |
||||
} |
||||
|
||||
/* Calculate base network address */ |
||||
network = (address & netmask); |
||||
|
||||
/* Calculate broadcast address */ |
||||
broadcast = network | ~(netmask); |
||||
} else { |
||||
throw new IllegalArgumentException("Could not parse [" + mask + "]"); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Convert a dotted decimal format address to a packed integer format |
||||
*/ |
||||
private int toInteger(String address) { |
||||
Matcher matcher = addressPattern.matcher(address); |
||||
if (matcher.matches()) { |
||||
return matchAddress(matcher); |
||||
} else { |
||||
throw new IllegalArgumentException("Could not parse [" + address + "]"); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Convenience method to extract the components of a dotted decimal address and |
||||
* pack into an integer using a regex match |
||||
*/ |
||||
private int matchAddress(Matcher matcher) { |
||||
int addr = 0; |
||||
for (int i = 1; i <= 4; ++i) { |
||||
int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); |
||||
addr |= ((n & 0xff) << 8 * (4 - i)); |
||||
} |
||||
return addr; |
||||
} |
||||
|
||||
/* |
||||
* Convert a packed integer address into a 4-element array |
||||
*/ |
||||
private int[] toArray(int val) { |
||||
int ret[] = new int[4]; |
||||
for (int j = 3; j >= 0; --j) { |
||||
ret[j] |= ((val >>> 8 * (3 - j)) & (0xff)); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
/* |
||||
* Convert a 4-element array into dotted decimal format |
||||
*/ |
||||
private String format(int[] octets) { |
||||
StringBuilder str = new StringBuilder(); |
||||
for (int i = 0; i < octets.length; ++i) { |
||||
str.append(octets[i]); |
||||
if (i != octets.length - 1) { |
||||
str.append("."); |
||||
} |
||||
} |
||||
return str.toString(); |
||||
} |
||||
|
||||
/* |
||||
* Convenience function to check integer boundaries. |
||||
* Checks if a value x is in the range [begin,end]. |
||||
* Returns x if it is in range, throws an exception otherwise. |
||||
*/ |
||||
private int rangeCheck(int value, int begin, int end) { |
||||
if (value >= begin && value <= end) { // (begin,end]
|
||||
return value; |
||||
} |
||||
|
||||
throw new IllegalArgumentException( |
||||
"Value [" + value + "] not in range [" + begin + "," + end + "]"); |
||||
} |
||||
|
||||
/* |
||||
* Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy |
||||
* see Hacker's Delight section 5.1 |
||||
*/ |
||||
int pop(int x) { |
||||
x = x - ((x >>> 1) & 0x55555555); |
||||
x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); |
||||
x = (x + (x >>> 4)) & 0x0F0F0F0F; |
||||
x = x + (x >>> 8); |
||||
x = x + (x >>> 16); |
||||
return x & 0x0000003F; |
||||
} |
||||
|
||||
/* Convert two dotted decimal addresses to a single xxx.xxx.xxx.xxx/yy format |
||||
* by counting the 1-bit population in the mask address. (It may be better to count |
||||
* NBITS-#trailing zeroes for this case) |
||||
*/ |
||||
private String toCidrNotation(String addr, String mask) { |
||||
return addr + "/" + pop(toInteger(mask)); |
||||
} |
||||
} |
@ -1,113 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package aria.apache.commons.net.util; |
||||
|
||||
import java.security.GeneralSecurityException; |
||||
import java.security.KeyStore; |
||||
import java.security.SecureRandom; |
||||
import java.security.cert.CertificateException; |
||||
import java.security.cert.X509Certificate; |
||||
|
||||
import javax.net.ssl.KeyManager; |
||||
import javax.net.ssl.TrustManager; |
||||
import javax.net.ssl.TrustManagerFactory; |
||||
import javax.net.ssl.X509TrustManager; |
||||
|
||||
/** |
||||
* TrustManager utilities for generating TrustManagers. |
||||
* |
||||
* @since 3.0 |
||||
*/ |
||||
public final class TrustManagerUtils { |
||||
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {}; |
||||
|
||||
private static class TrustManager implements X509TrustManager { |
||||
|
||||
private final boolean checkServerValidity; |
||||
|
||||
TrustManager(boolean checkServerValidity) { |
||||
this.checkServerValidity = checkServerValidity; |
||||
} |
||||
|
||||
/** |
||||
* Never generates a CertificateException. |
||||
*/ |
||||
@Override public void checkClientTrusted(X509Certificate[] certificates, String authType) { |
||||
return; |
||||
} |
||||
|
||||
@Override public void checkServerTrusted(X509Certificate[] certificates, String authType) |
||||
throws CertificateException { |
||||
if (checkServerValidity) { |
||||
for (X509Certificate certificate : certificates) { |
||||
certificate.checkValidity(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return an empty array of certificates |
||||
*/ |
||||
@Override public X509Certificate[] getAcceptedIssuers() { |
||||
return EMPTY_X509CERTIFICATE_ARRAY; |
||||
} |
||||
} |
||||
|
||||
private static final X509TrustManager ACCEPT_ALL = new TrustManager(false); |
||||
|
||||
private static final X509TrustManager CHECK_SERVER_VALIDITY = new TrustManager(true); |
||||
|
||||
/** |
||||
* Generate a TrustManager that performs no checks. |
||||
* |
||||
* @return the TrustManager |
||||
*/ |
||||
public static X509TrustManager getAcceptAllTrustManager() { |
||||
return ACCEPT_ALL; |
||||
} |
||||
|
||||
/** |
||||
* Generate a TrustManager that checks server certificates for validity, |
||||
* but otherwise performs no checks. |
||||
* |
||||
* @return the validating TrustManager |
||||
*/ |
||||
public static X509TrustManager getValidateServerCertificateTrustManager() { |
||||
return CHECK_SERVER_VALIDITY; |
||||
} |
||||
|
||||
/** |
||||
* Return the default TrustManager provided by the JVM. |
||||
* <p> |
||||
* This should be the same as the default used by |
||||
* {@link javax.net.ssl.SSLContext#init(KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)} |
||||
* SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} |
||||
* when the TrustManager parameter is set to {@code null} |
||||
* |
||||
* @param keyStore the KeyStore to use, may be {@code null} |
||||
* @return the default TrustManager |
||||
* @throws GeneralSecurityException if an error occurs |
||||
*/ |
||||
public static X509TrustManager getDefaultTrustManager(KeyStore keyStore) |
||||
throws GeneralSecurityException { |
||||
String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); |
||||
TrustManagerFactory instance = TrustManagerFactory.getInstance(defaultAlgorithm); |
||||
instance.init(keyStore); |
||||
return (X509TrustManager) instance.getTrustManagers()[0]; |
||||
} |
||||
} |
@ -1,21 +0,0 @@ |
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
/** |
||||
* Utility classes |
||||
*/ |
||||
package aria.apache.commons.net.util; |
@ -1,52 +0,0 @@ |
||||
package com.arialyy.aria.ftp; |
||||
|
||||
import aria.apache.commons.net.ftp.FTPSClient; |
||||
import java.io.IOException; |
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
import java.net.Socket; |
||||
import java.util.Locale; |
||||
import javax.net.ssl.SSLContext; |
||||
import javax.net.ssl.SSLSession; |
||||
import javax.net.ssl.SSLSessionContext; |
||||
import javax.net.ssl.SSLSocket; |
||||
|
||||
public class SSLSessionReuseFTPSClient extends FTPSClient { |
||||
|
||||
SSLSessionReuseFTPSClient(boolean b, SSLContext context) { |
||||
super(b, context); |
||||
} |
||||
|
||||
// adapted from:
|
||||
// https://trac.cyberduck.io/browser/trunk/ftp/src/main/java/ch/cyberduck/core/ftp/FTPClient.java
|
||||
@Override |
||||
protected void _prepareDataSocket_(final Socket socket) throws IOException { |
||||
if (socket instanceof SSLSocket) { |
||||
// Control socket is SSL
|
||||
final SSLSession session = ((SSLSocket) _socket_).getSession(); |
||||
if (session.isValid()) { |
||||
final SSLSessionContext context = session.getSessionContext(); |
||||
try { |
||||
//final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
|
||||
final Field sessionHostPortCache = |
||||
context.getClass().getDeclaredField("sessionsByHostAndPort"); |
||||
sessionHostPortCache.setAccessible(true); |
||||
final Object cache = sessionHostPortCache.get(context); |
||||
final Method method = |
||||
cache.getClass().getDeclaredMethod("put", Object.class, Object.class); |
||||
method.setAccessible(true); |
||||
method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostName(), |
||||
String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session); |
||||
method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostAddress(), |
||||
String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session); |
||||
} catch (NoSuchFieldException e) { |
||||
throw new IOException(e); |
||||
} catch (Exception e) { |
||||
throw new IOException(e); |
||||
} |
||||
} else { |
||||
throw new IOException("Invalid SSL Session"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,82 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.ftp.download; |
||||
|
||||
import android.os.Looper; |
||||
import com.arialyy.aria.core.common.AbsEntity; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.group.AbsGroupLoader; |
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil; |
||||
import com.arialyy.aria.core.inf.IEntity; |
||||
import com.arialyy.aria.core.listener.IEventListener; |
||||
import com.arialyy.aria.core.loader.IInfoTask; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.util.ALog; |
||||
|
||||
/** |
||||
* ftp 组合任务加载器 |
||||
*/ |
||||
final class FtpDGLoader extends AbsGroupLoader { |
||||
FtpDGLoader(AbsTaskWrapper groupWrapper, IEventListener listener) { |
||||
super(groupWrapper, listener); |
||||
} |
||||
|
||||
@Override protected void handlerTask(Looper looper) { |
||||
if (isBreak()) { |
||||
return; |
||||
} |
||||
mInfoTask.run(); |
||||
} |
||||
|
||||
@Override |
||||
protected AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo) { |
||||
return new FtpSubDLoaderUtil(wrapper, getScheduler(), needGetFileInfo); |
||||
} |
||||
|
||||
/** |
||||
* 启动子任务下载 |
||||
*/ |
||||
private void startSub() { |
||||
// ftp需要获取完成只任务信息才更新只任务数量
|
||||
getState().setSubSize(getWrapper().getSubTaskWrapper().size()); |
||||
|
||||
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { |
||||
if (wrapper.getState() != IEntity.STATE_COMPLETE) { |
||||
startSubLoader(createSubLoader(wrapper, false)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override public void addComponent(IInfoTask infoTask) { |
||||
mInfoTask = infoTask; |
||||
infoTask.setCallback(new IInfoTask.Callback() { |
||||
@Override public void onSucceed(String key, CompleteInfo info) { |
||||
if (info.code >= 200 && info.code < 300) { |
||||
startSub(); |
||||
} else { |
||||
ALog.e(TAG, "获取任务信息失败,code:" + info.code); |
||||
mListener.onFail(false, null); |
||||
} |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
mListener.onFail(needRetry, e); |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.ftp.download; |
||||
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper; |
||||
import com.arialyy.aria.core.group.AbsGroupLoader; |
||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil; |
||||
import com.arialyy.aria.core.listener.IEventListener; |
||||
import com.arialyy.aria.core.loader.LoaderStructure; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.ftp.FtpTaskOption; |
||||
|
||||
/** |
||||
* Created by Aria.Lao on 2017/7/27. |
||||
* ftp文件夹下载工具 |
||||
*/ |
||||
public final class FtpDGLoaderUtil extends AbsGroupLoaderUtil { |
||||
|
||||
public FtpDGLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { |
||||
super(wrapper, listener); |
||||
wrapper.generateTaskOption(FtpTaskOption.class); |
||||
} |
||||
|
||||
@Override protected AbsGroupLoader getLoader() { |
||||
return mLoader == null ? new FtpDGLoader(getTaskWrapper(), getListener()) : mLoader; |
||||
} |
||||
|
||||
@Override protected LoaderStructure buildLoaderStructure() { |
||||
LoaderStructure structure = new LoaderStructure(); |
||||
structure.addComponent(new FtpDGInfoTask((DGTaskWrapper) getTaskWrapper())); |
||||
structure.accept(getLoader()); |
||||
return structure; |
||||
} |
||||
} |
@ -1,124 +0,0 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.ftp.download; |
||||
|
||||
import android.net.Uri; |
||||
import android.text.TextUtils; |
||||
import com.arialyy.aria.core.FtpUrlEntity; |
||||
import com.arialyy.aria.core.common.AbsEntity; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil; |
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil; |
||||
import com.arialyy.aria.core.inf.IEntity; |
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback; |
||||
import com.arialyy.aria.core.listener.IEventListener; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.ftp.FtpDirInfoThread; |
||||
import com.arialyy.aria.ftp.FtpTaskOption; |
||||
import java.util.concurrent.locks.Condition; |
||||
import java.util.concurrent.locks.ReentrantLock; |
||||
|
||||
/** |
||||
* Created by Aria.Lao on 2017/7/27. |
||||
* ftp文件夹下载工具 |
||||
*/ |
||||
public class FtpDirDLoaderUtil extends AbsGroupLoaderUtil { |
||||
private ReentrantLock LOCK = new ReentrantLock(); |
||||
private Condition condition = LOCK.newCondition(); |
||||
|
||||
public FtpDirDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { |
||||
super(wrapper, listener); |
||||
wrapper.generateTaskOption(FtpTaskOption.class); |
||||
} |
||||
|
||||
@Override |
||||
protected AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo) { |
||||
return new FtpSubDLoaderUtil(getScheduler(), wrapper, needGetFileInfo); |
||||
} |
||||
|
||||
@Override protected boolean onStart() { |
||||
super.onStart(); |
||||
|
||||
if (getWrapper().getEntity().getFileSize() > 1) { |
||||
startDownload(true); |
||||
} else { |
||||
FtpDirInfoThread infoThread = new FtpDirInfoThread(getWrapper(), new OnFileInfoCallback() { |
||||
@Override public void onComplete(String url, CompleteInfo info) { |
||||
if (info.code >= 200 && info.code < 300) { |
||||
startDownload(false); |
||||
} |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
mListener.onFail(needRetry, e); |
||||
} |
||||
}); |
||||
new Thread(infoThread).start(); |
||||
try { |
||||
LOCK.lock(); |
||||
condition.await(); |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} finally { |
||||
LOCK.unlock(); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @param needCloneInfo 第一次下载,信息已经在{@link FtpDirInfoThread}中clone了 |
||||
*/ |
||||
private void startDownload(boolean needCloneInfo) { |
||||
// ftp需要获取完成只任务信息才更新只任务数量
|
||||
getState().setSubSize(getWrapper().getSubTaskWrapper().size()); |
||||
try { |
||||
LOCK.lock(); |
||||
condition.signalAll(); |
||||
} finally { |
||||
LOCK.unlock(); |
||||
} |
||||
for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { |
||||
if (needCloneInfo) { |
||||
cloneInfo(wrapper); |
||||
} |
||||
if (wrapper.getState() != IEntity.STATE_COMPLETE) { |
||||
startSubLoader(createSubLoader(wrapper, true)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void cloneInfo(DTaskWrapper subWrapper) { |
||||
FtpTaskOption option = (FtpTaskOption) getWrapper().getTaskOption(); |
||||
FtpUrlEntity urlEntity = option.getUrlEntity().clone(); |
||||
Uri uri = Uri.parse(subWrapper.getEntity().getUrl()); |
||||
String remotePath = uri.getPath(); |
||||
urlEntity.remotePath = TextUtils.isEmpty(remotePath) ? "/" : remotePath; |
||||
|
||||
FtpTaskOption subOption = new FtpTaskOption(); |
||||
subOption.setUrlEntity(urlEntity); |
||||
subOption.setCharSet(option.getCharSet()); |
||||
subOption.setProxy(option.getProxy()); |
||||
subOption.setClientConfig(option.getClientConfig()); |
||||
subOption.setNewFileName(option.getNewFileName()); |
||||
subOption.setProxy(option.getProxy()); |
||||
subOption.setUploadInterceptor(option.getUploadInterceptor()); |
||||
|
||||
subWrapper.setTaskOption(subOption); |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
/* |
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.arialyy.aria.ftp.upload; |
||||
|
||||
import com.arialyy.aria.core.common.AbsEntity; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.listener.IEventListener; |
||||
import com.arialyy.aria.core.loader.IInfoTask; |
||||
import com.arialyy.aria.core.loader.NormalLoader; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
|
||||
final class FtpULoader extends NormalLoader { |
||||
FtpULoader(AbsTaskWrapper wrapper, IEventListener listener) { |
||||
super(wrapper, listener); |
||||
} |
||||
|
||||
@Override public void addComponent(IInfoTask infoTask) { |
||||
mInfoTask = infoTask; |
||||
infoTask.setCallback(new IInfoTask.Callback() { |
||||
@Override public void onSucceed(String key, CompleteInfo info) { |
||||
if (info.code == FtpUFileInfoTask.CODE_COMPLETE) { |
||||
getListener().onComplete(); |
||||
} else { |
||||
startThreadTask(); |
||||
} |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
getListener().onFail(needRetry, e); |
||||
} |
||||
}); |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue