/*
* Copyright (C) 2000 - 2008 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD 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 OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*/
package com.naryx.tagfusion.cfm.tag.net;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.nary.io.FileUtils;
import com.nary.util.FastMap;
import com.nary.util.string;
import com.naryx.tagfusion.cfm.engine.cfBooleanData;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfDateData;
import com.naryx.tagfusion.cfm.engine.cfNumberData;
import com.naryx.tagfusion.cfm.engine.cfQueryResultData;
import com.naryx.tagfusion.cfm.engine.cfSession;
import com.naryx.tagfusion.cfm.engine.cfStringData;
import com.naryx.tagfusion.cfm.engine.cfStructData;
import com.naryx.tagfusion.cfm.engine.cfmBadFileException;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
import com.naryx.tagfusion.cfm.parser.cfLData;
import com.naryx.tagfusion.cfm.parser.runTime;
import com.naryx.tagfusion.cfm.tag.cfTag;
import com.naryx.tagfusion.cfm.tag.cfTagReturnType;
/*
* This class provides the implementation of the CFFTP
*/
public class cfFTP extends cfTag implements Serializable {
static final long serialVersionUID = 1;
protected void defaultParameters(String _tag) throws cfmBadFileException {
defaultAttribute("PORT", 21);
defaultAttribute("URIDIRECTORY", "No");
defaultAttribute("PASSIVE", "No");
parseTagHeader(_tag);
if (!containsAttribute("ACTION"))
throw newBadFileException("Missing ACTION", "You need to provide a ACTION");
}
public cfTagReturnType render(cfSession _Session) throws cfmRunTimeException {
// --[ Need to get a connection sorted out
String ACTION = getDynamic(_Session, "ACTION").getString().toLowerCase();
if (ACTION.equals("open")) {
if (!containsAttribute("CONNECTION"))
throw newRunTimeException("When ACTION=OPEN you must provide a CONNECTION attribute");
try {
openNewConnection(_Session);
} catch (SecurityException secExc) {
throw newRunTimeException("CFFTP is not supported if SocketPermission is not enabled for the FTP server.");
}
} else if (ACTION.equals("close")) {
if (!containsAttribute("CONNECTION"))
throw newRunTimeException("When ACTION=CLOSE you must provide a CONNECTION attribute");
closeConnection(_Session);
} else {
cfFTPConnection ftpCon;
try {
ftpCon = getConnection(_Session);
} catch (SecurityException secExc) {
throw newRunTimeException("CFFTP is not supported if SocketPermission is not enabled for the FTP server.");
}
if (!ftpCon.didSucceed()) {
handleError(_Session, ftpCon);
return cfTagReturnType.NORMAL;
}
// --[ Put a lock on the ftpConnection to ensure it can't be reused.
try {
ftpCon.lock();
if (ACTION.equals("changedir"))
actionChangeDir(_Session, ftpCon);
else if (ACTION.equals("createdir"))
actionCreateDir(_Session, ftpCon);
else if (ACTION.equals("removedir"))
actionRemoveDir(_Session, ftpCon);
else if (ACTION.equals("existsdir"))
actionDirExists(_Session, ftpCon);
else if (ACTION.equals("getcurrentdir"))
actionGetCurrentDir(_Session, ftpCon);
else if (ACTION.equals("getcurrenturl"))
actionGetCurrentURL(_Session, ftpCon);
else if (ACTION.equals("existsfile"))
actionFileExists(_Session, ftpCon);
else if (ACTION.equals("exists"))
actionExists(_Session, ftpCon);
else if (ACTION.equals("remove"))
actionRemove(_Session, ftpCon);
else if (ACTION.equals("rename"))
actionRename(_Session, ftpCon);
else if (ACTION.equals("putfile"))
actionPutFile(_Session, ftpCon);
else if (ACTION.equals("getfile"))
actionGetFile(_Session, ftpCon);
else if (ACTION.equals("listdir"))
actionListDir(_Session, ftpCon);
} finally {
// --[ Release the lock
ftpCon.unlock();
}
handleError(_Session, ftpCon);
}
return cfTagReturnType.NORMAL;
}
// -----------------------------------------------------------------
private cfFTPConnection getConnection(cfSession _Session) throws cfmRunTimeException {
// If this method is called then they must provide a CONNECTION attribute
if (!containsAttribute("CONNECTION"))
throw newRunTimeException("You must provide a CONNECTION attribute");
return getConnection(_Session, getDynamic(_Session, "CONNECTION").getString().toLowerCase());
}
private cfFTPConnection getConnection(cfSession _Session, String _connection) throws cfmRunTimeException {
cfFTPConnection ftpData = null;
cfData data = runTime.runExpression(_Session, _connection, false);
if ((data.getDataType() == cfData.CFLDATA) && ((cfLData) data).exists()) {
ftpData = (cfFTPConnection) ((cfLData) data).Get(_Session.getCFContext());
}
// try{
// ftpData = (cfFTPConnection) runTime.runExpression( _Session, _connection );
// }catch( cfmRunTimeException ignored ){}
if (ftpData != null) {
if (containsAttribute("STOPONERROR"))
ftpData.setStopOnError(getDynamic(_Session, "STOPONERROR").getBoolean());
if (!ftpData.isConnectionOpen())
ftpData.open();
} else {
ftpData = openConnection(_Session);
_Session.setData(_connection, ftpData);
}
ftpData.resetError();
return ftpData;
}
// -----------------------------------------------------------------
private void openNewConnection(cfSession _Session) throws cfmRunTimeException {
String connection = getDynamic(_Session, "CONNECTION").getString().toLowerCase();
cfFTPConnection ftpData = getConnection(_Session, connection);
if (ftpData == null) {
ftpData = openConnection(_Session);
_Session.setData(connection, ftpData);
} else {
if (!ftpData.isConnectionOpen())
ftpData.open();
}
handleError(_Session, ftpData);
}
private void closeConnection(cfSession _Session) throws cfmRunTimeException {
String connection = getDynamic(_Session, "CONNECTION").getString().toLowerCase();
cfFTPConnection ftpData;
try {
ftpData = (cfFTPConnection) runTime.runExpression(_Session, connection);
if (ftpData != null)
ftpData.close();
} catch (cfmRunTimeException rte) {
ftpData = new cfFTPConnection(false, 0, "Connection did not exist");
}
if (containsAttribute("STOPONERROR"))
ftpData.setStopOnError(getDynamic(_Session, "STOPONERROR").getBoolean());
handleError(_Session, ftpData);
}
// -----------------------------------------------------------------
private cfFTPConnection openConnection(cfSession _Session) throws cfmRunTimeException {
// ---[ Opens a clean connection
if (!containsAttribute("SERVER"))
throw newRunTimeException("CFFTP: Missing the SERVER attribute");
if (!containsAttribute("USERNAME"))
throw newRunTimeException("CFFTP: Missing the USERNAME attribute");
if (!containsAttribute("PASSWORD"))
throw newRunTimeException("CFFTP: Missing the PASSWORD attribute");
cfFTPConnection ftpCon = new cfFTPConnection(getDynamic(_Session, "SERVER").getString(), getDynamic(_Session, "PORT").getInt(), getDynamic(_Session, "USERNAME").getString(), getDynamic(_Session, "PASSWORD").getString());
// --[ Set any optional secondary parameters
if (containsAttribute("TIMEOUT"))
ftpCon.setTimeout(getDynamic(_Session, "TIMEOUT").getInt());
if (containsAttribute("STOPONERROR"))
ftpCon.setStopOnError(getDynamic(_Session, "STOPONERROR").getBoolean());
// --[ Attempt to open the connection
ftpCon.open();
return ftpCon;
}
private static String determineTransferMode(File LOCALFILE, cfData asciiListData) throws cfmRunTimeException {
String asciiList = "txt;htm;html;cfm;cfml;shtm;shtml;css;asp;asa";
if (asciiListData != null)
asciiList = asciiListData.getString();
int c1 = LOCALFILE.toString().lastIndexOf(".");
if (c1 == -1)
return "BINARY";
String ext = LOCALFILE.toString().substring(c1 + 1).toLowerCase();
List<String> tokens = string.split(asciiList, ";");
for (int i = 0; i < tokens.size(); i++) {
if (ext.equals(tokens.get(i)))
return "ASCII";
}
return "BINARY";
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void handleError(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
cfStructData error = new cfStructData();
error.setData("succeeded", cfBooleanData.getcfBooleanData(ftpCon.didSucceed()));
error.setData("errorcode", new cfNumberData(ftpCon.getErrorCode()));
error.setData("errortext", new cfStringData(ftpCon.getErrorText()));
if (!ftpCon.didSucceed() && ftpCon.stopOnError())
throw newRunTimeException("The operation could not finish: " + ftpCon.getErrorCode() + " " + ftpCon.getErrorText());
if (ftpCon.getReturnValue() != null)
error.setData("returnvalue", ftpCon.getReturnValue());
if (containsAttribute("RESULT")) {
_Session.setData(getDynamic(_Session, "RESULT").getString(), error);
} else {
_Session.setData("cfftp", error);
}
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionChangeDir(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("DIRECTORY"))
throw newRunTimeException("CFFTP.changeDir: Missing the DIRECTORY attribute");
ftpCon.actionChangeDir(getDynamic(_Session, "DIRECTORY").getString());
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionCreateDir(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("DIRECTORY"))
throw newRunTimeException("CFFTP.changeDir: Missing the DIRECTORY attribute");
ftpCon.actionCreateDir(getDynamic(_Session, "DIRECTORY").getString());
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionRemoveDir(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("DIRECTORY"))
throw newRunTimeException("CFFTP.changeDir: Missing the DIRECTORY attribute");
ftpCon.actionRemoveDir(getDynamic(_Session, "DIRECTORY").getString());
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionDirExists(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("DIRECTORY"))
throw newRunTimeException("CFFTP.changeDir: Missing the DIRECTORY attribute");
boolean bResult = ftpCon.actionDirExists(getDynamic(_Session, "DIRECTORY").getString());
ftpCon.setReturnValue(cfBooleanData.getcfBooleanData(bResult));
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private static void actionGetCurrentDir(cfSession _Session, cfFTPConnection ftpCon) {
String result = ftpCon.actionGetCurrentDir();
ftpCon.setReturnValue(new cfStringData(result));
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private static void actionGetCurrentURL(cfSession _Session, cfFTPConnection ftpCon) {
String result = ftpCon.actionGetCurrentURL();
ftpCon.setReturnValue(new cfStringData(result));
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionFileExists(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("REMOTEFILE"))
throw newRunTimeException("CFFTP.existsfile: Missing the REMOTEFILE attribute");
if (containsAttribute("PASSIVE"))
ftpCon.setPassive(getDynamic(_Session, "PASSIVE").getBoolean());
try {
boolean bResult = ftpCon.actionFileExists(getDynamic(_Session, "REMOTEFILE").getString());
ftpCon.setReturnValue(cfBooleanData.getcfBooleanData(bResult));
} catch (IOException e) {
throw newRunTimeException("CFFTP.fileexists IOException: " + e.getMessage());
}
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionExists(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("ITEM"))
throw newRunTimeException("CFFTP.exists: Missing the ITEM attribute");
if (containsAttribute("PASSIVE"))
ftpCon.setPassive(getDynamic(_Session, "PASSIVE").getBoolean());
String item = getDynamic(_Session, "ITEM").getString();
boolean bResult;
try {
bResult = ftpCon.actionFileExists(item);
if (bResult)
ftpCon.setReturnValue(cfBooleanData.TRUE);
} catch (IOException e) {
throw newRunTimeException("CFFTP.exists IOException: " + e.getMessage());
}
bResult = ftpCon.actionDirExists(item);
ftpCon.setReturnValue(cfBooleanData.getcfBooleanData(bResult));
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionRemove(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("ITEM"))
throw newRunTimeException("CFFTP.remove: Missing the ITEM attribute");
ftpCon.actionRemove(getDynamic(_Session, "ITEM").getString());
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionRename(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("EXISTING"))
throw newRunTimeException("CFFTP.rename: Missing the EXISTING attribute");
if (!containsAttribute("NEW"))
throw newRunTimeException("CFFTP.rename: Missing the NEW attribute");
ftpCon.actionRename(getDynamic(_Session, "EXISTING").getString(), getDynamic(_Session, "NEW").getString());
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionPutFile(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("LOCALFILE"))
throw newRunTimeException("CFFTP.putfile: Missing the LOCALFILE attribute");
if (!containsAttribute("REMOTEFILE"))
throw newRunTimeException("CFFTP.putfile: Missing the REMOTEFILE attribute");
if (containsAttribute("PASSIVE"))
ftpCon.setPassive(getDynamic(_Session, "PASSIVE").getBoolean());
// ---[ Local File
File localFile;
if (getDynamic(_Session, "URIDIRECTORY").getBoolean())
localFile = FileUtils.getRealFile(_Session.REQ, getDynamic(_Session, "LOCALFILE").getString());
else
localFile = new File(getDynamic(_Session, "LOCALFILE").getString());
if (!localFile.isFile())
throw newRunTimeException("CFFTP.putfile: Local file, " + localFile.toString() + ", doesn't exist");
String transferMode = "AUTO";
if (containsAttribute("TRANSFERMODE"))
transferMode = getDynamic(_Session, "TRANSFERMODE").getString().toUpperCase();
if (transferMode.equals("AUTO"))
transferMode = determineTransferMode(localFile, getDynamic(_Session, "ASCIIEXTENSIONLIST"));
try {
ftpCon.actionPutFile(localFile, getDynamic(_Session, "REMOTEFILE").getString(), transferMode);
} catch (IOException e) {
throw newRunTimeException("CFFTP.putfile IOException: " + e.getMessage());
}
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionGetFile(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("REMOTEFILE"))
throw newRunTimeException("CFFTP.getFile: Missing the REMOTEFILE attribute");
if (!containsAttribute("LOCALFILE"))
throw newRunTimeException("CFFTP.getfile: Missing the LOCALFILE attribute");
if (containsAttribute("PASSIVE"))
ftpCon.setPassive(getDynamic(_Session, "PASSIVE").getBoolean());
// ---[ Local File
File localFile;
if (getDynamic(_Session, "URIDIRECTORY").getBoolean())
localFile = FileUtils.getRealFile(_Session.REQ, getDynamic(_Session, "LOCALFILE").getString());
else
localFile = new File(getDynamic(_Session, "LOCALFILE").getString());
boolean failIfExists = true;
if (containsAttribute("FAILIFEXISTS")) {
failIfExists = getDynamic(_Session, "FAILIFEXISTS").getBoolean();
}
if (failIfExists && localFile.isFile())
throw newRunTimeException("CFFTP.getfile: Local file, " + localFile.toString() + ", already exists");
String transferMode = "AUTO";
if (containsAttribute("TRANSFERMODE"))
transferMode = getDynamic(_Session, "TRANSFERMODE").getString().toUpperCase();
if (transferMode.equals("AUTO"))
transferMode = determineTransferMode(localFile, getDynamic(_Session, "ASCIIEXTENSIONLIST"));
try {
ftpCon.actionGetFile(localFile, getDynamic(_Session, "REMOTEFILE").getString(), transferMode);
} catch (IOException e) {
throw newRunTimeException("CFFTP.getFile IOException: " + e.getMessage());
}
}
// -----------------------------------------------------------------
// -----------------------------------------------------------------
private void actionListDir(cfSession _Session, cfFTPConnection ftpCon) throws cfmRunTimeException {
if (!containsAttribute("DIRECTORY"))
throw newRunTimeException("CFFTP.listDir: Missing the DIRECTORY attribute");
if (!containsAttribute("NAME"))
throw newRunTimeException("CFFTP.listDir: Missing the NAME attribute");
if (containsAttribute("PASSIVE"))
ftpCon.setPassive(getDynamic(_Session, "PASSIVE").getBoolean());
String name = getDynamic(_Session, "NAME").getString();
List<fileInfo> fileList;
try {
fileList = ftpCon.actionListDir(getDynamic(_Session, "DIRECTORY").getString());
} catch (IOException e) {
throw newRunTimeException("CFFTP.listDir IOException: " + e.getMessage());
}
cfQueryResultData queryFile = new cfQueryResultData(new String[] { "name", "path", "url", "length", "lastmodified", "attributes", "isdirectory", "mode" }, "CFFTP");
List<Map<String, cfData>> resultQuery = new ArrayList<Map<String, cfData>>(fileList.size());
Iterator<fileInfo> iter = fileList.iterator();
while (iter.hasNext()) {
fileInfo fI = iter.next();
Map<String, cfData> HM = new FastMap<String, cfData>();
HM.put("name", new cfStringData(fI.getName()));
HM.put("path", new cfStringData(fI.getPath()));
HM.put("url", new cfStringData("ftp://" + ftpCon.getServer() + fI.getPath()));
HM.put("length", new cfNumberData(fI.getLength()));
HM.put("lastmodified", new cfDateData(fI.getLastModified()));
HM.put("attributes", new cfStringData(fI.getAttributes()));
HM.put("isdirectory", cfBooleanData.getcfBooleanData(fI.isDirectory()));
HM.put("mode", new cfStringData(fI.getMode()));
resultQuery.add(HM);
}
// --[ Set the Query
queryFile.populateQuery(resultQuery);
_Session.setData(name, queryFile);
}
}