You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2011/12/31 20:14:12 UTC

svn commit: r1226180 - in /james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core: AbstractAddHeadersFilter.java ReceivedDataLineFilter.java SeparatingDataLineFilter.java

Author: norman
Date: Sat Dec 31 19:14:11 2011
New Revision: 1226180

URL: http://svn.apache.org/viewvc?rev=1226180&view=rev
Log:
Add abstract base classes for header and body filtering / modification. See PROTOCOLS-77

Added:
    james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java   (with props)
    james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java   (with props)
Modified:
    james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java

Added: james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java?rev=1226180&view=auto
==============================================================================
--- james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java (added)
+++ james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java Sat Dec 31 19:14:11 2011
@@ -0,0 +1,126 @@
+/****************************************************************
+ * 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.james.protocols.smtp.core;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.james.protocols.api.ProtocolSession.State;
+import org.apache.james.protocols.api.Response;
+import org.apache.james.protocols.api.handler.LineHandler;
+import org.apache.james.protocols.smtp.SMTPSession;
+
+public abstract class AbstractAddHeadersFilter extends SeparatingDataLineFilter{
+
+    private static final AtomicInteger COUNTER = new AtomicInteger(0);
+    
+    private final String headersPrefixAdded = "HEADERS_PREFIX_ADDED" + COUNTER.incrementAndGet();
+    
+    enum Location{
+        Prefix,
+        Suffix
+    }
+    
+    /**
+     * Return the {@link Location} to add the headers in
+     * 
+     * @return location
+     */
+    protected abstract Location getLocation();
+    
+    
+    @Override
+    protected Response onSeparatorLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        if (getLocation() == Location.Suffix && session.getAttachment(headersPrefixAdded, State.Transaction) == null) { 
+            session.setAttachment(headersPrefixAdded, Boolean.TRUE, State.Transaction);
+            return addHeaders(session, line, next);
+        }
+        return super.onSeparatorLine(session, line, next);
+    }
+
+    @Override
+    protected Response onHeadersLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        if (getLocation() == Location.Prefix) {
+            return addHeaders(session, line, next);
+        }
+        return super.onHeadersLine(session, line, next);
+    }
+    
+    private Response addHeaders(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        Response response;
+        for (Header header: headers(session)) {
+            response = header.transferTo(session, next);
+            if (response != null) {
+                return response;
+            }
+        }
+        return next.onLine(session, line);
+    }
+    
+    /**
+     * Return the {@link Header}'s to operate on
+     * 
+     * @return headers
+     */
+    protected abstract Collection<Header> headers(SMTPSession session);
+    
+    public final static class Header {
+        public final String name;
+        public final String value;
+
+        public Header(String name, String value) {
+            this.name = name;
+            this.value = value;
+        }
+        
+        public String toString() {
+             return name + ": " + value + "\r\n";
+        }
+        
+        /**
+         * Transfer the content of the {@link Header} to the given {@link LineHandler}.
+         * 
+         * This is done for each line of the {@link Header} until the end is reached or the {@link LineHandler#onLine(org.apache.james.protocols.api.ProtocolSession, ByteBuffer)}
+         * return <code>non-null</code>
+         * 
+         * @param session
+         * @param handler
+         * @return response
+         */
+        public Response transferTo(SMTPSession session, LineHandler<SMTPSession> handler) {
+            try {
+                String[] lines = toString().split("\r\n");
+                Response response = null;
+                for (int i = 0; i < lines.length; i++) {
+                     response = handler.onLine(session, ByteBuffer.wrap((lines[i] + "\r\n").getBytes("US-ASCII")));
+                     if (response != null) {
+                         break;
+                     }
+                }
+                return response;
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException("NO US-ASCII ?", e);
+            }
+        }
+    }
+    
+    
+}

Propchange: james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java?rev=1226180&r1=1226179&r2=1226180&view=diff
==============================================================================
--- james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java (original)
+++ james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java Sat Dec 31 19:14:11 2011
@@ -18,24 +18,19 @@
  ****************************************************************/
 package org.apache.james.protocols.smtp.core;
 
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
 import org.apache.james.protocols.api.ProtocolSession.State;
-import org.apache.james.protocols.api.Response;
-import org.apache.james.protocols.api.handler.LineHandler;
 import org.apache.james.protocols.smtp.MailAddress;
 import org.apache.james.protocols.smtp.SMTPSession;
 
