All pastes #746012 Raw Edit

Mine

public java v1 · immutable
·published 2007-10-22 21:48 UTC
rendered paste body
/* * This file is part of DrFTPD, Distributed FTP Daemon. * * DrFTPD 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 2 of the License, or (at your option) any later * version. * * DrFTPD 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 * DrFTPD; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA *///modifications used //identifier:regex - regex filterpackage net.sf.drftpd.master.command.plugins;import java.io.FileNotFoundException;import java.io.IOException;import java.io.PrintWriter;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;import java.net.UnknownHostException;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.ResourceBundle;import java.util.StringTokenizer;import javax.net.ServerSocketFactory;import javax.net.SocketFactory;import javax.net.ssl.HandshakeCompletedEvent;import javax.net.ssl.HandshakeCompletedListener;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSocket;import net.sf.drftpd.NoAvailableSlaveException;import net.sf.drftpd.NoSFVEntryException;import net.sf.drftpd.ObjectNotFoundException;import net.sf.drftpd.SlaveUnavailableException;import net.sf.drftpd.event.TransferEvent;import net.sf.drftpd.master.BaseFtpConnection;import net.sf.drftpd.master.FtpRequest;import net.sf.drftpd.master.command.CommandManager;import net.sf.drftpd.master.command.CommandManagerFactory;import net.sf.drftpd.master.config.ZipscriptConfig;import org.apache.log4j.Logger;import org.drftpd.ActiveConnection;import org.drftpd.Bytes;import org.drftpd.Checksum;import org.drftpd.PassiveConnection;import org.drftpd.SFVFile;import org.drftpd.SSLGetContext;import org.drftpd.commands.CommandHandler;import org.drftpd.commands.CommandHandlerFactory;import org.drftpd.commands.Reply;import org.drftpd.commands.ReplyException;import org.drftpd.commands.ReplySlaveUnavailableException;import org.drftpd.commands.UnhandledCommandException;import org.drftpd.commands.UserManagement;import org.drftpd.master.RemoteSlave;import org.drftpd.master.RemoteTransfer;import org.drftpd.remotefile.FileStillTransferringException;import org.drftpd.remotefile.LinkedRemoteFile;import org.drftpd.remotefile.LinkedRemoteFileInterface;import org.drftpd.remotefile.ListUtils;import org.drftpd.remotefile.StaticRemoteFile;import org.drftpd.slave.ConnectInfo;import org.drftpd.slave.Connection;import org.drftpd.slave.RemoteIOException;import org.drftpd.slave.Transfer;import org.drftpd.slave.TransferFailedException;import org.drftpd.slave.TransferStatus;import org.drftpd.usermanager.UserFileException;import org.tanesha.replacer.ReplacerEnvironment;import org.drftpd.SFVFile.SFVStatus;/** * @author mog * @author zubov * @version $Id: DataConnectionHandler.java 1593 2007-01-31 22:56:52Z zubov $ */public class DataConnectionHandler implements CommandHandler, CommandHandlerFactory,    Cloneable, HandshakeCompletedListener {    private static final Logger logger = Logger.getLogger(DataConnectionHandler.class);    private SSLContext _ctx;    private boolean _encryptedDataChannel;    private boolean _SSLHandshakeClientMode = false;    protected boolean _isPasv = false;    protected boolean _isPort = false;    /**     * Holds the address that getDataSocket() should connect to in PORT mode.     */    private InetSocketAddress _portAddress;    protected boolean _preTransfer = false;    private RemoteSlave _preTransferRSlave;    private long _resumePosition = 0;    private RemoteSlave _rslave;    /**     * ServerSocket for PASV mode.     */    private PassiveConnection _passiveConnection;    private RemoteTransfer _transfer;    private LinkedRemoteFileInterface _transferFile;    private char _type = 'A';	private boolean _handshakeCompleted;    public DataConnectionHandler() {        super();        _handshakeCompleted = false;        try {            _ctx = SSLGetContext.getSSLContext();        } catch (FileNotFoundException e) {        	_ctx = null;        	logger.warn("Couldn't load SSLContext, SSL/TLS disabled");        } catch (Exception e) {            _ctx = null;            logger.warn("Couldn't load SSLContext, SSL/TLS disabled", e);        }    }    private Reply doAUTH(BaseFtpConnection conn) {        if (_ctx == null) {            return new Reply(500, "TLS not configured");        }        Socket s = conn.getControlSocket();        //reply success        conn.getControlWriter().write(new Reply(234,                conn.getRequest().getCommandLine() + " successful").toString());        conn.getControlWriter().flush();        SSLSocket s2 = null;        try {            s2 = (SSLSocket) _ctx.getSocketFactory().createSocket(s,                    s.getInetAddress().getHostAddress(), s.getPort(), true);            conn.setControlSocket(s2);            s2.setUseClientMode(false);            s2.addHandshakeCompletedListener(this);            s2.startHandshake();            while(!_handshakeCompleted) {            	synchronized(this) {            		try {            			wait(10000);            		} catch (InterruptedException e) {            			s2.close();            			conn.stop("Took too long to negotiate SSL");            			return new Reply(400, "Took too long to negotiate SSL");            		}            	}            }            // reset for possible auth later            _handshakeCompleted = false;        } catch (IOException e) {            logger.warn("", e);            if (s2 != null) {            	try {            		s2.close();            	} catch (IOException e2){            		logger.debug("error closing SSLSocket connection");            	}            }            conn.stop(e.getMessage());            return null;		}        s2 = null;        return null;    }    /**     * <code>MODE &lt;SP&gt; <mode-code> &lt;CRLF&gt;</code><br>     *     * The argument is a single Telnet character code specifying the data     * transfer modes described in the Section on Transmission Modes.     */    private Reply doMODE(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        // argument check        if (!request.hasArgument()) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        if (request.getArgument().equalsIgnoreCase("S")) {            return Reply.RESPONSE_200_COMMAND_OK;        }        return Reply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;    }    /**     * <code>PASV &lt;CRLF&gt;</code><br>     *     * This command requests the server-DTP to "listen" on a data port (which is     * not its default data port) and to wait for a connection rather than     * initiate one upon receipt of a transfer command. The response to this     * command includes the host and port address this server is listening on.     */    private Reply doPASVandCPSV(BaseFtpConnection conn) {        if (!_preTransfer) {            return new Reply(500,                "You need to use a client supporting PRET (PRE Transfer) to use PASV");        }        //reset();        _preTransfer = false;        if (isPort() == true) {            throw new RuntimeException();        }                if (conn.getRequest().getCommand().equals("CPSV")) {        	_SSLHandshakeClientMode=true;        }        InetSocketAddress address = null;        if (_preTransferRSlave == null) {            try {				_passiveConnection = new PassiveConnection(_encryptedDataChannel ? _ctx : null, conn.getGlobalContext().getPortRange(), false);                try {					address = new InetSocketAddress(conn.getGlobalContext()							.getConfig().getPasvAddress(), _passiveConnection							.getLocalPort());				} catch (NullPointerException e) {					address = new InetSocketAddress(conn.getControlSocket()							.getLocalAddress(), _passiveConnection.getLocalPort());				}            _isPasv = true;            } catch (Exception ex) {                logger.warn("", ex);                return new Reply(550, ex.getMessage());            }        } else {            try {                String index = _preTransferRSlave.issueListenToSlave(_encryptedDataChannel, _SSLHandshakeClientMode);                ConnectInfo ci = _preTransferRSlave.fetchTransferResponseFromIndex(index);                _transfer = _preTransferRSlave.getTransfer(ci.getTransferIndex());                address = new InetSocketAddress(_preTransferRSlave.getPASVIP(),_transfer.getAddress().getPort());                _isPasv = true;            } catch (SlaveUnavailableException e) {            	reset(conn);                return Reply.RESPONSE_530_SLAVE_UNAVAILABLE;            } catch (RemoteIOException e) {            	reset(conn);                _preTransferRSlave.setOffline(                    "Slave could not listen for a connection");                logger.error("Slave could not listen for a connection", e);                return new Reply(500,                    "Slave could not listen for a connection");            }        }                if (conn.getRequest().getCommand().equals("CPSV")) {        	// can only reset it if the transfer was setup with CPSV        	_SSLHandshakeClientMode = false;        }        if (address.getAddress() == null || address.getAddress().getHostAddress() == null) {        	return new Reply(500, "Address for is unresolvable, check pasv_addr setting");        }                String addrStr = address.getAddress().getHostAddress().replace('.', ',') +            ',' + (address.getPort() >> 8) + ',' + (address.getPort() & 0xFF);        return new Reply(227, "Entering Passive Mode (" + addrStr + ").");    }    private Reply doPBSZ(BaseFtpConnection conn)        throws UnhandledCommandException {        String cmd = conn.getRequest().getArgument();        if ((cmd == null) || !cmd.equals("0")) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        return Reply.RESPONSE_200_COMMAND_OK;    }    /**     * <code>PORT &lt;SP&gt; <host-port> &lt;CRLF&gt;</code><br>     *     * The argument is a HOST-PORT specification for the data port to be used in     * data connection. There are defaults for both the user and server data     * ports, and under normal circumstances this command and its reply are not     * needed. If this command is used, the argument is the concatenation of a     * 32-bit internet host address and a 16-bit TCP port address. This address     * information is broken into 8-bit fields and the value of each field is     * transmitted as a decimal number (in character string representation). The     * fields are separated by commas. A port command would be:     *     * PORT h1,h2,h3,h4,p1,p2     *     * where h1 is the high order 8 bits of the internet host address.     */    private Reply doPORT(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        reset(conn);        InetAddress clientAddr = null;        // argument check        if (!request.hasArgument()) {            //Syntax error in parameters or arguments            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        StringTokenizer st = new StringTokenizer(request.getArgument(), ",");        if (st.countTokens() != 6) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        // get data server        String dataSrvName = st.nextToken() + '.' + st.nextToken() + '.' +            st.nextToken() + '.' + st.nextToken();        try {            clientAddr = InetAddress.getByName(dataSrvName);        } catch (UnknownHostException ex) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        String portHostAddress = clientAddr.getHostAddress();        String clientHostAddress = conn.getControlSocket().getInetAddress()                                       .getHostAddress();        if ((portHostAddress.startsWith("192.168.") &&                !clientHostAddress.startsWith("192.168.")) ||                (portHostAddress.startsWith("10.") &&                !clientHostAddress.startsWith("10."))) {            Reply response = new Reply(501);            response.addComment("==YOU'RE BEHIND A NAT ROUTER==");            response.addComment(                "Configure the firewall settings of your FTP client");            response.addComment("  to use your real IP: " +                conn.getControlSocket().getInetAddress().getHostAddress());            response.addComment("And set up port forwarding in your router.");            response.addComment(                "Or you can just use a PRET capable client, see");            response.addComment("  http://drftpd.org/ for PRET capable clients");            return response;        }        int clientPort;        // get data server port        try {            int hi = Integer.parseInt(st.nextToken());            int lo = Integer.parseInt(st.nextToken());            clientPort = (hi << 8) | lo;        } catch (NumberFormatException ex) {        	reset(conn);            return Reply.RESPONSE_501_SYNTAX_ERROR;            //out.write(ftpStatus.getResponse(552, request, user, null));        }        _isPort = true;        _portAddress = new InetSocketAddress(clientAddr, clientPort);        if (portHostAddress.startsWith("127.")) {            return new Reply(200,                "Ok, but distributed transfers won't work with local addresses");        }        //Notify the user that this is not his IP.. Good for NAT users that        // aren't aware that their IP has changed.        if (!clientAddr.equals(conn.getControlSocket().getInetAddress())) {            return new Reply(200,                "FXP allowed. If you're not FXPing then set your IP to " +                conn.getControlSocket().getInetAddress().getHostAddress() +                " (usually in firewall settings)");        }        return Reply.RESPONSE_200_COMMAND_OK;    }    private Reply doPRET(BaseFtpConnection conn) {        reset(conn);        FtpRequest request = conn.getRequest();        FtpRequest ghostRequest = new FtpRequest(request.getArgument());        String cmd = ghostRequest.getCommand();        if (cmd.equals("LIST") || cmd.equals("NLST") || cmd.equals("MLSD")) {            _preTransferRSlave = null;            _preTransfer = true;            return new Reply(200, "OK, will use master for upcoming transfer");        } else if (cmd.equals("RETR")) {            try {                LinkedRemoteFileInterface downFile = conn.getCurrentDirectory()                                                         .lookupFile(ghostRequest.getArgument());                _preTransferRSlave = conn.getGlobalContext().getSlaveSelectionManager().getASlave(downFile.getAvailableSlaves(),                        Transfer.TRANSFER_SENDING_DOWNLOAD, conn, downFile);                _preTransfer = true;                return new Reply(200,                    "OK, will use " + _preTransferRSlave.getName() +                    " for upcoming transfer");            } catch (NoAvailableSlaveException e) {                return Reply.RESPONSE_530_SLAVE_UNAVAILABLE;            } catch (FileNotFoundException e) {                return Reply.RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN;            }        } else if (cmd.equals("STOR")) {            LinkedRemoteFile.NonExistingFile nef = conn.getCurrentDirectory()                                                       .lookupNonExistingFile(ghostRequest.getArgument());            if (nef.exists()) {                return Reply.RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN_FILE_EXISTS;            }            if (!ListUtils.isLegalFileName(nef.getPath())) {                return Reply.RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN;            }            try {                _preTransferRSlave = conn.getGlobalContext().getSlaveSelectionManager().getASlave(conn.getGlobalContext()                                                                                   .getSlaveManager()                                                                                   .getAvailableSlaves(),                        Transfer.TRANSFER_RECEIVING_UPLOAD, conn,                        nef.getFile());                _preTransfer = true;                return new Reply(200,                    "OK, will use " + _preTransferRSlave.getName() +                    " for upcoming transfer");            } catch (NoAvailableSlaveException e) {                return Reply.RESPONSE_530_SLAVE_UNAVAILABLE;            }        } else {            return Reply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;        }    }        private Reply doSSCN(BaseFtpConnection conn) {        if (_ctx == null) {            return new Reply(500, "TLS not configured");        }                if (!(conn.getControlSocket() instanceof SSLSocket)) {        	return new Reply(500, "You are not on a secure channel");        }                if (!_encryptedDataChannel) {        	return new Reply(500, "SSCN only works for encrypted transfers");        }        		if (conn.getRequest().hasArgument()) {			if (conn.getRequest().getArgument().equalsIgnoreCase("ON")) {				_SSLHandshakeClientMode = true;			}			if (conn.getRequest().getArgument().equalsIgnoreCase("OFF")) {				_SSLHandshakeClientMode = false;			}		}		return new Reply(220, "SSCN:"				+ (_SSLHandshakeClientMode ? "CLIENT" : "SERVER") + " METHOD");	}    private Reply doPROT(BaseFtpConnection conn)        throws UnhandledCommandException {        if (_ctx == null) {            return new Reply(500, "TLS not configured");        }                if (!(conn.getControlSocket() instanceof SSLSocket)) {        	return new Reply(500, "You are not on a secure channel");        }        FtpRequest req = conn.getRequest();        if (!req.hasArgument()) {            //clear            _encryptedDataChannel = false;            return Reply.RESPONSE_200_COMMAND_OK;        }        if (!req.hasArgument() || (req.getArgument().length() != 1)) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        switch (Character.toUpperCase(req.getArgument().charAt(0))) {        case 'C':            //clear            _encryptedDataChannel = false;            return Reply.RESPONSE_200_COMMAND_OK;        case 'P':            //private            _encryptedDataChannel = true;            return Reply.RESPONSE_200_COMMAND_OK;        default:            return Reply.RESPONSE_501_SYNTAX_ERROR;        }    }    /**     * <code>REST &lt;SP&gt; <marker> &lt;CRLF&gt;</code><br>     *     * The argument field represents the server marker at which file transfer is     * to be restarted. This command does not cause file transfer but skips over     * the file to the specified data checkpoint. This command shall be     * immediately followed by the appropriate FTP service command which shall     * cause file transfer to resume.     */    private Reply doREST(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        // argument check        if (!request.hasArgument()) {        	reset(conn);            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        String skipNum = request.getArgument();        try {            _resumePosition = Long.parseLong(skipNum);        } catch (NumberFormatException ex) {        	reset(conn);            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        if (_resumePosition < 0) {            _resumePosition = 0;            reset(conn);            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        return Reply.RESPONSE_350_PENDING_FURTHER_INFORMATION;    }    private Reply doSITE_RESCAN(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        boolean forceRescan = (request.hasArgument() &&            request.getArgument().equalsIgnoreCase("force"));        LinkedRemoteFileInterface directory = conn.getCurrentDirectory();        SFVFile sfv;        try {            sfv = conn.getCurrentDirectory().lookupSFVFile();        } catch (Exception e) {            return new Reply(200, "Error getting SFV File: " +                e.getMessage());        }        PrintWriter out = conn.getControlWriter();        for (Iterator i = sfv.getEntries().entrySet().iterator(); i.hasNext();) {            Map.Entry entry = (Map.Entry) i.next();            String fileName = (String) entry.getKey();            Long checkSum = (Long) entry.getValue();            LinkedRemoteFileInterface file;            try {                file = directory.lookupFile(fileName);            } catch (FileNotFoundException ex) {                out.write("200- SFV: " +                    Checksum.formatChecksum(checkSum.longValue()) + " SLAVE: " +                    fileName + " MISSING" + BaseFtpConnection.NEWLINE);                continue;            }            String status;            long fileCheckSum = 0;            try {                if (forceRescan) {                    fileCheckSum = file.getCheckSumFromSlave();                } else {                    fileCheckSum = file.getCheckSum();                }            } catch (NoAvailableSlaveException e1) {                out.println("200- " + fileName + "SFV: " +                    Checksum.formatChecksum(checkSum.longValue()) +                    " SLAVE: OFFLINE");                continue;            } catch (IOException ex) {                out.print("200- " + fileName + " SFV: " +                    Checksum.formatChecksum(checkSum.longValue()) +                    " SLAVE: IO error: " + ex.getMessage());                continue;            }            if (fileCheckSum == 0L) {                status = "FAILED - failed to checksum file";            } else if (checkSum.longValue() == fileCheckSum) {                status = "OK";            } else {                status = "FAILED - checksum mismatch";            }            out.println("200- " + fileName + " SFV: " +                Checksum.formatChecksum(checkSum.longValue()) + " SLAVE: " +                Checksum.formatChecksum(fileCheckSum) + " " + status);            continue;        }        return Reply.RESPONSE_200_COMMAND_OK;    }    private Reply doSITE_XDUPE(BaseFtpConnection conn) {        return Reply.RESPONSE_502_COMMAND_NOT_IMPLEMENTED;        //		resetState();        //        //		if (!request.hasArgument()) {        //			if (this.xdupe == 0) {        //				out.println("200 Extended dupe mode is disabled.");        //			} else {        //				out.println(        //					"200 Extended dupe mode " + this.xdupe + " is enabled.");        //			}        //			return;        //		}        //        //		short myXdupe;        //		try {        //			myXdupe = Short.parseShort(request.getArgument());        //		} catch (NumberFormatException ex) {        //			out.print(FtpResponse.RESPONSE_501_SYNTAX_ERROR);        //			return;        //		}        //        //		if (myXdupe > 0 || myXdupe < 4) {        //			out.print(        //				FtpResponse.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM);        //			return;        //		}        //		this.xdupe = myXdupe;        //		out.println("200 Activated extended dupe mode " + myXdupe + ".");    }    /**     * <code>STRU &lt;SP&gt; &lt;structure-code&gt; &lt;CRLF&gt;</code><br>     *     * The argument is a single Telnet character code specifying file structure.     */    private Reply doSTRU(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        // argument check        if (!request.hasArgument()) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        if (request.getArgument().equalsIgnoreCase("F")) {            return Reply.RESPONSE_200_COMMAND_OK;        }        return Reply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;    }    /**     * <code>SYST &lt;CRLF&gt;</code><br>     *     * This command is used to find out the type of operating system at the     * server.     */    private Reply doSYST(BaseFtpConnection conn) {        /*         * String systemName = System.getProperty("os.name"); if(systemName ==         * null) { systemName = "UNKNOWN"; } else { systemName =         * systemName.toUpperCase(); systemName = systemName.replace(' ', '-'); }         * String args[] = {systemName};         */        return Reply.RESPONSE_215_SYSTEM_TYPE;        //String args[] = { "UNIX" };        //out.write(ftpStatus.getResponse(215, request, user, args));    }    /**     * <code>TYPE &lt;SP&gt; &lt;type-code&gt; &lt;CRLF&gt;</code><br>     *     * The argument specifies the representation type.     */    private Reply doTYPE(BaseFtpConnection conn) {        FtpRequest request = conn.getRequest();        // get type from argument        if (!request.hasArgument()) {            return Reply.RESPONSE_501_SYNTAX_ERROR;        }        // set it        if (setType(request.getArgument().charAt(0))) {            return Reply.RESPONSE_200_COMMAND_OK;        }        return Reply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM;    }    public Reply execute(BaseFtpConnection conn)        throws ReplyException {        String cmd = conn.getRequest().getCommand();                     if ("MODE".equals(cmd)) {            return doMODE(conn);        }        if ("PASV".equals(cmd) || "CPSV".equals(cmd)) {            return doPASVandCPSV(conn);        }        if ("PORT".equals(cmd)) {            return doPORT(conn);        }        if ("PRET".equals(cmd)) {            return doPRET(conn);        }        if ("REST".equals(cmd)) {            return doREST(conn);        }        if ("RETR".equals(cmd) || "STOR".equals(cmd) || "APPE".equals(cmd)) {            return transfer(conn);        }        if ("SITE RESCAN".equals(cmd)) {            return doSITE_RESCAN(conn);        }        if ("SITE XDUPE".equals(cmd)) {            return doSITE_XDUPE(conn);        }        if ("STRU".equals(cmd)) {            return doSTRU(conn);        }        if ("SYST".equals(cmd)) {            return doSYST(conn);        }        if ("TYPE".equals(cmd)) {            return doTYPE(conn);        }        if ("AUTH".equals(cmd)) {            return doAUTH(conn);        }        if ("PROT".equals(cmd)) {            return doPROT(conn);        }        if ("PBSZ".equals(cmd)) {            return doPBSZ(conn);        }                if ("SSCN".equals(cmd)) {        	return doSSCN(conn);        }        throw UnhandledCommandException.create(DataConnectionHandler.class,            conn.getRequest());    }    /**     * Get the data socket.     *     * Used by LIST and NLST and MLST.     */    public Socket getDataSocket() throws IOException {        Socket dataSocket;        // get socket depending on the selection        if (isPort()) {            try {				ActiveConnection ac = new ActiveConnection(_encryptedDataChannel ? _ctx : null, _portAddress, _SSLHandshakeClientMode);                dataSocket = ac.connect(0);            } catch (IOException ex) {                logger.warn("Error opening data socket", ex);                dataSocket = null;                throw ex;            }        } else if (isPasv()) {            try {                dataSocket = _passiveConnection.connect(0);            } finally {				if (_passiveConnection != null) {					_passiveConnection.abort();	                _passiveConnection = null;				}            }        } else {            throw new IllegalStateException("Neither PASV nor PORT");        }		// Already done since we are using ActiveConnection and PasvConnection/*        dataSocket.setSoTimeout(Connection.TIMEOUT); // 15 seconds timeout        if (dataSocket instanceof SSLSocket) {            SSLSocket ssldatasocket = (SSLSocket) dataSocket;            ssldatasocket.setUseClientMode(false);            ssldatasocket.startHandshake();        }*/        return dataSocket;    }    public String[] getFeatReplies() {        if (_ctx != null) {            return new String[] { "PRET", "AUTH SSL", "PBSZ", "CPSV" , "SSCN"};        }        return new String[] { "PRET" };    }        public String getHelp(String cmd) {        ResourceBundle bundle = ResourceBundle.getBundle(DataConnectionHandler.class.getName());        if ("".equals(cmd))            return bundle.getString("help.general")+"\n";        else if("rescan".equals(cmd))            return bundle.getString("help.rescan")+"\n";        else            return "";    }    public RemoteSlave getTranferSlave() {        return _rslave;    }    public synchronized RemoteTransfer getTransfer() throws ObjectNotFoundException {        if (_transfer == null)            throw new ObjectNotFoundException();        return _transfer;    }    public LinkedRemoteFileInterface getTransferFile() {        return _transferFile;    }    /**     * Get the user data type.     */    public char getType() {        return _type;    }    public CommandHandler initialize(BaseFtpConnection conn,        CommandManager initializer) {        try {            return (DataConnectionHandler) clone();        } catch (CloneNotSupportedException e) {            throw new RuntimeException(e);        }    }    public boolean isEncryptedDataChannel() {        return _encryptedDataChannel;    }    /**     * Guarantes pre transfer is set up correctly.     */    public boolean isPasv() {        return _isPasv;    }    public boolean isPort() {        return _isPort;    }    public boolean isPreTransfer() {        return _preTransfer || isPasv();    }    public synchronized boolean isTransfering() {		return _transfer != null && _rslave != null && _transferFile != null;	}    public void load(CommandManagerFactory initializer) {    }    protected synchronized void reset(BaseFtpConnection conn) {        _rslave = null;        if (_transfer != null) {        	try {        		_transfer.abort("reset");        	} catch (Throwable t) {        		logger.debug("reset failed to abort transfer on the slave", t);        	}        }        _transfer = null;        if (_transferFile != null) {        	if ((conn.getRequest().getCommand().equals("STOR") == true) &&                    (_transferFile.getXfertime() == -1)) {                        // Transfer failed on STOR        		_transferFile.setXfertime(0);        	}        	_transferFile = null;        }        _preTransfer = false;        _preTransferRSlave = null;        if (_passiveConnection != null) { //isPasv() && _preTransferRSlave == null            _passiveConnection.abort();        }        _isPasv = false;        _passiveConnection = null;        _isPort = false;        _resumePosition = 0;    }    /**     * Set the data type. Supported types are A (ascii) and I (binary).     *     * @return true if success     */    private boolean setType(char type) {        type = Character.toUpperCase(type);        if ((type != 'A') && (type != 'I')) {            return false;        }        _type = type;        return true;    }    /**     * <code>STOU &lt;CRLF&gt;</code><br>     *     * This command behaves like STOR except that the resultant file is to be     * created in the current directory under a name unique to that directory.     * The 250 Transfer Started response must include the name generated.     */    //TODO STOU    /*     * public void doSTOU(FtpRequest request, PrintWriter out) {     *  // reset state variables resetState();     *  // get filenames String fileName =     * user.getVirtualDirectory().getAbsoluteName("ftp.dat"); String     * physicalName = user.getVirtualDirectory().getPhysicalName(fileName); File     * requestedFile = new File(physicalName); requestedFile =     * IoUtils.getUniqueFile(requestedFile); fileName =     * user.getVirtualDirectory().getVirtualName(requestedFile.getAbsolutePath());     * String args[] = {fileName};     *  // check permission     * if(!user.getVirtualDirectory().hasCreatePermission(fileName, false)) {     * out.write(ftpStatus.getResponse(550, request, user, null)); return; }     *  // now transfer file data out.print(FtpResponse.RESPONSE_150_OK);     * InputStream is = null; OutputStream os = null; try { Socket dataSoc =     * mDataConnection.getDataSocket(); if (dataSoc == null) {     * out.write(ftpStatus.getResponse(550, request, user, args)); return; }     *     *     * is = dataSoc.getInputStream(); os = user.getOutputStream( new     * FileOutputStream(requestedFile) );     *     * StreamConnector msc = new StreamConnector(is, os);     * msc.setMaxTransferRate(user.getMaxUploadRate()); msc.setObserver(this);     * msc.connect();     *     * if(msc.hasException()) { out.write(ftpStatus.getResponse(451, request,     * user, null)); return; } else {     * mConfig.getStatistics().setUpload(requestedFile, user,     * msc.getTransferredSize()); }     *     * out.write(ftpStatus.getResponse(226, request, user, null));     * mDataConnection.reset(); out.write(ftpStatus.getResponse(250, request,     * user, args)); } catch(IOException ex) {     * out.write(ftpStatus.getResponse(425, request, user, null)); } finally {     * IoUtils.close(is); IoUtils.close(os); mDataConnection.reset(); } }     */    /**     * <code>RETR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>     *     * This command causes the server-DTP to transfer a copy of the file,     * specified in the pathname, to the server- or user-DTP at the other end of     * the data connection. The status and contents of the file at the server     * site shall be unaffected.     *     * RETR 125, 150 (110) 226, 250 425, 426, 451 450, 550 500, 501, 421, 530     * <p>     * <code>STOR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>     *     * This command causes the server-DTP to accept the data transferred via the     * data connection and to store the data as a file at the server site. If     * the file specified in the pathname exists at the server site, then its     * contents shall be replaced by the data being transferred. A new file is     * created at the server site if the file specified in the pathname does not     * already exist.     *     * STOR 125, 150 (110) 226, 250 425, 426, 451, 551, 552 532, 450, 452, 553     * 500, 501, 421, 530     *     * ''zipscript?? renames bad uploads to .bad, how do we handle this with     * resumes?     */    //TODO add APPE support    private Reply transfer(BaseFtpConnection conn)        throws ReplyException {        ReplacerEnvironment env = new ReplacerEnvironment();        if (!_encryptedDataChannel &&                conn.getGlobalContext().getConfig().checkPermission("denydatauncrypted", conn.getUserNull())) {        	reset(conn);            return new Reply(530, "USE SECURE DATA CONNECTION");        }        try {            FtpRequest request = conn.getRequest();            char direction = conn.getDirection();            String cmd = conn.getRequest().getCommand();            boolean isStor = cmd.equals("STOR");            boolean isRetr = cmd.equals("RETR");            boolean isAppe = cmd.equals("APPE");            boolean isStou = cmd.equals("STOU");            String eventType = isRetr ? "RETR" : "STOR";            if (isAppe || isStou) {                throw UnhandledCommandException.create(DataConnectionHandler.class,                    conn.getRequest());            }            // argument check            if (!request.hasArgument()) {            	// reset(); already done in finally block                return Reply.RESPONSE_501_SYNTAX_ERROR;            }            //          Checks maxsim up/down            // _simup OR _simdown = 0, exempt            int comparison = 0;            int count = conn.transferCounter(direction);            env.add("maxsim", count);            if (direction == Transfer.TRANSFER_RECEIVING_UPLOAD) {            	comparison =  conn.getUserNull().getMaxSimUp();                env.add("direction", "upload");            } else {            	comparison =  conn.getUserNull().getMaxSimDown();                env.add("direction", "download");            }            if (comparison != 0 && count >= comparison)            	return new Reply(550, conn.jprintf(DataConnectionHandler.class, "transfer.err.maxsim", env));                        // get filenames            LinkedRemoteFileInterface targetDir;            String targetFileName;            if (isRetr) {                try {                    _transferFile = conn.getCurrentDirectory().lookupFile(request.getArgument());                    if (!_transferFile.isFile()) {                    	// reset(); already done in finally block                        return new Reply(550, "Not a plain file");                    }                    targetDir = _transferFile.getParentFileNull();                    targetFileName = _transferFile.getName();                } catch (FileNotFoundException ex) {                	// reset(); already done in finally block                    return new Reply(550, ex.getMessage());                }            } else if (isStor) {                LinkedRemoteFile.NonExistingFile ret = conn.getCurrentDirectory()                                                           .lookupNonExistingFile(conn.getGlobalContext()                                                                                      .getConfig()                                                                                      .getFileName(request.getArgument()));                targetDir = ret.getFile();                targetFileName = ret.getPath();                if (ret.exists()) {                    // target exists, this could be overwrite or resume                    //TODO overwrite & resume files.                	// reset(); already done in finally block                    return Reply.RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN_FILE_EXISTS;                    //_transferFile = targetDir;                    //targetDir = _transferFile.getParent();                    //if(_transfereFile.getOwner().equals(getUser().getUsername()))                    // {                    //	// allow overwrite/resume                    //}                    //if(directory.isDirectory()) {                    //	return FtpReply.RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN;                    //}                }                if(!conn.getGlobalContext().getCheckConfig().checkAllowedFilename(conn.getUserNull(), ret)) {                	return new Reply(553, "Upload file denied - Due to Regexp configuration");                }				                if (!ListUtils.isLegalFileName(targetFileName) ||                        !conn.getGlobalContext().getConfig().checkPathPermission("privpath", conn.getUserNull(), targetDir, true)) {                	// reset(); already done in finally block                    return new Reply(553,                        "Requested action not taken. File name not allowed.");                }                //do our zipscript sfv checks                String checkName = targetFileName.toLowerCase();                ZipscriptConfig zsCfg = conn.getGlobalContext().getZsConfig();                boolean SfvFirstEnforcedPath = zsCfg.checkSfvFirstEnforcedPath(targetDir,                 		conn.getUserNull());                 try {                    SFVFile sfv;					try {						sfv = conn.getCurrentDirectory().lookupSFVFile();					} catch (FileStillTransferringException e) {						// I have no idea how to handle this						return new Reply(400, "SFVFile still transferring.");					}                    if (checkName.endsWith(".sfv") &&                     	!zsCfg.multiSfvAllowed()) {                        return new Reply(533,                        	"Requested action not taken. Multiple SFV files not allowed.");                    }                    if (SfvFirstEnforcedPath &&                     		!zsCfg.checkAllowedExtension(checkName)) {                		// filename not explicitly permitted, check for sfv entry                        boolean allow = false;                        if (zsCfg.restrictSfvEnabled()) {                            for (Iterator iter = sfv.getNames().iterator(); iter.hasNext();) {                                String name = (String) iter.next();                                if (name.toLowerCase().equals(checkName)) {                                    allow = true;                                    break;                                }                            }                            if (!allow) {                                return new Reply(533,                                	"Requested action not taken. File not found in sfv.");                            }                        }                    }                } catch (FileNotFoundException e1) {                    // no sfv found in dir                 	if(checkName.endsWith(".sfv") && SfvFirstEnforcedPath && conn.getGlobalContext().getCheckConfig().checkSfvDenyUpload(targetDir)) { //identifier:regex                		return new Reply(533, "Requested action not taken. SFV not allowed due to subdir");                	}					                	if ( !zsCfg.checkAllowedExtension(checkName) &&                 			SfvFirstEnforcedPath ) {                		// filename not explicitly permitted                		// ForceSfvFirst is on, and file is in an enforced path.                        return new Reply(533,                        	"Requested action not taken. You must upload sfv first.");                	}                } catch (IOException e1) {                    //error reading sfv, do nothing                } catch (NoAvailableSlaveException e1) {                    //sfv not online, do nothing                }            } else {            	// reset(); already done in finally block            	throw UnhandledCommandException.create(            			DataConnectionHandler.class, request);            }            // check access            if (!conn.getGlobalContext().getConfig().checkPathPermission("privpath", conn.getUserNull(), targetDir, true)) {            	// reset(); already done in finally block                return new Reply(550,                    request.getArgument() + ": No such file");            }            switch (direction) {            case Transfer.TRANSFER_SENDING_DOWNLOAD:                if (!conn.getGlobalContext().getConfig().checkPathPermission("download", conn.getUserNull(), targetDir)) {                	// reset(); already done in finally block                    return Reply.RESPONSE_530_ACCESS_DENIED;                }                break;            case Transfer.TRANSFER_RECEIVING_UPLOAD:                if (!conn.getGlobalContext().getConfig().checkPathPermission("upload", conn.getUserNull(), targetDir)) {                	// reset(); already done in finally block                    return Reply.RESPONSE_530_ACCESS_DENIED;                }                break;            default:            	// reset(); already done in finally block                throw UnhandledCommandException.create(DataConnectionHandler.class,                    request);            }            //check credits            if (isRetr) {                if ((conn.getUserNull().getKeyedMap().getObjectFloat(                        UserManagement.RATIO) != 0)                        && (conn.getGlobalContext().getConfig()                                .getCreditLossRatio(_transferFile,                                        conn.getUserNull()) != 0)                        && (conn.getUserNull().getCredits() < _transferFile                                .length())) {                	// reset(); already done in finally block                    return new Reply(550, "Not enough credits.");                }            }            //setup _rslave            //if (isCpsv)            if (isPasv()) {                //				isPasv() means we're setup correctly                //				if (!_preTransfer || _preTransferRSlave == null)                //					return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;                //check pretransfer                if (isRetr &&                        !_transferFile.getSlaves().contains(_preTransferRSlave)) {                	// reset(); already done in finally block                    return Reply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;                }                _rslave = _preTransferRSlave;                //_preTransferRSlave = null;                //_preTransfer = false;                //code above to be handled by reset()            } else {                try {                    if (direction == Transfer.TRANSFER_SENDING_DOWNLOAD) {                        _rslave = conn.getGlobalContext().getSlaveSelectionManager().getASlave(_transferFile.getAvailableSlaves(),                                Transfer.TRANSFER_SENDING_DOWNLOAD, conn,                                _transferFile);                    } else if (direction == Transfer.TRANSFER_RECEIVING_UPLOAD) {                        _rslave = conn.getGlobalContext().getSlaveSelectionManager().getASlave(conn.getGlobalContext()                                                                                .getSlaveManager()                                                                                .getAvailableSlaves(),                                Transfer.TRANSFER_RECEIVING_UPLOAD, conn,                                targetDir);                    } else {                    	// reset(); already done in finally block                        throw new RuntimeException();                    }                } catch (NoAvailableSlaveException ex) {                	//TODO Might not be good to 450 reply always                	//from rfc: 450 Requested file action not taken. File unavailable (e.g., file busy).                	// reset(); already done in finally block                	throw new ReplySlaveUnavailableException(ex, 450);                }            }			/*            if(!conn.getGlobalContext().getTraficSlave().checkSlave(_rslave)) {              	return new Reply(553, "File upload denied - trafic limit has been reached on this slave");            }*/            if (isStor) {                //setup upload                if (_rslave == null) {                	// reset(); already done in finally block                    throw new NullPointerException();                }                List rslaves = Collections.singletonList(_rslave);                StaticRemoteFile uploadFile = new StaticRemoteFile(rslaves,                        targetFileName, conn.getUserNull().getName(),                        conn.getUserNull().getGroup(), 0L,                        System.currentTimeMillis(), 0L);                synchronized (this) {                	uploadFile.setXfertime(-1); // used for new files to be                								   // uploaded, see getXfertime()                	_transferFile = targetDir.addFile(uploadFile);                }            }            // setup _transfer            if (isPort()) {                try {                    String index = _rslave.issueConnectToSlave(_portAddress							.getAddress().getHostAddress(), _portAddress							.getPort(), _encryptedDataChannel, _SSLHandshakeClientMode);                    ConnectInfo ci = _rslave.fetchTransferResponseFromIndex(index);                    synchronized (this) {                    	_transfer = _rslave.getTransfer(ci.getTransferIndex());                    }                } catch (Exception ex) {                    logger.fatal("rslave=" + _rslave, ex);                	// reset(); already done in finally block                    return new Reply(450,                        ex.getClass().getName() + " from slave: " +                        ex.getMessage());                }            } else if (isPasv()) {                //_transfer is already set up by doPASV()            } else {            	// reset(); already done in finally block            	if (isStor) {            		_transferFile.delete();            	}                return Reply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS;            }            {                PrintWriter out = conn.getControlWriter();                out.write(new Reply(150,                        "File status okay; about to open data connection " +                        (isRetr ? "from " : "to ") + _rslave.getName() + ".").toString());                out.flush();            }            TransferStatus status = null;            //transfer            try {                //TODO ABORtable transfers                if (isRetr) {                    _transfer.sendFile(_transferFile.getPath(), getType(),                        _resumePosition);                    while (true) {                        status = _transfer.getTransferStatus();                        if (status.isFinished()) {                            break;                        }                        try {                            Thread.sleep(100);                        } catch (InterruptedException e1) {                        }                    }                } else if (isStor) {                    _transfer.receiveFile(_transferFile.getPath(), getType(),                        _resumePosition);                    while (true) {                        status = _transfer.getTransferStatus();                        _transferFile.setLength(status.getTransfered());                        if (status.isFinished()) {                            break;                        }                        try {                            Thread.sleep(100);                        } catch (InterruptedException e1) {                        }                    }                } else {                    throw new RuntimeException();                }            } catch (IOException ex) {            	logger.debug("", ex);                if (ex instanceof TransferFailedException) {                	// the below chunk makes no sense, we don't process it anywhere/*                    status = ((TransferFailedException) ex).getStatus();                    conn.getGlobalContext()                        .dispatchFtpEvent(new TransferEvent(conn, eventType,                            _transferFile, conn.getClientAddress(), _rslave,                            _transfer.getAddress().getAddress(), _type, false));*/                    if (isRetr) {                        conn.getUserNull().updateCredits(-status.getTransfered());                    }                }                Reply reply = null;                if (isStor) {                    _transferFile.delete();                    logger.error("IOException during transfer, deleting file",                        ex);                    reply = new Reply(426, "Transfer failed, deleting file");                } else {                    logger.error("IOException during transfer", ex);                    reply = new Reply(426, ex.getMessage());                }                                reply.addComment(ex.getMessage());            	// reset(); already done in finally block                return reply;            } catch (SlaveUnavailableException e) {            	logger.debug("", e);                Reply reply = null;                if (isStor) {                    _transferFile.delete();                    logger.error("Slave went offline during transfer, deleting file",                        e);                    reply = new Reply(426,                            "Slave went offline during transfer, deleting file");                } else {                    logger.error("Slave went offline during transfer", e);                    reply = new Reply(426,                            "Slave went offline during transfer");                }                reply.addComment(e.getLocalizedMessage());            	// reset(); already done in finally block                return reply;            }            //		TransferThread transferThread = new TransferThread(rslave,            // transfer);            //		System.err.println("Calling interruptibleSleepUntilFinished");            //		try {            //			transferThread.interruptibleSleepUntilFinished();            //		} catch (Throwable e1) {            //			e1.printStackTrace();            //		}            //		System.err.println("Finished");            env = new ReplacerEnvironment();            env.add("bytes", Bytes.formatBytes(status.getTransfered()));            env.add("speed", Bytes.formatBytes(status.getXferSpeed()) + "/s");            env.add("seconds", "" + ((float)status.getElapsed() / 1000F));            env.add("checksum", Checksum.formatChecksum(status.getChecksum()));            Reply response = new Reply(226,                    conn.jprintf(DataConnectionHandler.class,                        "transfer.complete", env));            synchronized (conn.getGlobalContext()) { // need to synchronize														// here so only one				// TransferEvent can be sent at a time				if (isStor) {					if (_resumePosition == 0) {						_transferFile.setCheckSum(status.getChecksum());					} else {						// try {						// checksum = _transferFile.getCheckSumFromSlave();						// } catch (NoAvailableSlaveException e) {						// response.addComment(						// "No available slaves when getting checksum from						// slave: "						// + e.getMessage());						// logger.warn("", e);						// checksum = 0;						// } catch (IOException e) {						// response.addComment(						// "IO error getting checksum from slave: "						// + e.getMessage());						// logger.warn("", e);						// checksum = 0;						// }					}					_transferFile.setLastModified(System.currentTimeMillis());					_transferFile.setLength(status.getTransfered());					_transferFile.setXfertime(status.getElapsed());				}				boolean zipscript = zipscript(isRetr, isStor, status						.getChecksum(), response, targetFileName, targetDir);				if (zipscript) {					// transferstatistics					if (isRetr) {						float ratio = conn.getGlobalContext().getConfig()								.getCreditLossRatio(_transferFile,										conn.getUserNull());						if (ratio != 0) {							conn.getUserNull().updateCredits(									(long) (-status.getTransfered() * ratio));						}						if (!conn.getGlobalContext().getConfig()								.checkPathPermission("nostatsdn",										conn.getUserNull(),										conn.getCurrentDirectory())) {							conn.getUserNull().updateDownloadedBytes(									status.getTransfered());							conn.getUserNull().updateDownloadedTime(									status.getElapsed());							conn.getUserNull().updateDownloadedFiles(1);						}					} else {						conn.getUserNull().updateCredits(								(long) (status.getTransfered() * conn										.getGlobalContext().getConfig()										.getCreditCheckRatio(_transferFile,												conn.getUserNull())));						if (!conn.getGlobalContext().getConfig()								.checkPathPermission("nostatsup",										conn.getUserNull(),										conn.getCurrentDirectory())) {							conn.getUserNull().updateUploadedBytes(									status.getTransfered());							conn.getUserNull().updateUploadedTime(									status.getElapsed());							conn.getUserNull().updateUploadedFiles(1);						}					}					try {						conn.getUserNull().commit();					} catch (UserFileException e) {						logger.warn("", e);					}				}				// Dispatch for both STOR and RETR				conn.getGlobalContext().dispatchFtpEvent(						new TransferEvent(conn, eventType, _transferFile, conn								.getClientAddress(), _rslave, _transfer								.getAddress().getAddress(), getType()));				return response;			}        } finally {            reset(conn);        }    }    public void unload() {    }    /**	 * @param isRetr	 * @param isStor	 * @param status	 * @param response	 * @param targetFileName	 * @param targetDir	 *            Returns true if crc check was okay, i.e, if credits should be	 *            altered	 */    private boolean zipscript(boolean isRetr, boolean isStor, long checksum,        Reply response, String targetFileName,        LinkedRemoteFileInterface targetDir) {        // zipscript        logger.debug("Running zipscript on file " + targetFileName +            " with CRC of " + checksum);        if (isRetr) {            //compare checksum from transfer to cached checksum            logger.debug("checksum from transfer = " + checksum);            if (checksum != 0) {                response.addComment("Checksum from transfer: " +                    Checksum.formatChecksum(checksum));                long cachedChecksum;                cachedChecksum = _transferFile.getCheckSumCached();                if (cachedChecksum == 0) {                    _transferFile.setCheckSum(checksum);                } else if (cachedChecksum != checksum) {                    response.addComment(                        "WARNING: checksum from transfer didn't match cached checksum");                    logger.info("checksum from transfer " +                        Checksum.formatChecksum(checksum) +                        "didn't match cached checksum" +                        Checksum.formatChecksum(cachedChecksum) + " for " +                        _transferFile.toString() + " from slave " +                        _rslave.getName(), new Throwable());                }                //compare checksum from transfer to checksum from sfv                try {                    long sfvChecksum;					try {						sfvChecksum = _transferFile.getParentFileNull()						                                .lookupSFVFile()						                                .getChecksum(_transferFile.getName());	                    if (sfvChecksum == checksum) {	                        response.addComment(	                            "checksum from transfer matched checksum in .sfv");	                    } else {	                        response.addComment(	                            "WARNING: checksum from transfer didn't match checksum in .sfv");	                    }					} catch (FileStillTransferringException e) {						response								.addComment("checksum from sfv doesn't exist yet, SFVFile is being uploaded");					}                } catch (NoAvailableSlaveException e1) {                    response.addComment(                        "slave with .sfv offline, checksum not verified");                } catch (FileNotFoundException e1) {                    //continue without verification                } catch (NoSFVEntryException e1) {                    //file not found in .sfv, continue                } catch (IOException e1) {                    logger.info("", e1);                    response.addComment("IO Error reading sfv file: " +                        e1.getMessage());                }            } else { // slave has disabled download crc                //response.addComment("Slave has disabled download checksum");            }        } else if (isStor) {            if (!targetFileName.toLowerCase().endsWith(".sfv")) {                try {                    long sfvChecksum;					try {						sfvChecksum  = targetDir.lookupSFVFile().getChecksum(targetFileName);	                    if (checksum == sfvChecksum) {	                        response.addComment("checksum match: SLAVE/SFV:" +	                            Long.toHexString(checksum));	                    } else if (checksum == 0) {	                        response.addComment(	                            "checksum match: SLAVE/SFV: DISABLED");	                    } else {	                        response.addComment("checksum mismatch: SLAVE: " +	                            Long.toHexString(checksum) + " SFV: " +	                            Long.toHexString(sfvChecksum));	                        response.addComment(" deleting file");	                        response.setMessage("Checksum mismatch, deleting file");	                        _transferFile.delete();	                        //				getUser().updateCredits(	                        //					- ((long) getUser().getRatio() * transferedBytes));	                        //				getUser().updateUploadedBytes(-transferedBytes);	                        // response.addComment(conn.status());	                        return false; // don't modify credits	                        //				String badtargetFilename = targetFilename + ".bad";	                        //	                        //				try {	                        //					LinkedRemoteFile badtargetFile =	                        //						targetDir.getFile(badtargetFilename);	                        //					badtargetFile.delete();	                        //					response.addComment(	                        //						"zipscript - removing "	                        //							+ badtargetFilename	                        //							+ " to be replaced with new file");	                        //				} catch (FileNotFoundException e2) {	                        //					//good, continue...	                        //					response.addComment(	                        //						"zipscript - checksum mismatch, renaming to "	                        //							+ badtargetFilename);	                        //				}	                        //				targetFile.renameTo(targetDir.getPath() +	                        // badtargetFilename);	                    }					} catch (FileStillTransferringException e) {						response.addComment("No sfv to compare to (SFVTransferring), file allowed");					}                } catch (NoAvailableSlaveException e) {                    response.addComment(                        "zipscript - SFV unavailable, slave(s) with .sfv file is offline");                } catch (NoSFVEntryException e) {                    response.addComment("zipscript - no entry in sfv for file");                } catch (IOException e) {                    response.addComment(                        "zipscript - SFV unavailable, IO error: " +                        e.getMessage());                }            }        }        return true; // modify credits, transfer was okay    }	public synchronized void handshakeCompleted(HandshakeCompletedEvent arg0) {		_handshakeCompleted = true;		notifyAll();	}}