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 * <mailet match="IsInWhiteList=db://maildb" class="ToProcessor">
51 * <processor> transport </processor>
52 * </mailet>
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
131 DataSourceSelector datasources = (DataSourceSelector) serviceManager.lookup(DataSourceSelector.ROLE);
132
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
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
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
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
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
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 }