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