FileDocCategorySizeDatePackage
IsInWhiteList.javaAPI DocApache James 2.3.110042Fri Jan 12 12:56:32 GMT 2007org.apache.james.transport.matchers

IsInWhiteList.java

/****************************************************************
 * 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.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);
        }
    }
    
}