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 2006/11/10 16:30:26 UTC
svn commit: r473367 - in /james/server/trunk/src:
java/org/apache/james/smtpserver/core/filter/fastfail/
java/org/apache/james/util/junkscore/ test/org/apache/james/smtpserver/
Author: norman
Date: Fri Nov 10 07:30:25 2006
New Revision: 473367
URL: http://svn.apache.org/viewvc?view=rev&rev=473367
Log:
Create a JunkScoreHandler and the utils. First part for JAMES-614
Added:
james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java (with props)
james/server/trunk/src/java/org/apache/james/util/junkscore/
james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java (with props)
james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java (with props)
james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java (with props)
james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java (with props)
Added: james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java?view=auto&rev=473367
==============================================================================
--- james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java Fri Nov 10 07:30:25 2006
@@ -0,0 +1,155 @@
+/****************************************************************
+ * 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.smtpserver.core.filter.fastfail;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.james.smtpserver.ConnectHandler;
+import org.apache.james.smtpserver.MessageHandler;
+import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.junkscore.ComposedJunkScore;
+import org.apache.james.util.junkscore.JunkScore;
+import org.apache.james.util.junkscore.JunkScoreImpl;
+import org.apache.james.util.mail.dsn.DSNStatus;
+
+public class JunkScoreHandler extends AbstractLogEnabled implements ConnectHandler, MessageHandler,Configurable {
+
+ private double maxScore = 0;
+ private String action;
+ private static final String REJECT_ACTION = "reject";
+ private static final String COMPOSE_ACTION = "compose";
+ private static final String HEADER_ACTION = "header";
+
+ /**
+ * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
+ */
+ public void configure(Configuration arg0) throws ConfigurationException {
+ Configuration maxScoreConfig = arg0.getChild("maxScore");
+
+ if (maxScoreConfig != null) {
+ setMaxScore(maxScoreConfig.getValueAsDouble(0));
+ }
+
+ Configuration actionConfig = arg0.getChild("action");
+ if (actionConfig != null) {
+ setAction(actionConfig.getValue().toLowerCase());
+ } else {
+ throw new ConfigurationException("Please configure the action");
+ }
+ }
+
+ public void setMaxScore(double maxScore) {
+ this.maxScore = maxScore;
+ }
+
+ public void setAction(String action) throws ConfigurationException {
+ if (!action.equals(REJECT_ACTION) && !action.equals(COMPOSE_ACTION) && !action.equals(HEADER_ACTION))
+ throw new ConfigurationException("Illegal action: " + action);
+
+ this.action = action;
+ }
+
+ /**
+ * @see org.apache.james.smtpserver.MessageHandler#onMessage(org.apache.james.smtpserver.SMTPSession)
+ */
+ public void onMessage(SMTPSession session) {
+ checkScore(session);
+ }
+
+ /**
+ *
+ */
+ private void checkScore(SMTPSession session) {
+ JunkScore score1 = (JunkScore) session.getConnectionState().get(JunkScore.JUNK_SCORE_SESSION);
+ JunkScore score2 = (JunkScore) session.getState().get(JunkScore.JUNK_SCORE);
+ JunkScore composed = new ComposedJunkScore(score1,score2);
+
+ if (action.equals(COMPOSE_ACTION)) {
+ // Save the scores attribute to maybe use it later!
+ session.getMail().setAttribute(JunkScore.JUNK_SCORE_SESSION_ATTR, String.valueOf(score1.getCompleteStoredScores()));
+ session.getMail().setAttribute(JunkScore.JUNK_SCORE_ATTR, String.valueOf(score2.getCompleteStoredScores()));
+ session.getMail().setAttribute(JunkScore.JUNK_SCORE_COMPOSED_ATTR, String.valueOf(composed.getCompleteStoredScores()));
+ } else if (action.equals(REJECT_ACTION)) {
+ if (maxScore < composed.getCompleteStoredScores()) {
+
+
+ String responseString = "554 "
+ + DSNStatus.getStatus(DSNStatus.PERMANENT,
+ DSNStatus.SECURITY_OTHER)
+ + " This message reach the spam hits treshold. Please contact the Postmaster if the email is not SPAM. Message rejected";
+ StringBuffer buffer = new StringBuffer(256).append(
+ "Rejected message from ").append(
+ session.getState().get(SMTPSession.SENDER)
+ .toString()).append(" from host ")
+ .append(session.getRemoteHost()).append(" (")
+ .append(session.getRemoteIPAddress()).append(
+ ") " + responseString).append(
+ ". Required rejection hits: "
+ + maxScore
+ + " hits: " + composed.getCompleteStoredScores());
+ getLogger().info(buffer.toString());
+
+ session.writeResponse(responseString);
+ session.setStopHandlerProcessing(true);
+ session.abortMessage();
+ }
+ } else if (action.equals(HEADER_ACTION)) {
+ try {
+ MimeMessage message = session.getMail().getMessage();
+ Map scores = composed.getStoredScores();
+ Iterator itScores = scores.keySet().iterator();
+
+ StringBuffer header = new StringBuffer();
+ while (itScores.hasNext()) {
+ String key = itScores.next().toString();
+ header.append(key);
+ header.append("=");
+ header.append(scores.get(key));
+ header.append("; ");
+ }
+
+ message.setHeader("X-JUNKSCORE", header.toString());
+ message.setHeader("X-JUNKSCORE-COMPOSED", String.valueOf(composed.getCompleteStoredScores()));
+
+ } catch (MessagingException e) {
+ getLogger().info("Unable to add Junkscore to header: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.james.smtpserver.ConnectHandler#onConnect(org.apache.james.smtpserver.SMTPSession)
+ */
+ public void onConnect(SMTPSession session) {
+ session.getState().put(JunkScore.JUNK_SCORE, new JunkScoreImpl());
+ session.getConnectionState().put(JunkScore.JUNK_SCORE_SESSION, new JunkScoreImpl());
+ }
+}
Propchange: james/server/trunk/src/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java
URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java?view=auto&rev=473367
==============================================================================
--- james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java (added)
+++ james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java Fri Nov 10 07:30:25 2006
@@ -0,0 +1,89 @@
+/****************************************************************
+ * 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.util.junkscore;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class to compose the two Junkscore Objects
+ */
+public class ComposedJunkScore implements JunkScore {
+
+ JunkScore score1;
+
+ JunkScore score2;
+
+ /**
+ * Construct Class
+ *
+ * @param score1 The JunkScore for the whole session
+ * @param score2 The JunkScore for the nail
+ * @throws IllegalArgumentException get thrown if one of the given JunkScore Objects is null
+ */
+ public ComposedJunkScore (JunkScore score1, JunkScore score2) throws IllegalArgumentException {
+ if (score1 == null || score2 == null ) throw new IllegalArgumentException("JunkScore can not be null");
+ this.score1 = score1;
+ this.score2 = score2;
+ }
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getCompleteStoredScores()
+ */
+ public double getCompleteStoredScores() {
+ return (score1.getCompleteStoredScores() + score2.getCompleteStoredScores());
+ }
+
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getStoredScore(java.lang.String)
+ */
+ public double getStoredScore(String key) {
+ return (score1.getStoredScore(key) + score2.getStoredScore(key));
+ }
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getStoredScores()
+ */
+ public Map getStoredScores() {
+ // copy the Map
+ Map m = new HashMap(score1.getStoredScores());
+ m.putAll(score2.getStoredScores());
+ return m;
+ }
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#resetStoredScores()
+ */
+ public double resetStoredScores() {
+ return (score1.resetStoredScores() + score2.resetStoredScores());
+ }
+
+ /**
+ * Return only 0
+ */
+ public double setStoredScore(String key, double score) {
+ // just do nothing here and return 0
+ return 0;
+ }
+
+}
Propchange: james/server/trunk/src/java/org/apache/james/util/junkscore/ComposedJunkScore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java
URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java?view=auto&rev=473367
==============================================================================
--- james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java (added)
+++ james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java Fri Nov 10 07:30:25 2006
@@ -0,0 +1,83 @@
+/****************************************************************
+ * 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.util.junkscore;
+
+import java.util.Map;
+
+public interface JunkScore {
+
+ /**
+ * The key for the JunkScore Object which holds scores per SMTPSession
+ */
+ public final String JUNK_SCORE_SESSION = "JUNK_SCORE_SESSION";
+
+ /**
+ * The key for the JunkScore Object which holds scores per mail
+ */
+ public final String JUNK_SCORE = "JUNK_SCORE";
+
+ public final String JUNK_SCORE_SESSION_ATTR = "org.apache.james.junkscore.session";
+
+ public final String JUNK_SCORE_ATTR = "org.apache.james.junkscore";
+
+ public final String JUNK_SCORE_COMPOSED_ATTR = "org.apache.james.junkscore.composed";
+
+ /**
+ * Return the summary of stored scores
+ *
+ * @return score the summary of all stored scores
+ */
+ public double getCompleteStoredScores();
+
+
+ /**
+ * Return a copy of the Map which contains the keys with the correspending scores
+ *
+ * @return scoreMape the map which holds all keys and scores
+ */
+ public Map getStoredScores();
+
+ /**
+ * Return the score for the given key. Returns 0 if no score with the given key exist
+ *
+ * @param key the key to get the score for
+ * @return score the score
+ */
+ public double getStoredScore(String key);
+
+ /**
+ * Set the score for the given key. Return the previous stored score for the key.
+ *
+ * @param key the key under which the score should be stored
+ * @param score the store to score
+ * @return oldScore the previous scored stored under the given key
+ */
+ public double setStoredScore(String key, double score);
+
+ /**
+ * Reset the all stored scores in the map. Return the summary of the previous stored scores.
+ *
+ * @return oldScore the summary of the old score;
+ */
+ public double resetStoredScores();
+}
Propchange: james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java?view=auto&rev=473367
==============================================================================
--- james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java (added)
+++ james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java Fri Nov 10 07:30:25 2006
@@ -0,0 +1,97 @@
+/****************************************************************
+ * 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.util.junkscore;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ *
+ * The Object which holds all junkscore
+ */
+public class JunkScoreImpl implements JunkScore {
+
+ /**
+ * The map to store the scores
+ */
+ private Map scoreMap = new HashMap();
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getCompleteStoredScores()
+ */
+ public double getCompleteStoredScores() {
+ double count = 0;
+ Iterator s = scoreMap.keySet().iterator();
+
+ while (s.hasNext()) {
+ count =+ Double.parseDouble(scoreMap.get(s.next()).toString());
+ }
+ return count;
+ }
+
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getStoredScores()
+ */
+ public Map getStoredScores() {
+ // Get sure we return a copy of the Map so it can not get wrong objects added
+ return new HashMap(scoreMap);
+ }
+
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#getStoredScore(java.lang.String)
+ */
+ public double getStoredScore(String key) {
+ Object s = scoreMap.get(key);
+
+ if (s != null) {
+ return Double.parseDouble(s.toString());
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#setStoredScore(java.lang.String, double)
+ */
+ public double setStoredScore(String key, double score) {
+ Object s = null;
+ scoreMap.put(key, String.valueOf(score));
+
+ if (s == null) {
+ return 0;
+ } else {
+ return Double.parseDouble(s.toString());
+ }
+ }
+
+ /**
+ * @see org.apache.james.util.junkscore.JunkScore#resetStoredScores()
+ */
+ public double resetStoredScores() {
+ double oldSum = getCompleteStoredScores();
+ scoreMap.clear();
+ return oldSum;
+ }
+
+}
Propchange: james/server/trunk/src/java/org/apache/james/util/junkscore/JunkScoreImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java?view=auto&rev=473367
==============================================================================
--- james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java (added)
+++ james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java Fri Nov 10 07:30:25 2006
@@ -0,0 +1,159 @@
+/****************************************************************
+ * 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.smtpserver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.james.smtpserver.core.filter.fastfail.JunkScoreHandler;
+import org.apache.james.test.mock.avalon.MockLogger;
+import org.apache.james.test.mock.javaxmail.MockMimeMessage;
+import org.apache.james.test.mock.mailet.MockMail;
+import org.apache.james.util.junkscore.JunkScore;
+import org.apache.mailet.Mail;
+
+import junit.framework.TestCase;
+
+public class JunkScoreHandlerTest extends TestCase {
+ private String response = null;
+ private boolean stopped = false;
+ private boolean messageAborted = false;
+ private final static String KEY1 = "KEY1";
+ private final static String KEY2 = "KEY2";
+ private final static double SCORE1 = 10.0;
+ private final static double SCORE2 = 7.1;
+
+ public void setUp() {
+ response = null;
+ stopped = false;
+ messageAborted = false;
+ }
+
+ private SMTPSession setupMockedSMTPSession() {
+ SMTPSession session = new AbstractSMTPSession() {
+ HashMap state = new HashMap();
+ HashMap cState = new HashMap();
+ Mail m = null;
+
+ public Map getState() {
+ state.put(SMTPSession.SENDER, "sender@localhost");
+ return state;
+ }
+
+ public Map getConnectionState() {
+ return cState;
+ }
+
+ public void writeResponse(String resp) {
+ response = resp;
+ }
+
+ public void setStopHandlerProcessing(boolean b) {
+ stopped = b;
+ }
+
+ public void abortMessage() {
+ messageAborted = true;
+ }
+
+ public Mail getMail(){
+ if (m == null) m = getMockMail();
+ return m;
+ }
+
+ public String getRemoteHost() {
+ return "anyHost";
+ }
+
+ public String getRemoteIPAddress() {
+ return "000.000.000.001";
+ }
+ };
+ return session;
+ }
+
+ private Mail getMockMail(){
+ Mail m = new MockMail();
+ try {
+ m.setMessage(new MockMimeMessage());
+ } catch (MessagingException e) {
+ e.printStackTrace();
+ }
+ return m;
+ }
+
+ public void testIllegalActionThrowException() {
+ boolean exception = false;
+ JunkScoreHandler handler = new JunkScoreHandler();
+ ContainerUtil.enableLogging(handler,new MockLogger());
+
+ try {
+ handler.setAction("invalid");
+ } catch (ConfigurationException e) {
+ exception = true;
+ }
+
+ assertTrue("Exception thrown",exception);
+ }
+
+ public void testRejectAction() throws ConfigurationException {
+
+ SMTPSession session = setupMockedSMTPSession();
+ JunkScoreHandler handler = new JunkScoreHandler();
+ ContainerUtil.enableLogging(handler,new MockLogger());
+
+ handler.setAction("reject");
+ handler.setMaxScore(15.0);
+ handler.onConnect(session);
+ handler.onMessage(session);
+
+ assertNull("Not rejected",response);
+ ((JunkScore) session.getState().get(JunkScore.JUNK_SCORE)).setStoredScore(KEY1, SCORE1);
+ ((JunkScore) session.getConnectionState().get(JunkScore.JUNK_SCORE_SESSION)).setStoredScore(KEY2, SCORE2);
+ handler.onMessage(session);
+
+ assertNotNull("Rejected",response);
+ assertTrue("Rejected",stopped);
+ assertTrue("Rejected",messageAborted);
+ }
+
+ public void testHeaderAction() throws ConfigurationException, MessagingException {
+ SMTPSession session = setupMockedSMTPSession();
+ JunkScoreHandler handler = new JunkScoreHandler();
+ ContainerUtil.enableLogging(handler,new MockLogger());
+
+ handler.setAction("header");
+
+ handler.onConnect(session);
+ ((JunkScore) session.getState().get(JunkScore.JUNK_SCORE)).setStoredScore(KEY1, SCORE1);
+ ((JunkScore) session.getConnectionState().get(JunkScore.JUNK_SCORE_SESSION)).setStoredScore(KEY2, SCORE2);
+ handler.onMessage(session);
+
+ MimeMessage message = session.getMail().getMessage();
+ assertNotNull("Header added",message.getHeader("X-JUNKSCORE")[0]);
+ assertNotNull("Header added",message.getHeader("X-JUNKSCORE-COMPOSED")[0]);
+ }
+}
Propchange: james/server/trunk/src/test/org/apache/james/smtpserver/JunkScoreHandlerTest.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org