rana_b      02/03/06 05:54:40

  Modified:    ftpserver/src/java/org/apache/avalon/ftpserver
                        FtpConnection.java FtpDataConnection.java
                        FtpException.java FtpRequest.java FtpStatus.java
                        FtpStatus.properties FtpUser.java
  Log:
  second stage of refactoring
  
  Revision  Changes    Path
  1.7       +1244 
-1268jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpConnection.java
  
  Index: FtpConnection.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpConnection.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- FtpConnection.java        14 Dec 2001 01:22:02 -0000      1.6
  +++ FtpConnection.java        6 Mar 2002 13:54:40 -0000       1.7
  @@ -31,17 +31,14 @@
   import java.lang.reflect.Method;
   import java.lang.reflect.InvocationTargetException;
   
  +import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  +
  +import org.apache.avalon.ftpserver.util.StreamConnectorObserver;
   import org.apache.avalon.ftpserver.util.IoUtils;
   import org.apache.avalon.ftpserver.util.StreamConnector;
   import org.apache.avalon.ftpserver.util.Message;
  -import org.apache.avalon.ftpserver.blocks.config.DefaultConfig;
  -import org.apache.avalon.ftpserver.services.FtpConfigService;
  -import org.apache.avalon.ftpserver.interfaces.UserHandler;
  -import org.apache.avalon.ftpserver.interfaces.IpRestrictor;
  -
  -import org.apache.avalon.framework.logger.AbstractLogEnabled;
  -import org.apache.avalon.framework.component.*;
  -import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  +import org.apache.avalon.ftpserver.interfaces.SpyConnectionInterface;
  +import org.apache.avalon.ftpserver.interfaces.FtpConnectionObserver;
   
   
   /**
  @@ -58,24 +55,23 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Rana Bhattacharyya</a>
    */
   public
  -class FtpConnection extends AbstractLogEnabled
  -                    implements Component, ConnectionHandler{
  +class FtpConnection implements ConnectionHandler, StreamConnectorObserver {
   
  -    private final static SimpleDateFormat DATE_FMT = new 
SimpleDateFormat("yyyyMMddHHmmss.SSS");
  -    private final static TimeZone GMT_TZ = TimeZone.getTimeZone("GMT");
  +    private final static SimpleDateFormat DATE_FMT = new 
SimpleDateFormat("yyyyMMddHHmmss.SSS"); 
       private final static String CRLF = "\r\n";
  +    
       private final static Class[] METHOD_INPUT_SIG = new Class[] 
{FtpRequest.class, Writer.class};
       
       
  -    private FtpConfigService mCfg             = null;
  -    private UserHandler mUserHandler;
  -    private IpRestrictor mIpRestrictor;
  -    private FtpStatus mFtpStatus       = null;
  -    private FtpDataConnection mDataCon = null;
  -    private Socket mControlSoc         = null;
  -    private FtpUser mUser              = null;
  +    private FtpConfig mCfg                  = null;
  +    private FtpStatus mFtpStatus            = null;
  +    private FtpDataConnection mDataCon      = null;
  +    private Socket mControlSoc              = null;
  +    private FtpUser mUser                   = null;
  +    private SpyConnectionInterface mSpy     = null;
  +    private FtpConnectionObserver mObserver = null;
   
  -    private boolean mbStopRequest      = false;
  +    private boolean mbStopRequest       = false;
   
       // command state specific temporary variables
       private boolean mbReset   = false;
  @@ -90,92 +86,87 @@
       /**
        * Set configuration file and the control socket.
        */
  -    public FtpConnection(FtpConfigService ftpConfig, UserHandler 
userHandler, IpRestrictor ipRestrictor) {
  +    public FtpConnection(FtpConfig ftpConfig) {
         mCfg = ftpConfig;
  -      mUserHandler = userHandler;
  -      mIpRestrictor = ipRestrictor;
         mFtpStatus = mCfg.getStatus();
  +      mUser = new FtpUser();  
       }
   
   
  -   /**
  -    * Handle new client connection.
  -    */
  -   public void handleConnection(final Socket socket) {
  -      getLogger().info("Handling new request from " + 
socket.getInetAddress());
  -      mControlSoc = socket;
  -      mDataCon = new FtpDataConnection(mCfg);
  -      mUser = new FtpUser(mCfg, mControlSoc, mDataCon);
  -      mUserHandler.newConnection(mUser);
  -      serveRequest();
  -   }
  -
  -
       /**
        * Server one FTP connection.
        */
  -    private void serveRequest() {
  -             
  +    public void handleConnection(final Socket socket) {
  +        
  +        InetAddress clientAddress = socket.getInetAddress();
  +        mCfg.getLogger().info("Handling new request from " + 
clientAddress.getHostAddress());
  +        mControlSoc = socket;
  +        mDataCon = new FtpDataConnection(mCfg);
  +        mUser.setClientAddress(clientAddress);
  +        mCfg.getConnectionService().newConnection(this);
  +        
           BufferedReader in = null;
  -        Writer out = null;
  +        Writer out = null;        
  +        
           try {
  -            in = new BufferedReader(new 
InputStreamReader(mControlSoc.getInputStream()));
  -            out = new OutputStreamWriter(mControlSoc.getOutputStream());
  -                     
  +            in = new BufferedReader(new 
InputStreamReader(mControlSoc.getInputStream()));              
  +            out = new OutputStreamWriter(mControlSoc.getOutputStream());     
               
  +        
               // permission check
  -            if( !mIpRestrictor.hasPermission(mControlSoc.getInetAddress()) ) 
{
  -                write(out, mFtpStatus.getResponse(530, null, null));
  +            if( 
!mCfg.getIpRestrictor().hasPermission(mControlSoc.getInetAddress()) ) {
  +                write(out, mFtpStatus.getResponse(530, null, mUser, null));
                   return;
               }
  -                     
  -            write(out, mFtpStatus.getResponse(220, null, null));
  -
  +            write(out, mFtpStatus.getResponse(220, null, mUser, null));
  +        
               do {
  +                notifyObserver();
                   String commandLine = in.readLine();
  -
  +            
                   // test command line
                   if(commandLine == null) {
                       break;
                   }
  -
  +            
                   commandLine = commandLine.trim();
                   spyPrint(commandLine);
                   spyPrint("\n");
  -
  +            
                   if(commandLine.equals("")) {
                       continue;
                   }
  -
  +            
                   FtpRequest request = null;
                   try {
  -
  +                
                       // parse input command
                       request = new FtpRequest(commandLine);
  -                    request.implementationCheck();
  -
  +                    implementationCheck(request);
  +                
                       // check user permission
                       if(!hasPermission(request)) {
  -                        write(out, mFtpStatus.getResponse(530, request, 
null));
  +                        write(out, mFtpStatus.getResponse(530, request, 
mUser, null));
                           break;
                       }
  -
  +                
                       // command execute
                       execute(request, out);
                   }
                   catch(FtpException ex) {
  -                     write(out, mFtpStatus.getResponse(ex.getErrorCode(), 
request, null));
  -                     if(ex.getErrorCode() == 530) {
  +                     write(out, mFtpStatus.getResponse(ex.getErrorCode(), 
request, mUser, null)); 
  +                     if( (ex.getErrorCode() == 530) || (ex.getErrorCode() == 
221)  ) {
                            break;
                        }
                   }
               }
               while(!mbStopRequest);
           }
  -        catch(Throwable ex) {}
  +        catch(Exception ex) {
  +        }
           finally {
               IoUtils.close(in);
               IoUtils.close(out);
  -            stop();
  +            
mCfg.getConnectionService().closeConnection(mUser.getSessionId());
           }
       }
   
  @@ -185,13 +176,12 @@
        */
       private void execute(FtpRequest request, Writer out) throws 
FtpException, IOException {
           try {
  -             mUser.hitUser();
                String metName = "do" + request.getCommand();
  -             Method actionMet = getClass().getDeclaredMethod(metName, 
METHOD_INPUT_SIG);
  +             Method actionMet = getClass().getDeclaredMethod(metName, new 
Class[] {FtpRequest.class, Writer.class});
                actionMet.invoke(this, new Object[] {request, out});
            }
            catch(NoSuchMethodException ex) {
  -             write(out, mFtpStatus.getResponse(502, request, null));
  +             write(out, mFtpStatus.getResponse(502, request, mUser, null));
            }
            catch(InvocationTargetException ex) {
                Throwable th = ex.getTargetException();
  @@ -199,16 +189,32 @@
                    throw (FtpException)th;
                }
                else {
  -                 write(out, mFtpStatus.getResponse(500, request, null));
  +                 write(out, mFtpStatus.getResponse(500, request, mUser, 
null));
                }
            }
            catch(IllegalAccessException ex) {
  -             write(out, mFtpStatus.getResponse(500, request, null));
  +             write(out, mFtpStatus.getResponse(500, request, mUser, null));
            }
       }
   
   
       /**
  +     * Check this command implementation.
  +     */
  +    private void implementationCheck(FtpRequest request) throws FtpException 
{ 
  +      String command = request.getCommand();
  +      if(!FtpRequest.isImplementedFtpCommand(command)) {
  +          if(FtpRequest.isNonImplementedFtpCommand(command)) {
  +              throw new FtpException(502);
  +          }
  +          else {
  +              throw new FtpException(500);
  +          }
  +      }
  +    }
  +     
  +    
  +    /**
        * Write and flush the string.
        */
       protected void write(Writer wr, String str) throws IOException {
  @@ -216,1302 +222,1272 @@
           wr.write(str);
           wr.flush();
       }
  -
  +    
   
       /**
        * User logout and stop this thread.
        */
       public void stop() {
  -        if (!mbStopRequest) {
  -            mbStopRequest = true;
  -            mUserHandler.closeConnection(mUser.getSessionId());
  +        mbStopRequest = true;
  +        if (mDataCon != null) {
  +            mDataCon.reset();
  +            mDataCon = null;
  +        }
  +        if (mControlSoc != null) {
  +            try {
  +                mControlSoc.close();
  +            }
  +            catch(Exception ex) {
  +            }
  +            mControlSoc = null;
           }
  +        mUser.logout();        
  +        mObserver = null;
       }
  -
  +     
       /**
        * Is the connection closed?
        */
       public boolean isClosed() {
           return mbStopRequest;
       }
  -
  -
  -    /**
  -     * Has ftp argument.
  -     */
  -    protected void hasArgument(FtpRequest request) throws FtpException {
  -        if(request.getArgument() == null) {
  -            throw new FtpException(501);
  -        }
  -    }
  -
  +    
  +    
       /**
        * Check the user permission to execute this command.
        */
       protected boolean hasPermission(FtpRequest request) {
           String cmd = request.getCommand();
  -        return mUser.hasLoggedIn() ||
  -                cmd.equals("USER") ||
  +        return mUser.hasLoggedIn() || 
  +                cmd.equals("USER") || 
                   cmd.equals("PASS") ||
                   cmd.equals("HELP");
       }
  -
  +     
       /**
        * Reset temporary state variables.
        */
       protected void resetState() {
           mbRenFr = false;
           mstRenFr = null;
  -
  +            
           mbReset = false;
           mlSkipLen = 0;
  -
  +            
           mbUser = false;
           mbPass = false;
       }
  -
  -    /**
  -     * Get an unique file name under this directory.
  -     */
  -    protected String getUniqueFileName(File dir) {
  -
  -        String fileName = null;
  -        Random rd = new Random(System.currentTimeMillis());
  -
  -        while(true) {
  -            fileName = String.valueOf(Math.abs(rd.nextLong())) + ".ftp";
  -            File fl = new File(dir, fileName);
  -            if(!fl.exists()) {
  -                break;
  -            }
  -        }
  -        return fileName;
  -    }
  -
  + 
  +    
       /**
        * Monitor the user activity.
        */
       private void spyPrint(final String str) {
  -        if(mUser.getSpyObject() != null) {
  -            mCfg.getMessageQueue().add(new Message() {
  +        final SpyConnectionInterface spy = mSpy;
  +        if (spy != null) {
  +            Message msg = new Message() {
                   public void execute() {
                       try {
  -                        mUser.getSpyObject().write(str);
  +                        spy.write(str);
                       }
                       catch(Exception ex) {
  -                        mUser.setSpyObject(null);
  +                        mSpy = null;
  +                        mCfg.getLogger().error("FtpConnection.spyPrint()", 
ex);
                       }
                   }
  -            });
  +            };
  +            mCfg.getMessageQueue().add(msg);
           }
       }
  +    
  +    /**
  +     * Get user object
  +     */
  +    public FtpUser getUser() {
  +        return mUser;
  +    }
  +     
  +    /**
  +     * Get connection spy object
  +     */
  +    public SpyConnectionInterface getSpyObject() {
  +        return mSpy;
  +    }
  +    
  +    /**
  +     * Set spy object
  +     */
  +    public void setSpyObject(SpyConnectionInterface spy) {
  +        mSpy = spy;
  +    }
  +    
  +    /**
  +     * Get observer
  +     */
  +    public FtpConnectionObserver getObserver() {
  +        return mObserver;
  +    }
   
  +    /**
  +     * Set observer
  +     */
  +    public void setObserver(FtpConnectionObserver obsr) {
  +        mObserver = obsr;
  +    }
   
  -     ////////////////////////////////////////////////////////////
  -     /////////////////   all the FTP handlers   /////////////////
  -     ////////////////////////////////////////////////////////////
  -     /**
  -      * <code>ABOR &lt;CRLF&gt;</code><br>
  -      *
  -      * This command tells the server to abort the previous FTP
  -      * service command and any associated transfer of data.
  -      * No action is to be taken if the previous command
  -      * has been completed (including data transfer).  The control
  -      * connection is not to be closed by the server, but the data
  -      * connection must be closed.
  -      * Current implementation does not do anything. As here data
  -      * transfers are not multi-threaded.
  -      */
  -     protected void doABOR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -         mDataCon.reset();
  -         write(out, mFtpStatus.getResponse(226, request, null));
  -     }
  -
  -
  -     /**
  -      * <code>APPE &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 in
  -      * a file at the server site.  If the file specified in the
  -      * pathname exists at the server site, then the data shall be
  -      * appended to that file; otherwise the file specified in the
  -      * pathname shall be created at the server site.
  -      */
  -     protected void doAPPE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         String fileName = request.getArgument();
  -         ArrayList args = new ArrayList(1);
  -         args.add(mUser.getVirtualDirectory().getVirtualFileName(fileName));
  -
  -         if(!mUser.getVirtualDirectory().getWritePermission()) {
  -             write(out, mFtpStatus.getResponse(450, request, args));
  -             return;
  -         }
  -
  -         File requestedFile = 
mUser.getVirtualDirectory().getFileObject(fileName);
  -
  -         // now transfer file data
  -         write(out, mFtpStatus.getResponse(150, request, args));
  -         InputStream is = null;
  -         OutputStream os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             is = dataSoc.getInputStream();
  -             RandomAccessFile raf = new RandomAccessFile(requestedFile, 
"rw");
  -             raf.seek(raf.length());
  -             os = mUser.getOutputStream( new FileOutputStream(raf.getFD()) );
  -
  -             StreamConnector msc = new StreamConnector(is, os);
  -             msc.setMaxTransferRate(mUser.getMaxUploadRate());
  -             msc.setIsBuffered(true);
  -             msc.setObserver(mUser);
  -             msc.connect();
  -
  -             if(msc.hasException()) {
  -                 write(out, mFtpStatus.getResponse(451, request, args));
  -             }
  -             else {
  -                 mCfg.getStatistics().setUpload(msc.getTransferredSize());
  -             }
  -
  -             write(out, mFtpStatus.getResponse(226, request, args));
  -             mDataCon.reset();
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, args));
  -         }
  -         finally {
  -            IoUtils.close(is);
  -            IoUtils.close(os);
  -            mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>CDUP &lt;CRLF&gt;</code><br>
  -      *
  -      * This command is a special case of CWD, and is included to
  -      * simplify the implementation of programs for transferring
  -      * directory trees between operating systems having different
  -      * syntaxes for naming the parent directory.  The reply codes
  -      * shall be identical to the reply codes of CWD.
  -      */
  -     protected void doCDUP(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -             
  -         // change directory
  -         if (mUser.getVirtualDirectory().changeDirectory("..")) {
  -            ArrayList args = new ArrayList(1);
  -             args.add(mUser.getVirtualDirectory().getCurrentDirectory());
  -             write(out, mFtpStatus.getResponse(200, request, args));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(431, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>CWD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command allows the user to work with a different
  -      * directory for file storage or retrieval without
  -      * altering his login or accounting information.  Transfer
  -      * parameters are similarly unchanged.  The argument is a
  -      * pathname specifying a directory.
  -      */
  -     protected void doCWD(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -              
  -         // get new directory name
  -         String dirName = "/";
  -         if (request.hasArgument()) {
  -             dirName = request.getArgument();
  -         }
  -         
  -         // change directory
  -         if (mUser.getVirtualDirectory().changeDirectory(dirName)) {
  -             ArrayList args = new ArrayList(1);
  -             args.add(mUser.getVirtualDirectory().getCurrentDirectory());
  -             write(out, mFtpStatus.getResponse(200, request, args));
  -         }
  -              else {
  -             write(out, mFtpStatus.getResponse(431, request, null));
  -              }
  -     }
  -
  +    /**
  +     * Notify observer.
  +     */
  +    public void notifyObserver() {
  +       mUser.hitUser();
  +       final FtpUser thisUser = mUser; 
  +       final FtpConnectionObserver obsr = mObserver;
   
  -     /**
  -      * <code>DELE &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes the file specified in the pathname to be
  -      * deleted at the server site.
  -      */
  -     protected void doDELE(FtpRequest request, Writer out) throws 
IOException {
  +       if (obsr != null) {
  +            Message msg = new Message() {
  +                public void execute() {
  +                    obsr.updateConnection(thisUser);
  +                }
  +            };
  +            mCfg.getMessageQueue().add(msg);
  +       }
  +    }
  +    
  +    /**
  +     * This method tracks data transfer.
  +     */
  +    public void dataTransferred(int sz) {
  +         notifyObserver();
  +    }
  +    
  +    /**
  +     * Last defense to logout and close.
  +     */
  +    protected void finalize() throws Throwable {
  +        stop();
  +        super.finalize();
  +    }
  +     
   
  +    ////////////////////////////////////////////////////////////
  +    /////////////////   all the FTP handlers   /////////////////
  +    ////////////////////////////////////////////////////////////
  +    /**
  +     * <code>ABOR &lt;CRLF&gt;</code><br>
  +     *
  +     * This command tells the server to abort the previous FTP
  +     * service command and any associated transfer of data.
  +     * No action is to be taken if the previous command
  +     * has been completed (including data transfer).  The control
  +     * connection is not to be closed by the server, but the data
  +     * connection must be closed.  
  +     * Current implementation does not do anything. As here data 
  +     * transfers are not multi-threaded. 
  +     */
  +    protected void doABOR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
           // reset state variables
           resetState();
  -
  +        mDataCon.reset();
  +        write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +    }
  +    
  +    
  +    /**
  +     * <code>APPE &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 in
  +     * a file at the server site.  If the file specified in the
  +     * pathname exists at the server site, then the data shall be
  +     * appended to that file; otherwise the file specified in the
  +     * pathname shall be created at the server site.
  +     */
  +    protected void doAPPE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +       
  +        // reset state variables
  +        resetState();
  +        
           // argument check
           if(!request.hasArgument()) {
  -           write(out, mFtpStatus.getResponse(501, request, null));
  -           return;
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
           }
  -             
  -        // get filename
  -        String fileName = 
mUser.getVirtualDirectory().getAbsoluteFileName(request.getArgument());
  -        ArrayList args = new ArrayList(1);
  -        args.add( 
fileName.substring(mUser.getVirtualDirectory().getRootDirectory().length() - 
1).trim() );
  -             
  +        
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File requestedFile = new File(physicalName);
  +        String args[] = {fileName};
  +        
           // check permission
  -        if(!mUser.getVirtualDirectory().hasWritePermission(fileName, true)) {
  -            write(out, mFtpStatus.getResponse(450, request, args));
  +        if(!mUser.getVirtualDirectory().hasWritePermission(physicalName, 
true)) {
  +            write(out, mFtpStatus.getResponse(450, request, mUser, args));
               return;
           }
  -             
  -        // now delete
  -        if(new File(fileName).delete()) {
  -           write(out, mFtpStatus.getResponse(250, request, args));
  -           mCfg.getStatistics().setDelete();
  +        
  +        // now transfer file data
  +        write(out, mFtpStatus.getResponse(150, request, mUser, args));
  +        InputStream is = null;
  +        OutputStream os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            is = dataSoc.getInputStream();
  +            RandomAccessFile raf = new RandomAccessFile(requestedFile, "rw");
  +            raf.seek(raf.length());
  +            os = mUser.getOutputStream( new FileOutputStream(raf.getFD()) );
  +            
  +            StreamConnector msc = new StreamConnector(is, os);
  +            msc.setMaxTransferRate(mUser.getMaxUploadRate());
  +            msc.setIsBuffered(true);
  +            msc.setObserver(this);
  +            msc.connect();
  +            
  +            if(msc.hasException()) {
  +                write(out, mFtpStatus.getResponse(451, request, mUser, 
args));
  +            }
  +            else {
  +                mCfg.getStatistics().setUpload(requestedFile, mUser, 
msc.getTransferredSize());
  +            }
  +            
  +            write(out, mFtpStatus.getResponse(226, request, mUser, args));
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, args));
  +        }
  +        finally {
  +           IoUtils.close(is);
  +           IoUtils.close(os);
  +           mDataCon.reset(); 
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>CDUP &lt;CRLF&gt;</code><br>
  +     *
  +     * This command is a special case of CWD, and is included to
  +     * simplify the implementation of programs for transferring
  +     * directory trees between operating systems having different
  +     * syntaxes for naming the parent directory.  The reply codes
  +     * shall be identical to the reply codes of CWD.      
  +     */
  +    protected void doCDUP(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // change directory
  +        if (mUser.getVirtualDirectory().changeDirectory("..")) {
  +            String args[] = 
{mUser.getVirtualDirectory().getCurrentDirectory()};
  +            write(out, mFtpStatus.getResponse(200, request, mUser, args));
           }
           else {
  -           write(out, mFtpStatus.getResponse(450, request, args));
  +             write(out, mFtpStatus.getResponse(431, request, mUser, null));
           }
  +    }
  +    
  +    
  +    /**
  +     * <code>CWD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command allows the user to work with a different
  +     * directory for file storage or retrieval without
  +     * altering his login or accounting information.  Transfer
  +     * parameters are similarly unchanged.  The argument is a
  +     * pathname specifying a directory.
  +     */
  +    protected void doCWD(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // get new directory name
  +        String dirName = "/";
  +        if (request.hasArgument()) {
  +             dirName = request.getArgument();
  +        } 
  +        
  +        // change directory
  +        if (mUser.getVirtualDirectory().changeDirectory(dirName)) {
  +            String args[] = 
{mUser.getVirtualDirectory().getCurrentDirectory()};
  +            write(out, mFtpStatus.getResponse(200, request, mUser, args));
  +        }
  +     else {
  +             write(out, mFtpStatus.getResponse(431, request, mUser, null));
        }
  -
  -     /**
  -      * <code>FEAT</code><br>
  -      *
  -      * Display supported ftp extended commands.
  -      */
  -     protected void doFEAT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -         write(out, mFtpStatus.getResponse(211, request, null));
  -     }
  -
  -     /**
  -      * <code>HELP [&lt;SP&gt; <string>] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command shall cause the server to send helpful
  -      * information regarding its implementation status over the
  -      * control connection to the user.  The command may take an
  -      * argument (e.g., any command name) and return more specific
  -      * information as a response.
  -      */
  -     protected void doHELP(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // print global help
  -         if(!request.hasArgument()) {
  -             write(out, mFtpStatus.getResponse(214, null, null));
  -             return;
  -         }
  -
  -         // print command specific help
  -         String ftpCmd = request.getArgument().toUpperCase();
  -         ArrayList args = new ArrayList();
  -         if(!request.isFtpCommand(ftpCmd)) {
  -             args.add(ftpCmd);
  -             ftpCmd = "UNKNOWN";
  -         }
  -         FtpRequest tempRequest = new FtpRequest(ftpCmd);
  -         write(out, mFtpStatus.getResponse(214, tempRequest, args));
  -         return;
  -     }
  -
  -
  -     /**
  -      * <code>LIST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes a list to be sent from the server to the
  -      * passive DTP.  If the pathname specifies a directory or other
  -      * group of files, the server should transfer a list of files
  -      * in the specified directory.  If the pathname specifies a
  -      * file then the server should send current information on the
  -      * file.  A null argument implies the user's current working or
  -      * default directory.  The data transfer is over the data
  -      * connection
  -      */
  -     protected void doLIST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         Writer os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             os = new OutputStreamWriter(dataSoc.getOutputStream());
  -             
  -             if 
(!mUser.getVirtualDirectory().printList(request.getArgument(), os)) {
  -                     throw new FtpException(501);
  -             }
  -             
  -             os.flush();
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  -             IoUtils.close(os);
  -             mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>MDTM &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * Returns the date and time of when a file was modified.
  -      */
  -     protected void doMDTM(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +    }
  +    
  +    
  +    /**
  +     * <code>DELE &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes the file specified in the pathname to be
  +     * deleted at the server site.
  +     */
  +    protected void doDELE(FtpRequest request, Writer out) throws IOException 
{
  +       
  +       // reset state variables
  +       resetState();  
  +        
  +       // argument check
  +       if(!request.hasArgument()) {
  +          write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +          return;  
  +       }    
  +       
  +       // get filenames
  +       String fileName = request.getArgument();
  +       fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +       String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +       File requestedFile = new File(physicalName);
  +       String[] args = {fileName};
  +       
  +       // check permission
  +       if(!mUser.getVirtualDirectory().hasWritePermission(physicalName, 
true)) {
  +           write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +           return;
  +       }
  +    
  +       // now delete
  +       if(requestedFile.delete()) {
  +          write(out, mFtpStatus.getResponse(250, request, mUser, args)); 
  +          mCfg.getStatistics().setDelete(requestedFile, mUser); 
  +       }
  +       else {
  +          write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +       }
  +    }
  +    
  +    
  +    /**
  +     * <code>HELP [&lt;SP&gt; <string>] &lt;CRLF&gt;</code><br>
  +     *
  +     * This command shall cause the server to send helpful
  +     * information regarding its implementation status over the
  +     * control connection to the user.  The command may take an
  +     * argument (e.g., any command name) and return more specific
  +     * information as a response.
  +     */
  +    protected void doHELP(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // print global help
  +        if(!request.hasArgument()) {
  +            write(out, mFtpStatus.getResponse(214, null, mUser, null));
               return;
  -         }
  -
  -         // reset state variables
  -         resetState();
  -
  -         File reqFile = 
mUser.getVirtualDirectory().getFileObject(request.getArgument());
  -         if(reqFile.exists()) {
  -             ArrayList args = new ArrayList();
  -             args.add(DATE_FMT.format(new Date(reqFile.lastModified())));
  -             write(out, mFtpStatus.getResponse(213, request, args));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(550, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>MKD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes the directory specified in the pathname
  -      * to be created as a directory (if the pathname is absolute)
  -      * or as a subdirectory of the current working directory (if
  -      * the pathname is relative).
  -      */
  -     protected void doMKD(FtpRequest request, Writer out) throws IOException 
{
  -
  +        }
  +        
  +        // print command specific help
  +        String ftpCmd = request.getArgument().toUpperCase();
  +        String args[] = null;
  +        if(!request.isFtpCommand(ftpCmd)) {
  +            args = new String[] {ftpCmd};
  +            ftpCmd = "UNKNOWN";
  +        }
  +        FtpRequest tempRequest = new FtpRequest(ftpCmd);
  +        write(out, mFtpStatus.getResponse(214, tempRequest, mUser, args));
  +        return;
  +    } 
  +    
  +    
  +    /**
  +     * <code>LIST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes a list to be sent from the server to the
  +     * passive DTP.  If the pathname specifies a directory or other
  +     * group of files, the server should transfer a list of files
  +     * in the specified directory.  If the pathname specifies a
  +     * file then the server should send current information on the
  +     * file.  A null argument implies the user's current working or
  +     * default directory.  The data transfer is over the data
  +     * connection
  +     */
  +    protected void doLIST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
           // reset state variables
           resetState();
  -
  +        
  +        write(out, mFtpStatus.getResponse(150, request, mUser, null));
  +        Writer os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            os = new OutputStreamWriter(dataSoc.getOutputStream());
  +            
  +            if 
(!mUser.getVirtualDirectory().printList(request.getArgument(), os)) {
  +             write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +            }
  +            else {
  +               os.flush();
  +               write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +            }
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, null));
  +        }
  +        finally {
  +            IoUtils.close(os);
  +            mDataCon.reset();
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>MDTM &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     * 
  +     * Returns the date and time of when a file was modified.
  +     */
  +    protected void doMDTM(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
           // argument check
           if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
           }
  -             
  -        // get filename
  -        String fileName = 
mUser.getVirtualDirectory().getAbsoluteFileName(request.getArgument());
  -        ArrayList args = new ArrayList(1);
  -        args.add( 
fileName.substring(mUser.getVirtualDirectory().getRootDirectory().length() - 
1).trim() );
  -             
  -        // check permission
  -        if(!mUser.getVirtualDirectory().hasCreatePermission(fileName, true)) 
{
  -            write(out, mFtpStatus.getResponse(450, request, args));
  -            return;
  -        }
  -     
  -             // now create directory
  -        if(new File(fileName).mkdirs()) {
  -           write(out, mFtpStatus.getResponse(250, request, args));
  +       
  +        // reset state variables
  +        resetState();
  +       
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File reqFile = new File(physicalName);
  +
  +        // now print date
  +        if(reqFile.exists()) {
  +            String args[] = {DATE_FMT.format(new 
Date(reqFile.lastModified()))};
  +            write(out, mFtpStatus.getResponse(213, request, mUser, args));
           }
           else {
  -           write(out, mFtpStatus.getResponse(450, request, args));
  +            write(out, mFtpStatus.getResponse(550, request, mUser, null));
           }
  -     }
  -
  -     /**
  -      * <code>MLST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes a file property displaying to be sent from
  -      * server to user site.  The pathname should specify an existing
  -      * file or directory name (no wildcard character);
  -      */
  -     protected void doMLST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         // get requested file object
  -         String reqPath = "./";
  -         if(request.hasArgument()) {
  -             reqPath = request.getArgument();
  -         }
  -         File reqFile = mUser.getVirtualDirectory().getFileObject(reqPath);
  -         reqPath = mUser.getVirtualDirectory().getVirtualFileName(reqPath);
  -
  -         // does not exist - send error message
  -         if(!reqFile.exists()) {
  -             write(out, mFtpStatus.getResponse(501, request, null));
  -             return;
  -         }
  -
  -         // populate file properties
  -         List args = new ArrayList(8);
  -         args.add(reqPath);
  -         if(reqFile.isDirectory()) {
  -             args.add("dir");
  -         }
  -         else {
  -             args.add("file");
  -         }
  -         args.add(String.valueOf(reqFile.length()));
  -         String perm = "";
  -         if(mUser.getVirtualDirectory().hasReadPermission(reqPath, false)) {
  -             perm += "r";
  -         }
  -         if(mUser.getVirtualDirectory().hasWritePermission(reqPath, false)) {
  -             perm += "wad";
  -         }
  -         args.add(perm);
  -         args.add(DATE_FMT.format(new Date(reqFile.lastModified())));
  -         write(out, mFtpStatus.getResponse(250, request, args));
  -     }
  -
  -     /**
  -      * <code>MLSD [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes a directory listing to be sent from
  -      * server to user site.  The pathname should specify a
  -      * directory (no wildcard character); a null argument implies
  -      * the current directory.  The server will return a stream of
  -      * names, size, type, last modification time of the files.
  -      */
  -     protected void doMLSD(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         // get requested directory
  -         String reqPath = "./";
  -         if(request.hasArgument()) {
  -             reqPath = request.getArgument();
  -         }
  -         File reqFile = mUser.getVirtualDirectory().getFileObject(reqPath);
  -         reqPath = mUser.getVirtualDirectory().getVirtualFileName(reqPath);
  -
  -         // error check
  -         if(!reqFile.isDirectory()) {
  -             write(out, mFtpStatus.getResponse(501, request, null));
  -             return;
  -         }
  -
  -         // directory listing - use data socket
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         Writer os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             os = new OutputStreamWriter(dataSoc.getOutputStream());
  -             File[] allFiles = reqFile.listFiles();
  -             for(int i=0; i<allFiles.length; i++) {
  -                 os.write("type=");
  -                 if(allFiles[i].isDirectory()) {
  -                     os.write("dir");
  -                 }
  -                 else {
  -                     os.write("file");
  -                 }
  -                 os.write(";size=");
  -                 os.write(String.valueOf(allFiles[i].length()));
  -                 os.write(";perm=");
  -                 String perm = "";
  -                 
if(mUser.getVirtualDirectory().hasReadPermission(allFiles[i].getAbsolutePath(), 
true)) {
  -                     perm += "r";
  -                 }
  -                 
if(mUser.getVirtualDirectory().hasWritePermission(allFiles[i].getAbsolutePath(),
 true)) {
  -                     perm += "wad";
  -                 }
  -                 os.write(perm);
  -                 os.write(";modify=");
  -                 os.write(DATE_FMT.format(new 
Date(allFiles[i].lastModified())));
  -                 os.write("; ");
  -                 os.write(mUser.getVirtualDirectory().getName(allFiles[i]));
  -                 os.write(CRLF);
  -             }
  -             os.flush();
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  -             IoUtils.close(os);
  -             mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doMODE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         if (mUser.setMode(request.getArgument().charAt(0))) {
  -             write(out, mFtpStatus.getResponse(200, request, null));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(504, request, null));
  -         }
  -     }
  -
  +    } 
  +    
  +    
  +    /**
  +     * <code>MKD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes the directory specified in the pathname
  +     * to be created as a directory (if the pathname is absolute)
  +     * or as a subdirectory of the current working directory (if
  +     * the pathname is relative).
  +     */
  +    protected void doMKD(FtpRequest request, Writer out) throws IOException {
  +       
  +       // reset state variables
  +       resetState(); 
  +        
  +       // argument check
  +       if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +       }
  +       
  +       // get filenames
  +       String fileName = request.getArgument();
  +       fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +       String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +       String args[] = {fileName};
  +       
  +       // check permission
  +       if(!mUser.getVirtualDirectory().hasCreatePermission(physicalName, 
true)) {
  +           write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +           return;
  +       }
  +       
  +    // now create directory
  +       if(new File(fileName).mkdirs()) {
  +          write(out, mFtpStatus.getResponse(250, request, mUser, args)); 
  +       }
  +       else {
  +          write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +       }
  +    }
   
  -     /**
  -      * <code>NLST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes a directory listing to be sent from
  -      * server to user site.  The pathname should specify a
  -      * directory or other system-specific file group descriptor; a
  -      * null argument implies the current directory.  The server
  -      * will return a stream of names of files and no other
  -      * information.
  -      */
  -     protected void doNLST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         Writer os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             os = new OutputStreamWriter(dataSoc.getOutputStream());
  -             
  -             if 
(!mUser.getVirtualDirectory().printNList(request.getArgument(), os)) {
  -                     throw new FtpException(501);
  -             }
  -             
  -             os.flush();
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  -             IoUtils.close(os);
  -             mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>NOOP &lt;CRLF&gt;</code><br>
  -      *
  -      * This command does not affect any parameters or previously
  -      * entered commands. It specifies no action other than that the
  -      * server send an OK reply.
  -      */
  -     protected void doNOOP(FtpRequest request, Writer out) throws 
IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         write(out, mFtpStatus.getResponse(200, request, null));
  -     }
  -
  -
  -     /**
  -      * <code>PASS &lt;SP&gt; <password> &lt;CRLF&gt;</code><br>
  -      *
  -      * The argument field is a Telnet string specifying the user's
  -      * password.  This command must be immediately preceded by the
  -      * user name command.
  -      */
  -     protected void doPASS(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // set state variables
  -         if(!mbUser) {
  -             write(out, mFtpStatus.getResponse(500, request, null));
  -             resetState();
  -             return;
  -         }
  -         resetState();
  -         mbPass = true;
  -
  -         // set user password and login
  -         ArrayList args = new ArrayList(1);
  -         args.add(mUser.getName());
  -         String pass = request.hasArgument() ? request.getArgument() : "";
  -         mUser.setPassword(pass);
  -         mUserHandler.login(mUser.getSessionId());
  -         write(out, mFtpStatus.getResponse(230, request, args));
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doPASV(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -         mDataCon.setPasvCommand();
  -
  -         InetAddress servAddr = mDataCon.getInetAddress();
  -         int servPort = mDataCon.getPort();
  -
  -         String addrStr = servAddr.getHostAddress().replace( '.', ',' ) + 
',' + (servPort>>8) + ',' + (servPort&0xFF);
  -         ArrayList args = new ArrayList();
  -         args.add(addrStr);
  -         write(out, mFtpStatus.getResponse(227, request, args));
  -         mDataCon.listenPasvConnection();
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doPORT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         InetAddress clientAddr = null;
  -         int clientPort = 0;
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         StringTokenizer st = new StringTokenizer(request.getArgument(), 
",");
  -         if(st.countTokens() != 6) {
  -             write(out, mFtpStatus.getResponse(510, request, null));
  -             return;
  -         }
  -
  -         // get data server
  -         String dataSrvName = st.nextToken() + '.' + st.nextToken() + '.' +
  -                              st.nextToken() + '.' + st.nextToken();
  -         try {
  -             clientAddr = InetAddress.getByName(dataSrvName);
  -         }
  -         catch(UnknownHostException ex) {
  -             write(out, mFtpStatus.getResponse(553, request, null));
  -             return;
  -         }
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doMODE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        if (mUser.setMode(request.getArgument().charAt(0))) {
  +           write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +        }
  +        else {
  +           write(out, mFtpStatus.getResponse(504, request, mUser, null));
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>NLST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes a directory listing to be sent from
  +     * server to user site.  The pathname should specify a
  +     * directory or other system-specific file group descriptor; a
  +     * null argument implies the current directory.  The server
  +     * will return a stream of names of files and no other
  +     * information.
  +     */
  +    protected void doNLST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        write(out, mFtpStatus.getResponse(150, request, mUser, null));
  +        Writer os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            os = new OutputStreamWriter(dataSoc.getOutputStream());
  +            
  +            if 
(!mUser.getVirtualDirectory().printNList(request.getArgument(), os)) {
  +             write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +            }
  +            else {
  +               os.flush();
  +               write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +            }
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, null));
  +        }
  +        finally {
  +            IoUtils.close(os);
  +            mDataCon.reset();
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>NOOP &lt;CRLF&gt;</code><br>
  +     *
  +     * This command does not affect any parameters or previously
  +     * entered commands. It specifies no action other than that the
  +     * server send an OK reply.
  +     */
  +    protected void doNOOP(FtpRequest request, Writer out) throws IOException 
{
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +    } 
  +    
  +    
  +    /**
  +     * <code>PASS &lt;SP&gt; <password> &lt;CRLF&gt;</code><br>
  +     *
  +     * The argument field is a Telnet string specifying the user's
  +     * password.  This command must be immediately preceded by the
  +     * user name command.
  +     */
  +    protected void doPASS(FtpRequest request, Writer out) throws 
FtpException, IOException {
   
  -         // get data server port
  -         try {
  -             int hi = Integer.parseInt(st.nextToken());
  -             int lo = Integer.parseInt(st.nextToken());
  -             clientPort = (hi << 8) | lo;
  -         }
  -         catch(NumberFormatException ex) {
  -            write(out, mFtpStatus.getResponse(552, request, null));
  +        // set state variables
  +        if(!mbUser) {
  +            write(out, mFtpStatus.getResponse(500, request, mUser, null));
  +            resetState();
               return;
  -         }
  -         mDataCon.setPortCommand(clientAddr, clientPort);
  -         write(out, mFtpStatus.getResponse(200, request, null));
  -     }
  -
  -
  -     /**
  -      * <code>PWD  &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes the name of the current working
  -      * directory to be returned in the reply.
  -      */
  -     protected void doPWD(FtpRequest request, Writer out) throws IOException 
{
  -
  -         // reset state variables
  -         resetState();
  -
  -         ArrayList args = new ArrayList(1);
  -         args.add(mUser.getVirtualDirectory().getCurrentDirectory());
  -         write(out, mFtpStatus.getResponse(257, request, args));
  -     }
  -
  -
  -     /**
  -      * <code>QUIT &lt;CRLF&gt;</code><br>
  -      *
  -      * This command terminates a USER and if file transfer is not
  -      * in progress, the server closes the control connection.
  -      */
  -     protected void doQUIT(FtpRequest request, Writer out) throws 
IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         stop();
  -     }
  +        }
  +        resetState();
  +        mbPass = true;        
  +        
  +        // set user password and login
  +        String pass = request.hasArgument() ? request.getArgument() : "";
  +        mUser.setPassword(pass);     
   
  +        if (!mCfg.getConnectionService().login(mUser)){
  +           throw new FtpException(530);
  +        }
  +        
  +        String args[] = {mUser.getName()};
  +        write(out, mFtpStatus.getResponse(230, request, mUser, args));
  +    }
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doPASV(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        mDataCon.setPasvCommand();
  +        
  +        InetAddress servAddr = mDataCon.getInetAddress();
  +        int servPort = mDataCon.getPort();
  +        
  +        String addrStr = servAddr.getHostAddress().replace( '.', ',' ) + ',' 
+ (servPort>>8) + ',' + (servPort&0xFF);
  +        String[] args = {addrStr};
  +        
  +        write(out, mFtpStatus.getResponse(227, request, mUser, args));
  +        mDataCon.listenPasvConnection();
  +    }
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doPORT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        InetAddress clientAddr = null;
  +        int clientPort = 0;
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
   
  -     /**
  -      * <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.
  -      */
  -     protected void doREST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +        StringTokenizer st = new StringTokenizer(request.getArgument(), ",");
  +        if(st.countTokens() != 6) {
  +            write(out, mFtpStatus.getResponse(510, request, mUser, null));
               return;
  -         }
  -
  -         // set state variables
  -         resetState();
  -         mlSkipLen = 0;
  -         String skipNum = request.getArgument();
  -         try {
  -              mlSkipLen = Long.parseLong(skipNum);
  -         }
  -         catch(NumberFormatException ex) {
  -             write(out, mFtpStatus.getResponse(501, request, null));
  -             return;
  -         }
  -         if(mlSkipLen < 0) {
  -             mlSkipLen = 0;
  -             write(out, mFtpStatus.getResponse(501, request, null));
  -             return;
  -         }
  -         mbReset = true;
  -         write(out, mFtpStatus.getResponse(350, request, null));
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doRETR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // set state variables
  -         long skipLen = (mbReset) ? mlSkipLen : 0;
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +        }
  +            
  +        // get data server
  +        String dataSrvName = st.nextToken() + '.' + st.nextToken() + '.' +
  +                             st.nextToken() + '.' + st.nextToken();
  +        try {
  +            clientAddr = InetAddress.getByName(dataSrvName);
  +        }
  +        catch(UnknownHostException ex) {
  +            write(out, mFtpStatus.getResponse(553, request, mUser, null));
               return;
  -         }
  -
  -         String fileName = request.getArgument();
  -         if(!mUser.getVirtualDirectory().hasReadPermission(fileName, false)) 
{
  -             write(out, mFtpStatus.getResponse(550, request, null));
  -             return;
  -         }
  -         File requestedFile = 
