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 vi...@apache.org on 2006/06/11 22:20:11 UTC
svn commit: r413525 - in /james/server/branches/v2.3/src:
conf/james-config.xml conf/sqlResources.xml
java/org/apache/james/transport/mailets/WhiteListManager.java
java/org/apache/james/transport/matchers/IsInWhiteList.java
Author: vincenzo
Date: Sun Jun 11 13:20:10 2006
New Revision: 413525
URL: http://svn.apache.org/viewvc?rev=413525&view=rev
Log:
Adding whitelist support matcher and mailet (see http://issues.apache.org/jira/browse/JAMES-528).
Added:
james/server/branches/v2.3/src/java/org/apache/james/transport/mailets/WhiteListManager.java
james/server/branches/v2.3/src/java/org/apache/james/transport/matchers/IsInWhiteList.java
Modified:
james/server/branches/v2.3/src/conf/james-config.xml
james/server/branches/v2.3/src/conf/sqlResources.xml
Modified: james/server/branches/v2.3/src/conf/james-config.xml
URL: http://svn.apache.org/viewvc/james/server/branches/v2.3/src/conf/james-config.xml?rev=413525&r1=413524&r2=413525&view=diff
==============================================================================
--- james/server/branches/v2.3/src/conf/james-config.xml (original)
+++ james/server/branches/v2.3/src/conf/james-config.xml Sun Jun 11 13:20:10 2006
@@ -214,6 +214,37 @@
</mailet>
-->
+ <!-- Whitelist Management -->
+ <!-- Manages for each local user a "white list" of remote addresses whose messages -->
+ <!-- should never be blocked as spam. -->
+ <!-- -->
+ <!-- If <automaticInsert> is true, it will check, for a local sender, if a remote recipient -->
+ <!-- is already in the list: if not, it will be automatically inserted. -->
+ <!-- This is under the interpretation that if a local sender X sends a message to a -->
+ <!-- remote recipient Y, then later on if a message is sent by Y to X it should be -->
+ <!-- considered always valid and never blocked; hence Y should be in the white list -->
+ <!-- of X. -->
+ <!-- -->
+ <!-- Another mode of operations is when a local sender sends a message to <whitelistManagerAddress> -->
+ <!-- with one of three specific values in the subject, to -->
+ <!-- (i) send back a message displaying a list of the addresses in his own list (<displayFlag>); -->
+ <!-- (ii) insert some new addresses in his own list (<insertFlag>); -->
+ <!-- (iii) remove some addresses from his own list (<removeFlag>). -->
+ <!-- In all of the three above cases the message will be ghosted and the postmaster will reply -->
+ <!-- to the sender. -->
+ <!-- -->
+ <!-- The sender name is always converted to its primary name (handling aliases). -->
+ <!--
+ <mailet match="SMTPAuthSuccessful" class="WhiteListManager" onMailetException="ignore">
+ <repositoryPath>db://maildb</repositoryPath>
+ <automaticInsert>true</automaticInsert>
+ <whitelistManagerAddress>whitelist.manager@xxx.yyy</whitelistManagerAddress>
+ <displayFlag>display</displayFlag>
+ <insertFlag>insert</insertFlag>
+ <removeFlag>remove</removeFlag>
+ </mailet>
+ -->
+
<!-- "not spam" bayesian analysis feeder. -->
<!--
<mailet match="RecipientIs=not.spam@xxx.yyy" class="BayesianAnalysisFeeder">
@@ -328,6 +359,15 @@
<processor> transport </processor>
</mailet>
-->
+
+ <!-- If the sender is in a recipient's whitelist, it is a valid sender, -->
+ <!-- and as such the message should not be considered spam for such recipient. -->
+ <!--
+ <mailet match="IsInWhiteList=db://maildb" class="ToProcessor" onMatchException="noMatch">
+ <processor> transport </processor>
+ </mailet>
+ -->
+
<!-- End of White List -->
<!-- Check for delivery from a known spam server -->
Modified: james/server/branches/v2.3/src/conf/sqlResources.xml
URL: http://svn.apache.org/viewvc/james/server/branches/v2.3/src/conf/sqlResources.xml?rev=413525&r1=413524&r2=413525&view=diff
==============================================================================
--- james/server/branches/v2.3/src/conf/sqlResources.xml (original)
+++ james/server/branches/v2.3/src/conf/sqlResources.xml Sun Jun 11 13:20:10 2006
@@ -722,5 +722,116 @@
</sqlDefs>
+<!-- SQL statements to support the WhiteListManager mailet and the IsInWhiteList matcher -->
+<!-- -->
+<sqlDefs name="WhiteList">
+
+ <sql name="whiteListTableName">whitelist</sql>
+
+ <!-- Statements used to retrieve a single entry. -->
+ <sql name="selectByPK">SELECT localUser, localHost FROM whitelist where (localUser=? AND localHost=? AND remoteUser=? AND remoteHost=?)</sql>
+
+ <!-- Statements used to all entries by sender address. -->
+ <sql name="selectBySender">SELECT remoteUser, remoteHost FROM whitelist where (localUser=? AND localHost=?) ORDER BY remoteUser, remoteHost</sql>
+
+ <!-- Statements used to insert an entry. -->
+ <sql name="insert">INSERT INTO whitelist (localUser, localHost, remoteUser, remoteHost) VALUES (?,?,?,?)</sql>
+
+ <!-- Statements used to delete an entry. -->
+ <sql name="deleteByPK">DELETE FROM whitelist where (localUser=? AND localHost=? AND remoteUser=? AND remoteHost=?)</sql>
+
+ <!-- Statements used to create the "whitelist" table. -->
+ <sql name="createWhiteListTable" db="hypersonic">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ ) </sql>
+ <sql name="createWhiteListTable" db="hsqldb">
+ CREATE CACHED TABLE ${table} (
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ ) </sql>
+ <sql name="createWhiteListTable" db="mysql">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) character set latin1 NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) character set latin1 NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ ) TYPE=InnoDB
+ </sql>
+ <sql name="createWhiteListTable" db="mssql">
+ CREATE TABLE [whitelist] (
+ [localUser] [varchar] (64) NOT NULL,
+ [localHost] [varchar] (255) NOT NULL,
+ [remoteUser] [varchar] (64) NOT NULL,
+ [remoteHost] [varchar] (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="oracle">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="postgresql">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="sapdb">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="db2">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="ingres">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+ <sql name="createWhiteListTable" db="derby">
+ CREATE TABLE whitelist (
+ localUser varchar (64) NOT NULL,
+ localHost varchar (255) NOT NULL,
+ remoteUser varchar (64) NOT NULL,
+ remoteHost varchar (255) NOT NULL,
+ PRIMARY KEY (localUser, localHost, remoteUser, remoteHost)
+ )
+ </sql>
+
+</sqlDefs>
+
</sqlResources>
Added: james/server/branches/v2.3/src/java/org/apache/james/transport/mailets/WhiteListManager.java
URL: http://svn.apache.org/viewvc/james/server/branches/v2.3/src/java/org/apache/james/transport/mailets/WhiteListManager.java?rev=413525&view=auto
==============================================================================
--- james/server/branches/v2.3/src/java/org/apache/james/transport/mailets/WhiteListManager.java (added)
+++ james/server/branches/v2.3/src/java/org/apache/james/transport/mailets/WhiteListManager.java Sun Jun 11 13:20:10 2006
@@ -0,0 +1,830 @@
+/***********************************************************************
+ * Copyright (c) 2000-2006 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.transport.mailets;
+
+import org.apache.mailet.*;
+import org.apache.mailet.dates.RFC822DateFormat;
+
+import org.apache.avalon.cornerstone.services.datasources.*;
+import org.apache.avalon.excalibur.datasource.*;
+import org.apache.avalon.framework.service.*;
+
+import org.apache.james.*;
+import org.apache.james.core.*;
+import org.apache.james.services.*;
+import org.apache.james.util.*;
+
+import javax.mail.*;
+import javax.mail.internet.*;
+
+import java.sql.*;
+import java.util.*;
+import java.text.*;
+import java.io.*;
+
+/** <P>Manages for each local user a "white list" of remote addresses whose messages
+ * should never be blocked as spam.</P>
+ * <P>The normal behaviour is to check, for a local sender, if a remote recipient
+ * is already in the list: if not, it will be automatically inserted.
+ * This is under the interpretation that if a local sender <I>X</I> sends a message to a
+ * remote recipient <I>Y</I>, then later on if a message is sent by <I>Y</I> to <I>X</I> it should be
+ * considered always valid and never blocked; hence <I>Y</I> should be in the white list
+ * of <I>X</I>.</P>
+ * <P>Another mode of operations is when a local sender sends a message to <I>whitelistManagerAddress</I>
+ * with one of three specific values in the subject, to
+ * (i) send back a message displaying a list of the addresses in his own list;
+ * (ii) insert some new addresses in his own list;
+ * (iii) remove some addresses from his own list.
+ * In all this cases the message will be ghosted and the postmaster will reply
+ * to the sender.</P>
+ * <P> The sender name is always converted to its primary name (handling aliases).</P>
+ * <P>Sample configuration:</P>
+ * <PRE><CODE>
+ * <mailet match="SMTPAuthSuccessful" class="WhiteListManager">
+ * <repositoryPath> db://maildb </repositoryPath>
+ * <!--
+ * If true automatically inserts the local sender to remote recipients entries in the whitelist (default is false).
+ * -->
+ * <automaticInsert>true</automaticInsert>
+ * <!--
+ * Set this to an email address of the "whitelist manager" to send commands to (default is null).
+ * -->
+ * <whitelistManagerAddress>whitelist.manager@xxx.yyy</whitelistManagerAddress>
+ * <!--
+ * Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
+ * to tell the mailet to send back the contents of the white list (default is null).
+ * -->
+ * <displayFlag>display whitelist</displayFlag>
+ * <!--
+ * Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
+ * to tell the mailet to insert some new remote recipients to the white list (default is null).
+ * -->
+ * <insertFlag>insert whitelist</insertFlag>
+ * <!--
+ * Set this to a unique text that you can use (by sending a message to the "whitelist manager" above)
+ * to tell the mailet to remove some remote recipients from the white list (default is null).
+ * -->
+ * <removeFlag>remove whitelist</removeFlag>
+ * </mailet>
+ * </CODE></PRE>
+ *
+ * @see org.apache.james.transport.matchers.IsInWhiteList
+ * @version SVN $Revision: $ $Date: $
+ * @since 2.3.0
+ */
+public class WhiteListManager extends GenericMailet {
+
+ private boolean automaticInsert;
+ private String displayFlag;
+ private String insertFlag;
+ private String removeFlag;
+ private MailAddress whitelistManagerAddress;
+
+ private String selectByPK;
+ private String selectBySender;
+ private String insert;
+ private String deleteByPK;
+
+ /** The date format object used to generate RFC 822 compliant date headers. */
+ private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
+
+ private DataSourceComponent datasource;
+
+ /** The store containing the local user repository. */
+ private UsersStore usersStore;
+
+ /** The user repository for this mail server. Contains all the users with inboxes
+ * on this server.
+ */
+ private UsersRepository localusers;
+
+ /**
+ * The JDBCUtil helper class
+ */
+ private final JDBCUtil theJDBCUtil = new JDBCUtil() {
+ protected void delegatedLog(String logString) {
+ log("WhiteListManager: " + logString);
+ }
+ };
+
+ /**
+ * Contains all of the sql strings for this component.
+ */
+ private SqlResources sqlQueries = new SqlResources();
+
+ /**
+ * Holds value of property sqlFile.
+ */
+ private File sqlFile;
+
+ /**
+ * Holds value of property sqlParameters.
+ */
+ private Map sqlParameters = new HashMap();
+
+ /**
+ * Getter for property sqlParameters.
+ * @return Value of property sqlParameters.
+ */
+ private Map getSqlParameters() {
+
+ return this.sqlParameters;
+ }
+
+ /**
+ * Setter for property sqlParameters.
+ * @param sqlParameters New value of property sqlParameters.
+ */
+ private void setSqlParameters(Map sqlParameters) {
+
+ this.sqlParameters = sqlParameters;
+ }
+
+ /** Initializes the mailet.
+ */
+ public void init() throws MessagingException {
+ automaticInsert = new Boolean(getInitParameter("automaticInsert")).booleanValue();
+ log("automaticInsert: " + automaticInsert);
+
+ displayFlag = getInitParameter("displayFlag");
+ insertFlag = getInitParameter("insertFlag");
+ removeFlag = getInitParameter("removeFlag");
+
+ String whitelistManagerAddressString = getInitParameter("whitelistManagerAddress");
+ if (whitelistManagerAddressString != null) {
+ whitelistManagerAddressString = whitelistManagerAddressString.trim();
+ log("whitelistManagerAddress: " + whitelistManagerAddressString);
+ try {
+ whitelistManagerAddress = new MailAddress(whitelistManagerAddressString);
+ }
+ catch (javax.mail.internet.ParseException pe) {
+ throw new MessagingException("Bad whitelistManagerAddress", pe);
+ }
+
+ if (displayFlag != null) {
+ displayFlag = displayFlag.trim();
+ log("displayFlag: " + displayFlag);
+ }
+ else {
+ log("displayFlag is null");
+ }
+ if (insertFlag != null) {
+ insertFlag = insertFlag.trim();
+ log("insertFlag: " + insertFlag);
+ }
+ else {
+ log("insertFlag is null");
+ }
+ if (removeFlag != null) {
+ removeFlag = removeFlag.trim();
+ log("removeFlag: " + removeFlag);
+ }
+ else {
+ log("removeFlag is null");
+ }
+ }
+ else {
+ log("whitelistManagerAddress is null; will ignore commands");
+ }
+
+ String repositoryPath = getInitParameter("repositoryPath");
+ if (repositoryPath != null) {
+ log("repositoryPath: " + repositoryPath);
+ }
+ else {
+ throw new MessagingException("repositoryPath is null");
+ }
+
+ ServiceManager serviceManager = (ServiceManager) getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
+
+ try {
+ // Get the DataSourceSelector block
+ DataSourceSelector datasources = (DataSourceSelector) serviceManager.lookup(DataSourceSelector.ROLE);
+ // Get the data-source required.
+ int stindex = repositoryPath.indexOf("://") + 3;
+ String datasourceName = repositoryPath.substring(stindex);
+ datasource = (DataSourceComponent) datasources.select(datasourceName);
+ } catch (Exception e) {
+ throw new MessagingException("Can't get datasource", e);
+ }
+
+ try {
+ // Get the UsersRepository
+ usersStore = (UsersStore)serviceManager.lookup(UsersStore.ROLE);
+ localusers = (UsersRepository)usersStore.getRepository("LocalUsers");
+ } catch (Exception e) {
+ throw new MessagingException("Can't get the local users repository", e);
+ }
+
+ try {
+ initSqlQueries(datasource.getConnection(), getMailetContext());
+ } catch (Exception e) {
+ throw new MessagingException("Exception initializing queries", e);
+ }
+
+ selectByPK = sqlQueries.getSqlString("selectByPK", true);
+ selectBySender = sqlQueries.getSqlString("selectBySender", true);
+ insert = sqlQueries.getSqlString("insert", true);
+ deleteByPK = sqlQueries.getSqlString("deleteByPK", true);
+ }
+
+ /** Services the mailet.
+ */
+ public void service(Mail mail) throws MessagingException {
+
+ // check if it's a local sender
+ MailAddress senderMailAddress = mail.getSender();
+ if (senderMailAddress == null) {
+ return;
+ }
+ String senderUser = senderMailAddress.getUser();
+ String senderHost = senderMailAddress.getHost();
+ if ( !getMailetContext().isLocalServer(senderHost)
+ || !getMailetContext().isLocalUser(senderUser)) {
+ // not a local sender, so return
+ return;
+ }
+
+ Collection recipients = mail.getRecipients();
+
+ if (recipients.size() == 1
+ && whitelistManagerAddress != null
+ && whitelistManagerAddress.equals(recipients.toArray()[0])) {
+
+ mail.setState(Mail.GHOST);
+
+ String subject = mail.getMessage().getSubject();
+ if (displayFlag != null && displayFlag.equals(subject)) {
+ manageDisplayRequest(mail);
+ }
+ else if (insertFlag != null && insertFlag.equals(subject)) {
+ manageInsertRequest(mail);
+ }
+ else if (removeFlag != null && removeFlag.equals(subject)) {
+ manageRemoveRequest(mail);
+ }
+ else {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ out.println("Answering on behalf of: " + whitelistManagerAddress);
+ out.println("ERROR: Unknown command in the subject line: " + subject);
+ sendReplyFromPostmaster(mail, sout.toString());
+ }
+ return;
+ }
+
+ if (automaticInsert) {
+ checkAndInsert(senderMailAddress, recipients);
+ }
+
+ }
+
+ /** Returns a string describing this mailet.
+ *
+ * @return a string describing this mailet
+ */
+ public String getMailetInfo() {
+ return "White List Manager mailet";
+ }
+
+ /** Loops through each address in the recipient list, checks if in the senders
+ * list and inserts in it otherwise.
+ */
+ private void checkAndInsert(MailAddress senderMailAddress, Collection recipients) throws MessagingException {
+ String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
+ String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
+
+ senderUser = getPrimaryName(senderUser);
+
+ Connection conn = null;
+ PreparedStatement selectStmt = null;
+ PreparedStatement insertStmt = null;
+ boolean dbUpdated = false;
+
+ try {
+
+ for (Iterator i = recipients.iterator(); i.hasNext(); ) {
+ ResultSet selectRS = null;
+ try {
+ MailAddress recipientMailAddress = (MailAddress)i.next();
+ String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
+ String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
+
+ if (getMailetContext().isLocalServer(recipientHost)) {
+ // not a remote recipient, so skip
+ continue;
+ }
+
+ if (conn == null) {
+ conn = datasource.getConnection();
+ }
+
+ if (selectStmt == null) {
+ selectStmt = conn.prepareStatement(selectByPK);
+ }
+ selectStmt.setString(1, senderUser);
+ selectStmt.setString(2, senderHost);
+ selectStmt.setString(3, recipientUser);
+ selectStmt.setString(4, recipientHost);
+ selectRS = selectStmt.executeQuery();
+ if (selectRS.next()) {
+ //This address was already in the list
+ continue;
+ }
+
+ if (insertStmt == null) {
+ insertStmt = conn.prepareStatement(insert);
+ }
+ insertStmt.setString(1, senderUser);
+ insertStmt.setString(2, senderHost);
+ insertStmt.setString(3, recipientUser);
+ insertStmt.setString(4, recipientHost);
+ insertStmt.executeUpdate();
+ dbUpdated = true;
+
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(selectRS);
+ }
+
+ //Commit our changes if necessary.
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.commit();
+ dbUpdated = false;
+ }
+ }
+ } catch (SQLException sqle) {
+ log("Error accessing database", sqle);
+ throw new MessagingException("Exception thrown", sqle);
+ } finally {
+ theJDBCUtil.closeJDBCStatement(selectStmt);
+ theJDBCUtil.closeJDBCStatement(insertStmt);
+ //Rollback our changes if necessary.
+ try {
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.rollback();
+ dbUpdated = false;
+ }
+ }
+ catch (Exception e) {}
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ /** Manages a display request.
+ */
+ private void manageDisplayRequest(Mail mail)
+ throws MessagingException {
+ MailAddress senderMailAddress = mail.getSender();
+ String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
+ String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
+
+ senderUser = getPrimaryName(senderUser);
+
+ Connection conn = null;
+ PreparedStatement selectStmt = null;
+ ResultSet selectRS = null;
+
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+
+ try {
+ out.println("Answering on behalf of: " + whitelistManagerAddress);
+ out.println("Displaying white list of " + (new MailAddress(senderUser, senderHost)) + ":");
+ out.println();
+
+ conn = datasource.getConnection();
+ selectStmt = conn.prepareStatement(selectBySender);
+ selectStmt.setString(1, senderUser);
+ selectStmt.setString(2, senderHost);
+ selectRS = selectStmt.executeQuery();
+ while (selectRS.next()) {
+ MailAddress mailAddress =
+ new MailAddress(selectRS.getString(1), selectRS.getString(2));
+ out.println(mailAddress.toInternetAddress().toString());
+ }
+
+ out.println();
+ out.println("Finished");
+
+ sendReplyFromPostmaster(mail, sout.toString());
+
+ } catch (SQLException sqle) {
+ out.println("Error accessing the database");
+ sendReplyFromPostmaster(mail, sout.toString());
+ throw new MessagingException("Error accessing database", sqle);
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(selectRS);
+ theJDBCUtil.closeJDBCStatement(selectStmt);
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ /** Manages an insert request.
+ */
+ private void manageInsertRequest(Mail mail)
+ throws MessagingException {
+ MailAddress senderMailAddress = mail.getSender();
+ String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
+ String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
+
+ senderUser = getPrimaryName(senderUser);
+
+ Connection conn = null;
+ PreparedStatement selectStmt = null;
+ PreparedStatement insertStmt = null;
+ boolean dbUpdated = false;
+
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+
+ try {
+ out.println("Answering on behalf of: " + whitelistManagerAddress);
+ out.println("Inserting in the white list of " + (new MailAddress(senderUser, senderHost)) + " ...");
+ out.println();
+
+ MimeMessage message = mail.getMessage() ;
+
+ Object content= message.getContent();
+
+ if (message.getContentType().startsWith("text/plain")
+ && content instanceof String) {
+ StringTokenizer st = new StringTokenizer((String) content, " \t\n\r\f,;:<>");
+ while (st.hasMoreTokens()) {
+ ResultSet selectRS = null;
+ try {
+ MailAddress recipientMailAddress;
+ try {
+ recipientMailAddress = new MailAddress(st.nextToken());
+ }
+ catch (javax.mail.internet.ParseException pe) {
+ continue;
+ }
+ String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
+ String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
+
+ if (getMailetContext().isLocalServer(recipientHost)) {
+ // not a remote recipient, so skip
+ continue;
+ }
+
+ if (conn == null) {
+ conn = datasource.getConnection();
+ }
+
+ if (selectStmt == null) {
+ selectStmt = conn.prepareStatement(selectByPK);
+ }
+ selectStmt.setString(1, senderUser);
+ selectStmt.setString(2, senderHost);
+ selectStmt.setString(3, recipientUser);
+ selectStmt.setString(4, recipientHost);
+ selectRS = selectStmt.executeQuery();
+ if (selectRS.next()) {
+ //This address was already in the list
+ out.println("Skipped: " + recipientMailAddress);
+ continue;
+ }
+
+ if (insertStmt == null) {
+ insertStmt = conn.prepareStatement(insert);
+ }
+ insertStmt.setString(1, senderUser);
+ insertStmt.setString(2, senderHost);
+ insertStmt.setString(3, recipientUser);
+ insertStmt.setString(4, recipientHost);
+ insertStmt.executeUpdate();
+ dbUpdated = true;
+ out.println("Inserted: " + recipientMailAddress);
+
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(selectRS);
+ }
+ }
+
+ if (dbUpdated) {
+ log("Insertion request issued by " + senderMailAddress);
+ }
+ //Commit our changes if necessary.
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.commit() ;
+ dbUpdated = false;
+ }
+ }
+ else {
+ out.println("The message must be plain - no action");
+ }
+
+ out.println();
+ out.println("Finished");
+
+ sendReplyFromPostmaster(mail, sout.toString());
+
+ } catch (SQLException sqle) {
+ out.println("Error accessing the database");
+ sendReplyFromPostmaster(mail, sout.toString());
+ throw new MessagingException("Error accessing the database", sqle);
+ } catch (IOException ioe) {
+ out.println("Error getting message content");
+ sendReplyFromPostmaster(mail, sout.toString());
+ throw new MessagingException("Error getting message content", ioe);
+ } finally {
+ theJDBCUtil.closeJDBCStatement(selectStmt);
+ theJDBCUtil.closeJDBCStatement(insertStmt);
+ //Rollback our changes if necessary.
+ try {
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.rollback() ;
+ dbUpdated = false;
+ }
+ }
+ catch (Exception e) {}
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ /** Manages a remove request.
+ */
+ private void manageRemoveRequest(Mail mail)
+ throws MessagingException {
+ MailAddress senderMailAddress = mail.getSender();
+ String senderUser = senderMailAddress.getUser().toLowerCase(Locale.US);
+ String senderHost = senderMailAddress.getHost().toLowerCase(Locale.US);
+
+ senderUser = getPrimaryName(senderUser);
+
+ Connection conn = null;
+ PreparedStatement selectStmt = null;
+ PreparedStatement deleteStmt = null;
+ boolean dbUpdated = false;
+
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+
+ try {
+ out.println("Answering on behalf of: " + whitelistManagerAddress);
+ out.println("Removing from the white list of " + (new MailAddress(senderUser, senderHost)) + " ...");
+ out.println();
+
+ MimeMessage message = mail.getMessage() ;
+
+ Object content= message.getContent();
+
+ if (message.getContentType().startsWith("text/plain")
+ && content instanceof String) {
+ StringTokenizer st = new StringTokenizer((String) content, " \t\n\r\f,;:<>");
+ while (st.hasMoreTokens()) {
+ ResultSet selectRS = null;
+ try {
+ MailAddress recipientMailAddress;
+ try {
+ recipientMailAddress = new MailAddress(st.nextToken());
+ }
+ catch (javax.mail.internet.ParseException pe) {
+ continue;
+ }
+ String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
+ String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
+
+ if (getMailetContext().isLocalServer(recipientHost)) {
+ // not a remote recipient, so skip
+ continue;
+ }
+
+ if (conn == null) {
+ conn = datasource.getConnection();
+ }
+
+ if (selectStmt == null) {
+ selectStmt = conn.prepareStatement(selectByPK);
+ }
+ selectStmt.setString(1, senderUser);
+ selectStmt.setString(2, senderHost);
+ selectStmt.setString(3, recipientUser);
+ selectStmt.setString(4, recipientHost);
+ selectRS = selectStmt.executeQuery();
+ if (!selectRS.next()) {
+ //This address was not in the list
+ out.println("Skipped: " + recipientMailAddress);
+ continue;
+ }
+
+ if (deleteStmt == null) {
+ deleteStmt = conn.prepareStatement(deleteByPK);
+ }
+ deleteStmt.setString(1, senderUser);
+ deleteStmt.setString(2, senderHost);
+ deleteStmt.setString(3, recipientUser);
+ deleteStmt.setString(4, recipientHost);
+ deleteStmt.executeUpdate();
+ dbUpdated = true;
+ out.println("Removed: " + recipientMailAddress);
+
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(selectRS);
+ }
+ }
+
+ if (dbUpdated) {
+ log("Removal request issued by " + senderMailAddress);
+ }
+ //Commit our changes if necessary.
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.commit() ;
+ dbUpdated = false;
+ }
+ }
+ else {
+ out.println("The message must be plain - no action");
+ }
+
+ out.println();
+ out.println("Finished");
+
+ sendReplyFromPostmaster(mail, sout.toString());
+
+ } catch (SQLException sqle) {
+ out.println("Error accessing the database");
+ sendReplyFromPostmaster(mail, sout.toString());
+ throw new MessagingException("Error accessing the database", sqle);
+ } catch (IOException ioe) {
+ out.println("Error getting message content");
+ sendReplyFromPostmaster(mail, sout.toString());
+ throw new MessagingException("Error getting message content", ioe);
+ } finally {
+ theJDBCUtil.closeJDBCStatement(selectStmt);
+ theJDBCUtil.closeJDBCStatement(deleteStmt);
+ //Rollback our changes if necessary.
+ try {
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.rollback() ;
+ dbUpdated = false;
+ }
+ }
+ catch (Exception e) {}
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ private void sendReplyFromPostmaster(Mail mail, String stringContent) throws MessagingException {
+ try {
+ MailAddress notifier = getMailetContext().getPostmaster();
+
+ MailAddress senderMailAddress = mail.getSender();
+
+ MimeMessage message = mail.getMessage();
+ //Create the reply message
+ MimeMessage reply = new MimeMessage(Session.getDefaultInstance(System.getProperties(), null));
+
+ //Create the list of recipients in the Address[] format
+ InternetAddress[] rcptAddr = new InternetAddress[1];
+ rcptAddr[0] = senderMailAddress.toInternetAddress();
+ reply.setRecipients(Message.RecipientType.TO, rcptAddr);
+
+ //Set the sender...
+ reply.setFrom(notifier.toInternetAddress());
+
+ //Create the message body
+ MimeMultipart multipart = new MimeMultipart();
+ //Add message as the first mime body part
+ MimeBodyPart part = new MimeBodyPart();
+ part.setContent(stringContent, "text/plain");
+ part.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
+ multipart.addBodyPart(part);
+
+ reply.setContent(multipart);
+ reply.setHeader(RFC2822Headers.CONTENT_TYPE, multipart.getContentType());
+
+ //Create the list of recipients in our MailAddress format
+ Set recipients = new HashSet();
+ recipients.add(senderMailAddress);
+
+ //Set additional headers
+ if (reply.getHeader(RFC2822Headers.DATE)==null){
+ reply.setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new java.util.Date()));
+ }
+ String subject = message.getSubject();
+ if (subject == null) {
+ subject = "";
+ }
+ if (subject.indexOf("Re:") == 0){
+ reply.setSubject(subject);
+ } else {
+ reply.setSubject("Re:" + subject);
+ }
+ reply.setHeader(RFC2822Headers.IN_REPLY_TO, message.getMessageID());
+
+ //Send it off...
+ getMailetContext().sendMail(notifier, recipients, reply);
+ }
+ catch (Exception e) {
+ log("Exception found sending reply", e);
+ }
+ }
+
+ /** Gets the main name of a local customer, handling alias */
+ private String getPrimaryName(String originalUsername) {
+ String username;
+ try {
+ username = localusers.getRealName(originalUsername);
+ JamesUser user = (JamesUser) localusers.getUserByName(username);
+ if (user.getAliasing()) {
+ username = user.getAlias();
+ }
+ }
+ catch (Exception e) {
+ username = originalUsername;
+ }
+ return username;
+ }
+
+ /**
+ * Initializes the sql query environment from the SqlResources file.
+ * Will look for conf/sqlResources.xml.
+ * @param conn The connection for accessing the database
+ * @param mailetContext The current mailet context,
+ * for finding the conf/sqlResources.xml file
+ * @throws Exception If any error occurs
+ */
+ public void initSqlQueries(Connection conn, org.apache.mailet.MailetContext mailetContext) throws Exception {
+ try {
+ if (conn.getAutoCommit()) {
+ conn.setAutoCommit(false);
+ }
+
+ this.sqlFile = new File((String) mailetContext.getAttribute("confDir"), "sqlResources.xml").getCanonicalFile();
+ sqlQueries.init(this.sqlFile, "WhiteList" , conn, getSqlParameters());
+
+ checkTables(conn);
+ } finally {
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ private void checkTables(Connection conn) throws SQLException {
+ DatabaseMetaData dbMetaData = conn.getMetaData();
+ // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
+ // Try UPPER, lower, and MixedCase, to see if the table is there.
+
+ boolean dbUpdated = false;
+
+ dbUpdated = createTable(conn, "whiteListTableName", "createWhiteListTable");
+
+ //Commit our changes if necessary.
+ if (conn != null && dbUpdated && !conn.getAutoCommit()) {
+ conn.commit();
+ dbUpdated = false;
+ }
+
+ }
+
+ private boolean createTable(Connection conn, String tableNameSqlStringName, String createSqlStringName) throws SQLException {
+ String tableName = sqlQueries.getSqlString(tableNameSqlStringName, true);
+
+ DatabaseMetaData dbMetaData = conn.getMetaData();
+
+ // Try UPPER, lower, and MixedCase, to see if the table is there.
+ if (theJDBCUtil.tableExists(dbMetaData, tableName)) {
+ return false;
+ }
+
+ PreparedStatement createStatement = null;
+
+ try {
+ createStatement =
+ conn.prepareStatement(sqlQueries.getSqlString(createSqlStringName, true));
+ createStatement.execute();
+
+ StringBuffer logBuffer = null;
+ logBuffer =
+ new StringBuffer(64)
+ .append("Created table '")
+ .append(tableName)
+ .append("' using sqlResources string '")
+ .append(createSqlStringName)
+ .append("'.");
+ log(logBuffer.toString());
+
+ } finally {
+ theJDBCUtil.closeJDBCStatement(createStatement);
+ }
+
+ return true;
+ }
+
+}
+
Added: james/server/branches/v2.3/src/java/org/apache/james/transport/matchers/IsInWhiteList.java
URL: http://svn.apache.org/viewvc/james/server/branches/v2.3/src/java/org/apache/james/transport/matchers/IsInWhiteList.java?rev=413525&view=auto
==============================================================================
--- james/server/branches/v2.3/src/java/org/apache/james/transport/matchers/IsInWhiteList.java (added)
+++ james/server/branches/v2.3/src/java/org/apache/james/transport/matchers/IsInWhiteList.java Sun Jun 11 13:20:10 2006
@@ -0,0 +1,269 @@
+/***********************************************************************
+ * Copyright (c) 2000-2006 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.transport.matchers;
+
+import org.apache.mailet.*;
+
+import org.apache.avalon.cornerstone.services.datasources.*;
+import org.apache.avalon.excalibur.datasource.*;
+import org.apache.avalon.framework.service.*;
+
+import org.apache.james.*;
+import org.apache.james.core.*;
+import org.apache.james.services.*;
+import org.apache.james.util.*;
+
+import javax.mail.*;
+import javax.mail.internet.*;
+
+import java.util.Collection;
+import java.util.StringTokenizer;
+
+import java.sql.*;
+import java.util.*;
+import java.text.*;
+import java.io.*;
+
+/**
+ * <P>Matches recipients having the mail sender in the recipient's private whitelist .</P>
+ * <P> The recipient name is always converted to its primary name (handling aliases).</P>
+ * <P>Configuration string: The database name containing the white list table.</P>
+ * <P>Example:</P>
+ * <PRE><CODE>
+ * <mailet match="IsInWhiteList=db://maildb" class="ToProcessor">
+ * <processor> transport </processor>
+ * </mailet>
+ * </CODE></PRE>
+ * @see org.apache.james.transport.mailets.WhiteListManager
+ * @version SVN $Revision: $ $Date: $
+ * @since 2.3.0
+ */
+public class IsInWhiteList extends GenericMatcher {
+
+ private String selectByPK;
+
+ private DataSourceComponent datasource;
+
+ /** The store containing the local user repository. */
+ private UsersStore usersStore;
+
+ /** The user repository for this mail server. Contains all the users with inboxes
+ * on this server.
+ */
+ private UsersRepository localusers;
+
+ /**
+ * The JDBCUtil helper class
+ */
+ private final JDBCUtil theJDBCUtil = new JDBCUtil() {
+ protected void delegatedLog(String logString) {
+ log("IsInWhiteList: " + logString);
+ }
+ };
+
+ /**
+ * Contains all of the sql strings for this component.
+ */
+ private SqlResources sqlQueries = new SqlResources();
+
+ /**
+ * Holds value of property sqlFile.
+ */
+ private File sqlFile;
+
+ /**
+ * Holds value of property sqlParameters.
+ */
+ private Map sqlParameters = new HashMap();
+
+ /**
+ * Getter for property sqlParameters.
+ * @return Value of property sqlParameters.
+ */
+ private Map getSqlParameters() {
+
+ return this.sqlParameters;
+ }
+
+ /**
+ * Setter for property sqlParameters.
+ * @param sqlParameters New value of property sqlParameters.
+ */
+ private void setSqlParameters(Map sqlParameters) {
+
+ this.sqlParameters = sqlParameters;
+ }
+
+ public void init() throws javax.mail.MessagingException {
+ String repositoryPath = null;
+ StringTokenizer st = new StringTokenizer(getCondition(), ", \t", false);
+ if (st.hasMoreTokens()) {
+ repositoryPath = st.nextToken().trim();
+ }
+ if (repositoryPath != null) {
+ log("repositoryPath: " + repositoryPath);
+ }
+ else {
+ throw new MessagingException("repositoryPath is null");
+ }
+
+ ServiceManager serviceManager = (ServiceManager) getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
+
+ try {
+ // Get the DataSourceSelector block
+ DataSourceSelector datasources = (DataSourceSelector) serviceManager.lookup(DataSourceSelector.ROLE);
+ // Get the data-source required.
+ int stindex = repositoryPath.indexOf("://") + 3;
+ String datasourceName = repositoryPath.substring(stindex);
+ datasource = (DataSourceComponent) datasources.select(datasourceName);
+ } catch (Exception e) {
+ throw new MessagingException("Can't get datasource", e);
+ }
+
+ try {
+ // Get the UsersRepository
+ usersStore = (UsersStore)serviceManager.lookup(UsersStore.ROLE);
+ localusers = (UsersRepository)usersStore.getRepository("LocalUsers");
+ } catch (Exception e) {
+ throw new MessagingException("Can't get the local users repository", e);
+ }
+
+ try {
+ initSqlQueries(datasource.getConnection(), getMailetContext());
+ } catch (Exception e) {
+ throw new MessagingException("Exception initializing queries", e);
+ }
+
+ selectByPK = sqlQueries.getSqlString("selectByPK", true);
+ }
+
+ public Collection match(Mail mail) throws MessagingException {
+ // check if it's a local sender
+ MailAddress senderMailAddress = mail.getSender();
+ if (senderMailAddress == null) {
+ return null;
+ }
+ String senderUser = senderMailAddress.getUser();
+ String senderHost = senderMailAddress.getHost();
+ if ( getMailetContext().isLocalServer(senderHost)
+ && getMailetContext().isLocalUser(senderUser)) {
+ // is a local sender, so return
+ return null;
+ }
+
+ senderUser = senderUser.toLowerCase(Locale.US);
+ senderHost = senderHost.toLowerCase(Locale.US);
+
+ Collection recipients = mail.getRecipients();
+
+ Collection inWhiteList = new java.util.HashSet();
+
+ Connection conn = null;
+ PreparedStatement selectStmt = null;
+ ResultSet selectRS = null;
+ try {
+
+ for (Iterator i = recipients.iterator(); i.hasNext(); ) {
+ try {
+ MailAddress recipientMailAddress = (MailAddress)i.next();
+ String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
+ String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
+
+ if (!getMailetContext().isLocalServer(recipientHost)) {
+ // not a local recipient, so skip
+ continue;
+ }
+
+ recipientUser = getPrimaryName(recipientUser);
+
+ if (conn == null) {
+ conn = datasource.getConnection();
+ }
+
+ if (selectStmt == null) {
+ selectStmt = conn.prepareStatement(selectByPK);
+ }
+ selectStmt.setString(1, recipientUser);
+ selectStmt.setString(2, recipientHost);
+ selectStmt.setString(3, senderUser);
+ selectStmt.setString(4, senderHost);
+ selectRS = selectStmt.executeQuery();
+ if (selectRS.next()) {
+ //This address was already in the list
+ inWhiteList.add(recipientMailAddress);
+ }
+
+ } finally {
+ theJDBCUtil.closeJDBCResultSet(selectRS);
+ }
+
+ }
+
+ return inWhiteList;
+
+ } catch (SQLException sqle) {
+ log("Error accessing database", sqle);
+ throw new MessagingException("Exception thrown", sqle);
+ } finally {
+ theJDBCUtil.closeJDBCStatement(selectStmt);
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+ /** Gets the main name of a local customer, handling alias */
+ private String getPrimaryName(String originalUsername) {
+ String username;
+ try {
+ username = localusers.getRealName(originalUsername);
+ JamesUser user = (JamesUser) localusers.getUserByName(username);
+ if (user.getAliasing()) {
+ username = user.getAlias();
+ }
+ }
+ catch (Exception e) {
+ username = originalUsername;
+ }
+ return username;
+ }
+
+ /**
+ * Initializes the sql query environment from the SqlResources file.
+ * Will look for conf/sqlResources.xml.
+ * Will <I>not</I> create the database resources, if missing
+ * (this task is done, if needed, in the {@link WhiteListManager}
+ * initialization routine).
+ * @param conn The connection for accessing the database
+ * @param mailetContext The current mailet context,
+ * for finding the conf/sqlResources.xml file
+ * @throws Exception If any error occurs
+ */
+ public void initSqlQueries(Connection conn, org.apache.mailet.MailetContext mailetContext) throws Exception {
+ try {
+ if (conn.getAutoCommit()) {
+ conn.setAutoCommit(false);
+ }
+
+ this.sqlFile = new File((String) mailetContext.getAttribute("confDir"), "sqlResources.xml").getCanonicalFile();
+ sqlQueries.init(this.sqlFile, "WhiteList" , conn, getSqlParameters());
+
+ } finally {
+ theJDBCUtil.closeJDBCConnection(conn);
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org