-public class ReceivedDataLineFilter implements DataLineFilter {
-
-    private final static String CHARSET = "US-ASCII";
+public class ReceivedDataLineFilter extends AbstractAddHeadersFilter {
     
     private static final ThreadLocal<DateFormat> DATEFORMAT = new ThreadLocal<DateFormat>() {
 
@@ -47,91 +42,6 @@ public class ReceivedDataLineFilter impl
         
     };
 
-    private final static String HEADERS_WRITTEN = "HEADERS_WRITTEN";
-
-
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.protocols.smtp.core.DataLineFilter#onLine(org.apache.james.protocols.smtp.SMTPSession, java.nio.ByteBuffer, org.apache.james.protocols.api.handler.LineHandler)
-     */
-    public Response onLine(SMTPSession session,  ByteBuffer line, LineHandler<SMTPSession> next) {
-        if (session.getAttachment(HEADERS_WRITTEN, State.Transaction) == null) {
-            Response response = addNewReceivedMailHeaders(session, next);
-
-            session.setAttachment(HEADERS_WRITTEN, true, State.Transaction);
-            
-            if (response != null) {
-                return response;
-            }
-        }
-        Response resp =  next.onLine(session, line);
-        return resp;
-    }
-
-    @SuppressWarnings("unchecked")
-    private Response addNewReceivedMailHeaders(SMTPSession session, LineHandler<SMTPSession> next) {
-        try {
-            StringBuilder headerLineBuffer = new StringBuilder();
-
-            String heloMode = (String) session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection);
-            String heloName = (String) session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Connection);
-
-            // Put our Received header first
-            headerLineBuffer.append("Received: from ").append(session.getRemoteAddress().getHostName());
-
-            if (heloName != null) {
-                headerLineBuffer.append(" (").append(heloMode).append(" ").append(heloName).append(") ");
-            }
-
-            headerLineBuffer.append(" ([").append(session.getRemoteAddress().getAddress().getHostAddress()).append("])").append("\r\n");
-
-            Response response = next.onLine(session, ByteBuffer.wrap(headerLineBuffer.toString().getBytes(CHARSET)));
-            if (response != null) {
-                return response;
-            }
-            headerLineBuffer.delete(0, headerLineBuffer.length());
-
-            headerLineBuffer.append("          by ").append(session.getConfiguration().getHelloName()).append(" (").append(session.getConfiguration().getSoftwareName()).append(") with ").append(getServiceType(session, heloMode));
-
-           
-            headerLineBuffer.append(" ID ").append(session.getSessionID());
-
-            if (((Collection<?>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).size() == 1) {
-                // Only indicate a recipient if they're the only recipient
-                // (prevents email address harvesting and large headers in
-                // bulk email)
-                headerLineBuffer.append("\r\n");
-                next.onLine(session, ByteBuffer.wrap(headerLineBuffer.toString().getBytes(CHARSET)));
-                headerLineBuffer.delete(0, headerLineBuffer.length());
-
-                headerLineBuffer.delete(0, headerLineBuffer.length());
-                headerLineBuffer.append("          for <").append(((List<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).get(0).toString()).append(">;").append("\r\n");
-                response = next.onLine(session, ByteBuffer.wrap(headerLineBuffer.toString().getBytes(CHARSET)));
-
-                if (response != null) {
-                    return response;
-                }
-                headerLineBuffer.delete(0, headerLineBuffer.length());
-                headerLineBuffer.delete(0, headerLineBuffer.length());
-
-            } else {
-                // Put the ; on the end of the 'by' line
-                headerLineBuffer.append(";");
-                headerLineBuffer.append("\r\n");
-
-                response = next.onLine(session, ByteBuffer.wrap(headerLineBuffer.toString().getBytes(CHARSET)));
-                if (response != null) {
-                    return response;
-                }
-                headerLineBuffer.delete(0, headerLineBuffer.length());
-            }
-            headerLineBuffer = null;
-            return next.onLine(session, ByteBuffer.wrap(("          " + DATEFORMAT.get().format(new Date()) + "\r\n").getBytes(CHARSET)));
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException("No US-ASCII support ?");
-        }
-    }
     
     
     /**
@@ -161,4 +71,44 @@ public class ReceivedDataLineFilter impl
             return "SMTP";
         }
     }
+
+    @Override
+    protected Location getLocation() {
+        return Location.Prefix;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected Collection<Header> headers(SMTPSession session) {
+        StringBuilder headerLineBuffer = new StringBuilder();
+
+        String heloMode = (String) session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection);
+        String heloName = (String) session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Connection);
+
+        // Put our Received header first
+        headerLineBuffer.append("from ").append(session.getRemoteAddress().getHostName());
+
+        if (heloName != null) {
+            headerLineBuffer.append(" (").append(heloMode).append(" ").append(heloName).append(") ");
+        }
+        headerLineBuffer.append(" ([").append(session.getRemoteAddress().getAddress().getHostAddress()).append("])").append("\r\n");
+        headerLineBuffer.delete(0, headerLineBuffer.length());
+
+        headerLineBuffer.append("          by ").append(session.getConfiguration().getHelloName()).append(" (").append(session.getConfiguration().getSoftwareName()).append(") with ").append(getServiceType(session, heloMode));
+        headerLineBuffer.append(" ID ").append(session.getSessionID());
+
+        if (((Collection<?>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).size() == 1) {
+            // Only indicate a recipient if they're the only recipient
+            // (prevents email address harvesting and large headers in
+            // bulk email)
+            headerLineBuffer.append("\r\n");
+            headerLineBuffer.append("          for <").append(((List<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).get(0).toString()).append(">;");
+        } else {
+            // Put the ; on the end of the 'by' line
+            headerLineBuffer.append(";");
+        }
+        headerLineBuffer.append("          " + DATEFORMAT.get().format(new Date()));
+
+        return Arrays.asList(new Header("Received", headerLineBuffer.toString()));
+    }
 }

Added: james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java
URL: http://svn.apache.org/viewvc/james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java?rev=1226180&view=auto
==============================================================================
--- james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java (added)
+++ james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java Sat Dec 31 19:14:11 2011
@@ -0,0 +1,113 @@
+/****************************************************************
+ * 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.james.protocols.smtp.core;
+
+import java.nio.ByteBuffer;
+
+import org.apache.james.protocols.api.Response;
+import org.apache.james.protocols.api.ProtocolSession.State;
+import org.apache.james.protocols.api.handler.LineHandler;
+import org.apache.james.protocols.smtp.SMTPSession;
+
+/**
+ * Abstract base class which makes it easier to handles lines be providing one method per message part.
+ * </br>
+ * </br>
+ * This is:
+ * </br>
+ * <strong>headers</strong></br>
+ * <strong>separator</strong></br>
+ * <strong>body</strong></br>
+ * </br>
+ * 
+ * Subclasses should override at least one of these methods:
+ * </br>
+ * {@link #onHeadersLine(SMTPSession, ByteBuffer, LineHandler)}</br>
+ * {@link #onSeparatorLine(SMTPSession, ByteBuffer, LineHandler)}</br>
+ * {@link #onBodyLine(SMTPSession, ByteBuffer, LineHandler)}</br>
+ * 
+ *
+ */
+public abstract class SeparatingDataLineFilter implements DataLineFilter{
+
+    private static final String HEADERS_COMPLETE = "HEADERS_COMPLETE";
+    
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.protocols.smtp.core.DataLineFilter#onLine(org.apache.james.protocols.smtp.SMTPSession, java.nio.ByteBuffer, org.apache.james.protocols.api.handler.LineHandler)
+     */
+    public final Response onLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        if (session.getAttachment(HEADERS_COMPLETE, State.Transaction) == null) {
+            if (line.remaining() == 2 ) {
+                if (line.get() == '\r' && line.get() == '\n') {
+                    line.rewind();
+                    Response response = onSeparatorLine(session, line, next);
+                    session.setAttachment(HEADERS_COMPLETE, Boolean.TRUE, State.Transaction);
+                    return response;
+                }
+                line.rewind();
+            }
+            return onHeadersLine(session, line, next);
+        }
+        
+        return onBodyLine(session, line, next);
+    }
+    
+    /**
+     * Gets called when the separating line is received. This is the CLRF sequence. 
+     * 
+     * This implementation just calls {@link LineHandler#onLine(org.apache.james.protocols.api.ProtocolSession, ByteBuffer)} but subclasses should override it if needed.
+     *
+     * @param session
+     * @param line
+     * @param next
+     * @return response
+     */
+    protected Response onSeparatorLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        return next.onLine(session, line);
+    }
+    
+    /**
+     * Gets called for each received line until the CRLF sequence was received.
+     * 
+     * This implementation just calls {@link LineHandler#onLine(org.apache.james.protocols.api.ProtocolSession, ByteBuffer)} but subclasses should override it if needed.
+     * 
+     * @param session
+     * @param line
+     * @param next
+     * @return response
+     */
+    protected Response onHeadersLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        return next.onLine(session, line);
+    }
+    
+    /**
+     * Gets called for each received line after the CRLF sequence was received.
+     * 
+     * This implementation just calls {@link LineHandler#onLine(org.apache.james.protocols.api.ProtocolSession, ByteBuffer)} but subclasses should override it if needed.
+     * 
+     * @param session
+     * @param line
+     * @param next
+     * @return response
+     */
+    protected Response onBodyLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
+        return next.onLine(session, line);
+    }
+}

Propchange: james/protocols/trunk/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org