📄 abstractvirtualusertable.java
字号:
/*********************************************************************** * Copyright (c) 2000-2004 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * Licensed under the Apache License, Version 2.0 (the "License"); you * * may not use this file except in compliance with the License. You * * may obtain a copy of the License at: * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * * implied. See the License for the specific language governing * * permissions and limitations under the License. * ***********************************************************************/package org.apache.james.transport.mailets;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.Map;import java.util.StringTokenizer;import javax.mail.MessagingException;import javax.mail.internet.ParseException;import org.apache.james.core.MailImpl;import org.apache.james.util.XMLResources;import org.apache.mailet.GenericMailet;import org.apache.mailet.Mail;import org.apache.mailet.MailAddress;import org.apache.oro.text.regex.MalformedPatternException;import org.apache.oro.text.regex.MatchResult;import org.apache.oro.text.regex.Pattern;import org.apache.oro.text.regex.Perl5Compiler;import org.apache.oro.text.regex.Perl5Matcher;/** * Provides an abstraction of common functionality needed for implementing * a Virtual User Table. Override the <code>mapRecipients</code> method to * map virtual recipients to real recipients. */public abstract class AbstractVirtualUserTable extends GenericMailet{ static private final String MARKER = "org.apache.james.transport.mailets.AbstractVirtualUserTable.mapped"; /** * Checks the recipient list of the email for user mappings. Maps recipients as * appropriate, modifying the recipient list of the mail and sends mail to any new * non-local recipients. * * @param mail the mail to process */ public void service(Mail mail) throws MessagingException { if (mail.getAttribute(MARKER) != null) { mail.removeAttribute(MARKER); return; } Collection recipientsToRemove = new HashSet(); Collection recipientsToAddLocal = new ArrayList(); Collection recipientsToAddForward = new ArrayList(); Collection recipients = mail.getRecipients(); Map recipientsMap = new HashMap(recipients.size()); for (Iterator iter = recipients.iterator(); iter.hasNext(); ) { MailAddress address = (MailAddress)iter.next(); // Assume all addresses are non-virtual at start recipientsMap.put(address, null); } mapRecipients(recipientsMap); for (Iterator iter = recipientsMap.keySet().iterator(); iter.hasNext(); ) { MailAddress source = (MailAddress)iter.next(); String targetString = (String)recipientsMap.get(source); // Only non-null mappings are translated if(targetString != null) { if (targetString.startsWith("error:")) { //Mark this source address as an address to remove from the recipient list recipientsToRemove.add(source); processDSN(mail, source, targetString); } else { StringTokenizer tokenizer = new StringTokenizer(targetString, getSeparator(targetString)); while (tokenizer.hasMoreTokens()) { String targetAddress = tokenizer.nextToken().trim(); // log("Attempting to map from " + source + " to " + targetAddress); if (targetAddress.startsWith("regex:")) { targetAddress = regexMap(mail, source, targetAddress); if (targetAddress == null) continue; } try { MailAddress target = (targetAddress.indexOf('@') < 0) ? new MailAddress(targetAddress, "localhost") : new MailAddress(targetAddress); //Mark this source address as an address to remove from the recipient list recipientsToRemove.add(source); // We need to separate local and remote // recipients. This is explained below. if (getMailetContext().isLocalServer(target.getHost())) { recipientsToAddLocal.add(target); } else { recipientsToAddForward.add(target); } StringBuffer buf = new StringBuffer().append("Translating virtual user ") .append(source) .append(" to ") .append(target); log(buf.toString()); } catch (ParseException pe) { //Don't map this address... there's an invalid address mapping here StringBuffer exceptionBuffer = new StringBuffer(128) .append("There is an invalid map from ") .append(source) .append(" to ") .append(targetAddress); log(exceptionBuffer.toString()); continue; } } } } } // Remove mapped recipients recipients.removeAll(recipientsToRemove); // Add mapped recipients that are local recipients.addAll(recipientsToAddLocal); // We consider an address that we map to be, by definition, a // local address. Therefore if we mapped to a remote address, // then we want to make sure that the mail can be relayed. // However, the original e-mail would typically be subjected to // relay testing. By posting a new mail back through the // system, we have a locally generated mail, which will not be // subjected to relay testing. // Forward to mapped recipients that are remote if (recipientsToAddForward.size() != 0) { // Can't use this ... some mappings could lead to an infinite loop // getMailetContext().sendMail(mail.getSender(), recipientsToAddForward, mail.getMessage()); // duplicates the Mail object, to be able to modify the new mail keeping the original untouched MailImpl newMail = (MailImpl) ((MailImpl) mail).duplicate(newName((MailImpl) mail)); try { newMail.setRemoteAddr(java.net.InetAddress.getLocalHost().getHostAddress()); newMail.setRemoteHost(java.net.InetAddress.getLocalHost().getHostName()); } catch (java.net.UnknownHostException _) { newMail.setRemoteAddr("127.0.0.1"); newMail.setRemoteHost("localhost"); } newMail.setRecipients(recipientsToAddForward); newMail.setAttribute(MARKER, Boolean.TRUE); getMailetContext().sendMail(newMail); } // If there are no recipients left, Ghost the message if (recipients.size() == 0) { mail.setState(Mail.GHOST); } } /** * Override to map virtual recipients to real recipients, both local and non-local. * Each key in the provided map corresponds to a potential virtual recipient, stored as * a <code>MailAddress</code> object. * * Translate virtual recipients to real recipients by mapping a string containing the * address of the real recipient as a value to a key. Leave the value <code>null<code> * if no mapping should be performed. Multiple recipients may be specified by delineating * the mapped string with commas, semi-colons or colons. * * @param recipientsMap the mapping of virtual to real recipients, as * <code>MailAddress</code>es to <code>String</code>s. */ protected abstract void mapRecipients(Map recipientsMap) throws MessagingException; /** * Sends the message for DSN processing * * @param mail the Mail instance being processed * @param address the MailAddress causing the DSN * @param error a String in the form "error:<code> <msg>" */ private void processDSN(Mail mail, MailAddress address, String error) { // parse "error:<code> <msg>" int msgPos = error.indexOf(' '); try { Integer code = Integer.valueOf(error.substring("error:".length(),msgPos)); } catch (NumberFormatException e) { log("Cannot send DSN. Exception parsing DSN code from: " + error, e); return; } String msg = error.substring(msgPos + 1); // process bounce for "source" address try { getMailetContext().bounce(mail, error); } catch (MessagingException me) { log("Cannot send DSN. Exception during DSN processing: ", me); } } /** * Processes regex virtual user mapping * * If a mapped target string begins with the prefix regex:, it must be * formatted as regex:<regular-expression>:<parameterized-string>, * e.g., regex:(.*)@(.*):${1}@tld * * @param mail the Mail instance being processed * @param address the MailAddress to be mapped * @param targetString a String specifying the mapping */ private String regexMap(Mail mail, MailAddress address, String targetString) { String result = null; try { int msgPos = targetString.indexOf(':', "regex:".length() + 1); // log("regex: targetString = " + targetString); // log("regex: msgPos = " + msgPos); // log("regex: compile " + targetString.substring("regex:".length(), msgPos)); // log("regex: address = " + address.toString()); // log("regex: replace = " + targetString.substring(msgPos + 1)); Pattern pattern = new Perl5Compiler().compile(targetString.substring("regex:".length(), msgPos)); Perl5Matcher matcher = new Perl5Matcher(); if (matcher.matches(address.toString(), pattern)) { MatchResult match = matcher.getMatch(); Map parameters = new HashMap(match.groups()); for (int i = 1; i < match.groups(); i++) { parameters.put(Integer.toString(i), match.group(i)); } result = XMLResources.replaceParameters(targetString.substring(msgPos + 1), parameters); } } catch (Exception e) { log("Exception during regexMap processing: ", e); } // log("regex: result = " + result); return result; } /** * Returns the character used to delineate multiple addresses. * * @param targetString the string to parse * @return the character to tokenize on */ private String getSeparator(String targetString) { return (targetString.indexOf(',') > -1 ? "," : (targetString.indexOf(';') > -1 ? ";" : (targetString.indexOf("regex:") > -1? "" : ":" ))); } private static final java.util.Random random = new java.util.Random(); // Used to generate new mail names /** * Create a unique new primary key name. * * @param mail the mail to use as the basis for the new mail name * @return a new name */ private String newName(MailImpl mail) throws MessagingException { String oldName = mail.getName(); // Checking if the original mail name is too long, perhaps because of a // loop caused by a configuration error. // it could cause a "null pointer exception" in AvalonMailRepository much // harder to understand. if (oldName.length() > 76) { int count = 0; int index = 0; while ((index = oldName.indexOf('!', index + 1)) >= 0) { count++; } // It looks like a configuration loop. It's better to stop. if (count > 7) { throw new MessagingException("Unable to create a new message name: too long. Possible loop in config.xml."); } else { oldName = oldName.substring(0, 76); } } StringBuffer nameBuffer = new StringBuffer(64) .append(oldName) .append("-!") .append(random.nextInt(1048576)); return nameBuffer.toString(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -