You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ftpserver-commits@incubator.apache.org by ng...@apache.org on 2007/01/11 22:46:42 UTC

svn commit: r495421 [1/2] - in /incubator/ftpserver/trunk/core: ./ src/java/org/apache/ftpserver/ src/java/org/apache/ftpserver/command/ src/java/org/apache/ftpserver/ftplet/ src/java/org/apache/ftpserver/interfaces/ src/java/org/apache/ftpserver/liste...

Author: ngn
Date: Thu Jan 11 14:46:41 2007
New Revision: 495421

URL: http://svn.apache.org/viewvc?view=rev&rev=495421
Log:
Adding a MINA based listener. Also contains a lot of other changes needed for this implementation.
MINA listener is still not the default due to it not yet supporting SSL/TLS fully.

Added:
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/MinaConnection.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/MinaFtpProtocolHandler.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/MinaFtpResponseOutput.java   (with props)
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/MinaListener.java   (with props)
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/FtpResponseImplTest.java   (with props)
Modified:
    incubator/ftpserver/trunk/core/pom.xml
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpRequestImpl.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpServer.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpSessionImpl.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpStatisticsImpl.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpWriter.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/AUTH.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/EPRT.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PORT.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_DESCUSER.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_STAT.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_WHO.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_ZONE.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/USER.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ftplet/DefaultFtpletContainer.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/interfaces/Ssl.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/Connection.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/ConnectionManagerImpl.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOConnection.java
    incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ssl/DefaultSsl.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/FtpLetContainerTestTemplate.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/FtpLetReturnDefaultTest.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/FtpLetReturnDisconnectTest.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/FtpLetReturnSkipTest.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/MockFtplet.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/ftplet/MockFtpletCallback.java
    incubator/ftpserver/trunk/core/src/test/org/apache/ftpserver/interfaces/ServerFtpStatisticsTestTemplate.java

Modified: incubator/ftpserver/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/pom.xml?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/pom.xml (original)
+++ incubator/ftpserver/trunk/core/pom.xml Thu Jan 11 14:46:41 2007
@@ -128,6 +128,21 @@
 
         <!--Only used for testing -->
         <dependency>
+	      <groupId>org.slf4j</groupId>
+	      <artifactId>slf4j-jcl</artifactId>
+	      <version>1.1.0</version>
+	    </dependency>
+        <dependency>
+	      <groupId>org.apache.mina</groupId>
+	      <artifactId>mina-core</artifactId>
+	      <version>1.0.1</version>
+	    </dependency>
+        <dependency>
+	      <groupId>org.apache.mina</groupId>
+	      <artifactId>mina-filter-ssl</artifactId>
+	      <version>1.0.1</version>
+	    </dependency>
+        <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>${log4j-version}</version>

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpRequestImpl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpRequestImpl.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpRequestImpl.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpRequestImpl.java Thu Jan 11 14:46:41 2007
@@ -33,7 +33,6 @@
     
     private ConnectionObserver observer;
 
-    
     /**
      * Default constructor.
      */
@@ -104,9 +103,16 @@
 
     /**
      * Has argument.
-     * TODO: should be in interface?
      */
     public boolean hasArgument() {
         return getArgument() != null;
+    }
+
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return getRequestLine();
     }
 }

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */  
+
+package org.apache.ftpserver;
+
+import org.apache.ftpserver.ftplet.FtpResponse;
+
+/**
+ * FTP request object.
+ */
+public class FtpResponseImpl implements FtpResponse {
+    
+    private int code;
+    private String message;
+    private final static String CRLF     = "\r\n";
+    /**
+     * @param code
+     * @param message
+     */
+    public FtpResponseImpl(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+    /**
+     * @return the code
+     */
+    public int getCode() {
+        return code;
+    }
+    /**
+     * @return the message
+     */
+    public String getMessage() {
+        return message;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        String notNullMessage = message;
+        if(notNullMessage == null) {
+            notNullMessage = "";
+        }
+        
+        StringBuffer sb = new StringBuffer();
+
+        // no newline
+        if (notNullMessage.indexOf('\n') == -1) {
+            sb.append(code);
+            sb.append(" ");
+            sb.append(notNullMessage);
+            sb.append(CRLF);
+        } else {
+            String[] lines = notNullMessage.split("\n");
+            
+            sb.append(code);
+            sb.append("-");
+
+            for (int i = 0; i < lines.length; i++) {
+                String line = lines[i].trim();
+                
+                if(i + 1 == lines.length) {
+                    sb.append(code);
+                    sb.append(" ");
+                }
+                
+                sb.append(line);
+                sb.append(CRLF);
+            }
+            
+        }
+        
+        return sb.toString();
+    }
+    
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpResponseImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpServer.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpServer.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpServer.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpServer.java Thu Jan 11 14:46:41 2007
@@ -50,13 +50,14 @@
 
     /**
      * Constructor. Set the server object.
+     * @throws Exception 
      */
-    public FtpServer(FtpServerContext ftpConfig) {
-        this.serverContext = ftpConfig;
+    public FtpServer(FtpServerContext serverContext) throws Exception {
+        this.serverContext = serverContext;
         log = this.serverContext.getLogFactory().getInstance(getClass());
 
         // for now just create one 
-        listeners.add(new IOListener(ftpConfig));
+        listeners.add(new IOListener(serverContext));
     }
 
     /**

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpSessionImpl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpSessionImpl.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpSessionImpl.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpSessionImpl.java Thu Jan 11 14:46:41 2007
@@ -24,6 +24,7 @@
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.security.cert.Certificate;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.zip.DeflaterOutputStream;
@@ -51,8 +52,8 @@
     private User user;
     private HashMap attributeMap;
     private InetAddress remoteAddr;
-    private ConnectionObserver observer;
     private String language;
+    private Certificate[] clientCertificates;
     
     private int maxIdleTime = 0;
     private long connectionTime = 0L;
@@ -94,13 +95,6 @@
     }
     
     /**
-     * Get the observer object to get what the user is sending.
-     */
-    public void setObserver(ConnectionObserver observer) {
-        this.observer = observer;
-    } 
-    
-    /**
      * Reset temporary state variables.
      */
     public void resetState() {
@@ -119,16 +113,7 @@
         renameFrom = null;
         fileOffset = 0L;
     }
-    
-    /**
-     * Spy print. Monitor user request.
-     */
-    private void spyRequest(String str) {
-        ConnectionObserver observer = this.observer;
-        if(observer != null) {
-            observer.request(str + "\r\n");
-        }
-    }
+
     
     /**
      * Set login attribute & user file system view.
@@ -267,7 +252,7 @@
     /**
      * Get remote address
      */
-    public InetAddress getRemoteAddress() {
+    public InetAddress getClientAddress() {
         return remoteAddr;
     }
     
@@ -414,5 +399,13 @@
      */
     public void setStructure(Structure stru) {
         structure = stru;
+    }
+    
+    public Certificate[] getClientCertificates() {
+        return clientCertificates;
+    }
+    
+    public void setClientCertificates(Certificate[] certificates) {
+        this.clientCertificates = certificates;
     }
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpStatisticsImpl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpStatisticsImpl.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpStatisticsImpl.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpStatisticsImpl.java Thu Jan 11 14:46:41 2007
@@ -335,15 +335,15 @@
             userLoginTable.put(user.getName(), statisticsTable);
             //new login, put 1 in the login number
             statisticsTable.put(LOGIN_NUMBER, new Integer(1));
-            statisticsTable.put(connection.getSession().getRemoteAddress().getHostAddress(), new Integer(1));
+            statisticsTable.put(connection.getSession().getClientAddress().getHostAddress(), new Integer(1));
           } else{
             Integer loginNumber = (Integer) statisticsTable.get(LOGIN_NUMBER);
             statisticsTable.put(LOGIN_NUMBER, new Integer(loginNumber.intValue() + 1));
-            Integer loginNumberPerIP = (Integer) statisticsTable.get(connection.getSession().getRemoteAddress().getHostAddress());
+            Integer loginNumberPerIP = (Integer) statisticsTable.get(connection.getSession().getClientAddress().getHostAddress());
             if(loginNumberPerIP == null){//new connection from this ip
-              statisticsTable.put(connection.getSession().getRemoteAddress().getHostAddress(), new Integer(1));
+              statisticsTable.put(connection.getSession().getClientAddress().getHostAddress(), new Integer(1));
             } else{//this ip has connections already
-              statisticsTable.put(connection.getSession().getRemoteAddress().getHostAddress(), new Integer(loginNumberPerIP.intValue() + 1));
+              statisticsTable.put(connection.getSession().getClientAddress().getHostAddress(), new Integer(loginNumberPerIP.intValue() + 1));
             }
           }
         }
@@ -373,13 +373,13 @@
           Hashtable statisticsTable = (Hashtable) userLoginTable.get(user.getName());
           Integer loginNumber = (Integer) statisticsTable.get(LOGIN_NUMBER);
           statisticsTable.put(LOGIN_NUMBER, new Integer(loginNumber.intValue() - 1));
-          Integer loginNumberPerIP = (Integer) statisticsTable.get(connection.getSession().getRemoteAddress().getHostAddress());
+          Integer loginNumberPerIP = (Integer) statisticsTable.get(connection.getSession().getClientAddress().getHostAddress());
           if(loginNumberPerIP != null){//this should always be true
             if(loginNumberPerIP.intValue() <= 1){//the last login from this ip, remove this ip address
-              statisticsTable.remove(connection.getSession().getRemoteAddress().getHostAddress());
+              statisticsTable.remove(connection.getSession().getClientAddress().getHostAddress());
             }
           } else{//this ip has other logins, reduce the number
-            statisticsTable.put(connection.getSession().getRemoteAddress().getHostAddress(), new Integer(loginNumberPerIP.intValue() - 1));
+            statisticsTable.put(connection.getSession().getClientAddress().getHostAddress(), new Integer(loginNumberPerIP.intValue() - 1));
           }
         }
         
@@ -508,7 +508,7 @@
     private void notifyLoginFail(Connection connection) {
         StatisticsObserver observer = this.observer;
         if (observer != null) {
-            observer.notifyLoginFail(connection.getSession().getRemoteAddress());
+            observer.notifyLoginFail(connection.getSession().getClientAddress());
         }
     }
     

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpWriter.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpWriter.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpWriter.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/FtpWriter.java Thu Jan 11 14:46:41 2007
@@ -19,36 +19,27 @@
 
 package org.apache.ftpserver;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.StringReader;
-import java.io.Writer;
 import java.net.InetAddress;
-import java.net.Socket;
 
 import org.apache.commons.logging.Log;
 import org.apache.ftpserver.ftplet.FileSystemView;
 import org.apache.ftpserver.ftplet.FtpRequest;
-import org.apache.ftpserver.ftplet.FtpResponse;
+import org.apache.ftpserver.ftplet.FtpResponseOutput;
 import org.apache.ftpserver.ftplet.FtpSession;
 import org.apache.ftpserver.ftplet.FtpStatistics;
 import org.apache.ftpserver.interfaces.FtpServerContext;
 import org.apache.ftpserver.interfaces.MessageResource;
 import org.apache.ftpserver.listener.ConnectionObserver;
 import org.apache.ftpserver.util.DateUtils;
-import org.apache.ftpserver.util.IoUtils;
 
 /**
  * FTP response object. The server uses this to send server messages
  *
  * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
  */
-public 
-class FtpWriter implements FtpResponse {
+public abstract class FtpWriter implements FtpResponseOutput {
 
-    private final static String CRLF     = "\r\n";
-    
     ///////////////////////// All Server Vatiables /////////////////////////
     public static final String SERVER_IP   = "server.ip";
     public static final String SERVER_PORT = "server.port";
@@ -92,22 +83,10 @@
     
     /////////////////////////////////////////////////////////////////////////////
     
-    private Log log;
-    private Writer writer;
+    protected Log log;
     private ConnectionObserver observer;
     private FtpServerContext serverContext;
     private FtpSession session;
-    private InetAddress serverAddress;
-
-        
-    /**
-     * Set the control socket.
-     */
-    public void setControlSocket(Socket soc) throws IOException {
-        serverAddress = soc.getLocalAddress();
-        writer = new OutputStreamWriter(soc.getOutputStream(), "UTF-8");
-    }
-    
     /**
      * Set ftp config.
      */
@@ -133,7 +112,7 @@
     /**
      * Spy print. Monitor server response.
      */
-    private void spyResponse(String str) {
+    protected void spyResponse(String str) {
         ConnectionObserver observer = this.observer;
         if(observer != null) {
             observer.response(str);
@@ -156,77 +135,8 @@
             msg = "";
         }
         msg = replaceVariables(code, basicMsg, msg);
-        write(code, msg);
-    }
-
-    /**
-     * Send the ftp server reply code to client.
-     */
-    public void write(int code) throws IOException {
-        write(code, null);
-    }
-    
-    /**
-     * Send the ftp code and message to client
-     */
-    public void write(int code, String msg) throws IOException {
-        if(msg == null) {
-            msg = "";
-        }
-        
-        msg = processNewLine(code, msg);
-        spyResponse(msg);
-        writer.write(msg);
-        writer.flush();
-    }
-    
-    /**
-     * Close writer.
-     */
-    public void close() {
-        IoUtils.close(writer);
-    }
-    
-    /**
-     * Process ftp response new line character.
-     */
-    private String processNewLine(int code, String msg) {
-        
-        // no newline
-        if(msg.indexOf('\n') == -1) {
-            return code + " " + msg + CRLF;
-        }
-        
-        StringBuffer buff = new StringBuffer(256);
-        try {
-            BufferedReader sr = new BufferedReader(new StringReader(msg));
         
-            buff.append(code);
-            buff.append('-');
-        
-            String line = sr.readLine();
-            for(;;) {
-                String nextLine = sr.readLine();    
-            
-                if(nextLine != null) {
-                    buff.append(line);
-                    buff.append(CRLF);
-                }
-                else {
-                    buff.append(code);
-                    buff.append(' ');
-                    buff.append(line);
-                    buff.append(CRLF);
-                    break;
-                }
-                line = nextLine;
-            }
-            sr.close();
-        }
-        catch(IOException ex) {
-            log.debug("Exception creating output line", ex);
-        }
-        return buff.toString();
+        write(new FtpResponseImpl(code, msg));
     }
     
     /**
@@ -306,6 +216,8 @@
         return varVal;
     } 
     
+    protected abstract InetAddress getFallbackServerAddress();
+    
     /**
      * Get server variable value.
      */
@@ -317,9 +229,11 @@
         if(varName.equals(SERVER_IP)) {
             InetAddress addr = serverContext.getDataConnectionConfig().getPassiveAddress();
             if(addr == null) {
-                addr = serverAddress;
+                addr = getFallbackServerAddress();
+            }
+            if(addr != null) {
+                varVal = addr.getHostAddress();
             }
-            varVal = addr.getHostAddress();
         }
         
         // server port
@@ -530,7 +444,7 @@
         
         // client ip
         if(varName.equals(CLIENT_IP)) {
-            varVal = session.getRemoteAddress().getHostAddress();
+            varVal = session.getClientAddress().getHostAddress();
         }
         
         // client connection time
@@ -572,4 +486,6 @@
         }
         return varVal; 
     }
+    
+    public abstract void close();
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/AUTH.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/AUTH.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/AUTH.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/AUTH.java Thu Jan 11 14:46:41 2007
@@ -68,7 +68,7 @@
         if(authType.equals("SSL")) {
             out.send(234, "AUTH.SSL", null);
             try {
-                connection.createSecureSocket("SSL");
+                connection.secureControlChannel("SSL");
             }
             catch(FtpException ex) {
                 throw ex;
@@ -81,7 +81,7 @@
         else if(authType.equals("TLS")) {
             out.send(234, "AUTH.TLS", null);
             try {
-                connection.createSecureSocket("TLS");
+                connection.secureControlChannel("TLS");
             }
             catch(FtpException ex) {
                 throw ex;

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/EPRT.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/EPRT.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/EPRT.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/EPRT.java Thu Jan 11 14:46:41 2007
@@ -95,7 +95,7 @@
         
         // check IP
         if(dataCfg.isActiveIpCheck()) {
-            InetAddress clientAddr = session.getRemoteAddress();
+            InetAddress clientAddr = session.getClientAddress();
             if(!dataAddr.equals(clientAddr)) {
                 out.send(510, "EPRT.mismatch", null);
                 return;

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PASS.java Thu Jan 11 14:46:41 2007
@@ -20,10 +20,6 @@
 package org.apache.ftpserver.command;
 
 import java.io.IOException;
-import java.net.Socket;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSocket;
 
 import org.apache.commons.logging.Log;
 import org.apache.ftpserver.FtpSessionImpl;
@@ -120,18 +116,8 @@
             User authenticatedUser = null;
             try {
                 UserMetadata userMetadata = new UserMetadata();
-                Socket controlSocket = connection.getControlSocket();
-                userMetadata.setInetAddress(controlSocket.getInetAddress());
-                
-                if(controlSocket instanceof SSLSocket) {
-                    SSLSocket sslControlSocket = (SSLSocket) controlSocket;
-                    
-                    try {
-                        userMetadata.setCertificateChain(sslControlSocket.getSession().getPeerCertificates());
-                    } catch(SSLPeerUnverifiedException e) {
-                        // ignore, certificate will not be available to UserManager
-                    }
-                }
+                userMetadata.setInetAddress(session.getClientAddress());
+                userMetadata.setCertificateChain(session.getClientCertificates());
                 
                 Authentication auth;
                 if(anonymous) {

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PORT.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PORT.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PORT.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/PORT.java Thu Jan 11 14:46:41 2007
@@ -98,7 +98,7 @@
         
         // check IP
         if(dataCfg.isActiveIpCheck()) {
-            InetAddress clientAddr = session.getRemoteAddress();
+            InetAddress clientAddr = session.getClientAddress();
             if(!dataAddr.equals(clientAddr)) {
                 out.send(510, "PORT.mismatch", null);
                 return;

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_DESCUSER.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_DESCUSER.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_DESCUSER.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_DESCUSER.java Thu Jan 11 14:46:41 2007
@@ -21,6 +21,7 @@
 
 import java.io.IOException;
 
+import org.apache.ftpserver.FtpResponseImpl;
 import org.apache.ftpserver.FtpSessionImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.ftplet.FtpException;
@@ -107,7 +108,7 @@
             sb.append("downloadrate    : 0\n");
         }
         sb.append('\n');
-        out.write(200, sb.toString());
+        out.write(new FtpResponseImpl(200, sb.toString()));
     }
 
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_STAT.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_STAT.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_STAT.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_STAT.java Thu Jan 11 14:46:41 2007
@@ -21,6 +21,7 @@
 
 import java.io.IOException;
 
+import org.apache.ftpserver.FtpResponseImpl;
 import org.apache.ftpserver.FtpSessionImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.ftplet.FtpException;
@@ -76,7 +77,7 @@
         sb.append("Current Connections      : ").append( stat.getCurrentConnectionNumber() ).append('\n');
         sb.append("Total Connections        : ").append( stat.getTotalConnectionNumber() ).append('\n');
         sb.append('\n');
-        out.write(200, sb.toString());
+        out.write(new FtpResponseImpl(200, sb.toString()));
     }
     
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_WHO.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_WHO.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_WHO.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_WHO.java Thu Jan 11 14:46:41 2007
@@ -23,6 +23,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.ftpserver.FtpResponseImpl;
 import org.apache.ftpserver.FtpSessionImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.ftplet.FtpException;
@@ -76,13 +77,13 @@
             
             User tmpUsr = tmpReq.getUser();
             sb.append( StringUtils.pad(tmpUsr.getName(), ' ', true, 16) );
-            sb.append( StringUtils.pad(tmpReq.getRemoteAddress().getHostAddress(), ' ', true, 16) );
+            sb.append( StringUtils.pad(tmpReq.getClientAddress().getHostAddress(), ' ', true, 16) );
             sb.append( StringUtils.pad(DateUtils.getISO8601Date(tmpReq.getLoginTime().getTime()), ' ', true, 20) );
             sb.append( StringUtils.pad(DateUtils.getISO8601Date(tmpReq.getLastAccessTime().getTime()), ' ', true, 20) );
             sb.append('\n');
         }
         sb.append('\n');
-        out.write(200, sb.toString());
+        out.write(new FtpResponseImpl(200, sb.toString()));
     }
 
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_ZONE.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_ZONE.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_ZONE.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/SITE_ZONE.java Thu Jan 11 14:46:41 2007
@@ -23,6 +23,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
+import org.apache.ftpserver.FtpResponseImpl;
 import org.apache.ftpserver.FtpSessionImpl;
 import org.apache.ftpserver.FtpWriter;
 import org.apache.ftpserver.ftplet.FtpException;
@@ -52,6 +53,6 @@
         
         // send timezone data
         String timezone = TIMEZONE_FMT.format(new Date());
-        out.write(200, timezone);
+        out.write(new FtpResponseImpl(200, timezone));
     }
 }

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/USER.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/USER.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/USER.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/command/USER.java Thu Jan 11 14:46:41 2007
@@ -113,7 +113,7 @@
                 
                 ConcurrentLoginRequest loginRequest = new  ConcurrentLoginRequest(
                         stat.getCurrentUserLoginNumber(configUser) + 1,
-                        stat.getCurrentUserLoginNumber(configUser, session.getRemoteAddress()) + 1);
+                        stat.getCurrentUserLoginNumber(configUser, session.getClientAddress()) + 1);
                 
                 if(configUser.authorize(loginRequest) == null) {
                     out.send(421, "USER.login", null);

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ftplet/DefaultFtpletContainer.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ftplet/DefaultFtpletContainer.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ftplet/DefaultFtpletContainer.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/ftplet/DefaultFtpletContainer.java Thu Jan 11 14:46:41 2007
@@ -126,7 +126,7 @@
     /**
      * Call ftplet onConnect.
      */
-    public FtpletEnum onConnect(FtpSession session, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onConnect(FtpSession session, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -147,7 +147,7 @@
     /**
      * Call ftplet onDisconnect.
      */
-    public FtpletEnum onDisconnect(FtpSession session, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onDisconnect(FtpSession session, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -168,7 +168,7 @@
     /**
      * Call ftplet onLogin.
      */
-    public FtpletEnum onLogin(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onLogin(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -189,7 +189,7 @@
     /** 
      * Call ftplet onDeleteStart.
      */
-    public FtpletEnum onDeleteStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onDeleteStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -211,7 +211,7 @@
     /**
      * Call ftplet onDeleteEnd.
      */
-    public FtpletEnum onDeleteEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onDeleteEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -232,7 +232,7 @@
     /**
      * Call ftplet onUploadStart.
      */
-    public FtpletEnum onUploadStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onUploadStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -253,7 +253,7 @@
     /**
      * Call ftplet onUploadEnd.
      */
-    public FtpletEnum onUploadEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onUploadEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -274,7 +274,7 @@
     /**
      * Call ftplet onDownloadStart.
      */
-    public FtpletEnum onDownloadStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onDownloadStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -295,7 +295,7 @@
     /**
      * Call ftplet onDownloadEnd.
      */
-    public FtpletEnum onDownloadEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onDownloadEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -316,7 +316,7 @@
     /**
      * Call ftplet onRmdirStart.
      */
-    public FtpletEnum onRmdirStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onRmdirStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -337,7 +337,7 @@
     /**
      * Call ftplet onRmdirEnd.
      */
-    public FtpletEnum onRmdirEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onRmdirEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -358,7 +358,7 @@
     /**
      * Call ftplet onMkdirStart.
      */
-    public FtpletEnum onMkdirStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onMkdirStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -379,7 +379,7 @@
     /** 
      * Call ftplet onMkdirEnd.
      */
-    public FtpletEnum onMkdirEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onMkdirEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -400,7 +400,7 @@
     /**
      * Call ftplet onAppendStart.
      */
-    public FtpletEnum onAppendStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onAppendStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -421,7 +421,7 @@
     /**
      * Call ftplet onAppendEnd.
      */
-    public FtpletEnum onAppendEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onAppendEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -442,7 +442,7 @@
     /**
      * Call ftplet onUploadUniqueStart.
      */
-    public FtpletEnum onUploadUniqueStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onUploadUniqueStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -463,7 +463,7 @@
     /**
      * Call ftplet onUploadUniqueEnd.
      */
-    public FtpletEnum onUploadUniqueEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onUploadUniqueEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -484,7 +484,7 @@
     /**
      * Call ftplet onRenameStart.
      */
-    public FtpletEnum onRenameStart(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onRenameStart(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -505,7 +505,7 @@
     /**
      * Call ftplet onRenameEnd.
      */
-    public FtpletEnum onRenameEnd(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onRenameEnd(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {
@@ -526,7 +526,7 @@
     /**
      * Call ftplet onSite.
      */
-    public FtpletEnum onSite(FtpSession session, FtpRequest request, FtpResponse response) throws FtpException, IOException {
+    public FtpletEnum onSite(FtpSession session, FtpRequest request, FtpResponseOutput response) throws FtpException, IOException {
         FtpletEnum retVal = FtpletEnum.RET_DEFAULT;
         int sz = ftplets.size();
         for(int i=0; i<sz; ++i) {

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/interfaces/Ssl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/interfaces/Ssl.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/interfaces/Ssl.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/interfaces/Ssl.java Thu Jan 11 14:46:41 2007
@@ -22,6 +22,9 @@
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
 
 import org.apache.ftpserver.ftplet.Component;
 
@@ -32,7 +35,13 @@
  */
 public 
 interface Ssl extends Component {
-
+    
+    SSLContext getSSLContext() throws GeneralSecurityException;
+    SSLContext getSSLContext(String protocol) throws GeneralSecurityException;
+    
+    boolean getClientAuthenticationRequired();
+    
+    
     /**
      * Create secure server socket.
      */

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */  
+
+package org.apache.ftpserver.listener;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.ftpserver.FtpSessionImpl;
+import org.apache.ftpserver.ftplet.DataType;
+import org.apache.ftpserver.ftplet.FtpSession;
+import org.apache.ftpserver.interfaces.FtpServerContext;
+import org.apache.ftpserver.util.IoUtils;
+
+
+/**
+ * This is a generic request handler. It delegates 
+ * the request to appropriate method in subclass.
+ *
+ * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
+ */
+public abstract class AbstractConnection implements Connection {
+    
+    protected FtpServerContext serverContext;
+    protected Log log;
+    
+    protected FtpSessionImpl ftpSession;
+    private ConnectionObserver observer;
+    
+    
+    /**
+     * Spy print. Monitor user request.
+     */
+    protected void spyRequest(String str) {
+        ConnectionObserver observer = this.observer;
+        if(observer != null) {
+            observer.request(str + "\r\n");
+        }
+    }
+    
+    /**
+     * Constructor - set the control socket.
+     */
+    public AbstractConnection(FtpServerContext serverContext) throws IOException {
+        this.serverContext = serverContext;
+        log = this.serverContext.getLogFactory().getInstance(getClass());
+    }
+    
+    /**
+     * Get the configuration object.
+     */
+    public FtpServerContext getServerContext() {
+        return serverContext;
+    }
+
+        
+    /**
+     * Get request.
+     */
+    public FtpSession getSession() {
+        return ftpSession;
+    }
+    
+    /**
+     * Set observer.
+     */
+    public void setObserver(ConnectionObserver observer) {
+        this.observer = observer;
+    }  
+    
+    /**
+     * Notify connection manager observer.
+     */
+    protected void notifyObserver() {
+        ftpSession.updateLastAccessTime();
+        serverContext.getConnectionManager().updateConnection(this);
+    }
+
+
+    /**
+     * Transfer data.
+     */
+    public final long transfer(InputStream in, OutputStream out, int maxRate) throws IOException {
+        
+        BufferedInputStream bis = IoUtils.getBufferedInputStream(in);
+        BufferedOutputStream bos = IoUtils.getBufferedOutputStream( out );
+        
+        boolean isAscii = ftpSession.getDataType() == DataType.ASCII;
+        long startTime = System.currentTimeMillis();
+        long transferredSize = 0L;
+        byte[] buff = new byte[4096];
+        
+        while(true) {
+            
+            // if current rate exceeds the max rate, sleep for 50ms 
+            // and again check the current transfer rate
+            if(maxRate > 0) {
+                
+                // prevent "divide by zero" exception
+                long interval = System.currentTimeMillis() - startTime;
+                if(interval == 0) {
+                    interval = 1;
+                }
+                
+                // check current rate
+                long currRate = (transferredSize*1000L)/interval;
+                if(currRate > maxRate) {
+                    try { Thread.sleep(50); } catch(InterruptedException ex) {break;}
+                    continue;
+                }
+            }
+            
+            // read data
+            int count = bis.read(buff);
+            if(count == -1) {
+                break;
+            }
+            
+            // write data
+            // if ascii, replace \n by \r\n
+            if(isAscii) {
+                for(int i=0; i<count; ++i) {
+                    byte b = buff[i];
+                    if(b == '\n') {
+                        bos.write('\r');
+                    }
+                    bos.write(b);
+                }
+            }
+            else {
+                bos.write(buff, 0, count);
+            }
+            
+            transferredSize += count;
+            notifyObserver();
+        }
+        
+        return transferredSize;
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/AbstractConnection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/Connection.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/Connection.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/Connection.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/Connection.java Thu Jan 11 14:46:41 2007
@@ -22,7 +22,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.Socket;
 
 import org.apache.ftpserver.ftplet.FtpSession;
 import org.apache.ftpserver.interfaces.FtpServerContext;
@@ -33,7 +32,7 @@
  * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
  */
 public
-interface Connection extends Runnable {
+interface Connection {
 
     /**
      * Get current session.
@@ -60,13 +59,9 @@
      * Secure the control socket
      * @param type The type of security to use, i.e. SSL or TLS
      * @throws Exception
-     * TODO: Limit exception type.
-     * TODO: Rename without create (indicates factory)
      */
-    void createSecureSocket(String type) throws Exception;
+    void secureControlChannel(String type) throws Exception;
 
     long transfer(InputStream bis, OutputStream bos, int maxRate) throws IOException;
-
-    Socket getControlSocket();
 }
  

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/ConnectionManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/ConnectionManagerImpl.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/ConnectionManagerImpl.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/ConnectionManagerImpl.java Thu Jan 11 14:46:41 2007
@@ -167,8 +167,11 @@
          */
         connection.getSession().setMaxIdleTime(defaultIdleSec);
         
-        // now start a new thread to serve this connection
-        new Thread(connection).start();
+        // now start a new thread to serve this connection if needed
+        if(connection instanceof Runnable) {
+            new Thread((Runnable)connection).start();
+        }
+        
     }
     
     /**

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,226 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.ftpserver.listener;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import org.apache.commons.logging.Log;
+import org.apache.ftpserver.FtpSessionImpl;
+import org.apache.ftpserver.FtpWriter;
+import org.apache.ftpserver.ftplet.FileSystemView;
+import org.apache.ftpserver.ftplet.FtpException;
+import org.apache.ftpserver.ftplet.FtpRequest;
+import org.apache.ftpserver.ftplet.FtpSession;
+import org.apache.ftpserver.ftplet.Ftplet;
+import org.apache.ftpserver.ftplet.FtpletEnum;
+import org.apache.ftpserver.ftplet.User;
+import org.apache.ftpserver.interfaces.Command;
+import org.apache.ftpserver.interfaces.CommandFactory;
+import org.apache.ftpserver.interfaces.FtpServerContext;
+import org.apache.ftpserver.interfaces.IpRestrictor;
+import org.apache.ftpserver.interfaces.ServerFtpStatistics;
+
+public class FtpProtocolHandler {
+    
+    protected Log log;
+    protected FtpServerContext serverContext;
+    
+    public FtpProtocolHandler(FtpServerContext serverContext) throws IOException {
+        this.serverContext = serverContext;
+        
+        log = serverContext.getLogFactory().getInstance(FtpProtocolHandler.class);
+    }
+
+    public void onConnectionOpened(Connection connection, FtpSessionImpl session, FtpWriter writer) throws Exception {
+        InetAddress clientAddr = session.getClientAddress();
+        ConnectionManager conManager = serverContext.getConnectionManager();
+        Ftplet ftpletContainer = serverContext.getFtpletContainer();
+        
+        if(conManager == null) {
+            return;
+        }
+        if(ftpletContainer == null) {
+            return;
+        }
+        
+        // write log message
+        String hostAddress = clientAddr.getHostAddress();
+        log.info("Open connection - " + hostAddress);
+        
+        // notify ftp statistics
+        ServerFtpStatistics ftpStat = (ServerFtpStatistics)serverContext.getFtpStatistics();
+        ftpStat.setOpenConnection(connection);
+        
+        // call Ftplet.onConnect() method
+        boolean isSkipped = false;
+
+        FtpletEnum ftpletRet = ftpletContainer.onConnect(session, writer);
+        if(ftpletRet == FtpletEnum.RET_SKIP) {
+            isSkipped = true;
+        }
+        else if(ftpletRet == FtpletEnum.RET_DISCONNECT) {
+            conManager.closeConnection(connection);
+            return;
+        }
+        
+        if(!isSkipped) {
+
+            // IP permission check
+            IpRestrictor ipRestrictor = serverContext.getIpRestrictor();
+            if( !ipRestrictor.hasPermission(clientAddr) ) {
+                log.warn("No permission to access from " + hostAddress);
+                writer.send(530, "ip.restricted", null);
+                return;
+            }
+            
+            // connection limit check
+            int maxConnections = conManager.getMaxConnections();
+            
+            if(maxConnections != 0 && ftpStat.getCurrentConnectionNumber() > maxConnections) {
+                log.warn("Maximum connection limit reached.");
+                writer.send(530, "connection.limit", null);
+                return;
+            }
+            
+            // everything is fine - go ahead 
+            writer.send(220, null, null);
+        }
+    }
+    
+    public void onRequestReceived(Connection connection, FtpSessionImpl session, FtpWriter writer, FtpRequest request ) throws IOException, FtpException {
+        session.setCurrentRequest(request);
+        
+        if(!hasPermission(session, request)) {
+            writer.send(530, "permission", null);
+            return;
+        }
+
+        // execute command
+        service(connection, request, session, writer);
+        
+        if(session != null) {
+            session.setCurrentRequest(null);
+        }
+
+    }
+    
+    public void onConnectionClosed(Connection connection, FtpSessionImpl session, FtpWriter writer) {
+        // call Ftplet.onDisconnect() method.
+        try {
+            Ftplet ftpletContainer = serverContext.getFtpletContainer();
+            ftpletContainer.onDisconnect(session, writer);
+        }
+        catch(Exception ex) {
+            log.warn("RequestHandler.close()", ex);
+        }
+
+        // notify statistics object and close request
+        ServerFtpStatistics ftpStat = (ServerFtpStatistics)serverContext.getFtpStatistics();
+
+        if(session != null) {
+            
+            // log message
+            User user = session.getUser();
+            String userName = user != null ? user.getName() : "<Not logged in>";
+            InetAddress clientAddr = session.getClientAddress(); 
+            log.info("Close connection : " + clientAddr.getHostAddress() + " - " + userName);
+            
+            // logout if necessary and notify statistics
+            if(session.isLoggedIn()) {
+                session.setLogout();
+                ftpStat.setLogout(connection);
+            }
+            ftpStat.setCloseConnection(connection);
+            
+            // clear request
+            session.clear();
+            session.getFtpDataConnection().dispose();
+            FileSystemView fview = session.getFileSystemView();
+            if(fview != null) {
+                fview.dispose();
+            }
+            session = null;
+        }
+                
+        // close ftp writer
+        if(writer != null) {
+            writer.setObserver(null);
+            writer.close();
+            writer = null;
+        }
+
+    }
+    
+    /**
+     * Execute the ftp command.
+     */
+    private void service(Connection connection, FtpRequest request, FtpSessionImpl session, FtpWriter out) throws IOException, FtpException {
+        try {
+            String commandName = request.getCommand();
+            CommandFactory commandFactory = serverContext.getCommandFactory();
+            Command command = commandFactory.getCommand(commandName);
+            if(command != null) {
+                command.execute(connection, request, session, out);
+            }
+            else {
+                out.send(502, "not.implemented", null);
+            }
+        }
+        catch(Exception ex) {
+            
+            // send error reply
+            try { 
+                out.send(550, null, null);
+            }
+            catch(Exception ex1) {
+            }
+            
+            if (ex instanceof java.io.IOException) {
+               throw (IOException)ex;
+            }
+            else {
+                log.warn("RequestHandler.service()", ex);
+            }
+        }
+    }
+    
+    /**
+     * Check user permission to execute ftp command. 
+     */
+    private boolean hasPermission(FtpSession session, FtpRequest request) {
+        String cmd = request.getCommand();
+        if(cmd == null) {
+            return false;
+        }
+        return session.isLoggedIn() ||
+               cmd.equals("USER")   || 
+               cmd.equals("PASS")   ||
+               cmd.equals("QUIT")   ||
+               cmd.equals("AUTH")   ||
+               cmd.equals("HELP")   ||
+               cmd.equals("SYST")   ||
+               cmd.equals("FEAT")   ||
+               cmd.equals("PBSZ")   ||
+               cmd.equals("PROT")   ||
+               cmd.equals("LANG")   ||
+               cmd.equals("ACCT");
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/FtpProtocolHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOConnection.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOConnection.java?view=diff&rev=495421&r1=495420&r2=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOConnection.java (original)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOConnection.java Thu Jan 11 14:46:41 2007
@@ -19,41 +19,26 @@
 
 package org.apache.ftpserver.listener.io;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketException;
 
 import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocket;
 
-import org.apache.commons.logging.Log;
 import org.apache.ftpserver.FtpDataConnection;
 import org.apache.ftpserver.FtpRequestImpl;
 import org.apache.ftpserver.FtpSessionImpl;
 import org.apache.ftpserver.FtpWriter;
-import org.apache.ftpserver.ftplet.DataType;
-import org.apache.ftpserver.ftplet.FileSystemView;
 import org.apache.ftpserver.ftplet.FtpException;
-import org.apache.ftpserver.ftplet.FtpRequest;
-import org.apache.ftpserver.ftplet.FtpSession;
-import org.apache.ftpserver.ftplet.Ftplet;
-import org.apache.ftpserver.ftplet.FtpletEnum;
-import org.apache.ftpserver.ftplet.User;
-import org.apache.ftpserver.interfaces.Command;
-import org.apache.ftpserver.interfaces.CommandFactory;
 import org.apache.ftpserver.interfaces.FtpServerContext;
-import org.apache.ftpserver.interfaces.IpRestrictor;
-import org.apache.ftpserver.interfaces.ServerFtpStatistics;
 import org.apache.ftpserver.interfaces.Ssl;
-import org.apache.ftpserver.listener.Connection;
-import org.apache.ftpserver.listener.ConnectionManager;
+import org.apache.ftpserver.listener.AbstractConnection;
 import org.apache.ftpserver.listener.ConnectionObserver;
+import org.apache.ftpserver.listener.FtpProtocolHandler;
 import org.apache.ftpserver.util.IoUtils;
 
 
@@ -63,26 +48,26 @@
  *
  * @author <a href="mailto:rana_b@yahoo.com">Rana Bhattacharyya</a>
  */
-public 
-class IOConnection implements Connection {
-    
-    private FtpServerContext serverContext;
-    private Log log;
+public class IOConnection extends AbstractConnection implements Runnable {
     
     private Socket controlSocket;
-    private FtpSessionImpl session;
-    private FtpWriter writer;
+    private IOFtpResponseOutput writer;
     private BufferedReader reader;
     private boolean isConnectionClosed;
     
+    private FtpProtocolHandler protocolHandler;
+    
     
     /**
      * Constructor - set the control socket.
      */
     public IOConnection(FtpServerContext serverContext, Socket controlSocket) throws IOException {
-        this.serverContext = serverContext;
+        super(serverContext);
+        
         this.controlSocket = controlSocket;
-        log = this.serverContext.getLogFactory().getInstance(getClass());
+        
+        // TODO how can we share this between all connections?
+        protocolHandler = new FtpProtocolHandler(serverContext);
         
         // data connection object
         FtpDataConnection dataCon = new FtpDataConnection();
@@ -90,15 +75,25 @@
         dataCon.setServerControlAddress(controlSocket.getLocalAddress());
         
         // reader object
-        session = new FtpSessionImpl();
-        session.setClientAddress(this.controlSocket.getInetAddress());
-        session.setFtpDataConnection(dataCon);
+        ftpSession = new FtpSessionImpl();
+        ftpSession.setClientAddress(this.controlSocket.getInetAddress());
+        ftpSession.setFtpDataConnection(dataCon);
+        
+        if(this.controlSocket instanceof SSLSocket) {
+            SSLSocket sslControlSocket = (SSLSocket) this.controlSocket;
+            
+            try {
+                ftpSession.setClientCertificates(sslControlSocket.getSession().getPeerCertificates());
+            } catch(SSLPeerUnverifiedException e) {
+                // ignore, certificate will not be available to the session
+            }
+        }
         
         // writer object
-        writer = new FtpWriter();
+        writer = new IOFtpResponseOutput();
         writer.setControlSocket(this.controlSocket);
         writer.setServerContext(this.serverContext);
-        writer.setFtpSession(session);
+        writer.setFtpSession(ftpSession);
     }
     
     /**
@@ -112,93 +107,22 @@
             writer.setObserver(observer);
         }
         
-        // set request observer
-        FtpSessionImpl session = this.session;
-        if(session != null) {
-            session.setObserver(observer);
-        }
+        super.setObserver(observer);
     }   
     
     /**
-     * Get the configuration object.
-     */
-    public FtpServerContext getServerContext() {
-        return serverContext;
-    }
-
-        
-    /**
-     * Get request.
-     */
-    public FtpSession getSession() {
-        return session;
-    }
-    
-    /**
      * Server one FTP client connection.
      */
     public void run() {
-        if(session == null ) {
+        if(ftpSession == null ) {
             return;
         }
         if(serverContext == null) {
         	return;
         }
         
-        InetAddress clientAddr = session.getRemoteAddress();
-        ConnectionManager conManager = serverContext.getConnectionManager();
-        Ftplet ftpletContainer = serverContext.getFtpletContainer();
-        
-        if(conManager == null) {
-        	return;
-        }
-        if(ftpletContainer == null) {
-        	return;
-        }
         try {
-            
-            // write log message
-            String hostAddress = clientAddr.getHostAddress();
-            log.info("Open connection - " + hostAddress);
-            
-            // notify ftp statistics
-            ServerFtpStatistics ftpStat = (ServerFtpStatistics)serverContext.getFtpStatistics();
-            ftpStat.setOpenConnection(this);
-            
-            // call Ftplet.onConnect() method
-            boolean isSkipped = false;
-
-            FtpletEnum ftpletRet = ftpletContainer.onConnect(session, writer);
-            if(ftpletRet == FtpletEnum.RET_SKIP) {
-                isSkipped = true;
-            }
-            else if(ftpletRet == FtpletEnum.RET_DISCONNECT) {
-                conManager.closeConnection(this);
-                return;
-            }
-            
-            if(!isSkipped) {
-
-                // IP permission check
-                IpRestrictor ipRestrictor = serverContext.getIpRestrictor();
-                if( !ipRestrictor.hasPermission(clientAddr) ) {
-                    log.warn("No permission to access from " + hostAddress);
-                    writer.send(530, "ip.restricted", null);
-                    return;
-                }
-                
-                // connection limit check
-                int maxConnections = conManager.getMaxConnections();
-                
-                if(maxConnections != 0 && ftpStat.getCurrentConnectionNumber() > maxConnections) {
-                    log.warn("Maximum connection limit reached.");
-                    writer.send(530, "connection.limit", null);
-                    return;
-                }
-                
-                // everything is fine - go ahead 
-                writer.send(220, null, null);
-            }
+            protocolHandler.onConnectionOpened(this, ftpSession, writer);
             
             reader = new BufferedReader(new InputStreamReader(controlSocket.getInputStream(), "UTF-8"));
             do {
@@ -214,21 +138,12 @@
                     continue;
                 }
                 
+                spyRequest(commandLine);
+                
                 // parse and check permission
                 FtpRequestImpl request = new FtpRequestImpl(commandLine);
-                session.setCurrentRequest(request);
                 
-                if(!hasPermission(request)) {
-                    writer.send(530, "permission", null);
-                    continue;
-                }
-
-                // execute command
-                service(request, session, writer);
-                
-                if(session != null) {
-                    session.setCurrentRequest(null);
-                }
+                protocolHandler.onRequestReceived(this, ftpSession, writer, request);
             }
             while(!isConnectionClosed);
         } catch(SocketException ex) {
@@ -241,53 +156,12 @@
         finally {
             // close all resources if not done already
             if(!isConnectionClosed) {
-                 conManager.closeConnection(this);
+                 serverContext.getConnectionManager().closeConnection(this);
             }
         }
     }
-    
-    /**
-     * Notify connection manager observer.
-     */
-    protected void notifyObserver() {
-        session.updateLastAccessTime();
-        serverContext.getConnectionManager().updateConnection(this);
-    }
 
     /**
-     * Execute the ftp command.
-     */
-    public void service(FtpRequest request, FtpSessionImpl session, FtpWriter out) throws IOException, FtpException {
-        try {
-            String commandName = request.getCommand();
-            CommandFactory commandFactory = serverContext.getCommandFactory();
-            Command command = commandFactory.getCommand(commandName);
-            if(command != null) {
-                command.execute(this, request, session, out);
-            }
-            else {
-                out.send(502, "not.implemented", null);
-            }
-        }
-        catch(Exception ex) {
-            
-            // send error reply
-            try { 
-                out.send(550, null, null);
-            }
-            catch(Exception ex1) {
-            }
-            
-            if (ex instanceof java.io.IOException) {
-               throw (IOException)ex;
-            }
-            else {
-                log.warn("RequestHandler.service()", ex);
-            }
-        }
-    }
-    
-    /**
      * Close connection. This is called by the connection service.
      */
     public void close() {
@@ -299,52 +173,8 @@
             }
             isConnectionClosed = true;
         }
-        
-        // call Ftplet.onDisconnect() method.
-        try {
-            Ftplet ftpletContainer = serverContext.getFtpletContainer();
-            ftpletContainer.onDisconnect(session, writer);
-        }
-        catch(Exception ex) {
-            log.warn("RequestHandler.close()", ex);
-        }
-
-        // notify statistics object and close request
-        ServerFtpStatistics ftpStat = (ServerFtpStatistics)serverContext.getFtpStatistics();
 
-        if(session != null) {
-            
-            // log message
-            User user = session.getUser();
-            String userName = user != null ? user.getName() : "<Not logged in>";
-            InetAddress clientAddr = session.getRemoteAddress(); 
-            log.info("Close connection : " + clientAddr.getHostAddress() + " - " + userName);
-            
-            // logout if necessary and notify statistics
-            if(session.isLoggedIn()) {
-                session.setLogout();
-                ftpStat.setLogout(this);
-            }
-            ftpStat.setCloseConnection(this);
-            
-            // clear request
-            session.clear();
-            session.setObserver(null);
-            session.getFtpDataConnection().dispose();
-            FileSystemView fview = session.getFileSystemView();
-            if(fview != null) {
-                fview.dispose();
-            }
-            session = null;
-        }
-                
-        // close ftp writer
-        FtpWriter writer = this.writer;
-        if(writer != null) {
-            writer.setObserver(null);
-            writer.close();
-            writer = null;
-        }
+        protocolHandler.onConnectionClosed(this, ftpSession, writer);
         
         // close buffered reader
         BufferedReader reader = this.reader;
@@ -364,97 +194,12 @@
             }
             controlSocket = null;
         }
-    }
-
-    /**
-     * Check user permission to execute ftp command. 
-     */
-    protected boolean hasPermission(FtpRequest request) {
-        String cmd = request.getCommand();
-        if(cmd == null) {
-            return false;
-        }
-        return session.isLoggedIn() ||
-               cmd.equals("USER")   || 
-		       cmd.equals("PASS")   ||
-		       cmd.equals("QUIT")   ||
-		       cmd.equals("AUTH")   ||
-		       cmd.equals("HELP")   ||
-		       cmd.equals("SYST")   ||
-		       cmd.equals("FEAT")   ||
-		       cmd.equals("PBSZ")   ||
-		       cmd.equals("PROT")   ||
-	           cmd.equals("LANG")   ||
-	           cmd.equals("ACCT");
-    }    
-    
-    /**
-     * Transfer data.
-     */
-    public final long transfer(InputStream in, 
-                               OutputStream out,
-                               int maxRate) throws IOException {
-        
-        BufferedInputStream bis = IoUtils.getBufferedInputStream(in);
-        BufferedOutputStream bos = IoUtils.getBufferedOutputStream( out );
-        
-        boolean isAscii = session.getDataType() == DataType.ASCII;
-        long startTime = System.currentTimeMillis();
-        long transferredSize = 0L;
-        byte[] buff = new byte[4096];
-        
-        while(true) {
-            
-            // if current rate exceeds the max rate, sleep for 50ms 
-            // and again check the current transfer rate
-            if(maxRate > 0) {
-                
-                // prevent "divide by zero" exception
-                long interval = System.currentTimeMillis() - startTime;
-                if(interval == 0) {
-                    interval = 1;
-                }
-                
-                // check current rate
-                long currRate = (transferredSize*1000L)/interval;
-                if(currRate > maxRate) {
-                    try { Thread.sleep(50); } catch(InterruptedException ex) {break;}
-                    continue;
-                }
-            }
-            
-            // read data
-            int count = bis.read(buff);
-            if(count == -1) {
-                break;
-            }
-            
-            // write data
-            // if ascii, replace \n by \r\n
-            if(isAscii) {
-                for(int i=0; i<count; ++i) {
-                    byte b = buff[i];
-                    if(b == '\n') {
-                        bos.write('\r');
-                    }
-                    bos.write(b);
-                }
-            }
-            else {
-                bos.write(buff, 0, count);
-            }
-            
-            transferredSize += count;
-            notifyObserver();
-        }
-        
-        return transferredSize;
-    }       
+    }   
     
     /**
      * Create secure socket.
      */
-    public void createSecureSocket(String protocol) throws Exception {
+    public void secureControlChannel(String protocol) throws Exception {
 
         // change socket to SSL socket
         Ssl ssl = serverContext.getSocketFactory().getSSL();
@@ -469,13 +214,5 @@
         
         // set control socket
         controlSocket = ssoc;
-    }
-    
-    /**
-     * Retrive the socket used for the control channel
-     * @return The control socket
-     */
-    public Socket getControlSocket() {
-        return controlSocket;
     }
 }

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ftpserver.listener.io;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.InetAddress;
+import java.net.Socket;
+
+import org.apache.ftpserver.FtpWriter;
+import org.apache.ftpserver.ftplet.FtpResponse;
+import org.apache.ftpserver.util.IoUtils;
+
+public class IOFtpResponseOutput extends FtpWriter {
+
+    private Writer writer;
+    private InetAddress serverAddress;
+
+    public void write(FtpResponse response) throws IOException {
+
+        String out = response.toString();
+
+        spyResponse(out);
+        writer.write(out);
+        writer.flush();
+    }
+
+    /**
+     * Set the control socket.
+     */
+    public void setControlSocket(Socket soc) throws IOException {
+        serverAddress = soc.getLocalAddress();
+        writer = new OutputStreamWriter(soc.getOutputStream(), "UTF-8");
+    }
+        
+    /**
+     * Close writer.
+     */
+    public void close() {
+        IoUtils.close(writer);
+    }
+
+    protected InetAddress getFallbackServerAddress() {
+        return serverAddress;
+    }
+
+    
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/io/IOFtpResponseOutput.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.ftpserver.listener.mina;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+
+import org.apache.ftpserver.FtpRequestImpl;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.mina.filter.codec.demux.MessageDecoderAdapter;
+import org.apache.mina.filter.codec.demux.MessageDecoderResult;
+
+public class FtpRequestDecoder extends MessageDecoderAdapter
+{
+    private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
+
+    public MessageDecoderResult decodable( IoSession session, ByteBuffer in )
+    {
+        try {
+            String line = in.getString(decoder);
+            System.out.println(line);
+
+            if(line.endsWith("\n")) {
+                return MessageDecoderResult.OK;
+            } else {
+                return MessageDecoderResult.NEED_DATA;
+            }
+        } catch (CharacterCodingException e) {
+            return MessageDecoderResult.NOT_OK;
+        }
+    }
+
+    public MessageDecoderResult decode( IoSession session, ByteBuffer in,
+            ProtocolDecoderOutput out ) throws Exception
+    {
+        String line = in.getString(decoder);
+        System.out.println(line);
+        
+        out.write(new FtpRequestImpl(line));
+
+        return MessageDecoderResult.OK;
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpRequestDecoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.ftpserver.listener.mina;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ftpserver.ftplet.FtpResponse;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.apache.mina.filter.codec.demux.MessageEncoder;
+
+/**
+ * A {@link MessageEncoder} that encodes {@link FtpResponse}.
+ */
+public class FtpResponseEncoder implements MessageEncoder
+{
+    private static final CharsetEncoder ENCODER = Charset.forName("UTF-8").newEncoder();
+
+    private static final Set TYPES;
+
+    static
+    {
+        Set types = new HashSet();
+        types.add( FtpResponse.class );
+        TYPES = Collections.unmodifiableSet( types );
+    }
+
+    public FtpResponseEncoder()
+    {
+    }
+
+    public void encode( IoSession session, Object message,
+            ProtocolEncoderOutput out ) throws Exception
+    {
+        FtpResponse ftpResponse = (FtpResponse) message;
+        
+        ByteBuffer buf = ByteBuffer.allocate( 256 );
+
+        buf.putString( ftpResponse.toString(), ENCODER );
+        
+        buf.flip();
+        out.write(buf);
+
+    }
+
+    public Set getMessageTypes()
+    {
+        return TYPES;
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpResponseEncoder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java
URL: http://svn.apache.org/viewvc/incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java?view=auto&rev=495421
==============================================================================
--- incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java (added)
+++ incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java Thu Jan 11 14:46:41 2007
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.ftpserver.listener.mina;
+
+import org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory;
+
+/**
+ * Provides a protocol codec for HTTP server.
+ * 
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 448080 $, $Date: 2006-09-20 08:03:48 +0200 (on, 20 sep 2006) $
+ */
+public class FtpServerProtocolCodecFactory extends
+        DemuxingProtocolCodecFactory
+{
+    public FtpServerProtocolCodecFactory()
+    {
+        super.register( FtpRequestDecoder.class );
+        super.register( FtpResponseEncoder.class );
+    }
+}

Propchange: incubator/ftpserver/trunk/core/src/java/org/apache/ftpserver/listener/mina/FtpServerProtocolCodecFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native