//*****************************************************************************
//*
//* (c) Copyright 2002. Glub Tech, Incorporated. All Rights Reserved.
//*
//* $Id: FTPCommand.java 37 2009-05-11 22:46:15Z gary $
//*
//*****************************************************************************
package com.glub.secureftp.bean;
import java.io.*;
import java.lang.Class;
import java.lang.reflect.Method;
import java.net.*;
import java.text.*;
import java.util.*;
import org.apache.regexp.*;
import com.glub.util.*;
/**
* The <code>FTPCommand</code> class is responsible for handling the standard
* commands used in the File Transfer Protocol.
*
* @author Brian Knight
* @version $Revision: 47 $, $Date: 2009-12-01 23:35:56 -0800 (Tue, 01 Dec 2009) $
* @since 2.5.5
*/
public class FTPCommand {
private boolean forcePasvToUseControlIP = false;
private String controlIP = null;
PrintWriter cmdWriter; // output stream for command channel
BufferedReader cmdReader; // input stream for command channel
String reply; // entire reply from server
int replyCode; // numeric reply code from server
String replyMessage; // message received from server
RECompiler compiler; // pattern compiler
RE matcher; // pattern matcher
DateFormat mdtmFormat = new SimpleDateFormat( "yyyyMMddHHmmss z" );
OutputStreamWriter recvCmdWriter = null; // data received back from server
OutputStreamWriter sendCmdWriter = null; // data sent to server
/**
* Create a new <code>FTPCommand</code> object.
*
* @param reader based on the input stream from the control socket.
* @param writer based on the output stream from the control socket.
*/
public FTPCommand( BufferedReader reader, PrintWriter writer ) {
this( reader, writer, null, null );
}
/**
* Create a new <code>FTPCommand</code> object.
*
* @param reader based on the input stream from the control socket.
* @param writer based on the output stream from the control socket.
* @param sendCmdStream stream used to report commands set to the FTP server.
* @param recvCmdStream stream used to report commands received from the
* FTP server.
*/
public FTPCommand( BufferedReader reader, PrintWriter writer,
OutputStream sendCmdStream, OutputStream recvCmdStream ) {
cmdReader = reader;
cmdWriter = writer;
setSendCmdStream( sendCmdStream );
setRecvCmdStream( recvCmdStream );
reply = null;
replyCode = -1;
replyMessage = null;
compiler = new RECompiler();
matcher = new RE();
}
/**
* Set the stream responsible for getting replies from the FTP server.
*
* @param recvCmdStream the stream used to get replies from the FTP server.
*/
public void setRecvCmdStream( OutputStream recvCmdStream ) {
_setRecvCmdStream( recvCmdStream );
}
/**
* Set the stream responsible for getting commands sent to the FTP server.
*
* @param sendCmdStream the stream used to get the commands sent to
* the FTP server.
*/
public void setSendCmdStream( OutputStream sendCmdStream ) {
_setSendCmdStream( sendCmdStream );
}
/**
* Specify the username for logging in to the FTP server.
*
* @param username name of the user attempting to login.
*
* @exception FTPNeedPasswordException if a password is required for login.
* @exception FTPNeedAccountException if account name is required for login.
* @exception FTPBadLoginException if login is denied.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>username</code> is missing.
*/
public synchronized void user(String username)
throws FTPNeedPasswordException, FTPNeedAccountException,
FTPBadLoginException, FTPException, IllegalArgumentException {
_user( username );
}
/**
* Specify the password for logging in to the FTP server.
*
* @param password password for the user attempting to login
*
* @exception FTPNeedAccountException if account name is required for login.
* @exception FTPBadLoginException if login is denied.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>username</code> is missing.
*/
public synchronized void pass(String password)
throws FTPNeedAccountException, FTPBadLoginException,
FTPException, IllegalArgumentException {
_pass( password );
}
/**
* Specify the account name to the FTP server.
*
* @param account account name for the user attempting to login
*
* @exception FTPBadLoginException if login is denied.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>username</code> is missing.
*/
public synchronized void acct(String account)
throws FTPBadLoginException, FTPException, IllegalArgumentException {
_acct( account );
}
/**
* Quit the FTP session.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void quit() throws FTPException {
_quit();
}
/**
* Get system information from the FTP server.
*
* @return system information as returned by the remote server.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized String syst() throws FTPException {
return _syst();
}
/**
* Delete a file from the FTP server.
*
* @param filename name of the file to delete.
*
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>filename</code> is missing.
*/
public synchronized void delete(String filename)
throws FTPException, IllegalArgumentException {
_delete( filename );
}
/**
* Rename a file on the FTP server.
*
* @param from existing name of the file.
* @param to new name for the file.
*
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if either <code>from</code> or
* <code>to</code> is missing.
*/
public synchronized void rename(String from, String to)
throws FTPException, IllegalArgumentException {
_rename( from, to );
}
/**
* Make a directory on the FTP server.
*
* @param dir new directory name.
*
* @exception FTPAccessDeniedException if the directory couldn't be created
* due to access restrictions.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>dir</code> is missing.
*/
public synchronized void mkdir(String dir)
throws FTPException, FTPAccessDeniedException,
IllegalArgumentException {
_mkdir( dir );
}
/**
* Remove a directory from the FTP server.
*
* @param dir new directory name.
*
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>dir</code> is missing.
*/
public synchronized void rmdir(String dir)
throws FTPException, IllegalArgumentException {
_rmdir( dir );
}
/**
* Restart an incomplete file transfer.
*
* @param byteOffset the amount of bytes to seek into the restore.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void rest( long byteOffset ) throws FTPException {
_rest( byteOffset );
}
/**
* Get the modification time of a file on the FTP server.
*
* @param file the name of the file.
*
* @return the file time or <code>null</code> if the time could not be
* determined.
*
* @exception FTPNoSuchFileException if <code>filename</code> does not exist.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>file</code> is missing.
*/
public synchronized Date mdtm( String file ) throws FTPNoSuchFileException,
FTPException,
IllegalArgumentException {
return _mdtm( file );
}
/**
* Change remote directory on the FTP server.
*
* @param dir the directory name.
*
* @exception FTPNotADirectoryException if <code>dir</code> is not a directory.
* @exception FTPNoSuchFileException if <code>dir</code> does not exist.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>dir</code> is missing.
*/
public synchronized void chdir(String dir)
throws FTPNotADirectoryException, FTPNoSuchFileException,
FTPException, IllegalArgumentException {
_chdir( dir );
}
/**
* Move up one directory on the FTP server.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void cdup() throws FTPException {
_cdup();
}
/**
* Get the working directory on the FTP server.
*
* @return the working directory on the FTP server,
* or null if the results could not be parsed.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized String pwd() throws FTPException {
return _pwd();
}
/**
* Abort a data transfer.
* <P>
* This method is not synchronized since abort may need to interrupt
* another method executing on the same object.
*
* @param data an Object that implements the FTPData interface.
*
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>data</code> is missing.
*/
public void abort( FTPData data ) throws FTPException,
IllegalArgumentException {
try {
_abort( data );
}
catch ( FTPException fe ) {
throw fe;
}
finally {
data.abortComplete();
}
}
/**
* Retrieve a file from the FTP server.
*
* @param file name of the file.
* @param data an Object that implements the FTPData interface.
*
* @exception FTPException if the FTP server returns an error code.
* @throws IOException if there are socket problems.
* @exception IllegalArgumentException if either <code>file</code> or
* <code>data</code> is missing.
*/
public synchronized void retrieve(String file, FTPData data)
throws FTPException, IOException, IllegalArgumentException {
_retrieve( file, data );
}
/**
* Store a file on the FTP server.
*
* @param file name of the file.
* @param data an Object that implements the FTPData interface.
*
* @exception FTPException if the FTP server returns an error code.
* @throws IOException if there are socket problems.
* @exception IllegalArgumentException if either <code>file</code> or
* <code>data</code> is missing.
*/
public synchronized void store(String file, FTPData data)
throws FTPException, IOException, IllegalArgumentException {
_store( file, data );
}
/**
* Append to a file on the FTP server.
*
* @param file name of the file.
* @param data an Object that implements the FTPData interface.
*
* @exception FTPException if the FTP server returns an error code.
* @throws IOException if there are socket problems.
* @exception IllegalArgumentException if either <code>file</code> or
* <code>data</code> is missing.
*/
public synchronized void append(String file, FTPData data)
throws FTPException, IOException, IllegalArgumentException {
_append( file, data );
}
/**
* Set the type of transfer.
*
* @param t the transfer type ('A' = ascii, 'I' = binary image).
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void type(char t) throws FTPException {
_type( t );
}
/**
* Mode Z compression
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void modeZ() throws FTPException {
_modeZ();
}
/**
* Get the size of a file from the FTP server.
*
* @param filename name of the file.
*
* @return size of the file, or -1 if the results could not be parsed.
*
* @exception FTPNoSuchFileException if <code>filename</code> does not exist.
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if <code>filename</code> is missing.
*/
public synchronized long size(String filename) throws FTPNoSuchFileException,
FTPException,
IllegalArgumentException {
return _size( filename );
}
/**
* List files in a directory on the FTP server.
*
* @param itemsToList the items to list.
* @param data an Object that implements the FTPData interface.
* @param showHidden flag to show hidden files (subject to availibility)
*
* @exception FTPException if the FTP server returns an error code.
* @throws IOException if there are socket problems.
* @exception IllegalArgumentException if <code>data</code> is missing.
*/
public synchronized void list(String itemsToList, FTPData data,
boolean showHidden)
throws FTPException, IOException, IllegalArgumentException {
_list( itemsToList, data, showHidden );
}
/**
* NList files in a directory on the FTP server.
*
* @param itemsToList the items to list.
* @param data an Object that implements the FTPData interface.
*
* @exception FTPException if the FTP server returns an error code.
* @throws IOException if there are socket problems.
* @exception IllegalArgumentException if <code>data</code> is missing.
*/
public synchronized void nlst(String itemsToList, FTPData data)
throws FTPException, IOException, IllegalArgumentException {
_nlst( itemsToList, data );
}
/**
* Request a PORT data transfer from the FTP server.
*
* @param hostInfo HostInfo for the local listening socket.
*
* @exception FTPException if the FTP server returns an error code.
* @exception IllegalArgumentException if hostInfo is null
*/
public synchronized void port( HostInfo hostInfo )
throws FTPException, IllegalArgumentException {
_port( hostInfo );
}
/**
* Request a PASV data transfer from the FTP server.
*
* @return HostInfo for connecting to the remote data socket,
or null if the results could not be parsed.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized HostInfo pasv() throws FTPException {
return _pasv();
}
/**
* Get help from the FTP server.
*
* @param item item to get help on from server
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized String help(String item) throws FTPException {
return _help( item );
}
/**
* Send a raw command to the FTP server.
*
* @param rawCmd command to send to the server
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void raw( String rawCmd ) throws FTPException {
_raw( rawCmd );
}
/**
* Send a noop to the FTP server.
*
* @exception FTPException if the FTP server returns an error code.
*/
public synchronized void noop() throws FTPException {
_noop();
}
/**
* Get the last full reply from the FTP server.
*
* @return the last reply from the FTP server.
*/
public synchronized String getReply() {
return reply;
}
/**
* Get the last reply code from the FTP server.
*
* @return the last reply code from the FTP server.
*/
public synchronized int getReplyCode() {
return replyCode;
}
/**
* Get the last reply message from the FTP server.
*
* @return the last reply message from the FTP server.
*/
public synchronized String getReplyMessage() {
return replyMessage;
}
/**
* Send a command to the FTP server.
*
* @param cmd the command to send to the FTP server.
*
* @exception FTPException if the FTP server returns an error code.
*/
protected void sendCmd(String cmd) throws FTPException {
sendCmd( cmd, null );
}
/**
* Send a command to the FTP server with command masking for client reporting.
* This is useful for PASS and ACCT so nobody sees what actually was sent.
*
* @param cmd the command to send to the FTP server.
* @param cmdMask the command mask that will be returned to the client.
*
* @exception FTPException if the FTP server returns an error code.
*/
protected void sendCmd(String cmd, String cmdMask)
throws FTPException {
_sendCmd( cmd, cmdMask );
}
/**
* Receive the message back from the FTP server.
*
* @exception FTPException if the FTP server returns an error code.
*/
//protected synchronized void recvCmd() throws FTPException {
protected void recvCmd() throws FTPException {
_recvCmd();
}
/**
* Forces passive data transfers to use the control socket IP address.
*
* @param on true if to use control socket IP, false if off.
*/
public void forcePasvToUseControlIP( boolean on ) {
forcePasvToUseControlIP = on;
}
/**
* Sets the control channel IP address.
*
* @param ip the control socket IP
* @see #forcePasvToUseControlIP(boolean)
*/
public void setControlIP( String ip ) {
controlIP = ip;
}
/*
*
* The methods below are here for obfuscation purposes.
*
*/
private void _setRecvCmdStream( OutputStream recvCmdStream ) {
if ( recvCmdStream == null ) {
recvCmdWriter = null;
}
else {
recvCmdWriter = new OutputStreamWriter(recvCmdStream);
}
}
private void _setSendCmdStream( OutputStream sendCmdStream ) {
if ( sendCmdStream == null ) {
sendCmdWriter = null;
}
else {
sendCmdWriter = new OutputStreamWriter(sendCmdStream);
}
}
private synchronized void _user(String username)
throws FTPNeedPasswordException, FTPNeedAccountException,
FTPBadLoginException, FTPException, IllegalArgumentException {
if (username == null || username.trim().length() == 0)
throw new IllegalArgumentException( "Missing username" );
sendCmd("USER " + username);
recvCmd();
// Login was successful if reply code is 230
if (replyCode == 230) { }
else if (replyCode == 331)
throw new FTPNeedPasswordException();
else if (replyCode == 332)
throw new FTPNeedAccountException();
else if (replyCode == 530)
throw new FTPBadLoginException(replyMessage);
else
throw new FTPException(replyMessage);
}
private synchronized void _pass(String password)
throws FTPNeedAccountException, FTPBadLoginException,
FTPException, IllegalArgumentException {
if (password == null || password.trim().length() == 0)
throw new IllegalArgumentException( "Missing password" );
sendCmd("PASS " + password, "PASS **********");
recvCmd();
// Login was successful if reply code is 202 or 230
if (replyCode == 202 || replyCode == 230) { }
else if (replyCode == 332)
throw new FTPNeedAccountException();
else if (replyCode == 530)
throw new FTPBadLoginException(replyMessage);
else
throw new FTPException(replyMessage);
}
private synchronized void _acct(String account)
throws FTPBadLoginException, FTPException, IllegalArgumentException {
if (account == null || account.trim().length() == 0)
throw new IllegalArgumentException( "Missing account" );
sendCmd("ACCT " + account, "ACCT **********");
recvCmd();
if (replyCode == 202 || replyCode == 230) { }
else if (replyCode == 530)
throw new FTPBadLoginException(replyMessage);
else
throw new FTPException(replyMessage);
}
private synchronized void _quit() throws FTPException {
sendCmd("QUIT");
recvCmd();
if (replyCode != 221)
throw new FTPException(replyMessage);
}
private synchronized String _syst() throws FTPException {
sendCmd("SYST");
recvCmd();
//if ((replyCode / 200) != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException( replyMessage );
return replyMessage;
}
private synchronized void _delete(String filename)
throws FTPException, IllegalArgumentException {
if (filename == null || filename.trim().length() == 0)
throw new IllegalArgumentException( "Missing filename" );
sendCmd("DELE " + filename);
recvCmd();
//if (replyCode != 250)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _rename(String from, String to)
throws FTPException, IllegalArgumentException {
if (from == null || from.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'from' parameter" );
if (to == null || to.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'to' parameter" );
sendCmd("RNFR " + from);
recvCmd();
if (replyCode != 350)
throw new FTPException(replyMessage);
sendCmd("RNTO " + to);
recvCmd();
//if (replyCode == 250) { } // Rename was successful
if (replyCode >= 200 && replyCode < 300) { }
else if (replyCode == 532)
throw new FTPNeedAccountException(replyMessage);
else
throw new FTPException(replyMessage);
}
private synchronized void _mkdir(String dir)
throws FTPException, FTPAccessDeniedException,
IllegalArgumentException {
if (dir == null || dir.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'dir' parameter" );
sendCmd("MKD " + dir);
recvCmd();
if (replyCode != 257) {
if ( replyMessage.indexOf("denied") > 0 ) {
throw new FTPAccessDeniedException(replyMessage);
}
else {
throw new FTPException(replyMessage);
}
}
}
private synchronized void _rmdir(String dir)
throws FTPException, IllegalArgumentException {
if (dir == null || dir.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'dir' parameter" );
sendCmd("RMD " + dir);
recvCmd();
//if (replyCode != 250)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _rest( long byteOffset ) throws FTPException {
if ( byteOffset < 0 ) {
byteOffset = 0;
}
sendCmd("REST " + byteOffset);
recvCmd();
if (replyCode != 350)
throw new FTPException(replyMessage);
}
private synchronized Date _mdtm( String file ) throws FTPNoSuchFileException,
FTPException,
IllegalArgumentException {
Date result = null;
if ( file == null || file.trim().length() == 0 )
throw new IllegalArgumentException( "Missing 'file' parameter" );
sendCmd("MDTM " + file);
recvCmd();
if ((replyCode / 550) == 1) {
throw new FTPNoSuchFileException(replyMessage);
}
else if (replyCode / 213 != 1) {
throw new FTPException(replyMessage);
}
int milliSecLoc = replyMessage.indexOf('.');
String sDate = replyMessage;
if ( milliSecLoc > 0 ) {
sDate = replyMessage.substring(0, milliSecLoc);
}
// fix stupid y2k bug!
if ( sDate.length() == 15 ) {
StringBuffer strBuf = new StringBuffer( sDate );
strBuf.delete( 0, 3 );
strBuf.insert( 0, "20" );
sDate = strBuf.toString();
}
try {
//Calendar cal = Calendar.getInstance();
result = mdtmFormat.parse( sDate + " GMT" );
}
catch ( ParseException pe ) {}
return result;
}
private synchronized void _chdir(String dir)
throws FTPNotADirectoryException, FTPNoSuchFileException,
FTPPermissionDeniedException, FTPException,
IllegalArgumentException {
if (dir == null || dir.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'dir' parameter" );
sendCmd("CWD " + dir);
recvCmd();
//if (replyCode == 250) {
if (replyCode >= 200 && replyCode < 300) {
// status probably ok
// unless the stupid server returns an ok code when it shouldn't!
if ( replyMessage.trim().equals("<virtual directory>") &&
!dir.trim().equals("/") )
throw new FTPNotADirectoryException(replyMessage);
}
else if (replyCode == 550) {
if (replyMessage.toLowerCase().indexOf("not a directory") >= 0 ||
replyMessage.toLowerCase().indexOf("directory name is invalid") >= 0)
throw new FTPNotADirectoryException(replyMessage);
else if (replyMessage.toLowerCase().indexOf("no such") >= 0)
throw new FTPNoSuchFileException(replyMessage);
else if (replyMessage.toLowerCase().indexOf("permission denied") >= 0)
throw new FTPPermissionDeniedException(replyMessage);
else
throw new FTPException(replyMessage);
}
else {
throw new FTPException(replyMessage);
}
}
private synchronized void _cdup() throws FTPException {
sendCmd("CDUP");
recvCmd();
//if (replyCode != 250)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized String _pwd() throws FTPException {
String remoteDir = null;
sendCmd("PWD");
recvCmd();
//if (replyCode != 257)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
String temp = replyMessage;
int start = temp.indexOf('"');
if (start >= 0) {
int end = temp.indexOf('"', start + 1);
if (end >= 0)
remoteDir = temp.substring(start + 1, end);
// there is some stupid FTP servers that don't properly send back
// a pwd.
if ( remoteDir != null && remoteDir.trim().equals("<virtual directory>") )
remoteDir = "";
}
else {
// there is some stupid FTP servers that don't properly send back
// a pwd.
if ( replyMessage.trim().equals("<virtual directory>") )
remoteDir = "";
}
return remoteDir;
}
private void _abort( FTPData data ) throws FTPException {
if ( data == null ) {
throw new IllegalArgumentException( "Missing 'data' parameter" );
}
Socket control = data.getControlSocket();
if ( control != null ) {
byte interpretAs = (byte)255;
byte interruptedProcess = (byte)244;
try {
Method urgentDataMethod = null;
Class[] args = { int.class };
urgentDataMethod = control.getClass().getMethod("sendUrgentData", args);
if ( null != urgentDataMethod ) {
control.sendUrgentData( interpretAs );
control.sendUrgentData( interruptedProcess );
}
}
catch ( SocketException se ) {
// in case the sendUrgentData doesn't exist
}
catch ( Exception e ) {
throw new FTPException( e.getMessage() );
}
}
sendCmd("ABOR");
data.abortTransfer();
recvCmd();
// Aborted in time or data transfer error occurred
if (replyCode == 226 || replyCode == 426 || replyCode == 550) {
//String abortReply = replyMessage;
try {
// Still need to get response to the ABOR command
recvCmd();
}
catch (Exception e) {
}
if (replyCode == 425) {
// transfer cancelled
throw new FTPAbortException(replyMessage);
}
else if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
// Response for ABOR only, maybe not doing data transfer
else if (replyCode == 225) {
// Nothing else to get
throw new FTPAbortException("ABOR command successful.");
}
else {
throw new FTPException(replyMessage);
}
}
private synchronized void _retrieve(String file, FTPData data)
throws FTPException, IOException {
if (file == null || file.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'file' parameter" );
if (data == null)
throw new IllegalArgumentException( "Missing 'data' parameter" );
sendCmd("RETR " + file);
// Start of transfer
recvCmd();
if (replyCode / 100 != 1)
throw new FTPException(replyMessage);
data.doTransfer();
// End of transfer
recvCmd();
//if (replyCode / 200 != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _store(String file, FTPData data)
throws FTPException, IOException {
if (file == null || file.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'file' parameter" );
if (data == null)
throw new IllegalArgumentException( "Missing 'data' parameter" );
sendCmd("STOR " + file);
// Start of transfer
recvCmd();
if (replyCode / 100 != 1)
throw new FTPException(replyMessage);
data.doTransfer();
// End of transfer
recvCmd();
//if (replyCode / 200 != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _append(String file, FTPData data)
throws FTPException, IOException {
if (file == null || file.trim().length() == 0)
throw new IllegalArgumentException( "Missing 'file' parameter" );
if (data == null)
throw new IllegalArgumentException( "Missing 'data' parameter" );
sendCmd("APPE " + file);
// Start of transfer
recvCmd();
if (replyCode / 100 != 1)
throw new FTPException(replyMessage);
data.doTransfer();
// End of transfer
recvCmd();
//if (replyCode / 200 != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _type(char t) throws FTPException {
sendCmd("TYPE " + t);
recvCmd();
//if (replyCode != 200)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _modeZ() throws FTPException {
sendCmd("MODE Z");
recvCmd();
if ( replyCode < 200 || replyCode >= 300) {
throw new FTPException(replyMessage);
}
}
private synchronized long _size(String filename) throws FTPException {
long value = -1;
if (filename == null || filename.trim().length() == 0)
throw new IllegalArgumentException( "Missing filename" );
sendCmd("SIZE " + filename);
recvCmd();
try {
//if ((replyCode / 200) == 1) {
if (replyCode >= 200 && replyCode < 300) {
value = Long.parseLong(replyMessage.trim());
}
else if ((replyCode / 550) == 1) {
throw new FTPNoSuchFileException(replyMessage);
}
else {
throw new FTPException(replyMessage);
}
}
catch (NumberFormatException nfe) { }
return value;
}
private synchronized void _list(String itemsToList, FTPData data,
boolean showHidden)
throws FTPException, IOException {
if (data == null)
throw new IllegalArgumentException( "Missing 'data' parameter" );
boolean listAll = showHidden;
String listAllStr = System.getProperty("glub.disableListWithDashA");
if ( null != listAllStr ) {
Boolean value = new Boolean( listAllStr );
listAll = value.booleanValue();
}
String listOptions = "";
if ( listAll ) {
listOptions = " -a";
}
if ( itemsToList != null && itemsToList.trim().length() > 0 ) {
sendCmd("LIST" + listOptions + " " + itemsToList.trim());
}
else {
sendCmd("LIST" + listOptions);
}
// Start of transfer
recvCmd();
if (replyCode / 100 != 1)
throw new FTPException(replyMessage);
data.doTransfer();
// End of transfer
recvCmd();
//if (replyCode / 200 != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _nlst(String itemsToList, FTPData data)
throws FTPException, IOException {
if (data == null)
throw new IllegalArgumentException( "Missing 'data' parameter" );
if ( itemsToList != null && itemsToList.trim().length() > 0 ) {
sendCmd("NLST " + itemsToList.trim());
}
else {
sendCmd("NLST");
}
// Start of transfer
recvCmd();
if (replyCode / 100 != 1)
throw new FTPException(replyMessage);
data.doTransfer();
// End of transfer
recvCmd();
//if (replyCode / 200 != 1)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized void _port( HostInfo hostInfo )
throws FTPException, IllegalArgumentException {
if (hostInfo == null)
throw new IllegalArgumentException( "Missing hostInfo" );
int port = hostInfo.getPort();
int hiPort = port >> 8;
int loPort = port & 0xff;
String hostAddress = hostInfo.getHostAddress();
hostAddress = Util.searchAndReplace( hostAddress, ".", ",", true );
sendCmd("PORT " + hostAddress + ',' + hiPort + ',' + loPort);
recvCmd();
//if (replyCode != 200)
if (replyCode < 200 || replyCode >= 300)
throw new FTPException(replyMessage);
}
private synchronized HostInfo _pasv() throws FTPException {
HostInfo hostInfo = null;
String dataAddr = null;
int dataPort = -1;
sendCmd("PASV");
recvCmd();
if (replyCode != 227)
throw new FTPException(replyMessage);
//String temp = replyMessage;
try {
REProgram pattern =
compiler.compile("(\\d+,\\d+,\\d+,\\d+),(\\d+),(\\d+)");
matcher.setProgram(pattern);
if (matcher.match(replyMessage)) {
if ( forcePasvToUseControlIP ) {
dataAddr = controlIP;
if ( dataAddr == null )
dataAddr = matcher.getParen(1).replace(',', '.');
}
else {
dataAddr = matcher.getParen(1).replace(',', '.');
}
dataPort = (Integer.parseInt(matcher.getParen(2)) << 8)
| Integer.parseInt(matcher.getParen(3));
hostInfo = new HostInfo( dataAddr, dataPort );
}
}
catch (Exception e) {
// Leave hostInfo as null to indicate failure
}
return hostInfo;
}
private synchronized String _help(String item) throws FTPException {
if ( item == null )
item = "";
String command = "HELP " + item;
sendCmd(command.trim());
recvCmd();
if (replyCode != 214)
throw new FTPException(replyMessage);
return reply;
}
private synchronized void _raw( String rawCmd ) throws FTPException {
sendCmd(rawCmd);
recvCmd();
}
private synchronized void _noop() throws FTPException {
sendCmd("NOOP");
recvCmd();
}
private void _sendCmd(String cmd, String cmdMask)
throws FTPException {
cmdWriter.print(cmd + "\r\n");
cmdWriter.flush();
if ( sendCmdWriter != null ) {
try {
if ( cmdMask != null ) {
sendCmdWriter.write(cmdMask);
}
else {
sendCmdWriter.write(cmd);
}
sendCmdWriter.write(System.getProperty("line.separator"));
sendCmdWriter.flush();
}
catch ( IOException ioe ) {
throw new FTPException("Cannot log send command: " + ioe.getMessage());
}
}
// Flush the stream and check its error state
if (cmdWriter.checkError()) {
throw new FTPConnectionLostException("Connection lost.");
}
}
//private synchronized void _recvCmd() throws FTPException {
private void _recvCmd() throws FTPException {
StringWriter writer = new StringWriter();
replyCode = -1;
replyMessage = null;
recvWrite(writer);
reply = writer.toString();
// strip the new line char at the end
if ( reply.length() > 1 ) {
reply = reply.substring(0, reply.length() - 1);
}
if ( recvCmdWriter != null && reply != null ) {
try {
recvCmdWriter.write(reply);
recvCmdWriter.write(System.getProperty("line.separator"));
recvCmdWriter.flush();
}
catch ( IOException ioe ) {
throw new FTPException("Cannot log recv command: " + ioe.getMessage());
}
}
try {
replyMessage = reply.substring(4).trim();
}
catch (Exception e) {
replyMessage = "";
}
if (replyCode == 421) {
cleanup();
throw new FTPConnectionLostException("Connection lost.");
}
}
//private synchronized void recvWrite(Writer writer) throws FTPException {
private void recvWrite(Writer writer) throws FTPException {
String line;
try {
PrintWriter out = new PrintWriter(writer, false);
if ((line = cmdReader.readLine()) == null) {
return;
}
out.print(line + "\r\n");
out.flush();
if ( line.length() < 3 ) {
return;
}
try {
replyCode = Integer.parseInt(line.substring(0, 3));
}
catch (NumberFormatException nfe) {
out.close();
throw new FTPException( line );
}
// Multi-line responses are indicated by a hyphen after the reply code
if (line.charAt(3) != '-')
return;
while ((line = cmdReader.readLine()) != null) {
//out.println(line);
out.print(line + "\r\n");
out.flush();
out.close();
if ( line.length() > 3 ) {
try {
int rc = Integer.parseInt(line.substring(0, 3));
// Multi-line is done when the reply code is followed by a space
if (line.charAt(3) == ' ' && rc == replyCode)
break;
}
catch (NumberFormatException e) {
// Multi-line responses do not need a reply code on every line,
// so this exception may occur under normal circumstances.
}
}
}
}
catch (InterruptedIOException iioe) {
// NEED TO DO: handle this
//debug.println("read interrupted: " + iioe.getMessage());
throw new FTPException(iioe.getMessage());
}
/*
catch (javax.net.ssl.SSLException sse) {
sse.printStackTrace();
}
*/
catch (IOException ioe) {
throw new FTPConnectionLostException("Connection lost: " +
ioe.getMessage());
}
}
/**
* Housekeeping for the control socket.
*/
private synchronized void cleanup() {
Util.close( cmdReader );
Util.close( cmdWriter );
}
}