mUser.getVirtualDirectory().getFileObject(fileName);
  -
  -         // now transfer file data
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         InputStream is = null;
  -         OutputStream os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             os = dataSoc.getOutputStream();
  -
  -             RandomAccessFile raf = new RandomAccessFile(requestedFile, "r");
  -             raf.seek(skipLen);
  -             is = mUser.getInputStream( new FileInputStream(raf.getFD()) );
  -
  -             StreamConnector msc = new StreamConnector(is, os);
  -             msc.setMaxTransferRate(mUser.getMaxDownloadRate());
  -             msc.setIsBuffered(true);
  -             msc.setObserver(mUser);
  -             msc.connect();
  -
  -             if(msc.hasException()) {
  -                 write(out, mFtpStatus.getResponse(451, request, null));
  -                 return;
  -             }
  -             else {
  -                 mCfg.getStatistics().setDownload(msc.getTransferredSize());
  -             }
  -
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -             mDataCon.reset();
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  -             IoUtils.close(is);
  -             IoUtils.close(os);
  -             mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>RMD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command causes the directory specified in the pathname
  -      * to be removed as a directory (if the pathname is absolute)
  -      * or as a subdirectory of the current working directory (if
  -      * the pathname is relative).
  -      */
  -     protected void doRMD(FtpRequest request, Writer out) throws IOException 
{
  -
  +        }
  +        
  +        // get data server port
  +        try {
  +            int hi = Integer.parseInt(st.nextToken());
  +            int lo = Integer.parseInt(st.nextToken());
  +            clientPort = (hi << 8) | lo;     
  +        }
  +        catch(NumberFormatException ex) {
  +           write(out, mFtpStatus.getResponse(552, request, mUser, null)); 
  +           return; 
  +        }
  +        mDataCon.setPortCommand(clientAddr, clientPort);
  +        write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +    }
  +    
  +    
  +    /**
  +     * <code>PWD  &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes the name of the current working
  +     * directory to be returned in the reply.
  +     */
  +    protected void doPWD(FtpRequest request, Writer out) throws IOException {
  +        
           // reset state variables
           resetState();
  -
  +        String args[] = {mUser.getVirtualDirectory().getCurrentDirectory()};
  +        write(out, mFtpStatus.getResponse(257, request, mUser, args));
  +    }
  +    
  +    
  +    /**
  +     * <code>QUIT &lt;CRLF&gt;</code><br>
  +     *
  +     * This command terminates a USER and if file transfer is not
  +     * in progress, the server closes the control connection.
  +     */
  +    protected void doQUIT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // and exit
  +        throw new FtpException(221);
  +    }
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doREST(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
           // argument check
           if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +       
  +        // set state variables
  +        resetState();
  +        mlSkipLen = 0;
  +        String skipNum = request.getArgument();
  +        try { 
  +             mlSkipLen = Long.parseLong(skipNum);
  +        }
  +        catch(NumberFormatException ex) {
  +            write(out, mFtpStatus.getResponse(501, request, mUser, null)); 
               return;
           }
  -             
  -        // get file name
  -        String fileName = 
mUser.getVirtualDirectory().getAbsoluteFileName(request.getArgument());
  -        ArrayList args = new ArrayList(1);
  -        args.add( 
fileName.substring(mUser.getVirtualDirectory().getRootDirectory().length() - 
1).trim() );
  -             
  +        if(mlSkipLen < 0) {
  +            mlSkipLen = 0;
  +            write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +            return;
  +        }
  +        mbReset = true;
  +        write(out, mFtpStatus.getResponse(350, request, mUser, null));
  +    } 
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doRETR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // set state variables
  +        long skipLen = (mbReset) ? mlSkipLen : 0;
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File requestedFile = new File(physicalName);
  +        String args[] = {fileName};
  +        
           // check permission
  -        if(!mUser.getVirtualDirectory().hasWritePermission(fileName, true)) {
  -            write(out, mFtpStatus.getResponse(450, request, args));
  +        if(!mUser.getVirtualDirectory().hasReadPermission(physicalName, 
true)) {
  +            write(out, mFtpStatus.getResponse(550, request, mUser, args));
               return;
           }
  -             
  -        // now delete
  -        if(new File(fileName).delete()) {
  -           write(out, mFtpStatus.getResponse(250, request, args));
  +        
  +        // now transfer file data
  +        write(out, mFtpStatus.getResponse(150, request, mUser, null));
  +        InputStream is = null;
  +        OutputStream os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            os = mUser.getOutputStream(dataSoc.getOutputStream());
  +            
  +            RandomAccessFile raf = new RandomAccessFile(requestedFile, "r");
  +            raf.seek(skipLen);
  +            is = new FileInputStream(raf.getFD());                 
  +          
  +            StreamConnector msc = new StreamConnector(is, os);
  +            msc.setMaxTransferRate(mUser.getMaxDownloadRate());
  +            msc.setIsBuffered(true);
  +            msc.setObserver(this);
  +            msc.connect();
  +            
  +            if(msc.hasException()) {
  +                write(out, mFtpStatus.getResponse(451, request, mUser, 
args));
  +                return;
  +            }
  +            else {
  +                mCfg.getStatistics().setDownload(requestedFile, mUser, 
msc.getTransferredSize());
  +            }
  +            
  +            write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, null));
  +        }
  +        finally {
  +            IoUtils.close(is);
  +            IoUtils.close(os);
  +            mDataCon.reset();
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>RMD  &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command causes the directory specified in the pathname
  +     * to be removed as a directory (if the pathname is absolute)
  +     * or as a subdirectory of the current working directory (if
  +     * the pathname is relative).
  +     */
  +    protected void doRMD(FtpRequest request, Writer out) throws IOException {
  +       
  +       // reset state variables
  +       resetState(); 
  +        
  +       // argument check
  +       if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +       }
  +       
  +       // get file names
  +       String fileName = request.getArgument();
  +       fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +       String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +       File requestedFile = new File(physicalName);
  +       String args[] = {fileName};
  +       
  +       // check permission
  +       if(!mUser.getVirtualDirectory().hasWritePermission(physicalName, 
true)) {
  +           write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +           return;
  +       }
  +    
  +       // now delete
  +       if(requestedFile.delete()) {
  +          write(out, mFtpStatus.getResponse(250, request, mUser, args)); 
  +       }
  +       else {
  +          write(out, mFtpStatus.getResponse(450, request, mUser, args));
  +       }
  +    }
  +    
  +    
  +    /**
  +     * <code>RNFR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command specifies the old pathname of the file which is
  +     * to be renamed.  This command must be immediately followed by
  +     * a "rename to" command specifying the new file pathname.
  +     */
  +    protected void doRNFR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variable
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        // set state variable
  +        mbRenFr = true;
  +        
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        mstRenFr = mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        String args[] = {fileName};
  +        
  +        write(out, mFtpStatus.getResponse(350, request, mUser, args));
  +    }
  +    
  +    
  +    /**
  +     * <code>RNTO &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * This command specifies the new pathname of the file
  +     * specified in the immediately preceding "rename from"
  +     * command.  Together the two commands cause a file to be
  +     * renamed.
  +     */
  +    protected void doRNTO(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           resetState(); 
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        // set state variables
  +        if((!mbRenFr) || (mstRenFr == null)) {
  +             resetState();
  +             write(out, mFtpStatus.getResponse(100, request, mUser, null));
  +             return;
  +        }
  +        
  +        // get filenames
  +        String fromFileStr = 
mUser.getVirtualDirectory().getVirtualName(mstRenFr);
  +        String toFileStr = request.getArgument();
  +        toFileStr = mUser.getVirtualDirectory().getAbsoluteName(toFileStr);
  +        String physicalToFileStr = 
mUser.getVirtualDirectory().getPhysicalName(toFileStr);
  +        File fromFile = new File(mstRenFr);
  +        File toFile = new File(physicalToFileStr);
  +        String args[] = {fromFileStr, toFileStr};
  +        
  +        resetState();
  +        
  +        // check permission
  +        
if(!mUser.getVirtualDirectory().hasCreatePermission(physicalToFileStr, true)) {
  +           write(out, mFtpStatus.getResponse(553, request, mUser, null));
  +           return;
  +        }
  +        
  +        // now rename
  +        if(fromFile.renameTo(toFile)) {
  +            write(out, mFtpStatus.getResponse(250, request, mUser, args));
           }
           else {
  -           write(out, mFtpStatus.getResponse(450, request, args));
  +            write(out, mFtpStatus.getResponse(553, request, mUser, args));
           }
  -     }
  -
  -
  -     /**
  -      * <code>RNFR &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command specifies the old pathname of the file which is
  -      * to be renamed.  This command must be immediately followed by
  -      * a "rename to" command specifying the new file pathname.
  -      */
  -     protected void doRNFR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variable
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         // set state variable
  -         mbRenFr = true;
  -         mstRenFr = 
