修复FTP上传文件不完整的bug,尝试处理ftp 断点续传上传

pull/330/head
AriaLyy 7 years ago
parent 9d354fa935
commit afb47c8446
  1. 4
      Aria/build.gradle
  2. 196
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  3. 81
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  4. 23
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  5. 4
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  6. 155
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java
  7. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  8. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  9. 14
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  10. 13
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  11. 44
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  12. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  13. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  14. 3
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  15. 55
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  16. 129
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  17. 74
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/ProgressInputStream.java
  18. 13
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  19. 2
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  20. 1
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  21. 55
      AriaFtpPlug/src/main/java/org/apache/commons/net/DatagramSocketClient.java
  22. 6
      AriaFtpPlug/src/main/java/org/apache/commons/net/DatagramSocketFactory.java
  23. 17
      AriaFtpPlug/src/main/java/org/apache/commons/net/DefaultDatagramSocketFactory.java
  24. 66
      AriaFtpPlug/src/main/java/org/apache/commons/net/DefaultSocketFactory.java
  25. 10
      AriaFtpPlug/src/main/java/org/apache/commons/net/MalformedServerReplyException.java
  26. 48
      AriaFtpPlug/src/main/java/org/apache/commons/net/PrintCommandListener.java
  27. 27
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandEvent.java
  28. 5
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandListener.java
  29. 34
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandSupport.java
  30. 180
      AriaFtpPlug/src/main/java/org/apache/commons/net/SocketClient.java
  31. 1
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/Configurable.java
  32. 347
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTP.java
  33. 1084
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPClient.java
  34. 82
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java
  35. 47
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPCmd.java
  36. 33
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
  37. 11
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPConnectionClosedException.java
  38. 123
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFile.java
  39. 9
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileEntryParser.java
  40. 19
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java
  41. 1
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileFilter.java
  42. 11
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileFilters.java
  43. 34
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPHTTPClient.java
  44. 52
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java
  45. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPReply.java
  46. 228
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
  47. 6
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSCommand.java
  48. 14
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSServerSocketFactory.java
  49. 58
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSSocketFactory.java
  50. 23
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSTrustManager.java
  51. 33
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/OnFtpInputStreamListener.java
  52. 26
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java
  53. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java
  54. 129
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java
  55. 67
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java
  56. 19
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java
  57. 3
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParser.java
  58. 62
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
  59. 72
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MLSxEntryParser.java
  60. 49
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java
  61. 118
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java
  62. 79
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java
  63. 38
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java
  64. 57
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java
  65. 139
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java
  66. 4
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/ParserInitializationException.java
  67. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java
  68. 144
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java
  69. 113
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java
  70. 52
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java
  71. 18
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CRLFLineReader.java
  72. 39
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamAdapter.java
  73. 40
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamEvent.java
  74. 20
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamException.java
  75. 9
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamListener.java
  76. 63
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/DotTerminatedMessageReader.java
  77. 66
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/DotTerminatedMessageWriter.java
  78. 57
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/FromNetASCIIInputStream.java
  79. 59
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/FromNetASCIIOutputStream.java
  80. 10
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/SocketInputStream.java
  81. 16
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/SocketOutputStream.java
  82. 46
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/ToNetASCIIInputStream.java
  83. 33
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/ToNetASCIIOutputStream.java
  84. 99
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/Util.java
  85. 416
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/Base64.java
  86. 9
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/Charsets.java
  87. 59
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/KeyManagerUtils.java
  88. 19
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/ListenerList.java
  89. 20
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/SSLContextUtils.java
  90. 9
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/SSLSocketUtils.java
  91. 113
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/SubnetUtils.java
  92. 37
      AriaFtpPlug/src/main/java/org/apache/commons/net/util/TrustManagerUtils.java
  93. 2
      app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java
  94. 4
      app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java

@ -23,8 +23,8 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations') compile project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.0' // compile 'com.arialyy.aria:aria-ftp-plug:1.0.0'
// compile project(':AriaFtpPlug') compile project(':AriaFtpPlug')
} }
apply from: 'bintray-release.gradle' apply from: 'bintray-release.gradle'

@ -0,0 +1,196 @@
/*
* 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.core.common;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "HttpFileInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
protected OnFileInfoCallback mCallback;
protected long mSize = 0;
protected String mServerIp, mPort;
protected String charSet = "UTF-8";
private boolean isUpload = false;
public AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
if (mEntity instanceof UploadEntity) {
isUpload = true;
}
}
/**
* 设置请求的远程文件路径
*
* @return 远程文件路径
*/
protected abstract String setRemotePath();
@Override public void run() {
FTPClient client = null;
try {
client = createFtpClient();
if (client == null) return;
String remotePath =
new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
FTPFile[] files = client.listFiles(remotePath);
mSize = getFileSize(files, client, remotePath);
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
if (isUpload) {
//服务器上没有该文件路径,表示该任务为新的上传任务
mTaskEntity.isNewTask = true;
} else {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
}
mTaskEntity.code = reply;
mEntity.update();
mTaskEntity.update();
onPreComplete(reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void start() {
new Thread(this).start();
}
protected void onPreComplete(int code) {
}
/**
* 创建FTP客户端
*/
private FTPClient createFtpClient() throws IOException {
String url = "";
if (mEntity instanceof DownloadEntity) {
url = ((DownloadEntity) mEntity).getUrl();
} else if (mEntity instanceof UploadEntity) {
url = ((UploadEntity) mEntity).getUrl();
} else if (mEntity instanceof DownloadGroupEntity) {
url = mEntity.getKey();
} else {
failDownload("未知实体");
Log.e(TAG, "未知实体");
return null;
}
String[] pp = url.split("/")[2].split(":");
mServerIp = pp[0];
mPort = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(mServerIp, Integer.parseInt(mPort));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器,错误码为:" + reply);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5);
return client;
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException 字符串编码转换错误
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
size += getFileSize(client.listFiles(
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
protected void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

@ -0,0 +1,81 @@
/*
* 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.core.common;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by lyy on 2017/9/26.
* FTP单任务父类
*/
public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
extends AbsThreadTask<ENTITY, TASK_ENTITY> {
protected String charSet, serverIp, port;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
protected AbsFtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_ENTITY> info) {
super(constance, listener, info);
}
/**
* 构建FTP客户端
*/
protected FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
serverIp = pp[0];
port = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(serverIp, Integer.parseInt(port));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setBufferSize(mBufSize);
//client.setControlKeepAliveTimeout(5);
//client.setCopyStreamListener();
return client;
}
}

@ -19,7 +19,7 @@ import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
@ -37,7 +37,7 @@ import java.util.TimerTask;
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
* 任务线程 * 任务线程
*/ */
public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable { implements Runnable {
/** /**
* 线程重试次数 * 线程重试次数
@ -56,10 +56,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
protected SubThreadConfig<TASK_ENTITY> mConfig; protected SubThreadConfig<TASK_ENTITY> mConfig;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
private int mFailNum = 0; private int mFailNum = 0;
private String mTaskType; private String mTaskType;
private Timer mFailTimer; private Timer mFailTimer;
@ -74,9 +70,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mConfig = info; mConfig = info;
mTaskEntity = mConfig.TASK_ENTITY; mTaskEntity = mConfig.TASK_ENTITY;
mEntity = mTaskEntity.getEntity(); mEntity = mTaskEntity.getEntity();
if (mConfig.SUPPORT_BP) {
mConfigFPath = info.CONFIG_FILE_PATH; mConfigFPath = info.CONFIG_FILE_PATH;
}
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
mTaskType = getTaskType(); mTaskType = getTaskType();
@ -105,14 +99,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
final long currentTemp = mChildCurrentLocation;
STATE.STOP_NUM++; STATE.STOP_NUM++;
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
+ mConfig.TEMP_FILE.getName() + mConfig.TEMP_FILE.getName()
+ "】thread__" + "】thread__"
+ mConfig.THREAD_ID + mConfig.THREAD_ID
+ "__停止, stop location ==> " + "__停止, stop location ==> "
+ mChildCurrentLocation); + currentTemp);
writeConfig(false, mChildCurrentLocation); writeConfig(false, currentTemp);
if (STATE.isStop()) { if (STATE.isStop()) {
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
STATE.isRunning = false; STATE.isRunning = false;
@ -170,7 +165,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
/** /**
* 任务失败 * 任务失败
*/ */
protected void fail(long currentLocation, String msg, Exception ex) { protected void fail(final long currentLocation, String msg, Exception ex) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
if (ex != null) { if (ex != null) {
@ -213,7 +208,8 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mFailNum++; mFailNum++;
Log.w(TAG, Log.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试"); "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试");
mConfig.START_LOCATION = mChildCurrentLocation; final long retryLocation = mChildCurrentLocation;
mConfig.START_LOCATION = retryLocation;
AbsThreadTask.this.run(); AbsThreadTask.this.run();
} }
}, RETRY_INTERVAL); }, RETRY_INTERVAL);
@ -231,8 +227,9 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
/** /**
* 将记录写入到配置文件 * 将记录写入到配置文件
*/ */
protected void writeConfig(boolean isComplete, long record) throws IOException { protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
Log.d(TAG, "really record == " + record);
String key = null, value = null; String key = null, value = null;
if (0 < record && record < mConfig.END_LOCATION) { if (0 < record && record < mConfig.END_LOCATION) {
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID; key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;

@ -1,6 +1,6 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.common;
interface OnFileInfoCallback { public interface OnFileInfoCallback {
/** /**
* 处理完成 * 处理完成
* *

@ -1,155 +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.core.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "HttpFileInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
private OnFileInfoCallback mCallback;
protected long mSize = 0;
AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
}
@Override public void run() {
FTPClient client = null;
try {
String url = mTaskEntity.getEntity().getKey();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器,错误码为:" + reply);
return;
}
client.setDataTimeout(mConnectTimeOut);
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
FTPFile[] files =
client.listFiles(new String(remotePath.getBytes(charSet), AbsThreadTask.SERVER_CHARSET));
mSize = getFileSize(files, client, remotePath);
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
mTaskEntity.code = reply;
onPreComplete();
mEntity.update();
mTaskEntity.update();
mCallback.onComplete(mEntity.getKey(), reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
void start() {
new Thread(this).start();
}
protected void onPreComplete() {
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
size += getFileSize(client.listFiles(
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.downloader;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -33,14 +35,20 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
super(taskEntity, callback); super(taskEntity, callback);
} }
@Override void handleFile(String remotePath, FTPFile ftpFile) { @Override protected String setRemotePath() {
String url = mEntity.getKey();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile); super.handleFile(remotePath, ftpFile);
addEntity(remotePath, ftpFile); addEntity(remotePath, ftpFile);
} }
@Override protected void onPreComplete() { @Override protected void onPreComplete(int code) {
super.onPreComplete(); super.onPreComplete(code);
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getKey(), code);
} }
private void addEntity(String remotePath, FTPFile ftpFile) { private void addEntity(String remotePath, FTPFile ftpFile) {

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -28,8 +30,15 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
super(taskEntity, callback); super(taskEntity, callback);
} }
@Override protected void onPreComplete() { @Override protected String setRemotePath() {
super.onPreComplete(); String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length())
+ "/"
+ mEntity.getFileName();
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
if (mSize != mTaskEntity.getEntity().getFileSize()) { if (mSize != mTaskEntity.getEntity().getFileSize()) {
mTaskEntity.isNewTask = true; mTaskEntity.isNewTask = true;
} }

@ -15,9 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
@ -27,7 +26,6 @@ import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
@ -35,7 +33,7 @@ import org.apache.commons.net.ftp.FTPReply;
* Created by Aria.Lao on 2017/7/24. * Created by Aria.Lao on 2017/7/24.
* Ftp下载任务 * Ftp下载任务
*/ */
class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
@ -57,40 +55,16 @@ class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
+ ",结束位置:" + ",结束位置:"
+ mConfig.END_LOCATION + mConfig.END_LOCATION
+ "】"); + "】");
client = createClient();
if (client == null) return;
String url = mEntity.getUrl(); String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":"); String remotePath = new String(
String serverIp = pp[0]; url.substring(url.indexOf(port) + port.length(), url.length()).getBytes(charSet),
int port = Integer.parseInt(pp[1]); SERVER_CHARSET);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
return;
}
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(mConfig.START_LOCATION);
client.allocate(mBufSize); is = client.retrieveFileStream(remotePath);
is = client.retrieveFileStream(
new String(remotePath.getBytes(charSet), SERVER_CHARSET));
//发送第二次指令时,还需要再做一次判断 //发送第二次指令时,还需要再做一次判断
reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) { if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect(); client.disconnect();
fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null); fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null);

@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;

@ -17,6 +17,7 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;

@ -45,6 +45,9 @@ public class FtpUploadTarget
File file = new File(filePath); File file = new File(filePath);
mEntity.setFileName(file.getName()); mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length()); mEntity.setFileSize(file.length());
//暂时不支持断点续传上传
mTaskEntity.isSupportBP = false;
} }
/** /**

@ -0,0 +1,55 @@
/*
* 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.core.upload.uploader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/9/26.
* FTP远程服务器文件信息
*/
class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> {
static final int CODE_EXISTS = 0xab1;
private boolean exists = false;
FtpFileInfoThread(UploadTaskEntity taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
}
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length())
+ "/"
+ mEntity.getFileName();
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
//远程文件已完成
if (ftpFile != null && ftpFile.getSize() == mEntity.getFileSize()) {
exists = true;
}
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mCallback.onComplete(mEntity.getKey(), exists ? CODE_EXISTS : code);
}
}

@ -15,9 +15,8 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
@ -27,28 +26,29 @@ import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.apache.commons.net.ftp.FTP; import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.OnFtpInputStreamListener;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
/** /**
* Created by Aria.Lao on 2017/7/28. * Created by Aria.Lao on 2017/7/28.
* FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限 * FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限
*/ */
class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
private String dir, remotePath, charSet; private String dir, remotePath;
FtpThreadTask(StateConstance constance, IEventListener listener, FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UploadTaskEntity> info) { SubThreadConfig<UploadTaskEntity> info) {
super(constance, listener, info); super(constance, listener, info);
} }
@Override public void run() { @Override public void run() {
FTPClient client = null; FTPClient client = null;
OutputStream os = null;
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
@ -64,22 +64,16 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = mConfig.START_LOCATION;
client = createClient(); client = createClient();
if (client == null) return; if (client == null) return;
initPath();
client.makeDirectory(dir); client.makeDirectory(dir);
client.changeWorkingDirectory(dir); client.changeWorkingDirectory(dir);
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(mConfig.START_LOCATION);
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
file.seek(mConfig.START_LOCATION); if (mConfig.START_LOCATION != 0) {
if (!isRemoteComplete(client)) { file.skipBytes((int) mConfig.START_LOCATION);
os = client.storeFileStream(new String(remotePath.getBytes(charSet), SERVER_CHARSET)); //file.seek(mConfig.START_LOCATION);
//发送第二次指令时,还需要再做一次判断
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
return;
}
upload(file, os);
} }
upload(client, file);
if (STATE.isCancel || STATE.isStop) return; if (STATE.isCancel || STATE.isStop) return;
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕"); Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕");
writeConfig(true, 1); writeConfig(true, 1);
@ -101,9 +95,6 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
if (file != null) { if (file != null) {
file.close(); file.close();
} }
if (os != null) {
os.close();
}
if (client != null && client.isConnected()) { if (client != null && client.isConnected()) {
client.disconnect(); client.disconnect();
} }
@ -113,14 +104,55 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
} }
} }
/** private void initPath() throws UnsupportedEncodingException {
* 远程文件是否已经玩飞车 String url = mEntity.getUrl();
* String temp = url.substring(url.indexOf(port) + port.length(), url.length());
* @return true 任务已经完成 dir = new String(temp.getBytes(charSet), SERVER_CHARSET);
*/ remotePath = new String((temp + "/" + mEntity.getFileName()).getBytes(charSet), SERVER_CHARSET);
private boolean isRemoteComplete(FTPClient client) throws IOException { }
FTPFile[] files = client.listFiles(new String(remotePath.getBytes(charSet), SERVER_CHARSET));
return files.length != 0 && files[0].getSize() == mEntity.getFileSize(); private void upload(final FTPClient client, final BufferedRandomAccessFile bis)
throws IOException {
//client.storeFile(remotePath,
// new ProgressInputStream(bis, new ProgressInputStream.ProgressCallback() {
// @Override public void onProgressCallback(byte[] buffer, int byteOffset, int byteCount)
// throws IOException {
// if (STATE.isCancel || STATE.isStop) {
// long s = client.abor();
// Log.d(TAG, "s = " + s);
// client.disconnect();
// }
// progress(byteCount);
// }
// }));
try {
client.storeFile(remotePath, new ProgressInputStream(bis), new OnFtpInputStreamListener() {
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) {
if (STATE.isCancel || STATE.isStop) {
try {
client.abor();
} catch (IOException e) {
e.printStackTrace();
}
}
progress(bytesTransferred);
}
});
} catch (IOException e) {
//e.printStackTrace();
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
}
} }
/** /**
@ -143,48 +175,11 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
os.write(buffer, 0, len); os.write(buffer, 0, len);
progress(len); progress(len);
} }
Log.d(TAG, len + "");
} }
} }
/**
* 构建FTP客户端
*/
private FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
dir = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
remotePath = dir + "/" + mEntity.getFileName();
FTPClient client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
return null;
}
charSet = "UTF-8";
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.allocate(mBufSize);
return client;
}
@Override protected String getTaskType() { @Override protected String getTaskType() {
return "FTP_UPLOAD"; return "FTP_UPLOAD";
} }
} }

@ -0,0 +1,74 @@
/*
* 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.core.upload.uploader;
import android.support.annotation.NonNull;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by lyy on 2017/9/26.
* 具有进度的InputStream
*/
final class ProgressInputStream extends InputStream {
private BufferedRandomAccessFile mIs;
private ProgressCallback mCallback;
private int count;
interface ProgressCallback {
void onProgressCallback(byte[] buffer, int byteOffset, int byteCount) throws IOException;
}
ProgressInputStream(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
mIs = is;
mCallback = callback;
}
ProgressInputStream(@NonNull BufferedRandomAccessFile is) {
mIs = is;
}
@Override public void close() throws IOException {
mIs.close();
}
@Override public int read() throws IOException {
return mIs.read();
}
@Override public int read(@NonNull byte[] buffer) throws IOException {
count = mIs.read(buffer);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, 0, count);
}
return count;
}
@Override public int read(@NonNull byte[] buffer, int byteOffset, int byteCount)
throws IOException {
count = mIs.read(buffer, byteOffset, byteCount);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, byteOffset, byteCount);
}
return count;
}
@Override public long skip(long byteCount) throws IOException {
return mIs.skipBytes((int) byteCount);
}
}

@ -16,6 +16,7 @@
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.inf.IUploadListener; import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
@ -46,8 +47,20 @@ public class SimpleUploadUtil implements IUtil, Runnable {
@Override public void run() { @Override public void run() {
mListener.onPre(); mListener.onPre();
new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code == FtpFileInfoThread.CODE_EXISTS) {
mListener.onComplete();
} else {
mUploader.start(); mUploader.start();
} }
}
@Override public void onFail(String url, String errorMsg) {
mListener.onFail(true);
}
}).start();
}
@Override public long getFileSize() { @Override public long getFileSize() {
return mUploader.getFileSize(); return mUploader.getFileSize();

@ -230,7 +230,7 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
/** /**
* 遍历所有数据 * 查找表的所有数据
*/ */
static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) { static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db); db = checkDb(db);

@ -705,6 +705,7 @@ public class CommonUtil {
* 设置打印的异常格式 * 设置打印的异常格式
*/ */
public static String getPrintException(Throwable ex) { public static String getPrintException(Throwable ex) {
if (ex == null) return "";
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n"); err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n"); err.append("====================Exception Info====================\n");

@ -47,8 +47,7 @@ import java.nio.charset.Charset;
* @see DatagramSocketFactory * @see DatagramSocketFactory
***/ ***/
public abstract class DatagramSocketClient public abstract class DatagramSocketClient {
{
/*** /***
* The default DatagramSocketFactory shared by all DatagramSocketClient * The default DatagramSocketFactory shared by all DatagramSocketClient
* instances. * instances.
@ -79,15 +78,13 @@ public abstract class DatagramSocketClient
* Default constructor for DatagramSocketClient. Initializes * Default constructor for DatagramSocketClient. Initializes
* _socket_ to null, _timeout_ to 0, and _isOpen_ to false. * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
***/ ***/
public DatagramSocketClient() public DatagramSocketClient() {
{
_socket_ = null; _socket_ = null;
_timeout_ = 0; _timeout_ = 0;
_isOpen_ = false; _isOpen_ = false;
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} }
/*** /***
* Opens a DatagramSocket on the local host at the first available port. * Opens a DatagramSocket on the local host at the first available port.
* Also sets the timeout on the socket to the default timeout set * Also sets the timeout on the socket to the default timeout set
@ -99,14 +96,12 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open() throws SocketException public void open() throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(); _socket_ = _socketFactory_.createDatagramSocket();
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Opens a DatagramSocket on the local host at a specified port. * Opens a DatagramSocket on the local host at a specified port.
* Also sets the timeout on the socket to the default timeout set * Also sets the timeout on the socket to the default timeout set
@ -119,14 +114,12 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open(int port) throws SocketException public void open(int port) throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(port); _socket_ = _socketFactory_.createDatagramSocket(port);
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Opens a DatagramSocket at the specified address on the local host * Opens a DatagramSocket at the specified address on the local host
* at a specified port. * at a specified port.
@ -141,23 +134,19 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open(int port, InetAddress laddr) throws SocketException public void open(int port, InetAddress laddr) throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(port, laddr); _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Closes the DatagramSocket used for the connection. * Closes the DatagramSocket used for the connection.
* You should call this method after you've finished using the class * You should call this method after you've finished using the class
* instance and also before you call {@link #open open() } * instance and also before you call {@link #open open() }
* again. _isOpen_ is set to false and _socket_ is set to null. * again. _isOpen_ is set to false and _socket_ is set to null.
***/ ***/
public void close() public void close() {
{
if (_socket_ != null) { if (_socket_ != null) {
_socket_.close(); _socket_.close();
} }
@ -165,18 +154,15 @@ public abstract class DatagramSocketClient
_isOpen_ = false; _isOpen_ = false;
} }
/*** /***
* Returns true if the client has a currently open socket. * Returns true if the client has a currently open socket.
* *
* @return True if the client has a currently open socket, false otherwise. * @return True if the client has a currently open socket, false otherwise.
***/ ***/
public boolean isOpen() public boolean isOpen() {
{
return _isOpen_; return _isOpen_;
} }
/*** /***
* Set the default timeout in milliseconds to use when opening a socket. * 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. * After a call to open, the timeout for the socket is set using this value.
@ -188,12 +174,10 @@ public abstract class DatagramSocketClient
* @param timeout The timeout in milliseconds to use for the datagram socket * @param timeout The timeout in milliseconds to use for the datagram socket
* connection. * connection.
***/ ***/
public void setDefaultTimeout(int timeout) public void setDefaultTimeout(int timeout) {
{
_timeout_ = timeout; _timeout_ = timeout;
} }
/*** /***
* Returns the default timeout in milliseconds that is used when * Returns the default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
@ -201,12 +185,10 @@ public abstract class DatagramSocketClient
* @return The default timeout in milliseconds that is used when * @return The default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
***/ ***/
public int getDefaultTimeout() public int getDefaultTimeout() {
{
return _timeout_; return _timeout_;
} }
/*** /***
* Set the timeout in milliseconds of a currently open connection. * Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened * Only call this method after a connection has been opened
@ -216,12 +198,10 @@ public abstract class DatagramSocketClient
* open datagram socket connection. * open datagram socket connection.
* @throws SocketException if an error setting the timeout * @throws SocketException if an error setting the timeout
***/ ***/
public void setSoTimeout(int timeout) throws SocketException public void setSoTimeout(int timeout) throws SocketException {
{
_socket_.setSoTimeout(timeout); _socket_.setSoTimeout(timeout);
} }
/*** /***
* Returns the timeout in milliseconds of the currently opened socket. * Returns the timeout in milliseconds of the currently opened socket.
* If you call this method when the client socket is not open, * If you call this method when the client socket is not open,
@ -230,12 +210,10 @@ public abstract class DatagramSocketClient
* @return The timeout in milliseconds of the currently opened socket. * @return The timeout in milliseconds of the currently opened socket.
* @throws SocketException if an error getting the timeout * @throws SocketException if an error getting the timeout
***/ ***/
public int getSoTimeout() throws SocketException public int getSoTimeout() throws SocketException {
{
return _socket_.getSoTimeout(); return _socket_.getSoTimeout();
} }
/*** /***
* Returns the port number of the open socket on the local host used * 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 * for the connection. If you call this method when the client socket
@ -244,12 +222,10 @@ public abstract class DatagramSocketClient
* @return The port number of the open socket on the local host used * @return The port number of the open socket on the local host used
* for the connection. * for the connection.
***/ ***/
public int getLocalPort() public int getLocalPort() {
{
return _socket_.getLocalPort(); return _socket_.getLocalPort();
} }
/*** /***
* Returns the local address to which the client's socket is bound. * 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 * If you call this method when the client socket is not open, a
@ -257,12 +233,10 @@ public abstract class DatagramSocketClient
* *
* @return The local address to which the client's socket is bound. * @return The local address to which the client's socket is bound.
***/ ***/
public InetAddress getLocalAddress() public InetAddress getLocalAddress() {
{
return _socket_.getLocalAddress(); return _socket_.getLocalAddress();
} }
/*** /***
* Sets the DatagramSocketFactory used by the DatagramSocketClient * Sets the DatagramSocketFactory used by the DatagramSocketClient
* to open DatagramSockets. If the factory value is null, then a default * to open DatagramSockets. If the factory value is null, then a default
@ -272,8 +246,7 @@ public abstract class DatagramSocketClient
* @param factory The new DatagramSocketFactory the DatagramSocketClient * @param factory The new DatagramSocketFactory the DatagramSocketClient
* should use. * should use.
***/ ***/
public void setDatagramSocketFactory(DatagramSocketFactory factory) public void setDatagramSocketFactory(DatagramSocketFactory factory) {
{
if (factory == null) { if (factory == null) {
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} else { } else {

@ -35,8 +35,7 @@ import java.net.SocketException;
* *
***/ ***/
public interface DatagramSocketFactory public interface DatagramSocketFactory {
{
/*** /***
* Creates a DatagramSocket on the local host at the first available port. * Creates a DatagramSocket on the local host at the first available port.
@ -64,6 +63,5 @@ public interface DatagramSocketFactory
* @return the socket * @return the socket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
public DatagramSocket createDatagramSocket(int port, InetAddress laddr) public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException;
throws SocketException;
} }

@ -34,17 +34,14 @@ import java.net.SocketException;
* @see DatagramSocketClient#setDatagramSocketFactory * @see DatagramSocketClient#setDatagramSocketFactory
***/ ***/
public class DefaultDatagramSocketFactory implements DatagramSocketFactory public class DefaultDatagramSocketFactory implements DatagramSocketFactory {
{
/*** /***
* Creates a DatagramSocket on the local host at the first available port. * Creates a DatagramSocket on the local host at the first available port.
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket() throws SocketException {
public DatagramSocket createDatagramSocket() throws SocketException
{
return new DatagramSocket(); return new DatagramSocket();
} }
@ -55,9 +52,7 @@ public class DefaultDatagramSocketFactory implements DatagramSocketFactory
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket(int port) throws SocketException {
public DatagramSocket createDatagramSocket(int port) throws SocketException
{
return new DatagramSocket(port); return new DatagramSocket(port);
} }
@ -70,10 +65,8 @@ public class DefaultDatagramSocketFactory implements DatagramSocketFactory
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket(int port, InetAddress laddr)
public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException {
throws SocketException
{
return new DatagramSocket(port, laddr); return new DatagramSocket(port, laddr);
} }
} }

@ -40,16 +40,14 @@ import javax.net.SocketFactory;
* @see SocketClient#setSocketFactory * @see SocketClient#setSocketFactory
***/ ***/
public class DefaultSocketFactory extends SocketFactory public class DefaultSocketFactory extends SocketFactory {
{
/** The proxy to use when creating new sockets. */ /** The proxy to use when creating new sockets. */
private final Proxy connProxy; private final Proxy connProxy;
/** /**
* The default constructor. * The default constructor.
*/ */
public DefaultSocketFactory() public DefaultSocketFactory() {
{
this(null); this(null);
} }
@ -59,8 +57,7 @@ public class DefaultSocketFactory extends SocketFactory
* @param proxy The Proxy to use when creating new Sockets. * @param proxy The Proxy to use when creating new Sockets.
* @since 3.2 * @since 3.2
*/ */
public DefaultSocketFactory(Proxy proxy) public DefaultSocketFactory(Proxy proxy) {
{
connProxy = proxy; connProxy = proxy;
} }
@ -71,11 +68,8 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
* @since 3.2 * @since 3.2
*/ */
@Override @Override public Socket createSocket() throws IOException {
public Socket createSocket() throws IOException if (connProxy != null) {
{
if (connProxy != null)
{
return new Socket(connProxy); return new Socket(connProxy);
} }
return new Socket(); return new Socket();
@ -90,12 +84,9 @@ public class DefaultSocketFactory extends SocketFactory
* @throws UnknownHostException If the hostname cannot be resolved. * @throws UnknownHostException If the hostname cannot be resolved.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(String host, int port)
public Socket createSocket(String host, int port) throws UnknownHostException, IOException {
throws UnknownHostException, IOException if (connProxy != null) {
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.connect(new InetSocketAddress(host, port)); s.connect(new InetSocketAddress(host, port));
return s; return s;
@ -111,12 +102,8 @@ public class DefaultSocketFactory extends SocketFactory
* @return A Socket connected to the given host and port. * @return A Socket connected to the given host and port.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(InetAddress address, int port) throws IOException {
public Socket createSocket(InetAddress address, int port) if (connProxy != null) {
throws IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.connect(new InetSocketAddress(address, port)); s.connect(new InetSocketAddress(address, port));
return s; return s;
@ -136,13 +123,9 @@ public class DefaultSocketFactory extends SocketFactory
* @throws UnknownHostException If the hostname cannot be resolved. * @throws UnknownHostException If the hostname cannot be resolved.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
public Socket createSocket(String host, int port, throws UnknownHostException, IOException {
InetAddress localAddr, int localPort) if (connProxy != null) {
throws UnknownHostException, IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.bind(new InetSocketAddress(localAddr, localPort)); s.bind(new InetSocketAddress(localAddr, localPort));
s.connect(new InetSocketAddress(host, port)); s.connect(new InetSocketAddress(host, port));
@ -162,13 +145,9 @@ public class DefaultSocketFactory extends SocketFactory
* @return A Socket connected to the given host and port. * @return A Socket connected to the given host and port.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddr,
public Socket createSocket(InetAddress address, int port, int localPort) throws IOException {
InetAddress localAddr, int localPort) if (connProxy != null) {
throws IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.bind(new InetSocketAddress(localAddr, localPort)); s.bind(new InetSocketAddress(localAddr, localPort));
s.connect(new InetSocketAddress(address, port)); s.connect(new InetSocketAddress(address, port));
@ -186,8 +165,7 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port) throws IOException public ServerSocket createServerSocket(int port) throws IOException {
{
return new ServerSocket(port); return new ServerSocket(port);
} }
@ -202,9 +180,7 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port, int backlog) public ServerSocket createServerSocket(int port, int backlog) throws IOException {
throws IOException
{
return new ServerSocket(port, backlog); return new ServerSocket(port, backlog);
} }
@ -221,10 +197,8 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port, int backlog, public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr)
InetAddress bindAddr) throws IOException {
throws IOException
{
return new ServerSocket(port, backlog, bindAddr); return new ServerSocket(port, backlog, bindAddr);
} }
} }

@ -32,14 +32,12 @@ import java.io.IOException;
* *
***/ ***/
public class MalformedServerReplyException extends IOException public class MalformedServerReplyException extends IOException {
{
private static final long serialVersionUID = 6006765264250543945L; private static final long serialVersionUID = 6006765264250543945L;
/*** Constructs a MalformedServerReplyException with no message ***/ /*** Constructs a MalformedServerReplyException with no message ***/
public MalformedServerReplyException() public MalformedServerReplyException() {
{
super(); super();
} }
@ -48,9 +46,7 @@ public class MalformedServerReplyException extends IOException
* *
* @param message The message explaining the reason for the exception. * @param message The message explaining the reason for the exception.
***/ ***/
public MalformedServerReplyException(String message) public MalformedServerReplyException(String message) {
{
super(message); super(message);
} }
} }

@ -28,8 +28,7 @@ import java.io.PrintWriter;
* @since 2.0 * @since 2.0
***/ ***/
public class PrintCommandListener implements ProtocolCommandListener public class PrintCommandListener implements ProtocolCommandListener {
{
private final PrintWriter __writer; private final PrintWriter __writer;
private final boolean __nologin; private final boolean __nologin;
private final char __eolMarker; private final char __eolMarker;
@ -42,8 +41,7 @@ public class PrintCommandListener implements ProtocolCommandListener
* e.g. System.out * e.g. System.out
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream) public PrintCommandListener(PrintStream stream) {
{
this(new PrintWriter(stream)); this(new PrintWriter(stream));
} }
@ -53,7 +51,6 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin) { public PrintCommandListener(PrintStream stream, boolean suppressLogin) {
@ -67,7 +64,6 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) { public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) {
@ -81,11 +77,12 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @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 * @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the
* * output
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker, boolean showDirection) { public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker,
boolean showDirection) {
this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection); this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection);
} }
@ -94,8 +91,7 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
*/ */
public PrintCommandListener(PrintWriter writer) public PrintCommandListener(PrintWriter writer) {
{
this(writer, false); this(writer, false);
} }
@ -104,11 +100,9 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin) public PrintCommandListener(PrintWriter writer, boolean suppressLogin) {
{
this(writer, suppressLogin, (char) 0); this(writer, suppressLogin, (char) 0);
} }
@ -119,11 +113,9 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) {
{
this(writer, suppressLogin, eolMarker, false); this(writer, suppressLogin, eolMarker, false);
} }
@ -134,21 +126,19 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @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 * @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the
* * output
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker, boolean showDirection) public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker,
{ boolean showDirection) {
__writer = writer; __writer = writer;
__nologin = suppressLogin; __nologin = suppressLogin;
__eolMarker = eolMarker; __eolMarker = eolMarker;
__directionMarker = showDirection; __directionMarker = showDirection;
} }
@Override @Override public void protocolCommandSent(ProtocolCommandEvent event) {
public void protocolCommandSent(ProtocolCommandEvent event)
{
if (__directionMarker) { if (__directionMarker) {
__writer.print("> "); __writer.print("> ");
} }
@ -161,7 +151,7 @@ public class PrintCommandListener implements ProtocolCommandListener
final String IMAP_LOGIN = "LOGIN"; final String IMAP_LOGIN = "LOGIN";
if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP
String msg = event.getMessage(); String msg = event.getMessage();
msg=msg.substring(0, msg.indexOf(IMAP_LOGIN)+IMAP_LOGIN.length()); msg = msg.substring(0, msg.indexOf(IMAP_LOGIN) + IMAP_LOGIN.length());
__writer.print(msg); __writer.print(msg);
__writer.println(" *******"); // Don't bother with EOL marker for this! __writer.println(" *******"); // Don't bother with EOL marker for this!
} else { } else {
@ -174,14 +164,14 @@ public class PrintCommandListener implements ProtocolCommandListener
__writer.flush(); __writer.flush();
} }
private String getPrintableString(String msg){ private String getPrintableString(String msg) {
if (__eolMarker == 0) { if (__eolMarker == 0) {
return msg; return msg;
} }
int pos = msg.indexOf(SocketClient.NETASCII_EOL); int pos = msg.indexOf(SocketClient.NETASCII_EOL);
if (pos > 0) { if (pos > 0) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(msg.substring(0,pos)); sb.append(msg.substring(0, pos));
sb.append(__eolMarker); sb.append(__eolMarker);
sb.append(msg.substring(pos)); sb.append(msg.substring(pos));
return sb.toString(); return sb.toString();
@ -189,9 +179,7 @@ public class PrintCommandListener implements ProtocolCommandListener
return msg; return msg;
} }
@Override @Override public void protocolReplyReceived(ProtocolCommandEvent event) {
public void protocolReplyReceived(ProtocolCommandEvent event)
{
if (__directionMarker) { if (__directionMarker) {
__writer.print("< "); __writer.print("< ");
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net; package org.apache.commons.net;
import java.util.EventObject; import java.util.EventObject;
/*** /***
@ -32,8 +33,7 @@ import java.util.EventObject;
* @see ProtocolCommandSupport * @see ProtocolCommandSupport
***/ ***/
public class ProtocolCommandEvent extends EventObject public class ProtocolCommandEvent extends EventObject {
{
private static final long serialVersionUID = 403743538418947240L; private static final long serialVersionUID = 403743538418947240L;
private final int __replyCode; private final int __replyCode;
@ -52,8 +52,7 @@ public class ProtocolCommandEvent extends EventObject
* @param message The entire command string verbatim as sent to the server, * @param message The entire command string verbatim as sent to the server,
* including all arguments. * including all arguments.
***/ ***/
public ProtocolCommandEvent(Object source, String command, String message) public ProtocolCommandEvent(Object source, String command, String message) {
{
super(source); super(source);
__replyCode = 0; __replyCode = 0;
__message = message; __message = message;
@ -61,7 +60,6 @@ public class ProtocolCommandEvent extends EventObject
__command = command; __command = command;
} }
/*** /***
* Creates a ProtocolCommandEvent signalling a reply to a command was * Creates a ProtocolCommandEvent signalling a reply to a command was
* received. ProtocolCommandEvents created with this constructor * received. ProtocolCommandEvents created with this constructor
@ -76,8 +74,7 @@ public class ProtocolCommandEvent extends EventObject
* strings like OK rather than integer codes (i.e., POP3Repy.OK). * strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server. * @param message The entire reply as received from the server.
***/ ***/
public ProtocolCommandEvent(Object source, int replyCode, String message) public ProtocolCommandEvent(Object source, int replyCode, String message) {
{
super(source); super(source);
__replyCode = replyCode; __replyCode = replyCode;
__message = message; __message = message;
@ -93,12 +90,10 @@ public class ProtocolCommandEvent extends EventObject
* @return The string representation of the command type sent, or null * @return The string representation of the command type sent, or null
* if this is a reply event. * if this is a reply event.
***/ ***/
public String getCommand() public String getCommand() {
{
return __command; return __command;
} }
/*** /***
* Returns the reply code of the received server reply. Undefined if * Returns the reply code of the received server reply. Undefined if
* this is not a reply event. * this is not a reply event.
@ -106,8 +101,7 @@ public class ProtocolCommandEvent extends EventObject
* @return The reply code of the received server reply. Undefined if * @return The reply code of the received server reply. Undefined if
* not a reply event. * not a reply event.
***/ ***/
public int getReplyCode() public int getReplyCode() {
{
return __replyCode; return __replyCode;
} }
@ -118,8 +112,7 @@ public class ProtocolCommandEvent extends EventObject
* @return true If the ProtocolCommandEvent was generated as a result * @return true If the ProtocolCommandEvent was generated as a result
* of sending a command. False otherwise. * of sending a command. False otherwise.
***/ ***/
public boolean isCommand() public boolean isCommand() {
{
return __isCommand; return __isCommand;
} }
@ -130,8 +123,7 @@ public class ProtocolCommandEvent extends EventObject
* @return true If the ProtocolCommandEvent was generated as a result * @return true If the ProtocolCommandEvent was generated as a result
* of receiving a reply. False otherwise. * of receiving a reply. False otherwise.
***/ ***/
public boolean isReply() public boolean isReply() {
{
return !isCommand(); return !isCommand();
} }
@ -141,8 +133,7 @@ public class ProtocolCommandEvent extends EventObject
* *
* @return The entire message sent to or received from the server. * @return The entire message sent to or received from the server.
***/ ***/
public String getMessage() public String getMessage() {
{
return __message; return __message;
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net; package org.apache.commons.net;
import java.util.EventListener; import java.util.EventListener;
/*** /***
@ -36,8 +37,7 @@ import java.util.EventListener;
* @see ProtocolCommandSupport * @see ProtocolCommandSupport
***/ ***/
public interface ProtocolCommandListener extends EventListener public interface ProtocolCommandListener extends EventListener {
{
/*** /***
* This method is invoked by a ProtocolCommandEvent source after * This method is invoked by a ProtocolCommandEvent source after
@ -54,5 +54,4 @@ public interface ProtocolCommandListener extends EventListener
* @param event The ProtocolCommandEvent fired. * @param event The ProtocolCommandEvent fired.
***/ ***/
public void protocolReplyReceived(ProtocolCommandEvent event); public void protocolReplyReceived(ProtocolCommandEvent event);
} }

@ -33,8 +33,7 @@ import org.apache.commons.net.util.ListenerList;
* @see ProtocolCommandListener * @see ProtocolCommandListener
***/ ***/
public class ProtocolCommandSupport implements Serializable public class ProtocolCommandSupport implements Serializable {
{
private static final long serialVersionUID = -8017692739988399978L; private static final long serialVersionUID = -8017692739988399978L;
private final Object __source; private final Object __source;
@ -46,13 +45,11 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param source The source to use for all generated ProtocolCommandEvents. * @param source The source to use for all generated ProtocolCommandEvents.
***/ ***/
public ProtocolCommandSupport(Object source) public ProtocolCommandSupport(Object source) {
{
__listeners = new ListenerList(); __listeners = new ListenerList();
__source = source; __source = source;
} }
/*** /***
* Fires a ProtocolCommandEvent signalling the sending of a command to all * Fires a ProtocolCommandEvent signalling the sending of a command to all
* registered listeners, invoking their * registered listeners, invoking their
@ -64,15 +61,13 @@ public class ProtocolCommandSupport implements Serializable
* @param message The entire command string verbatim as sent to the server, * @param message The entire command string verbatim as sent to the server,
* including all arguments. * including all arguments.
***/ ***/
public void fireCommandSent(String command, String message) public void fireCommandSent(String command, String message) {
{
ProtocolCommandEvent event; ProtocolCommandEvent event;
event = new ProtocolCommandEvent(__source, command, message); event = new ProtocolCommandEvent(__source, command, message);
for (EventListener listener : __listeners) for (EventListener listener : __listeners) {
{ ((ProtocolCommandListener) listener).protocolCommandSent(event);
((ProtocolCommandListener)listener).protocolCommandSent(event);
} }
} }
@ -89,14 +84,12 @@ public class ProtocolCommandSupport implements Serializable
* strings like OK rather than integer codes (i.e., POP3Repy.OK). * strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server. * @param message The entire reply as received from the server.
***/ ***/
public void fireReplyReceived(int replyCode, String message) public void fireReplyReceived(int replyCode, String message) {
{
ProtocolCommandEvent event; ProtocolCommandEvent event;
event = new ProtocolCommandEvent(__source, replyCode, message); event = new ProtocolCommandEvent(__source, replyCode, message);
for (EventListener listener : __listeners) for (EventListener listener : __listeners) {
{ ((ProtocolCommandListener) listener).protocolReplyReceived(event);
((ProtocolCommandListener)listener).protocolReplyReceived(event);
} }
} }
@ -105,8 +98,7 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param listener The ProtocolCommandListener to add. * @param listener The ProtocolCommandListener to add.
***/ ***/
public void addProtocolCommandListener(ProtocolCommandListener listener) public void addProtocolCommandListener(ProtocolCommandListener listener) {
{
__listeners.addListener(listener); __listeners.addListener(listener);
} }
@ -115,21 +107,17 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param listener The ProtocolCommandListener to remove. * @param listener The ProtocolCommandListener to remove.
***/ ***/
public void removeProtocolCommandListener(ProtocolCommandListener listener) public void removeProtocolCommandListener(ProtocolCommandListener listener) {
{
__listeners.removeListener(listener); __listeners.removeListener(listener);
} }
/*** /***
* Returns the number of ProtocolCommandListeners currently registered. * Returns the number of ProtocolCommandListeners currently registered.
* *
* @return The number of ProtocolCommandListeners currently registered. * @return The number of ProtocolCommandListeners currently registered.
***/ ***/
public int getListenerCount() public int getListenerCount() {
{
return __listeners.getListenerCount(); return __listeners.getListenerCount();
} }
} }

@ -31,7 +31,6 @@ import java.nio.charset.Charset;
import javax.net.ServerSocketFactory; import javax.net.ServerSocketFactory;
import javax.net.SocketFactory; import javax.net.SocketFactory;
/** /**
* The SocketClient provides the basic operations that are required of * The SocketClient provides the basic operations that are required of
* client objects accessing sockets. It is meant to be * client objects accessing sockets. It is meant to be
@ -50,10 +49,10 @@ import javax.net.SocketFactory;
* them by directly invoking a constructor. By honoring this contract * them by directly invoking a constructor. By honoring this contract
* you guarantee that a user will always be able to provide his own * you guarantee that a user will always be able to provide his own
* Socket implementations by substituting his own SocketFactory. * Socket implementations by substituting his own SocketFactory.
*
* @see SocketFactory * @see SocketFactory
*/ */
public abstract class SocketClient public abstract class SocketClient {
{
/** /**
* The end of line character sequence used by most IETF protocols. That * The end of line character sequence used by most IETF protocols. That
* is a carriage return followed by a newline: "\r\n" * is a carriage return followed by a newline: "\r\n"
@ -61,8 +60,7 @@ public abstract class SocketClient
public static final String NETASCII_EOL = "\r\n"; public static final String NETASCII_EOL = "\r\n";
/** The default SocketFactory shared by all SocketClient instances. */ /** The default SocketFactory shared by all SocketClient instances. */
private static final SocketFactory __DEFAULT_SOCKET_FACTORY = private static final SocketFactory __DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault();
SocketFactory.getDefault();
/** The default {@link ServerSocketFactory} */ /** The default {@link ServerSocketFactory} */
private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
@ -123,8 +121,7 @@ public abstract class SocketClient
* and _socketFactory_ to a shared instance of * and _socketFactory_ to a shared instance of
* {@link org.apache.commons.net.DefaultSocketFactory}. * {@link org.apache.commons.net.DefaultSocketFactory}.
*/ */
public SocketClient() public SocketClient() {
{
_socket_ = null; _socket_ = null;
_hostname_ = null; _hostname_ = null;
_input_ = null; _input_ = null;
@ -135,7 +132,6 @@ public abstract class SocketClient
_serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
} }
/** /**
* Because there are so many connect() methods, the _connectAction_() * Because there are so many connect() methods, the _connectAction_()
* method is provided as a means of performing some action immediately * method is provided as a means of performing some action immediately
@ -151,22 +147,22 @@ public abstract class SocketClient
* Subclasses overriding this method should start by calling * Subclasses overriding this method should start by calling
* <code> super._connectAction_() </code> first to ensure the * <code> super._connectAction_() </code> first to ensure the
* initialization of the aforementioned protected variables. * initialization of the aforementioned protected variables.
*
* @throws IOException (SocketException) if a problem occurs with the socket * @throws IOException (SocketException) if a problem occurs with the socket
*/ */
protected void _connectAction_() throws IOException protected void _connectAction_() throws IOException {
{
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_input_ = _socket_.getInputStream(); _input_ = _socket_.getInputStream();
_output_ = _socket_.getOutputStream(); _output_ = _socket_.getOutputStream();
} }
/** /**
* Opens a Socket connected to a remote host at the specified port and * Opens a Socket connected to a remote host at the specified port and
* originating from the current host at a system assigned port. * originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @param port The port to connect to on 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 SocketException If the socket timeout could not be set.
@ -174,9 +170,7 @@ public abstract class SocketClient
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host, int port) public void connect(InetAddress host, int port) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = null; _hostname_ = null;
_connect(host, port, null, -1); _connect(host, port, null, -1);
} }
@ -187,6 +181,7 @@ public abstract class SocketClient
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @param port The port to connect to on 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 SocketException If the socket timeout could not be set.
@ -195,20 +190,18 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname, int port) public void connect(String hostname, int port) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = hostname; _hostname_ = hostname;
_connect(InetAddress.getByName(hostname), port, null, -1); _connect(InetAddress.getByName(hostname), port, null, -1);
} }
/** /**
* Opens a Socket connected to a remote host at the specified port and * Opens a Socket connected to a remote host at the specified port and
* originating from the specified local address and port. * originating from the specified local address and port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @param port The port to connect to on the remote host. * @param port The port to connect to on the remote host.
* @param localAddr The local address to use. * @param localAddr The local address to use.
@ -218,18 +211,15 @@ public abstract class SocketClient
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host, int port, public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
InetAddress localAddr, int localPort) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = null; _hostname_ = null;
_connect(host, port, localAddr, localPort); _connect(host, port, localAddr, localPort);
} }
// helper method to allow code to be shared with connect(String,...) methods // helper method to allow code to be shared with connect(String,...) methods
private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort) private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort)
throws SocketException, IOException throws SocketException, IOException {
{
_socket_ = _socketFactory_.createSocket(); _socket_ = _socketFactory_.createSocket();
if (receiveBufferSize != -1) { if (receiveBufferSize != -1) {
_socket_.setReceiveBufferSize(receiveBufferSize); _socket_.setReceiveBufferSize(receiveBufferSize);
@ -250,6 +240,7 @@ public abstract class SocketClient
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @param port The port to connect to on the remote host. * @param port The port to connect to on the remote host.
* @param localAddr The local address to use. * @param localAddr The local address to use.
@ -260,40 +251,37 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname, int port, public void connect(String hostname, int port, InetAddress localAddr, int localPort)
InetAddress localAddr, int localPort) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = hostname; _hostname_ = hostname;
_connect(InetAddress.getByName(hostname), port, localAddr, localPort); _connect(InetAddress.getByName(hostname), port, localAddr, localPort);
} }
/** /**
* Opens a Socket connected to a remote host at the current default port * Opens a Socket connected to a remote host at the current default port
* and originating from the current host at a system assigned port. * and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @throws SocketException If the socket timeout could not be set. * @throws SocketException If the socket timeout could not be set.
* @throws IOException If the socket could not be opened. In most * @throws IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host) throws SocketException, IOException public void connect(InetAddress host) throws SocketException, IOException {
{
_hostname_ = null; _hostname_ = null;
connect(host, _defaultPort_); connect(host, _defaultPort_);
} }
/** /**
* Opens a Socket connected to a remote host at the current default * Opens a Socket connected to a remote host at the current default
* port and originating from the current host at a system assigned port. * port and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @throws SocketException If the socket timeout could not be set. * @throws SocketException If the socket timeout could not be set.
* @throws IOException If the socket could not be opened. In most * @throws IOException If the socket could not be opened. In most
@ -301,12 +289,10 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname) throws SocketException, IOException public void connect(String hostname) throws SocketException, IOException {
{
connect(hostname, _defaultPort_); connect(hostname, _defaultPort_);
} }
/** /**
* Disconnects the socket connection. * Disconnects the socket connection.
* You should call this method after you've finished using the class * You should call this method after you've finished using the class
@ -315,10 +301,10 @@ public abstract class SocketClient
* again. _isConnected_ is set to false, _socket_ is set to null, * again. _isConnected_ is set to false, _socket_ is set to null,
* _input_ is set to null, and _output_ is set to null. * _input_ is set to null, and _output_ is set to null.
* <p> * <p>
*
* @throws IOException If there is an error closing the socket. * @throws IOException If there is an error closing the socket.
*/ */
public void disconnect() throws IOException public void disconnect() throws IOException {
{
closeQuietly(_socket_); closeQuietly(_socket_);
closeQuietly(_input_); closeQuietly(_input_);
closeQuietly(_output_); closeQuietly(_output_);
@ -329,7 +315,7 @@ public abstract class SocketClient
} }
private void closeQuietly(Socket socket) { private void closeQuietly(Socket socket) {
if (socket != null){ if (socket != null) {
try { try {
socket.close(); socket.close();
} catch (IOException e) { } catch (IOException e) {
@ -338,8 +324,8 @@ public abstract class SocketClient
} }
} }
private void closeQuietly(Closeable close){ private void closeQuietly(Closeable close) {
if (close != null){ if (close != null) {
try { try {
close.close(); close.close();
} catch (IOException e) { } catch (IOException e) {
@ -347,15 +333,16 @@ public abstract class SocketClient
} }
} }
} }
/** /**
* Returns true if the client is currently connected to a server. * Returns true if the client is currently connected to a server.
* <p> * <p>
* Delegates to {@link Socket#isConnected()} * Delegates to {@link Socket#isConnected()}
*
* @return True if the client is currently connected to a server, * @return True if the client is currently connected to a server,
* false otherwise. * false otherwise.
*/ */
public boolean isConnected() public boolean isConnected() {
{
if (_socket_ == null) { if (_socket_ == null) {
return false; return false;
} }
@ -367,14 +354,14 @@ public abstract class SocketClient
* Make various checks on the socket to test if it is available for use. * 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 * Note that the only sure test is to use it, but these checks may help
* in some cases. * in some cases.
* @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a> *
* @return {@code true} if the socket appears to be available for use * @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 * @since 3.0
*/ */
public boolean isAvailable(){ public boolean isAvailable() {
if (isConnected()) { if (isConnected()) {
try try {
{
if (_socket_.getInetAddress() == null) { if (_socket_.getInetAddress() == null) {
return false; return false;
} }
@ -399,9 +386,7 @@ public abstract class SocketClient
/* ignore the result, catch exceptions: */ /* ignore the result, catch exceptions: */
_socket_.getInputStream(); _socket_.getInputStream();
_socket_.getOutputStream(); _socket_.getOutputStream();
} } catch (IOException ioex) {
catch (IOException ioex)
{
return false; return false;
} }
return true; return true;
@ -416,10 +401,10 @@ public abstract class SocketClient
* variable stores this value. If never set, the default port is equal * variable stores this value. If never set, the default port is equal
* to zero. * to zero.
* <p> * <p>
*
* @param port The default port to set. * @param port The default port to set.
*/ */
public void setDefaultPort(int port) public void setDefaultPort(int port) {
{
_defaultPort_ = port; _defaultPort_ = port;
} }
@ -427,14 +412,13 @@ public abstract class SocketClient
* Returns the current value of the default port (stored in * Returns the current value of the default port (stored in
* {@link #_defaultPort_ _defaultPort_ }). * {@link #_defaultPort_ _defaultPort_ }).
* <p> * <p>
*
* @return The current value of the default port. * @return The current value of the default port.
*/ */
public int getDefaultPort() public int getDefaultPort() {
{
return _defaultPort_; return _defaultPort_;
} }
/** /**
* Set the default timeout in milliseconds to use when opening a socket. * Set the default timeout in milliseconds to use when opening a socket.
* This value is only used previous to a call to * This value is only used previous to a call to
@ -443,28 +427,26 @@ public abstract class SocketClient
* which operates on an the currently opened socket. _timeout_ contains * which operates on an the currently opened socket. _timeout_ contains
* the new timeout value. * the new timeout value.
* <p> * <p>
*
* @param timeout The timeout in milliseconds to use for the socket * @param timeout The timeout in milliseconds to use for the socket
* connection. * connection.
*/ */
public void setDefaultTimeout(int timeout) public void setDefaultTimeout(int timeout) {
{
_timeout_ = timeout; _timeout_ = timeout;
} }
/** /**
* Returns the default timeout in milliseconds that is used when * Returns the default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
* <p> * <p>
*
* @return The default timeout in milliseconds that is used when * @return The default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
*/ */
public int getDefaultTimeout() public int getDefaultTimeout() {
{
return _timeout_; return _timeout_;
} }
/** /**
* Set the timeout in milliseconds of a currently open connection. * Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened * Only call this method after a connection has been opened
@ -477,15 +459,14 @@ public abstract class SocketClient
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setSoTimeout(int timeout) throws SocketException public void setSoTimeout(int timeout) throws SocketException {
{
_socket_.setSoTimeout(timeout); _socket_.setSoTimeout(timeout);
} }
/** /**
* Set the underlying socket send buffer size. * Set the underlying socket send buffer size.
* <p> * <p>
*
* @param size The size of the buffer in bytes. * @param size The size of the buffer in bytes.
* @throws SocketException never thrown, but subclasses might want to do so * @throws SocketException never thrown, but subclasses might want to do so
* @since 2.0 * @since 2.0
@ -496,16 +477,18 @@ public abstract class SocketClient
/** /**
* Get the current sendBuffer size * Get the current sendBuffer size
*
* @return the size, or -1 if not initialised * @return the size, or -1 if not initialised
* @since 3.0 * @since 3.0
*/ */
protected int getSendBufferSize(){ protected int getSendBufferSize() {
return sendBufferSize; return sendBufferSize;
} }
/** /**
* Sets the underlying socket receive buffer size. * Sets the underlying socket receive buffer size.
* <p> * <p>
*
* @param size The size of the buffer in bytes. * @param size The size of the buffer in bytes.
* @throws SocketException never (but subclasses may wish to do so) * @throws SocketException never (but subclasses may wish to do so)
* @since 2.0 * @since 2.0
@ -516,22 +499,23 @@ public abstract class SocketClient
/** /**
* Get the current receivedBuffer size * Get the current receivedBuffer size
*
* @return the size, or -1 if not initialised * @return the size, or -1 if not initialised
* @since 3.0 * @since 3.0
*/ */
protected int getReceiveBufferSize(){ protected int getReceiveBufferSize() {
return receiveBufferSize; return receiveBufferSize;
} }
/** /**
* Returns the timeout in milliseconds of the currently opened socket. * Returns the timeout in milliseconds of the currently opened socket.
* <p> * <p>
*
* @return The timeout in milliseconds of the currently opened socket. * @return The timeout in milliseconds of the currently opened socket.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getSoTimeout() throws SocketException public int getSoTimeout() throws SocketException {
{
return _socket_.getSoTimeout(); return _socket_.getSoTimeout();
} }
@ -539,27 +523,26 @@ public abstract class SocketClient
* Enables or disables the Nagle's algorithm (TCP_NODELAY) on the * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
* currently opened socket. * currently opened socket.
* <p> * <p>
*
* @param on True if Nagle's algorithm is to be enabled, false if not. * @param on True if Nagle's algorithm is to be enabled, false if not.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setTcpNoDelay(boolean on) throws SocketException public void setTcpNoDelay(boolean on) throws SocketException {
{
_socket_.setTcpNoDelay(on); _socket_.setTcpNoDelay(on);
} }
/** /**
* Returns true if Nagle's algorithm is enabled on the currently opened * Returns true if Nagle's algorithm is enabled on the currently opened
* socket. * socket.
* <p> * <p>
*
* @return True if Nagle's algorithm is enabled on the currently opened * @return True if Nagle's algorithm is enabled on the currently opened
* socket, false otherwise. * socket, false otherwise.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public boolean getTcpNoDelay() throws SocketException public boolean getTcpNoDelay() throws SocketException {
{
return _socket_.getTcpNoDelay(); return _socket_.getTcpNoDelay();
} }
@ -570,6 +553,7 @@ public abstract class SocketClient
* implementation dependent). It looks as though the Windows WSA sockets implementation * 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 * allows a specific keepalive value to be set, although this seems not to be the case on
* other systems. * other systems.
*
* @param keepAlive If true, keepAlive is turned on * @param keepAlive If true, keepAlive is turned on
* @throws SocketException if there is a problem with the socket * @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
@ -582,6 +566,7 @@ public abstract class SocketClient
/** /**
* Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket.
* Delegates to {@link Socket#getKeepAlive()} * Delegates to {@link Socket#getKeepAlive()}
*
* @return True if SO_KEEPALIVE is enabled. * @return True if SO_KEEPALIVE is enabled.
* @throws SocketException if there is a problem with the socket * @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
@ -594,55 +579,52 @@ public abstract class SocketClient
/** /**
* Sets the SO_LINGER timeout on the currently opened socket. * Sets the SO_LINGER timeout on the currently opened socket.
* <p> * <p>
*
* @param on True if linger is to be enabled, false if not. * @param on True if linger is to be enabled, false if not.
* @param val The linger timeout (in hundredths of a second?) * @param val The linger timeout (in hundredths of a second?)
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setSoLinger(boolean on, int val) throws SocketException public void setSoLinger(boolean on, int val) throws SocketException {
{
_socket_.setSoLinger(on, val); _socket_.setSoLinger(on, val);
} }
/** /**
* Returns the current SO_LINGER timeout of the currently opened socket. * Returns the current SO_LINGER timeout of the currently opened socket.
* <p> * <p>
*
* @return The current SO_LINGER timeout. If SO_LINGER is disabled returns * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns
* -1. * -1.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getSoLinger() throws SocketException public int getSoLinger() throws SocketException {
{
return _socket_.getSoLinger(); return _socket_.getSoLinger();
} }
/** /**
* Returns the port number of the open socket on the local host used * Returns the port number of the open socket on the local host used
* for the connection. * for the connection.
* Delegates to {@link Socket#getLocalPort()} * Delegates to {@link Socket#getLocalPort()}
* <p> * <p>
*
* @return The port number of the open socket on the local host used * @return The port number of the open socket on the local host used
* for the connection. * for the connection.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getLocalPort() public int getLocalPort() {
{
return _socket_.getLocalPort(); return _socket_.getLocalPort();
} }
/** /**
* Returns the local address to which the client's socket is bound. * Returns the local address to which the client's socket is bound.
* Delegates to {@link Socket#getLocalAddress()} * Delegates to {@link Socket#getLocalAddress()}
* <p> * <p>
*
* @return The local address to which the client's socket is bound. * @return The local address to which the client's socket is bound.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public InetAddress getLocalAddress() public InetAddress getLocalAddress() {
{
return _socket_.getLocalAddress(); return _socket_.getLocalAddress();
} }
@ -651,27 +633,24 @@ public abstract class SocketClient
* connected. * connected.
* Delegates to {@link Socket#getPort()} * Delegates to {@link Socket#getPort()}
* <p> * <p>
*
* @return The port number of the remote host to which the client is * @return The port number of the remote host to which the client is
* connected. * connected.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getRemotePort() public int getRemotePort() {
{
return _socket_.getPort(); return _socket_.getPort();
} }
/** /**
* @return The remote address to which the client is connected. * @return The remote address to which the client is connected.
* Delegates to {@link Socket#getInetAddress()} * Delegates to {@link Socket#getInetAddress()}
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public InetAddress getRemoteAddress() public InetAddress getRemoteAddress() {
{
return _socket_.getInetAddress(); return _socket_.getInetAddress();
} }
/** /**
* Verifies that the remote end of the given socket is connected to the * Verifies that the remote end of the given socket is connected to the
* the same host that the SocketClient is currently connected to. This * the same host that the SocketClient is currently connected to. This
@ -679,11 +658,11 @@ public abstract class SocketClient
* accept a connection from a server, such as an FTP data connection or * accept a connection from a server, such as an FTP data connection or
* a BSD R command standard error stream. * a BSD R command standard error stream.
* <p> * <p>
*
* @param socket the item to check against * @param socket the item to check against
* @return True if the remote hosts are the same, false if not. * @return True if the remote hosts are the same, false if not.
*/ */
public boolean verifyRemote(Socket socket) public boolean verifyRemote(Socket socket) {
{
InetAddress host1, host2; InetAddress host1, host2;
host1 = socket.getInetAddress(); host1 = socket.getInetAddress();
@ -692,7 +671,6 @@ public abstract class SocketClient
return host1.equals(host2); return host1.equals(host2);
} }
/** /**
* Sets the SocketFactory used by the SocketClient to open socket * Sets the SocketFactory used by the SocketClient to open socket
* connections. If the factory value is null, then a default * connections. If the factory value is null, then a default
@ -700,10 +678,10 @@ public abstract class SocketClient
* previously altered it). * previously altered it).
* Any proxy setting is discarded. * Any proxy setting is discarded.
* <p> * <p>
*
* @param factory The new SocketFactory the SocketClient should use. * @param factory The new SocketFactory the SocketClient should use.
*/ */
public void setSocketFactory(SocketFactory factory) public void setSocketFactory(SocketFactory factory) {
{
if (factory == null) { if (factory == null) {
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} else { } else {
@ -721,6 +699,7 @@ public abstract class SocketClient
* factory is used (only do this to reset the factory after having * factory is used (only do this to reset the factory after having
* previously altered it). * previously altered it).
* <p> * <p>
*
* @param factory The new ServerSocketFactory the SocketClient should use. * @param factory The new ServerSocketFactory the SocketClient should use.
* @since 2.0 * @since 2.0
*/ */
@ -733,8 +712,10 @@ public abstract class SocketClient
} }
/** /**
* Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket}
* object's
* connect() method. * connect() method.
*
* @param connectTimeout The connection timeout to use (in ms) * @param connectTimeout The connection timeout to use (in ms)
* @since 2.0 * @since 2.0
*/ */
@ -744,6 +725,7 @@ public abstract class SocketClient
/** /**
* Get the underlying socket connection timeout. * Get the underlying socket connection timeout.
*
* @return timeout (in ms) * @return timeout (in ms)
* @since 2.0 * @since 2.0
*/ */
@ -753,6 +735,7 @@ public abstract class SocketClient
/** /**
* Get the underlying {@link ServerSocketFactory} * Get the underlying {@link ServerSocketFactory}
*
* @return The server socket factory * @return The server socket factory
* @since 2.2 * @since 2.2
*/ */
@ -760,7 +743,6 @@ public abstract class SocketClient
return _serverSocketFactory_; return _serverSocketFactory_;
} }
/** /**
* Adds a ProtocolCommandListener. * Adds a ProtocolCommandListener.
* *
@ -810,7 +792,7 @@ public abstract class SocketClient
/** /**
* Create the CommandSupport instance if required * Create the CommandSupport instance if required
*/ */
protected void createCommandSupport(){ protected void createCommandSupport() {
__commandSupport = new ProtocolCommandSupport(this); __commandSupport = new ProtocolCommandSupport(this);
} }
@ -840,6 +822,7 @@ public abstract class SocketClient
/** /**
* Gets the proxy for use with all the connections. * Gets the proxy for use with all the connections.
*
* @return the current proxy for connections. * @return the current proxy for connections.
*/ */
public Proxy getProxy() { public Proxy getProxy() {
@ -853,8 +836,7 @@ public abstract class SocketClient
* @since 3.3 * @since 3.3
* @deprecated Since the code now requires Java 1.6 as a mininmum * @deprecated Since the code now requires Java 1.6 as a mininmum
*/ */
@Deprecated @Deprecated public String getCharsetName() {
public String getCharsetName() {
return charset.name(); return charset.name();
} }

@ -17,7 +17,6 @@
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
/** /**
* This interface adds the aspect of configurability by means of * This interface adds the aspect of configurability by means of
* a supplied FTPClientConfig object to other classes in the * a supplied FTPClientConfig object to other classes in the

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@ -92,8 +93,7 @@ import org.apache.commons.net.io.CRLFLineReader;
* @version $Id: FTP.java 1782546 2017-02-11 00:05:41Z sebb $ * @version $Id: FTP.java 1782546 2017-02-11 00:05:41Z sebb $
***/ ***/
public class FTP extends SocketClient public class FTP extends SocketClient {
{
/*** The default FTP data port (20). ***/ /*** The default FTP data port (20). ***/
public static final int DEFAULT_DATA_PORT = 20; public static final int DEFAULT_DATA_PORT = 20;
/*** The default FTP control port (21). ***/ /*** The default FTP control port (21). ***/
@ -114,7 +114,6 @@ public class FTP extends SocketClient
***/ ***/
public static final int EBCDIC_FILE_TYPE = 1; public static final int EBCDIC_FILE_TYPE = 1;
/*** /***
* A constant used to indicate the file(s) being transferred should * A constant used to indicate the file(s) being transferred should
* be treated as a binary image, i.e., no translations should be * be treated as a binary image, i.e., no translations should be
@ -266,8 +265,7 @@ public class FTP extends SocketClient
* <code>DEFAULT_PORT</code> and initializes internal data structures * <code>DEFAULT_PORT</code> and initializes internal data structures
* for saving FTP reply information. * for saving FTP reply information.
***/ ***/
public FTP() public FTP() {
{
super(); super();
setDefaultPort(DEFAULT_PORT); setDefaultPort(DEFAULT_PORT);
_replyLines = new ArrayList<String>(); _replyLines = new ArrayList<String>();
@ -288,31 +286,30 @@ public class FTP extends SocketClient
// test that the line starts with a digit rather than starting with // test that the line starts with a digit rather than starting with
// the code. // the code.
private boolean __lenientCheck(String line) { private boolean __lenientCheck(String line) {
return (!(line.length() > REPLY_CODE_LEN&& line.charAt(REPLY_CODE_LEN) != '-' && return (!(line.length() > REPLY_CODE_LEN
Character.isDigit(line.charAt(0)))); && line.charAt(REPLY_CODE_LEN) != '-'
&& Character.isDigit(line.charAt(0))));
} }
/** /**
* Get the reply, and pass it to command listeners * Get the reply, and pass it to command listeners
*/ */
private void __getReply() throws IOException private void __getReply() throws IOException {
{
__getReply(true); __getReply(true);
} }
/** /**
* Get the reply, but don't pass it to command listeners. * Get the reply, but don't pass it to command listeners.
* Used for keep-alive processing only. * Used for keep-alive processing only.
* @since 3.0 *
* @throws IOException on error * @throws IOException on error
* @since 3.0
*/ */
protected void __getReplyNoReport() throws IOException protected void __getReplyNoReport() throws IOException {
{
__getReply(false); __getReply(false);
} }
private void __getReply(boolean reportReply) throws IOException private void __getReply(boolean reportReply) throws IOException {
{
int length; int length;
_newReplyString = true; _newReplyString = true;
@ -321,26 +318,21 @@ public class FTP extends SocketClient
String line = _controlInput_.readLine(); String line = _controlInput_.readLine();
if (line == null) { if (line == null) {
throw new FTPConnectionClosedException( throw new FTPConnectionClosedException("Connection closed without indication.");
"Connection closed without indication.");
} }
// In case we run into an anomaly we don't want fatal index exceptions // In case we run into an anomaly we don't want fatal index exceptions
// to be thrown. // to be thrown.
length = line.length(); length = line.length();
if (length < REPLY_CODE_LEN) { if (length < REPLY_CODE_LEN) {
throw new MalformedServerReplyException( throw new MalformedServerReplyException("Truncated server reply: " + line);
"Truncated server reply: " + line);
} }
String code = null; String code = null;
try try {
{
code = line.substring(0, REPLY_CODE_LEN); code = line.substring(0, REPLY_CODE_LEN);
_replyCode = Integer.parseInt(code); _replyCode = Integer.parseInt(code);
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
throw new MalformedServerReplyException( throw new MalformedServerReplyException(
"Could not parse response code.\nServer Reply: " + line); "Could not parse response code.\nServer Reply: " + line);
} }
@ -352,13 +344,11 @@ public class FTP extends SocketClient
char sep = line.charAt(REPLY_CODE_LEN); char sep = line.charAt(REPLY_CODE_LEN);
// Get extra lines if message continues. // Get extra lines if message continues.
if (sep == '-') { if (sep == '-') {
do do {
{
line = _controlInput_.readLine(); line = _controlInput_.readLine();
if (line == null) { if (line == null) {
throw new FTPConnectionClosedException( throw new FTPConnectionClosedException("Connection closed without indication.");
"Connection closed without indication.");
} }
_replyLines.add(line); _replyLines.add(line);
@ -366,18 +356,16 @@ public class FTP extends SocketClient
// The length() check handles problems that could arise from readLine() // The length() check handles problems that could arise from readLine()
// returning too soon after encountering a naked CR or some other // returning too soon after encountering a naked CR or some other
// anomaly. // anomaly.
} } while (isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line));
while ( isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line));
} else if (isStrictReplyParsing()) { } else if (isStrictReplyParsing()) {
if (length == REPLY_CODE_LEN + 1) { // expecting some text if (length == REPLY_CODE_LEN + 1) { // expecting some text
throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
} else if (sep != ' ') { } else if (sep != ' ') {
throw new MalformedServerReplyException("Invalid server reply: '" + line +"'"); throw new MalformedServerReplyException("Invalid server reply: '" + line + "'");
} }
} }
} else if (isStrictReplyParsing()) { } else if (isStrictReplyParsing()) {
throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
} }
if (reportReply) { if (reportReply) {
@ -385,7 +373,8 @@ public class FTP extends SocketClient
} }
if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) {
throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); throw new FTPConnectionClosedException(
"FTP response 421 received. Server closed connection.");
} }
} }
@ -393,13 +382,10 @@ public class FTP extends SocketClient
* Initiates control connections and gets initial reply. * Initiates control connections and gets initial reply.
* Initializes {@link #_controlInput_} and {@link #_controlOutput_}. * Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
*/ */
@Override @Override protected void _connectAction_() throws IOException {
protected void _connectAction_() throws IOException
{
_connectAction_(null); _connectAction_(null);
} }
/** /**
* Initiates control connections and gets initial reply. * Initiates control connections and gets initial reply.
* Initializes {@link #_controlInput_} and {@link #_controlOutput_}. * Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
@ -410,14 +396,12 @@ public class FTP extends SocketClient
*/ */
protected void _connectAction_(Reader socketIsReader) throws IOException { protected void _connectAction_(Reader socketIsReader) throws IOException {
super._connectAction_(); // sets up _input_ and _output_ super._connectAction_(); // sets up _input_ and _output_
if(socketIsReader == null) { if (socketIsReader == null) {
_controlInput_ = _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
} else { } else {
_controlInput_ = new CRLFLineReader(socketIsReader); _controlInput_ = new CRLFLineReader(socketIsReader);
} }
_controlOutput_ = _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
if (connectTimeout > 0) { // NET-385 if (connectTimeout > 0) { // NET-385
int original = _socket_.getSoTimeout(); int original = _socket_.getSoTimeout();
_socket_.setSoTimeout(connectTimeout); _socket_.setSoTimeout(connectTimeout);
@ -443,7 +427,6 @@ public class FTP extends SocketClient
} }
} }
/** /**
* Saves the character encoding to be used by the FTP control connection. * Saves the character encoding to be used by the FTP control connection.
* Some FTP servers require that commands be issued in a non-ASCII * Some FTP servers require that commands be issued in a non-ASCII
@ -458,7 +441,6 @@ public class FTP extends SocketClient
_controlEncoding = encoding; _controlEncoding = encoding;
} }
/** /**
* @return The character encoding used to communicate over the * @return The character encoding used to communicate over the
* control connection. * control connection.
@ -467,7 +449,6 @@ public class FTP extends SocketClient
return _controlEncoding; return _controlEncoding;
} }
/*** /***
* Closes the control connection to the FTP server and sets to null * Closes the control connection to the FTP server and sets to null
* some internal data so that the memory may be reclaimed by the * some internal data so that the memory may be reclaimed by the
@ -477,9 +458,7 @@ public class FTP extends SocketClient
* *
* @throws IOException If an error occurs while disconnecting. * @throws IOException If an error occurs while disconnecting.
***/ ***/
@Override @Override public void disconnect() throws IOException {
public void disconnect() throws IOException
{
super.disconnect(); super.disconnect();
_controlInput_ = null; _controlInput_ = null;
_controlOutput_ = null; _controlOutput_ = null;
@ -487,7 +466,6 @@ public class FTP extends SocketClient
_replyString = null; _replyString = null;
} }
/*** /***
* Sends an FTP command to the server, waits for a reply and returns the * Sends an FTP command to the server, waits for a reply and returns the
* numerical response code. After invocation, for more detailed * numerical response code. After invocation, for more detailed
@ -508,8 +486,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(String command, String args) throws IOException public int sendCommand(String command, String args) throws IOException {
{
if (_controlOutput_ == null) { if (_controlOutput_ == null) {
throw new IOException("Connection is not open"); throw new IOException("Connection is not open");
} }
@ -529,8 +506,7 @@ public class FTP extends SocketClient
__commandBuffer.append(command); __commandBuffer.append(command);
if (args != null) if (args != null) {
{
__commandBuffer.append(' '); __commandBuffer.append(' ');
__commandBuffer.append(args); __commandBuffer.append(args);
} }
@ -538,20 +514,15 @@ public class FTP extends SocketClient
return __commandBuffer.toString(); return __commandBuffer.toString();
} }
private void __send(String message) throws IOException, private void __send(String message)
FTPConnectionClosedException, SocketException { throws IOException, FTPConnectionClosedException, SocketException {
try{ try {
_controlOutput_.write(message); _controlOutput_.write(message);
_controlOutput_.flush(); _controlOutput_.flush();
} } catch (SocketException e) {
catch (SocketException e) if (!isConnected()) {
{
if (!isConnected())
{
throw new FTPConnectionClosedException("Connection unexpectedly closed."); throw new FTPConnectionClosedException("Connection unexpectedly closed.");
} } else {
else
{
throw e; throw e;
} }
} }
@ -592,9 +563,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead
***/ ***/
@Deprecated @Deprecated public int sendCommand(int command, String args) throws IOException {
public int sendCommand(int command, String args) throws IOException
{
return sendCommand(FTPCommand.getCommand(command), args); return sendCommand(FTPCommand.getCommand(command), args);
} }
@ -609,8 +578,8 @@ public class FTP extends SocketClient
* to send. * to send.
* @return The integer value of the FTP reply code returned by the server * @return The integer value of the FTP reply code returned by the server
* in response to the command. * in response to the command.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -618,7 +587,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.3 * @since 3.3
*/ */
public int sendCommand(FTPCmd command) throws IOException{ public int sendCommand(FTPCmd command) throws IOException {
return sendCommand(command, null); return sendCommand(command, null);
} }
@ -635,8 +604,8 @@ public class FTP extends SocketClient
* set to null, then the command is sent with no argument. * set to null, then the command is sent with no argument.
* @return The integer value of the FTP reply code returned by the server * @return The integer value of the FTP reply code returned by the server
* in response to the command. * in response to the command.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -644,7 +613,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.3 * @since 3.3
*/ */
public int sendCommand(FTPCmd command, String args) throws IOException{ public int sendCommand(FTPCmd command, String args) throws IOException {
return sendCommand(command.getCommand(), args); return sendCommand(command.getCommand(), args);
} }
@ -666,12 +635,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(String command) throws IOException public int sendCommand(String command) throws IOException {
{
return sendCommand(command, null); return sendCommand(command, null);
} }
/*** /***
* Sends an FTP command with no arguments to the server, waits for a * Sends an FTP command with no arguments to the server, waits for a
* reply and returns the numerical response code. After invocation, for * reply and returns the numerical response code. After invocation, for
@ -691,12 +658,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(int command) throws IOException public int sendCommand(int command) throws IOException {
{
return sendCommand(command, null); return sendCommand(command, null);
} }
/*** /***
* Returns the integer value of the reply code of the last FTP reply. * Returns the integer value of the reply code of the last FTP reply.
* You will usually only use this method after you connect to the * You will usually only use this method after you connect to the
@ -705,8 +670,7 @@ public class FTP extends SocketClient
* *
* @return The integer value of the reply code of the last FTP reply. * @return The integer value of the reply code of the last FTP reply.
***/ ***/
public int getReplyCode() public int getReplyCode() {
{
return _replyCode; return _replyCode;
} }
@ -727,13 +691,11 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while receiving the * @throws IOException If an I/O error occurs while receiving the
* server reply. * server reply.
***/ ***/
public int getReply() throws IOException public int getReply() throws IOException {
{
__getReply(); __getReply();
return _replyCode; return _replyCode;
} }
/*** /***
* Returns the lines of text from the last FTP server response as an array * Returns the lines of text from the last FTP server response as an array
* of strings, one entry per line. The end of line markers of each are * of strings, one entry per line. The end of line markers of each are
@ -741,8 +703,7 @@ public class FTP extends SocketClient
* *
* @return The lines of text from the last FTP response as an array. * @return The lines of text from the last FTP response as an array.
***/ ***/
public String[] getReplyStrings() public String[] getReplyStrings() {
{
return _replyLines.toArray(new String[_replyLines.size()]); return _replyLines.toArray(new String[_replyLines.size()]);
} }
@ -753,8 +714,7 @@ public class FTP extends SocketClient
* *
* @return The entire text from the last FTP response as a String. * @return The entire text from the last FTP response as a String.
***/ ***/
public String getReplyString() public String getReplyString() {
{
StringBuilder buffer; StringBuilder buffer;
if (!_newReplyString) { if (!_newReplyString) {
@ -773,7 +733,6 @@ public class FTP extends SocketClient
return (_replyString = buffer.toString()); return (_replyString = buffer.toString());
} }
/*** /***
* A convenience method to send the FTP USER command to the server, * A convenience method to send the FTP USER command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -788,26 +747,25 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int user(String username) throws IOException public int user(String username) throws IOException {
{
return sendCommand(FTPCmd.USER, username); return sendCommand(FTPCmd.USER, username);
} }
/** /**
* A convenience method to send the FTP PASS command to the server, * A convenience method to send the FTP PASS command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
*
* @param password The plain text password of the username being logged into. * @param password The plain text password of the username being logged into.
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int pass(String password) throws IOException public int pass(String password) throws IOException {
{
return sendCommand(FTPCmd.PASS, password); return sendCommand(FTPCmd.PASS, password);
} }
@ -825,12 +783,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int acct(String account) throws IOException public int acct(String account) throws IOException {
{
return sendCommand(FTPCmd.ACCT, account); return sendCommand(FTPCmd.ACCT, account);
} }
/*** /***
* A convenience method to send the FTP ABOR command to the server, * A convenience method to send the FTP ABOR command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -844,8 +800,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int abor() throws IOException public int abor() throws IOException {
{
return sendCommand(FTPCmd.ABOR); return sendCommand(FTPCmd.ABOR);
} }
@ -863,8 +818,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int cwd(String directory) throws IOException public int cwd(String directory) throws IOException {
{
return sendCommand(FTPCmd.CWD, directory); return sendCommand(FTPCmd.CWD, directory);
} }
@ -881,8 +835,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int cdup() throws IOException public int cdup() throws IOException {
{
return sendCommand(FTPCmd.CDUP); return sendCommand(FTPCmd.CDUP);
} }
@ -899,8 +852,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int quit() throws IOException public int quit() throws IOException {
{
return sendCommand(FTPCmd.QUIT); return sendCommand(FTPCmd.QUIT);
} }
@ -917,8 +869,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rein() throws IOException public int rein() throws IOException {
{
return sendCommand(FTPCmd.REIN); return sendCommand(FTPCmd.REIN);
} }
@ -936,8 +887,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int smnt(String dir) throws IOException public int smnt(String dir) throws IOException {
{
return sendCommand(FTPCmd.SMNT, dir); return sendCommand(FTPCmd.SMNT, dir);
} }
@ -956,8 +906,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int port(InetAddress host, int port) throws IOException public int port(InetAddress host, int port) throws IOException {
{
int num; int num;
StringBuilder info = new StringBuilder(24); StringBuilder info = new StringBuilder(24);
@ -996,8 +945,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
***/ ***/
public int eprt(InetAddress host, int port) throws IOException public int eprt(InetAddress host, int port) throws IOException {
{
int num; int num;
StringBuilder info = new StringBuilder(); StringBuilder info = new StringBuilder();
String h; String h;
@ -1040,8 +988,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int pasv() throws IOException public int pasv() throws IOException {
{
return sendCommand(FTPCmd.PASV); return sendCommand(FTPCmd.PASV);
} }
@ -1061,30 +1008,29 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
***/ ***/
public int epsv() throws IOException public int epsv() throws IOException {
{
return sendCommand(FTPCmd.EPSV); return sendCommand(FTPCmd.EPSV);
} }
/** /**
* A convenience method to send the FTP TYPE command for text files * A convenience method to send the FTP TYPE command for text files
* to the server, receive the reply, and return the reply code. * to the server, receive the reply, and return the reply code.
*
* @param fileType The type of the file (one of the <code>FILE_TYPE</code> * @param fileType The type of the file (one of the <code>FILE_TYPE</code>
* constants). * constants).
* @param formatOrByteSize The format of the file (one of the * @param formatOrByteSize The format of the file (one of the
* <code>_FORMAT</code> constants. In the case of * <code>_FORMAT</code> constants. In the case of
* <code>LOCAL_FILE_TYPE</code>, the byte size. * <code>LOCAL_FILE_TYPE</code>, the byte size.
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int type(int fileType, int formatOrByteSize) throws IOException public int type(int fileType, int formatOrByteSize) throws IOException {
{
StringBuilder arg = new StringBuilder(); StringBuilder arg = new StringBuilder();
arg.append(__modes.charAt(fileType)); arg.append(__modes.charAt(fileType));
@ -1098,7 +1044,6 @@ public class FTP extends SocketClient
return sendCommand(FTPCmd.TYPE, arg.toString()); return sendCommand(FTPCmd.TYPE, arg.toString());
} }
/** /**
* A convenience method to send the FTP TYPE command to the server, * A convenience method to send the FTP TYPE command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1106,18 +1051,16 @@ public class FTP extends SocketClient
* @param fileType The type of the file (one of the <code>FILE_TYPE</code> * @param fileType The type of the file (one of the <code>FILE_TYPE</code>
* constants). * constants).
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int type(int fileType) throws IOException public int type(int fileType) throws IOException {
{ return sendCommand(FTPCmd.TYPE, __modes.substring(fileType, fileType + 1));
return sendCommand(FTPCmd.TYPE,
__modes.substring(fileType, fileType + 1));
} }
/*** /***
@ -1135,10 +1078,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stru(int structure) throws IOException public int stru(int structure) throws IOException {
{ return sendCommand(FTPCmd.STRU, __modes.substring(structure, structure + 1));
return sendCommand(FTPCmd.STRU,
__modes.substring(structure, structure + 1));
} }
/*** /***
@ -1156,10 +1097,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int mode(int mode) throws IOException public int mode(int mode) throws IOException {
{ return sendCommand(FTPCmd.MODE, __modes.substring(mode, mode + 1));
return sendCommand(FTPCmd.MODE,
__modes.substring(mode, mode + 1));
} }
/*** /***
@ -1179,8 +1118,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int retr(String pathname) throws IOException public int retr(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RETR, pathname); return sendCommand(FTPCmd.RETR, pathname);
} }
@ -1202,8 +1140,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stor(String pathname) throws IOException public int stor(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STOR, pathname); return sendCommand(FTPCmd.STOR, pathname);
} }
@ -1223,8 +1160,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stou() throws IOException public int stou() throws IOException {
{
return sendCommand(FTPCmd.STOU); return sendCommand(FTPCmd.STOU);
} }
@ -1246,8 +1182,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int stou(String pathname) throws IOException public int stou(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STOU, pathname); return sendCommand(FTPCmd.STOU, pathname);
} }
@ -1269,8 +1204,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int appe(String pathname) throws IOException public int appe(String pathname) throws IOException {
{
return sendCommand(FTPCmd.APPE, pathname); return sendCommand(FTPCmd.APPE, pathname);
} }
@ -1288,21 +1222,20 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int allo(int bytes) throws IOException public int allo(int bytes) throws IOException {
{
return sendCommand(FTPCmd.ALLO, Integer.toString(bytes)); return sendCommand(FTPCmd.ALLO, Integer.toString(bytes));
} }
/** /**
* A convenience method to send the FTP FEAT command to the server, receive the reply, * A convenience method to send the FTP FEAT command to the server, receive the reply,
* and return the reply code. * and return the reply code.
*
* @return The reply code received by the server * @return The reply code received by the server
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
*/ */
public int feat() throws IOException public int feat() throws IOException {
{
return sendCommand(FTPCmd.FEAT); return sendCommand(FTPCmd.FEAT);
} }
@ -1321,10 +1254,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int allo(int bytes, int recordSize) throws IOException public int allo(int bytes, int recordSize) throws IOException {
{ return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + Integer.toString(recordSize));
return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " +
Integer.toString(recordSize));
} }
/*** /***
@ -1341,24 +1272,20 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rest(String marker) throws IOException public int rest(String marker) throws IOException {
{
return sendCommand(FTPCmd.REST, marker); return sendCommand(FTPCmd.REST, marker);
} }
/** /**
* @param file name of file * @param file name of file
* @return the status * @return the status
* @throws IOException on error * @throws IOException on error
* @since 2.0 * @since 2.0
**/ **/
public int mdtm(String file) throws IOException public int mdtm(String file) throws IOException {
{
return sendCommand(FTPCmd.MDTM, file); return sendCommand(FTPCmd.MDTM, file);
} }
/** /**
* A convenience method to send the FTP MFMT command to the server, * A convenience method to send the FTP MFMT command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1366,22 +1293,20 @@ public class FTP extends SocketClient
* @param pathname The pathname for which mtime is to be changed * @param pathname The pathname for which mtime is to be changed
* @param timeval Timestamp in <code>YYYYMMDDhhmmss</code> format * @param timeval Timestamp in <code>YYYYMMDDhhmmss</code> format
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2
* @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a> * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
* @since 2.2
**/ **/
public int mfmt(String pathname, String timeval) throws IOException public int mfmt(String pathname, String timeval) throws IOException {
{
return sendCommand(FTPCmd.MFMT, timeval + " " + pathname); return sendCommand(FTPCmd.MFMT, timeval + " " + pathname);
} }
/*** /***
* A convenience method to send the FTP RNFR command to the server, * A convenience method to send the FTP RNFR command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1396,8 +1321,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rnfr(String pathname) throws IOException public int rnfr(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RNFR, pathname); return sendCommand(FTPCmd.RNFR, pathname);
} }
@ -1415,8 +1339,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rnto(String pathname) throws IOException public int rnto(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RNTO, pathname); return sendCommand(FTPCmd.RNTO, pathname);
} }
@ -1434,8 +1357,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int dele(String pathname) throws IOException public int dele(String pathname) throws IOException {
{
return sendCommand(FTPCmd.DELE, pathname); return sendCommand(FTPCmd.DELE, pathname);
} }
@ -1453,8 +1375,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rmd(String pathname) throws IOException public int rmd(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RMD, pathname); return sendCommand(FTPCmd.RMD, pathname);
} }
@ -1472,8 +1393,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int mkd(String pathname) throws IOException public int mkd(String pathname) throws IOException {
{
return sendCommand(FTPCmd.MKD, pathname); return sendCommand(FTPCmd.MKD, pathname);
} }
@ -1490,8 +1410,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int pwd() throws IOException public int pwd() throws IOException {
{
return sendCommand(FTPCmd.PWD); return sendCommand(FTPCmd.PWD);
} }
@ -1511,8 +1430,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int list() throws IOException public int list() throws IOException {
{
return sendCommand(FTPCmd.LIST); return sendCommand(FTPCmd.LIST);
} }
@ -1534,8 +1452,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int list(String pathname) throws IOException public int list(String pathname) throws IOException {
{
return sendCommand(FTPCmd.LIST, pathname); return sendCommand(FTPCmd.LIST, pathname);
} }
@ -1547,8 +1464,8 @@ public class FTP extends SocketClient
* , which will handle all low level details for you. * , which will handle all low level details for you.
* *
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1556,8 +1473,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlsd() throws IOException public int mlsd() throws IOException {
{
return sendCommand(FTPCmd.MLSD); return sendCommand(FTPCmd.MLSD);
} }
@ -1571,8 +1487,8 @@ public class FTP extends SocketClient
* @param path the path to report on * @param path the path to report on
* @return The reply code received from the server, * @return The reply code received from the server,
* may be {@code null} in which case the command is sent with no parameters * may be {@code null} in which case the command is sent with no parameters
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1580,8 +1496,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlsd(String path) throws IOException public int mlsd(String path) throws IOException {
{
return sendCommand(FTPCmd.MLSD, path); return sendCommand(FTPCmd.MLSD, path);
} }
@ -1593,8 +1508,8 @@ public class FTP extends SocketClient
* , which will handle all low level details for you. * , which will handle all low level details for you.
* *
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1602,8 +1517,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlst() throws IOException public int mlst() throws IOException {
{
return sendCommand(FTPCmd.MLST); return sendCommand(FTPCmd.MLST);
} }
@ -1617,8 +1531,8 @@ public class FTP extends SocketClient
* @param path the path to report on * @param path the path to report on
* @return The reply code received from the server, * @return The reply code received from the server,
* may be {@code null} in which case the command is sent with no parameters * may be {@code null} in which case the command is sent with no parameters
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1626,8 +1540,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlst(String path) throws IOException public int mlst(String path) throws IOException {
{
return sendCommand(FTPCmd.MLST, path); return sendCommand(FTPCmd.MLST, path);
} }
@ -1647,8 +1560,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int nlst() throws IOException public int nlst() throws IOException {
{
return sendCommand(FTPCmd.NLST); return sendCommand(FTPCmd.NLST);
} }
@ -1670,8 +1582,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int nlst(String pathname) throws IOException public int nlst(String pathname) throws IOException {
{
return sendCommand(FTPCmd.NLST, pathname); return sendCommand(FTPCmd.NLST, pathname);
} }
@ -1689,8 +1600,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int site(String parameters) throws IOException public int site(String parameters) throws IOException {
{
return sendCommand(FTPCmd.SITE, parameters); return sendCommand(FTPCmd.SITE, parameters);
} }
@ -1707,8 +1617,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int syst() throws IOException public int syst() throws IOException {
{
return sendCommand(FTPCmd.SYST); return sendCommand(FTPCmd.SYST);
} }
@ -1725,8 +1634,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stat() throws IOException public int stat() throws IOException {
{
return sendCommand(FTPCmd.STAT); return sendCommand(FTPCmd.STAT);
} }
@ -1744,8 +1652,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stat(String pathname) throws IOException public int stat(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STAT, pathname); return sendCommand(FTPCmd.STAT, pathname);
} }
@ -1762,8 +1669,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int help() throws IOException public int help() throws IOException {
{
return sendCommand(FTPCmd.HELP); return sendCommand(FTPCmd.HELP);
} }
@ -1781,8 +1687,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int help(String command) throws IOException public int help(String command) throws IOException {
{
return sendCommand(FTPCmd.HELP, command); return sendCommand(FTPCmd.HELP, command);
} }
@ -1799,13 +1704,13 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int noop() throws IOException public int noop() throws IOException {
{
return sendCommand(FTPCmd.NOOP); return sendCommand(FTPCmd.NOOP);
} }
/** /**
* Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2. * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2.
*
* @return True if strict, false if lenient * @return True if strict, false if lenient
* @since 2.0 * @since 2.0
*/ */
@ -1815,6 +1720,7 @@ public class FTP extends SocketClient
/** /**
* Set strict multiline parsing. * Set strict multiline parsing.
*
* @param strictMultilineParsing the setting * @param strictMultilineParsing the setting
* @since 2.0 * @since 2.0
*/ */
@ -1829,6 +1735,7 @@ public class FTP extends SocketClient
* <br> * <br>
* If false, only the 3 digit code is required (as was the case for versions up to 3.5) * If false, only the 3 digit code is required (as was the case for versions up to 3.5)
* <br> * <br>
*
* @return True if strict (default), false if additional checks are not made * @return True if strict (default), false if additional checks are not made
* @since 3.6 * @since 3.6
*/ */
@ -1845,6 +1752,7 @@ public class FTP extends SocketClient
* <p> * <p>
* <b>This should not be required by a well-behaved FTP server</b> * <b>This should not be required by a well-behaved FTP server</b>
* <br> * <br>
*
* @param strictReplyParsing the setting * @param strictReplyParsing the setting
* @since 3.6 * @since 3.6
*/ */
@ -1855,8 +1763,7 @@ public class FTP extends SocketClient
/** /**
* Provide command support to super-class * Provide command support to super-class
*/ */
@Override @Override protected ProtocolCommandSupport getCommandSupport() {
protected ProtocolCommandSupport getCommandSupport() {
return _commandSupport_; return _commandSupport_;
} }
} }

@ -129,14 +129,13 @@ import java.util.TreeMap;
* FTPFile[] files = listFiles(directory); * FTPFile[] files = listFiles(directory);
* </pre> * </pre>
* *
* @since 1.4
* @see Configurable * @see Configurable
* @see FTPClient * @see FTPClient
* @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig)
* @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl
* @since 1.4
*/ */
public class FTPClientConfig public class FTPClientConfig {
{
/** /**
* Identifier by which a unix-based ftp server is known throughout * Identifier by which a unix-based ftp server is known throughout
@ -149,6 +148,7 @@ public class FTPClientConfig
* trimmed from file names. This is to maintain backwards compatibility with * trimmed from file names. This is to maintain backwards compatibility with
* the original behaviour of the parser which ignored multiple spaces between the date * the original behaviour of the parser which ignored multiple spaces between the date
* and the start of the file name. * and the start of the file name.
*
* @since 3.4 * @since 3.4
*/ */
public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM";
@ -228,9 +228,9 @@ public class FTPClientConfig
private String serverTimeZoneId = null; private String serverTimeZoneId = null;
private boolean saveUnparseableEntries = false; private boolean saveUnparseableEntries = false;
/** /**
* The main constructor for an FTPClientConfig object * The main constructor for an FTPClientConfig object
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See {@link #getServerSystemKey() serverSystemKey} * connected to. See {@link #getServerSystemKey() serverSystemKey}
* If set to the empty string, then FTPClient uses the system type returned by the server. * If set to the empty string, then FTPClient uses the system type returned by the server.
@ -251,6 +251,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of the format string member fields * Constructor which allows setting of the format string member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -260,10 +261,8 @@ public class FTPClientConfig
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} * {@link #setRecentDateFormatStr(String) recentDateFormatStr}
* @since 3.6 * @since 3.6
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr,
String defaultDateFormatStr, String recentDateFormatStr) {
String recentDateFormatStr)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.recentDateFormatStr = recentDateFormatStr; this.recentDateFormatStr = recentDateFormatStr;
@ -271,6 +270,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of most member fields * Constructor which allows setting of most member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -285,13 +285,8 @@ public class FTPClientConfig
* @param serverTimeZoneId See * @param serverTimeZoneId See
* {@link #setServerTimeZoneId(String) serverTimeZoneId} * {@link #setServerTimeZoneId(String) serverTimeZoneId}
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr,
String defaultDateFormatStr, String serverLanguageCode, String shortMonthNames, String serverTimeZoneId) {
String recentDateFormatStr,
String serverLanguageCode,
String shortMonthNames,
String serverTimeZoneId)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.recentDateFormatStr = recentDateFormatStr; this.recentDateFormatStr = recentDateFormatStr;
@ -302,6 +297,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of all member fields * Constructor which allows setting of all member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -320,15 +316,9 @@ public class FTPClientConfig
* @param saveUnparseableEntries See * @param saveUnparseableEntries See
* {@link #setUnparseableEntries(boolean) saveUnparseableEntries} * {@link #setUnparseableEntries(boolean) saveUnparseableEntries}
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr,
String defaultDateFormatStr, String serverLanguageCode, String shortMonthNames, String serverTimeZoneId,
String recentDateFormatStr, boolean lenientFutureDates, boolean saveUnparseableEntries) {
String serverLanguageCode,
String shortMonthNames,
String serverTimeZoneId,
boolean lenientFutureDates,
boolean saveUnparseableEntries)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.lenientFutureDates = lenientFutureDates; this.lenientFutureDates = lenientFutureDates;
@ -353,6 +343,7 @@ public class FTPClientConfig
/** /**
* Copy constructor * Copy constructor
*
* @param config source * @param config source
* @since 3.6 * @since 3.6
*/ */
@ -368,18 +359,17 @@ public class FTPClientConfig
} }
private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<String, Object>(); private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<String, Object>();
static { static {
// if there are other commonly used month name encodings which // if there are other commonly used month name encodings which
// correspond to particular locales, please add them here. // correspond to particular locales, please add them here.
// many locales code short names for months as all three letters // many locales code short names for months as all three letters
// these we handle simply. // these we handle simply.
LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH);
LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); LANGUAGE_CODE_MAP.put("de", Locale.GERMAN);
LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); LANGUAGE_CODE_MAP.put("it", Locale.ITALIAN);
LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish
LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese
LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish
@ -392,11 +382,9 @@ public class FTPClientConfig
LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak
LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian
// some don't // some don't
LANGUAGE_CODE_MAP.put("fr", LANGUAGE_CODE_MAP.put("fr",
"jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french
} }
/** /**
@ -406,6 +394,7 @@ public class FTPClientConfig
* or else the fully qualified class name of a parser implementing both * or else the fully qualified class name of a parser implementing both
* the <code>FTPFileEntryParser</code> and <code>Configurable</code> * the <code>FTPFileEntryParser</code> and <code>Configurable</code>
* interfaces. * interfaces.
*
* @return Returns the serverSystemKey property. * @return Returns the serverSystemKey property.
*/ */
public String getServerSystemKey() { public String getServerSystemKey() {
@ -415,6 +404,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr}
* property. * property.
*
* @return Returns the defaultDateFormatStr property. * @return Returns the defaultDateFormatStr property.
*/ */
public String getDefaultDateFormatStr() { public String getDefaultDateFormatStr() {
@ -423,6 +413,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property.
*
* @return Returns the recentDateFormatStr property. * @return Returns the recentDateFormatStr property.
*/ */
@ -432,6 +423,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property.
*
* @return Returns the serverTimeZoneId property. * @return Returns the serverTimeZoneId property.
*/ */
public String getServerTimeZoneId() { public String getServerTimeZoneId() {
@ -443,6 +435,7 @@ public class FTPClientConfig
* getter for the {@link #setShortMonthNames(String) shortMonthNames} * getter for the {@link #setShortMonthNames(String) shortMonthNames}
* property. * property.
* </p> * </p>
*
* @return Returns the shortMonthNames. * @return Returns the shortMonthNames.
*/ */
public String getShortMonthNames() { public String getShortMonthNames() {
@ -453,6 +446,7 @@ public class FTPClientConfig
* <p> * <p>
* getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property.
* </p> * </p>
*
* @return Returns the serverLanguageCode property. * @return Returns the serverLanguageCode property.
*/ */
public String getServerLanguageCode() { public String getServerLanguageCode() {
@ -463,12 +457,14 @@ public class FTPClientConfig
* <p> * <p>
* getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property.
* </p> * </p>
*
* @return Returns the lenientFutureDates. * @return Returns the lenientFutureDates.
* @since 1.5 * @since 1.5
*/ */
public boolean isLenientFutureDates() { public boolean isLenientFutureDates() {
return lenientFutureDates; return lenientFutureDates;
} }
/** /**
* <p> * <p>
* setter for the defaultDateFormatStr property. This property * setter for the defaultDateFormatStr property. This property
@ -481,6 +477,7 @@ public class FTPClientConfig
* <code>java.text.SimpleDateFormat</code>. * <code>java.text.SimpleDateFormat</code>.
* property. * property.
* </p> * </p>
*
* @param defaultDateFormatStr The defaultDateFormatStr to set. * @param defaultDateFormatStr The defaultDateFormatStr to set.
*/ */
public void setDefaultDateFormatStr(String defaultDateFormatStr) { public void setDefaultDateFormatStr(String defaultDateFormatStr) {
@ -502,6 +499,7 @@ public class FTPClientConfig
* This should be in the format described for * This should be in the format described for
* <code>java.text.SimpleDateFormat</code>. * <code>java.text.SimpleDateFormat</code>.
* </p> * </p>
*
* @param recentDateFormatStr The recentDateFormatStr to set. * @param recentDateFormatStr The recentDateFormatStr to set.
*/ */
public void setRecentDateFormatStr(String recentDateFormatStr) { public void setRecentDateFormatStr(String recentDateFormatStr) {
@ -525,12 +523,14 @@ public class FTPClientConfig
* </p><p> * </p><p>
* This is used primarily in unix-based systems. * This is used primarily in unix-based systems.
* </p> * </p>
*
* @param lenientFutureDates set true to compensate for out-of-synch * @param lenientFutureDates set true to compensate for out-of-synch
* conditions. * conditions.
*/ */
public void setLenientFutureDates(boolean lenientFutureDates) { public void setLenientFutureDates(boolean lenientFutureDates) {
this.lenientFutureDates = lenientFutureDates; this.lenientFutureDates = lenientFutureDates;
} }
/** /**
* <p> * <p>
* setter for the serverTimeZoneId property. This property * setter for the serverTimeZoneId property. This property
@ -543,6 +543,7 @@ public class FTPClientConfig
* <code>java.util.TimeZone</code> to refer to time zones, for example, * <code>java.util.TimeZone</code> to refer to time zones, for example,
* <code>America/Chicago</code> or <code>Asia/Rangoon</code>. * <code>America/Chicago</code> or <code>Asia/Rangoon</code>.
* </p> * </p>
*
* @param serverTimeZoneId The serverTimeZoneId to set. * @param serverTimeZoneId The serverTimeZoneId to set.
*/ */
public void setServerTimeZoneId(String serverTimeZoneId) { public void setServerTimeZoneId(String serverTimeZoneId) {
@ -564,6 +565,7 @@ public class FTPClientConfig
* conceivably be specified as * conceivably be specified as
* <code>"jan|feb|mar|apr|ma&#xED;|j&#xFA;n|j&#xFA;l|&#xE1;g&#xFA;|sep|okt|n&#xF3;v|des"</code>. * <code>"jan|feb|mar|apr|ma&#xED;|j&#xFA;n|j&#xFA;l|&#xE1;g&#xFA;|sep|okt|n&#xF3;v|des"</code>.
* </p> * </p>
*
* @param shortMonthNames The value to set to the shortMonthNames property. * @param shortMonthNames The value to set to the shortMonthNames property.
*/ */
public void setShortMonthNames(String shortMonthNames) { public void setShortMonthNames(String shortMonthNames) {
@ -608,6 +610,7 @@ public class FTPClientConfig
* via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters.
* </p> * </p>
*
* @param serverLanguageCode The value to set to the serverLanguageCode property. * @param serverLanguageCode The value to set to the serverLanguageCode property.
*/ */
public void setServerLanguageCode(String serverLanguageCode) { public void setServerLanguageCode(String serverLanguageCode) {
@ -620,19 +623,19 @@ public class FTPClientConfig
* short month names corresponding to the code. If there is no corresponding * short month names corresponding to the code. If there is no corresponding
* entry in the table, the object returned will be that for * entry in the table, the object returned will be that for
* <code>Locale.US</code> * <code>Locale.US</code>
*
* @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode}
* @return a DateFormatSymbols object configured with short month names * @return a DateFormatSymbols object configured with short month names
* corresponding to the supplied code, or with month names for * corresponding to the supplied code, or with month names for
* <code>Locale.US</code> if there is no corresponding entry in the internal * <code>Locale.US</code> if there is no corresponding entry in the internal
* table. * table.
*/ */
public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) {
{
Object lang = LANGUAGE_CODE_MAP.get(languageCode); Object lang = LANGUAGE_CODE_MAP.get(languageCode);
if (lang != null) { if (lang != null) {
if (lang instanceof Locale) { if (lang instanceof Locale) {
return new DateFormatSymbols((Locale) lang); return new DateFormatSymbols((Locale) lang);
} else if (lang instanceof String){ } else if (lang instanceof String) {
return getDateFormatSymbols((String) lang); return getDateFormatSymbols((String) lang);
} }
} }
@ -642,13 +645,13 @@ public class FTPClientConfig
/** /**
* Returns a DateFormatSymbols object configured with short month names * Returns a DateFormatSymbols object configured with short month names
* as in the supplied string * as in the supplied string
*
* @param shortmonths This should be as described in * @param shortmonths This should be as described in
* {@link #setShortMonthNames(String) shortMonthNames} * {@link #setShortMonthNames(String) shortMonthNames}
* @return a DateFormatSymbols object configured with short month names * @return a DateFormatSymbols object configured with short month names
* as in the supplied string * as in the supplied string
*/ */
public static DateFormatSymbols getDateFormatSymbols(String shortmonths) public static DateFormatSymbols getDateFormatSymbols(String shortmonths) {
{
String[] months = splitShortMonthString(shortmonths); String[] months = splitShortMonthString(shortmonths);
DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); DateFormatSymbols dfs = new DateFormatSymbols(Locale.US);
dfs.setShortMonths(months); dfs.setShortMonths(months);
@ -659,15 +662,14 @@ public class FTPClientConfig
StringTokenizer st = new StringTokenizer(shortmonths, "|"); StringTokenizer st = new StringTokenizer(shortmonths, "|");
int monthcnt = st.countTokens(); int monthcnt = st.countTokens();
if (12 != monthcnt) { if (12 != monthcnt) {
throw new IllegalArgumentException( throw new IllegalArgumentException("expecting a pipe-delimited string containing 12 tokens");
"expecting a pipe-delimited string containing 12 tokens");
} }
String[] months = new String[13]; String[] months = new String[13];
int pos = 0; int pos = 0;
while(st.hasMoreTokens()) { while (st.hasMoreTokens()) {
months[pos++] = st.nextToken(); months[pos++] = st.nextToken();
} }
months[pos]=""; months[pos] = "";
return months; return months;
} }
@ -688,6 +690,7 @@ public class FTPClientConfig
* <p> * <p>
* In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} * In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()}
* and {@link FTPFile#isValid()} will return {@code false} * and {@link FTPFile#isValid()} will return {@code false}
*
* @param saveUnparseable if true, then create FTPFile entries if parsing fails * @param saveUnparseable if true, then create FTPFile entries if parsing fails
* @since 3.4 * @since 3.4
*/ */
@ -705,5 +708,4 @@ public class FTPClientConfig
public boolean getUnparseableEntries() { public boolean getUnparseableEntries() {
return this.saveUnparseableEntries; return this.saveUnparseableEntries;
} }
} }

@ -19,50 +19,10 @@
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
/** /**
* @since 3.3 * @since 3.3
*/ */
public enum FTPCmd { public enum FTPCmd {
ABOR, 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,;
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 // Aliases
@ -108,8 +68,7 @@ public enum FTPCmd {
* @return The FTP protcol command string corresponding to a specified * @return The FTP protcol command string corresponding to a specified
* command code. * command code.
*/ */
public final String getCommand() public final String getCommand() {
{
return this.name(); return this.name();
} }

@ -27,9 +27,7 @@ package org.apache.commons.net.ftp;
* *
* @deprecated use {@link FTPCmd} instead * @deprecated use {@link FTPCmd} instead
*/ */
@Deprecated @Deprecated public final class FTPCommand {
public final class FTPCommand
{
public static final int USER = 0; public static final int USER = 0;
public static final int PASS = 1; public static final int PASS = 1;
@ -77,12 +75,14 @@ public final class FTPCommand
/** /**
* Machine parseable list for a directory * Machine parseable list for a directory
*
* @since 3.0 * @since 3.0
*/ */
public static final int MLSD = 38; public static final int MLSD = 38;
/** /**
* Machine parseable list for a single file * Machine parseable list for a single file
*
* @since 3.0 * @since 3.0
*/ */
public static final int MLST = 39; public static final int MLST = 39;
@ -135,24 +135,24 @@ public final class FTPCommand
public static final int SET_MOD_TIME = MFMT; public static final int SET_MOD_TIME = MFMT;
// Cannot be instantiated // Cannot be instantiated
private FTPCommand() private FTPCommand() {
{} }
private static final String[] _commands = { private static final String[] _commands = {
"USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "PASV", "TYPE", "STRU",
"PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD",
"REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", "MKD", "PWD", "LIST", "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT",
"NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", "EPSV", "EPRT", "MLSD", "MLST"
"EPSV", "EPRT", "MLSD", "MLST" }; };
// default access needed for Unit test // default access needed for Unit test
static void checkArray(){ static void checkArray() {
int expectedLength = LAST+1; int expectedLength = LAST + 1;
if (_commands.length != expectedLength) { if (_commands.length != expectedLength) {
throw new RuntimeException("Incorrect _commands array. Should have length " throw new RuntimeException("Incorrect _commands array. Should have length "
+expectedLength+" found "+_commands.length); + expectedLength
+ " found "
+ _commands.length);
} }
} }
@ -164,8 +164,7 @@ public final class FTPCommand
* @return The FTP protcol command string corresponding to a specified * @return The FTP protcol command string corresponding to a specified
* command code. * command code.
*/ */
public static final String getCommand(int command) public static final String getCommand(int command) {
{
return _commands[command]; return _commands[command];
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.IOException; import java.io.IOException;
/*** /***
@ -31,14 +32,12 @@ import java.io.IOException;
* @see FTPClient * @see FTPClient
***/ ***/
public class FTPConnectionClosedException extends IOException public class FTPConnectionClosedException extends IOException {
{
private static final long serialVersionUID = 3500547241659379952L; private static final long serialVersionUID = 3500547241659379952L;
/*** Constructs a FTPConnectionClosedException with no message ***/ /*** Constructs a FTPConnectionClosedException with no message ***/
public FTPConnectionClosedException() public FTPConnectionClosedException() {
{
super(); super();
} }
@ -47,9 +46,7 @@ public class FTPConnectionClosedException extends IOException
* *
* @param message The message explaining the reason for the exception. * @param message The message explaining the reason for the exception.
***/ ***/
public FTPConnectionClosedException(String message) public FTPConnectionClosedException(String message) {
{
super(message); super(message);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.Serializable; import java.io.Serializable;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -30,8 +31,7 @@ import java.util.TimeZone;
* @see FTPClient#listFiles * @see FTPClient#listFiles
***/ ***/
public class FTPFile implements Serializable public class FTPFile implements Serializable {
{
private static final long serialVersionUID = 9010790363003271996L; private static final long serialVersionUID = 9010790363003271996L;
/** A constant indicating an FTPFile is a file. ***/ /** A constant indicating an FTPFile is a file. ***/
@ -68,8 +68,7 @@ public class FTPFile implements Serializable
private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION] private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION]
/*** Creates an empty FTPFile. ***/ /*** Creates an empty FTPFile. ***/
public FTPFile() public FTPFile() {
{
_permissions = new boolean[3][3]; _permissions = new boolean[3][3];
_type = UNKNOWN_TYPE; _type = UNKNOWN_TYPE;
// init these to values that do not occur in listings // init these to values that do not occur in listings
@ -85,11 +84,11 @@ public class FTPFile implements Serializable
/** /**
* Constructor for use by {@link FTPListParseEngine} only. * Constructor for use by {@link FTPListParseEngine} only.
* Used to create FTPFile entries for failed parses * Used to create FTPFile entries for failed parses
*
* @param rawListing line that could not be parsed. * @param rawListing line that could not be parsed.
* @since 3.4 * @since 3.4
*/ */
FTPFile(String rawListing) FTPFile(String rawListing) {
{
_permissions = null; // flag that entry is invalid _permissions = null; // flag that entry is invalid
_rawListing = rawListing; _rawListing = rawListing;
_type = UNKNOWN_TYPE; _type = UNKNOWN_TYPE;
@ -103,15 +102,13 @@ public class FTPFile implements Serializable
_name = null; _name = null;
} }
/*** /***
* Set the original FTP server raw listing from which the FTPFile was * Set the original FTP server raw listing from which the FTPFile was
* created. * created.
* *
* @param rawListing The raw FTP server listing. * @param rawListing The raw FTP server listing.
***/ ***/
public void setRawListing(String rawListing) public void setRawListing(String rawListing) {
{
_rawListing = rawListing; _rawListing = rawListing;
} }
@ -121,20 +118,17 @@ public class FTPFile implements Serializable
* @return The original FTP server raw listing used to initialize the * @return The original FTP server raw listing used to initialize the
* FTPFile. * FTPFile.
***/ ***/
public String getRawListing() public String getRawListing() {
{
return _rawListing; return _rawListing;
} }
/*** /***
* Determine if the file is a directory. * Determine if the file is a directory.
* *
* @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if * @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isDirectory() public boolean isDirectory() {
{
return (_type == DIRECTORY_TYPE); return (_type == DIRECTORY_TYPE);
} }
@ -144,8 +138,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>FILE_TYPE</code>, false if * @return True if the file is of type <code>FILE_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isFile() public boolean isFile() {
{
return (_type == FILE_TYPE); return (_type == FILE_TYPE);
} }
@ -155,8 +148,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isSymbolicLink() public boolean isSymbolicLink() {
{
return (_type == SYMBOLIC_LINK_TYPE); return (_type == SYMBOLIC_LINK_TYPE);
} }
@ -166,8 +158,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isUnknown() public boolean isUnknown() {
{
return (_type == UNKNOWN_TYPE); return (_type == UNKNOWN_TYPE);
} }
@ -177,8 +168,9 @@ public class FTPFile implements Serializable
* Other methods may fail. * Other methods may fail.
* *
* Used in conjunction with list parsing that preseverves entries that failed to parse. * Used in conjunction with list parsing that preseverves entries that failed to parse.
* @see FTPClientConfig#setUnparseableEntries(boolean) *
* @return true if the entry is valid * @return true if the entry is valid
* @see FTPClientConfig#setUnparseableEntries(boolean)
* @since 3.4 * @since 3.4
*/ */
public boolean isValid() { public boolean isValid() {
@ -191,31 +183,26 @@ public class FTPFile implements Serializable
* *
* @param type The integer code representing the type of the file. * @param type The integer code representing the type of the file.
***/ ***/
public void setType(int type) public void setType(int type) {
{
_type = type; _type = type;
} }
/*** /***
* Return the type of the file (one of the <code>_TYPE</code> constants), * 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. * e.g., if it is a directory, a regular file, or a symbolic link.
* *
* @return The type of the file. * @return The type of the file.
***/ ***/
public int getType() public int getType() {
{
return _type; return _type;
} }
/*** /***
* Set the name of the file. * Set the name of the file.
* *
* @param name The name of the file. * @param name The name of the file.
***/ ***/
public void setName(String name) public void setName(String name) {
{
_name = name; _name = name;
} }
@ -224,89 +211,75 @@ public class FTPFile implements Serializable
* *
* @return The name of the file. * @return The name of the file.
***/ ***/
public String getName() public String getName() {
{
return _name; return _name;
} }
/** /**
* Set the file size in bytes. * Set the file size in bytes.
*
* @param size The file size in bytes. * @param size The file size in bytes.
*/ */
public void setSize(long size) public void setSize(long size) {
{
_size = size; _size = size;
} }
/*** /***
* Return the file size in bytes. * Return the file size in bytes.
* *
* @return The file size in bytes. * @return The file size in bytes.
***/ ***/
public long getSize() public long getSize() {
{
return _size; return _size;
} }
/*** /***
* Set the number of hard links to this file. This is not to be * Set the number of hard links to this file. This is not to be
* confused with symbolic links. * confused with symbolic links.
* *
* @param links The number of hard links to this file. * @param links The number of hard links to this file.
***/ ***/
public void setHardLinkCount(int links) public void setHardLinkCount(int links) {
{
_hardLinkCount = links; _hardLinkCount = links;
} }
/*** /***
* Return the number of hard links to this file. This is not to be * Return the number of hard links to this file. This is not to be
* confused with symbolic links. * confused with symbolic links.
* *
* @return The number of hard links to this file. * @return The number of hard links to this file.
***/ ***/
public int getHardLinkCount() public int getHardLinkCount() {
{
return _hardLinkCount; return _hardLinkCount;
} }
/*** /***
* Set the name of the group owning the file. This may be * Set the name of the group owning the file. This may be
* a string representation of the group number. * a string representation of the group number.
* *
* @param group The name of the group owning the file. * @param group The name of the group owning the file.
***/ ***/
public void setGroup(String group) public void setGroup(String group) {
{
_group = group; _group = group;
} }
/*** /***
* Returns the name of the group owning the file. Sometimes this will be * Returns the name of the group owning the file. Sometimes this will be
* a string representation of the group number. * a string representation of the group number.
* *
* @return The name of the group owning the file. * @return The name of the group owning the file.
***/ ***/
public String getGroup() public String getGroup() {
{
return _group; return _group;
} }
/*** /***
* Set the name of the user owning the file. This may be * Set the name of the user owning the file. This may be
* a string representation of the user number; * a string representation of the user number;
* *
* @param user The name of the user owning the file. * @param user The name of the user owning the file.
***/ ***/
public void setUser(String user) public void setUser(String user) {
{
_user = user; _user = user;
} }
@ -316,24 +289,20 @@ public class FTPFile implements Serializable
* *
* @return The name of the user owning the file. * @return The name of the user owning the file.
***/ ***/
public String getUser() public String getUser() {
{
return _user; return _user;
} }
/*** /***
* If the FTPFile is a symbolic link, use this method to set the name of the * If the FTPFile is a symbolic link, use this method to set the name of the
* file being pointed to by the symbolic link. * file being pointed to by the symbolic link.
* *
* @param link The file pointed to by the symbolic link. * @param link The file pointed to by the symbolic link.
***/ ***/
public void setLink(String link) public void setLink(String link) {
{
_link = link; _link = link;
} }
/*** /***
* If the FTPFile is a symbolic link, this method returns the name of the * 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. * file being pointed to by the symbolic link. Otherwise it returns null.
@ -341,12 +310,10 @@ public class FTPFile implements Serializable
* @return The file pointed to by the symbolic link (null if the FTPFile * @return The file pointed to by the symbolic link (null if the FTPFile
* is not a symbolic link). * is not a symbolic link).
***/ ***/
public String getLink() public String getLink() {
{
return _link; return _link;
} }
/*** /***
* Set the file timestamp. This usually the last modification time. * Set the file timestamp. This usually the last modification time.
* The parameter is not cloned, so do not alter its value after calling * The parameter is not cloned, so do not alter its value after calling
@ -354,23 +321,19 @@ public class FTPFile implements Serializable
* *
* @param date A Calendar instance representing the file timestamp. * @param date A Calendar instance representing the file timestamp.
***/ ***/
public void setTimestamp(Calendar date) public void setTimestamp(Calendar date) {
{
_date = date; _date = date;
} }
/*** /***
* Returns the file timestamp. This usually the last modification time. * Returns the file timestamp. This usually the last modification time.
* *
* @return A Calendar instance representing the file timestamp. * @return A Calendar instance representing the file timestamp.
***/ ***/
public Calendar getTimestamp() public Calendar getTimestamp() {
{
return _date; return _date;
} }
/*** /***
* Set if the given access group (one of the <code> _ACCESS </code> * Set if the given access group (one of the <code> _ACCESS </code>
* constants) has the given access permission (one of the * constants) has the given access permission (one of the
@ -383,12 +346,10 @@ public class FTPFile implements Serializable
* @param value True if permission is allowed, false if not. * @param value True if permission is allowed, false if not.
* @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range
***/ ***/
public void setPermission(int access, int permission, boolean value) public void setPermission(int access, int permission, boolean value) {
{
_permissions[access][permission] = value; _permissions[access][permission] = value;
} }
/*** /***
* Determines if the given access group (one of the <code> _ACCESS </code> * Determines if the given access group (one of the <code> _ACCESS </code>
* constants) has the given access permission (one of the * constants) has the given access permission (one of the
@ -402,8 +363,7 @@ public class FTPFile implements Serializable
* @return true if {@link #isValid()} is {@code true &&} the associated permission is set; * @return true if {@link #isValid()} is {@code true &&} the associated permission is set;
* {@code false} otherwise. * {@code false} otherwise.
***/ ***/
public boolean hasPermission(int access, int permission) public boolean hasPermission(int access, int permission) {
{
if (_permissions == null) { if (_permissions == null) {
return false; return false;
} }
@ -415,9 +375,7 @@ public class FTPFile implements Serializable
* *
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
*/ */
@Override @Override public String toString() {
public String toString()
{
return getRawListing(); return getRawListing();
} }
@ -435,8 +393,7 @@ public class FTPFile implements Serializable
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
* @since 3.0 * @since 3.0
*/ */
public String toFormattedString() public String toFormattedString() {
{
return toFormattedString(null); return toFormattedString(null);
} }
@ -448,13 +405,13 @@ public class FTPFile implements Serializable
* Note: if the instance is not valid {@link #isValid()}, no useful * Note: if the instance is not valid {@link #isValid()}, no useful
* information can be returned. In this case, use {@link #getRawListing()} * information can be returned. In this case, use {@link #getRawListing()}
* instead. * instead.
*
* @param timezone the timezone to use for displaying the time stamp * @param timezone the timezone to use for displaying the time stamp
* If {@code null}, then use the Calendar entry timezone * If {@code null}, then use the Calendar entry timezone
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
* @since 3.4 * @since 3.4
*/ */
public String toFormattedString(final String timezone) public String toFormattedString(final String timezone) {
{
if (!isValid()) { if (!isValid()) {
return "[Invalid: could not parse file entry]"; return "[Invalid: could not parse file entry]";
@ -472,7 +429,7 @@ public class FTPFile implements Serializable
if (timestamp != null) { if (timestamp != null) {
if (timezone != null) { if (timezone != null) {
TimeZone newZone = TimeZone.getTimeZone(timezone); TimeZone newZone = TimeZone.getTimeZone(timezone);
if (!newZone.equals(timestamp.getTimeZone())){ if (!newZone.equals(timestamp.getTimeZone())) {
Date original = timestamp.getTime(); Date original = timestamp.getTime();
Calendar newStamp = Calendar.getInstance(newZone); Calendar newStamp = Calendar.getInstance(newZone);
newStamp.setTime(original); newStamp.setTime(original);
@ -501,8 +458,8 @@ public class FTPFile implements Serializable
return sb.toString(); return sb.toString();
} }
private char formatType(){ private char formatType() {
switch(_type) { switch (_type) {
case FILE_TYPE: case FILE_TYPE:
return '-'; return '-';
case DIRECTORY_TYPE: case DIRECTORY_TYPE:
@ -514,7 +471,7 @@ public class FTPFile implements Serializable
} }
} }
private String permissionToString(int access ){ private String permissionToString(int access) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (hasPermission(access, READ_PERMISSION)) { if (hasPermission(access, READ_PERMISSION)) {
sb.append('r'); sb.append('r');

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -78,8 +79,7 @@ import java.util.List;
* @see FTPFile * @see FTPFile
* @see FTPClient#listFiles() * @see FTPClient#listFiles()
*/ */
public interface FTPFileEntryParser public interface FTPFileEntryParser {
{
/** /**
* Parses a line of an FTP server file listing and converts it into a usable * 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 * format in the form of an <code> FTPFile </code> instance. If the
@ -100,13 +100,11 @@ public interface FTPFileEntryParser
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
String readNextEntry(BufferedReader reader) throws IOException; String readNextEntry(BufferedReader reader) throws IOException;
/** /**
* This method is a hook for those implementors (such as * This method is a hook for those implementors (such as
* VMSVersioningFTPEntryParser, and possibly others) which need to * VMSVersioningFTPEntryParser, and possibly others) which need to
@ -116,12 +114,9 @@ public interface FTPFileEntryParser
* The default implementation can be a no-op. * The default implementation can be a no-op.
* *
* @param original Original list after it has been created from the server stream * @param original Original list after it has been created from the server stream
*
* @return Original list as processed by this method. * @return Original list as processed by this method.
*/ */
List<String> preParse(List<String> original); List<String> preParse(List<String> original);
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -24,16 +25,12 @@ import java.util.List;
* This abstract class implements both the older FTPFileListParser and * This abstract class implements both the older FTPFileListParser and
* newer FTPFileEntryParser interfaces with default functionality. * newer FTPFileEntryParser interfaces with default functionality.
* All the classes in the parser subpackage inherit from this. * All the classes in the parser subpackage inherit from this.
*
*/ */
public abstract class FTPFileEntryParserImpl public abstract class FTPFileEntryParserImpl implements FTPFileEntryParser {
implements FTPFileEntryParser
{
/** /**
* The constructor for a FTPFileEntryParserImpl object. * The constructor for a FTPFileEntryParserImpl object.
*/ */
public FTPFileEntryParserImpl() public FTPFileEntryParserImpl() {
{
} }
/** /**
@ -43,15 +40,13 @@ public abstract class FTPFileEntryParserImpl
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
@Override @Override public String readNextEntry(BufferedReader reader) throws IOException {
public String readNextEntry(BufferedReader reader) throws IOException
{
return reader.readLine(); return reader.readLine();
} }
/** /**
* This method is a hook for those implementors (such as * This method is a hook for those implementors (such as
* VMSVersioningFTPEntryParser, and possibly others) which need to * VMSVersioningFTPEntryParser, and possibly others) which need to
@ -61,11 +56,9 @@ public abstract class FTPFileEntryParserImpl
* This default implementation does nothing. * This default implementation does nothing.
* *
* @param original Original list after it has been created from the server stream * @param original Original list after it has been created from the server stream
*
* @return <code>original</code> unmodified. * @return <code>original</code> unmodified.
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
return original; return original;
} }
} }

@ -20,6 +20,7 @@ package org.apache.commons.net.ftp;
/** /**
* Perform filtering on FTPFile entries. * Perform filtering on FTPFile entries.
*
* @since 2.2 * @since 2.2
*/ */
public interface FTPFileFilter { public interface FTPFileFilter {

@ -20,6 +20,7 @@ package org.apache.commons.net.ftp;
/** /**
* Implements some simple FTPFileFilter classes. * Implements some simple FTPFileFilter classes.
*
* @since 2.2 * @since 2.2
*/ */
public class FTPFileFilters { public class FTPFileFilters {
@ -28,8 +29,7 @@ public class FTPFileFilters {
* Accepts all FTPFile entries, including null. * Accepts all FTPFile entries, including null.
*/ */
public static final FTPFileFilter ALL = new FTPFileFilter() { public static final FTPFileFilter ALL = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return true; return true;
} }
}; };
@ -38,8 +38,7 @@ public class FTPFileFilters {
* Accepts all non-null FTPFile entries. * Accepts all non-null FTPFile entries.
*/ */
public static final FTPFileFilter NON_NULL = new FTPFileFilter() { public static final FTPFileFilter NON_NULL = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return file != null; return file != null;
} }
}; };
@ -48,10 +47,8 @@ public class FTPFileFilters {
* Accepts all (non-null) FTPFile directory entries. * Accepts all (non-null) FTPFile directory entries.
*/ */
public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() { public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return file != null && file.isDirectory(); return file != null && file.isDirectory();
} }
}; };
} }

@ -43,7 +43,7 @@ public class FTPHTTPClient extends FTPClient {
private final String proxyUsername; private final String proxyUsername;
private final String proxyPassword; private final String proxyPassword;
private static final byte[] CRLF={'\r', '\n'}; private static final byte[] CRLF = { '\r', '\n' };
private final Base64 base64 = new Base64(); private final Base64 base64 = new Base64();
private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV) private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV)
@ -60,7 +60,6 @@ public class FTPHTTPClient extends FTPClient {
this(proxyHost, proxyPort, null, null); this(proxyHost, proxyPort, null, null);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
@ -69,9 +68,7 @@ public class FTPHTTPClient extends FTPClient {
*/ */
// Kept to maintain binary compatibility // Kept to maintain binary compatibility
// Not strictly necessary, but Clirr complains even though there is a super-impl // Not strictly necessary, but Clirr complains even though there is a super-impl
@Override @Override @Deprecated protected Socket _openDataConnection_(int command, String arg)
@Deprecated
protected Socket _openDataConnection_(int command, String arg)
throws IOException { throws IOException {
return super._openDataConnection_(command, arg); return super._openDataConnection_(command, arg);
} }
@ -82,9 +79,7 @@ public class FTPHTTPClient extends FTPClient {
* @throws IllegalStateException if connection mode is not passive * @throws IllegalStateException if connection mode is not passive
* @since 3.1 * @since 3.1
*/ */
@Override @Override protected Socket _openDataConnection_(String command, String arg) throws IOException {
protected Socket _openDataConnection_(String command, String arg)
throws IOException {
//Force local passive mode, active mode not supported by through proxy //Force local passive mode, active mode not supported by through proxy
if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
throw new IllegalStateException("Only passive connection mode supported"); throw new IllegalStateException("Only passive connection mode supported");
@ -126,8 +121,7 @@ public class FTPHTTPClient extends FTPClient {
return socket; return socket;
} }
@Override @Override public void connect(String host, int port) throws SocketException, IOException {
public void connect(String host, int port) throws SocketException, IOException {
_socket_ = _socketFactory_.createSocket(proxyHost, proxyPort); _socket_ = _socketFactory_.createSocket(proxyHost, proxyPort);
_input_ = _socket_.getInputStream(); _input_ = _socket_.getInputStream();
@ -135,17 +129,16 @@ public class FTPHTTPClient extends FTPClient {
Reader socketIsReader; Reader socketIsReader;
try { try {
socketIsReader = tunnelHandshake(host, port, _input_, _output_); socketIsReader = tunnelHandshake(host, port, _input_, _output_);
} } catch (Exception e) {
catch (Exception e) { IOException ioe = new IOException("Could not connect to " + host + " using port " + port);
IOException ioe = new IOException("Could not connect to " + host+ " using port " + port);
ioe.initCause(e); ioe.initCause(e);
throw ioe; throw ioe;
} }
super._connectAction_(socketIsReader); super._connectAction_(socketIsReader);
} }
private BufferedReader tunnelHandshake(String host, int port, InputStream input, OutputStream output) throws IOException, private BufferedReader tunnelHandshake(String host, int port, InputStream input,
UnsupportedEncodingException { OutputStream output) throws IOException, UnsupportedEncodingException {
final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1";
final String hostString = "Host: " + host + ":" + port; final String hostString = "Host: " + host + ":" + port;
@ -157,18 +150,17 @@ public class FTPHTTPClient extends FTPClient {
if (proxyUsername != null && proxyPassword != null) { if (proxyUsername != null && proxyPassword != null) {
final String auth = proxyUsername + ":" + proxyPassword; final String auth = proxyUsername + ":" + proxyPassword;
final String header = "Proxy-Authorization: Basic " final String header =
+ base64.encodeToString(auth.getBytes("UTF-8")); "Proxy-Authorization: Basic " + base64.encodeToString(auth.getBytes("UTF-8"));
output.write(header.getBytes("UTF-8")); output.write(header.getBytes("UTF-8"));
} }
output.write(CRLF); output.write(CRLF);
List<String> response = new ArrayList<String>(); List<String> response = new ArrayList<String>();
BufferedReader reader = new BufferedReader( BufferedReader reader = new BufferedReader(new InputStreamReader(input, getCharset()));
new InputStreamReader(input, getCharset()));
for (String line = reader.readLine(); line != null for (String line = reader.readLine(); line != null && line.length() > 0;
&& line.length() > 0; line = reader.readLine()) { line = reader.readLine()) {
response.add(line); response.add(line);
} }

@ -29,7 +29,6 @@ import java.util.ListIterator;
import org.apache.commons.net.util.Charsets; import org.apache.commons.net.util.Charsets;
/** /**
* This class handles the entire process of parsing a listing of * This class handles the entire process of parsing a listing of
* file entries from the server. * file entries from the server.
@ -73,6 +72,7 @@ import org.apache.commons.net.util.Charsets;
* <p> * <p>
* For unpaged access, simply use FTPClient.listFiles(). That method * For unpaged access, simply use FTPClient.listFiles(). That method
* uses this class transparently. * uses this class transparently.
*
* @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $ * @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $
*/ */
public class FTPListParseEngine { public class FTPListParseEngine {
@ -89,6 +89,7 @@ public class FTPListParseEngine {
/** /**
* Intended for use by FTPClient only * Intended for use by FTPClient only
*
* @since 3.4 * @since 3.4
*/ */
FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) { FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) {
@ -108,13 +109,9 @@ public class FTPListParseEngine {
* *
* @param stream input stream provided by the server socket. * @param stream input stream provided by the server socket.
* @param encoding the encoding to be used for reading the stream * @param encoding the encoding to be used for reading the stream
* * @throws IOException thrown on any failure to read from the sever.
* @throws IOException
* thrown on any failure to read from the sever.
*/ */
public void readServerList(InputStream stream, String encoding) public void readServerList(InputStream stream, String encoding) throws IOException {
throws IOException
{
this.entries = new LinkedList<String>(); this.entries = new LinkedList<String>();
readStream(stream, encoding); readStream(stream, encoding);
this.parser.preParse(this.entries); this.parser.preParse(this.entries);
@ -131,19 +128,15 @@ public class FTPListParseEngine {
* *
* @param stream The socket stream on which the input will be read. * @param stream The socket stream on which the input will be read.
* @param encoding The encoding to use. * @param encoding The encoding to use.
* * @throws IOException thrown on any failure to read the stream
* @throws IOException
* thrown on any failure to read the stream
*/ */
private void readStream(InputStream stream, String encoding) throws IOException private void readStream(InputStream stream, String encoding) throws IOException {
{ BufferedReader reader =
BufferedReader reader = new BufferedReader( new BufferedReader(new InputStreamReader(stream, Charsets.toCharset(encoding)));
new InputStreamReader(stream, Charsets.toCharset(encoding)));
String line = this.parser.readNextEntry(reader); String line = this.parser.readNextEntry(reader);
while (line != null) while (line != null) {
{
this.entries.add(line); this.entries.add(line);
line = this.parser.readNextEntry(reader); line = this.parser.readNextEntry(reader);
} }
@ -161,9 +154,7 @@ public class FTPListParseEngine {
* After this method is called this object's internal iterator is advanced * 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. * by a number of positions equal to the size of the array returned.
* *
* @param quantityRequested * @param quantityRequested the maximum number of entries we want to get.
* the maximum number of entries we want to get.
*
* @return an array of at most <code>quantityRequested</code> FTPFile * @return an array of at most <code>quantityRequested</code> FTPFile
* objects starting at the current position of this iterator within its * 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 * list and at least the number of elements which exist in the list at
@ -186,7 +177,6 @@ public class FTPListParseEngine {
count--; count--;
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
} }
/** /**
@ -202,9 +192,7 @@ public class FTPListParseEngine {
* After this method is called this object's internal iterator is moved * 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. * back by a number of positions equal to the size of the array returned.
* *
* @param quantityRequested * @param quantityRequested the maximum number of entries we want to get.
* the maximum number of entries we want to get.
*
* @return an array of at most <code>quantityRequested</code> FTPFile * @return an array of at most <code>quantityRequested</code> FTPFile
* objects starting at the current position of this iterator within its * 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 * list and at least the number of elements which exist in the list at
@ -224,7 +212,7 @@ public class FTPListParseEngine {
if (temp == null && saveUnparseableEntries) { if (temp == null && saveUnparseableEntries) {
temp = new FTPFile(entry); temp = new FTPFile(entry);
} }
tmpResults.add(0,temp); tmpResults.add(0, temp);
count--; count--;
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
@ -239,8 +227,7 @@ public class FTPListParseEngine {
* None of the entries will be null * None of the entries will be null
* @throws IOException - not ever thrown, may be removed in a later release * @throws IOException - not ever thrown, may be removed in a later release
*/ */
public FTPFile[] getFiles() public FTPFile[] getFiles() throws IOException // TODO remove; not actually thrown
throws IOException // TODO remove; not actually thrown
{ {
return getFiles(FTPFileFilters.NON_NULL); return getFiles(FTPFileFilters.NON_NULL);
} }
@ -251,7 +238,6 @@ public class FTPListParseEngine {
* The files are filtered before being added to the array. * The files are filtered before being added to the array.
* *
* @param filter FTPFileFilter, must not be <code>null</code>. * @param filter FTPFileFilter, must not be <code>null</code>.
*
* @return an array of FTPFile objects containing the whole list of * @return an array of FTPFile objects containing the whole list of
* files returned by the server as read by this object's parser. * files returned by the server as read by this object's parser.
* <p><b> * <p><b>
@ -260,8 +246,8 @@ public class FTPListParseEngine {
* check each entry for null before referencing it, or use the * check each entry for null before referencing it, or use the
* a filter such as {@link FTPFileFilters#NON_NULL} which does not * a filter such as {@link FTPFileFilters#NON_NULL} which does not
* allow null entries. * allow null entries.
* @since 2.2
* @throws IOException - not ever thrown, may be removed in a later release * @throws IOException - not ever thrown, may be removed in a later release
* @since 2.2
*/ */
public FTPFile[] getFiles(FTPFileFilter filter) public FTPFile[] getFiles(FTPFileFilter filter)
throws IOException // TODO remove; not actually thrown throws IOException // TODO remove; not actually thrown
@ -274,12 +260,11 @@ public class FTPListParseEngine {
if (temp == null && saveUnparseableEntries) { if (temp == null && saveUnparseableEntries) {
temp = new FTPFile(entry); temp = new FTPFile(entry);
} }
if (filter.accept(temp)){ if (filter.accept(temp)) {
tmpResults.add(temp); tmpResults.add(temp);
} }
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
} }
/** /**
@ -315,15 +300,12 @@ public class FTPListParseEngine {
/** /**
* Do not use. * Do not use.
*
* @param stream the stream from which to read * @param stream the stream from which to read
* @throws IOException on error * @throws IOException on error
* @deprecated use {@link #readServerList(InputStream, String)} instead * @deprecated use {@link #readServerList(InputStream, String)} instead
*/ */
@Deprecated @Deprecated public void readServerList(InputStream stream) throws IOException {
public void readServerList(InputStream stream)
throws IOException
{
readServerList(stream, null); readServerList(stream, null);
} }
} }

@ -26,8 +26,7 @@ package org.apache.commons.net.ftp;
* TODO replace with an enum * TODO replace with an enum
***/ ***/
public final class FTPReply public final class FTPReply {
{
public static final int RESTART_MARKER = 110; public static final int RESTART_MARKER = 110;
public static final int SERVICE_NOT_READY = 120; public static final int SERVICE_NOT_READY = 120;
@ -100,8 +99,8 @@ public final class FTPReply
public static final int EXTENDED_PORT_FAILURE = 522; public static final int EXTENDED_PORT_FAILURE = 522;
// Cannot be instantiated // Cannot be instantiated
private FTPReply() private FTPReply() {
{} }
/*** /***
* Determine if a reply code is a positive preliminary response. All * Determine if a reply code is a positive preliminary response. All
@ -115,8 +114,7 @@ public final class FTPReply
* @return True if a reply code is a postive preliminary response, false * @return True if a reply code is a postive preliminary response, false
* if not. * if not.
***/ ***/
public static boolean isPositivePreliminary(int reply) public static boolean isPositivePreliminary(int reply) {
{
return (reply >= 100 && reply < 200); return (reply >= 100 && reply < 200);
} }
@ -130,8 +128,7 @@ public final class FTPReply
* @return True if a reply code is a postive completion response, false * @return True if a reply code is a postive completion response, false
* if not. * if not.
***/ ***/
public static boolean isPositiveCompletion(int reply) public static boolean isPositiveCompletion(int reply) {
{
return (reply >= 200 && reply < 300); return (reply >= 200 && reply < 300);
} }
@ -148,8 +145,7 @@ public final class FTPReply
* @return True if a reply code is a postive intermediate response, false * @return True if a reply code is a postive intermediate response, false
* if not. * if not.
***/ ***/
public static boolean isPositiveIntermediate(int reply) public static boolean isPositiveIntermediate(int reply) {
{
return (reply >= 300 && reply < 400); return (reply >= 300 && reply < 400);
} }
@ -163,8 +159,7 @@ public final class FTPReply
* @return True if a reply code is a negative transient response, false * @return True if a reply code is a negative transient response, false
* if not. * if not.
***/ ***/
public static boolean isNegativeTransient(int reply) public static boolean isNegativeTransient(int reply) {
{
return (reply >= 400 && reply < 500); return (reply >= 400 && reply < 500);
} }
@ -178,24 +173,21 @@ public final class FTPReply
* @return True if a reply code is a negative permanent response, false * @return True if a reply code is a negative permanent response, false
* if not. * if not.
***/ ***/
public static boolean isNegativePermanent(int reply) public static boolean isNegativePermanent(int reply) {
{
return (reply >= 500 && reply < 600); return (reply >= 500 && reply < 600);
} }
/** /**
* Determine if a reply code is a protected response. * Determine if a reply code is a protected response.
*
* @param reply The reply code to test. * @param reply The reply code to test.
* @return True if a reply code is a protected response, false * @return True if a reply code is a protected response, false
* if not. * if not.
* @since 3.0 * @since 3.0
*/ */
public static boolean isProtectedReplyCode(int reply) public static boolean isProtectedReplyCode(int reply) {
{
// actually, only 3 protected reply codes are // actually, only 3 protected reply codes are
// defined in RFC 2228: 631, 632 and 633. // defined in RFC 2228: 631, 632 and 633.
return (reply >= 600 && reply < 700); return (reply >= 600 && reply < 700);
} }
} }

@ -45,23 +45,24 @@ import org.apache.commons.net.util.TrustManagerUtils;
* Warning: the hostname is not verified against the certificate by default, use * Warning: the hostname is not verified against the certificate by default, use
* {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)}
* (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. * (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 $ * @version $Id: FTPSClient.java 1747829 2016-06-11 00:57:57Z sebb $
* @since 2.0 * @since 2.0
*/ */
public class FTPSClient extends FTPClient { public class FTPSClient extends FTPClient {
// From http://www.iana.org/assignments/port-numbers // From http://www.iana.org/assignments/port-numbers
// ftps-data 989/tcp ftp protocol, data, over TLS/SSL // ftps-data 989/tcp ftp protocol, data, over TLS/SSL
// ftps-data 989/udp 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/tcp ftp protocol, control, over TLS/SSL
// ftps 990/udp 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_DATA_PORT = 989;
public static final int DEFAULT_FTPS_PORT = 990; public static final int DEFAULT_FTPS_PORT = 990;
/** The value that I can set in PROT command (C = Clear, P = Protected) */ /** The value that I can set in PROT command (C = Clear, P = Protected) */
private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" };
/** Default PROT Command */ /** Default PROT Command */
private static final String DEFAULT_PROT = "C"; private static final String DEFAULT_PROT = "C";
/** Default secure socket protocol name, i.e. TLS */ /** Default secure socket protocol name, i.e. TLS */
@ -107,7 +108,8 @@ public class FTPSClient extends FTPClient {
/** The protocol versions */ /** The protocol versions */
private String[] protocols = null; private String[] protocols = null;
/** The FTPS {@link TrustManager} implementation, default validate only /**
* The FTPS {@link TrustManager} implementation, default validate only
* {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
*/ */
private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
@ -124,7 +126,8 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
* *
* Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false) * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit
* (isImplicit = false)
*/ */
public FTPSClient() { public FTPSClient() {
this(DEFAULT_PROTOCOL, false); this(DEFAULT_PROTOCOL, false);
@ -133,6 +136,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* Calls {@link #FTPSClient(String, boolean)} * Calls {@link #FTPSClient(String, boolean)}
*
* @param isImplicit The security mode (Implicit/Explicit). * @param isImplicit The security mode (Implicit/Explicit).
*/ */
public FTPSClient(boolean isImplicit) { public FTPSClient(boolean isImplicit) {
@ -153,6 +157,7 @@ public class FTPSClient extends FTPClient {
* and security mode. If isImplicit is true, the port is set to * and security mode. If isImplicit is true, the port is set to
* {@link #DEFAULT_FTPS_PORT} i.e. 990. * {@link #DEFAULT_FTPS_PORT} i.e. 990.
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param protocol the protocol * @param protocol the protocol
* @param isImplicit The security mode(Implicit/Explicit). * @param isImplicit The security mode(Implicit/Explicit).
*/ */
@ -168,6 +173,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param isImplicit The security mode(Implicit/Explicit). * @param isImplicit The security mode(Implicit/Explicit).
* @param context A pre-configured SSL Context * @param context A pre-configured SSL Context
*/ */
@ -180,16 +186,17 @@ public class FTPSClient extends FTPClient {
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* and isImplicit {@code false} * and isImplicit {@code false}
* Calls {@link #FTPSClient(boolean, SSLContext)} * Calls {@link #FTPSClient(boolean, SSLContext)}
*
* @param context A pre-configured SSL Context * @param context A pre-configured SSL Context
*/ */
public FTPSClient(SSLContext context) { public FTPSClient(SSLContext context) {
this(false, context); this(false, context);
} }
/** /**
* Set AUTH command use value. * Set AUTH command use value.
* This processing is done before connected processing. * This processing is done before connected processing.
*
* @param auth AUTH command use value. * @param auth AUTH command use value.
*/ */
public void setAuthValue(String auth) { public void setAuthValue(String auth) {
@ -198,23 +205,23 @@ public class FTPSClient extends FTPClient {
/** /**
* Return AUTH command use value. * Return AUTH command use value.
*
* @return AUTH command use value. * @return AUTH command use value.
*/ */
public String getAuthValue() { public String getAuthValue() {
return this.auth; return this.auth;
} }
/** /**
* Because there are so many connect() methods, * Because there are so many connect() methods,
* the _connectAction_() method is provided as a means of performing * the _connectAction_() method is provided as a means of performing
* some action immediately after establishing a connection, * some action immediately after establishing a connection,
* rather than reimplementing all of the connect() methods. * rather than reimplementing all of the connect() methods.
*
* @throws IOException If it throw by _connectAction_. * @throws IOException If it throw by _connectAction_.
* @see org.apache.commons.net.SocketClient#_connectAction_() * @see org.apache.commons.net.SocketClient#_connectAction_()
*/ */
@Override @Override protected void _connectAction_() throws IOException {
protected void _connectAction_() throws IOException {
// Implicit mode. // Implicit mode.
if (isImplicit) { if (isImplicit) {
sslNegotiation(); sslNegotiation();
@ -229,6 +236,7 @@ public class FTPSClient extends FTPClient {
/** /**
* AUTH command. * AUTH command.
*
* @throws SSLException If it server reply code not equal "234" and "334". * @throws SSLException If it server reply code not equal "234" and "334".
* @throws IOException If an I/O error occurs while either sending * @throws IOException If an I/O error occurs while either sending
* the command. * the command.
@ -245,6 +253,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Performs a lazy init of the SSL context * Performs a lazy init of the SSL context
*
* @throws IOException * @throws IOException
*/ */
private void initSslContext() throws IOException { private void initSslContext() throws IOException {
@ -256,6 +265,7 @@ public class FTPSClient extends FTPClient {
/** /**
* SSL/TLS negotiation. Acquires an SSL socket of a control * SSL/TLS negotiation. Acquires an SSL socket of a control
* connection and carries out handshake processing. * connection and carries out handshake processing.
*
* @throws IOException If server negotiation fails * @throws IOException If server negotiation fails
*/ */
protected void sslNegotiation() throws IOException { protected void sslNegotiation() throws IOException {
@ -265,8 +275,7 @@ public class FTPSClient extends FTPClient {
SSLSocketFactory ssf = context.getSocketFactory(); SSLSocketFactory ssf = context.getSocketFactory();
String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress(); String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress();
int port = _socket_.getPort(); int port = _socket_.getPort();
SSLSocket socket = SSLSocket socket = (SSLSocket) ssf.createSocket(_socket_, host, port, false);
(SSLSocket) ssf.createSocket(_socket_, host, port, false);
socket.setEnableSessionCreation(isCreation); socket.setEnableSessionCreation(isCreation);
socket.setUseClientMode(isClientMode); socket.setUseClientMode(isClientMode);
@ -290,10 +299,10 @@ public class FTPSClient extends FTPClient {
// TODO the following setup appears to duplicate that in the super class methods // TODO the following setup appears to duplicate that in the super class methods
_socket_ = socket; _socket_ = socket;
_controlInput_ = new BufferedReader(new InputStreamReader( _controlInput_ =
socket .getInputStream(), getControlEncoding())); new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
_controlOutput_ = new BufferedWriter(new OutputStreamWriter( _controlOutput_ =
socket.getOutputStream(), getControlEncoding())); new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
if (isClientMode) { if (isClientMode) {
if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) {
@ -304,6 +313,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Get the {@link KeyManager} instance. * Get the {@link KeyManager} instance.
*
* @return The {@link KeyManager} instance * @return The {@link KeyManager} instance
*/ */
private KeyManager getKeyManager() { private KeyManager getKeyManager() {
@ -322,6 +332,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls whether a new SSL session may be established by this socket. * Controls whether a new SSL session may be established by this socket.
*
* @param isCreation The established socket flag. * @param isCreation The established socket flag.
*/ */
public void setEnabledSessionCreation(boolean isCreation) { public void setEnabledSessionCreation(boolean isCreation) {
@ -331,21 +342,24 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if new SSL sessions may be established by this socket. * 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 * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an
* instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()})
* enabled,
* this returns False. * this returns False.
*
* @return true - Indicates that sessions may be created; * @return true - Indicates that sessions may be created;
* this is the default. * this is the default.
* false - indicates that an existing session must be resumed. * false - indicates that an existing session must be resumed.
*/ */
public boolean getEnableSessionCreation() { public boolean getEnableSessionCreation() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnableSessionCreation(); return ((SSLSocket) _socket_).getEnableSessionCreation();
} }
return false; return false;
} }
/** /**
* Configures the socket to require client authentication. * Configures the socket to require client authentication.
*
* @param isNeedClientAuth The need client auth flag. * @param isNeedClientAuth The need client auth flag.
*/ */
public void setNeedClientAuth(boolean isNeedClientAuth) { public void setNeedClientAuth(boolean isNeedClientAuth) {
@ -355,12 +369,13 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if the socket will require client authentication. * Returns true if the socket will require client authentication.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the server mode socket should request * @return true - If the server mode socket should request
* that the client authenticate itself. * that the client authenticate itself.
*/ */
public boolean getNeedClientAuth() { public boolean getNeedClientAuth() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getNeedClientAuth(); return ((SSLSocket) _socket_).getNeedClientAuth();
} }
return false; return false;
} }
@ -369,6 +384,7 @@ public class FTPSClient extends FTPClient {
* Configures the socket to request client authentication, * Configures the socket to request client authentication,
* but only if such a request is appropriate to the cipher * but only if such a request is appropriate to the cipher
* suite negotiated. * suite negotiated.
*
* @param isWantClientAuth The want client auth flag. * @param isWantClientAuth The want client auth flag.
*/ */
public void setWantClientAuth(boolean isWantClientAuth) { public void setWantClientAuth(boolean isWantClientAuth) {
@ -378,12 +394,13 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if the socket will request client authentication. * Returns true if the socket will request client authentication.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the server mode socket should request * @return true - If the server mode socket should request
* that the client authenticate itself. * that the client authenticate itself.
*/ */
public boolean getWantClientAuth() { public boolean getWantClientAuth() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getWantClientAuth(); return ((SSLSocket) _socket_).getWantClientAuth();
} }
return false; return false;
} }
@ -391,6 +408,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Configures the socket to use client (or server) mode in its first * Configures the socket to use client (or server) mode in its first
* handshake. * handshake.
*
* @param isClientMode The use client mode flag. * @param isClientMode The use client mode flag.
*/ */
public void setUseClientMode(boolean isClientMode) { public void setUseClientMode(boolean isClientMode) {
@ -401,12 +419,13 @@ public class FTPSClient extends FTPClient {
* Returns true if the socket is set to use client mode * Returns true if the socket is set to use client mode
* in its first handshake. * in its first handshake.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the socket should start its first handshake * @return true - If the socket should start its first handshake
* in "client" mode. * in "client" mode.
*/ */
public boolean getUseClientMode() { public boolean getUseClientMode() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getUseClientMode(); return ((SSLSocket) _socket_).getUseClientMode();
} }
return false; return false;
} }
@ -414,6 +433,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls which particular cipher suites are enabled for use on this * Controls which particular cipher suites are enabled for use on this
* connection. Called before server negotiation. * connection. Called before server negotiation.
*
* @param cipherSuites The cipher suites. * @param cipherSuites The cipher suites.
*/ */
public void setEnabledCipherSuites(String[] cipherSuites) { public void setEnabledCipherSuites(String[] cipherSuites) {
@ -425,11 +445,12 @@ public class FTPSClient extends FTPClient {
* Returns the names of the cipher suites which could be enabled * Returns the names of the cipher suites which could be enabled
* for use on this connection. * for use on this connection.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
*
* @return An array of cipher suite names, or <code>null</code> * @return An array of cipher suite names, or <code>null</code>
*/ */
public String[] getEnabledCipherSuites() { public String[] getEnabledCipherSuites() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnabledCipherSuites(); return ((SSLSocket) _socket_).getEnabledCipherSuites();
} }
return null; return null;
} }
@ -437,6 +458,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls which particular protocol versions are enabled for use on this * Controls which particular protocol versions are enabled for use on this
* connection. I perform setting before a server negotiation. * connection. I perform setting before a server negotiation.
*
* @param protocolVersions The protocol versions. * @param protocolVersions The protocol versions.
*/ */
public void setEnabledProtocols(String[] protocolVersions) { public void setEnabledProtocols(String[] protocolVersions) {
@ -448,17 +470,19 @@ public class FTPSClient extends FTPClient {
* Returns the names of the protocol versions which are currently * Returns the names of the protocol versions which are currently
* enabled for use on this connection. * enabled for use on this connection.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
*
* @return An array of protocols, or <code>null</code> * @return An array of protocols, or <code>null</code>
*/ */
public String[] getEnabledProtocols() { public String[] getEnabledProtocols() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnabledProtocols(); return ((SSLSocket) _socket_).getEnabledProtocols();
} }
return null; return null;
} }
/** /**
* PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
*
* @param pbsz Protection Buffer Size. * @param pbsz Protection Buffer Size.
* @throws SSLException If the server reply code does not equal "200". * @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
@ -480,10 +504,10 @@ public class FTPSClient extends FTPClient {
* Issues the command and parses the response to return the negotiated value. * Issues the command and parses the response to return the negotiated value.
* *
* @param pbsz Protection Buffer Size. * @param pbsz Protection Buffer Size.
* @return the negotiated value.
* @throws SSLException If the server reply code does not equal "200". * @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @return the negotiated value.
* @see #execPBSZ(long) * @see #execPBSZ(long)
* @since 3.0 * @since 3.0
*/ */
@ -539,12 +563,12 @@ public class FTPSClient extends FTPClient {
/** /**
* Check the value that can be set in PROT Command value. * Check the value that can be set in PROT Command value.
*
* @param prot Data Channel Protection Level. * @param prot Data Channel Protection Level.
* @return True - A set point is right / False - A set point is not right * @return True - A set point is right / False - A set point is not right
*/ */
private boolean checkPROTValue(String prot) { private boolean checkPROTValue(String prot) {
for (String element : PROT_COMMAND_VALUE) for (String element : PROT_COMMAND_VALUE) {
{
if (element.equals(prot)) { if (element.equals(prot)) {
return true; return true;
} }
@ -556,6 +580,7 @@ public class FTPSClient extends FTPClient {
* Send an FTP command. * Send an FTP command.
* A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket}
* instance to be assigned to a plain {@link Socket} * instance to be assigned to a plain {@link Socket}
*
* @param command The FTP command. * @param command The FTP command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending the command. * @throws IOException If an I/O error occurs while sending the command.
@ -563,8 +588,7 @@ public class FTPSClient extends FTPClient {
* @see FTP#sendCommand(String) * @see FTP#sendCommand(String)
*/ */
// Would like to remove this method, but that will break any existing clients that are using CCC // Would like to remove this method, but that will break any existing clients that are using CCC
@Override @Override public int sendCommand(String command, String args) throws IOException {
public int sendCommand(String command, String args) throws IOException {
int repCode = super.sendCommand(command, args); int repCode = super.sendCommand(command, args);
/* If CCC is issued, restore socket i/o streams to unsecured versions */ /* If CCC is issued, restore socket i/o streams to unsecured versions */
if (CMD_CCC.equals(command)) { if (CMD_CCC.equals(command)) {
@ -572,11 +596,9 @@ public class FTPSClient extends FTPClient {
_socket_.close(); _socket_.close();
_socket_ = plainSocket; _socket_ = plainSocket;
_controlInput_ = new BufferedReader( _controlInput_ = new BufferedReader(
new InputStreamReader( new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
_socket_ .getInputStream(), getControlEncoding()));
_controlOutput_ = new BufferedWriter( _controlOutput_ = new BufferedWriter(
new OutputStreamWriter( new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
_socket_.getOutputStream(), getControlEncoding()));
} else { } else {
throw new SSLException(getReplyString()); throw new SSLException(getReplyString());
} }
@ -587,6 +609,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns a socket of the data connection. * Returns a socket of the data connection.
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The int representation of the FTP command to send. * @param command The int representation of the FTP command to send.
* @param arg The arguments to the FTP command. * @param arg The arguments to the FTP command.
* If this parameter is set to null, then the command is sent with * If this parameter is set to null, then the command is sent with
@ -601,15 +624,14 @@ public class FTPSClient extends FTPClient {
@Override @Override
// Strictly speaking this is not needed, but it works round a Clirr bug // Strictly speaking this is not needed, but it works round a Clirr bug
// So rather than invoke the parent code, we do it here // So rather than invoke the parent code, we do it here
@Deprecated @Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException {
protected Socket _openDataConnection_(int command, String arg)
throws IOException {
return _openDataConnection_(FTPCommand.getCommand(command), arg); return _openDataConnection_(FTPCommand.getCommand(command), arg);
} }
/** /**
* Returns a socket of the data connection. * Returns a socket of the data connection.
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The textual representation of the FTP command to send. * @param command The textual representation of the FTP command to send.
* @param arg The arguments to the FTP command. * @param arg The arguments to the FTP command.
* If this parameter is set to null, then the command is sent with * If this parameter is set to null, then the command is sent with
@ -621,13 +643,11 @@ public class FTPSClient extends FTPClient {
* @see FTPClient#_openDataConnection_(int, String) * @see FTPClient#_openDataConnection_(int, String)
* @since 3.2 * @since 3.2
*/ */
@Override @Override protected Socket _openDataConnection_(String command, String arg) throws IOException {
protected Socket _openDataConnection_(String command, String arg)
throws IOException {
Socket socket = super._openDataConnection_(command, arg); Socket socket = super._openDataConnection_(command, arg);
_prepareDataSocket_(socket); _prepareDataSocket_(socket);
if (socket instanceof SSLSocket) { if (socket instanceof SSLSocket) {
SSLSocket sslSocket = (SSLSocket)socket; SSLSocket sslSocket = (SSLSocket) socket;
sslSocket.setUseClientMode(isClientMode); sslSocket.setUseClientMode(isClientMode);
sslSocket.setEnableSessionCreation(isCreation); sslSocket.setEnableSessionCreation(isCreation);
@ -655,12 +675,12 @@ public class FTPSClient extends FTPClient {
* Called by {@link #_openDataConnection_(int, String)} immediately * Called by {@link #_openDataConnection_(int, String)} immediately
* after creating the socket. * after creating the socket.
* The default implementation is a no-op * The default implementation is a no-op
*
* @param socket the socket to set up * @param socket the socket to set up
* @throws IOException on error * @throws IOException on error
* @since 3.1 * @since 3.1
*/ */
protected void _prepareDataSocket_(Socket socket) protected void _prepareDataSocket_(Socket socket) throws IOException {
throws IOException {
} }
/** /**
@ -686,22 +706,23 @@ public class FTPSClient extends FTPClient {
/** /**
* Get the currently configured {@link HostnameVerifier}. * Get the currently configured {@link HostnameVerifier}.
* The verifier is only used on client mode connections. * The verifier is only used on client mode connections.
*
* @return A HostnameVerifier instance. * @return A HostnameVerifier instance.
* @since 3.4 * @since 3.4
*/ */
public HostnameVerifier getHostnameVerifier() public HostnameVerifier getHostnameVerifier() {
{
return hostnameVerifier; return hostnameVerifier;
} }
/** /**
* Override the default {@link HostnameVerifier} to use. * Override the default {@link HostnameVerifier} to use.
* The verifier is only used on client mode connections. * The verifier is only used on client mode connections.
* @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable. *
* @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to
* disable.
* @since 3.4 * @since 3.4
*/ */
public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) {
{
hostnameVerifier = newHostnameVerifier; hostnameVerifier = newHostnameVerifier;
} }
@ -714,8 +735,7 @@ public class FTPSClient extends FTPClient {
* @return True if enabled, false if not. * @return True if enabled, false if not.
* @since 3.4 * @since 3.4
*/ */
public boolean isEndpointCheckingEnabled() public boolean isEndpointCheckingEnabled() {
{
return tlsEndpointChecking; return tlsEndpointChecking;
} }
@ -725,11 +745,11 @@ public class FTPSClient extends FTPClient {
* *
* This check is only performed on client mode connections. * This check is only performed on client mode connections.
* *
* @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on
* Java 1.7+.
* @since 3.4 * @since 3.4
*/ */
public void setEndpointCheckingEnabled(boolean enable) public void setEndpointCheckingEnabled(boolean enable) {
{
tlsEndpointChecking = enable; tlsEndpointChecking = enable;
} }
@ -740,12 +760,11 @@ public class FTPSClient extends FTPClient {
* Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)}
* to reset the factories that may have been changed during the session, * to reset the factories that may have been changed during the session,
* e.g. by {@link #execPROT(String)} * e.g. by {@link #execPROT(String)}
*
* @throws IOException If an error occurs while disconnecting. * @throws IOException If an error occurs while disconnecting.
* @since 3.0 * @since 3.0
*/ */
@Override @Override public void disconnect() throws IOException {
public void disconnect() throws IOException
{
super.disconnect(); super.disconnect();
if (plainSocket != null) { if (plainSocket != null) {
plainSocket.close(); plainSocket.close();
@ -756,131 +775,120 @@ public class FTPSClient extends FTPClient {
/** /**
* Send the AUTH command with the specified mechanism. * Send the AUTH command with the specified mechanism.
*
* @param mechanism The mechanism name to send with the command. * @param mechanism The mechanism name to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execAUTH(String mechanism) throws IOException public int execAUTH(String mechanism) throws IOException {
{
return sendCommand(CMD_AUTH, mechanism); return sendCommand(CMD_AUTH, mechanism);
} }
/** /**
* Send the ADAT command with the specified authentication data. * Send the ADAT command with the specified authentication data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execADAT(byte[] data) throws IOException public int execADAT(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_ADAT); return sendCommand(CMD_ADAT);
} }
} }
/** /**
* Send the CCC command to the server. * Send the CCC command to the server.
* The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be
* assigned
* to a plain {@link Socket} instances * to a plain {@link Socket} instances
*
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execCCC() throws IOException public int execCCC() throws IOException {
{
int repCode = sendCommand(CMD_CCC); int repCode = sendCommand(CMD_CCC);
// This will be performed by sendCommand(String, String) // This will be performed by sendCommand(String, String)
// if (FTPReply.isPositiveCompletion(repCode)) { // if (FTPReply.isPositiveCompletion(repCode)) {
// _socket_.close(); // _socket_.close();
// _socket_ = plainSocket; // _socket_ = plainSocket;
// _controlInput_ = new BufferedReader( // _controlInput_ = new BufferedReader(
// new InputStreamReader( // new InputStreamReader(
// _socket_.getInputStream(), getControlEncoding())); // _socket_.getInputStream(), getControlEncoding()));
// _controlOutput_ = new BufferedWriter( // _controlOutput_ = new BufferedWriter(
// new OutputStreamWriter( // new OutputStreamWriter(
// _socket_.getOutputStream(), getControlEncoding())); // _socket_.getOutputStream(), getControlEncoding()));
// } // }
return repCode; return repCode;
} }
/** /**
* Send the MIC command with the specified data. * Send the MIC command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execMIC(byte[] data) throws IOException public int execMIC(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Send the CONF command with the specified data. * Send the CONF command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execCONF(byte[] data) throws IOException public int execCONF(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Send the ENC command with the specified data. * Send the ENC command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execENC(byte[] data) throws IOException public int execENC(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Parses the given ADAT response line and base64-decodes the data. * Parses the given ADAT response line and base64-decodes the data.
*
* @param reply The ADAT reply to parse. * @param reply The ADAT reply to parse.
* @return the data in the reply, base64-decoded. * @return the data in the reply, base64-decoded.
* @since 3.0 * @since 3.0
*/ */
public byte[] parseADATReply(String reply) public byte[] parseADATReply(String reply) {
{
if (reply == null) { if (reply == null) {
return null; return null;
} else { } else {
@ -890,6 +898,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
*
* @param prefix the prefix to find * @param prefix the prefix to find
* @param reply where to find the prefix * @param reply where to find the prefix
* @return the remainder of the string after the prefix, or null if the prefix was not present. * @return the remainder of the string after the prefix, or null if the prefix was not present.
@ -900,26 +909,21 @@ public class FTPSClient extends FTPClient {
return null; return null;
} }
// N.B. Cannot use trim before substring as leading space would affect the offset. // N.B. Cannot use trim before substring as leading space would affect the offset.
return reply.substring(idx+prefix.length()).trim(); return reply.substring(idx + prefix.length()).trim();
} }
// DEPRECATED - for API compatibility only - DO NOT USE // DEPRECATED - for API compatibility only - DO NOT USE
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String KEYSTORE_ALGORITHM;
public static String KEYSTORE_ALGORITHM;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String TRUSTSTORE_ALGORITHM;
public static String TRUSTSTORE_ALGORITHM;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String PROVIDER;
public static String PROVIDER;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String STORE_TYPE;
public static String STORE_TYPE;
} }
/* kate: indent-width 4; replace-tabs on; */ /* kate: indent-width 4; replace-tabs on; */

@ -19,11 +19,11 @@ package org.apache.commons.net.ftp;
/** /**
* FTPS-specific commands. * FTPS-specific commands.
*
* @since 2.0 * @since 2.0
* @deprecated 3.0 DO NOT USE * @deprecated 3.0 DO NOT USE
*/ */
@Deprecated @Deprecated public final class FTPSCommand {
public final class FTPSCommand {
public static final int AUTH = 0; public static final int AUTH = 0;
public static final int ADAT = 1; public static final int ADAT = 1;
public static final int PBSZ = 2; public static final int PBSZ = 2;
@ -36,7 +36,7 @@ public final class FTPSCommand {
public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT;
public static final int CLEAR_COMMAND_CHANNEL = CCC; public static final int CLEAR_COMMAND_CHANNEL = CCC;
private static final String[] _commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; private static final String[] _commands = { "AUTH", "ADAT", "PBSZ", "PROT", "CCC" };
/** /**
* Retrieve the FTPS command string corresponding to a specified * Retrieve the FTPS command string corresponding to a specified

@ -27,6 +27,7 @@ import javax.net.ssl.SSLServerSocket;
/** /**
* Server socket factory for FTPS connections. * Server socket factory for FTPS connections.
*
* @since 2.2 * @since 2.2
*/ */
public class FTPSServerSocketFactory extends ServerSocketFactory { public class FTPSServerSocketFactory extends ServerSocketFactory {
@ -39,23 +40,20 @@ public class FTPSServerSocketFactory extends ServerSocketFactory {
} }
// Override the default superclass method // Override the default superclass method
@Override @Override public ServerSocket createServerSocket() throws IOException {
public ServerSocket createServerSocket() throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket()); return init(this.context.getServerSocketFactory().createServerSocket());
} }
@Override @Override public ServerSocket createServerSocket(int port) throws IOException {
public ServerSocket createServerSocket(int port) throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port)); return init(this.context.getServerSocketFactory().createServerSocket(port));
} }
@Override @Override public ServerSocket createServerSocket(int port, int backlog) throws IOException {
public ServerSocket createServerSocket(int port, int backlog) throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); return init(this.context.getServerSocketFactory().createServerSocket(port, backlog));
} }
@Override @Override public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress)
public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress));
} }

@ -26,7 +26,6 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
/** /**
*
* Implementation of org.apache.commons.net.SocketFactory * Implementation of org.apache.commons.net.SocketFactory
* *
* @since 2.0 * @since 2.0
@ -40,18 +39,16 @@ public class FTPSSocketFactory extends SocketFactory {
} }
// Override the default implementation // Override the default implementation
@Override @Override public Socket createSocket() throws IOException {
public Socket createSocket() throws IOException{
return this.context.getSocketFactory().createSocket(); return this.context.getSocketFactory().createSocket();
} }
@Override @Override public Socket createSocket(String address, int port)
public Socket createSocket(String address, int port) throws UnknownHostException, IOException { throws UnknownHostException, IOException {
return this.context.getSocketFactory().createSocket(address, port); return this.context.getSocketFactory().createSocket(address, port);
} }
@Override @Override public Socket createSocket(InetAddress address, int port) throws IOException {
public Socket createSocket(InetAddress address, int port) throws IOException {
return this.context.getSocketFactory().createSocket(address, port); return this.context.getSocketFactory().createSocket(address, port);
} }
@ -62,51 +59,58 @@ public class FTPSSocketFactory extends SocketFactory {
} }
@Override @Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException {
return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort);
} }
// DEPRECATED METHODS - for API compatibility only - DO NOT USE // DEPRECATED METHODS - for API compatibility only - DO NOT USE
/** @param port the port /**
* @param port the port
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead}
@Deprecated */
public java.net.ServerSocket createServerSocket(int port) throws IOException { @Deprecated public java.net.ServerSocket createServerSocket(int port) throws IOException {
return this.init(this.context.getServerSocketFactory().createServerSocket(port)); return this.init(this.context.getServerSocketFactory().createServerSocket(port));
} }
/** @param port the port /**
* @param port the port
* @param backlog the backlog * @param backlog the backlog
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead}
@Deprecated */
public java.net.ServerSocket createServerSocket(int port, int backlog) throws IOException { @Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog)
throws IOException {
return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog));
} }
/** @param port the port /**
* @param port the port
* @param backlog the backlog * @param backlog the backlog
* @param ifAddress the interface * @param ifAddress the interface
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress)
@Deprecated * instead}
public java.net.ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { */
return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); @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 /**
* @param socket the socket
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)}
@Deprecated */
public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException { @Deprecated public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException {
((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true); ((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true);
return socket; return socket;
} }
} }

@ -24,37 +24,30 @@ import javax.net.ssl.X509TrustManager;
/** /**
* Do not use. * Do not use.
*
* @since 2.0 * @since 2.0
* @deprecated 3.0 use * @deprecated 3.0 use
* {@link org.apache.commons.net.util.TrustManagerUtils#getValidateServerCertificateTrustManager() * {@link org.apache.commons.net.util.TrustManagerUtils#getValidateServerCertificateTrustManager()
* TrustManagerUtils#getValidateServerCertificateTrustManager()} instead * TrustManagerUtils#getValidateServerCertificateTrustManager()} instead
*/ */
@Deprecated @Deprecated public class FTPSTrustManager implements X509TrustManager {
public class FTPSTrustManager implements X509TrustManager private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {};
{
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[]{};
/** /**
* No-op * No-op
*/ */
@Override @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) {
public void checkClientTrusted(X509Certificate[] certificates, String authType)
{
return; return;
} }
@Override @Override public void checkServerTrusted(X509Certificate[] certificates, String authType)
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException throws CertificateException {
{ for (X509Certificate certificate : certificates) {
for (X509Certificate certificate : certificates)
{
certificate.checkValidity(); certificate.checkValidity();
} }
} }
@Override @Override public X509Certificate[] getAcceptedIssuers() {
public X509Certificate[] getAcceptedIssuers()
{
return EMPTY_X509CERTIFICATE_ARRAY; return EMPTY_X509CERTIFICATE_ARRAY;
} }
} }

@ -0,0 +1,33 @@
/*
* 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 org.apache.commons.net.ftp;
import org.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);
}

@ -28,37 +28,27 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* If the cached parser wont match due to the server changed the dirstyle, * If the cached parser wont match due to the server changed the dirstyle,
* a new matching parser will be searched. * a new matching parser will be searched.
*/ */
public class CompositeFileEntryParser extends FTPFileEntryParserImpl public class CompositeFileEntryParser extends FTPFileEntryParserImpl {
{
private final FTPFileEntryParser[] ftpFileEntryParsers; private final FTPFileEntryParser[] ftpFileEntryParsers;
private FTPFileEntryParser cachedFtpFileEntryParser; private FTPFileEntryParser cachedFtpFileEntryParser;
public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) {
{
super(); super();
this.cachedFtpFileEntryParser = null; this.cachedFtpFileEntryParser = null;
this.ftpFileEntryParsers = ftpFileEntryParsers; this.ftpFileEntryParsers = ftpFileEntryParsers;
} }
@Override @Override public FTPFile parseFTPEntry(String listEntry) {
public FTPFile parseFTPEntry(String listEntry) if (cachedFtpFileEntryParser != null) {
{
if (cachedFtpFileEntryParser != null)
{
FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry);
if (matched != null) if (matched != null) {
{
return matched; return matched;
} }
} } else {
else for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers) {
{
for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers)
{
FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry);
if (matched != null) if (matched != null) {
{
cachedFtpFileEntryParser = ftpFileEntryParser; cachedFtpFileEntryParser = ftpFileEntryParser;
return matched; return matched;
} }

@ -23,7 +23,6 @@ import java.util.Calendar;
import org.apache.commons.net.ftp.Configurable; import org.apache.commons.net.ftp.Configurable;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
/** /**
* <p> * <p>
* This abstract class implements the common timestamp parsing * This abstract class implements the common timestamp parsing
@ -38,34 +37,33 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* *
* @since 1.4 * @since 1.4
*/ */
public abstract class ConfigurableFTPFileEntryParserImpl public abstract class ConfigurableFTPFileEntryParserImpl extends RegexFTPFileEntryParserImpl
extends RegexFTPFileEntryParserImpl implements Configurable {
implements Configurable
{
private final FTPTimestampParser timestampParser; private final FTPTimestampParser timestampParser;
/** /**
* constructor for this abstract class. * constructor for this abstract class.
*
* @param regex Regular expression used main parsing of the * @param regex Regular expression used main parsing of the
* file listing. * file listing.
*/ */
public ConfigurableFTPFileEntryParserImpl(String regex) public ConfigurableFTPFileEntryParserImpl(String regex) {
{
super(regex); super(regex);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
} }
/** /**
* constructor for this abstract class. * constructor for this abstract class.
*
* @param regex Regular expression used main parsing of the * @param regex Regular expression used main parsing of the
* file listing. * file listing.
* @param flags the flags to apply, see * @param flags the flags to apply, see
* {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for none. * {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for
* none.
* @since 3.4 * @since 3.4
*/ */
public ConfigurableFTPFileEntryParserImpl(String regex, int flags) public ConfigurableFTPFileEntryParserImpl(String regex, int flags) {
{
super(regex, flags); super(regex, flags);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
} }
@ -85,7 +83,6 @@ implements Configurable
return this.timestampParser.parseTimestamp(timestampStr); return this.timestampParser.parseTimestamp(timestampStr);
} }
/** /**
* Implementation of the {@link Configurable Configurable} * Implementation of the {@link Configurable Configurable}
* interface. Configures this parser by delegating to the * interface. Configures this parser by delegating to the
@ -98,9 +95,7 @@ implements Configurable
* If it is null, a default configuration defined by * If it is null, a default configuration defined by
* each concrete subclass is used instead. * each concrete subclass is used instead.
*/ */
@Override @Override public void configure(FTPClientConfig config) {
public void configure(FTPClientConfig config)
{
if (this.timestampParser instanceof Configurable) { if (this.timestampParser instanceof Configurable) {
FTPClientConfig defaultCfg = getDefaultConfiguration(); FTPClientConfig defaultCfg = getDefaultConfiguration();
if (config != null) { if (config != null) {
@ -110,9 +105,9 @@ implements Configurable
if (null == config.getRecentDateFormatStr()) { if (null == config.getRecentDateFormatStr()) {
config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr());
} }
((Configurable)this.timestampParser).configure(config); ((Configurable) this.timestampParser).configure(config);
} else { } else {
((Configurable)this.timestampParser).configure(defaultCfg); ((Configurable) this.timestampParser).configure(defaultCfg);
} }
} }
} }
@ -122,6 +117,7 @@ implements Configurable
* a default configuration to be used when that subclass is * a default configuration to be used when that subclass is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for the subclass. * @return the default configuration for the subclass.
*/ */
protected abstract FTPClientConfig getDefaultConfiguration(); protected abstract FTPClientConfig getDefaultConfiguration();

@ -23,7 +23,6 @@ import org.apache.commons.net.ftp.Configurable;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFileEntryParser; import org.apache.commons.net.ftp.FTPFileEntryParser;
/** /**
* This is the default implementation of the * This is the default implementation of the
* FTPFileEntryParserFactory interface. This is the * FTPFileEntryParserFactory interface. This is the
@ -34,14 +33,14 @@ import org.apache.commons.net.ftp.FTPFileEntryParser;
* @see org.apache.commons.net.ftp.FTPClient#listFiles * @see org.apache.commons.net.ftp.FTPClient#listFiles
* @see org.apache.commons.net.ftp.FTPClient#setParserFactory * @see org.apache.commons.net.ftp.FTPClient#setParserFactory
*/ */
public class DefaultFTPFileEntryParserFactory public class DefaultFTPFileEntryParserFactory implements FTPFileEntryParserFactory {
implements FTPFileEntryParserFactory
{
// Match a plain Java Identifier // Match a plain Java Identifier
private static final String JAVA_IDENTIFIER = "\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart})*"; 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. // 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; private static final String JAVA_QUALIFIED_NAME =
"(" + JAVA_IDENTIFIER + "\\.)+" + JAVA_IDENTIFIER;
// Create the pattern, as it will be reused many times // Create the pattern, as it will be reused many times
private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME); private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME);
@ -85,9 +84,7 @@ public class DefaultFTPFileEntryParserFactory
* the supplied key into an FTPFileEntryParser. * the supplied key into an FTPFileEntryParser.
* @see FTPFileEntryParser * @see FTPFileEntryParser
*/ */
@Override @Override public FTPFileEntryParser createFileEntryParser(String key) {
public FTPFileEntryParser createFileEntryParser(String key)
{
if (key == null) { if (key == null) {
throw new ParserInitializationException("Parser key cannot be null"); throw new ParserInitializationException("Parser key cannot be null");
} }
@ -100,8 +97,7 @@ public class DefaultFTPFileEntryParserFactory
// Is the key a possible class name? // Is the key a possible class name?
if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) { if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) {
try try {
{
Class<?> parserClass = Class.forName(key); Class<?> parserClass = Class.forName(key);
try { try {
parser = (FTPFileEntryParser) parserClass.newInstance(); parser = (FTPFileEntryParser) parserClass.newInstance();
@ -121,58 +117,38 @@ public class DefaultFTPFileEntryParserFactory
if (parser == null) { // Now try for aliases if (parser == null) { // Now try for aliases
String ukey = key.toUpperCase(java.util.Locale.ENGLISH); String ukey = key.toUpperCase(java.util.Locale.ENGLISH);
if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) {
{
parser = new UnixFTPEntryParser(config, true); parser = new UnixFTPEntryParser(config, true);
} }
// must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it // must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it
else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) {
{
parser = new UnixFTPEntryParser(config, false); parser = new UnixFTPEntryParser(config, false);
} } else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0)
{
parser = new VMSVersioningFTPEntryParser(config); parser = new VMSVersioningFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0)
{
parser = createNTFTPEntryParser(config); parser = createNTFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0)
{
parser = new OS2FTPEntryParser(config); parser = new OS2FTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0
else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || || ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) {
ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0)
{
parser = createOS400FTPEntryParser(config); parser = createOS400FTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0)
{
parser = new MVSFTPEntryParser(); // Does not currently support config parameter parser = new MVSFTPEntryParser(); // Does not currently support config parameter
} } else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0)
{
parser = new NetwareFTPEntryParser(config); parser = new NetwareFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0)
{
parser = new MacOsPeterFTPEntryParser(config); parser = new MacOsPeterFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0) {
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. // L8 normally means Unix, but move it to the end for some L8 systems that aren't.
// This check should be last! // This check should be last!
parser = new UnixFTPEntryParser(config); parser = new UnixFTPEntryParser(config);
} } else {
else
{
throw new ParserInitializationException("Unknown parser type: " + key); throw new ParserInitializationException("Unknown parser type: " + key);
} }
} }
if (parser instanceof Configurable) { if (parser instanceof Configurable) {
((Configurable)parser).configure(config); ((Configurable) parser).configure(config);
} }
return parser; return parser;
} }
@ -189,31 +165,25 @@ public class DefaultFTPFileEntryParserFactory
* where the user knows that the server uses a non-default configuration * where the user knows that the server uses a non-default configuration
* and knows what that configuration is. * and knows what that configuration is.
* </p> * </p>
*
* @param config A {@link FTPClientConfig FTPClientConfig} * @param config A {@link FTPClientConfig FTPClientConfig}
* used to configure the parser created * used to configure the parser created
*
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. * @return the @link FTPFileEntryParser FTPFileEntryParser} so created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
* @throws NullPointerException if {@code config} is {@code null} * @throws NullPointerException if {@code config} is {@code null}
* @since 1.4 * @since 1.4
*/ */
@Override @Override public FTPFileEntryParser createFileEntryParser(FTPClientConfig config)
public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) throws ParserInitializationException {
throws ParserInitializationException
{
String key = config.getServerSystemKey(); String key = config.getServerSystemKey();
return createFileEntryParser(key, config); return createFileEntryParser(key, config);
} }
public FTPFileEntryParser createUnixFTPEntryParser() {
public FTPFileEntryParser createUnixFTPEntryParser()
{
return new UnixFTPEntryParser(); return new UnixFTPEntryParser();
} }
public FTPFileEntryParser createVMSVersioningFTPEntryParser() public FTPFileEntryParser createVMSVersioningFTPEntryParser() {
{
return new VMSVersioningFTPEntryParser(); return new VMSVersioningFTPEntryParser();
} }
@ -221,8 +191,7 @@ public class DefaultFTPFileEntryParserFactory
return new NetwareFTPEntryParser(); return new NetwareFTPEntryParser();
} }
public FTPFileEntryParser createNTFTPEntryParser() public FTPFileEntryParser createNTFTPEntryParser() {
{
return createNTFTPEntryParser(null); return createNTFTPEntryParser(null);
} }
@ -230,34 +199,29 @@ public class DefaultFTPFileEntryParserFactory
* Creates an NT FTP parser: if the config exists, and the system key equals * 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, * {@link FTPClientConfig.SYST_NT} then a plain {@link NTFTPEntryParser} is used,
* otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used. * otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used.
*
* @param config the config to use, may be {@code null} * @param config the config to use, may be {@code null}
* @return the parser * @return the parser
*/ */
private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) {
{ if (config != null && FTPClientConfig.SYST_NT.equals(config.getServerSystemKey())) {
if (config != null && FTPClientConfig.SYST_NT.equals(
config.getServerSystemKey()))
{
return new NTFTPEntryParser(config); return new NTFTPEntryParser(config);
} else { } else {
// clone the config as it may be changed by the parsers (NET-602) // clone the config as it may be changed by the parsers (NET-602)
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null;
return new CompositeFileEntryParser(new FTPFileEntryParser[] return new CompositeFileEntryParser(new FTPFileEntryParser[] {
{ new NTFTPEntryParser(config), new UnixFTPEntryParser(config2,
new NTFTPEntryParser(config), config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(
new UnixFTPEntryParser(config2, config2.getServerSystemKey()))
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey()))
}); });
} }
} }
public FTPFileEntryParser createOS2FTPEntryParser() public FTPFileEntryParser createOS2FTPEntryParser() {
{
return new OS2FTPEntryParser(); return new OS2FTPEntryParser();
} }
public FTPFileEntryParser createOS400FTPEntryParser() public FTPFileEntryParser createOS400FTPEntryParser() {
{
return createOS400FTPEntryParser(null); return createOS400FTPEntryParser(null);
} }
@ -265,31 +229,26 @@ public class DefaultFTPFileEntryParserFactory
* Creates an OS400 FTP parser: if the config exists, and the system key equals * 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, * {@link FTPClientConfig.SYST_OS400} then a plain {@link OS400FTPEntryParser} is used,
* otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used. * otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used.
*
* @param config the config to use, may be {@code null} * @param config the config to use, may be {@code null}
* @return the parser * @return the parser
*/ */
private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) {
{ if (config != null && FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) {
if (config != null &&
FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey()))
{
return new OS400FTPEntryParser(config); return new OS400FTPEntryParser(config);
} else { } else {
// clone the config as it may be changed by the parsers (NET-602) // clone the config as it may be changed by the parsers (NET-602)
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null;
return new CompositeFileEntryParser(new FTPFileEntryParser[] return new CompositeFileEntryParser(new FTPFileEntryParser[] {
{ new OS400FTPEntryParser(config), new UnixFTPEntryParser(config2,
new OS400FTPEntryParser(config), config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(
new UnixFTPEntryParser(config2, config2.getServerSystemKey()))
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey()))
}); });
} }
} }
public FTPFileEntryParser createMVSEntryParser() public FTPFileEntryParser createMVSEntryParser() {
{
return new MVSFTPEntryParser(); return new MVSFTPEntryParser();
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.util.Calendar; import java.util.Calendar;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
@ -29,19 +30,18 @@ import org.apache.commons.net.ftp.FTPFile;
* DefaultFTPParserFactory by classname. It will not be chosen * DefaultFTPParserFactory by classname. It will not be chosen
* by the autodetection scheme. * by the autodetection scheme.
* </B> * </B>
*
* @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $ * @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
*/ */
public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl {
{
/** /**
* months abbreviations looked for by this parser. Also used * months abbreviations looked for by this parser. Also used
* to determine <b>which</b> month has been matched by the parser. * to determine <b>which</b> month has been matched by the parser.
*/ */
private static final String MONTHS = private static final String MONTHS = "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -49,15 +49,23 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
private static final String REGEX = 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])"
+ "([\\-]|[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*"
+ "(\\S+)\\s*" // 13 // 12
+ "(\\S*)\\s*" // 14 user + "(\\S+)\\s*"
+ "(\\d*)\\s*" // 15 group // 13
+ "(\\d*)\\s*" // 16 filesize + "(\\S*)\\s*"
+ MONTHS // 17 month // 14 user
+ "\\s*" // TODO should the space be optional? + "(\\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 // TODO \\d* should be \\d? surely ? Otherwise 01111 is allowed
+ "((?:[012]\\d*)|(?:3[01]))\\s*" // 18 date [012]\d* or 3[01] + "((?:[012]\\d*)|(?:3[01]))\\s*"
// 18 date [012]\d* or 3[01]
+ "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s"
// 20 \d\d\d\d = year OR // 20 \d\d\d\d = year OR
// 21 [01]\d or 2[0123] hour + ':' // 21 [01]\d or 2[0123] hour + ':'
@ -66,10 +74,8 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
/** /**
* The sole constructor for a EnterpriseUnixFTPEntryParser object. * The sole constructor for a EnterpriseUnixFTPEntryParser object.
*
*/ */
public EnterpriseUnixFTPEntryParser() public EnterpriseUnixFTPEntryParser() {
{
super(REGEX); super(REGEX);
} }
@ -83,15 +89,12 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
if (matches(entry)) if (matches(entry)) {
{
String usr = group(14); String usr = group(14);
String grp = group(15); String grp = group(15);
String filesize = group(16); String filesize = group(16);
@ -105,12 +108,9 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
file.setType(FTPFile.FILE_TYPE); file.setType(FTPFile.FILE_TYPE);
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -123,25 +123,20 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
int pos = MONTHS.indexOf(mo); int pos = MONTHS.indexOf(mo);
int month = pos / 4; int month = pos / 4;
final int missingUnit; // the first missing unit final int missingUnit; // the first missing unit
try try {
{
if (yr != null) if (yr != null) {
{
// it's a year; there are no hours and minutes // it's a year; there are no hours and minutes
cal.set(Calendar.YEAR, Integer.parseInt(yr)); cal.set(Calendar.YEAR, Integer.parseInt(yr));
missingUnit = Calendar.HOUR_OF_DAY; missingUnit = Calendar.HOUR_OF_DAY;
} } else {
else
{
// it must be hour/minute or we wouldn't have matched // it must be hour/minute or we wouldn't have matched
missingUnit = Calendar.SECOND; missingUnit = Calendar.SECOND;
int year = cal.get(Calendar.YEAR); int year = cal.get(Calendar.YEAR);
// if the month we're reading is greater than now, it must // if the month we're reading is greater than now, it must
// be last year // be last year
if (cal.get(Calendar.MONTH) < month) if (cal.get(Calendar.MONTH) < month) {
{
year--; year--;
} }
cal.set(Calendar.YEAR, year); cal.set(Calendar.YEAR, year);
@ -152,9 +147,7 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da)); cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da));
cal.clear(missingUnit); cal.clear(missingUnit);
file.setTimestamp(cal); file.setTimestamp(cal);
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// do nothing, date will be uninitialized // do nothing, date will be uninitialized
} }
file.setName(name); file.setName(name);

@ -16,15 +16,16 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFileEntryParser; import org.apache.commons.net.ftp.FTPFileEntryParser;
/** /**
* The interface describes a factory for creating FTPFileEntryParsers. * The interface describes a factory for creating FTPFileEntryParsers.
*
* @since 1.2 * @since 1.2
*/ */
public interface FTPFileEntryParserFactory public interface FTPFileEntryParserFactory {
{
/** /**
* Implementation should be a method that decodes the * Implementation should be a method that decodes the
* supplied key and creates an object implementing the * supplied key and creates an object implementing the
@ -32,16 +33,13 @@ public interface FTPFileEntryParserFactory
* *
* @param key A string that somehow identifies an * @param key A string that somehow identifies an
* FTPFileEntryParser to be created. * FTPFileEntryParser to be created.
*
* @return the FTPFileEntryParser created. * @return the FTPFileEntryParser created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
*/ */
public FTPFileEntryParser createFileEntryParser(String key) public FTPFileEntryParser createFileEntryParser(String key) throws ParserInitializationException;
throws ParserInitializationException;
/** /**
*<p> * <p>
* Implementation should be a method that extracts * Implementation should be a method that extracts
* a key from the supplied {@link FTPClientConfig FTPClientConfig} * a key from the supplied {@link FTPClientConfig FTPClientConfig}
* parameter and creates an object implementing the * parameter and creates an object implementing the
@ -56,13 +54,10 @@ public interface FTPFileEntryParserFactory
* *
* @param config A {@link FTPClientConfig FTPClientConfig} * @param config A {@link FTPClientConfig FTPClientConfig}
* used to configure the parser created * used to configure the parser created
*
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. * @return the @link FTPFileEntryParser FTPFileEntryParser} so created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
* @since 1.4 * @since 1.4
*/ */
public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) public FTPFileEntryParser createFileEntryParser(FTPClientConfig config)
throws ParserInitializationException; throws ParserInitializationException;
} }

@ -23,6 +23,7 @@ import java.util.Calendar;
/** /**
* This interface specifies the concept of parsing an FTP server's * This interface specifies the concept of parsing an FTP server's
* timestamp. * timestamp.
*
* @since 1.4 * @since 1.4
*/ */
public interface FTPTimestampParser { public interface FTPTimestampParser {
@ -40,6 +41,7 @@ public interface FTPTimestampParser {
* Parses the supplied datestamp parameter. This parameter typically would * Parses the supplied datestamp parameter. This parameter typically would
* have been pulled from a longer FTP listing via the regular expression * have been pulled from a longer FTP listing via the regular expression
* mechanism * mechanism
*
* @param timestampStr - the timestamp portion of the FTP directory listing * @param timestampStr - the timestamp portion of the FTP directory listing
* to be parsed * to be parsed
* @return a <code>java.util.Calendar</code> object initialized to the date * @return a <code>java.util.Calendar</code> object initialized to the date
@ -48,5 +50,4 @@ public interface FTPTimestampParser {
* the implementor can parse the input. * the implementor can parse the input.
*/ */
public Calendar parseTimestamp(String timestampStr) throws ParseException; public Calendar parseTimestamp(String timestampStr) throws ParseException;
} }

@ -36,10 +36,7 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* @see ConfigurableFTPFileEntryParserImpl * @see ConfigurableFTPFileEntryParserImpl
* @since 1.4 * @since 1.4
*/ */
public class FTPTimestampParserImpl implements public class FTPTimestampParserImpl implements FTPTimestampParser, Configurable {
FTPTimestampParser, Configurable
{
/** The date format for all dates, except possibly recent dates. Assumed to include the year. */ /** The date format for all dates, except possibly recent dates. Assumed to include the year. */
private SimpleDateFormat defaultDateFormat; private SimpleDateFormat defaultDateFormat;
@ -66,13 +63,9 @@ public class FTPTimestampParserImpl implements
* e.g. for MINUTE it would clear MILLISECOND and SECOND * e.g. for MINUTE it would clear MILLISECOND and SECOND
*/ */
private static final int[] CALENDAR_UNITS = { private static final int[] CALENDAR_UNITS = {
Calendar.MILLISECOND, Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY,
Calendar.SECOND, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR
Calendar.MINUTE, };
Calendar.HOUR_OF_DAY,
Calendar.DAY_OF_MONTH,
Calendar.MONTH,
Calendar.YEAR};
/* /*
* Return the index to the array representing the least significant * Return the index to the array representing the least significant
@ -83,11 +76,11 @@ public class FTPTimestampParserImpl implements
if (dateFormat == null) { if (dateFormat == null) {
return 0; return 0;
} }
final String FORMAT_CHARS="SsmHdM"; final String FORMAT_CHARS = "SsmHdM";
final String pattern = dateFormat.toPattern(); final String pattern = dateFormat.toPattern();
for(char ch : FORMAT_CHARS.toCharArray()) { for (char ch : FORMAT_CHARS.toCharArray()) {
if (pattern.indexOf(ch) != -1){ // found the character if (pattern.indexOf(ch) != -1) { // found the character
switch(ch) { switch (ch) {
case 'S': case 'S':
return indexOf(Calendar.MILLISECOND); return indexOf(Calendar.MILLISECOND);
case 's': case 's':
@ -111,7 +104,7 @@ public class FTPTimestampParserImpl implements
*/ */
private static int indexOf(int calendarUnit) { private static int indexOf(int calendarUnit) {
int i; int i;
for(i = 0; i <CALENDAR_UNITS.length; i++) { for (i = 0; i < CALENDAR_UNITS.length; i++) {
if (calendarUnit == CALENDAR_UNITS[i]) { if (calendarUnit == CALENDAR_UNITS[i]) {
return i; return i;
} }
@ -128,12 +121,12 @@ public class FTPTimestampParserImpl implements
if (index <= 0) { // e.g. MILLISECONDS if (index <= 0) { // e.g. MILLISECONDS
return; return;
} }
final int field = CALENDAR_UNITS[index-1]; final int field = CALENDAR_UNITS[index - 1];
// Just in case the analysis is wrong, stop clearing if // Just in case the analysis is wrong, stop clearing if
// field value is not the default. // field value is not the default.
final int value = working.get(field); final int value = working.get(field);
if (value != 0) { // don't reset if it has a value if (value != 0) { // don't reset if it has a value
// new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG // new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG
} else { } else {
working.clear(field); // reset just the required field working.clear(field); // reset just the required field
} }
@ -159,13 +152,11 @@ public class FTPTimestampParserImpl implements
* *
* This method assumes that the server time is the same as the local time. * This method assumes that the server time is the same as the local time.
* *
* @see FTPTimestampParserImpl#parseTimestamp(String, Calendar)
*
* @param timestampStr The timestamp to be parsed * @param timestampStr The timestamp to be parsed
* @return a Calendar with the parsed timestamp * @return a Calendar with the parsed timestamp
* @see FTPTimestampParserImpl#parseTimestamp(String, Calendar)
*/ */
@Override @Override public Calendar parseTimestamp(String timestampStr) throws ParseException {
public Calendar parseTimestamp(String timestampStr) throws ParseException {
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
return parseTimestamp(timestampStr, now); return parseTimestamp(timestampStr, now);
} }
@ -179,11 +170,11 @@ public class FTPTimestampParserImpl implements
* This method allows a {@link Calendar} instance to be passed in which represents the * This method allows a {@link Calendar} instance to be passed in which represents the
* current (system) time. * current (system) time.
* *
* @see FTPTimestampParser#parseTimestamp(String)
* @param timestampStr The timestamp to be parsed * @param timestampStr The timestamp to be parsed
* @param serverTime The current time for the server * @param serverTime The current time for the server
* @return the calendar * @return the calendar
* @throws ParseException if timestamp cannot be parsed * @throws ParseException if timestamp cannot be parsed
* @see FTPTimestampParser#parseTimestamp(String)
* @since 1.5 * @since 1.5
*/ */
public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException {
@ -240,10 +231,10 @@ public class FTPTimestampParserImpl implements
if (parsed != null && pp.getIndex() == timestampStr.length()) { if (parsed != null && pp.getIndex() == timestampStr.length()) {
working.setTime(parsed); working.setTime(parsed);
} else { } else {
throw new ParseException( throw new ParseException("Timestamp '"
"Timestamp '"+timestampStr+"' could not be parsed using a server time of " + timestampStr
+serverTime.getTime().toString(), + "' could not be parsed using a server time of "
pp.getErrorIndex()); + serverTime.getTime().toString(), pp.getErrorIndex());
} }
setPrecision(defaultDateSmallestUnitIndex, working); setPrecision(defaultDateSmallestUnitIndex, working);
return working; return working;
@ -255,12 +246,14 @@ public class FTPTimestampParserImpl implements
public SimpleDateFormat getDefaultDateFormat() { public SimpleDateFormat getDefaultDateFormat() {
return defaultDateFormat; return defaultDateFormat;
} }
/** /**
* @return Returns the defaultDateFormat pattern string. * @return Returns the defaultDateFormat pattern string.
*/ */
public String getDefaultDateFormatString() { public String getDefaultDateFormatString() {
return defaultDateFormat.toPattern(); return defaultDateFormat.toPattern();
} }
/** /**
* @param format The defaultDateFormat to be set. * @param format The defaultDateFormat to be set.
* @param dfs the symbols to use (may be null) * @param dfs the symbols to use (may be null)
@ -278,18 +271,21 @@ public class FTPTimestampParserImpl implements
} }
this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat); this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat);
} }
/** /**
* @return Returns the recentDateFormat. * @return Returns the recentDateFormat.
*/ */
public SimpleDateFormat getRecentDateFormat() { public SimpleDateFormat getRecentDateFormat() {
return recentDateFormat; return recentDateFormat;
} }
/** /**
* @return Returns the recentDateFormat. * @return Returns the recentDateFormat.
*/ */
public String getRecentDateFormatString() { public String getRecentDateFormatString() {
return recentDateFormat.toPattern(); return recentDateFormat.toPattern();
} }
/** /**
* @param format The recentDateFormat to set. * @param format The recentDateFormat to set.
* @param dfs the symbols to use (may be null) * @param dfs the symbols to use (may be null)
@ -316,16 +312,17 @@ public class FTPTimestampParserImpl implements
return defaultDateFormat.getDateFormatSymbols().getShortMonths(); return defaultDateFormat.getDateFormatSymbols().getShortMonths();
} }
/** /**
* @return Returns the serverTimeZone used by this parser. * @return Returns the serverTimeZone used by this parser.
*/ */
public TimeZone getServerTimeZone() { public TimeZone getServerTimeZone() {
return this.defaultDateFormat.getTimeZone(); return this.defaultDateFormat.getTimeZone();
} }
/** /**
* sets a TimeZone represented by the supplied ID string into all * sets a TimeZone represented by the supplied ID string into all
* of the parsers used by this server. * of the parsers used by this server.
*
* @param serverTimeZone Time Id java.util.TimeZone id used by * @param serverTimeZone Time Id java.util.TimeZone id used by
* the ftp server. If null the client's local time zone is assumed. * the ftp server. If null the client's local time zone is assumed.
*/ */
@ -358,13 +355,13 @@ public class FTPTimestampParserImpl implements
* to parse timestamps.</li> * to parse timestamps.</li>
* <li>otherwise use default English month names</li> * <li>otherwise use default English month names</li>
* </ul><p> * </ul><p>
* Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String)
* serverTimeZoneId}
* has been supplied via the config, set that into all date formats that have * has been supplied via the config, set that into all date formats that have
* been configured. * been configured.
* </p> * </p>
*/ */
@Override @Override public void configure(FTPClientConfig config) {
public void configure(FTPClientConfig config) {
DateFormatSymbols dfs = null; DateFormatSymbols dfs = null;
String languageCode = config.getServerLanguageCode(); String languageCode = config.getServerLanguageCode();
@ -377,7 +374,6 @@ public class FTPTimestampParserImpl implements
dfs = FTPClientConfig.lookupDateFormatSymbols("en"); dfs = FTPClientConfig.lookupDateFormatSymbols("en");
} }
String recentFormatString = config.getRecentDateFormatStr(); String recentFormatString = config.getRecentDateFormatStr();
setRecentDateFormat(recentFormatString, dfs); setRecentDateFormat(recentFormatString, dfs);
@ -391,12 +387,14 @@ public class FTPTimestampParserImpl implements
this.lenientFutureDates = config.isLenientFutureDates(); this.lenientFutureDates = config.isLenientFutureDates();
} }
/** /**
* @return Returns the lenientFutureDates. * @return Returns the lenientFutureDates.
*/ */
boolean isLenientFutureDates() { boolean isLenientFutureDates() {
return lenientFutureDates; return lenientFutureDates;
} }
/** /**
* @param lenientFutureDates The lenientFutureDates to set. * @param lenientFutureDates The lenientFutureDates to set.
*/ */

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
@ -54,12 +55,12 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* *
* @since 3.0 * @since 3.0
*/ */
public class MLSxEntryParser extends FTPFileEntryParserImpl public class MLSxEntryParser extends FTPFileEntryParserImpl {
{
// This class is immutable, so a single instance can be shared. // This class is immutable, so a single instance can be shared.
private static final MLSxEntryParser PARSER = new MLSxEntryParser(); private static final MLSxEntryParser PARSER = new MLSxEntryParser();
private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<String, Integer>(); private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<String, Integer>();
static { static {
TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE)); 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("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // listed directory
@ -68,33 +69,29 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
} }
private static int UNIX_GROUPS[] = { // Groups in order of mode digits private static int UNIX_GROUPS[] = { // Groups in order of mode digits
FTPFile.USER_ACCESS, FTPFile.USER_ACCESS, FTPFile.GROUP_ACCESS, FTPFile.WORLD_ACCESS,
FTPFile.GROUP_ACCESS,
FTPFile.WORLD_ACCESS,
}; };
private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value
/* 0 */ {}, /* 0 */ {},
/* 1 */ {FTPFile.EXECUTE_PERMISSION}, /* 1 */ { FTPFile.EXECUTE_PERMISSION },
/* 2 */ {FTPFile.WRITE_PERMISSION}, /* 2 */ { FTPFile.WRITE_PERMISSION },
/* 3 */ {FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION}, /* 3 */ { FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION },
/* 4 */ {FTPFile.READ_PERMISSION}, /* 4 */ { FTPFile.READ_PERMISSION },
/* 5 */ {FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION}, /* 5 */ { FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION },
/* 6 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION}, /* 6 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION },
/* 7 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION}, /* 7 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION },
}; };
/** /**
* Create the parser for MSLT and MSLD listing entries * Create the parser for MSLT and MSLD listing entries
* This class is immutable, so one can use {@link #getInstance()} instead. * This class is immutable, so one can use {@link #getInstance()} instead.
*/ */
public MLSxEntryParser() public MLSxEntryParser() {
{
super(); super();
} }
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
if (entry.startsWith(" ")) {// leading space means no facts are present if (entry.startsWith(" ")) {// leading space means no facts are present
if (entry.length() > 1) { // is there a path name? if (entry.length() > 1) { // is there a path name?
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
@ -104,9 +101,8 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
} else { } else {
return null; // Invalid - no pathname return null; // Invalid - no pathname
} }
} }
String parts[] = entry.split(" ",2); // Path may contain space String parts[] = entry.split(" ", 2); // Path may contain space
if (parts.length != 2 || parts[1].length() == 0) { if (parts.length != 2 || parts[1].length() == 0) {
return null; // no space found or no file name return null; // no space found or no file name
} }
@ -119,11 +115,11 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
file.setName(parts[1]); file.setName(parts[1]);
String[] facts = factList.split(";"); String[] facts = factList.split(";");
boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode="); boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode=");
for(String fact : facts) { for (String fact : facts) {
String []factparts = fact.split("=", -1); // Don't drop empty values String[] factparts = fact.split("=", -1); // Don't drop empty values
// Sample missing permission // Sample missing permission
// drwx------ 2 mirror mirror 4096 Mar 13 2010 subversion // 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 // modify=20100313224553;perm=;type=dir;unique=811U282598;UNIX.group=500;UNIX.mode=0700;UNIX.owner=500; subversion
if (factparts.length != 2) { if (factparts.length != 2) {
return null; // invalid - there was no "=" sign return null; // invalid - there was no "=" sign
} }
@ -135,37 +131,33 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH); String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH);
if ("size".equals(factname)) { if ("size".equals(factname)) {
file.setSize(Long.parseLong(factvalue)); file.setSize(Long.parseLong(factvalue));
} } else if ("sizd".equals(factname)) { // Directory size
else if ("sizd".equals(factname)) { // Directory size
file.setSize(Long.parseLong(factvalue)); file.setSize(Long.parseLong(factvalue));
} } else if ("modify".equals(factname)) {
else if ("modify".equals(factname)) {
final Calendar parsed = parseGMTdateTime(factvalue); final Calendar parsed = parseGMTdateTime(factvalue);
if (parsed == null) { if (parsed == null) {
return null; return null;
} }
file.setTimestamp(parsed); file.setTimestamp(parsed);
} } else if ("type".equals(factname)) {
else if ("type".equals(factname)) {
Integer intType = TYPE_TO_INT.get(valueLowerCase); Integer intType = TYPE_TO_INT.get(valueLowerCase);
if (intType == null) { if (intType == null) {
file.setType(FTPFile.UNKNOWN_TYPE); file.setType(FTPFile.UNKNOWN_TYPE);
} else { } else {
file.setType(intType.intValue()); file.setType(intType.intValue());
} }
} } else if (factname.startsWith("unix.")) {
else if (factname.startsWith("unix.")) {
String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH); String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH);
if ("group".equals(unixfact)){ if ("group".equals(unixfact)) {
file.setGroup(factvalue); file.setGroup(factvalue);
} else if ("owner".equals(unixfact)){ } else if ("owner".equals(unixfact)) {
file.setUser(factvalue); file.setUser(factvalue);
} else if ("mode".equals(unixfact)){ // e.g. 0[1]755 } else if ("mode".equals(unixfact)) { // e.g. 0[1]755
int off = factvalue.length()-3; // only parse last 3 digits int off = factvalue.length() - 3; // only parse last 3 digits
for(int i=0; i < 3; i++){ for (int i = 0; i < 3; i++) {
int ch = factvalue.charAt(off+i)-'0'; int ch = factvalue.charAt(off + i) - '0';
if (ch >= 0 && ch <= 7) { // Check it's valid octal if (ch >= 0 && ch <= 7) { // Check it's valid octal
for(int p : UNIX_PERMS[ch]) { for (int p : UNIX_PERMS[ch]) {
file.setPermission(UNIX_GROUPS[i], p, true); file.setPermission(UNIX_GROUPS[i], p, true);
} }
} else { } else {
@ -191,7 +183,7 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
public static Calendar parseGMTdateTime(String timestamp) { public static Calendar parseGMTdateTime(String timestamp) {
final SimpleDateFormat sdf; final SimpleDateFormat sdf;
final boolean hasMillis; final boolean hasMillis;
if (timestamp.contains(".")){ if (timestamp.contains(".")) {
sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
hasMillis = true; hasMillis = true;
} else { } else {
@ -219,7 +211,7 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
// pvals = "a" / "c" / "d" / "e" / "f" / // pvals = "a" / "c" / "d" / "e" / "f" /
// "l" / "m" / "p" / "r" / "w" // "l" / "m" / "p" / "r" / "w"
private void doUnixPerms(FTPFile file, String valueLowerCase) { private void doUnixPerms(FTPFile file, String valueLowerCase) {
for(char c : valueLowerCase.toCharArray()) { for (char c : valueLowerCase.toCharArray()) {
// TODO these are mostly just guesses at present // TODO these are mostly just guesses at present
switch (c) { switch (c) {
case 'a': // (file) may APPEnd case 'a': // (file) may APPEnd

@ -99,8 +99,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* 1 2 3 4 * 1 2 3 4
* </pre> * </pre>
*/ */
static final String JES_LEVEL_1_LIST_REGEX = static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job number "(\\S+)\\s+" + // job number
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE)
"(\\S+)\\s+" + // number of spool files "(\\S+)\\s+" + // number of spool files
@ -142,8 +141,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* </pre> * </pre>
*/ */
static final String JES_LEVEL_2_LIST_REGEX = static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job number "(\\S+)\\s+" + // job number
"(\\S+)\\s+" + // owner ignored "(\\S+)\\s+" + // owner ignored
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored
@ -240,7 +238,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* The sole constructor for a MVSFTPEntryParser object. * The sole constructor for a MVSFTPEntryParser object.
*
*/ */
public MVSFTPEntryParser() { public MVSFTPEntryParser() {
super(""); // note the regex is set in preParse. super(""); // note the regex is set in preParse.
@ -254,12 +251,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* <code> null </code> is returned. Otherwise a <code> FTPFile </code> * <code> null </code> is returned. Otherwise a <code> FTPFile </code>
* instance representing the file is returned. * instance representing the file is returned.
* *
* @param entry * @param entry A line of text from the file listing
* A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
boolean isParsed = false; boolean isParsed = false;
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
@ -305,8 +300,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* a tape archive. These entries is currently not supported by this parser. * a tape archive. These entries is currently not supported by this parser.
* A null value is returned. * A null value is returned.
* *
* @param file * @param file will be updated with Name, Type, Timestamp if parsed.
* will be updated with Name, Type, Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -320,12 +314,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
// DSORG // DSORG
if ("PS".equals(dsorg)) { if ("PS".equals(dsorg)) {
file.setType(FTPFile.FILE_TYPE); file.setType(FTPFile.FILE_TYPE);
} } else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) {
else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) {
// regex already ruled out anything other than PO or PO-E // regex already ruled out anything other than PO or PO-E
file.setType(FTPFile.DIRECTORY_TYPE); file.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else {
return false; return false;
} }
@ -356,8 +348,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [9] Id: User id for last update * [9] Id: User id for last update
* </pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -387,8 +378,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* safe context, for example from a memberlist, where the regex for some * safe context, for example from a memberlist, where the regex for some
* reason fails. Then just assign the name field of FTPFile. * reason fails. Then just assign the name field of FTPFile.
* *
* @param file
* @param entry
* @return true if the entry string is non-null and non-empty * @return true if the entry string is non-null and non-empty
*/ */
private boolean parseSimpleEntry(FTPFile file, String entry) { private boolean parseSimpleEntry(FTPFile file, String entry) {
@ -405,8 +394,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* Parse the entry as a standard unix file. Using the UnixFTPEntryParser. * Parse the entry as a standard unix file. Using the UnixFTPEntryParser.
* *
* @param file
* @param entry
* @return true: entry is parsed, false: entry could not be parsed. * @return true: entry is parsed, false: entry could not be parsed.
*/ */
private boolean parseUnixList(FTPFile file, String entry) { private boolean parseUnixList(FTPFile file, String entry) {
@ -431,10 +418,9 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [3] Job status (INPUT,ACTIVE,OUTPUT) * [3] Job status (INPUT,ACTIVE,OUTPUT)
* [4] Number of sysout files * [4] Number of sysout files
* [5] The string "Spool Files" * [5] The string "Spool Files"
*</pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -471,8 +457,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [6] The rest * [6] The rest
* </pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -497,10 +482,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* z/OS-MVS File lists * z/OS-MVS File lists
* z/OS-MVS Member lists * z/OS-MVS Member lists
* unix file lists * unix file lists
*
* @since 2.0 * @since 2.0
*/ */
@Override @Override public List<String> preParse(List<String> orig) {
public List<String> preParse(List<String> orig) {
// simply remove the header line. Composite logic will take care of the // simply remove the header line. Composite logic will take care of the
// two different types of // two different types of
// list in short order. // list in short order.
@ -536,6 +521,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* Explicitly set the type of listing being processed. * Explicitly set the type of listing being processed.
*
* @param type The listing type. * @param type The listing type.
*/ */
void setType(int type) { void setType(int type) {
@ -545,10 +531,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/* /*
* @return * @return
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_MVS, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(FTPClientConfig.SYST_MVS,
DEFAULT_DATE_FORMAT, null);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
@ -28,14 +29,11 @@ import org.apache.commons.net.ftp.FTPFile;
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @since 3.1 * @since 3.1
*/ */
public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
static final String DEFAULT_DATE_FORMAT static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
= "MMM d yyyy"; //Nov 9 2001
static final String DEFAULT_RECENT_DATE_FORMAT static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
= "MMM d HH:mm"; //Nov 9 20:06
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -57,15 +55,18 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* state) * state)
* e z/OS external link bit * e z/OS external link bit
*/ */
private static final String REGEX = private static final String REGEX = "([bcdelfmpSs-])"
"([bcdelfmpSs-])" // type (1) // type (1)
+ "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" // permission + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+"
// permission
+ "(" + "("
+ "(folder\\s+)" + "(folder\\s+)"
+ "|" + "|"
+ "((\\d+)\\s+(\\d+)\\s+)" // resource size & data size + "((\\d+)\\s+(\\d+)\\s+)"
// resource size & data size
+ ")" + ")"
+ "(\\d+)\\s+" // size + "(\\d+)\\s+"
// size
/* /*
* numeric or standard format date: * numeric or standard format date:
* yyyy-mm-dd (expecting hh:mm to follow) * yyyy-mm-dd (expecting hh:mm to follow)
@ -83,17 +84,15 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
+ "(\\S*)(\\s*.*)"; // the rest + "(\\S*)(\\s*.*)"; // the rest
/** /**
* The default constructor for a UnixFTPEntryParser object. * The default constructor for a UnixFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public MacOsPeterFTPEntryParser() public MacOsPeterFTPEntryParser() {
{
this(null); this(null);
} }
@ -103,14 +102,13 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public MacOsPeterFTPEntryParser(FTPClientConfig config) public MacOsPeterFTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -125,15 +123,13 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
boolean isDevice = false; boolean isDevice = false;
if (matches(entry)) if (matches(entry)) {
{
String typeStr = group(1); String typeStr = group(1);
String hardLinkCount = "0"; String hardLinkCount = "0";
String usr = null; String usr = null;
@ -143,12 +139,9 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
String name = group(23); String name = group(23);
String endtoken = group(24); String endtoken = group(24);
try try {
{
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -156,8 +149,7 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// 'translucent' filesystems, of which a 'union' filesystem is one. // 'translucent' filesystems, of which a 'union' filesystem is one.
// bcdelfmpSs- // bcdelfmpSs-
switch (typeStr.charAt(0)) switch (typeStr.charAt(0)) {
{
case 'd': case 'd':
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
break; break;
@ -183,33 +175,23 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setType(type); file.setType(type);
int g = 4; int g = 4;
for (int access = 0; access < 3; access++, g += 4) for (int access = 0; access < 3; access++, g += 4) {
{
// Use != '-' to avoid having to check for suid and sticky bits // Use != '-' to avoid having to check for suid and sticky bits
file.setPermission(access, FTPFile.READ_PERMISSION, file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-")));
(!group(g).equals("-"))); file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-")));
file.setPermission(access, FTPFile.WRITE_PERMISSION,
(!group(g + 1).equals("-")));
String execPerm = group(g + 2); String execPerm = group(g + 2);
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) {
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
} } else {
else
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
} }
} }
if (!isDevice) if (!isDevice) {
{ try {
try
{
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); file.setHardLinkCount(Integer.parseInt(hardLinkCount));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
} }
@ -217,42 +199,29 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (null == endtoken) if (null == endtoken) {
{
file.setName(name); file.setName(name);
} } else {
else
{
// oddball cases like symbolic links, file names // oddball cases like symbolic links, file names
// with spaces in them. // with spaces in them.
name += endtoken; name += endtoken;
if (type == FTPFile.SYMBOLIC_LINK_TYPE) if (type == FTPFile.SYMBOLIC_LINK_TYPE) {
{
int end = name.indexOf(" -> "); int end = name.indexOf(" -> ");
// Give up if no link indicator is present // Give up if no link indicator is present
if (end == -1) if (end == -1) {
{
file.setName(name); file.setName(name);
} } else {
else
{
file.setName(name.substring(0, end)); file.setName(name.substring(0, end));
file.setLink(name.substring(end + 4)); file.setLink(name.substring(end + 4));
} }
} else {
}
else
{
file.setName(name); file.setName(name);
} }
} }
@ -265,14 +234,11 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(
FTPClientConfig.SYST_UNIX,
DEFAULT_DATE_FORMAT,
DEFAULT_RECENT_DATE_FORMAT); DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -29,14 +30,11 @@ import org.apache.commons.net.ftp.FTPFile;
* @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy hh:mma"; //11-09-01 12:30PM
= "MM-dd-yy hh:mma"; //11-09-01 12:30PM
private static final String DEFAULT_DATE_FORMAT2 private static final String DEFAULT_DATE_FORMAT2 = "MM-dd-yy kk:mm"; //11-09-01 18:30
= "MM-dd-yy kk:mm"; //11-09-01 18:30
private final FTPTimestampParser timestampParser; private final FTPTimestampParser timestampParser;
@ -51,13 +49,12 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The sole constructor for an NTFTPEntryParser object. * The sole constructor for an NTFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public NTFTPEntryParser() public NTFTPEntryParser() {
{
this(null); this(null);
} }
@ -67,23 +64,20 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public NTFTPEntryParser(FTPClientConfig config) public NTFTPEntryParser(FTPClientConfig config) {
{
super(REGEX, Pattern.DOTALL); super(REGEX, Pattern.DOTALL);
configure(config); configure(config);
FTPClientConfig config2 = new FTPClientConfig( FTPClientConfig config2 =
FTPClientConfig.SYST_NT, new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT2, null);
DEFAULT_DATE_FORMAT2,
null);
config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2); config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
((Configurable)this.timestampParser).configure(config2); ((Configurable) this.timestampParser).configure(config2);
} }
/** /**
@ -96,52 +90,37 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
f.setRawListing(entry); f.setRawListing(entry);
if (matches(entry)) if (matches(entry)) {
{ String datestr = group(1) + " " + group(2);
String datestr = group(1)+" "+group(2);
String dirString = group(3); String dirString = group(3);
String size = group(4); String size = group(4);
String name = group(5); String name = group(5);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// parsing fails, try the other date format // parsing fails, try the other date format
try try {
{
f.setTimestamp(timestampParser.parseTimestamp(datestr)); f.setTimestamp(timestampParser.parseTimestamp(datestr));
} } catch (ParseException e2) {
catch (ParseException e2)
{
// intentionally do nothing // intentionally do nothing
} }
} }
if (null == name || name.equals(".") || name.equals("..")) if (null == name || name.equals(".") || name.equals("..")) {
{
return (null); return (null);
} }
f.setName(name); f.setName(name);
if ("<DIR>".equals(dirString)) {
if ("<DIR>".equals(dirString))
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
f.setSize(0); f.setSize(0);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
if (null != size) if (null != size) {
{
f.setSize(Long.parseLong(size)); f.setSize(Long.parseLong(size));
} }
} }
@ -154,14 +133,10 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override public FTPClientConfig getDefaultConfiguration() {
public FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_NT,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -23,14 +23,15 @@ import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
/** /**
* Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of
* the proprietary
* extensions for Novell-specific operations are not supported. See * 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"> * <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> * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html</a>
* for more details. * for more details.
* *
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @since 1.5 * @since 1.5
*/ */
public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
@ -58,8 +59,8 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* The default constructor for a NetwareFTPEntryParser object. * The default constructor for a NetwareFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
@ -73,8 +74,8 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
@ -96,11 +97,13 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* <li><b>S</b> - Supervisor; All rights. * <li><b>S</b> - Supervisor; All rights.
* <li><b>R</b> - Read; Right to open and read or execute. * <li><b>R</b> - Read; Right to open and read or execute.
* <li><b>W</b> - Write; Right to open and modify. * <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>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>E</b> - Erase; Right to delete.
* <li><b>M</b> - Modify; Right to rename a file and to change attributes. * <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>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. * <li><b>A</b> - Access Control; Right to modify trustee assignments and the Inherited Rights
* Mask.
* </ul> * </ul>
* *
* See * See
@ -111,8 +114,7 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
if (matches(entry)) { if (matches(entry)) {
@ -148,30 +150,26 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
// Now set the permissions (or at least a subset thereof - full permissions would probably require // Now set the permissions (or at least a subset thereof - full permissions would probably require
// subclassing FTPFile and adding extra metainformation there) // subclassing FTPFile and adding extra metainformation there)
if (attrib.indexOf("R") != -1) { if (attrib.indexOf("R") != -1) {
f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
true);
} }
if (attrib.indexOf("W") != -1) { if (attrib.indexOf("W") != -1) {
f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
true);
} }
return (f); return (f);
} }
return null; return null;
} }
/** /**
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_RECENT_DATE_FORMAT);
DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
@ -31,13 +32,11 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
{ {
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy HH:mm"; //11-09-01 12:30
= "MM-dd-yy HH:mm"; //11-09-01 12:30
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
*/ */
private static final String REGEX = private static final String REGEX = "\\s*([0-9]+)\\s*"
"\\s*([0-9]+)\\s*"
+ "(\\s+|[A-Z]+)\\s*" + "(\\s+|[A-Z]+)\\s*"
+ "(DIR|\\s+)\\s*" + "(DIR|\\s+)\\s*"
+ "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */
@ -46,13 +45,12 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The default constructor for a OS2FTPEntryParser object. * The default constructor for a OS2FTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public OS2FTPEntryParser() public OS2FTPEntryParser() {
{
this(null); this(null);
} }
@ -62,14 +60,13 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public OS2FTPEntryParser(FTPClientConfig config) public OS2FTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -84,39 +81,28 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
if (matches(entry)) if (matches(entry)) {
{
String size = group(1); String size = group(1);
String attrib = group(2); String attrib = group(2);
String dirString = group(3); String dirString = group(3);
String datestr = group(4)+" "+group(5); String datestr = group(4) + " " + group(5);
String name = group(6); String name = group(6);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
//is it a DIR or a file //is it a DIR or a file
if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) {
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
} }
//set the name //set the name
f.setName(name.trim()); f.setName(name.trim());
@ -126,21 +112,16 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
return (f); return (f);
} }
return null; return null;
} }
/** /**
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_OS2, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_OS2,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -165,9 +165,12 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* [echo] Downloading members of a file: * [echo] Downloading members of a file:
* [ftp] getting files * [ftp] getting files
* [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUN.MBR * [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT -
* [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNER.MBR * FTP\i5-downloads-file\RUN.MBR
* [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNERBND.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 * [ftp] 3 files retrieved
* *
* *
@ -196,12 +199,18 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* [echo] Downloading members of all files of a library: * [echo] Downloading members of all files of a library:
* [ftp] getting files * [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\RUN.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR * FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR
* [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR * [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR * FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR
* [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR * [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR * 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 * [ftp] 6 files retrieved
* *
* *
@ -231,31 +240,24 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* </pre> * </pre>
*/ */
public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl 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 DEFAULT_DATE_FORMAT
= "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24
private static final String REGEX = "(\\S+)\\s+" // user
private static final String REGEX =
"(\\S+)\\s+" // user
+ "(?:(\\d+)\\s+)?" // size, empty for members + "(?:(\\d+)\\s+)?" // size, empty for members
+ "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members + "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members
+ "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM + "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM
+ "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE + "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE
/** /**
* The default constructor for a OS400FTPEntryParser object. * The default constructor for a OS400FTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public OS400FTPEntryParser() public OS400FTPEntryParser() {
{
this(null); this(null);
} }
@ -265,69 +267,52 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public OS400FTPEntryParser(FTPClientConfig config) public OS400FTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@Override public FTPFile parseFTPEntry(String entry) {
@Override
public FTPFile parseFTPEntry(String entry)
{
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
if (matches(entry)) if (matches(entry)) {
{
String usr = group(1); String usr = group(1);
String filesize = group(2); String filesize = group(2);
String datestr = ""; String datestr = "";
if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) {
{ datestr = group(3) + " " + group(4);
datestr = group(3)+" "+group(4);
} }
String typeStr = group(5); String typeStr = group(5);
String name = group(6); String name = group(6);
boolean mustScanForPathSeparator = true; boolean mustScanForPathSeparator = true;
try try {
{
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (typeStr.equalsIgnoreCase("*STMF")) {
if (typeStr.equalsIgnoreCase("*STMF"))
{
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) {
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*DIR")) {
else if (typeStr.equalsIgnoreCase("*DIR"))
{
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) {
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*FILE")) {
else if (typeStr.equalsIgnoreCase("*FILE"))
{
// File, defines the structure of the data (columns of a row) // File, defines the structure of the data (columns of a row)
// but the data is stored in one or more members. Typically a // but the data is stored in one or more members. Typically a
// source file contains multiple members whereas it is // source file contains multiple members whereas it is
@ -335,27 +320,20 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// file. // file.
// Save files are a special type of files which are used // Save files are a special type of files which are used
// to save objects, e.g. for backups. // to save objects, e.g. for backups.
if (name != null && name.toUpperCase().endsWith(".SAVF")) if (name != null && name.toUpperCase().endsWith(".SAVF")) {
{
mustScanForPathSeparator = false; mustScanForPathSeparator = false;
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
} } else {
else
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*MEM")) {
else if (typeStr.equalsIgnoreCase("*MEM"))
{
mustScanForPathSeparator = false; mustScanForPathSeparator = false;
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
if (isNullOrEmpty(name)) if (isNullOrEmpty(name)) {
{
return null; return null;
} }
if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) {
{
return null; return null;
} }
@ -365,9 +343,7 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// use the separator of the FTP server, which is a forward // use the separator of the FTP server, which is a forward
// slash in case of an AS/400. // slash in case of an AS/400.
name = name.replace('/', File.separatorChar); name = name.replace('/', File.separatorChar);
} } else {
else
{
type = FTPFile.UNKNOWN_TYPE; type = FTPFile.UNKNOWN_TYPE;
} }
@ -375,24 +351,18 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (name.endsWith("/")) if (name.endsWith("/")) {
{
name = name.substring(0, name.length() - 1); name = name.substring(0, name.length() - 1);
} }
if (mustScanForPathSeparator) if (mustScanForPathSeparator) {
{
int pos = name.lastIndexOf('/'); int pos = name.lastIndexOf('/');
if (pos > -1) if (pos > -1) {
{
name = name.substring(pos + 1); name = name.substring(pos + 1);
} }
} }
@ -405,7 +375,6 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
} }
/** /**
*
* @param string String value that is checked for <code>null</code> * @param string String value that is checked for <code>null</code>
* or empty. * or empty.
* @return <code>true</code> for <code>null</code> or empty values, * @return <code>true</code> for <code>null</code> or empty values,
@ -422,14 +391,10 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_OS400, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_OS400,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -54,9 +54,7 @@ public class ParserInitializationException extends RuntimeException {
* @return the root cause of this exception being thrown * @return the root cause of this exception being thrown
* @deprecated use {@link #getCause()} instead * @deprecated use {@link #getCause()} instead
*/ */
@Deprecated @Deprecated public Throwable getRootCause() {
public Throwable getRootCause() {
return super.getCause(); return super.getCause();
} }
} }

@ -15,7 +15,6 @@
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.util.regex.MatchResult; import java.util.regex.MatchResult;
@ -32,8 +31,7 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* *
* This is the base class for all regular expression based FTPFileEntryParser classes * This is the base class for all regular expression based FTPFileEntryParser classes
*/ */
public abstract class RegexFTPFileEntryParserImpl extends public abstract class RegexFTPFileEntryParserImpl extends FTPFileEntryParserImpl {
FTPFileEntryParserImpl {
/** /**
* internal pattern the matcher tries to match, representing a file * internal pattern the matcher tries to match, representing a file
* entry * entry
@ -57,9 +55,8 @@ public abstract class RegexFTPFileEntryParserImpl extends
* *
* @param regex The regular expression with which this object is * @param regex The regular expression with which this object is
* initialized. * initialized.
* * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* @throws IllegalArgumentException * be seen in
* 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 * 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 * been created with a bad regular expression. Since the parser must be
* created before use, this means that any bad parser subclasses created * created before use, this means that any bad parser subclasses created
@ -77,9 +74,8 @@ public abstract class RegexFTPFileEntryParserImpl extends
* @param regex The regular expression with which this object is * @param regex The regular expression with which this object is
* initialized. * initialized.
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. * @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
* @throws IllegalArgumentException * be seen in
* 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 * 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 * been created with a bad regular expression. Since the parser must be
* created before use, this means that any bad parser subclasses created * created before use, this means that any bad parser subclasses created
@ -126,7 +122,6 @@ public abstract class RegexFTPFileEntryParserImpl extends
* method. * method.
* *
* @param matchnum match group number to be retrieved * @param matchnum match group number to be retrieved
*
* @return the content of the <code>matchnum'th</code> group of the internal * @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 * match or null if this method is called without a match having
* been made. * been made.
@ -148,8 +143,10 @@ public abstract class RegexFTPFileEntryParserImpl extends
public String getGroupsAsString() { public String getGroupsAsString() {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
for (int i = 1; i <= this.result.groupCount(); i++) { for (int i = 1; i <= this.result.groupCount(); i++) {
b.append(i).append(") ").append(this.result.group(i)).append( b.append(i)
System.getProperty("line.separator")); .append(") ")
.append(this.result.group(i))
.append(System.getProperty("line.separator"));
} }
return b.toString(); return b.toString();
} }
@ -157,25 +154,26 @@ public abstract class RegexFTPFileEntryParserImpl extends
/** /**
* Alter the current regular expression being utilised for entry parsing * Alter the current regular expression being utilised for entry parsing
* and create a new {@link Pattern} instance. * and create a new {@link Pattern} instance.
*
* @param regex The new regular expression * @param regex The new regular expression
* @return true * @return true
* @since 2.0
* @throws IllegalArgumentException if the regex cannot be compiled * @throws IllegalArgumentException if the regex cannot be compiled
* @since 2.0
*/ */
public boolean setRegex(final String regex) { public boolean setRegex(final String regex) {
compileRegex(regex, 0); compileRegex(regex, 0);
return true; return true;
} }
/** /**
* Alter the current regular expression being utilised for entry parsing * Alter the current regular expression being utilised for entry parsing
* and create a new {@link Pattern} instance. * and create a new {@link Pattern} instance.
*
* @param regex The new regular expression * @param regex The new regular expression
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
* @return true * @return true
* @since 3.4
* @throws IllegalArgumentException if the regex cannot be compiled * @throws IllegalArgumentException if the regex cannot be compiled
* @since 3.4
*/ */
public boolean setRegex(final String regex, final int flags) { public boolean setRegex(final String regex, final int flags) {
compileRegex(regex, flags); compileRegex(regex, flags);

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
@ -30,31 +31,28 @@ import org.apache.commons.net.ftp.FTPFile;
* This class is based on the logic of Daniel Savarese's * This class is based on the logic of Daniel Savarese's
* DefaultFTPListParser, but adapted to use regular expressions and to fit the * DefaultFTPListParser, but adapted to use regular expressions and to fit the
* new FTPFileEntryParser interface. * new FTPFileEntryParser interface.
*
* @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $ * @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
static final String DEFAULT_DATE_FORMAT static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
= "MMM d yyyy"; //Nov 9 2001
static final String DEFAULT_RECENT_DATE_FORMAT static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
= "MMM d HH:mm"; //Nov 9 20:06
static final String NUMERIC_DATE_FORMAT static final String NUMERIC_DATE_FORMAT = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
= "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
// Suffixes used in Japanese listings after the numeric values // Suffixes used in Japanese listings after the numeric values
private static final String JA_MONTH = "\u6708"; private static final String JA_MONTH = "\u6708";
private static final String JA_DAY = "\u65e5"; private static final String JA_DAY = "\u65e5";
private static final String JA_YEAR = "\u5e74"; private static final String JA_YEAR = "\u5e74";
private static final String DEFAULT_DATE_FORMAT_JA private static final String DEFAULT_DATE_FORMAT_JA =
= "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年 "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年
private static final String DEFAULT_RECENT_DATE_FORMAT_JA private static final String DEFAULT_RECENT_DATE_FORMAT_JA =
= "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10 "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10
/** /**
* Some Linux distributions are now shipping an FTP server which formats * Some Linux distributions are now shipping an FTP server which formats
@ -69,10 +67,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Steve Cohen - 2005-04-17 * Steve Cohen - 2005-04-17
*/ */
public static final FTPClientConfig NUMERIC_DATE_CONFIG = public static final FTPClientConfig NUMERIC_DATE_CONFIG =
new FTPClientConfig( new FTPClientConfig(FTPClientConfig.SYST_UNIX, NUMERIC_DATE_FORMAT, null);
FTPClientConfig.SYST_UNIX,
NUMERIC_DATE_FORMAT,
null);
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -99,9 +94,8 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* this is not allowed for here as does not appear to be shown by FTP servers * this is not allowed for here as does not appear to be shown by FTP servers
* {@code @} file has extended attributes * {@code @} file has extended attributes
*/ */
private static final String REGEX = private static final String REGEX = "([bcdelfmpSs-])" // file type
"([bcdelfmpSs-])" // file type + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions
+"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions
+ "\\s*" // separator TODO why allow it to be omitted?? + "\\s*" // separator TODO why allow it to be omitted??
@ -124,13 +118,10 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* diacritics (e.g. umlaut) in some abbreviations. * diacritics (e.g. umlaut) in some abbreviations.
* Japanese uses numeric day and month with suffixes to distinguish them * Japanese uses numeric day and month with suffixes to distinguish them
* [d]dXX [d]dZZ * [d]dXX [d]dZZ
*/ */ + "(" + "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
+ "("+
"(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
"|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d "|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d
"|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM "|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM
"|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")"+ "|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")" + ")"
")"
+ "\\s+" // separator + "\\s+" // separator
@ -138,14 +129,12 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
year (for non-recent standard format) - yyyy year (for non-recent standard format) - yyyy
or time (for numeric or recent standard format) [h]h:mm or time (for numeric or recent standard format) [h]h:mm
or Japanese year - yyyyXX or Japanese year - yyyyXX
*/ */ + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
+ "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
+ "\\s" // separator + "\\s" // separator
+ "(.*)"; // the rest (21) + "(.*)"; // the rest (21)
// if true, leading spaces are trimmed from file names // if true, leading spaces are trimmed from file names
// this was the case for the original implementation // this was the case for the original implementation
final boolean trimLeadingSpaces; // package protected for access from test code final boolean trimLeadingSpaces; // package protected for access from test code
@ -153,13 +142,12 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The default constructor for a UnixFTPEntryParser object. * The default constructor for a UnixFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public UnixFTPEntryParser() public UnixFTPEntryParser() {
{
this(null); this(null);
} }
@ -169,14 +157,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public UnixFTPEntryParser(FTPClientConfig config) public UnixFTPEntryParser(FTPClientConfig config) {
{
this(config, false); this(config, false);
} }
@ -187,14 +174,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @param trimLeadingSpaces if {@code true}, trim leading spaces from file names * @param trimLeadingSpaces if {@code true}, trim leading spaces from file names
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 3.4 * @since 3.4
*/ */
public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
this.trimLeadingSpaces = trimLeadingSpaces; this.trimLeadingSpaces = trimLeadingSpaces;
@ -203,8 +189,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* Preparse the list to discard "total nnn" lines * Preparse the list to discard "total nnn" lines
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
ListIterator<String> iter = original.listIterator(); ListIterator<String> iter = original.listIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
String entry = iter.next(); String entry = iter.next();
@ -225,15 +210,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
boolean isDevice = false; boolean isDevice = false;
if (matches(entry)) if (matches(entry)) {
{
String typeStr = group(1); String typeStr = group(1);
String hardLinkCount = group(15); String hardLinkCount = group(15);
String usr = group(16); String usr = group(16);
@ -245,19 +228,16 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
name = name.replaceFirst("^\\s+", ""); name = name.replaceFirst("^\\s+", "");
} }
try try {
{
if (group(19).contains(JA_MONTH)) { // special processing for Japanese format if (group(19).contains(JA_MONTH)) { // special processing for Japanese format
FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl(); FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl();
jaParser.configure(new FTPClientConfig( jaParser.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA,
FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA, DEFAULT_RECENT_DATE_FORMAT_JA)); DEFAULT_RECENT_DATE_FORMAT_JA));
file.setTimestamp(jaParser.parseTimestamp(datestr)); file.setTimestamp(jaParser.parseTimestamp(datestr));
} else { } else {
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} }
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -265,8 +245,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// 'translucent' filesystems, of which a 'union' filesystem is one. // 'translucent' filesystems, of which a 'union' filesystem is one.
// bcdelfmpSs- // bcdelfmpSs-
switch (typeStr.charAt(0)) switch (typeStr.charAt(0)) {
{
case 'd': case 'd':
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
break; break;
@ -292,33 +271,23 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setType(type); file.setType(type);
int g = 4; int g = 4;
for (int access = 0; access < 3; access++, g += 4) for (int access = 0; access < 3; access++, g += 4) {
{
// Use != '-' to avoid having to check for suid and sticky bits // Use != '-' to avoid having to check for suid and sticky bits
file.setPermission(access, FTPFile.READ_PERMISSION, file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-")));
(!group(g).equals("-"))); file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-")));
file.setPermission(access, FTPFile.WRITE_PERMISSION,
(!group(g + 1).equals("-")));
String execPerm = group(g + 2); String execPerm = group(g + 2);
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) {
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
} } else {
else
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
} }
} }
if (!isDevice) if (!isDevice) {
{ try {
try
{
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); file.setHardLinkCount(Integer.parseInt(hardLinkCount));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
} }
@ -326,35 +295,25 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
// oddball cases like symbolic links, file names // oddball cases like symbolic links, file names
// with spaces in them. // with spaces in them.
if (type == FTPFile.SYMBOLIC_LINK_TYPE) if (type == FTPFile.SYMBOLIC_LINK_TYPE) {
{
int end = name.indexOf(" -> "); int end = name.indexOf(" -> ");
// Give up if no link indicator is present // Give up if no link indicator is present
if (end == -1) if (end == -1) {
{
file.setName(name); file.setName(name);
} } else {
else
{
file.setName(name.substring(0, end)); file.setName(name.substring(0, end));
file.setLink(name.substring(end + 4)); file.setLink(name.substring(end + 4));
} }
} else {
}
else
{
file.setName(name); file.setName(name);
} }
return file; return file;
@ -366,14 +325,11 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(
FTPClientConfig.SYST_UNIX,
DEFAULT_DATE_FORMAT,
DEFAULT_RECENT_DATE_FORMAT); DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
@ -28,9 +29,12 @@ import org.apache.commons.net.ftp.FTPFile;
* Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems.
* This is a sample of VMS LIST output * 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;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER]
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", * (RWED,RWED,RWED,RE)",
* "DATA.DIR;1 1/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> * <P><B>
* Note: VMSFTPEntryParser can only be instantiated through the * Note: VMSFTPEntryParser can only be instantiated through the
* DefaultFTPParserFactory by classname. It will not be chosen * DefaultFTPParserFactory by classname. It will not be chosen
@ -39,15 +43,12 @@ import org.apache.commons.net.ftp.FTPFile;
* <P> * <P>
* *
* @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
*
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
*/ */
public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
= "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -55,23 +56,21 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
private static final String REGEX = private static final String REGEX =
"(.*?;[0-9]+)\\s*" //1 file and version "(.*?;[0-9]+)\\s*" //1 file and version
+ "(\\d+)/\\d+\\s*" //2 size/allocated + "(\\d+)/\\d+\\s*" //2 size/allocated
+"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time + "(\\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 + "\\[(([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) + "\\([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]* ? // TODO - perhaps restrict permissions to [RWED]* ?
/** /**
* Constructor for a VMSFTPEntryParser object. * Constructor for a VMSFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public VMSFTPEntryParser() public VMSFTPEntryParser() {
{
this(null); this(null);
} }
@ -81,14 +80,13 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public VMSFTPEntryParser(FTPClientConfig config) public VMSFTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -103,34 +101,27 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
//one block in VMS equals 512 bytes //one block in VMS equals 512 bytes
long longBlock = 512; long longBlock = 512;
if (matches(entry)) if (matches(entry)) {
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
f.setRawListing(entry); f.setRawListing(entry);
String name = group(1); String name = group(1);
String size = group(2); String size = group(2);
String datestr = group(3)+" "+group(4); String datestr = group(3) + " " + group(4);
String owner = group(5); String owner = group(5);
String permissions[] = new String[3]; String permissions[] = new String[3];
permissions[0]= group(9); permissions[0] = group(9);
permissions[1]= group(10); permissions[1] = group(10);
permissions[2]= group(11); permissions[2] = group(11);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
String grp; String grp;
String user; String user;
StringTokenizer t = new StringTokenizer(owner, ","); StringTokenizer t = new StringTokenizer(owner, ",");
@ -148,22 +139,16 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
user = null; user = null;
} }
if (name.lastIndexOf(".DIR") != -1) if (name.lastIndexOf(".DIR") != -1) {
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
} }
//set FTPFile name //set FTPFile name
//Check also for versions to be returned or not //Check also for versions to be returned or not
if (isVersioning()) if (isVersioning()) {
{
f.setName(name); f.setName(name);
} } else {
else
{
name = name.substring(0, name.lastIndexOf(";")); name = name.substring(0, name.lastIndexOf(";"));
f.setName(name); f.setName(name);
} }
@ -181,13 +166,12 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
//R (read) W (write) E (execute) D (delete) //R (read) W (write) E (execute) D (delete)
//iterate for OWNER GROUP WORLD permissions //iterate for OWNER GROUP WORLD permissions
for (int access = 0; access < 3; access++) for (int access = 0; access < 3; access++) {
{
String permission = permissions[access]; String permission = permissions[access];
f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0);
f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0);
f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0);
} }
return f; return f;
@ -195,7 +179,6 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
return null; return null;
} }
/** /**
* Reads the next entry using the supplied BufferedReader object up to * Reads the next entry using the supplied BufferedReader object up to
* whatever delemits one entry from the next. This parser cannot use * whatever delemits one entry from the next. This parser cannot use
@ -204,25 +187,20 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
@Override @Override public String readNextEntry(BufferedReader reader) throws IOException {
public String readNextEntry(BufferedReader reader) throws IOException
{
String line = reader.readLine(); String line = reader.readLine();
StringBuilder entry = new StringBuilder(); StringBuilder entry = new StringBuilder();
while (line != null) while (line != null) {
{
if (line.startsWith("Directory") || line.startsWith("Total")) { if (line.startsWith("Directory") || line.startsWith("Total")) {
line = reader.readLine(); line = reader.readLine();
continue; continue;
} }
entry.append(line); entry.append(line);
if (line.trim().endsWith(")")) if (line.trim().endsWith(")")) {
{
break; break;
} }
line = reader.readLine(); line = reader.readLine();
@ -238,32 +216,29 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_VMS,
DEFAULT_DATE_FORMAT,
null);
} }
// DEPRECATED METHODS - for API compatibility only - DO NOT USE // DEPRECATED METHODS - for API compatibility only - DO NOT USE
/** /**
* DO NOT USE * DO NOT USE
*
* @param listStream the stream * @param listStream the stream
* @return the array of files * @return the array of files
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) No other FTPFileEntryParser implementations have this method. * @deprecated (2.2) No other FTPFileEntryParser implementations have this method.
*/ */
@Deprecated @Deprecated public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException {
public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException { org.apache.commons.net.ftp.FTPListParseEngine engine =
org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this); new org.apache.commons.net.ftp.FTPListParseEngine(this);
engine.readServerList(listStream, null); engine.readServerList(listStream, null);
return engine.getFiles(); return engine.getFiles();
} }
} }
/* Emacs configuration /* Emacs configuration

@ -34,32 +34,31 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* *
* This is a sample of VMS LIST output * 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;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER]
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", * (RWED,RWED,RWED,RE)",
* "DATA.DIR;1 1/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> * <P>
* *
* @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ * @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $
*
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser {
{
private final Pattern _preparse_pattern_; private final Pattern _preparse_pattern_;
private static final String PRE_PARSE_REGEX = private static final String PRE_PARSE_REGEX = "(.*?);([0-9]+)\\s*.*";
"(.*?);([0-9]+)\\s*.*";
/** /**
* Constructor for a VMSFTPEntryParser object. * Constructor for a VMSFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public VMSVersioningFTPEntryParser() public VMSVersioningFTPEntryParser() {
{
this(null); this(null);
} }
@ -69,27 +68,21 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public VMSVersioningFTPEntryParser(FTPClientConfig config) public VMSVersioningFTPEntryParser(FTPClientConfig config) {
{
super(); super();
configure(config); configure(config);
try try {
{
//_preparse_matcher_ = new Perl5Matcher(); //_preparse_matcher_ = new Perl5Matcher();
_preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX);
} catch (PatternSyntaxException pse) {
throw new IllegalArgumentException("Unparseable regex supplied: " + PRE_PARSE_REGEX);
} }
catch (PatternSyntaxException pse)
{
throw new IllegalArgumentException (
"Unparseable regex supplied: " + PRE_PARSE_REGEX);
}
} }
/** /**
@ -98,11 +91,9 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
* multiple files with the same name to remove the duplicates .. * multiple files with the same name to remove the duplicates ..
* *
* @param original Original list * @param original Original list
*
* @return Original list purged of duplicates * @return Original list purged of duplicates
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
HashMap<String, Integer> existingEntries = new HashMap<String, Integer>(); HashMap<String, Integer> existingEntries = new HashMap<String, Integer>();
ListIterator<String> iter = original.listIterator(); ListIterator<String> iter = original.listIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
@ -123,7 +114,6 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
} }
existingEntries.put(name, nv); existingEntries.put(name, nv);
} }
} }
// we've now removed all entries less than with less than the largest // we've now removed all entries less than with less than the largest
// version number for each name that were listed after the largest. // version number for each name that were listed after the largest.
@ -145,17 +135,13 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
} }
} }
} }
} }
return original; return original;
} }
@Override protected boolean isVersioning() {
@Override
protected boolean isVersioning() {
return true; return true;
} }
} }
/* Emacs configuration /* Emacs configuration

@ -28,18 +28,17 @@ import java.io.Reader;
* *
* @since 3.0 * @since 3.0
*/ */
public final class CRLFLineReader extends BufferedReader public final class CRLFLineReader extends BufferedReader {
{
private static final char LF = '\n'; private static final char LF = '\n';
private static final char CR = '\r'; private static final char CR = '\r';
/** /**
* Creates a CRLFLineReader that wraps an existing Reader * Creates a CRLFLineReader that wraps an existing Reader
* input source. * input source.
*
* @param reader The Reader input source. * @param reader The Reader input source.
*/ */
public CRLFLineReader(Reader reader) public CRLFLineReader(Reader reader) {
{
super(reader); super(reader);
} }
@ -47,18 +46,17 @@ public final class CRLFLineReader extends BufferedReader
* Read a line of text. * Read a line of text.
* A line is considered to be terminated by carriage return followed immediately by a linefeed. * A line is considered to be terminated by carriage return followed immediately by a linefeed.
* This contrasts with BufferedReader which also allows other combinations. * This contrasts with BufferedReader which also allows other combinations.
*
* @since 3.0 * @since 3.0
*/ */
@Override @Override public String readLine() throws IOException {
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int intch; int intch;
boolean prevWasCR = false; boolean prevWasCR = false;
synchronized(lock) { // make thread-safe (hopefully!) synchronized (lock) { // make thread-safe (hopefully!)
while((intch = read()) != -1) while ((intch = read()) != -1) {
{
if (prevWasCR && intch == LF) { if (prevWasCR && intch == LF) {
return sb.substring(0, sb.length()-1); return sb.substring(0, sb.length() - 1);
} }
if (intch == CR) { if (intch == CR) {
prevWasCR = true; prevWasCR = true;

@ -32,21 +32,18 @@ import org.apache.commons.net.util.ListenerList;
* reasons and also because multiple listeners cannot be registered given * reasons and also because multiple listeners cannot be registered given
* that the methods are static. * that the methods are static.
* *
* * @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $
* @see CopyStreamEvent * @see CopyStreamEvent
* @see CopyStreamListener * @see CopyStreamListener
* @see Util * @see Util
* @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $
*/ */
public class CopyStreamAdapter implements CopyStreamListener public class CopyStreamAdapter implements CopyStreamListener {
{
private final ListenerList internalListeners; private final ListenerList internalListeners;
/** /**
* Creates a new copyStreamAdapter. * Creates a new copyStreamAdapter.
*/ */
public CopyStreamAdapter() public CopyStreamAdapter() {
{
internalListeners = new ListenerList(); internalListeners = new ListenerList();
} }
@ -57,14 +54,12 @@ public class CopyStreamAdapter implements CopyStreamListener
* transferred in the last write. The CopyStreamAdapater will relay * transferred in the last write. The CopyStreamAdapater will relay
* the event to all of its registered listeners, listing itself as the * the event to all of its registered listeners, listing itself as the
* source of the event. * source of the event.
*
* @param event The CopyStreamEvent fired by the copying of a block of * @param event The CopyStreamEvent fired by the copying of a block of
* bytes. * bytes.
*/ */
@Override @Override public void bytesTransferred(CopyStreamEvent event) {
public void bytesTransferred(CopyStreamEvent event) for (EventListener listener : internalListeners) {
{
for (EventListener listener : internalListeners)
{
((CopyStreamListener) (listener)).bytesTransferred(event); ((CopyStreamListener) (listener)).bytesTransferred(event);
} }
} }
@ -76,6 +71,7 @@ public class CopyStreamAdapter implements CopyStreamListener
* transfer. The CopyStreamAdapater will create a CopyStreamEvent * transfer. The CopyStreamAdapater will create a CopyStreamEvent
* from the arguments and relay the event to all of its registered * from the arguments and relay the event to all of its registered
* listeners, listing itself as the source of the event. * listeners, listing itself as the source of the event.
*
* @param totalBytesTransferred The total number of bytes transferred * @param totalBytesTransferred The total number of bytes transferred
* so far by the copy operation. * so far by the copy operation.
* @param bytesTransferred The number of bytes copied by the most recent * @param bytesTransferred The number of bytes copied by the most recent
@ -84,14 +80,11 @@ public class CopyStreamAdapter implements CopyStreamListener
* This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if
* the size is unknown. * the size is unknown.
*/ */
@Override @Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred,
public void bytesTransferred(long totalBytesTransferred, long streamSize) {
int bytesTransferred, long streamSize) for (EventListener listener : internalListeners) {
{ ((CopyStreamListener) (listener)).bytesTransferred(totalBytesTransferred, bytesTransferred,
for (EventListener listener : internalListeners) streamSize);
{
((CopyStreamListener) (listener)).bytesTransferred(
totalBytesTransferred, bytesTransferred, streamSize);
} }
} }
@ -99,20 +92,20 @@ public class CopyStreamAdapter implements CopyStreamListener
* Registers a CopyStreamListener to receive CopyStreamEvents. * Registers a CopyStreamListener to receive CopyStreamEvents.
* Although this method is not declared to be synchronized, it is * Although this method is not declared to be synchronized, it is
* implemented in a thread safe manner. * implemented in a thread safe manner.
*
* @param listener The CopyStreamlistener to register. * @param listener The CopyStreamlistener to register.
*/ */
public void addCopyStreamListener(CopyStreamListener listener) public void addCopyStreamListener(CopyStreamListener listener) {
{
internalListeners.addListener(listener); internalListeners.addListener(listener);
} }
/** /**
* Unregisters a CopyStreamListener. Although this method is not * Unregisters a CopyStreamListener. Although this method is not
* synchronized, it is implemented in a thread safe manner. * synchronized, it is implemented in a thread safe manner.
*
* @param listener The CopyStreamlistener to unregister. * @param listener The CopyStreamlistener to unregister.
*/ */
public void removeCopyStreamListener(CopyStreamListener listener) public void removeCopyStreamListener(CopyStreamListener listener) {
{
internalListeners.removeListener(listener); internalListeners.removeListener(listener);
} }
} }

@ -25,14 +25,12 @@ import java.util.EventObject;
* transferred by the write triggering the event as well as the total * transferred by the write triggering the event as well as the total
* number of bytes transferred so far by the copy operation. * 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 CopyStreamListener
* @see CopyStreamAdapter * @see CopyStreamAdapter
* @see Util * @see Util
* @version $Id: CopyStreamEvent.java 1652801 2015-01-18 17:10:05Z sebb $
*/ */
public class CopyStreamEvent extends EventObject public class CopyStreamEvent extends EventObject {
{
private static final long serialVersionUID = -964927635655051867L; private static final long serialVersionUID = -964927635655051867L;
/** /**
@ -46,6 +44,7 @@ public class CopyStreamEvent extends EventObject
/** /**
* Creates a new CopyStreamEvent instance. * Creates a new CopyStreamEvent instance.
*
* @param source The source of the event. * @param source The source of the event.
* @param totalBytesTransferred The total number of bytes transferred so * @param totalBytesTransferred The total number of bytes transferred so
* far during a copy operation. * far during a copy operation.
@ -55,9 +54,8 @@ public class CopyStreamEvent extends EventObject
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
* size is unknown. * size is unknown.
*/ */
public CopyStreamEvent(Object source, long totalBytesTransferred, public CopyStreamEvent(Object source, long totalBytesTransferred, int bytesTransferred,
int bytesTransferred, long streamSize) long streamSize) {
{
super(source); super(source);
this.bytesTransferred = bytesTransferred; this.bytesTransferred = bytesTransferred;
this.totalBytesTransferred = totalBytesTransferred; this.totalBytesTransferred = totalBytesTransferred;
@ -67,22 +65,22 @@ public class CopyStreamEvent extends EventObject
/** /**
* Returns the number of bytes transferred by the write that triggered * Returns the number of bytes transferred by the write that triggered
* the event. * the event.
*
* @return The number of bytes transferred by the write that triggered * @return The number of bytes transferred by the write that triggered
* the vent. * the vent.
*/ */
public int getBytesTransferred() public int getBytesTransferred() {
{
return bytesTransferred; return bytesTransferred;
} }
/** /**
* Returns the total number of bytes transferred so far by the copy * Returns the total number of bytes transferred so far by the copy
* operation. * operation.
*
* @return The total number of bytes transferred so far by the copy * @return The total number of bytes transferred so far by the copy
* operation. * operation.
*/ */
public long getTotalBytesTransferred() public long getTotalBytesTransferred() {
{
return totalBytesTransferred; return totalBytesTransferred;
} }
@ -90,22 +88,26 @@ public class CopyStreamEvent extends EventObject
* Returns the size of the stream being copied. * Returns the size of the stream being copied.
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
* size is unknown. * size is unknown.
*
* @return The size of the stream being copied. * @return The size of the stream being copied.
*/ */
public long getStreamSize() public long getStreamSize() {
{
return streamSize; return streamSize;
} }
/** /**
* @since 3.0 * @since 3.0
*/ */
@Override @Override public String toString() {
public String toString(){ return getClass().getName()
return getClass().getName() + "[source=" + source + "[source="
+ ", total=" + totalBytesTransferred + source
+ ", bytes=" + bytesTransferred + ", total="
+ ", size=" + streamSize + totalBytesTransferred
+ ", bytes="
+ bytesTransferred
+ ", size="
+ streamSize
+ "]"; + "]";
} }
} }

@ -24,26 +24,24 @@ import java.io.IOException;
* copyStream() methods. It stores the number of bytes confirmed to * copyStream() methods. It stores the number of bytes confirmed to
* have been transferred before an I/O error as well as the IOException * have been transferred before an I/O error as well as the IOException
* responsible for the failure of a copy operation. * responsible for the failure of a copy operation.
* @see Util *
* @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $ * @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $
* @see Util
*/ */
public class CopyStreamException extends IOException public class CopyStreamException extends IOException {
{
private static final long serialVersionUID = -2602899129433221532L; private static final long serialVersionUID = -2602899129433221532L;
private final long totalBytesTransferred; private final long totalBytesTransferred;
/** /**
* Creates a new CopyStreamException instance. * Creates a new CopyStreamException instance.
*
* @param message A message describing the error. * @param message A message describing the error.
* @param bytesTransferred The total number of bytes transferred before * @param bytesTransferred The total number of bytes transferred before
* an exception was thrown in a copy operation. * an exception was thrown in a copy operation.
* @param exception The IOException thrown during a copy operation. * @param exception The IOException thrown during a copy operation.
*/ */
public CopyStreamException(String message, public CopyStreamException(String message, long bytesTransferred, IOException exception) {
long bytesTransferred,
IOException exception)
{
super(message); super(message);
initCause(exception); // merge this into super() call once we need 1.6+ initCause(exception); // merge this into super() call once we need 1.6+
totalBytesTransferred = bytesTransferred; totalBytesTransferred = bytesTransferred;
@ -52,20 +50,20 @@ public class CopyStreamException extends IOException
/** /**
* Returns the total number of bytes confirmed to have * Returns the total number of bytes confirmed to have
* been transferred by a failed copy operation. * been transferred by a failed copy operation.
*
* @return The total number of bytes confirmed to have * @return The total number of bytes confirmed to have
* been transferred by a failed copy operation. * been transferred by a failed copy operation.
*/ */
public long getTotalBytesTransferred() public long getTotalBytesTransferred() {
{
return totalBytesTransferred; return totalBytesTransferred;
} }
/** /**
* Returns the IOException responsible for the failure of a copy operation. * Returns the IOException responsible for the failure of a copy operation.
*
* @return The IOException responsible for the failure of a copy operation. * @return The IOException responsible for the failure of a copy operation.
*/ */
public IOException getIOException() public IOException getIOException() {
{
return (IOException) getCause(); // cast is OK because it was initialised with an IOException return (IOException) getCause(); // cast is OK because it was initialised with an IOException
} }
} }

@ -33,30 +33,29 @@ import java.util.EventListener;
* JavaBean event model, which is why the hooks have been included from the * JavaBean event model, which is why the hooks have been included from the
* beginning. * beginning.
* *
* * @version $Id: CopyStreamListener.java 1652801 2015-01-18 17:10:05Z sebb $
* @see CopyStreamEvent * @see CopyStreamEvent
* @see CopyStreamAdapter * @see CopyStreamAdapter
* @see Util * @see Util
* @version $Id: CopyStreamListener.java 1652801 2015-01-18 17:10:05Z sebb $
*/ */
public interface CopyStreamListener extends EventListener public interface CopyStreamListener extends EventListener {
{
/** /**
* This method is invoked by a CopyStreamEvent source after copying * This method is invoked by a CopyStreamEvent source after copying
* a block of bytes from a stream. The CopyStreamEvent will contain * a block of bytes from a stream. The CopyStreamEvent will contain
* the total number of bytes transferred so far and the number of bytes * the total number of bytes transferred so far and the number of bytes
* transferred in the last write. * transferred in the last write.
*
* @param event The CopyStreamEvent fired by the copying of a block of * @param event The CopyStreamEvent fired by the copying of a block of
* bytes. * bytes.
*/ */
public void bytesTransferred(CopyStreamEvent event); public void bytesTransferred(CopyStreamEvent event);
/** /**
* This method is not part of the JavaBeans model and is used by the * 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. * 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 * It is invoked after a block of bytes to inform the listener of the
* transfer. * transfer.
*
* @param totalBytesTransferred The total number of bytes transferred * @param totalBytesTransferred The total number of bytes transferred
* so far by the copy operation. * so far by the copy operation.
* @param bytesTransferred The number of bytes copied by the most recent * @param bytesTransferred The number of bytes copied by the most recent

@ -35,10 +35,10 @@ import java.io.Reader;
* Note: versions since 3.0 extend BufferedReader rather than Reader, * 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 * and no longer change the CRLF into the local EOL. Also only DOT CR LF
* acts as EOF. * acts as EOF.
*
* @version $Id: DotTerminatedMessageReader.java 1747119 2016-06-07 02:22:24Z ggregory $ * @version $Id: DotTerminatedMessageReader.java 1747119 2016-06-07 02:22:24Z ggregory $
*/ */
public final class DotTerminatedMessageReader extends BufferedReader public final class DotTerminatedMessageReader extends BufferedReader {
{
private static final char LF = '\n'; private static final char LF = '\n';
private static final char CR = '\r'; private static final char CR = '\r';
private static final int DOT = '.'; private static final int DOT = '.';
@ -50,10 +50,10 @@ public final class DotTerminatedMessageReader extends BufferedReader
/** /**
* Creates a DotTerminatedMessageReader that wraps an existing Reader * Creates a DotTerminatedMessageReader that wraps an existing Reader
* input source. * input source.
*
* @param reader The Reader input source containing the message. * @param reader The Reader input source containing the message.
*/ */
public DotTerminatedMessageReader(Reader reader) public DotTerminatedMessageReader(Reader reader) {
{
super(reader); super(reader);
// Assumes input is at start of message // Assumes input is at start of message
atBeginning = true; atBeginning = true;
@ -67,13 +67,13 @@ public final class DotTerminatedMessageReader extends BufferedReader
* the message properly (removing doubled dots and so on). All of * the message properly (removing doubled dots and so on). All of
* this is transparent to the programmer and is only mentioned for * this is transparent to the programmer and is only mentioned for
* completeness. * completeness.
*
* @return The next character in the message. Returns -1 if the end of the * @return The next character in the message. Returns -1 if the end of the
* message has been reached. * message has been reached.
* @throws IOException If an error occurs while reading the underlying * @throws IOException If an error occurs while reading the underlying
* stream. * stream.
*/ */
@Override @Override public int read() throws IOException {
public int read() throws IOException {
synchronized (lock) { synchronized (lock) {
if (eof) { if (eof) {
return -1; // Don't allow read past EOF return -1; // Don't allow read past EOF
@ -132,20 +132,18 @@ public final class DotTerminatedMessageReader extends BufferedReader
} }
} }
/** /**
* Reads the next characters from the message into an array and * Reads the next characters from the message into an array and
* returns the number of characters read. Returns -1 if the end of the * returns the number of characters read. Returns -1 if the end of the
* message has been reached. * message has been reached.
*
* @param buffer The character array in which to store the characters. * @param buffer The character array in which to store the characters.
* @return The number of characters read. Returns -1 if the * @return The number of characters read. Returns -1 if the
* end of the message has been reached. * end of the message has been reached.
* @throws IOException If an error occurs in reading the underlying * @throws IOException If an error occurs in reading the underlying
* stream. * stream.
*/ */
@Override @Override public int read(char[] buffer) throws IOException {
public int read(char[] buffer) throws IOException
{
return read(buffer, 0, buffer.length); return read(buffer, 0, buffer.length);
} }
@ -154,6 +152,7 @@ public final class DotTerminatedMessageReader extends BufferedReader
* returns the number of characters read. Returns -1 if the end of the * returns the number of characters read. Returns -1 if the end of the
* message has been reached. The characters are stored in the array * message has been reached. The characters are stored in the array
* starting from the given offset and up to the length specified. * starting from the given offset and up to the length specified.
*
* @param buffer The character array in which to store the characters. * @param buffer The character array in which to store the characters.
* @param offset The offset into the array at which to start storing * @param offset The offset into the array at which to start storing
* characters. * characters.
@ -163,28 +162,21 @@ public final class DotTerminatedMessageReader extends BufferedReader
* @throws IOException If an error occurs in reading the underlying * @throws IOException If an error occurs in reading the underlying
* stream. * stream.
*/ */
@Override @Override public int read(char[] buffer, int offset, int length) throws IOException {
public int read(char[] buffer, int offset, int length) throws IOException if (length < 1) {
{
if (length < 1)
{
return 0; return 0;
} }
int ch; int ch;
synchronized (lock) synchronized (lock) {
{ if ((ch = read()) == -1) {
if ((ch = read()) == -1)
{
return -1; return -1;
} }
int off = offset; int off = offset;
do do {
{
buffer[offset++] = (char) ch; buffer[offset++] = (char) ch;
} } while (--length > 0 && (ch = read()) != -1);
while (--length > 0 && (ch = read()) != -1);
return (offset - off); return (offset - off);
} }
@ -201,18 +193,14 @@ public final class DotTerminatedMessageReader extends BufferedReader
* for communicating with the server. If you do not fully read * for communicating with the server. If you do not fully read
* a message, you MUST close it, otherwise your program will likely * a message, you MUST close it, otherwise your program will likely
* hang or behave improperly. * hang or behave improperly.
*
* @throws IOException If an error occurs while reading the * @throws IOException If an error occurs while reading the
* underlying stream. * underlying stream.
*/ */
@Override @Override public void close() throws IOException {
public void close() throws IOException synchronized (lock) {
{ if (!eof) {
synchronized (lock) while (read() != -1) {
{
if (!eof)
{
while (read() != -1)
{
// read to EOF // read to EOF
} }
} }
@ -225,17 +213,16 @@ public final class DotTerminatedMessageReader extends BufferedReader
* Read a line of text. * Read a line of text.
* A line is considered to be terminated by carriage return followed immediately by a linefeed. * A line is considered to be terminated by carriage return followed immediately by a linefeed.
* This contrasts with BufferedReader which also allows other combinations. * This contrasts with BufferedReader which also allows other combinations.
*
* @since 3.0 * @since 3.0
*/ */
@Override @Override public String readLine() throws IOException {
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int intch; int intch;
synchronized(lock) { // make thread-safe (hopefully!) synchronized (lock) { // make thread-safe (hopefully!)
while((intch = read()) != -1) while ((intch = read()) != -1) {
{
if (intch == LF && atBeginning) { if (intch == LF && atBeginning) {
return sb.substring(0, sb.length()-1); return sb.substring(0, sb.length() - 1);
} }
sb.append((char) intch); sb.append((char) intch);
} }

@ -36,8 +36,7 @@ import java.io.Writer;
* *
***/ ***/
public final class DotTerminatedMessageWriter extends Writer public final class DotTerminatedMessageWriter extends Writer {
{
private static final int __NOTHING_SPECIAL_STATE = 0; private static final int __NOTHING_SPECIAL_STATE = 0;
private static final int __LAST_WAS_CR_STATE = 1; private static final int __LAST_WAS_CR_STATE = 1;
private static final int __LAST_WAS_NL_STATE = 2; private static final int __LAST_WAS_NL_STATE = 2;
@ -45,21 +44,18 @@ public final class DotTerminatedMessageWriter extends Writer
private int __state; private int __state;
private Writer __output; private Writer __output;
/*** /***
* Creates a DotTerminatedMessageWriter that wraps an existing Writer * Creates a DotTerminatedMessageWriter that wraps an existing Writer
* output destination. * output destination.
* *
* @param output The Writer output destination to write the message. * @param output The Writer output destination to write the message.
***/ ***/
public DotTerminatedMessageWriter(Writer output) public DotTerminatedMessageWriter(Writer output) {
{
super(output); super(output);
__output = output; __output = output;
__state = __NOTHING_SPECIAL_STATE; __state = __NOTHING_SPECIAL_STATE;
} }
/*** /***
* Writes a character to the output. Note that a call to this method * 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 * may result in multiple writes to the underling Writer in order to
@ -71,24 +67,20 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the * @throws IOException If an error occurs while writing to the
* underlying output. * underlying output.
***/ ***/
@Override @Override public void write(int ch) throws IOException {
public void write(int ch) throws IOException synchronized (lock) {
{ switch (ch) {
synchronized (lock)
{
switch (ch)
{
case '\r': case '\r':
__state = __LAST_WAS_CR_STATE; __state = __LAST_WAS_CR_STATE;
__output.write('\r'); __output.write('\r');
return ; return;
case '\n': case '\n':
if (__state != __LAST_WAS_CR_STATE) { if (__state != __LAST_WAS_CR_STATE) {
__output.write('\r'); __output.write('\r');
} }
__output.write('\n'); __output.write('\n');
__state = __LAST_WAS_NL_STATE; __state = __LAST_WAS_NL_STATE;
return ; return;
case '.': case '.':
// Double the dot at the beginning of a line // Double the dot at the beginning of a line
if (__state == __LAST_WAS_NL_STATE) { if (__state == __LAST_WAS_NL_STATE) {
@ -98,12 +90,11 @@ public final class DotTerminatedMessageWriter extends Writer
default: default:
__state = __NOTHING_SPECIAL_STATE; __state = __NOTHING_SPECIAL_STATE;
__output.write(ch); __output.write(ch);
return ; return;
} }
} }
} }
/*** /***
* Writes a number of characters from a character array to the output * Writes a number of characters from a character array to the output
* starting from a given offset. * starting from a given offset.
@ -114,18 +105,14 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output. * output.
***/ ***/
@Override @Override public void write(char[] buffer, int offset, int length) throws IOException {
public void write(char[] buffer, int offset, int length) throws IOException synchronized (lock) {
{
synchronized (lock)
{
while (length-- > 0) { while (length-- > 0) {
write(buffer[offset++]); write(buffer[offset++]);
} }
} }
} }
/*** /***
* Writes a character array to the output. * Writes a character array to the output.
* *
@ -133,13 +120,10 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output. * output.
***/ ***/
@Override @Override public void write(char[] buffer) throws IOException {
public void write(char[] buffer) throws IOException
{
write(buffer, 0, buffer.length); write(buffer, 0, buffer.length);
} }
/*** /***
* Writes a String to the output. * Writes a String to the output.
* *
@ -147,13 +131,10 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output. * output.
***/ ***/
@Override @Override public void write(String string) throws IOException {
public void write(String string) throws IOException
{
write(string.toCharArray()); write(string.toCharArray());
} }
/*** /***
* Writes part of a String to the output starting from a given offset. * Writes part of a String to the output starting from a given offset.
* *
@ -163,29 +144,22 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output. * output.
***/ ***/
@Override @Override public void write(String string, int offset, int length) throws IOException {
public void write(String string, int offset, int length) throws IOException
{
write(string.toCharArray(), offset, length); write(string.toCharArray(), offset, length);
} }
/*** /***
* Flushes the underlying output, writing all buffered output. * Flushes the underlying output, writing all buffered output.
* *
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output. * output.
***/ ***/
@Override @Override public void flush() throws IOException {
public void flush() throws IOException synchronized (lock) {
{
synchronized (lock)
{
__output.flush(); __output.flush();
} }
} }
/*** /***
* Flushes the underlying output, writing all buffered output, but doesn't * Flushes the underlying output, writing all buffered output, but doesn't
* actually close the underlying stream. The underlying stream may still * actually close the underlying stream. The underlying stream may still
@ -194,13 +168,10 @@ public final class DotTerminatedMessageWriter extends Writer
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* output or closing the Writer. * output or closing the Writer.
***/ ***/
@Override @Override public void close() throws IOException {
public void close() throws IOException synchronized (lock) {
{
synchronized (lock)
{
if (__output == null) { if (__output == null) {
return ; return;
} }
if (__state == __LAST_WAS_CR_STATE) { if (__state == __LAST_WAS_CR_STATE) {
@ -215,5 +186,4 @@ public final class DotTerminatedMessageWriter extends Writer
__output = null; __output = null;
} }
} }
} }

@ -32,8 +32,7 @@ import java.io.UnsupportedEncodingException;
* *
***/ ***/
public final class FromNetASCIIInputStream extends PushbackInputStream public final class FromNetASCIIInputStream extends PushbackInputStream {
{
static final boolean _noConversionRequired; static final boolean _noConversionRequired;
static final String _lineSeparator; static final String _lineSeparator;
static final byte[] _lineSeparatorBytes; static final byte[] _lineSeparatorBytes;
@ -44,7 +43,7 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
try { try {
_lineSeparatorBytes = _lineSeparator.getBytes("US-ASCII"); _lineSeparatorBytes = _lineSeparator.getBytes("US-ASCII");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("Broken JVM - cannot find US-ASCII charset!",e); throw new RuntimeException("Broken JVM - cannot find US-ASCII charset!", e);
} }
} }
@ -59,8 +58,7 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* @return True if the NETASCII line separator differs from the local * @return True if the NETASCII line separator differs from the local
* system line separator, false if they are the same. * system line separator, false if they are the same.
***/ ***/
public static final boolean isConversionRequired() public static final boolean isConversionRequired() {
{
return !_noConversionRequired; return !_noConversionRequired;
} }
@ -69,30 +67,23 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* InputStream. * InputStream.
* @param input the stream to wrap * @param input the stream to wrap
***/ ***/
public FromNetASCIIInputStream(InputStream input) public FromNetASCIIInputStream(InputStream input) {
{
super(input, _lineSeparatorBytes.length + 1); super(input, _lineSeparatorBytes.length + 1);
} }
private int __read() throws IOException {
private int __read() throws IOException
{
int ch; int ch;
ch = super.read(); ch = super.read();
if (ch == '\r') if (ch == '\r') {
{
ch = super.read(); ch = super.read();
if (ch == '\n') if (ch == '\n') {
{
unread(_lineSeparatorBytes); unread(_lineSeparatorBytes);
ch = super.read(); ch = super.read();
// This is a kluge for read(byte[], ...) to read the right amount // This is a kluge for read(byte[], ...) to read the right amount
--__length; --__length;
} } else {
else
{
if (ch != -1) { if (ch != -1) {
unread(ch); unread(ch);
} }
@ -103,7 +94,6 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
return ch; return ch;
} }
/*** /***
* Reads and returns the next byte in the stream. If the end of the * 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 * message has been reached, returns -1. Note that a call to this method
@ -117,9 +107,7 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* @throws IOException If an error occurs while reading the underlying * @throws IOException If an error occurs while reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read() throws IOException {
public int read() throws IOException
{
if (_noConversionRequired) { if (_noConversionRequired) {
return super.read(); return super.read();
} }
@ -127,7 +115,6 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
return __read(); return __read();
} }
/*** /***
* Reads the next number of bytes from the stream into an array and * 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 * returns the number of bytes read. Returns -1 if the end of the
@ -139,13 +126,10 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* @throws IOException If an error occurs in reading the underlying * @throws IOException If an error occurs in reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read(byte buffer[]) throws IOException {
public int read(byte buffer[]) throws IOException
{
return read(buffer, 0, buffer.length); return read(buffer, 0, buffer.length);
} }
/*** /***
* Reads the next number of bytes from the stream into an array and returns * 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 * the number of bytes read. Returns -1 if the end of the
@ -160,9 +144,7 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* @throws IOException If an error occurs while reading the underlying * @throws IOException If an error occurs while reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read(byte buffer[], int offset, int length) throws IOException {
public int read(byte buffer[], int offset, int length) throws IOException
{
if (_noConversionRequired) { if (_noConversionRequired) {
return super.read(buffer, offset, length); return super.read(buffer, offset, length);
} }
@ -182,26 +164,22 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
__length = 1; __length = 1;
} }
if ((ch = __read()) == -1) { if ((ch = __read()) == -1) {
return -1; return -1;
} }
off = offset; off = offset;
do do {
{ buffer[offset++] = (byte) ch;
buffer[offset++] = (byte)ch; } while (--__length > 0 && (ch = __read()) != -1);
}
while (--__length > 0 && (ch = __read()) != -1);
return (offset - off); return (offset - off);
} }
// PushbackInputStream in JDK 1.1.3 returns the wrong thing // PushbackInputStream in JDK 1.1.3 returns the wrong thing
// TODO - can we delete this override now? // TODO - can we delete this override now?
/*** /***
* Returns the number of bytes that can be read without blocking EXCEPT * Returns the number of bytes that can be read without blocking EXCEPT
* when newline conversions have to be made somewhere within the * when newline conversions have to be made somewhere within the
@ -209,13 +187,10 @@ public final class FromNetASCIIInputStream extends PushbackInputStream
* rely on the value returned by this method if you are trying to avoid * rely on the value returned by this method if you are trying to avoid
* blocking. * blocking.
***/ ***/
@Override @Override public int available() throws IOException {
public int available() throws IOException
{
if (in == null) { if (in == null) {
throw new IOException("Stream closed"); throw new IOException("Stream closed");
} }
return (buf.length - pos) + in.available(); return (buf.length - pos) + in.available();
} }
} }

@ -36,8 +36,7 @@ import java.io.OutputStream;
* *
***/ ***/
public final class FromNetASCIIOutputStream extends FilterOutputStream public final class FromNetASCIIOutputStream extends FilterOutputStream {
{
private boolean __lastWasCR; private boolean __lastWasCR;
/*** /***
@ -46,24 +45,19 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
* *
* @param output The OutputStream to wrap. * @param output The OutputStream to wrap.
***/ ***/
public FromNetASCIIOutputStream(OutputStream output) public FromNetASCIIOutputStream(OutputStream output) {
{
super(output); super(output);
__lastWasCR = false; __lastWasCR = false;
} }
private void __write(int ch) throws IOException {
private void __write(int ch) throws IOException switch (ch) {
{
switch (ch)
{
case '\r': case '\r':
__lastWasCR = true; __lastWasCR = true;
// Don't write anything. We need to see if next one is linefeed // Don't write anything. We need to see if next one is linefeed
break; break;
case '\n': case '\n':
if (__lastWasCR) if (__lastWasCR) {
{
out.write(FromNetASCIIInputStream._lineSeparatorBytes); out.write(FromNetASCIIInputStream._lineSeparatorBytes);
__lastWasCR = false; __lastWasCR = false;
break; break;
@ -72,8 +66,7 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
out.write('\n'); out.write('\n');
break; break;
default: default:
if (__lastWasCR) if (__lastWasCR) {
{
out.write('\r'); out.write('\r');
__lastWasCR = false; __lastWasCR = false;
} }
@ -82,7 +75,6 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
} }
} }
/*** /***
* Writes a byte to the stream. Note that a call to this method * 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 * might not actually write a byte to the underlying stream until a
@ -95,20 +87,15 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(int ch) throws IOException {
public synchronized void write(int ch) if (FromNetASCIIInputStream._noConversionRequired) {
throws IOException
{
if (FromNetASCIIInputStream._noConversionRequired)
{
out.write(ch); out.write(ch);
return ; return;
} }
__write(ch); __write(ch);
} }
/*** /***
* Writes a byte array to the stream. * Writes a byte array to the stream.
* *
@ -116,14 +103,10 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(byte buffer[]) throws IOException {
public synchronized void write(byte buffer[])
throws IOException
{
write(buffer, 0, buffer.length); write(buffer, 0, buffer.length);
} }
/*** /***
* Writes a number of bytes from a byte array to the stream starting from * Writes a number of bytes from a byte array to the stream starting from
* a given offset. * a given offset.
@ -134,16 +117,13 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(byte buffer[], int offset, int length)
public synchronized void write(byte buffer[], int offset, int length) throws IOException {
throws IOException if (FromNetASCIIInputStream._noConversionRequired) {
{
if (FromNetASCIIInputStream._noConversionRequired)
{
// FilterOutputStream method is very slow. // FilterOutputStream method is very slow.
//super.write(buffer, offset, length); //super.write(buffer, offset, length);
out.write(buffer, offset, length); out.write(buffer, offset, length);
return ; return;
} }
while (length-- > 0) { while (length-- > 0) {
@ -151,20 +131,15 @@ public final class FromNetASCIIOutputStream extends FilterOutputStream
} }
} }
/*** /***
* Closes the stream, writing all pending data. * Closes the stream, writing all pending data.
* *
* @throws IOException If an error occurs while closing the stream. * @throws IOException If an error occurs while closing the stream.
***/ ***/
@Override @Override public synchronized void close() throws IOException {
public synchronized void close() if (FromNetASCIIInputStream._noConversionRequired) {
throws IOException
{
if (FromNetASCIIInputStream._noConversionRequired)
{
super.close(); super.close();
return ; return;
} }
if (__lastWasCR) { if (__lastWasCR) {

@ -34,8 +34,7 @@ import java.net.Socket;
* @see SocketOutputStream * @see SocketOutputStream
***/ ***/
public class SocketInputStream extends FilterInputStream public class SocketInputStream extends FilterInputStream {
{
private final Socket __socket; private final Socket __socket;
/*** /***
@ -46,8 +45,7 @@ public class SocketInputStream extends FilterInputStream
* @param socket The socket to close on closing the stream. * @param socket The socket to close on closing the stream.
* @param stream The input stream to wrap. * @param stream The input stream to wrap.
***/ ***/
public SocketInputStream(Socket socket, InputStream stream) public SocketInputStream(Socket socket, InputStream stream) {
{
super(stream); super(stream);
__socket = socket; __socket = socket;
} }
@ -59,9 +57,7 @@ public class SocketInputStream extends FilterInputStream
* @throws IOException If there is an error in closing the stream * @throws IOException If there is an error in closing the stream
* or socket. * or socket.
***/ ***/
@Override @Override public void close() throws IOException {
public void close() throws IOException
{
super.close(); super.close();
__socket.close(); __socket.close();
} }

@ -34,8 +34,7 @@ import java.net.Socket;
* @see SocketInputStream * @see SocketInputStream
***/ ***/
public class SocketOutputStream extends FilterOutputStream public class SocketOutputStream extends FilterOutputStream {
{
private final Socket __socket; private final Socket __socket;
/*** /***
@ -46,13 +45,11 @@ public class SocketOutputStream extends FilterOutputStream
* @param socket The socket to close on closing the stream. * @param socket The socket to close on closing the stream.
* @param stream The input stream to wrap. * @param stream The input stream to wrap.
***/ ***/
public SocketOutputStream(Socket socket, OutputStream stream) public SocketOutputStream(Socket socket, OutputStream stream) {
{
super(stream); super(stream);
__socket = socket; __socket = socket;
} }
/*** /***
* Writes a number of bytes from a byte array to the stream starting from * Writes a number of bytes from a byte array to the stream starting from
* a given offset. This method bypasses the equivalent method in * a given offset. This method bypasses the equivalent method in
@ -65,13 +62,10 @@ public class SocketOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public void write(byte buffer[], int offset, int length) throws IOException {
public void write(byte buffer[], int offset, int length) throws IOException
{
out.write(buffer, offset, length); out.write(buffer, offset, length);
} }
/*** /***
* Closes the stream and immediately afterward closes the referenced * Closes the stream and immediately afterward closes the referenced
* socket. * socket.
@ -79,9 +73,7 @@ public class SocketOutputStream extends FilterOutputStream
* @throws IOException If there is an error in closing the stream * @throws IOException If there is an error in closing the stream
* or socket. * or socket.
***/ ***/
@Override @Override public void close() throws IOException {
public void close() throws IOException
{
super.close(); super.close();
__socket.close(); __socket.close();
} }

@ -32,8 +32,7 @@ import java.io.InputStream;
* *
***/ ***/
public final class ToNetASCIIInputStream extends FilterInputStream public final class ToNetASCIIInputStream extends FilterInputStream {
{
private static final int __NOTHING_SPECIAL = 0; private static final int __NOTHING_SPECIAL = 0;
private static final int __LAST_WAS_CR = 1; private static final int __LAST_WAS_CR = 1;
private static final int __LAST_WAS_NL = 2; private static final int __LAST_WAS_NL = 2;
@ -45,13 +44,11 @@ public final class ToNetASCIIInputStream extends FilterInputStream
* *
* @param input The InputStream to wrap. * @param input The InputStream to wrap.
***/ ***/
public ToNetASCIIInputStream(InputStream input) public ToNetASCIIInputStream(InputStream input) {
{
super(input); super(input);
__status = __NOTHING_SPECIAL; __status = __NOTHING_SPECIAL;
} }
/*** /***
* Reads and returns the next byte in the stream. If the end of the * Reads and returns the next byte in the stream. If the end of the
* message has been reached, returns -1. * message has been reached, returns -1.
@ -61,27 +58,22 @@ public final class ToNetASCIIInputStream extends FilterInputStream
* @throws IOException If an error occurs while reading the underlying * @throws IOException If an error occurs while reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read() throws IOException {
public int read() throws IOException
{
int ch; int ch;
if (__status == __LAST_WAS_NL) if (__status == __LAST_WAS_NL) {
{
__status = __NOTHING_SPECIAL; __status = __NOTHING_SPECIAL;
return '\n'; return '\n';
} }
ch = in.read(); ch = in.read();
switch (ch) switch (ch) {
{
case '\r': case '\r':
__status = __LAST_WAS_CR; __status = __LAST_WAS_CR;
return '\r'; return '\r';
case '\n': case '\n':
if (__status != __LAST_WAS_CR) if (__status != __LAST_WAS_CR) {
{
__status = __LAST_WAS_NL; __status = __LAST_WAS_NL;
return '\r'; return '\r';
} }
@ -94,7 +86,6 @@ public final class ToNetASCIIInputStream extends FilterInputStream
//return ch; //return ch;
} }
/*** /***
* Reads the next number of bytes from the stream into an array and * 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 * returns the number of bytes read. Returns -1 if the end of the
@ -106,13 +97,10 @@ public final class ToNetASCIIInputStream extends FilterInputStream
* @throws IOException If an error occurs in reading the underlying * @throws IOException If an error occurs in reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read(byte buffer[]) throws IOException {
public int read(byte buffer[]) throws IOException
{
return read(buffer, 0, buffer.length); return read(buffer, 0, buffer.length);
} }
/*** /***
* Reads the next number of bytes from the stream into an array and returns * 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 * the number of bytes read. Returns -1 if the end of the
@ -127,9 +115,7 @@ public final class ToNetASCIIInputStream extends FilterInputStream
* @throws IOException If an error occurs while reading the underlying * @throws IOException If an error occurs while reading the underlying
* stream. * stream.
***/ ***/
@Override @Override public int read(byte buffer[], int offset, int length) throws IOException {
public int read(byte buffer[], int offset, int length) throws IOException
{
int ch, off; int ch, off;
if (length < 1) { if (length < 1) {
@ -153,25 +139,19 @@ public final class ToNetASCIIInputStream extends FilterInputStream
off = offset; off = offset;
do do {
{ buffer[offset++] = (byte) ch;
buffer[offset++] = (byte)ch; } while (--length > 0 && (ch = read()) != -1);
}
while (--length > 0 && (ch = read()) != -1);
return (offset - off); return (offset - off);
} }
/*** Returns false. Mark is not supported. ***/ /*** Returns false. Mark is not supported. ***/
@Override @Override public boolean markSupported() {
public boolean markSupported()
{
return false; return false;
} }
@Override @Override public int available() throws IOException {
public int available() throws IOException
{
int result; int result;
result = in.available(); result = in.available();

@ -32,8 +32,7 @@ import java.io.OutputStream;
* *
***/ ***/
public final class ToNetASCIIOutputStream extends FilterOutputStream public final class ToNetASCIIOutputStream extends FilterOutputStream {
{
private boolean __lastWasCR; private boolean __lastWasCR;
/*** /***
@ -42,13 +41,11 @@ public final class ToNetASCIIOutputStream extends FilterOutputStream
* *
* @param output The OutputStream to wrap. * @param output The OutputStream to wrap.
***/ ***/
public ToNetASCIIOutputStream(OutputStream output) public ToNetASCIIOutputStream(OutputStream output) {
{
super(output); super(output);
__lastWasCR = false; __lastWasCR = false;
} }
/*** /***
* Writes a byte to the stream. Note that a call to this method * 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 * may result in multiple writes to the underlying input stream in order
@ -60,16 +57,12 @@ public final class ToNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(int ch) throws IOException {
public synchronized void write(int ch) switch (ch) {
throws IOException
{
switch (ch)
{
case '\r': case '\r':
__lastWasCR = true; __lastWasCR = true;
out.write('\r'); out.write('\r');
return ; return;
case '\n': case '\n':
if (!__lastWasCR) { if (!__lastWasCR) {
out.write('\r'); out.write('\r');
@ -78,11 +71,10 @@ public final class ToNetASCIIOutputStream extends FilterOutputStream
default: default:
__lastWasCR = false; __lastWasCR = false;
out.write(ch); out.write(ch);
return ; return;
} }
} }
/*** /***
* Writes a byte array to the stream. * Writes a byte array to the stream.
* *
@ -90,14 +82,10 @@ public final class ToNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(byte buffer[]) throws IOException {
public synchronized void write(byte buffer[])
throws IOException
{
write(buffer, 0, buffer.length); write(buffer, 0, buffer.length);
} }
/*** /***
* Writes a number of bytes from a byte array to the stream starting from * Writes a number of bytes from a byte array to the stream starting from
* a given offset. * a given offset.
@ -108,13 +96,10 @@ public final class ToNetASCIIOutputStream extends FilterOutputStream
* @throws IOException If an error occurs while writing to the underlying * @throws IOException If an error occurs while writing to the underlying
* stream. * stream.
***/ ***/
@Override @Override public synchronized void write(byte buffer[], int offset, int length)
public synchronized void write(byte buffer[], int offset, int length) throws IOException {
throws IOException
{
while (length-- > 0) { while (length-- > 0) {
write(buffer[offset++]); write(buffer[offset++]);
} }
} }
} }

@ -35,8 +35,7 @@ import java.net.Socket;
* @see CopyStreamAdapter * @see CopyStreamAdapter
***/ ***/
public final class Util public final class Util {
{
/** /**
* The default buffer size ({@value}) used by * The default buffer size ({@value}) used by
* {@link #copyStream copyStream } and {@link #copyReader copyReader} * {@link #copyStream copyStream } and {@link #copyReader copyReader}
@ -45,9 +44,8 @@ public final class Util
public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
// Cannot be instantiated // Cannot be instantiated
private Util() private Util() {
{ } }
/*** /***
* Copies the contents of an InputStream to an OutputStream using a * Copies the contents of an InputStream to an OutputStream using a
@ -87,31 +85,24 @@ public final class Util
* the CopyStreamException getTotalBytesTransferred() and * the CopyStreamException getTotalBytesTransferred() and
* getIOException() methods. * getIOException() methods.
***/ ***/
public static final long copyStream(InputStream source, OutputStream dest, public static final long copyStream(InputStream source, OutputStream dest, int bufferSize,
int bufferSize, long streamSize, long streamSize, CopyStreamListener listener, boolean flush) throws CopyStreamException {
CopyStreamListener listener,
boolean flush)
throws CopyStreamException
{
int numBytes; int numBytes;
long total = 0; long total = 0;
byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
try try {
{ while ((numBytes = source.read(buffer)) != -1) {
while ((numBytes = source.read(buffer)) != -1)
{
// Technically, some read(byte[]) methods may return 0 and we cannot // Technically, some read(byte[]) methods may return 0 and we cannot
// accept that as an indication of EOF. // accept that as an indication of EOF.
if (numBytes == 0) if (numBytes == 0) {
{
int singleByte = source.read(); int singleByte = source.read();
if (singleByte < 0) { if (singleByte < 0) {
break; break;
} }
dest.write(singleByte); dest.write(singleByte);
if(flush) { if (flush) {
dest.flush(); dest.flush();
} }
++total; ++total;
@ -122,7 +113,7 @@ public final class Util
} }
dest.write(buffer, 0, numBytes); dest.write(buffer, 0, numBytes);
if(flush) { if (flush) {
dest.flush(); dest.flush();
} }
total += numBytes; total += numBytes;
@ -130,11 +121,8 @@ public final class Util
listener.bytesTransferred(total, numBytes, streamSize); listener.bytesTransferred(total, numBytes, streamSize);
} }
} }
} } catch (IOException e) {
catch (IOException e) throw new CopyStreamException("IOException caught while copying.", total, e);
{
throw new CopyStreamException("IOException caught while copying.",
total, e);
} }
return total; return total;
@ -175,16 +163,11 @@ public final class Util
* the CopyStreamException getTotalBytesTransferred() and * the CopyStreamException getTotalBytesTransferred() and
* getIOException() methods. * getIOException() methods.
***/ ***/
public static final long copyStream(InputStream source, OutputStream dest, public static final long copyStream(InputStream source, OutputStream dest, int bufferSize,
int bufferSize, long streamSize, long streamSize, CopyStreamListener listener) throws CopyStreamException {
CopyStreamListener listener) return copyStream(source, dest, bufferSize, streamSize, listener, true);
throws CopyStreamException
{
return copyStream(source, dest, bufferSize, streamSize, listener,
true);
} }
/*** /***
* Copies the contents of an InputStream to an OutputStream using a * Copies the contents of an InputStream to an OutputStream using a
* copy buffer of a given size. The contents of the InputStream are * copy buffer of a given size. The contents of the InputStream are
@ -207,15 +190,11 @@ public final class Util
* the CopyStreamException getTotalBytesTransferred() and * the CopyStreamException getTotalBytesTransferred() and
* getIOException() methods. * getIOException() methods.
***/ ***/
public static final long copyStream(InputStream source, OutputStream dest, public static final long copyStream(InputStream source, OutputStream dest, int bufferSize)
int bufferSize) throws CopyStreamException {
throws CopyStreamException return copyStream(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
{
return copyStream(source, dest, bufferSize,
CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
} }
/*** /***
* Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code> * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
* @param source where to copy from * @param source where to copy from
@ -224,12 +203,10 @@ public final class Util
* @throws CopyStreamException on error * @throws CopyStreamException on error
***/ ***/
public static final long copyStream(InputStream source, OutputStream dest) public static final long copyStream(InputStream source, OutputStream dest)
throws CopyStreamException throws CopyStreamException {
{
return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
} }
/*** /***
* Copies the contents of a Reader to a Writer using a * Copies the contents of a Reader to a Writer using a
* copy buffer of a given size and notifies the provided * copy buffer of a given size and notifies the provided
@ -263,23 +240,17 @@ public final class Util
* the CopyStreamException getTotalBytesTransferred() and * the CopyStreamException getTotalBytesTransferred() and
* getIOException() methods. * getIOException() methods.
***/ ***/
public static final long copyReader(Reader source, Writer dest, public static final long copyReader(Reader source, Writer dest, int bufferSize, long streamSize,
int bufferSize, long streamSize, CopyStreamListener listener) throws CopyStreamException {
CopyStreamListener listener)
throws CopyStreamException
{
int numChars; int numChars;
long total = 0; long total = 0;
char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
try try {
{ while ((numChars = source.read(buffer)) != -1) {
while ((numChars = source.read(buffer)) != -1)
{
// Technically, some read(char[]) methods may return 0 and we cannot // Technically, some read(char[]) methods may return 0 and we cannot
// accept that as an indication of EOF. // accept that as an indication of EOF.
if (numChars == 0) if (numChars == 0) {
{
int singleChar = source.read(); int singleChar = source.read();
if (singleChar < 0) { if (singleChar < 0) {
break; break;
@ -300,17 +271,13 @@ public final class Util
listener.bytesTransferred(total, numChars, streamSize); listener.bytesTransferred(total, numChars, streamSize);
} }
} }
} } catch (IOException e) {
catch (IOException e) throw new CopyStreamException("IOException caught while copying.", total, e);
{
throw new CopyStreamException("IOException caught while copying.",
total, e);
} }
return total; return total;
} }
/*** /***
* Copies the contents of a Reader to a Writer using a * Copies the contents of a Reader to a Writer using a
* copy buffer of a given size. The contents of the Reader are * copy buffer of a given size. The contents of the Reader are
@ -332,15 +299,11 @@ public final class Util
* the CopyStreamException getTotalBytesTransferred() and * the CopyStreamException getTotalBytesTransferred() and
* getIOException() methods. * getIOException() methods.
***/ ***/
public static final long copyReader(Reader source, Writer dest, public static final long copyReader(Reader source, Writer dest, int bufferSize)
int bufferSize) throws CopyStreamException {
throws CopyStreamException return copyReader(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
{
return copyReader(source, dest, bufferSize,
CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
} }
/*** /***
* Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code> * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
* @param source where to copy from * @param source where to copy from
@ -348,9 +311,7 @@ public final class Util
* @return number of bytes copied * @return number of bytes copied
* @throws CopyStreamException on error * @throws CopyStreamException on error
***/ ***/
public static final long copyReader(Reader source, Writer dest) public static final long copyReader(Reader source, Writer dest) throws CopyStreamException {
throws CopyStreamException
{
return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
} }

@ -20,31 +20,34 @@ package org.apache.commons.net.util;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* Provides Base64 encoding and decoding as defined by RFC 2045. * Provides Base64 encoding and decoding as defined by RFC 2045.
* *
* <p> * <p>
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein. * <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and
* Borenstein.
* </p> * </p>
* <p> * <p>
* The class can be parameterized in the following manner with various constructors: * The class can be parameterized in the following manner with various constructors:
* <ul> * <ul>
* <li>URL-safe mode: Default off.</li> * <li>URL-safe mode: Default off.</li>
* <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up
* being multiples of
* 4 in the encoded data. * 4 in the encoded data.
* <li>Line separator: Default is CRLF ("\r\n")</li> * <li>Line separator: Default is CRLF ("\r\n")</li>
* </ul> * </ul>
* <p> * <p>
* Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode * Since this class operates directly on byte streams, and not character streams, it is hard-coded
* character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). * to only encode/decode
* character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1,
* Windows-1252, UTF-8, etc).
* </p> * </p>
* *
* @version $Id: Base64.java 1697293 2015-08-24 01:01:00Z sebb $
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @since 2.2 * @since 2.2
* @version $Id: Base64.java 1697293 2015-08-24 01:01:00Z sebb $
*/ */
public class Base64 { public class Base64 {
private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
@ -55,7 +58,8 @@ public class Base64 {
* Chunk size per RFC 2045 section 6.8. * Chunk size per RFC 2045 section 6.8.
* *
* <p> * <p>
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any * The {@value} character limit does not count the trailing CRLF, but counts all other characters,
* including any
* equal signs. * equal signs.
* </p> * </p>
* *
@ -68,23 +72,23 @@ public class Base64 {
* *
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/ */
private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; private static final byte[] CHUNK_SEPARATOR = { '\r', '\n' };
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/** /**
* This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" * This array is a lookup table that translates 6-bit positive integer index values into their
* "Base64 Alphabet"
* equivalents as specified in Table 1 of RFC 2045. * equivalents as specified in Table 1 of RFC 2045.
* *
* Thanks to "commons" project in ws.apache.org for this code. * Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/ */
private static final byte[] STANDARD_ENCODE_TABLE = { private static final byte[] STANDARD_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '5', '6', '7', '8', '9', '+', '/'
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
}; };
/** /**
@ -93,11 +97,10 @@ public class Base64 {
* This table is only used when the Base64's mode is set to URL-SAFE. * This table is only used when the Base64's mode is set to URL-SAFE.
*/ */
private static final byte[] URL_SAFE_ENCODE_TABLE = { private static final byte[] URL_SAFE_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '5', '6', '7', '8', '9', '-', '_'
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
}; };
/** /**
@ -106,24 +109,27 @@ public class Base64 {
private static final byte PAD = '='; private static final byte PAD = '=';
/** /**
* This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in * This array is a lookup table that translates Unicode characters drawn from the "Base64
* Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 * Alphabet" (as specified in
* Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in
* the Base64
* alphabet but fall within the bounds of the array are translated to -1. * alphabet but fall within the bounds of the array are translated to -1.
* *
* Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder
* URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). * seamlessly handles both
* URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what
* to emit).
* *
* Thanks to "commons" project in ws.apache.org for this code. * Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/ */
private static final byte[] DECODE_TABLE = { private static final byte[] DECODE_TABLE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 47, 48, 49, 50, 51
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
}; };
/** Mask used to extract 6 bits, used when encoding */ /** Mask used to extract 6 bits, used when encoding */
@ -137,14 +143,17 @@ public class Base64 {
// some state be preserved between calls of encode() and decode(). // some state be preserved between calls of encode() and decode().
/** /**
* Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static
* to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch * because it is able
* to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so
* we can switch
* between the two modes. * between the two modes.
*/ */
private final byte[] encodeTable; private final byte[] encodeTable;
/** /**
* Line length for encoding. Not used when decoding. A value of zero or less implies no chunking of the base64 * Line length for encoding. Not used when decoding. A value of zero or less implies no chunking
* of the base64
* encoded data. * encoded data.
*/ */
private final int lineLength; private final int lineLength;
@ -155,13 +164,15 @@ public class Base64 {
private final byte[] lineSeparator; private final byte[] lineSeparator;
/** /**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. * Convenience variable to help us determine when our buffer is going to run out of room and needs
* resizing.
* <code>decodeSize = 3 + lineSeparator.length;</code> * <code>decodeSize = 3 + lineSeparator.length;</code>
*/ */
private final int decodeSize; private final int decodeSize;
/** /**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. * Convenience variable to help us determine when our buffer is going to run out of room and needs
* resizing.
* <code>encodeSize = 4 + lineSeparator.length;</code> * <code>encodeSize = 4 + lineSeparator.length;</code>
*/ */
private final int encodeSize; private final int encodeSize;
@ -182,25 +193,29 @@ public class Base64 {
private int readPos; private int readPos;
/** /**
* Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to * Variable tracks how many characters have been written to the current line. Only used when
* encoding. We use it to
* make sure each encoded line never goes beyond lineLength (if lineLength > 0). * make sure each encoded line never goes beyond lineLength (if lineLength > 0).
*/ */
private int currentLinePos; private int currentLinePos;
/** /**
* Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when decoding. This variable * Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when
* decoding. This variable
* helps track that. * helps track that.
*/ */
private int modulus; private int modulus;
/** /**
* Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64 object becomes useless, * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64
* object becomes useless,
* and must be thrown away. * and must be thrown away.
*/ */
private boolean eof; private boolean eof;
/** /**
* Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store and extract the * Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store
* and extract the
* base64 encoding or decoding from this variable. * base64 encoding or decoding from this variable.
*/ */
private int x; private int x;
@ -208,7 +223,8 @@ public class Base64 {
/** /**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p> * <p>
* When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. * When encoding the line length is 76, the line separator is CRLF, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p> * </p>
* *
* <p> * <p>
@ -222,15 +238,16 @@ public class Base64 {
/** /**
* Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
* <p> * <p>
* When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. * When encoding the line length is 76, the line separator is CRLF, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p> * </p>
* *
* <p> * <p>
* When decoding all variants are supported. * When decoding all variants are supported.
* </p> * </p>
* *
* @param urlSafe * @param urlSafe if <code>true</code>, URL-safe encoding is used. In most cases this should be
* if <code>true</code>, URL-safe encoding is used. In most cases this should be set to * set to
* <code>false</code>. * <code>false</code>.
* @since 1.4 * @since 1.4
*/ */
@ -241,19 +258,22 @@ public class Base64 {
/** /**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p> * <p>
* When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is * When encoding the line length is given in the constructor, the line separator is CRLF, and the
* encoding table is
* STANDARD_ENCODE_TABLE. * STANDARD_ENCODE_TABLE.
* </p> * </p>
* <p> * <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in
* the encoded data.
* </p> * </p>
* <p> * <p>
* When decoding all variants are supported. * When decoding all variants are supported.
* </p> * </p>
* *
* @param lineLength * @param lineLength Each line of encoded data will be at most of the given length (rounded down
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). * to nearest multiple of 4).
* If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored
* when decoding.
* @since 1.4 * @since 1.4
*/ */
public Base64(int lineLength) { public Base64(int lineLength) {
@ -263,23 +283,25 @@ public class Base64 {
/** /**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p> * <p>
* When encoding the line length and line separator are given in the constructor, and the encoding table is * When encoding the line length and line separator are given in the constructor, and the encoding
* table is
* STANDARD_ENCODE_TABLE. * STANDARD_ENCODE_TABLE.
* </p> * </p>
* <p> * <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in
* the encoded data.
* </p> * </p>
* <p> * <p>
* When decoding all variants are supported. * When decoding all variants are supported.
* </p> * </p>
* *
* @param lineLength * @param lineLength Each line of encoded data will be at most of the given length (rounded down
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). * to nearest multiple of 4).
* If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored
* @param lineSeparator * when decoding.
* Each line of encoded data will end with this sequence of bytes. * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown when the provided lineSeparator included some base64
* Thrown when the provided lineSeparator included some base64 characters. * characters.
* @since 1.4 * @since 1.4
*/ */
public Base64(int lineLength, byte[] lineSeparator) { public Base64(int lineLength, byte[] lineSeparator) {
@ -289,26 +311,28 @@ public class Base64 {
/** /**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p> * <p>
* When encoding the line length and line separator are given in the constructor, and the encoding table is * When encoding the line length and line separator are given in the constructor, and the encoding
* table is
* STANDARD_ENCODE_TABLE. * STANDARD_ENCODE_TABLE.
* </p> * </p>
* <p> * <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in
* the encoded data.
* </p> * </p>
* <p> * <p>
* When decoding all variants are supported. * When decoding all variants are supported.
* </p> * </p>
* *
* @param lineLength * @param lineLength Each line of encoded data will be at most of the given length (rounded down
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). * to nearest multiple of 4).
* If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored
* @param lineSeparator * when decoding.
* Each line of encoded data will end with this sequence of bytes. * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
* @param urlSafe * @param urlSafe Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is
* Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode * only applied to encode
* operations. Decoding seamlessly handles both modes. * operations. Decoding seamlessly handles both modes.
* @throws IllegalArgumentException * @throws IllegalArgumentException The provided lineSeparator included some base64 characters.
* The provided lineSeparator included some base64 characters. That's not going to work! * That's not going to work!
* @since 1.4 * @since 1.4
*/ */
public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) { public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) {
@ -327,7 +351,8 @@ public class Base64 {
this.decodeSize = this.encodeSize - 1; this.decodeSize = this.encodeSize - 1;
if (containsBase64Byte(lineSeparator)) { if (containsBase64Byte(lineSeparator)) {
String sep = newStringUtf8(lineSeparator); String sep = newStringUtf8(lineSeparator);
throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]"); throw new IllegalArgumentException(
"lineSeperator must not contain base64 characters: [" + sep + "]");
} }
this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
} }
@ -374,15 +399,14 @@ public class Base64 {
} }
/** /**
* Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a
* maximum of bAvail
* bytes. Returns how many bytes were actually extracted. * bytes. Returns how many bytes were actually extracted.
* *
* @param b * @param b byte[] array to extract the buffered data into.
* byte[] array to extract the buffered data into. * @param bPos position in byte[] array to start extraction at.
* @param bPos * @param bAvail amount of bytes we're allowed to extract. We may extract fewer (if fewer are
* position in byte[] array to start extraction at. * available).
* @param bAvail
* amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
* @return The number of bytes successfully extracted into the provided byte[] array. * @return The number of bytes successfully extracted into the provided byte[] array.
*/ */
int readResults(byte[] b, int bPos, int bAvail) { int readResults(byte[] b, int bPos, int bAvail) {
@ -405,15 +429,14 @@ public class Base64 {
} }
/** /**
* Sets the streaming buffer. This is a small optimization where we try to buffer directly to the consumer's output * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the
* array for one round (if the consumer calls this method first) instead of starting our own buffer. * consumer's output
* array for one round (if the consumer calls this method first) instead of starting our own
* buffer.
* *
* @param out * @param out byte[] array to buffer directly to.
* byte[] array to buffer directly to. * @param outPos Position to start buffering into.
* @param outPos * @param outAvail Amount of bytes available for direct buffering.
* Position to start buffering into.
* @param outAvail
* Amount of bytes available for direct buffering.
*/ */
void setInitialBuffer(byte[] out, int outPos, int outAvail) { void setInitialBuffer(byte[] out, int outPos, int outAvail) {
// We can re-use consumer's original output array under // We can re-use consumer's original output array under
@ -427,8 +450,10 @@ public class Base64 {
/** /**
* <p> * <p>
* Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least
* the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last * twice: once with
* the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been
* reached, so flush last
* remaining bytes (if not multiple of 3). * remaining bytes (if not multiple of 3).
* </p> * </p>
* <p> * <p>
@ -436,12 +461,9 @@ public class Base64 {
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
* </p> * </p>
* *
* @param in * @param in byte[] array of binary data to base64 encode.
* byte[] array of binary data to base64 encode. * @param inPos Position to start reading data from.
* @param inPos * @param inAvail Amount of bytes available from input for encoding.
* Position to start reading data from.
* @param inAvail
* Amount of bytes available from input for encoding.
*/ */
void encode(byte[] in, int inPos, int inAvail) { void encode(byte[] in, int inPos, int inAvail) {
if (eof) { if (eof) {
@ -455,7 +477,7 @@ public class Base64 {
resizeBuffer(); resizeBuffer();
} }
switch (modulus) { switch (modulus) {
case 1 : case 1:
buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS]; buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS];
buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS]; buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS];
// URL-SAFE skips the padding to further reduce size. // URL-SAFE skips the padding to further reduce size.
@ -465,7 +487,7 @@ public class Base64 {
} }
break; break;
case 2 : case 2:
buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS]; buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS];
buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS]; buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS];
buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS]; buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS];
@ -510,13 +532,17 @@ public class Base64 {
/** /**
* <p> * <p>
* Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at
* with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" * least twice: once
* with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been
* reached. The "-1"
* call is not necessary when decoding, but it doesn't hurt, either. * call is not necessary when decoding, but it doesn't hurt, either.
* </p> * </p>
* <p> * <p>
* Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled,
* silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in, * since CR and LF are
* silently ignored, but has implications for other bytes, too. This method subscribes to the
* garbage-in,
* garbage-out philosophy: it will not check the provided data for validity. * garbage-out philosophy: it will not check the provided data for validity.
* </p> * </p>
* <p> * <p>
@ -524,12 +550,9 @@ public class Base64 {
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
* </p> * </p>
* *
* @param in * @param in byte[] array of ascii data to base64 decode.
* byte[] array of ascii data to base64 decode. * @param inPos Position to start reading data from.
* @param inPos * @param inAvail Amount of bytes available from input for encoding.
* Position to start reading data from.
* @param inAvail
* Amount of bytes available from input for encoding.
*/ */
void decode(byte[] in, int inPos, int inAvail) { void decode(byte[] in, int inPos, int inAvail) {
if (eof) { if (eof) {
@ -569,11 +592,11 @@ public class Base64 {
if (eof && modulus != 0) { if (eof && modulus != 0) {
x = x << 6; x = x << 6;
switch (modulus) { switch (modulus) {
case 2 : case 2:
x = x << 6; x = x << 6;
buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
break; break;
case 3 : case 3:
buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS); buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
break; break;
@ -586,9 +609,9 @@ public class Base64 {
/** /**
* Returns whether or not the <code>octet</code> is in the base 64 alphabet. * Returns whether or not the <code>octet</code> is in the base 64 alphabet.
* *
* @param octet * @param octet The value to test
* The value to test * @return <code>true</code> if the value is defined in the the base 64 alphabet,
* @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise. * <code>false</code> otherwise.
* @since 1.4 * @since 1.4
*/ */
public static boolean isBase64(byte octet) { public static boolean isBase64(byte octet) {
@ -596,12 +619,13 @@ public class Base64 {
} }
/** /**
* Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the * Tests a given byte array to see if it contains only valid characters within the Base64
* alphabet. Currently the
* method treats whitespace as valid. * method treats whitespace as valid.
* *
* @param arrayOctet * @param arrayOctet byte array to test
* byte array to test * @return <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the
* @return <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; * byte array is empty;
* false, otherwise * false, otherwise
*/ */
public static boolean isArrayByteBase64(byte[] arrayOctet) { public static boolean isArrayByteBase64(byte[] arrayOctet) {
@ -614,15 +638,15 @@ public class Base64 {
} }
/** /**
* Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. * Tests a given byte array to see if it contains only valid characters within the Base64
* alphabet.
* *
* @param arrayOctet * @param arrayOctet byte array to test
* byte array to test * @return <code>true</code> if any byte is a valid character in the Base64 alphabet; false
* @return <code>true</code> if any byte is a valid character in the Base64 alphabet; false herwise * herwise
*/ */
private static boolean containsBase64Byte(byte[] arrayOctet) { private static boolean containsBase64Byte(byte[] arrayOctet) {
for (byte element : arrayOctet) for (byte element : arrayOctet) {
{
if (isBase64(element)) { if (isBase64(element)) {
return true; return true;
} }
@ -633,8 +657,7 @@ public class Base64 {
/** /**
* Encodes binary data using the base64 algorithm but does not chunk the output. * Encodes binary data using the base64 algorithm but does not chunk the output.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return byte[] containing Base64 characters in their UTF-8 representation. * @return byte[] containing Base64 characters in their UTF-8 representation.
*/ */
public static byte[] encodeBase64(byte[] binaryData) { public static byte[] encodeBase64(byte[] binaryData) {
@ -646,8 +669,7 @@ public class Base64 {
* <p> * <p>
* For a non-chunking version, see {@link #encodeBase64StringUnChunked(byte[])}. * For a non-chunking version, see {@link #encodeBase64StringUnChunked(byte[])}.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return String containing Base64 characters. * @return String containing Base64 characters.
* @since 1.4 * @since 1.4
*/ */
@ -660,8 +682,7 @@ public class Base64 {
* <p> * <p>
* For a chunking version, see {@link #encodeBase64String(byte[])}. * For a chunking version, see {@link #encodeBase64String(byte[])}.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return String containing Base64 characters. * @return String containing Base64 characters.
* @since 3.2 * @since 3.2
*/ */
@ -672,8 +693,7 @@ public class Base64 {
/** /**
* Encodes binary data using the base64 algorithm. * Encodes binary data using the base64 algorithm.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @param useChunking whether to split the output into chunks * @param useChunking whether to split the output into chunks
* @return String containing Base64 characters. * @return String containing Base64 characters.
* @since 3.2 * @since 3.2
@ -683,11 +703,11 @@ public class Base64 {
} }
/** /**
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the
* output. The
* url-safe variation emits - and _ instead of + and / characters. * url-safe variation emits - and _ instead of + and / characters.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return byte[] containing Base64 characters in their UTF-8 representation. * @return byte[] containing Base64 characters in their UTF-8 representation.
* @since 1.4 * @since 1.4
*/ */
@ -696,11 +716,11 @@ public class Base64 {
} }
/** /**
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the
* output. The
* url-safe variation emits - and _ instead of + and / characters. * url-safe variation emits - and _ instead of + and / characters.
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return String containing Base64 characters * @return String containing Base64 characters
* @since 1.4 * @since 1.4
*/ */
@ -709,10 +729,10 @@ public class Base64 {
} }
/** /**
* Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character
* blocks
* *
* @param binaryData * @param binaryData binary data to encode
* binary data to encode
* @return Base64 characters chunked in 76 character blocks * @return Base64 characters chunked in 76 character blocks
*/ */
public static byte[] encodeBase64Chunked(byte[] binaryData) { public static byte[] encodeBase64Chunked(byte[] binaryData) {
@ -722,8 +742,7 @@ public class Base64 {
/** /**
* Decodes a String containing containing characters in the Base64 alphabet. * Decodes a String containing containing characters in the Base64 alphabet.
* *
* @param pArray * @param pArray A String containing Base64 character data
* A String containing Base64 character data
* @return a byte array containing binary data * @return a byte array containing binary data
* @since 1.4 * @since 1.4
*/ */
@ -742,8 +761,7 @@ public class Base64 {
/** /**
* Decodes a byte[] containing containing characters in the Base64 alphabet. * Decodes a byte[] containing containing characters in the Base64 alphabet.
* *
* @param pArray * @param pArray A byte array containing Base64 character data
* A byte array containing Base64 character data
* @return a byte array containing binary data * @return a byte array containing binary data
*/ */
public byte[] decode(byte[] pArray) { public byte[] decode(byte[] pArray) {
@ -769,32 +787,32 @@ public class Base64 {
} }
/** /**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * Encodes binary data using the base64 algorithm, optionally chunking the output into 76
* character blocks.
* *
* @param binaryData * @param binaryData Array containing binary data to encode.
* Array containing binary data to encode. * @param isChunked if <code>true</code> this encoder will chunk the base64 output into 76
* @param isChunked * character blocks
* if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
* @return Base64-encoded data. * @return Base64-encoded data.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than
* Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} * {@link Integer#MAX_VALUE}
*/ */
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
return encodeBase64(binaryData, isChunked, false); return encodeBase64(binaryData, isChunked, false);
} }
/** /**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * Encodes binary data using the base64 algorithm, optionally chunking the output into 76
* character blocks.
* *
* @param binaryData * @param binaryData Array containing binary data to encode.
* Array containing binary data to encode. * @param isChunked if <code>true</code> this encoder will chunk the base64 output into 76
* @param isChunked * character blocks
* if <code>true</code> this encoder will chunk the base64 output into 76 character blocks * @param urlSafe if <code>true</code> this encoder will emit - and _ instead of the usual + and /
* @param urlSafe * characters.
* if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
* @return Base64-encoded data. * @return Base64-encoded data.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than
* Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} * {@link Integer#MAX_VALUE}
* @since 1.4 * @since 1.4
*/ */
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe) { public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe) {
@ -802,32 +820,33 @@ public class Base64 {
} }
/** /**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * Encodes binary data using the base64 algorithm, optionally chunking the output into 76
* character blocks.
* *
* @param binaryData * @param binaryData Array containing binary data to encode.
* Array containing binary data to encode. * @param isChunked if <code>true</code> this encoder will chunk the base64 output into 76
* @param isChunked * character blocks
* if <code>true</code> this encoder will chunk the base64 output into 76 character blocks * @param urlSafe if <code>true</code> this encoder will emit - and _ instead of the usual + and /
* @param urlSafe * characters.
* if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters. * @param maxResultSize The maximum result size to accept.
* @param maxResultSize
* The maximum result size to accept.
* @return Base64-encoded data. * @return Base64-encoded data.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than
* Thrown when the input array needs an output array bigger than maxResultSize * maxResultSize
* @since 1.4 * @since 1.4
*/ */
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe, int maxResultSize) { public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe,
int maxResultSize) {
if (binaryData == null || binaryData.length == 0) { if (binaryData == null || binaryData.length == 0) {
return binaryData; return binaryData;
} }
long len = getEncodeLength(binaryData, isChunked ? CHUNK_SIZE : 0, isChunked ? CHUNK_SEPARATOR : EMPTY_BYTE_ARRAY); long len = getEncodeLength(binaryData, isChunked ? CHUNK_SIZE : 0,
isChunked ? CHUNK_SEPARATOR : EMPTY_BYTE_ARRAY);
if (len > maxResultSize) { if (len > maxResultSize) {
throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + throw new IllegalArgumentException("Input array too big, the output array would be bigger ("
len + + len
") than the specified maxium size of " + + ") than the specified maxium size of "
maxResultSize); + maxResultSize);
} }
Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
@ -837,8 +856,7 @@ public class Base64 {
/** /**
* Decodes a Base64 String into octets * Decodes a Base64 String into octets
* *
* @param base64String * @param base64String String containing Base64 data
* String containing Base64 data
* @return Array containing decoded data. * @return Array containing decoded data.
* @since 1.4 * @since 1.4
*/ */
@ -849,40 +867,36 @@ public class Base64 {
/** /**
* Decodes Base64 data into octets * Decodes Base64 data into octets
* *
* @param base64Data * @param base64Data Byte array containing Base64 data
* Byte array containing Base64 data
* @return Array containing decoded data. * @return Array containing decoded data.
*/ */
public static byte[] decodeBase64(byte[] base64Data) { public static byte[] decodeBase64(byte[] base64Data) {
return new Base64().decode(base64Data); return new Base64().decode(base64Data);
} }
/** /**
* Checks if a byte value is whitespace or not. * Checks if a byte value is whitespace or not.
* *
* @param byteToCheck * @param byteToCheck the byte to check
* the byte to check
* @return true if byte is whitespace, false otherwise * @return true if byte is whitespace, false otherwise
*/ */
private static boolean isWhiteSpace(byte byteToCheck) { private static boolean isWhiteSpace(byte byteToCheck) {
switch (byteToCheck) { switch (byteToCheck) {
case ' ' : case ' ':
case '\n' : case '\n':
case '\r' : case '\r':
case '\t' : case '\t':
return true; return true;
default : default:
return false; return false;
} }
} }
/** /**
* Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet. * Encodes a byte[] containing binary data, into a String containing characters in the Base64
* alphabet.
* *
* @param pArray * @param pArray a byte array containing binary data
* a byte array containing binary data
* @return A String containing only Base64 character data * @return A String containing only Base64 character data
* @since 1.4 * @since 1.4
*/ */
@ -901,10 +915,10 @@ public class Base64 {
} }
/** /**
* Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet. * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64
* alphabet.
* *
* @param pArray * @param pArray a byte array containing binary data
* a byte array containing binary data
* @return A byte array containing only Base64 character data * @return A byte array containing only Base64 character data
*/ */
public byte[] encode(byte[] pArray) { public byte[] encode(byte[] pArray) {
@ -938,7 +952,6 @@ public class Base64 {
* @param chunkSize line-length of the output (<= 0 means no chunking) between each * @param chunkSize line-length of the output (<= 0 means no chunking) between each
* chunkSeparator (e.g. CRLF). * chunkSeparator (e.g. CRLF).
* @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF). * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF).
*
* @return amount of space needed to encoded the supplied array. Returns * @return amount of space needed to encoded the supplied array. Returns
* a long since a max-len array will require Integer.MAX_VALUE + 33%. * a long since a max-len array will require Integer.MAX_VALUE + 33%.
*/ */
@ -962,11 +975,11 @@ public class Base64 {
} }
// Implementation of integer encoding used for crypto // Implementation of integer encoding used for crypto
/** /**
* Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
* *
* @param pArray * @param pArray a byte array containing base64 character data
* a byte array containing base64 character data
* @return A BigInteger * @return A BigInteger
* @since 1.4 * @since 1.4
*/ */
@ -977,11 +990,9 @@ public class Base64 {
/** /**
* Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
* *
* @param bigInt * @param bigInt a BigInteger
* a BigInteger
* @return A byte array containing base64 character data * @return A byte array containing base64 character data
* @throws NullPointerException * @throws NullPointerException if null is passed in
* if null is passed in
* @since 1.4 * @since 1.4
*/ */
public static byte[] encodeInteger(BigInteger bigInt) { public static byte[] encodeInteger(BigInteger bigInt) {
@ -994,8 +1005,7 @@ public class Base64 {
/** /**
* Returns a byte-array representation of a <code>BigInteger</code> without sign bit. * Returns a byte-array representation of a <code>BigInteger</code> without sign bit.
* *
* @param bigInt * @param bigInt <code>BigInteger</code> to be converted
* <code>BigInteger</code> to be converted
* @return a byte array representation of the BigInteger parameter * @return a byte array representation of the BigInteger parameter
*/ */
static byte[] toIntegerBytes(BigInteger bigInt) { static byte[] toIntegerBytes(BigInteger bigInt) {

@ -29,8 +29,8 @@ public class Charsets {
/** /**
* Returns a charset object for the given charset name. * Returns a charset object for the given charset name.
* *
* @param charsetName * @param charsetName The name of the requested charset; may be a canonical name, an alias, or
* The name of the requested charset; may be a canonical name, an alias, or null. If null, return the * null. If null, return the
* default charset. * default charset.
* @return A charset object for the named charset * @return A charset object for the named charset
*/ */
@ -41,11 +41,10 @@ public class Charsets {
/** /**
* Returns a charset object for the given charset name. * Returns a charset object for the given charset name.
* *
* @param charsetName * @param charsetName The name of the requested charset; may be a canonical name, an alias, or
* The name of the requested charset; may be a canonical name, an alias, or null. * null.
* If null, return the default charset. * If null, return the default charset.
* @param defaultCharsetName the charset name to use if the requested charset is null * @param defaultCharsetName the charset name to use if the requested charset is null
*
* @return A charset object for the named charset * @return A charset object for the named charset
*/ */
public static Charset toCharset(String charsetName, String defaultCharsetName) { public static Charset toCharset(String charsetName, String defaultCharsetName) {

@ -66,7 +66,7 @@ public final class KeyManagerUtils {
private static final String DEFAULT_STORE_TYPE = KeyStore.getDefaultType(); private static final String DEFAULT_STORE_TYPE = KeyStore.getDefaultType();
private KeyManagerUtils(){ private KeyManagerUtils() {
// Not instantiable // Not instantiable
} }
@ -75,15 +75,16 @@ public final class KeyManagerUtils {
* Does not handle server keys. * Does not handle server keys.
* *
* @param ks the keystore to use * @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 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 * @param keyPass the password of the key to use
* @return the customised KeyManager * @return the customised KeyManager
* @throws GeneralSecurityException if there is a problem creating the keystore * @throws GeneralSecurityException if there is a problem creating the keystore
*/ */
public static KeyManager createClientKeyManager(KeyStore ks, String keyAlias, String keyPass) public static KeyManager createClientKeyManager(KeyStore ks, String keyAlias, String keyPass)
throws GeneralSecurityException throws GeneralSecurityException {
{ ClientKeyStore cks =
ClientKeyStore cks = new ClientKeyStore(ks, keyAlias != null ? keyAlias : findAlias(ks), keyPass); new ClientKeyStore(ks, keyAlias != null ? keyAlias : findAlias(ks), keyPass);
return new X509KeyManager(cks); return new X509KeyManager(cks);
} }
@ -94,16 +95,16 @@ public final class KeyManagerUtils {
* @param storeType the type of the keyStore, e.g. "JKS" * @param storeType the type of the keyStore, e.g. "JKS"
* @param storePath the path to the keyStore * @param storePath the path to the keyStore
* @param storePass the keyStore password * @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 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 * @param keyPass the password of the key to use
* @return the customised KeyManager * @return the customised KeyManager
* @throws GeneralSecurityException if there is a problem creating the keystore * @throws GeneralSecurityException if there is a problem creating the keystore
* @throws IOException if there is a problem creating the keystore * @throws IOException if there is a problem creating the keystore
*/ */
public static KeyManager createClientKeyManager( public static KeyManager createClientKeyManager(String storeType, File storePath,
String storeType, File storePath, String storePass, String keyAlias, String keyPass) String storePass, String keyAlias, String keyPass)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
KeyStore ks = loadStore(storeType, storePath, storePass); KeyStore ks = loadStore(storeType, storePath, storePass);
return createClientKeyManager(ks, keyAlias, keyPass); return createClientKeyManager(ks, keyAlias, keyPass);
} }
@ -115,14 +116,14 @@ public final class KeyManagerUtils {
* *
* @param storePath the path to the keyStore * @param storePath the path to the keyStore
* @param storePass the keyStore password * @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 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 * @return the customised KeyManager
* @throws IOException if there is a problem creating the keystore * @throws IOException if there is a problem creating the keystore
* @throws GeneralSecurityException 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) public static KeyManager createClientKeyManager(File storePath, String storePass, String keyAlias)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, keyAlias, storePass); return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, keyAlias, storePass);
} }
@ -139,8 +140,7 @@ public final class KeyManagerUtils {
* @throws GeneralSecurityException 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) public static KeyManager createClientKeyManager(File storePath, String storePass)
throws IOException, GeneralSecurityException throws IOException, GeneralSecurityException {
{
return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, null, storePass); return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, null, storePass);
} }
@ -159,7 +159,7 @@ public final class KeyManagerUtils {
private static String findAlias(KeyStore ks) throws KeyStoreException { private static String findAlias(KeyStore ks) throws KeyStoreException {
Enumeration<String> e = ks.aliases(); Enumeration<String> e = ks.aliases();
while(e.hasMoreElements()) { while (e.hasMoreElements()) {
String entry = e.nextElement(); String entry = e.nextElement();
if (ks.isKeyEntry(entry)) { if (ks.isKeyEntry(entry)) {
return entry; return entry;
@ -174,13 +174,12 @@ public final class KeyManagerUtils {
private final PrivateKey key; private final PrivateKey key;
private final String keyAlias; private final String keyAlias;
ClientKeyStore(KeyStore ks, String keyAlias, String keyPass) throws GeneralSecurityException ClientKeyStore(KeyStore ks, String keyAlias, String keyPass) throws GeneralSecurityException {
{
this.keyAlias = keyAlias; this.keyAlias = keyAlias;
this.key = (PrivateKey) ks.getKey(this.keyAlias, keyPass.toCharArray()); this.key = (PrivateKey) ks.getKey(this.keyAlias, keyPass.toCharArray());
Certificate[] certs = ks.getCertificateChain(this.keyAlias); Certificate[] certs = ks.getCertificateChain(this.keyAlias);
X509Certificate[] X509certs = new X509Certificate[certs.length]; X509Certificate[] X509certs = new X509Certificate[certs.length];
for (int i=0; i < certs.length; i++) { for (int i = 0; i < certs.length; i++) {
X509certs[i] = (X509Certificate) certs[i]; X509certs[i] = (X509Certificate) certs[i];
} }
this.certChain = X509certs; this.certChain = X509certs;
@ -208,39 +207,31 @@ public final class KeyManagerUtils {
} }
// Call sequence: 1 // Call sequence: 1
@Override @Override public String chooseClientAlias(String[] keyType, Principal[] issuers,
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) { Socket socket) {
return keyStore.getAlias(); return keyStore.getAlias();
} }
// Call sequence: 2 // Call sequence: 2
@Override @Override public X509Certificate[] getCertificateChain(String alias) {
public X509Certificate[] getCertificateChain(String alias) {
return keyStore.getCertificateChain(); return keyStore.getCertificateChain();
} }
@Override @Override public String[] getClientAliases(String keyType, Principal[] issuers) {
public String[] getClientAliases(String keyType, Principal[] issuers) { return new String[] { keyStore.getAlias() };
return new String[]{ keyStore.getAlias()};
} }
// Call sequence: 3 // Call sequence: 3
@Override @Override public PrivateKey getPrivateKey(String alias) {
public PrivateKey getPrivateKey(String alias) {
return keyStore.getPrivateKey(); return keyStore.getPrivateKey();
} }
@Override @Override public String[] getServerAliases(String keyType, Principal[] issuers) {
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null; return null;
} }
@Override @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return null; return null;
} }
} }
} }

@ -25,29 +25,24 @@ import java.util.concurrent.CopyOnWriteArrayList;
/** /**
*/ */
public class ListenerList implements Serializable, Iterable<EventListener> public class ListenerList implements Serializable, Iterable<EventListener> {
{
private static final long serialVersionUID = -1934227607974228213L; private static final long serialVersionUID = -1934227607974228213L;
private final CopyOnWriteArrayList<EventListener> __listeners; private final CopyOnWriteArrayList<EventListener> __listeners;
public ListenerList() public ListenerList() {
{
__listeners = new CopyOnWriteArrayList<EventListener>(); __listeners = new CopyOnWriteArrayList<EventListener>();
} }
public void addListener(EventListener listener) public void addListener(EventListener listener) {
{
__listeners.add(listener); __listeners.add(listener);
} }
public void removeListener(EventListener listener) public void removeListener(EventListener listener) {
{
__listeners.remove(listener); __listeners.remove(listener);
} }
public int getListenerCount() public int getListenerCount() {
{
return __listeners.size(); return __listeners.size();
} }
@ -58,9 +53,7 @@ public class ListenerList implements Serializable, Iterable<EventListener>
* @since 2.0 * @since 2.0
* TODO Check that this is a good defensive strategy * TODO Check that this is a good defensive strategy
*/ */
@Override @Override public Iterator<EventListener> iterator() {
public Iterator<EventListener> iterator() {
return __listeners.iterator(); return __listeners.iterator();
} }
} }

@ -26,6 +26,7 @@ import javax.net.ssl.TrustManager;
/** /**
* General utilities for SSLContext. * General utilities for SSLContext.
*
* @since 3.0 * @since 3.0
*/ */
public class SSLContextUtils { public class SSLContextUtils {
@ -36,29 +37,32 @@ public class SSLContextUtils {
/** /**
* Create and initialise an SSLContext. * Create and initialise an SSLContext.
*
* @param protocol the protocol used to instatiate the context * @param protocol the protocol used to instatiate the context
* @param keyManager the key manager, may be {@code null} * @param keyManager the key manager, may be {@code null}
* @param trustManager the trust manager, may be {@code null} * @param trustManager the trust manager, may be {@code null}
* @return the initialised context. * @return the initialised context.
* @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs
*/ */
public static SSLContext createSSLContext(String protocol, KeyManager keyManager, TrustManager trustManager) public static SSLContext createSSLContext(String protocol, KeyManager keyManager,
throws IOException { TrustManager trustManager) throws IOException {
return createSSLContext(protocol, return createSSLContext(protocol, keyManager == null ? null : new KeyManager[] { keyManager },
keyManager == null ? null : new KeyManager[] { keyManager },
trustManager == null ? null : new TrustManager[] { trustManager }); trustManager == null ? null : new TrustManager[] { trustManager });
} }
/** /**
* Create and initialise an SSLContext. * Create and initialise an SSLContext.
*
* @param protocol the protocol used to instatiate the context * @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 keyManagers the array of key managers, may be {@code null} but array entries must not be
* @param trustManagers the array of trust managers, may be {@code null} but array entries must not be {@code null} * {@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. * @return the initialised context.
* @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs
*/ */
public static SSLContext createSSLContext(String protocol, KeyManager[] keyManagers, TrustManager[] trustManagers) public static SSLContext createSSLContext(String protocol, KeyManager[] keyManagers,
throws IOException { TrustManager[] trustManagers) throws IOException {
SSLContext ctx; SSLContext ctx;
try { try {
ctx = SSLContext.getInstance(protocol); ctx = SSLContext.getInstance(protocol);

@ -25,6 +25,7 @@ import javax.net.ssl.SSLSocket;
/** /**
* General utilities for SSLSocket. * General utilities for SSLSocket.
*
* @since 3.4 * @since 3.4
*/ */
public class SSLSocketUtils { public class SSLSocketUtils {
@ -34,16 +35,20 @@ public class SSLSocketUtils {
/** /**
* Enable the HTTPS endpoint identification algorithm on an SSLSocket. * Enable the HTTPS endpoint identification algorithm on an SSLSocket.
*
* @param socket the SSL socket * @param socket the SSL socket
* @return {@code true} on success (this is only supported on Java 1.7+) * @return {@code true} on success (this is only supported on Java 1.7+)
*/ */
public static boolean enableEndpointNameVerification(SSLSocket socket) { public static boolean enableEndpointNameVerification(SSLSocket socket) {
try { try {
Class<?> cls = Class.forName("javax.net.ssl.SSLParameters"); Class<?> cls = Class.forName("javax.net.ssl.SSLParameters");
Method setEndpointIdentificationAlgorithm = cls.getDeclaredMethod("setEndpointIdentificationAlgorithm", String.class); Method setEndpointIdentificationAlgorithm =
cls.getDeclaredMethod("setEndpointIdentificationAlgorithm", String.class);
Method getSSLParameters = SSLSocket.class.getDeclaredMethod("getSSLParameters"); Method getSSLParameters = SSLSocket.class.getDeclaredMethod("getSSLParameters");
Method setSSLParameters = SSLSocket.class.getDeclaredMethod("setSSLParameters", cls); Method setSSLParameters = SSLSocket.class.getDeclaredMethod("setSSLParameters", cls);
if (setEndpointIdentificationAlgorithm != null && getSSLParameters != null && setSSLParameters != null) { if (setEndpointIdentificationAlgorithm != null
&& getSSLParameters != null
&& setSSLParameters != null) {
Object sslParams = getSSLParameters.invoke(socket); Object sslParams = getSSLParameters.invoke(socket);
if (sslParams != null) { if (sslParams != null) {
setEndpointIdentificationAlgorithm.invoke(sslParams, "HTTPS"); setEndpointIdentificationAlgorithm.invoke(sslParams, "HTTPS");

@ -21,6 +21,7 @@ import java.util.regex.Pattern;
/** /**
* A class that performs some subnet calculations given a network address and a subnet mask. * A class that performs some subnet calculations given a network address and a subnet mask.
*
* @see "http://www.faqs.org/rfcs/rfc1519.html" * @see "http://www.faqs.org/rfcs/rfc1519.html"
* @since 2.0 * @since 2.0
*/ */
@ -40,9 +41,9 @@ public class SubnetUtils {
/** Whether the broadcast/network address are included in host count */ /** Whether the broadcast/network address are included in host count */
private boolean inclusiveHostCount = false; private boolean inclusiveHostCount = false;
/** /**
* Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" * 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" * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16"
* @throws IllegalArgumentException if the parameter is invalid, * @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 * 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
@ -53,6 +54,7 @@ public class SubnetUtils {
/** /**
* Constructor that takes a dotted decimal address and a dotted decimal mask. * Constructor that takes a dotted decimal address and a dotted decimal mask.
*
* @param address An IP address, e.g. "192.168.0.1" * @param address An IP address, e.g. "192.168.0.1"
* @param mask A dotted decimal netmask e.g. "255.255.0.0" * @param mask A dotted decimal netmask e.g. "255.255.0.0"
* @throws IllegalArgumentException if the address or mask is invalid, * @throws IllegalArgumentException if the address or mask is invalid,
@ -62,12 +64,12 @@ public class SubnetUtils {
calculate(toCidrNotation(address, mask)); calculate(toCidrNotation(address, mask));
} }
/** /**
* Returns <code>true</code> if the return value of {@link SubnetInfo#getAddressCount()} * Returns <code>true</code> if the return value of {@link SubnetInfo#getAddressCount()}
* includes the network and broadcast addresses. * includes the network and broadcast addresses.
* @since 2.2 *
* @return true if the hostcount includes the network and broadcast addresses * @return true if the hostcount includes the network and broadcast addresses
* @since 2.2
*/ */
public boolean isInclusiveHostCount() { public boolean isInclusiveHostCount() {
return inclusiveHostCount; return inclusiveHostCount;
@ -76,6 +78,7 @@ public class SubnetUtils {
/** /**
* Set to <code>true</code> if you want the return value of {@link SubnetInfo#getAddressCount()} * Set to <code>true</code> if you want the return value of {@link SubnetInfo#getAddressCount()}
* to include the network and broadcast addresses. * to include the network and broadcast addresses.
*
* @param inclusiveHostCount true if network and broadcast addresses are to be included * @param inclusiveHostCount true if network and broadcast addresses are to be included
* @since 2.2 * @since 2.2
*/ */
@ -83,41 +86,56 @@ public class SubnetUtils {
this.inclusiveHostCount = inclusiveHostCount; this.inclusiveHostCount = inclusiveHostCount;
} }
/** /**
* Convenience container for subnet summary information. * Convenience container for subnet summary information.
*
*/ */
public final class SubnetInfo { public final class SubnetInfo {
/* Mask to convert unsigned int to a long (i.e. keep 32 bits) */ /* Mask to convert unsigned int to a long (i.e. keep 32 bits) */
private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL;
private SubnetInfo() {} private SubnetInfo() {
}
private int netmask() {
return netmask;
}
private int network() {
return network;
}
private int address() {
return address;
}
private int netmask() { return netmask; } private int broadcast() {
private int network() { return network; } return broadcast;
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 // 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 networkLong() {
private long broadcastLong(){ return broadcast & UNSIGNED_INT_MASK; } return network & UNSIGNED_INT_MASK;
}
private long broadcastLong() {
return broadcast & UNSIGNED_INT_MASK;
}
private int low() { private int low() {
return (isInclusiveHostCount() ? network() : return (isInclusiveHostCount() ? network()
broadcastLong() - networkLong() > 1 ? network() + 1 : 0); : broadcastLong() - networkLong() > 1 ? network() + 1 : 0);
} }
private int high() { private int high() {
return (isInclusiveHostCount() ? broadcast() : return (isInclusiveHostCount() ? broadcast()
broadcastLong() - networkLong() > 1 ? broadcast() -1 : 0); : broadcastLong() - networkLong() > 1 ? broadcast() - 1 : 0);
} }
/** /**
* Returns true if the parameter <code>address</code> is in the * Returns true if the parameter <code>address</code> is in the
* range of usable endpoint addresses for this subnet. This excludes the * range of usable endpoint addresses for this subnet. This excludes the
* network and broadcast adresses. * network and broadcast adresses.
*
* @param address A dot-delimited IPv4 address, e.g. "192.168.0.1" * @param address A dot-delimited IPv4 address, e.g. "192.168.0.1"
* @return True if in range, false otherwise * @return True if in range, false otherwise
*/ */
@ -126,7 +144,6 @@ public class SubnetUtils {
} }
/** /**
*
* @param address the address to check * @param address the address to check
* @return true if it is in range * @return true if it is in range
* @since 3.4 (made public) * @since 3.4 (made public)
@ -177,23 +194,24 @@ public class SubnetUtils {
/** /**
* Get the count of available addresses. * Get the count of available addresses.
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false.
*
* @return the count of addresses, may be zero. * @return the count of addresses, may be zero.
* @throws RuntimeException if the correct count is greater than {@code Integer.MAX_VALUE} * @throws RuntimeException if the correct count is greater than {@code Integer.MAX_VALUE}
* @deprecated (3.4) use {@link #getAddressCountLong()} instead * @deprecated (3.4) use {@link #getAddressCountLong()} instead
*/ */
@Deprecated @Deprecated public int getAddressCount() {
public int getAddressCount() {
long countLong = getAddressCountLong(); long countLong = getAddressCountLong();
if (countLong > Integer.MAX_VALUE) { if (countLong > Integer.MAX_VALUE) {
throw new RuntimeException("Count is larger than an integer: " + countLong); throw new RuntimeException("Count is larger than an integer: " + countLong);
} }
// N.B. cannot be negative // N.B. cannot be negative
return (int)countLong; return (int) countLong;
} }
/** /**
* Get the count of available addresses. * Get the count of available addresses.
* Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false.
*
* @return the count of addresses, may be zero. * @return the count of addresses, may be zero.
* @since 3.4 * @since 3.4
*/ */
@ -209,10 +227,7 @@ public class SubnetUtils {
} }
public String getCidrSignature() { public String getCidrSignature() {
return toCidrNotation( return toCidrNotation(format(toArray(address())), format(toArray(netmask())));
format(toArray(address())),
format(toArray(netmask()))
);
} }
public String[] getAllAddresses() { public String[] getAllAddresses() {
@ -221,7 +236,7 @@ public class SubnetUtils {
if (ct == 0) { if (ct == 0) {
return addresses; return addresses;
} }
for (int add = low(), j=0; add <= high(); ++add, ++j) { for (int add = low(), j = 0; add <= high(); ++add, ++j) {
addresses[j] = format(toArray(add)); addresses[j] = format(toArray(add));
} }
return addresses; return addresses;
@ -229,27 +244,44 @@ public class SubnetUtils {
/** /**
* {@inheritDoc} * {@inheritDoc}
*
* @since 2.2 * @since 2.2
*/ */
@Override @Override public String toString() {
public String toString() {
final StringBuilder buf = new StringBuilder(); final StringBuilder buf = new StringBuilder();
buf.append("CIDR Signature:\t[").append(getCidrSignature()).append("]") buf.append("CIDR Signature:\t[")
.append(" Netmask: [").append(getNetmask()).append("]\n") .append(getCidrSignature())
.append("Network:\t[").append(getNetworkAddress()).append("]\n") .append("]")
.append("Broadcast:\t[").append(getBroadcastAddress()).append("]\n") .append(" Netmask: [")
.append("First Address:\t[").append(getLowAddress()).append("]\n") .append(getNetmask())
.append("Last Address:\t[").append(getHighAddress()).append("]\n") .append("]\n")
.append("# Addresses:\t[").append(getAddressCount()).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 buf.toString();
} }
} }
/** /**
* Return a {@link SubnetInfo} instance that contains subnet-specific statistics * Return a {@link SubnetInfo} instance that contains subnet-specific statistics
*
* @return new instance * @return new instance
*/ */
public final SubnetInfo getInfo() { return new SubnetInfo(); } public final SubnetInfo getInfo() {
return new SubnetInfo();
}
/* /*
* Initialize the internal fields from the supplied CIDR mask * Initialize the internal fields from the supplied CIDR mask
@ -296,7 +328,7 @@ public class SubnetUtils {
int addr = 0; int addr = 0;
for (int i = 1; i <= 4; ++i) { for (int i = 1; i <= 4; ++i) {
int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255));
addr |= ((n & 0xff) << 8*(4-i)); addr |= ((n & 0xff) << 8 * (4 - i));
} }
return addr; return addr;
} }
@ -307,7 +339,7 @@ public class SubnetUtils {
private int[] toArray(int val) { private int[] toArray(int val) {
int ret[] = new int[4]; int ret[] = new int[4];
for (int j = 3; j >= 0; --j) { for (int j = 3; j >= 0; --j) {
ret[j] |= ((val >>> 8*(3-j)) & (0xff)); ret[j] |= ((val >>> 8 * (3 - j)) & (0xff));
} }
return ret; return ret;
} }
@ -317,7 +349,7 @@ public class SubnetUtils {
*/ */
private String format(int[] octets) { private String format(int[] octets) {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
for (int i =0; i < octets.length; ++i){ for (int i = 0; i < octets.length; ++i) {
str.append(octets[i]); str.append(octets[i]);
if (i != octets.length - 1) { if (i != octets.length - 1) {
str.append("."); str.append(".");
@ -336,7 +368,8 @@ public class SubnetUtils {
return value; return value;
} }
throw new IllegalArgumentException("Value [" + value + "] not in range ["+begin+","+end+"]"); throw new IllegalArgumentException(
"Value [" + value + "] not in range [" + begin + "," + end + "]");
} }
/* /*

@ -30,9 +30,8 @@ import javax.net.ssl.X509TrustManager;
* *
* @since 3.0 * @since 3.0
*/ */
public final class TrustManagerUtils public final class TrustManagerUtils {
{ private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {};
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[]{};
private static class TrustManager implements X509TrustManager { private static class TrustManager implements X509TrustManager {
@ -45,19 +44,14 @@ public final class TrustManagerUtils
/** /**
* Never generates a CertificateException. * Never generates a CertificateException.
*/ */
@Override @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) {
public void checkClientTrusted(X509Certificate[] certificates, String authType)
{
return; return;
} }
@Override @Override public void checkServerTrusted(X509Certificate[] certificates, String authType)
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
throws CertificateException
{
if (checkServerValidity) { if (checkServerValidity) {
for (X509Certificate certificate : certificates) for (X509Certificate certificate : certificates) {
{
certificate.checkValidity(); certificate.checkValidity();
} }
} }
@ -66,23 +60,21 @@ public final class TrustManagerUtils
/** /**
* @return an empty array of certificates * @return an empty array of certificates
*/ */
@Override @Override public X509Certificate[] getAcceptedIssuers() {
public X509Certificate[] getAcceptedIssuers()
{
return EMPTY_X509CERTIFICATE_ARRAY; return EMPTY_X509CERTIFICATE_ARRAY;
} }
} }
private static final X509TrustManager ACCEPT_ALL=new TrustManager(false); private static final X509TrustManager ACCEPT_ALL = new TrustManager(false);
private static final X509TrustManager CHECK_SERVER_VALIDITY=new TrustManager(true); private static final X509TrustManager CHECK_SERVER_VALIDITY = new TrustManager(true);
/** /**
* Generate a TrustManager that performs no checks. * Generate a TrustManager that performs no checks.
* *
* @return the TrustManager * @return the TrustManager
*/ */
public static X509TrustManager getAcceptAllTrustManager(){ public static X509TrustManager getAcceptAllTrustManager() {
return ACCEPT_ALL; return ACCEPT_ALL;
} }
@ -92,7 +84,7 @@ public final class TrustManagerUtils
* *
* @return the validating TrustManager * @return the validating TrustManager
*/ */
public static X509TrustManager getValidateServerCertificateTrustManager(){ public static X509TrustManager getValidateServerCertificateTrustManager() {
return CHECK_SERVER_VALIDITY; return CHECK_SERVER_VALIDITY;
} }
@ -100,18 +92,19 @@ public final class TrustManagerUtils
* Return the default TrustManager provided by the JVM. * Return the default TrustManager provided by the JVM.
* <p> * <p>
* This should be the same as the default used by * This should be the same as the default used by
* {@link javax.net.ssl.SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom) * {@link javax.net.ssl.SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], * java.security.SecureRandom)
* SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} * SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
* when the TrustManager parameter is set to {@code null} * when the TrustManager parameter is set to {@code null}
*
* @param keyStore the KeyStore to use, may be {@code null} * @param keyStore the KeyStore to use, may be {@code null}
* @return the default TrustManager * @return the default TrustManager
* @throws GeneralSecurityException if an error occurs * @throws GeneralSecurityException if an error occurs
*/ */
public static X509TrustManager getDefaultTrustManager(KeyStore keyStore) throws GeneralSecurityException { public static X509TrustManager getDefaultTrustManager(KeyStore keyStore)
throws GeneralSecurityException {
String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory instance = TrustManagerFactory.getInstance(defaultAlgorithm); TrustManagerFactory instance = TrustManagerFactory.getInstance(defaultAlgorithm);
instance.init(keyStore); instance.init(keyStore);
return (X509TrustManager) instance.getTrustManagers()[0]; return (X509TrustManager) instance.getTrustManagers()[0];
} }
} }

@ -35,7 +35,7 @@ import java.io.File;
* Ftp下载测试 * Ftp下载测试
*/ */
public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> { public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> {
private final String URL = "ftp://172.18.104.147:21/haha/ftp_test.apk"; private final String URL = "ftp://172.18.104.229:21/haha/测试ss123/ftp_test.apk";
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState); super.init(savedInstanceState);

@ -34,8 +34,8 @@ import com.arialyy.simple.databinding.ActivityFtpUploadBinding;
* Ftp 文件上传demo * Ftp 文件上传demo
*/ */
public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> { public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
private final String FILE_PATH = "/mnt/sdcard/成都.mp3"; private final String FILE_PATH = "/mnt/sdcard/Download/jd.jpg";
private final String URL = "ftp://172.18.104.229:21/upload/测试"; private final String URL = "ftp://192.168.1.9:21/upload/测试";
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
setTile("FTP 文件上传"); setTile("FTP 文件上传");

Loading…
Cancel
Save