package name.wasi.util;
import java.io.*;
import java.net.ServerSocket ;
import java.net.Socket ;
import java.util.ArrayList;
import java.util.StringTokenizer ;
/**
* FTP通信を制御するクラスです
* @author wasi
* @version 1.0
*/
public class FTPManager {
/**
* 受信バッファサイズ
*/
public static final int DEFAULT_RECEIVE_BUF = 16384;
/**
* 送信バッファサイズ
*/
public static final int DEFAULT_SEND_BUF = 16384;
/**
* 既定回線接続再試行回数
*/
public static final int DEFAULT_RETRY_MAX = 3 ;
/**
* 既定回線接続再試行待ち時間(ミリ秒)
*/
public static final long DEFAULT_RETRY_WAIT = 100L;
/**
* 既定応答再試行待ち時間(ミリ秒)
*/
public static final long DEFAULT_RESPONSE_WAIT = 3000L;
/**
* 既定SO_TIMEOUT値(ミリ秒)
*/
public static final int DEFAULT_SO_TIMEOUT = 3000;
/**
* データ回線接続モード(能動)
*/
public static final int FTP_ACTIVE = 0;
/**
* データ回線接続モード(受動)
*/
public static final int FTP_PASSIVE = 1;
/**
* 自動転送モード判定
*/
public static final int FTP_TYPE_AUTO = -1;
/**
* テキスト転送モード(TYPE A)
*/
public static final int FTP_TYPE_TEXT = 0;
/**
* バイナリ転送モード(TYPE I)
*/
public static final int FTP_TYPE_BINARY = 1;
/**
* FTP制御ポート(規定値)
*/
private static final int FTP_PORT = 21;
/**
* テキスト転送モード標準拡張子一覧
*/
public static final String[] DEFAULT_TEXT_EXTENSION =
{"\\.txt", "\\.text", "\\.c", "\\.cpp", "\\.h", "\\.htm", "\\.html", "\\.shtm", "\\.shtml"
, "\\.rc", "\\.cgi", "\\.log", "\\.pl", "\\.sh", "\\.rb", "\\.java", "\\.jsp", "\\.asp", "\\.php"};
/**
* デバッグログ出力モード.
*/
private boolean debugLogMode = false;
/**
* 受信バッファサイズ
*/
private int receiveBuf;
/**
* 送信バッファサイズ
*/
private int sendBuf;
/**
* FTP接続用ソケット
*/
private Socket ctrlSocket;
/**
* 制御回線出力用ストリーム
*/
private PrintWriter ctrlOut;
/**
* 制御回線入力用ストリーム
*/
private BufferedReader ctrlIn;
/**
* FTP接続先ポート
*/
private int ftpHostPort;
/**
* ローカルホストアドレス
*/
private String localHostAddress;
/**
* 回線接続リトライ最大回数
*/
private int connRetryMax;
/**
* 回線接続リトライ待ち受け間隔
*/
private long connRetryWait;
/**
* 応答リトライ待ち受け間隔
*/
private long responseWait;
/**
* SO_TIMEOUT値
*/
private int soTimeOut;
/**
* データ回線接続モード種別
*/
private int connectMode;
/**
* テキスト転送モード拡張子一覧
*/
public String[] textExtension;
/**
* 同一ディレクトリ削除フラグ
*/
public boolean isSameDirDelete = false;
/**
* コンストラクタ
*/
public FTPManager() {
super();
this.receiveBuf = FTPManager.DEFAULT_RECEIVE_BUF;
this.sendBuf = FTPManager.DEFAULT_SEND_BUF;
this.connRetryMax = FTPManager.DEFAULT_RETRY_MAX;
this.connRetryWait = FTPManager.DEFAULT_RETRY_WAIT;
this.responseWait = FTPManager.DEFAULT_RESPONSE_WAIT;
this.soTimeOut = FTPManager.DEFAULT_SO_TIMEOUT;
this.connectMode = FTP_ACTIVE;
this.ftpHostPort = FTPManager.FTP_PORT;
this.textExtension = FTPManager.DEFAULT_TEXT_EXTENSION;
}
/**
* テキスト転送モード拡張子追加
* @param addExtension テキスト転送モード拡張子
*/
public void addTextExtension(String addExtension) {
String[] rtn = new String[this.textExtension.length + 1];
for (int iii = 0; iii < this.textExtension.length; iii++) {
rtn[iii] = this.textExtension[iii];
}
rtn[rtn.length -1] = addExtension;
this.textExtension = rtn;
}
/**
* 回線接続再試行回数設定
* @param connRetryMax 回線接続再試行回数
*/
public void setConnRetryMax(int connRetryMax) {
this.connRetryMax = connRetryMax;
}
/**
* 回線接続再試行待ち時間設定
* @param connRetryWait 回線接続再試行待ち時間
*/
public void setConnRetryWait(long connRetryWait) {
this.connRetryWait = connRetryWait;
}
/**
* 応答再試行待ち時間設定
* @param responseWait 応答再試行待ち時間
*/
public void setResponseWait(long responseWait) {
this.responseWait = responseWait;
}
/**
* SO_TIMEOUT値設定
* @param soTimeOut SO_TIMEOUT値
*/
public void setSoTimeOut(int soTimeOut) {
this.soTimeOut = soTimeOut;
}
/**
* 受信バッファサイズ設定
* @param receiveBuf 受信バッファサイズ
*/
public void setReceiveBufSize(int receiveBuf) {
this.receiveBuf = receiveBuf;
}
/**
* 送信バッファサイズ設定
* @param sendBuf 送信バッファサイズ
*/
public void setSendBufSize(int sendBuf) {
this.sendBuf = sendBuf;
}
/**
* 回線接続モード設定
* @param connectMode 回線接続モード
*/
public void setConnectMode(int connectMode) {
this.connectMode = connectMode;
}
/**
* FTP接続先ポート設定
* @param ftpHostPort FTP接続先ポート
*/
public void setFtpHostPort(int ftpHostPort) {
this.ftpHostPort = ftpHostPort;
}
/**
* ローカルホストアドレス設定
* @param localHostAddress ローカルホストアドレス
*/
public void setLocalHostAddress(String localHostAddress) {
this.localHostAddress = localHostAddress;
}
/**
* デバッグログ出力モード設定
* デバッグログの可否出力を設定します
* デフォルト値は false です
* @param debugLogMode デバッグログ出力モード(出力する:true / 出力しない:false)
*/
public void setDebugLogMode(boolean debugLogMode) {
this.debugLogMode = debugLogMode;
}
/**
* 同一ディレクトリ削除フラグ設定
* サーバー/ローカルに,転送/取得ディレクトリと同名のディレクトリがある場合に
* 同名ディレクトリを削除する場合には,同一ディレクトリ削除フラグを true に設定してください
* デフォルト値は false です
* @param isSameDirDelete 同一ディレクトリ削除フラグ
*/
public void isSameDirDelete(boolean isSameDirDelete) {
this.isSameDirDelete = isSameDirDelete;
}
/**
* 回線接続
* @param ftpHostAddress FTP接続先アドレス
* @param user ログインユーザ名
* @param pass ログインパスワード
* @throws Exception 例外
* @return boolean 回線接続可否
* @throws Exception 例外
*/
public boolean connect(String ftpHostAddress, String user, String pass) throws Exception {
boolean isConn = false;
for (int iii = 0; iii < this.connRetryMax; iii++) {
try {
this.ctrlSocket = new Socket(ftpHostAddress, this.ftpHostPort);
isConn = true;
} catch (Exception e) {
if (iii == (this.connRetryMax - 1)) {
throw e;
}
this.printStackTrace(e);
Thread.sleep(this.connRetryWait);
} finally {
if (isConn) {
break;
}
}
}
if (this.localHostAddress == null) {
this.localHostAddress = this.ctrlSocket.getLocalAddress().getHostAddress();
}
this.ctrlOut = new PrintWriter(this.ctrlSocket.getOutputStream());
this.ctrlIn = new BufferedReader(new InputStreamReader(this.ctrlSocket.getInputStream()));
if (!this.logon(user, pass)) {
return false;
}
return true;
}
/**
* 回線切断
* @return boolean 実行結果(成功:true / 失敗:false)
*/
public boolean close() {
boolean rtn = true;
try {
this.sendCommand("QUIT");
if (!this.isValidMessage("221")) {
this.printSystemOut("QUITコマンドの実行に失敗しました");
rtn = false;
}
} catch (Exception e) {
this.printStackTrace(e);
rtn = false;
}
if (this.ctrlOut != null) {
try {
this.ctrlOut.close();
}
catch (Exception e) {
this.printStackTrace(e);
rtn = false;
}
}
if (this.ctrlIn != null) {
try {
this.ctrlIn.close();
}
catch (Exception e) {
this.printStackTrace(e);
rtn = false;
}
}
if (this.ctrlSocket != null) {
try {
this.ctrlSocket.close();
}
catch (Exception e) {
this.printStackTrace(e);
rtn = false;
}
}
return rtn;
}
/**
* ディレクトリ移動
* @param dirName 移動先ディレクトリ
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean changeDir(String dirName) throws Exception {
String cmd = "CWD " + dirName;
this.sendCommand(cmd);
if (!this.isValidMessage("250")) {
return false;
}
return true;
}
/**
* ファイル削除
* @param fileName ファイル名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean deleteFile(String fileName) throws Exception {
String cmd = "DELE " + fileName;
this.sendCommand(cmd);
if (!this.isValidMessage("250")) {
return false;
}
return true;
}
/**
* ディレクトリ削除
* @param dirName ディレクトリ名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean removeDir(String dirName) throws Exception {
// ディレクトリ内データ削除
if (!this.deleteContentsOnDir(dirName)) {
return false;
}
// ディレクトリ削除
String cmd = "RMD " + dirName;
this.sendCommand(cmd);
if (!this.isValidMessage("257")) {
return false;
}
return true;
}
/**
* ディレクトリ作成
* @param dirName ディレクトリ名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean makeDir(String dirName) throws Exception {
String cmdstr = "MKD " + dirName;
this.sendCommand(cmdstr);
if (!this.isValidMessage("257")) {
return false;
}
return true;
}
/**
* ファイルリスト取得
* @return String[] ファイルリスト
* @throws Exception 例外
*/
public String[] getList() throws Exception {
return this.executeLST("NLST");
}
/**
* 詳細ファイルリスト取得
* @return String[] ファイルリスト
* @throws Exception 例外
*/
public String[] getListOfDetail() throws Exception {
return this.executeLST("LIST");
}
/**
* 正規表現によるファイル転送
* 転送ファイル名の指定には正規表現を使用します
* 複数ファイルがマッチする場合には,該当ファイル全ての転送を行います
* 正規表現によるマッチングが実施されるのは指定された転送ファイルパス直下のファイルのみです
*
* サーバーに,転送ディレクトリと同名のディレクトリがある場合に
* サーバー側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 転送ファイルパス
* @param regExpFileName 転送ファイル名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean putFileByRegExp(String path, String regExpFileName) throws Exception {
File dir = new File(path);
// 転送ファイル名に合致するファイル一覧を取得する
File[] files = dir.listFiles(new MatchFilter(regExpFileName));
if (files == null) {
return false;
}
for (int fileCnt = 0; fileCnt < files.length; fileCnt++) {
if (!this.putFile(path, files[fileCnt].getName())) {
return false;
}
}
return true;
}
/**
* ファイル転送
* サーバーに,転送ディレクトリと同名のディレクトリがある場合に
* サーバー側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 転送ファイルパス null指定可能
* @param fileName 転送ファイル名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean putFile(String path, String fileName) throws Exception {
return this.putFile(path, fileName, FTPManager.FTP_TYPE_AUTO);
}
/**
* ファイル転送
* ファイル転送モードは定数として以下の3つが用意されています
* 自動:FTP_TYPE_AUTO/テキストモード:FTP_TYPE_TEXT(TYPE A)/バイナリモード:FTP_TYPE_BINARY(TYPE I)
* 自動を設定した場合は,テキスト転送モード拡張子に設定されている拡張子を元に転送モードを判定します
* 標準のテキスト転送モード拡張子はDEFAULT_TEXT_EXTENSIONに設定されています
* テキスト転送モードの拡張子を追加する場合は,addTextExtension(String extension)メソッドにて追加を行ってください
*
* サーバーに,転送ディレクトリと同名のディレクトリがある場合に
* サーバー側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 転送ファイルパス null指定可能
* @param fileName 転送ファイル名
* @param type ファイル転送モード
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean putFile(String path, String fileName, int type) throws Exception {
boolean rtn = false;
byte[] sendBuf = new byte[this.sendBuf];
Socket dataSoc = null;
OutputStream dataOut = null;
FileInputStream fisIn = null;
String filePath = "";
// ファイルパス設定
if (path == null || "".equals(path)) {
filePath = fileName;
} else {
filePath = path + File.separator + fileName;
}
// ディレクトリの場合はディレクトリ転送
File content = new File(filePath);
if (content.isDirectory()) {
return this.putDir(path, fileName);
}
// 転送モード設定
type = this.judgeFtpType(fileName, type);
this.executeTYPE(type);
// ファイル転送実行
try {
dataSoc = this.getDataConnection("STOR " + fileName);
if (dataSoc == null) {
return false;
}
dataOut = dataSoc.getOutputStream();
fisIn = new FileInputStream(filePath);
int sendBytes = 0;
while((sendBytes = fisIn.read(sendBuf)) > 0) {
dataOut.write(sendBuf, 0, sendBytes);
dataOut.flush();
}
rtn = true;
} catch (FileNotFoundException e) {
this.printSystemOut("ファイルが見つかりません : " + filePath);
throw e;
} catch (Exception e) {
this.printSystemOut("ファイル転送に失敗しました");
throw e;
} finally {
if (fisIn != null) {
fisIn.close();
}
if (dataOut != null) {
dataOut.close();
}
if (dataSoc != null) {
dataSoc.close();
}
}
return rtn;
}
/**
* 正規表現によるファイル取得
* 取得ファイル名の指定には正規表現を使用します
* 複数ファイルがマッチする場合には,該当ファイル全ての取得を行います
* 正規表現によるマッチングが実施されるのは取得先直下のファイルのみです
*
* ローカルに,取得ディレクトリと同名のディレクトリがある場合に
* ローカル側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 取得ファイル保存先ディレクトリ(フルパス)
* @param regExpFileName 取得ファイル名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean getFileByRegExp(String path, String regExpFileName) throws Exception {
String[] srvFileList = this.getListOfInternalProcess();
if (srvFileList == null) {
return false;
}
for (int srvFileCnt = 0; srvFileCnt < srvFileList.length; srvFileCnt++) {
// 正規表現にマッチしない場合は処理を抜ける。
if (!srvFileList[srvFileCnt].matches(regExpFileName)) {
continue;
}
if (!this.getFile(path, srvFileList[srvFileCnt])) {
return false;
}
}
return true;
}
/**
* ファイル取得
* ローカルに,取得ディレクトリと同名のディレクトリがある場合に
* ローカル側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 取得ファイル保存先ディレクトリ(フルパス)
* @param fileName ファイル名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean getFile(String path, String fileName) throws Exception {
return this.getFile(path, fileName, FTPManager.FTP_TYPE_AUTO);
}
/**
* ファイル取得
* ファイル転送モードは定数として以下の3つが用意されています
* 自動:FTP_TYPE_AUTO/テキストモード:FTP_TYPE_TEXT(TYPE A)/バイナリモード:FTP_TYPE_BINARY(TYPE I)
* 自動を設定した場合は,テキスト転送モード拡張子に設定されている拡張子を元に転送モードを判定します
* 標準のテキスト転送モード拡張子はDEFAULT_TEXT_EXTENSIONに設定されています
* テキスト転送モードの拡張子を追加する場合は,addTextExtension(String extension)メソッドにて追加を行ってください
*
* ローカルに,取得ディレクトリと同名のディレクトリがある場合に
* ローカル側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 取得ファイル保存先ディレクトリ(フルパス)
* @param fileName ファイル名
* @param type ファイル転送モード
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
public boolean getFile(String path, String fileName, int type) throws Exception {
byte[] recvBuf = new byte[this.receiveBuf];
FileOutputStream fosOut = null;
Socket dataSoc = null;
InputStream dataIn = null;
String filePath = "";
// ディレクトリの場合はディレクトリ取得
if (this.isDir(fileName)) {
return this.getDir(path, fileName);
}
// 転送モード設定
type = this.judgeFtpType(fileName, type);
this.executeTYPE(type);
// ファイルパス設定
filePath = path + File.separator + fileName;
// ファイル取得実行
try {
dataSoc = this.getDataConnection("RETR " + fileName);
if (dataSoc == null) {
return false;
}
dataIn = dataSoc.getInputStream();
fosOut = new FileOutputStream(filePath);
int readBytes = 0;
while((readBytes = dataIn.read(recvBuf)) > 0) {
fosOut.write(recvBuf, 0, readBytes);
}
} catch (FileNotFoundException e) {
this.printSystemOut("ファイルが見つかりません : " + filePath);
throw e;
} catch (Exception e) {
this.printSystemOut("ファイル取得に失敗しました");
throw e;
} finally {
if (fosOut != null) {
fosOut.close();
}
if (dataIn != null) {
dataIn.close();
}
if (dataSoc != null) {
dataSoc.close();
}
}
return true;
}
/**
* ログイン
* @param user ユーザ名
* @param pass パスワード
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
private boolean logon(String user, String pass) throws Exception {
String cmd = "USER " + user;
this.sendCommand(cmd);
if (!this.isValidMessage("331")) {
return false;
}
cmd = "PASS " + pass;
this.sendCommand(cmd);
if (!this.isValidMessage("230")) {
return false;
}
return true;
}
/**
* コマンド送信
* @param cmd 送信コマンド
*/
private void sendCommand(String cmd) {
this.ctrlOut.println(cmd);
this.ctrlOut.flush();
this.printSystemOut(cmd);
}
/**
* 転送モード指定
* @param type 転送モード
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
private boolean executeTYPE(int type) throws Exception {
String cmd;
if (type == FTPManager.FTP_TYPE_TEXT) {
cmd = "TYPE A";
} else {
cmd = "TYPE I";
}
this.sendCommand(cmd);
if (!this.isValidMessage("200")) {
return false;
}
return true;
}
/**
* ファイルリスト取得
* @return String[] ファイルリスト
* @throws Exception 例外
*/
private String[] executeLST(String cmd) throws Exception {
String[] rtn = null;
StringBuffer rcvMsgBuf = new StringBuffer();
Socket dataSoc = null;
BufferedReader dataIn = null;
try {
dataSoc = this.getDataConnection(cmd);
if (dataSoc == null) {
return null;
}
dataIn = new BufferedReader(new InputStreamReader(dataSoc.getInputStream()));
while(dataIn.ready()) {
String line = dataIn.readLine();
rcvMsgBuf.append(line + "\n");
}
StringTokenizer st = new StringTokenizer(rcvMsgBuf.toString(), "\n");
int tokenCnt = st.countTokens();
rtn = new String[tokenCnt];
for (int cnt = 0; cnt < tokenCnt; cnt++) {
rtn[cnt] = st.nextToken();
}
} catch (Exception e) {
this.printSystemOut("ファイルリスト取得に失敗しました");
throw e;
} finally {
if (dataIn != null) {
dataIn.close();
}
if (dataSoc != null) {
dataSoc.close();
}
}
return rtn;
}
/**
* ディレクトリ内ファイル削除
* @param dirName ディレクトリ名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
private boolean deleteContentsOnDir(String dirName) throws Exception {
// ディレクトリ内に移動
if (!this.changeDir(dirName)) {
return false;
}
// ディレクトリ内ファイル一覧取得
String[] fileList = this.getListOfInternalProcess();
// ディレクトリ内詳細ファイル一覧取得
String[] detailList = this.getDetailListOfInternalProcess();
if (fileList != null) {
// ファイル数分処理を実行
for (int iii = 0; iii < fileList.length; iii++) {
File f = new File(fileList[iii]);
if (f == null) {
continue;
}
// ディレクトリの場合の処理
if (detailList[iii].startsWith("d")) {
if (!this.removeDir(f.getName())) {
return false;
}
} else { // ファイルの場合の処理
if (!this.deleteFile(f.getName())) {
return false;
}
}
}
}
// 元のディレクトリに戻る
if (!this.changeDir("../")) {
return false;
}
return true;
}
/**
* ディレクトリ転送
* サーバーに,転送ディレクトリと同名のディレクトリがある場合に
* サーバー側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 転送ファイルパス null指定可能
* @param dirName 転送ディレクトリ名
* @param isDelete 同一ディレクトリ削除フラグ(true : 削除する、false : 削除しない)
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception
*/
private boolean putDir(String path, String dirName) throws Exception {
// サーバーのファイル一覧を取得
String[] dirList = this.getList();
boolean isExistsDir = false; // ディレクトリ存在フラグ
if (dirList != null) {
// サーバーに、転送ディレクトリと同名のディレクトリがあるか判定
for (int iii = 0; iii < dirList.length; iii++) {
if (!dirList[iii].equals(dirName)) {
continue;
}
// 削除モードの場合、転送ディレクトリと同名のディレクトリは削除する
if (this.isSameDirDelete) {
// ディレクトリの削除
if (!this.removeDir(dirName)) {
return false;
}
} else {
isExistsDir = true;
}
}
}
// ディレクトリが存在しない場合は作成する
if (!isExistsDir) {
if (!this.makeDir(dirName)) {
return false;
}
}
// ディレクトリ内に移動
if (!this.changeDir(dirName)) {
return false;
}
// ディレクトリ内のファイルを転送
String dirPath = path + File.separator + dirName;
File dir = new File(dirPath);
File[] childFiles = dir.listFiles();
if (childFiles != null) {
for (int childCnt = 0; childCnt < childFiles.length; childCnt++) {
if (!this.putFile(dirPath, childFiles[childCnt].getName())) {
return false;
}
}
}
// 元のディレクトリに戻る
if (!this.changeDir("../")) {
return false;
}
return true;
}
/**
* ディレクトリ取得
* ローカルに,取得ディレクトリと同名のディレクトリがある場合に
* ローカル側の同名ディレクトリを削除する場合には,isSameDirDelete(boolean isSameDirDelete)メソッドにて
* 同一ディレクトリ削除フラグを true に設定してください
* @param path 取得ディレクトリ保存先パス(フルパス)
* @param dirName ディレクトリ名
* @return boolean 実行結果(成功:true / 失敗:false)
* @throws Exception 例外
*/
private boolean getDir(String path, String dirName) throws Exception {
File localFile = new File(path + File.separator + dirName);
// ローカルに、取得ディレクトリと同名のディレクトリがあるか判定
boolean isExists = localFile.exists();
// 削除モードの場合、取得ディレクトリと同名のディレクトリは削除する
if (isExists && this.isSameDirDelete) {
if (!localFile.delete()) {
return false;
}
isExists = false;
}
// ディレクトリが存在しない場合は作成する
if (!isExists) {
if (!localFile.mkdirs()) {
return false;
}
}
// ディレクトリ内に移動
if (!changeDir(dirName)) {
return false;
}
// ディレクトリ内のファイルを取得
String[] childList = this.getListOfInternalProcess();
if (childList == null) {
return false;
}
for (int childCnt = 0; childCnt < childList.length; childCnt++) {
if (!this.getFile(path + File.separator + dirName, childList[childCnt])) {
return false;
}
}
// 元のディレクトリに戻る
if (!this.changeDir("../")) {
return false;
}
return true;
}
/**
* ディレクトリ判定
* 指定ファイルがディレクトリか判定します
* @param fileName ファイル名
* @return boolean 判定結果(ディレクトリ:true / ディレクトリ以外:false)
* @throws Exception 例外
*/
private boolean isDir(String fileName) throws Exception {
boolean rtn = false;
String[] list = this.getListOfInternalProcess();
String[] detailList = this.getDetailListOfInternalProcess();
for (int iii = 0; iii < list.length; iii++) {
if (!list[iii].equals(fileName)) {
continue;
}
if (detailList[iii].startsWith("d")) {
rtn = true;
}
break;
}
return rtn;
}
/**
* 内部処理用リスト取得
* @return String[] 内部処理用リスト
* @throws Exception 例外
*/
@SuppressWarnings("unchecked")
private String[] getListOfInternalProcess() throws Exception {
String[] rtn = null;
String[] tmpList = this.getList();
if (tmpList == null) {
return null;
}
ArrayList list = new ArrayList();
for (int iii = 0; iii < tmpList.length; iii++) {
if (!tmpList[iii].matches("\\.")
&& !tmpList[iii].matches("\\.\\.")) {
list.add(tmpList[iii]);
}
}
rtn = (String[])list.toArray(new String[list.size()]);
return rtn;
}
/**
* 内部処理用詳細リスト取得
* @return String[] 内部処理用詳細リスト
* @throws Exception 例外
*/
@SuppressWarnings("unchecked")
private String[] getDetailListOfInternalProcess() throws Exception {
String[] rtn = null;
String[] tmpList = this.getListOfDetail();
if (tmpList == null) {
return null;
}
ArrayList list = new ArrayList();
for (int iii = 0; iii < tmpList.length; iii++) {
String fileName = this.getFileNameByDetail(tmpList[iii]);
if ((tmpList[iii].startsWith("-")
|| tmpList[iii].startsWith("d")
|| tmpList[iii].startsWith("l")
|| tmpList[iii].startsWith("c")
|| tmpList[iii].startsWith("b"))
&& !fileName.matches("\\.")
&& !fileName.matches("\\.\\.")) {
list.add(tmpList[iii]);
}
}
rtn = (String[])list.toArray(new String[list.size()]);
return rtn;
}
/**
* 詳細からファイル名取得
* @param detail 詳細
* @return String ファイル名
*/
private String getFileNameByDetail(String detail) {
String[] splitDetail = detail.split(" ");
return splitDetail[splitDetail.length - 1];
}
/**
* 応答メッセージ取得
* @param code 要求レスポンスコード
* @return 応答メッセージ
* @throws Exception 例外
*/
private synchronized String getReplyMsg(String code) throws Exception {
String rtn = null;
long timeOut = System.currentTimeMillis() + this.responseWait;
while(System.currentTimeMillis() < timeOut) {
if (!this.ctrlIn.ready()) {
continue;
}
rtn = this.ctrlIn.readLine();
if (rtn == null) {
continue;
}
this.printSystemOut(rtn);
if (rtn.startsWith("4") || rtn.startsWith("5")) {
break;
} else if (code != null && !"".equals(code)) {
if (rtn.startsWith(code)) {
break;
}
} else if (rtn.indexOf(" ") == 3) {
break;
}
}
return rtn;
}
/**
* 正常応答判定
* @param code 要求レスポンスコード
* @return boolean 判定結果(正常:true / 異状:false)
* @throws Exception 例外
*/
private boolean isValidMessage(String code) throws Exception {
String replyMsg = this.getReplyMsg(code);
if (replyMsg != null) {
return true;
}
return false;
}
/**
* ファイル転送種別判定
* @param fname ファイル名
* @param type ファイル転送種別
* @return int ファイル転送種別
*/
private int judgeFtpType(String fname, int type) {
int rtn = type;
// 転送モード設定
if (type != FTPManager.FTP_TYPE_TEXT && type != FTPManager.FTP_TYPE_BINARY) {
for (int iii = 0; iii < this.textExtension.length; iii++) {
if (fname.matches("\\.*" + this.textExtension[iii])) {
rtn = FTPManager.FTP_TYPE_TEXT;
break;
} else {
rtn = FTPManager.FTP_TYPE_BINARY;
}
}
}
return rtn;
}
/**
* PASVモード用回線アドレス取得
* PASV応答からPASVモード用回線アドレスを取得します
* 配列の最初の要素に要求IPアドレス次の要素にポート番号が入ります
* @return String[] PASVモード用回線アドレス(String[]{IPアドレス, ポート} 例:String[]{"192.168.0.1", "21"})
* @throws Exception 例外
*/
private String[] getPASVAddress() throws Exception {
String replyMsg = this.getReplyMsg("227");
if (replyMsg != null && replyMsg.startsWith("227")) {
return this.makePASVAddressByReplyMsg(replyMsg);
}
return null;
}
/**
* PASVモード用回線アドレス生成
* @param replyMsg 応答メッセージ
* @return String[] PASVモード用回線アドレス(String[]{IPアドレス, ポート} 例:String[]{"192.168.0.1", "21"})
* @throws Exception 例外
*/
private String[] makePASVAddressByReplyMsg(String replyMsg) throws Exception {
String[] rtn = new String[2];
StringTokenizer st = new StringTokenizer(replyMsg);
st.nextToken("(");
String addr = st.nextToken(")");
addr = addr.replaceAll("\\(", "");
String[] addrSplit = addr.split(",");
StringBuffer buf = new StringBuffer();
for (int iii = 0; iii < 4; iii++) {
if (iii > 0) {
buf.append(".");
}
buf.append(addrSplit[iii]);
}
rtn[0] = buf.toString();
rtn[1] = String.valueOf(
Integer.parseInt(addrSplit[4]) * 256 + Integer.parseInt(addrSplit[5]));
return rtn;
}
/**
* データ回線接続
* @param cmd 送信コマンド
* @return Socket データ送信回線
* @throws Exception 例外
*/
private Socket getDataConnection(String cmd) throws Exception {
Socket rtn = null;
ServerSocket srvSoc = null;
try {
if (this.connectMode == FTPManager.FTP_PASSIVE) {
String storeCmd = "PASV";
this.sendCommand(storeCmd);
String[] pasvAddr = this.getPASVAddress();
rtn = new Socket(pasvAddr[0], Integer.parseInt(pasvAddr[1]));
rtn.setSoTimeout(this.soTimeOut);
// コマンド送信
this.sendCommand(cmd);
if (!this.isValidMessage("226")) {
rtn = null;
}
} else {
String storeCmd = "PORT ";
srvSoc = new ServerSocket(0,1);
storeCmd = storeCmd + this.localHostAddress;
storeCmd = storeCmd.replace('.', ',');
storeCmd = storeCmd + ","
+ (((srvSoc.getLocalPort()) / 256) & 0xff)
+ ","
+ (srvSoc.getLocalPort() & 0xff);
this.sendCommand(storeCmd);
if (this.isValidMessage("200")) {
// コマンド送信
this.sendCommand(cmd);
if (this.isValidMessage("226")) {
rtn = srvSoc.accept();
}
}
}
} catch (Exception e) {
this.printSystemOut("データ回線接続に失敗しました");
throw e;
} finally {
if (srvSoc != null) {
srvSoc.close();
}
}
return rtn;
}
/**
* デバッグログメッセージ出力.
* @param logMsg ログメッセージ
*/
private void printSystemOut(String logMsg) {
if (this.debugLogMode) {
System.out.println(logMsg);
}
}
/**
* デバッグトレースログ出力
* @param e Throwable
*/
private void printStackTrace(Throwable e) {
if (this.debugLogMode) {
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*/
private class MatchFilter implements FileFilter {
/*
* (non-Javadoc)
*/
private String filter;
/*
* (non-Javadoc)
*/
private MatchFilter(String filter) {
this.filter = filter;
}
/*
* (non-Javadoc)
* @see java.io.FileFilter#accept(java.io.File)
*/
public boolean accept(File pathName) {
if (pathName.getName().matches(this.filter)) {
return true;
}
return false;
}
}
}