001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.transport.matchers;
019:
020: import org.apache.mailet.*;
021:
022: import org.apache.avalon.cornerstone.services.datasources.*;
023: import org.apache.avalon.excalibur.datasource.*;
024: import org.apache.avalon.framework.service.*;
025:
026: import org.apache.james.*;
027: import org.apache.james.core.*;
028: import org.apache.james.services.*;
029: import org.apache.james.util.*;
030:
031: import javax.mail.*;
032: import javax.mail.internet.*;
033:
034: import java.util.Collection;
035: import java.util.StringTokenizer;
036:
037: import java.sql.*;
038: import java.util.*;
039: import java.text.*;
040: import java.io.*;
041:
042: /**
043: * <P>Matches recipients having the mail sender in the recipient's private whitelist .</P>
044: * <P> The recipient name is always converted to its primary name (handling aliases).</P>
045: * <P>Configuration string: The database name containing the white list table.</P>
046: * <P>Example:</P>
047: * <PRE><CODE>
048: * <mailet match="IsInWhiteList=db://maildb" class="ToProcessor">
049: * <processor> transport </processor>
050: * </mailet>
051: * </CODE></PRE>
052: * @see org.apache.james.transport.mailets.WhiteListManager
053: * @version SVN $Revision: $ $Date: $
054: * @since 2.3.0
055: */
056: public class IsInWhiteList extends GenericMatcher {
057:
058: private String selectByPK;
059:
060: private DataSourceComponent datasource;
061:
062: /** The store containing the local user repository. */
063: private UsersStore usersStore;
064:
065: /** The user repository for this mail server. Contains all the users with inboxes
066: * on this server.
067: */
068: private UsersRepository localusers;
069:
070: /**
071: * The JDBCUtil helper class
072: */
073: private final JDBCUtil theJDBCUtil = new JDBCUtil() {
074: protected void delegatedLog(String logString) {
075: log("IsInWhiteList: " + logString);
076: }
077: };
078:
079: /**
080: * Contains all of the sql strings for this component.
081: */
082: private SqlResources sqlQueries = new SqlResources();
083:
084: /**
085: * Holds value of property sqlFile.
086: */
087: private File sqlFile;
088:
089: /**
090: * Holds value of property sqlParameters.
091: */
092: private Map sqlParameters = new HashMap();
093:
094: /**
095: * Getter for property sqlParameters.
096: * @return Value of property sqlParameters.
097: */
098: private Map getSqlParameters() {
099:
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(),
115: ", \t", false);
116: if (st.hasMoreTokens()) {
117: repositoryPath = st.nextToken().trim();
118: }
119: if (repositoryPath != null) {
120: log("repositoryPath: " + repositoryPath);
121: } else {
122: throw new MessagingException("repositoryPath is null");
123: }
124:
125: ServiceManager serviceManager = (ServiceManager) getMailetContext()
126: .getAttribute(Constants.AVALON_COMPONENT_MANAGER);
127:
128: try {
129: // Get the DataSourceSelector block
130: DataSourceSelector datasources = (DataSourceSelector) serviceManager
131: .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
136: .select(datasourceName);
137: } catch (Exception e) {
138: throw new MessagingException("Can't get datasource", e);
139: }
140:
141: try {
142: // Get the UsersRepository
143: usersStore = (UsersStore) serviceManager
144: .lookup(UsersStore.ROLE);
145: localusers = (UsersRepository) usersStore
146: .getRepository("LocalUsers");
147: } catch (Exception e) {
148: throw new MessagingException(
149: "Can't get the local users repository", e);
150: }
151:
152: try {
153: initSqlQueries(datasource.getConnection(),
154: getMailetContext());
155: } catch (Exception e) {
156: throw new MessagingException(
157: "Exception initializing queries", e);
158: }
159:
160: selectByPK = sqlQueries.getSqlString("selectByPK", true);
161: }
162:
163: public Collection match(Mail mail) throws MessagingException {
164: // check if it's a local sender
165: MailAddress senderMailAddress = mail.getSender();
166: if (senderMailAddress == null) {
167: return null;
168: }
169: String senderUser = senderMailAddress.getUser();
170: String senderHost = senderMailAddress.getHost();
171: if (getMailetContext().isLocalServer(senderHost)
172: && getMailetContext().isLocalUser(senderUser)) {
173: // is a local sender, so return
174: return null;
175: }
176:
177: senderUser = senderUser.toLowerCase(Locale.US);
178: senderHost = senderHost.toLowerCase(Locale.US);
179:
180: Collection recipients = mail.getRecipients();
181:
182: Collection inWhiteList = new java.util.HashSet();
183:
184: Connection conn = null;
185: PreparedStatement selectStmt = null;
186: ResultSet selectRS = null;
187: try {
188:
189: for (Iterator i = recipients.iterator(); i.hasNext();) {
190: try {
191: MailAddress recipientMailAddress = (MailAddress) i
192: .next();
193: String recipientUser = recipientMailAddress
194: .getUser().toLowerCase(Locale.US);
195: String recipientHost = recipientMailAddress
196: .getHost().toLowerCase(Locale.US);
197:
198: if (!getMailetContext()
199: .isLocalServer(recipientHost)) {
200: // not a local recipient, so skip
201: continue;
202: }
203:
204: recipientUser = getPrimaryName(recipientUser);
205:
206: if (conn == null) {
207: conn = datasource.getConnection();
208: }
209:
210: if (selectStmt == null) {
211: selectStmt = conn.prepareStatement(selectByPK);
212: }
213: selectStmt.setString(1, recipientUser);
214: selectStmt.setString(2, recipientHost);
215: selectStmt.setString(3, senderUser);
216: selectStmt.setString(4, senderHost);
217: selectRS = selectStmt.executeQuery();
218: if (selectRS.next()) {
219: //This address was already in the list
220: inWhiteList.add(recipientMailAddress);
221: }
222:
223: } finally {
224: theJDBCUtil.closeJDBCResultSet(selectRS);
225: }
226:
227: }
228:
229: return inWhiteList;
230:
231: } catch (SQLException sqle) {
232: log("Error accessing database", sqle);
233: throw new MessagingException("Exception thrown", sqle);
234: } finally {
235: theJDBCUtil.closeJDBCStatement(selectStmt);
236: theJDBCUtil.closeJDBCConnection(conn);
237: }
238: }
239:
240: /** Gets the main name of a local customer, handling alias */
241: private String getPrimaryName(String originalUsername) {
242: String username;
243: try {
244: username = localusers.getRealName(originalUsername);
245: JamesUser user = (JamesUser) localusers
246: .getUserByName(username);
247: if (user.getAliasing()) {
248: username = user.getAlias();
249: }
250: } catch (Exception e) {
251: username = originalUsername;
252: }
253: return username;
254: }
255:
256: /**
257: * Initializes the sql query environment from the SqlResources file.
258: * Will look for conf/sqlResources.xml.
259: * Will <I>not</I> create the database resources, if missing
260: * (this task is done, if needed, in the {@link WhiteListManager}
261: * initialization routine).
262: * @param conn The connection for accessing the database
263: * @param mailetContext The current mailet context,
264: * for finding the conf/sqlResources.xml file
265: * @throws Exception If any error occurs
266: */
267: public void initSqlQueries(Connection conn,
268: org.apache.mailet.MailetContext mailetContext)
269: throws Exception {
270: try {
271: if (conn.getAutoCommit()) {
272: conn.setAutoCommit(false);
273: }
274:
275: this .sqlFile = new File((String) mailetContext
276: .getAttribute("confDir"), "sqlResources.xml")
277: .getCanonicalFile();
278: sqlQueries.init(this .sqlFile, "WhiteList", conn,
279: getSqlParameters());
280:
281: } finally {
282: theJDBCUtil.closeJDBCConnection(conn);
283: }
284: }
285:
286: }
|