/**
* This file is part of Waarp Project.
*
* Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
* COPYRIGHT.txt in the distribution for a full listing of individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Waarp . If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.waarp.gateway.kernel.exec;
import java.io.File;
import java.io.IOException;
import org.waarp.common.digest.FilesystemBasedDigest;
import org.waarp.common.digest.FilesystemBasedDigest.DigestAlgo;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.ftp.client.WaarpFtp4jClient;
/**
* FTP client compatible for Waarp Gateway Kernel as JavaExecutor<br>
* <br>
* Ftp Transfer task: synchronous<br>
*
* Result of arguments will be as FTP command.<br>
* Format is the following:<br>
* "-file filepath <br>
* -to requestedHost <br>
* -port port <br>
* -user user <br>
* -pwd pwd <br>
* [-account account] <br>
* [-mode active/passive] <br>
* [-ssl no/implicit/explicit]<br>
* [-cwd remotepath] <br>
* [-digest (crc,md5,sha1)] <br>
* [-pre extraCommand1 with ',' as separator of arguments] <br>
* -command command from (get,put,append) <br>
* [-post extraCommand2 with ',' as separator of arguments]" <br>
* <br>
* <br>
* The order of commands will be:<br>
* 1) connection to requestHost on port (if ssl native => using native ssl link)<br>
* 2) User user<br>
* 3) PASS pwd<br>
* 4) if account => ACCT account<br>
* 5) if -ssl & auth => AUTH, PBSZ 0, PROT P <br>
* 6) if passive => PASV<br>
* 7) CWD remotepath; if error => MKD remotepath then CWD remotepath (and ignoring any error)<br>
* 8) if pre => extraCommand1 with ',' replaced by ' ' (note: do not use standard commands from FTP
* like
* ACCT,PASS,REIN,USER,APPE,STOR,STOU,RETR,RMD,RNFR,RNTO,ABOR,CWD,CDUP,MODE,PASV,PORT,STRU,TYPE,
* MDTM,MLSD,MLST,SIZE,AUTH) <br>
* 9) BINARY (binary format)<br>
* 10) if get => RETR filepath.basename ; if put => STOR filepath ; if append => APPE
* filepath.basename<br>
* 11) if digest & get/put/append & remote site compatible with XCRC,XMD5,XSHA1 => FEAT (parsing if
* found corresponding XCRC,XMD5,XSHA1) ; then XCRC/XMD5/XSHA1 filepath.basename ; then locally
* comparing this XCRC/XMD5/XSHA1 with the local file<br>
* 12) if post => extraCommand2 with ',' replaced by ' ' (note: do not use standard commands from
* FTP like
* ACCT,PASS,REIN,USER,APPE,STOR,STOU,RETR,RMD,RNFR,RNTO,ABOR,CWD,CDUP,MODE,PASV,PORT,STRU,TYPE
* ,MDTM,MLSD,MLST,SIZE,AUTH)<br>
* 13) QUIT<br>
*
*
* @author "Frederic Bregier"
*
*/
public class JavaExecutorWaarpFtp4jClient implements GatewayRunnable {
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory
.getLogger(JavaExecutorWaarpFtp4jClient.class);
boolean waitForValidation;
boolean useLocalExec;
int delay;
String[] args;
int status = 0;
public JavaExecutorWaarpFtp4jClient() {
}
@Override
public void run() {
logger.info("FtpTransfer with " + args.length + " arguments");
if (args.length < 10) {
status = -1;
logger.error("Not enough arguments");
return;
}
String filepath = null;
String filename = null;
String requested = null;
int port = 21;
String user = null;
String pwd = null;
String acct = null;
boolean isPassive = true;
int ssl = 0; // -1 native, 1 auth
String cwd = null;
int digest = 0; // 1 CRC, 2 MD5, 3 SHA1
String command = null;
int codeCommand = 0; // -1 get, 1 put, 2 append
String preArgs = null;
String postArgs = null;
/*
* "-file filepath <br> -to requestedHost <br> -port port <br> -user user <br> -pwd pwd <br>
* [-account account] <br> [-mode active/passive] <br> [-ssl no/implicit/explicit]<br> [-cwd
* remotepath] <br> [-digest (crc,md5,sha1)] <br> [-pre extraCommand1 with ',' as separator
* of arguments] <br> -command command from (get,put,append) <br> [-post extraCommand2 with
* ',' as separator of arguments]" <br>
*/
for (int i = 0; i < args.length; i++) {
if (args[i].equalsIgnoreCase("-file")) {
i++;
filepath = args[i];
filename = new File(filepath).getName();
} else if (args[i].equalsIgnoreCase("-to")) {
i++;
requested = args[i];
} else if (args[i].equalsIgnoreCase("-port")) {
i++;
port = Integer.parseInt(args[i]);
} else if (args[i].equalsIgnoreCase("-user")) {
i++;
user = args[i];
} else if (args[i].equalsIgnoreCase("-pwd")) {
i++;
pwd = args[i];
} else if (args[i].equalsIgnoreCase("-account")) {
i++;
acct = args[i];
} else if (args[i].equalsIgnoreCase("-mode")) {
i++;
isPassive = (args[i].equalsIgnoreCase("passive"));
} else if (args[i].equalsIgnoreCase("-ssl")) {
i++;
if (args[i].equalsIgnoreCase("implicit")) {
ssl = -1;
} else if (args[i].equalsIgnoreCase("explicit")) {
ssl = 1;
} else {
ssl = 0;
}
} else if (args[i].equalsIgnoreCase("-cwd")) {
i++;
cwd = args[i];
} else if (args[i].equalsIgnoreCase("-digest")) {
i++;
if (args[i].equalsIgnoreCase("crc")) {
digest = 1;
} else if (args[i].equalsIgnoreCase("md5")) {
digest = 2;
} else if (args[i].equalsIgnoreCase("sha1")) {
digest = 3;
} else {
digest = 0;
}
} else if (args[i].equalsIgnoreCase("-pre")) {
i++;
preArgs = args[i].replace(',', ' ');
} else if (args[i].equalsIgnoreCase("-post")) {
i++;
postArgs = args[i].replace(',', ' ');
} else if (args[i].equalsIgnoreCase("-command")) {
i++;
command = args[i];
// get,put,append,list
// -1 get, 1 put, 2 append
if (command.equalsIgnoreCase("get")) {
codeCommand = -1;
} else if (command.equalsIgnoreCase("put")) {
codeCommand = 1;
} else if (command.equalsIgnoreCase("append")) {
codeCommand = 2;
} else {
// error
codeCommand = 0;
}
}
}
if (filepath == null || requested == null || port <= 0 || user == null || pwd == null ||
codeCommand == 0) {
status = -2;
int code = 0 +
(filepath == null ? 1 : 0) + (requested == null ? 10 : 0) +
(port <= 0 ? 100 : 0) + (user == null ? 1000 : 0) + (pwd == null ? 10000 : 0) +
(codeCommand == 0 ? 100000 : 0);
logger.error("Not enough arguments: " + code);
return;
}
int timeout = 30000;
if (delay > 1000) {
timeout = delay;
}
WaarpFtp4jClient ftpClient =
new WaarpFtp4jClient(requested, port, user, pwd, acct, isPassive, ssl,
5000, timeout);
boolean connected = false;
for (int i = 0; i < 3; i++) {
if (ftpClient.connect()) {
connected = true;
break;
}
}
if (!connected) {
status = -3;
logger.error(ftpClient.getResult());
return;
}
try {
if (cwd != null && !ftpClient.changeDir(cwd)) {
ftpClient.makeDir(cwd);
if (!ftpClient.changeDir(cwd)) {
logger.warn("Cannot change od directory: " + cwd);
}
}
if (preArgs != null) {
String[] result = ftpClient.executeCommand(preArgs);
for (String string : result) {
logger.debug("PRE: " + string);
}
}
if (!ftpClient.transferFile(filepath, filename, codeCommand)) {
status = -4;
logger.error(ftpClient.getResult());
return;
}
if (digest > 0) {
// digest check
String params = null;
DigestAlgo algo = null;
switch (digest) {
case 1: // CRC
params = "XCRC ";
algo = DigestAlgo.CRC32;
break;
case 2: // MD5
params = "XMD5 ";
algo = DigestAlgo.MD5;
break;
case 3: // SHA1
default:
params = "XSHA1 ";
algo = DigestAlgo.SHA1;
break;
}
params += filename;
String[] values = ftpClient.executeCommand(params);
String hashresult = null;
if (values != null) {
values = values[0].split(" ");
hashresult = (values.length > 3 ? values[1] : values[0]);
}
if (hashresult == null) {
status = -5;
logger.error("Hash cannot be computed: " + ftpClient.getResult());
return;
}
// now check locally
String hash;
try {
hash = FilesystemBasedDigest.getHex(
FilesystemBasedDigest.getHash(new File(filepath), false, algo));
} catch (IOException e) {
hash = null;
}
if (hash == null || (!hash.equalsIgnoreCase(hashresult))) {
status = -6;
logger.error("Hash not equal: " + ftpClient.getResult());
return;
}
}
if (postArgs != null) {
String[] result = ftpClient.executeCommand(postArgs);
for (String string : result) {
logger.debug("POST: " + string);
}
}
} finally {
ftpClient.logout();
}
logger.info("FTP transfer in\n SUCCESS\n " + filepath +
"\n <REMOTE>" + requested + "</REMOTE>");
status = 0;
}
@Override
public void setArgs(boolean waitForValidation, boolean useLocalExec, int delay, String[] args) {
this.waitForValidation = waitForValidation;
this.useLocalExec = useLocalExec;
this.delay = delay;
this.args = args;
}
@Override
public int getFinalStatus() {
return status;
}
}