View Javadoc

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