View Javadoc

1   /************************************************************************
2    * Copyright (c) 2000-2006 The Apache Software Foundation.             *
3    * All rights reserved.                                                *
4    * ------------------------------------------------------------------- *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you *
6    * may not use this file except in compliance with the License. You    *
7    * may obtain a copy of the License at:                                *
8    *                                                                     *
9    *     http://www.apache.org/licenses/LICENSE-2.0                      *
10   *                                                                     *
11   * Unless required by applicable law or agreed to in writing, software *
12   * distributed under the License is distributed on an "AS IS" BASIS,   *
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
14   * implied.  See the License for the specific language governing       *
15   * permissions and limitations under the License.                      *
16   ***********************************************************************/
17  
18  package org.apache.james.transport.matchers;
19  
20  import org.apache.mailet.*;
21  
22  import org.apache.avalon.cornerstone.services.datasources.*;
23  import org.apache.avalon.excalibur.datasource.*;
24  import org.apache.avalon.framework.service.*;
25  
26  import org.apache.james.*;
27  import org.apache.james.core.*;
28  import org.apache.james.services.*;
29  import org.apache.james.util.*;
30  
31  import javax.mail.*;
32  import javax.mail.internet.*;
33  
34  import java.util.Collection;
35  import java.util.StringTokenizer;
36  
37  import java.sql.*;
38  import java.util.*;
39  import java.text.*;
40  import java.io.*;
41  
42  /***
43   * <P>Matches recipients having the mail sender in the recipient's private whitelist .</P>
44   * <P> The recipient name is always converted to its primary name (handling aliases).</P>
45   * <P>Configuration string: The database name containing the white list table.</P>
46   * <P>Example:</P>
47   * <PRE><CODE>
48   *    &lt;mailet match="IsInWhiteList=db://maildb" class="ToProcessor"&gt;
49   *       &lt;processor&gt; transport &lt;/processor&gt;
50   *    &lt;/mailet&gt;
51   * </CODE></PRE>
52   * @see org.apache.james.transport.mailets.WhiteListManager
53   * @version SVN $Revision: $ $Date: $
54   * @since 2.3.0
55   */
56  public class IsInWhiteList extends GenericMatcher {
57  
58      private String selectByPK;
59      
60      private DataSourceComponent datasource;
61      
62      /*** The store containing the local user repository. */
63      private UsersStore usersStore;
64  
65      /*** The user repository for this mail server.  Contains all the users with inboxes
66       * on this server.
67       */
68      private UsersRepository localusers;
69  
70      /***
71       * The JDBCUtil helper class
72       */
73      private final JDBCUtil theJDBCUtil = new JDBCUtil() {
74          protected void delegatedLog(String logString) {
75              log("IsInWhiteList: " + logString);
76          }
77      };
78      
79      /***
80       * Contains all of the sql strings for this component.
81       */
82      private SqlResources sqlQueries = new SqlResources();
83  
84      /***
85       * Holds value of property sqlFile.
86       */
87      private File sqlFile;
88  
89       /***
90       * Holds value of property sqlParameters.
91       */
92      private Map sqlParameters = new HashMap();
93  
94      /***
95       * Getter for property sqlParameters.
96       * @return Value of property sqlParameters.
97       */
98      private Map getSqlParameters() {
99  
100         return this.sqlParameters;
101     }
102 
103     /***
104      * Setter for property sqlParameters.
105      * @param sqlParameters New value of property sqlParameters.
106      */
107     private void setSqlParameters(Map sqlParameters) {
108 
109         this.sqlParameters = sqlParameters;
110     }
111 
112     public void init() throws javax.mail.MessagingException {
113         String repositoryPath = null;
114         StringTokenizer st = new StringTokenizer(getCondition(), ", \t", false);
115         if (st.hasMoreTokens()) {
116             repositoryPath = st.nextToken().trim();
117         }
118         if (repositoryPath != null) {
119             log("repositoryPath: " + repositoryPath);
120         }
121         else {
122             throw new MessagingException("repositoryPath is null");
123         }
124 
125         ServiceManager serviceManager = (ServiceManager) getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
126 
127         try {
128             // Get the DataSourceSelector block
129             DataSourceSelector datasources = (DataSourceSelector) serviceManager.lookup(DataSourceSelector.ROLE);
130             // Get the data-source required.
131             int stindex =   repositoryPath.indexOf("://") + 3;
132             String datasourceName = repositoryPath.substring(stindex);
133             datasource = (DataSourceComponent) datasources.select(datasourceName);
134         } catch (Exception e) {
135             throw new MessagingException("Can't get datasource", e);
136         }
137 
138          try {
139             // Get the UsersRepository
140             usersStore = (UsersStore)serviceManager.lookup(UsersStore.ROLE);
141             localusers = (UsersRepository)usersStore.getRepository("LocalUsers");
142         } catch (Exception e) {
143             throw new MessagingException("Can't get the local users repository", e);
144         }
145 
146         try {
147             initSqlQueries(datasource.getConnection(), getMailetContext());
148         } catch (Exception e) {
149             throw new MessagingException("Exception initializing queries", e);
150         }        
151         
152         selectByPK = sqlQueries.getSqlString("selectByPK", true);
153     }
154 
155     public Collection match(Mail mail) throws MessagingException {
156         // check if it's a local sender
157         MailAddress senderMailAddress = mail.getSender();
158         if (senderMailAddress == null) {
159             return null;
160         }
161         String senderUser = senderMailAddress.getUser();
162         String senderHost = senderMailAddress.getHost();
163         if (   getMailetContext().isLocalServer(senderHost)
164             && getMailetContext().isLocalUser(senderUser)) {
165             // is a local sender, so return
166             return null;
167         }
168         
169         senderUser = senderUser.toLowerCase(Locale.US);
170         senderHost = senderHost.toLowerCase(Locale.US);
171         
172         Collection recipients = mail.getRecipients();
173                 
174         Collection inWhiteList = new java.util.HashSet();
175         
176         Connection conn = null;
177         PreparedStatement selectStmt = null;
178         ResultSet selectRS = null;
179         try {
180             
181             for (Iterator i = recipients.iterator(); i.hasNext(); ) {
182                 try {
183                     MailAddress recipientMailAddress = (MailAddress)i.next();
184                     String recipientUser = recipientMailAddress.getUser().toLowerCase(Locale.US);
185                     String recipientHost = recipientMailAddress.getHost().toLowerCase(Locale.US);
186                     
187                     if (!getMailetContext().isLocalServer(recipientHost)) {
188                         // not a local recipient, so skip
189                         continue;
190                     }
191                     
192                     recipientUser = getPrimaryName(recipientUser);
193                     
194                     if (conn == null) {
195                         conn = datasource.getConnection();
196                     }
197                     
198                     if (selectStmt == null) {
199                         selectStmt = conn.prepareStatement(selectByPK);
200                     }
201                     selectStmt.setString(1, recipientUser);
202                     selectStmt.setString(2, recipientHost);
203                     selectStmt.setString(3, senderUser);
204                     selectStmt.setString(4, senderHost);
205                     selectRS = selectStmt.executeQuery();
206                     if (selectRS.next()) {
207                         //This address was already in the list
208                         inWhiteList.add(recipientMailAddress);
209                     }
210                                         
211                 } finally {
212                     theJDBCUtil.closeJDBCResultSet(selectRS);
213                 }
214                 
215             }
216             
217             return inWhiteList;
218             
219         } catch (SQLException sqle) {
220             log("Error accessing database", sqle);
221             throw new MessagingException("Exception thrown", sqle);
222         } finally {
223             theJDBCUtil.closeJDBCStatement(selectStmt);
224             theJDBCUtil.closeJDBCConnection(conn);
225         }
226     }
227 
228     /*** Gets the main name of a local customer, handling alias */
229     private String getPrimaryName(String originalUsername) {
230         String username;
231         try {
232             username = localusers.getRealName(originalUsername);
233             JamesUser user = (JamesUser) localusers.getUserByName(username);
234             if (user.getAliasing()) {
235                 username = user.getAlias();
236             }
237         }
238         catch (Exception e) {
239             username = originalUsername;
240         }
241         return username;
242     }
243     
244     /***
245      * Initializes the sql query environment from the SqlResources file.
246      * Will look for conf/sqlResources.xml.
247      * Will <I>not</I> create the database resources, if missing
248      * (this task is done, if needed, in the {@link WhiteListManager}
249      * initialization routine).
250      * @param conn The connection for accessing the database
251      * @param mailetContext The current mailet context,
252      * for finding the conf/sqlResources.xml file
253      * @throws Exception If any error occurs
254      */
255     public void initSqlQueries(Connection conn, org.apache.mailet.MailetContext mailetContext) throws Exception {
256         try {
257             if (conn.getAutoCommit()) {
258                 conn.setAutoCommit(false);
259             }
260             
261             this.sqlFile = new File((String) mailetContext.getAttribute("confDir"), "sqlResources.xml").getCanonicalFile();
262             sqlQueries.init(this.sqlFile, "WhiteList" , conn, getSqlParameters());
263             
264         } finally {
265             theJDBCUtil.closeJDBCConnection(conn);
266         }
267     }
268     
269 }