mUser.getVirtualDirectory().getAbsoluteFileName(request.getArgument());
  -
  -         write(out, mFtpStatus.getResponse(350, request, null));
  -     }
  -
  -
  -     /**
  -      * <code>RNTO &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * This command specifies the new pathname of the file
  -      * specified in the immediately preceding "rename from"
  -      * command.  Together the two commands cause a file to be
  -      * renamed.
  -      */
  -     protected void doRNTO(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            resetState();
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         // set state variables
  -         if((!mbRenFr) || (mstRenFr == null)) {
  -              resetState();
  -              write(out, mFtpStatus.getResponse(100, request, null));
  -              return;
  -         }
  -         File fromFile = new File(mstRenFr);
  -         resetState();
  -
  -         if(!mUser.getVirtualDirectory().getWritePermission()) {
  -            write(out, mFtpStatus.getResponse(553, request, null));
  -            return;
  -         }
  -
  -         File toFile = 
mUser.getVirtualDirectory().getFileObject(request.getArgument());
  -         if(fromFile.renameTo(toFile)) {
  -             write(out, mFtpStatus.getResponse(250, request, null));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(553, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>SITE &lt;SP&gt; <string> &lt;CRLF&gt;</code><br>
  -      *
  -      * This command is used by the server to provide services
  -      * specific to his system that are essential to file transfer
  -      * but not sufficiently universal to be included as commands in
  -      * the protocol.
  -      */
  -     protected void doSITE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -         write(out, mFtpStatus.getResponse(200, request, null));
  -     }
  -
  -
  -     /**
  -      * <code>SIZE &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * Returns the size of the file in bytes.
  -      */
  -     protected void doSIZE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -
  -         // reset state variables
  -         resetState();
  -
  -         File reqFile = 
mUser.getVirtualDirectory().getFileObject(request.getArgument());
  -         if(reqFile.exists()) {
  -             ArrayList args = new ArrayList();
  -             args.add(String.valueOf(reqFile.length()));
  -             write(out, mFtpStatus.getResponse(213, request, args));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(550, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>STAT [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  -      *
  -      * This command shall cause a status response to be sent over
  -      * the control connection in the form of a reply.
  -      */
  -     protected void doSTAT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -       ArrayList args = new ArrayList(3);
  -       args.add(mCfg.getServerAddress().getHostAddress());
  -       args.add(mControlSoc.getInetAddress().getHostAddress());
  -       args.add(mUser.getName());
  -       write(out, mFtpStatus.getResponse(211, request, args));
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doSTOR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // set state variables
  -         long skipLen = (mbReset) ? mlSkipLen : 0;
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +    } 
  +    
  +    
  +    /**
  +     * <code>SITE &lt;SP&gt; <string> &lt;CRLF&gt;</code><br>
  +     *
  +     * This command is used by the server to provide services
  +     * specific to his system that are essential to file transfer
  +     * but not sufficiently universal to be included as commands in
  +     * the protocol.
  +     */
  +    protected void doSITE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +    }
  +    
  +    
  +    /**
  +     * <code>SIZE &lt;SP&gt; &lt;pathname&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * Returns the size of the file in bytes.
  +     */
  +    protected void doSIZE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +       
  +        // reset state variables
  +        resetState();
  +       
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File reqFile = new File(physicalName);
  +        
  +        // print file size
  +        if(reqFile.exists()) {
  +            String args[] = {String.valueOf(reqFile.length())};             
  +            write(out, mFtpStatus.getResponse(213, request, mUser, args));
  +        }
  +        else {
  +            write(out, mFtpStatus.getResponse(550, request, mUser, null));
  +        }
  +    } 
  +    
  +    
  +    /**
  +     * <code>STAT [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code><br>
  +     *
  +     * This command shall cause a status response to be sent over
  +     * the control connection in the form of a reply.
  +     */
  +    protected void doSTAT(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        String args[] = {
  +           mCfg.getServerAddress().getHostAddress(),
  +           mControlSoc.getInetAddress().getHostAddress(),
  +           mUser.getName()
  +        };
  +      
  +        write(out, mFtpStatus.getResponse(211, request, mUser, args)); 
  +    } 
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doSTOR(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // set state variables
  +        long skipLen = (mbReset) ? mlSkipLen : 0;
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        // get filenames
  +        String fileName = request.getArgument();
  +        fileName = mUser.getVirtualDirectory().getAbsoluteName(fileName);
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File requestedFile = new File(physicalName);
  +        
  +        // get permission
  +        if(!mUser.getVirtualDirectory().hasCreatePermission(physicalName, 
true)) {
  +            write(out, mFtpStatus.getResponse(550, request, mUser, null));
               return;
  -         }
  -
  -         String fileName = request.getArgument();
  -         if(!mUser.getVirtualDirectory().hasCreatePermission(fileName, 
false)) {
  -             write(out, mFtpStatus.getResponse(550, request, null));
  -             return;
  -         }
  -         File requestedFile = 
mUser.getVirtualDirectory().getFileObject(fileName);
  -
  -         // now transfer file data
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         InputStream is = null;
  -         OutputStream os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             is = dataSoc.getInputStream();
  -
  -             RandomAccessFile raf = new RandomAccessFile(requestedFile, 
"rw");
  -             raf.seek(skipLen);
  -             os = mUser.getOutputStream( new FileOutputStream(raf.getFD()) );
  -
  -             StreamConnector msc = new StreamConnector(is, os);
  -             msc.setMaxTransferRate(mUser.getMaxUploadRate());
  -             msc.setIsBuffered(true);
  -             msc.setObserver(mUser);
  -             msc.connect();
  -
  -             if(msc.hasException()) {
  -                 write(out, mFtpStatus.getResponse(451, request, null));
  -                 return;
  -             }
  -             else {
  -                 mCfg.getStatistics().setUpload(msc.getTransferredSize());
  -             }
  -
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -             mDataCon.reset();
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  -             IoUtils.close(is);
  -             IoUtils.close(os);
  -             mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doSTOU(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         String fileName = 
getUniqueFileName(mUser.getVirtualDirectory().getFileObject("./"));
  -         ArrayList args = new ArrayList(1);
  -         args.add(fileName);
  -
  -         if(!mUser.getVirtualDirectory().hasCreatePermission(fileName, 
false)) {
  -             write(out, mFtpStatus.getResponse(550, request, null));
  -             return;
  -         }
  -         File requestedFile = 
mUser.getVirtualDirectory().getFileObject(fileName);
  -
  -         // now transfer file data
  -         write(out, mFtpStatus.getResponse(150, request, null));
  -         InputStream is = null;
  -         OutputStream os = null;
  -         try {
  -             Socket dataSoc = mDataCon.getDataSocket();
  -             is = dataSoc.getInputStream();
  -             os = mUser.getOutputStream( new FileOutputStream(requestedFile) 
);
  -
  -             StreamConnector msc = new StreamConnector(is, os);
  -             msc.setMaxTransferRate(mUser.getMaxUploadRate());
  -             msc.setIsBuffered(true);
  -             msc.setObserver(mUser);
  -             msc.connect();
  -
  -             if(msc.hasException()) {
  -                 write(out, mFtpStatus.getResponse(451, request, null));
  -                 return;
  -             }
  -             else {
  -                 mCfg.getStatistics().setUpload(msc.getTransferredSize());
  -             }
  -
  -             write(out, mFtpStatus.getResponse(226, request, null));
  -             mDataCon.reset();
  -             write(out, mFtpStatus.getResponse(250, request, args));
  -         }
  -         catch(IOException ex) {
  -             write(out, mFtpStatus.getResponse(425, request, null));
  -         }
  -         finally {
  +        }
  +        
  +        // now transfer file data
  +        write(out, mFtpStatus.getResponse(150, request, mUser, null));
  +        InputStream is = null;
  +        OutputStream os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            is = dataSoc.getInputStream();
  +            
  +            RandomAccessFile raf = new RandomAccessFile(requestedFile, "rw");
  +            raf.seek(skipLen);
  +            os = mUser.getOutputStream( new FileOutputStream(raf.getFD()) );
  +            
  +            StreamConnector msc = new StreamConnector(is, os);
  +            msc.setMaxTransferRate(mUser.getMaxUploadRate());
  +            msc.setIsBuffered(true);
  +            msc.setObserver(this);
  +            msc.connect();
  +            
  +            if(msc.hasException()) {
  +                write(out, mFtpStatus.getResponse(451, request, mUser, 
null));
  +                return;
  +            }
  +            else {
  +                mCfg.getStatistics().setUpload(requestedFile, mUser, 
msc.getTransferredSize());
  +            }
  +            
  +            write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, null));
  +        }
  +        finally {
               IoUtils.close(is);
               IoUtils.close(os);
               mDataCon.reset();
  -         }
  -     }
  -
  -
  -     /**
  -      * <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.
  -      */
  -     protected void doSTRU(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  -            return;
  -         }
  -                     
  -         if (mUser.setStructure(request.getArgument().charAt(0))) {
  -             write(out, mFtpStatus.getResponse(200, request, null));
  -         } 
  -         else {
  -             write(out, mFtpStatus.getResponse(504, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>SYST &lt;CRLF&gt;</code><br>
  -      *
  -      * This command is used to find out the type of operating
  -      * system at the server.
  -      */
  -     protected void doSYST(FtpRequest request, Writer out) throws 
IOException {
  -
  -         // reset state variables
  -         resetState();
  -
  -         ArrayList args = new ArrayList(1);
  -         args.add(mCfg.getSystemName());
  -         write(out, mFtpStatus.getResponse(215, request, args));
  -     }
  -
  -
  -     /**
  -      * <code>TYPE &lt;SP&gt; &lt;type-code&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * The argument specifies the representation type.
  -      */
  -     protected void doTYPE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // reset state variables
  -         resetState();
  -              
  -         // get type from argument
  -         char type = 'A';
  -         if (request.hasArgument()){
  -             type = request.getArgument().charAt(0);
  -         }
  -         
  -         // set it
  -         if (mUser.setType(type)) {
  -             write(out, mFtpStatus.getResponse(200, request, null));
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(504, request, null));
  -         }
  -     }
  -
  -
  -     /**
  -      * <code>USER &lt;SP&gt; &lt;username&gt; &lt;CRLF&gt;</code><br>
  -      *
  -      * The argument field is a Telnet string identifying the user.
  -      * The user identification is that which is required by the
  -      * server for access to its file system.  This command will
  -      * normally be the first command transmitted by the user after
  -      * the control connections are made.
  -      */
  -     protected void doUSER(FtpRequest request, Writer out) throws 
FtpException, IOException {
  -
  -         // set state variables
  -         resetState();
  -
  -         // argument check
  -         if(!request.hasArgument()) {
  -            write(out, mFtpStatus.getResponse(501, request, null));
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doSTOU(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // get filenames
  +        String fileName = 
mUser.getVirtualDirectory().getAbsoluteName("ftp.dat");
  +        String physicalName = 
mUser.getVirtualDirectory().getPhysicalName(fileName);
  +        File requestedFile = new File(physicalName);
  +        requestedFile = IoUtils.getUniqueFile(requestedFile);
  +        fileName = 
mUser.getVirtualDirectory().getVirtualName(requestedFile.getAbsolutePath());
  +        String args[] = {fileName};
  +        
  +        // check permission
  +        if(!mUser.getVirtualDirectory().hasCreatePermission(fileName, 
false)) {
  +            write(out, mFtpStatus.getResponse(550, request, mUser, null));
               return;
  -         }
  -
  -         // check user login status
  -         mbUser = true;
  -         if(mUser.hasLoggedIn()) {
  -             if(mUser.getName().equals(request.getArgument())) {
  -                 write(out, mFtpStatus.getResponse(230, request, null));
  -                 return;
  -             }
  -             else {
  -                 mUserHandler.closeConnection(mUser.getSessionId());
  -             }
  -         }
  -
  -         // set user name and send appropriate message
  -         mUser.setName(request.getArgument());
  -         if(mUser.getIsAnonymous()) {
  -             if(mCfg.isAnonymousLoginSupported()) {
  -                 FtpRequest anoRequest = new FtpRequest(mUser.getName());
  -                 write(out, mFtpStatus.getResponse(331, anoRequest, null));
  -             }
  -             else {
  -                 throw new FtpException(530);
  -             }
  -         }
  -         else {
  -             write(out, mFtpStatus.getResponse(331, request, null));
  -         }
  -     }
  +        }
  +        
  +        // now transfer file data
  +        write(out, mFtpStatus.getResponse(150, request, mUser, null));
  +        InputStream is = null;
  +        OutputStream os = null;
  +        try {
  +            Socket dataSoc = mDataCon.getDataSocket();
  +            is = dataSoc.getInputStream();
  +            os = mUser.getOutputStream( new FileOutputStream(requestedFile) 
);
  +            
  +            StreamConnector msc = new StreamConnector(is, os);
  +            msc.setMaxTransferRate(mUser.getMaxUploadRate());
  +            msc.setIsBuffered(true);
  +            msc.setObserver(this);
  +            msc.connect();
  +            
  +            if(msc.hasException()) {
  +                write(out, mFtpStatus.getResponse(451, request, mUser, 
null));
  +                return;
  +            }
  +            else {
  +                mCfg.getStatistics().setUpload(requestedFile, mUser, 
msc.getTransferredSize());
  +            }
  +            
  +            write(out, mFtpStatus.getResponse(226, request, mUser, null));
  +            mDataCon.reset();
  +            write(out, mFtpStatus.getResponse(250, request, mUser, args));
  +        }
  +        catch(IOException ex) {
  +            write(out, mFtpStatus.getResponse(425, request, mUser, null));
  +        }
  +        finally {
  +           IoUtils.close(is);
  +           IoUtils.close(os);
  +           mDataCon.reset(); 
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <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.
  +     */
  +    protected void doSTRU(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }
  +        
  +        if (mUser.setStructure(request.getArgument().charAt(0))) {
  +           write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +        }
  +        else {
  +             write(out, mFtpStatus.getResponse(504, request, mUser, null));
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>SYST &lt;CRLF&gt;</code><br> 
  +     *
  +     * This command is used to find out the type of operating
  +     * system at the server.
  +     */
  +    protected void doSYST(FtpRequest request, Writer out) throws IOException 
{
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        String args[] = {mCfg.getSystemName()};
  +        write(out, mFtpStatus.getResponse(215, request, mUser, args));
  +    }
  +    
  +    
  +    /**
  +     * <code>TYPE &lt;SP&gt; &lt;type-code&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * The argument specifies the representation type.
  +     */
  +    protected void doTYPE(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // reset state variables
  +        resetState();
  +        
  +        // get type from argument
  +        char type = 'A';
  +        if (request.hasArgument()){
  +             type = request.getArgument().charAt(0);
  +        }
  +        
  +        // set it
  +        if (mUser.setType(type)) {
  +           write(out, mFtpStatus.getResponse(200, request, mUser, null));
  +        }
  +        else {
  +             write(out, mFtpStatus.getResponse(504, request, mUser, null));
  +        }
  +    }
  +    
  +    
  +    /**
  +     * <code>USER &lt;SP&gt; &lt;username&gt; &lt;CRLF&gt;</code><br>
  +     *
  +     * The argument field is a Telnet string identifying the user.
  +     * The user identification is that which is required by the
  +     * server for access to its file system.  This command will
  +     * normally be the first command transmitted by the user after
  +     * the control connections are made.
  +     */
  +    protected void doUSER(FtpRequest request, Writer out) throws 
FtpException, IOException {
  +        
  +        // set state variables
  +        resetState();
  +        
  +        // argument check
  +        if(!request.hasArgument()) {
  +           write(out, mFtpStatus.getResponse(501, request, mUser, null));
  +           return;  
  +        }         
  +        
  +        // check user login status
  +        mbUser = true;
  +        if(mUser.hasLoggedIn()) {
  +            if(mUser.getName().equals(request.getArgument())) {
  +                write(out, mFtpStatus.getResponse(230, request, mUser, 
null));
  +                return;
  +            }
  +            else {
  +                
mCfg.getConnectionService().closeConnection(mUser.getSessionId());
  +            }
  +        }
   
  +        // set user name and send appropriate message
  +        mUser.setName(request.getArgument());
  +        if(mUser.getIsAnonymous()) {
  +            if(mCfg.isAnonymousLoginAllowed()) { 
  +                FtpRequest anoRequest = new FtpRequest(mUser.getName());
  +                write(out, mFtpStatus.getResponse(331, anoRequest, mUser, 
null));
  +            }
  +            else {
  +                throw new FtpException(530);
  +            }
  +        }
  +        else {
  +            write(out, mFtpStatus.getResponse(331, request, mUser, null));
  +        }
  +    }
   
  -     ///////////////////////////////////////////////////////////////
  -     static {
  -         DATE_FMT.setTimeZone(GMT_TZ);
  -     }
   }
  
  
  
  1.4       +28 -30    
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpDataConnection.java
  
  Index: FtpDataConnection.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpDataConnection.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- FtpDataConnection.java    14 Dec 2001 01:22:02 -0000      1.3
  +++ FtpDataConnection.java    6 Mar 2002 13:54:40 -0000       1.4
  @@ -8,9 +8,6 @@
   
   package org.apache.avalon.ftpserver;
   
  -import org.apache.avalon.ftpserver.services.FtpConfigService;
  -
  -import java.io.IOException;
   import java.net.Socket;
   import java.net.ServerSocket;
   import java.net.InetAddress;
  @@ -22,51 +19,51 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Rana Bhattacharyya</a>
    */
   class FtpDataConnection {
  -
  -    private FtpConfigService    mConfig  = null;
  +    
  +    private FtpConfig    mConfig  = null;
       private Socket       mDataSoc = null;
       private ServerSocket mServSoc = null;
       private InetAddress  mAddress = null;
       private int          miPort   = 0;
  -
  +    
       private boolean mbPort  = false;
       private boolean mbPasv  = false;
  -
  -
  +    
  +    
       /**
        * Constructor.
        * @param cfg ftp config object.
        */
  -    public FtpDataConnection(FtpConfigService cfg) {
  +    public FtpDataConnection(FtpConfig cfg) {
           mConfig = cfg;
       }
  -
  +    
       /**
        * Reset all the member variables. Close all sockets.
        */
       public void reset() {
  -
  +        
           // close data socket
           if(mDataSoc != null) {
               try { mDataSoc.close(); } catch(Exception ex) {}
               mDataSoc = null;
           }
  -
  +        
           // close server socket
           if(mServSoc != null) {
               try { mServSoc.close(); } catch(Exception ex) {}
               mServSoc = null;
           }
  -
  +        
           // reset other variables
           mAddress = null;
           miPort   = 0;
  -
  +        
           mbPort   = false;
           mbPasv   = false;
       }
  -
  -
  +     
  +     
       /**
        * Port command.
        */
  @@ -75,8 +72,8 @@
           mbPort = true;
           mAddress = addr;
           miPort = port;
  -    }
  -
  +    } 
  +    
       /**
        * Passive command.
        */
  @@ -93,7 +90,7 @@
               throw new FtpException(550);
           }
       }
  -
  +    
       /**
        * Listen for passive socket connection.
        */
  @@ -107,54 +104,55 @@
               throw new FtpException(425);
           }
       }
  -
  -
  +     
  +     
       /**
        * Get client address.
        */
       public InetAddress getInetAddress() {
           return mAddress;
       }
  -
  +     
       /**
        * Get port number.
        */
       public int getPort() {
           return miPort;
       }
  -
  +     
       /**
        * Get the data socket.
        */
       public Socket getDataSocket() throws FtpException {
  -
  +       
           // get socket depending on the selection
           if(mbPort) {
               try {
  -                mDataSoc = new Socket(mAddress, miPort);
  -                mDataSoc.setSoTimeout(60000);
  +                mDataSoc = new Socket(mAddress, miPort); 
  +                mDataSoc.setSoTimeout(60000);                  
               }
  -            catch(IOException ex) {
  +            catch(Exception ex) {
                   mDataSoc = null;
               }
           }
           else if(!mbPasv) {
               throw new FtpException(550);
           }
  -
  +        
           // result check
           if(mDataSoc == null) {
               throw new FtpException(550);
           }
  -
  +            
           return mDataSoc;
       }
  -
  +    
       /**
        * Last defense - close connections.
        */
       protected void finalize() throws Throwable {
           reset();
  +        super.finalize();
       }
   }
       
  
  
  
  1.2       +0 -1      
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpException.java
  
  Index: FtpException.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpException.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FtpException.java 28 Aug 2001 17:21:55 -0000      1.1
  +++ FtpException.java 6 Mar 2002 13:54:40 -0000       1.2
  @@ -39,5 +39,4 @@
       public String toString() {
           return String.valueOf(miFtpCode);
       }
  -
   }
  
  
  
  1.2       +50 -67    
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpRequest.java
  
  Index: FtpRequest.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpRequest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FtpRequest.java   28 Aug 2001 17:21:55 -0000      1.1
  +++ FtpRequest.java   6 Mar 2002 13:54:40 -0000       1.2
  @@ -8,100 +8,98 @@
   
   package org.apache.avalon.ftpserver;
   
  +import java.util.*;
   
   /**
  - * Ftp command request class. We can access command, line and argument using
  - * <code>{CMD}, {LINE}, {ARG}</code> within ftp status file. This represents
  + * Ftp command request class. We can access command, line and argument using 
  + * <code>{CMD}, {ARG}</code> within ftp status file. This represents 
    * single Ftp request.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Rana Bhattacharyya</a>
    */
   public
   class FtpRequest {
  -
  +    
       /**
        * Carriage return and new line.
        */
       private final static String CRLF = "\r\n";
  -
  +    
       /**
        * All supported ftp commands.
        */
       public final static String[] IMPLEMENTED_COMMANDS = {
           "ABOR",
  -        "APPE",
  +        "APPE",    
           "CDUP",
           "CWD",
  -        "DELE",
  -        "FEAT",    
  -        "HELP",
  +        "DELE",   
  +        "HELP",    
           "LIST",
  -        "MDTM",
  -        "MKD",
  -        "MLSD",    
  -        "MLST",    
  +        "MDTM",    
  +        "MKD",        
           "MODE",
  -        "NLST",
  +        "NLST",    
           "NOOP",
           "PASS",
  -        "PASV",
  +        "PASV",    
           "PORT",
           "PWD",
           "QUIT",
  -        "REST",
  +        "REST",    
           "RETR",
  -        "RMD",
  +        "RMD", 
           "RNFR",
           "RNTO",
  -        "SITE",
  -        "SIZE",
  -        "STAT",
  +        "SITE",    
  +        "SIZE", 
  +        "STAT",    
           "STOR",
  -        "STOU",
  +        "STOU",    
           "STRU",
           "SYST",
           "TYPE",
           "USER"
  -    };
  -
  +    }; 
  +    
       /**
        * These ftp commands are not implemented.
        */
       public final static String[] NON_IMPLEMENTED_COMMANDS = {
           "ACCT",
           "ALLO",
  +        "FEAT",
  +        "MLSD", 
  +        "MLST",
           "REIN",
  -        "SMNT",
  -    };
  -
  +        "SMNT", 
  +    }; 
  +    
       private String mstLine     = null;
       private String mstCommand  = null;
       private String mstArgument = null;
  -
  -
  +    
  +    
       /**
        * Constructor.
        *
        * @param commandLine ftp input command line.
        */
       public FtpRequest(String commandLine) throws FtpException {
  -
  +        
           if(commandLine == null) {
               throw new NullPointerException("Ftp command is null");
           }
  -
  -        mstLine = commandLine.trim();
  -        mstCommand = mstLine.toUpperCase();
  -
  +        
           // check command
           mstLine = commandLine.trim();
           if( mstLine.equals("") ) {
               throw new FtpException(500);
           }
  -
  +        
           parse();
       }
  -
  +     
       /**
        * Parse the ftp command line.
        */
  @@ -121,72 +119,73 @@
          }
       }
       
  -
  +    
       /**
        * Get the ftp command.
        */
       public String getCommand() {
           return mstCommand;
       }
  -
  +    
       /**
  -     * Get ftp input argument.
  -     */
  +     * Get ftp input argument.  
  +     */ 
       public String getArgument() {
           return mstArgument;
       }
  -
  +    
       /**
        * Get the ftp request line.
        */
       public String getCommandLine() {
           return mstLine;
       }
  -
  +    
       /**
        * Has argument.
        */
       public boolean hasArgument() {
           return getArgument() != null;
       }
  -
  -
  +    
  +    
       /**
        * Is an implemented ftp command?
        */
       public static boolean isImplementedFtpCommand(String cmd) {
  -
  +        
           // get the actual ftp command
           cmd = cmd.toUpperCase();
           if( (cmd.length()>0) && (cmd.charAt(0) == 'X') ) {
               cmd = cmd.substring(1);
           }
  -
  +        
           // now compare
           boolean bMatch = false;
  -        for(int i=0; i<IMPLEMENTED_COMMANDS.length; i++) {
  +        for(int i=IMPLEMENTED_COMMANDS.length; --i>=0; ) {
               if(IMPLEMENTED_COMMANDS[i].equals(cmd)) {
                   bMatch = true;
                   break;
               }
           }
  +
           return bMatch;
       }
  -
  +    
       /**
        * Is a non-implemented ftp command?
        */
       public static boolean isNonImplementedFtpCommand(String cmd) {
  -
  +        
           // get the actual ftp command
           cmd = cmd.toUpperCase();
           if( (cmd.length()>0) && (cmd.charAt(0) == 'X') ) {
               cmd = cmd.substring(1);
           }
  -
  +        
           // now compare
           boolean bMatch = false;
  -        for(int i=0; i<NON_IMPLEMENTED_COMMANDS.length; i++) {
  +        for(int i=NON_IMPLEMENTED_COMMANDS.length; --i>=0; ) {
               if(NON_IMPLEMENTED_COMMANDS[i].equals(cmd)) {
                   bMatch = true;
                   break;
  @@ -194,28 +193,12 @@
           }
           return bMatch;
       }
  -
  +     
       /**
        * Is it a ftp command (both implemented and non-implemented)?
        */
       public static boolean isFtpCommand(String cmd) {
           return isImplementedFtpCommand(cmd) || 
isNonImplementedFtpCommand(cmd);
       }
  -
  -
  -    /**
  -     * Check this command implementation.
  -     */
  -    public void implementationCheck() throws FtpException {
  -      if(!isImplementedFtpCommand(mstCommand)) {
  -          if(isNonImplementedFtpCommand(mstCommand)) {
  -              throw new FtpException(502);
  -          }
  -          else {
  -              throw new FtpException(500);
  -          }
  -      }
  -    }
  -
  +     
   }
  -
  
  
  
  1.3       +9 -16     
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpStatus.java
  
  Index: FtpStatus.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpStatus.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FtpStatus.java    8 Sep 2001 05:15:00 -0000       1.2
  +++ FtpStatus.java    6 Mar 2002 13:54:40 -0000       1.3
  @@ -9,14 +9,14 @@
   package org.apache.avalon.ftpserver;
   
   import java.io.*;
  -import java.util.*;
  +import java.util.Properties;
   
   /**
    * Ftp status line parser class. This class loads 
<code>FtpStatus.properties</code>
    * file from the classpath. It generates the descriptive ftp status for
    * astatus code. The actual response depends on the status code, the ftp
    * command and the passed argument list.
  - *
  + * 
    * @author <a href="mailto:[EMAIL PROTECTED]">Rana Bhattacharyya</a>
    */
   public
  @@ -27,7 +27,6 @@
       private final static String EMPTY    = "";
       private final static String CRLF     = "\r\n";
       
  -    private final static String LINE     = "LINE";
       private final static String CMD      = "CMD";
       private final static String ARG      = "ARG";
       
  @@ -44,7 +43,7 @@
       /**
        * Process ftp response new line character.
        */
  -    private String processNewLine(String msg, int status) {
  +    public String processNewLine(String msg, int status) {
           
           // no newline
           if(msg.indexOf('\n') == -1) {
  @@ -87,7 +86,7 @@
       /**
        * Get ftp message from the properties file and replace the variables.
        */
  -    private String getMessage(int status, FtpRequest cmdLine, List args) {
  +    private String getMessage(int status, FtpRequest cmdLine, String[] args) 
{
           
           // make the key from the passed parameters
           String key = PREFIX + status;
  @@ -137,7 +136,7 @@
       /**
        * Get variable value. 
        */
  -    private String getParam(FtpRequest cmdLine, List elm, String intStr) {
  +    private String getParam(FtpRequest cmdLine, String[] elms, String 
intStr) {
           
           // command line param
           if(cmdLine != null) {
  @@ -147,13 +146,10 @@
               if(intStr.equals(ARG)) {
                   return cmdLine.getArgument();
               }
  -            if(intStr.equals(LINE)) {
  -                return cmdLine.getCommandLine();
  -            }
           }
           
           // list param
  -        if(elm == null) {
  +        if(elms == null) {
               return EMPTY;
           }
           
  @@ -164,13 +160,10 @@
           catch(NumberFormatException ex) {
               return EMPTY;
           }
  -        if(elm == null) {
  -            return EMPTY;
  -        }
  -        if( (index < 0) || (index >= elm.size()) ) {
  +        if( (index < 0) || (index >= elms.length) ) {
               return EMPTY;
           }
  -        return elm.get(index).toString();
  +        return elms[index];
       }
       
       
  @@ -180,7 +173,7 @@
        * @param cmd ftp request object (may be null).
        * @param ars variable arguent list (may be null).
        */
  -    public String getResponse(int status, FtpRequest cmd, List args) {
  +    public String getResponse(int status, FtpRequest cmd, FtpUser user, 
String[] args) {
           String strRes = getMessage(status, cmd, args).trim();
           return processNewLine(strRes, status);
       }
  
  
  
  1.2       +64 -69    
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpStatus.properties
  
  Index: FtpStatus.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpStatus.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FtpStatus.properties      28 Aug 2001 17:21:55 -0000      1.1
  +++ FtpStatus.properties      6 Mar 2002 13:54:40 -0000       1.2
  @@ -2,42 +2,37 @@
   # Change if necessary
   # {CMD}  => FTP command
   # {ARG}  => FTP command argument
  -# {LINE} => FTP command line (including argument)
   # {n}    => the n-th element of the passed list    
  -FtpServer.status.110=Restart marker reply.
  -FtpServer.status.120=Service ready in {0} minutes.
  -FtpServer.status.125=Data connection already open; transfer starting.
  -FtpServer.status.150=File status okay; about to open data connection.
  +FtpServer.status.110=Restart marker reply
  +FtpServer.status.120=Service ready in {0} minutes
  +FtpServer.status.125=Data connection already open; transfer starting
  +FtpServer.status.150=File status okay; about to open data connection
  +        
  +FtpServer.status.200=Command {CMD} okay
  +FtpServer.status.200.CWD=Directory changed to {0}
  +FtpServer.status.200.CDUP=Directory changed to {0}
  +        
  +FtpServer.status.202=Command {CMD} not implemented, superfluous at this site
  +        
  +FtpServer.status.211=System status, or system help reply
  +FtpServer.status.211.STAT=FtpServer\nConnected to {0}\nConnected from 
{1}\nLogged in as {2}\nEnd of status
  +    
  +FtpServer.status.212=Directory status
           
  -FtpServer.status.200=Command {CMD} okay.
  -FtpServer.status.200.CWD=Directory changed to {0}.
  -FtpServer.status.200.CDUP=Directory changed to {0}.
  -        
  -FtpServer.status.202=Command {CMD} not implemented, superfluous at this site.
  -        
  -FtpServer.status.211=System status, or system help reply.
  -FtpServer.status.211.STAT=FtpServer\nConnected to {0}\nConnected from 
{1}\nLogged in as {2}\nEnd of status.
  -FtpServer.status.211.FEAT=Features\nMDTM\nMLST 
type*;size*;perm*;modify*;\nREST STREAM\nSIZE\nEnd of features.
  -        
  -FtpServer.status.212=Directory status.
  -        
  -FtpServer.status.213=File status.
  +FtpServer.status.213=File status
   FtpServer.status.213.SIZE={0}
   FtpServer.status.213.MDTM={0}
           
  -FtpServer.status.214=The following commands are implemented.\nABOR  APPE  
CDUP  CWD   DELE  FEAT  HELP  LIST  MDTM\nMLSD  MLST  MKD   MODE  NLST  NOOP  
PASS  PASV  PORT\nPWD   QUIT  REST  RETR  RMD   RNFR  RNTO  SITE  SIZE\nSTAT  
STOR  STOU  STRU  SYST  TYPE  USER\nEnd of help.
  +FtpServer.status.214=The following commands are implemented.\nABOR  APPE  
CDUP  CWD   DELE  HELP  LIST  MDTM\nMKD   MODE  NLST  NOOP  PASS  PASV  PORT  
PWD\nQUIT  REST  RETR  RMD   RNFR  RNTO  SITE  SIZE\nSTAT  STOR  STOU  STRU  
SYST  TYPE  USER\nEnd of help
           
   FtpServer.status.214.ABOR=Syntax: ABOR
   FtpServer.status.214.APPE=Syntax: APPE <sp> <pathname>
   FtpServer.status.214.CDUP=Syntax: CDUP
   FtpServer.status.214.CWD=Syntax: CWD <sp> <pathname>
  -FtpServer.status.214.DELE=Syntax: DELE <sp> <pathname>
  -FtpServer.status.214.FEAT=Syntax: FEAT    
  +FtpServer.status.214.DELE=Syntax: DELE <sp> <pathname>  
   FtpServer.status.214.HELP=Syntax: HELP [<sp> <string>]
   FtpServer.status.214.LIST=Syntax: LIST [<sp> <pathname>]
   FtpServer.status.214.MDTM=Syntax: MDTM <sp> <pathname>
  -FtpServer.status.214.MLSD=Syntax: MLSD [<sp> <pathname>]    
  -FtpServer.status.214.MLST=Syntax: MLST [<sp> <pathname>]    
   FtpServer.status.214.MKD=Syntax: MKD <sp> <pathname>
   FtpServer.status.214.MODE=Syntax: MODE <sp> <mode-code>
   FtpServer.status.214.NLST=Syntax: NLST [<sp> <pathname>]
  @@ -62,57 +57,57 @@
   FtpServer.status.214.UNKNOWN=Unknown command {0}
           
           
  -FtpServer.status.215={0} Type: org.apache.avalon.ftpserver.
  -FtpServer.status.220=Service ready for new user.
  -FtpServer.status.221=Service closing control connection.
  -FtpServer.status.225=Can't open data connection.
  -FtpServer.status.226=Closing data connection.
  -FtpServer.status.227.PASV=Entering Passive Mode ({0}).
  -FtpServer.status.230=User logged in, proceed.
  +FtpServer.status.215={0} Type: FtpServer
  +FtpServer.status.220=Service ready for new user
  +FtpServer.status.221=Service closing control connection
  +FtpServer.status.221.QUIT=Goodbye
  +FtpServer.status.225=Can't open data connection
  +FtpServer.status.226=Closing data connection
  +FtpServer.status.227.PASV=Entering Passive Mode ({0})
  +FtpServer.status.230=User logged in, proceed
           
  -FtpServer.status.250=Requested file action okay, completed.
  +FtpServer.status.250=Requested file action okay, completed
   FtpServer.status.250.STOU=Requested file action okay, completed. Generated 
file: {0}
  -FtpServer.status.250.MLST=Listing 
{0}\ntype={1};size={2};perm={3};modify={4}; {0}\nEnd of listing.
  -        
  -FtpServer.status.257.MKD=\"{0}\" created.
  -FtpServer.status.257.PWD=\"{0}\" is current directory.
  -FtpServer.status.257.PWD=\"{0}\" is current directory.
  -FtpServer.status.257.RMD=\"{0}\" deleted.
  -        
  -FtpServer.status.331=User name okay, need password for {ARG}.
  -FtpServer.status.331.ANONYMOUS=Guest login ok, send your complete e-mail 
address as password.
  -        
  -FtpServer.status.332=Need account for login.
  -        
  -FtpServer.status.350=Requested file action pending further information.
  -FtpServer.status.350.REST=Restarting at {ARG}. Send STORE or RETRIEVE to 
initiate transfer.
  -        
  -FtpServer.status.421=Service not available, closing control connection.
  -FtpServer.status.425=Can't open data connection.
  -FtpServer.status.426=Connection closed; transfer aborted.
  -FtpServer.status.431.CWD=No such directory.
  -FtpServer.status.450=Requested file action not taken.
  -FtpServer.status.451=Requested action aborted. Local error in processing.
  -FtpServer.status.452=Requested action not taken.
  -        
  -FtpServer.status.500=Syntax error, command {CMD} unrecognized.
  -        
  -FtpServer.status.501=Syntax error in parameters or arguments.
  -FtpServer.status.501.REST=\"{ARG}\" is not a valid argument.
  -FtpServer.status.501.MLST=\"{ARG}\" is not a valid pathname.
  -FtpServer.status.501.MLSD=\"{ARG}\" is not a valid directory.
  -        
  -FtpServer.status.502=Command {CMD} not implemented.
  -FtpServer.status.503=Bad sequence of commands.
  -FtpServer.status.504=Command {CMD} not implemented for that parameter.
  -FtpServer.status.521.MKD=\"{0}\" already exists.
  -FtpServer.status.530=Access denied.
  -FtpServer.status.532=Need account for storing files.
  +
  +FtpServer.status.257.MKD=\"{0}\" created
  +FtpServer.status.257.PWD=\"{0}\" is current directory
  +FtpServer.status.257.PWD=\"{0}\" is current directory
  +FtpServer.status.257.RMD=\"{0}\" deleted
  +        
  +FtpServer.status.331=User name okay, need password for {ARG}
  +FtpServer.status.331.ANONYMOUS=Guest login ok, send your complete e-mail 
address as password
  +        
  +FtpServer.status.332=Need account for login
  +        
  +FtpServer.status.350=Requested file action pending further information
  +FtpServer.status.350.REST=Restarting at {ARG}. Send STORE or RETRIEVE to 
initiate transfer
  +        
  +FtpServer.status.421=Service not available, closing control connection
  +FtpServer.status.425=Can't open data connection
  +FtpServer.status.426=Connection closed; transfer aborted
  +FtpServer.status.431.CWD=No such directory
  +FtpServer.status.450=Requested file action not taken
  +FtpServer.status.451=Requested action aborted. Local error in processing
  +FtpServer.status.452=Requested action not taken
  +        
  +FtpServer.status.500=Syntax error, command {CMD} unrecognized
  +        
  +FtpServer.status.501=Syntax error in parameters or arguments
  +FtpServer.status.501.REST=\"{ARG}\" is not a valid argument
  +FtpServer.status.501.MLST=\"{ARG}\" is not a valid pathname
  +FtpServer.status.501.MLSD=\"{ARG}\" is not a valid directory
  +    
  +FtpServer.status.502=Command {CMD} not implemented
  +FtpServer.status.503=Bad sequence of commands
  +FtpServer.status.504=Command {CMD} not implemented for that parameter
  +FtpServer.status.521.MKD=\"{0}\" already exists
  +FtpServer.status.530=Access denied
  +FtpServer.status.532=Need account for storing files
           
   FtpServer.status.550=Requested action not taken
   FtpServer.status.550.APPE=File {ARG} unavailable
   FtpServer.status.550.SIZE=File {ARG} unavailable
   FtpServer.status.550.MDTM=File {ARG} unavailable
           
  -FtpServer.status.552=Requested file action aborted.
  -FtpServer.status.553=Requested action not taken.
  +FtpServer.status.552=Requested file action aborted
  +FtpServer.status.553=Requested action not taken
  
  
  
  1.9       +23 -365   
jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpUser.java
  
  Index: FtpUser.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-apps/ftpserver/src/java/org/apache/avalon/ftpserver/FtpUser.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- FtpUser.java      30 Dec 2001 16:07:51 -0000      1.8
  +++ FtpUser.java      6 Mar 2002 13:54:40 -0000       1.9
  @@ -5,25 +5,14 @@
    * version 1.1, a copy of which has been included with this distribution in
    * the LICENSE file.
    */
  -
  + 
   package org.apache.avalon.ftpserver;
   
  -import java.io.InputStream;
   import java.io.OutputStream;
   import java.io.Serializable;
  -import java.net.Socket;
  -import java.net.InetAddress;
  -import java.rmi.server.UID;
   
  -import org.apache.avalon.ftpserver.util.StreamConnectorObserver;
  -import org.apache.avalon.ftpserver.util.AsciiInputStream;
   import org.apache.avalon.ftpserver.util.AsciiOutputStream;
  -import org.apache.avalon.ftpserver.util.Message;
  -import org.apache.avalon.ftpserver.util.VirtualDirectory;
  -import org.apache.avalon.ftpserver.interfaces.SpyUserInterface;
  -import org.apache.avalon.ftpserver.interfaces.FtpConnectionObserver;
  -import org.apache.avalon.ftpserver.interfaces.FtpConfig;
  -import org.apache.avalon.ftpserver.services.FtpConfigService;
  +import org.apache.avalon.ftpserver.usermanager.User;
   
   
   /**
  @@ -33,72 +22,24 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Rana Bhattacharyya</a>
    */
   public
  -class FtpUser implements StreamConnectorObserver, Serializable {
  -    
  -    public final static String ADMIN     = "admin";
  -    public final static String ANONYMOUS = "anonymous";
  -
  -    private transient Socket mSocket             = null;
  -    private transient FtpDataConnection mDataCon = null;
  -    private transient FtpConfigService mConfig          = null;
  +class FtpUser extends User implements Serializable {
       
  -    private transient SpyUserInterface mSpy           = null;
  -    private transient FtpConnectionObserver mObserver = null;
  -    private transient FtpUser mSelf                   = null;
  -
  -    private String mstSessionId   = null;
  -    private String mstUserName    = null;
  -    private String mstPassword    = null;
  -
  -    private long mlLoginTime         = 0;
  -    private long mlLastAccessTime    = 0;
  -    private long mlIdleTime          = 0; // infinite
  -    private int  miUploadRateLimit   = 0; // no limit
  -    private int  miDownloadRateLimit = 0; // no limit
  -
       private char mcDataType    = 'A';
       private char mcStructure   = 'F';
       private char mcMode        = 'S';
  -
  -    private boolean mbEnabled   = true;
  -    
  -     private VirtualDirectory mUserDirectory = null;
  -    private InetAddress mClientAddress      = null;
       
   
       /**
        * Constructor - does nothing.
        */
  -    public FtpUser(FtpConfigService cfg, Socket soc, FtpDataConnection 
dataCon) {
  -        mConfig = cfg;
  -        mSocket = soc;
  -        mDataCon = dataCon;
  -        if(mSocket != null) {
  -            mClientAddress = mSocket.getInetAddress();
  -        }
  -        mUserDirectory = new VirtualDirectory();
  -        if (mConfig != null) {
  -            setMaxIdleTime(mConfig.getMaxIdleTime());
  -        }
  -        mstSessionId = new UID().toString();
  -        mSelf = this;
  +    public FtpUser() {
       }
  -
  -    //////////////////////////////////////////////////
  -    /////////////    All Set Methods     /////////////
  -    //////////////////////////////////////////////////
  -    /**
  -     * Set user name.
  -     */
  -    public void setName(String name) {
  -        mstUserName = name;
  -    }
  -
  +    
       /**
  -     * Set user password
  +     * Get the user data type.
        */
  -    public void setPassword(String pass) {
  -        mstPassword = pass;
  +    public char getType() {
  +        return mcDataType;
       }
   
       /**
  @@ -116,6 +57,13 @@
   
   
       /**
  +     * Get the file structure.
  +     */
  +    public char getStructure() {
  +        return mcStructure;
  +    } 
  +   
  +    /**
        * Set the file structure. Supported structure type is F (file).
        * @return true if success
        */
  @@ -128,6 +76,14 @@
           return true;
       }
   
  +    
  +    /**
  +     * Get the transfer mode.
  +     */
  +    public char getMode() {
  +        return mcMode;
  +    }
  +    
       /**
        * Set the transfer type. Supported transfer type is S (stream).
        * @return true if success
  @@ -142,166 +98,6 @@
       }
   
       /**
  -     * Set the maximum idle time in second.
  -     */
  -    public void setMaxIdleTime(int idleSec) {
  -        if(idleSec < 0L) {
  -            mlIdleTime = 0L;
  -        }
  -        mlIdleTime = idleSec * 1000;
  -    }
  -
  -    /**
  -     * Set the user enable status
  -     */
  -    public void setEnabled(boolean enb) {
  -        mbEnabled = enb;
  -    }
  -
  -    /**
  -     * Set observer
  -     */
  -    public void setObserver(FtpConnectionObserver obsr) {
  -        mObserver = obsr;
  -    }
  -
  -    /**
  -     * Set the spy stream. This stream will be used to
  -     * write user request-response activities.
  -     */
  -    public void setSpyObject(SpyUserInterface spy) {
  -        mSpy = spy;
  -    }
  -
  -    /**
  -     * Set user maximum upload rate limit.
  -     * Less than or equal to zero means no limit.
  -     */
  -    public void setMaxUploadRate(int rate) {
  -        miUploadRateLimit = rate;
  -    }
  -
  -    /**
  -     * Set user maximum download rate limit.
  -     * Less than or equal to zero means no limit.
  -     */
  -    public void setMaxDownloadRate(int rate) {
  -        miDownloadRateLimit = rate;
  -    }
  -
  -    //////////////////////////////////////////////////
  -    /////////////    All Get Methods     /////////////
  -    //////////////////////////////////////////////////
  -    /**
  -     * Get the user name.
  -     */
  -    public String getName() {
  -        return mstUserName;
  -    }
  -
  -    /**
  -     * Get the user password.
  -     */
  -    public String getPassword() {
  -        return mstPassword;
  -    }
  -
  -    /**
  -     * Get the user data type.
  -     */
  -    public char getType() {
  -        return mcDataType;
  -    }
  -
  -    /**
  -     * Get the file structure.
  -     */
  -    public char getStructure() {
  -        return mcStructure;
  -    }
  -
  -    /**
  -     * Get the transfer mode.
  -     */
  -    public char getMode() {
  -        return mcMode;
  -    }
  -
  -    /**
  -     * Get remote address
  -     */
  -    public InetAddress getRemoteHost() {
  -        return mClientAddress;
  -    }
  -     
  -    /**
  -     * Get the maximum idle time in second.
  -     */
  -    public int getMaxIdleTime() {
  -        return (int)(mlIdleTime/1000);
  -    }
  -
  -    /**
  -     * Check the user login status.
  -     */
  -    public boolean hasLoggedIn() {
  -        return mlLoginTime != 0;
  -    }
  -
  -    /**
  -     * Get the user login time in millis.
  -     */
  -    public long getLoginTime() {
  -        return mlLoginTime;
  -    }
  -
  -    /**
  -     * Get the last access time in millis.
  -     */
  -    public long getLastAccessTime() {
  -        return mlLastAccessTime;
  -    }
  -
  -    /**
  -     * Get the user enable status.
  -     */
  -    public boolean getEnabled() {
  -        return mbEnabled;
  -    }
  -
  -    /**
  -     * Get the user control socket.
  -     */
  -    public Socket getSocket() {
  -        return mSocket;
  -    }
  -
  -    /**
  -     * Is an anonymous user?
  -     */
  -    public boolean getIsAnonymous() {
  -        return ANONYMOUS.equals(mstUserName);
  -    }
  -    
  -    /**
  -     * Is an admin user.
  -     */
  -    public boolean getIsAdmin() {
  -        return ADMIN.equals(mstUserName);
  -    }
  -
  -    /**
  -     * Get input stream. Returns <code>ftpsever.util.AsciiInputStream</code>
  -     * if necessary if the trasfer type is ASCII.
  -     */
  -    public InputStream getInputStream(InputStream is) {
  -        if(mcDataType == 'A') {
  -            is = new AsciiInputStream(is);
  -        }
  -        return is;
  -    }
  -
  -    /**
        * Get output stream. Returns 
<code>ftpserver.util.AsciiOutputStream</code>
        * if the transfer type is ASCII.
        */
  @@ -311,144 +107,6 @@
           }
           return os;
       }
  -
  -    /**
  -     * Get the spy stream.
  -     */
  -    public SpyUserInterface getSpyObject() {
  -        return mSpy;
  -    }
  -
  -    /**
  -     * Get maximum user upload rate in bytes/sec.
  -     */
  -    public int getMaxUploadRate() {
  -        return miUploadRateLimit;
  -    }
  -
  -    /**
  -     * Get maximum user download rate in bytes/sec
  -     */
  -    public int getMaxDownloadRate() {
  -        return miDownloadRateLimit;
  -    }
  -
  -    /**
  -     * Get login session id
  -     */
  -    public String getSessionId() {
  -        return mstSessionId;
  -    }
  -     
  -    /**
  -     * get user filesystem view
  -     */
  -    public VirtualDirectory getVirtualDirectory() {
  -     return mUserDirectory;
  -    }
  -    
  -    /////////////////////////////////////////////
  -    /////////////// Other Methods ///////////////
  -    /////////////////////////////////////////////
  -    /**
  -     * User login.
  -     */
  -     public void login() {
  -        mlLoginTime = System.currentTimeMillis();
  -        mlLastAccessTime = mlLoginTime;
  -     }
  -
  -    /**
  -     * User logout.
  -     */
  -     public void logout() {
  -         
  -         // close control socket
  -         if(mSocket!=null) {
  -           try {mSocket.close();} catch(Exception ex) {}
  -           mSocket = null;
  -         }
  -
  -         // close data socket
  -         if(mDataCon != null) {
  -             mDataCon.reset();
  -             mDataCon = null;
  -         }
  -         
  -         mlLoginTime = 0;
  -         mObserver = null;
  -     }
  -
  -     /**
  -      * Hit user. Update last access time.
  -      */
  -     public void hitUser() {
  -        mlLastAccessTime = System.currentTimeMillis();
  -        if(mObserver != null) {
  -             mConfig.getMessageQueue().add(new Message() {
  -                public void execute() {
  -                    try {
  -                        mObserver.updateConnection(mstSessionId);
  -                    }
  -                    catch(Exception ex) {
  -                        mSelf.setObserver(null);
  -                    }
  -                }
  -            });
  -        }
  -     }
  -
  -
  -     /**
  -      * Is an active user (is removable).
  -      * Compares the last access time with the specified time.
  -      */
  -     public boolean isActive(long currTime) {
  -         boolean bActive = true;
  -         if(mlIdleTime != 0L) {
  -            long idleTime = currTime - mlLastAccessTime;
  -            bActive = mlIdleTime > idleTime;
  -         }
  -         return bActive;
  -     }
  -
  -     /**
  -      * Is still active. Compares the last access time with the
  -      * current time.
  -      */
  -     public boolean isActive() {
  -         return isActive(System.currentTimeMillis());
  -     }
  -
  -
  -     /**
  -      * This method tracks data transfer.
  -      */
  -     public void dataTransferred(int sz) {
  -         hitUser();
  -     }
  -
  -     /**
  -      * String representation - user name
  -      */
  -     public String toString() {
  -         String retVal = "";
  -         if(mstUserName != null) {
  -             retVal = mstUserName;
  -         }
  -         return retVal;
  -     }
  -
  -     
  -    /**
  -     * Equality check.
  -     */
  -    public boolean equals(Object obj) {
  -        if (obj instanceof FtpUser) {
  -            return ((FtpUser)obj).mstSessionId.equals(mstSessionId);
  -        }
  -        return false;
  -    } 
   }
   
   
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to