1 17 18 package org.apache.james.transport.mailets; 19 20 import java.util.ArrayList ; 21 import java.util.Collection ; 22 import java.util.HashMap ; 23 import java.util.HashSet ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 import java.util.StringTokenizer ; 27 28 import javax.mail.MessagingException ; 29 import javax.mail.internet.ParseException ; 30 31 import org.apache.james.core.MailImpl; 32 import org.apache.james.util.XMLResources; 33 34 import org.apache.mailet.GenericMailet; 35 import org.apache.mailet.Mail; 36 import org.apache.mailet.MailAddress; 37 38 import org.apache.oro.text.regex.MalformedPatternException; 39 import org.apache.oro.text.regex.MatchResult; 40 import org.apache.oro.text.regex.Pattern; 41 import org.apache.oro.text.regex.Perl5Compiler; 42 import org.apache.oro.text.regex.Perl5Matcher; 43 44 49 public abstract class AbstractVirtualUserTable extends GenericMailet 50 { 51 static private final String MARKER = "org.apache.james.transport.mailets.AbstractVirtualUserTable.mapped"; 52 53 60 public void service(Mail mail) throws MessagingException 61 { 62 if (mail.getAttribute(MARKER) != null) { 63 mail.removeAttribute(MARKER); 64 return; 65 } 66 67 Collection recipientsToRemove = new HashSet (); 68 Collection recipientsToAddLocal = new ArrayList (); 69 Collection recipientsToAddForward = new ArrayList (); 70 71 Collection recipients = mail.getRecipients(); 72 Map recipientsMap = new HashMap (recipients.size()); 73 74 for (Iterator iter = recipients.iterator(); iter.hasNext(); ) { 75 MailAddress address = (MailAddress)iter.next(); 76 77 recipientsMap.put(address, null); 79 } 80 81 mapRecipients(recipientsMap); 82 83 for (Iterator iter = recipientsMap.keySet().iterator(); iter.hasNext(); ) { 84 MailAddress source = (MailAddress)iter.next(); 85 String targetString = (String )recipientsMap.get(source); 86 87 if(targetString != null) { 89 if (targetString.startsWith("error:")) { 90 recipientsToRemove.add(source); 92 processDSN(mail, source, targetString); 93 } else { 94 StringTokenizer tokenizer = new StringTokenizer (targetString, getSeparator(targetString)); 95 96 while (tokenizer.hasMoreTokens()) { 97 String targetAddress = tokenizer.nextToken().trim(); 98 99 101 if (targetAddress.startsWith("regex:")) { 102 targetAddress = regexMap(mail, source, targetAddress); 103 if (targetAddress == null) continue; 104 } 105 106 try { 107 MailAddress target = (targetAddress.indexOf('@') < 0) ? new MailAddress(targetAddress, "localhost") 108 : new MailAddress(targetAddress); 109 110 recipientsToRemove.add(source); 112 113 if (getMailetContext().isLocalServer(target.getHost())) { 116 recipientsToAddLocal.add(target); 117 } else { 118 recipientsToAddForward.add(target); 119 } 120 121 StringBuffer buf = new StringBuffer ().append("Translating virtual user ") 122 .append(source) 123 .append(" to ") 124 .append(target); 125 log(buf.toString()); 126 127 } catch (ParseException pe) { 128 StringBuffer exceptionBuffer = 130 new StringBuffer (128) 131 .append("There is an invalid map from ") 132 .append(source) 133 .append(" to ") 134 .append(targetAddress); 135 log(exceptionBuffer.toString()); 136 continue; 137 } 138 } 139 } 140 } 141 } 142 143 recipients.removeAll(recipientsToRemove); 145 146 recipients.addAll(recipientsToAddLocal); 148 149 157 if (recipientsToAddForward.size() != 0) { 159 162 MailImpl newMail = (MailImpl) ((MailImpl) mail).duplicate(newName((MailImpl) mail)); 164 try { 165 newMail.setRemoteAddr(java.net.InetAddress.getLocalHost().getHostAddress()); 166 newMail.setRemoteHost(java.net.InetAddress.getLocalHost().getHostName()); 167 } catch (java.net.UnknownHostException _) { 168 newMail.setRemoteAddr("127.0.0.1"); 169 newMail.setRemoteHost("localhost"); 170 } 171 newMail.setRecipients(recipientsToAddForward); 172 newMail.setAttribute(MARKER, Boolean.TRUE); 173 getMailetContext().sendMail(newMail); 174 } 175 176 if (recipients.size() == 0) { 178 mail.setState(Mail.GHOST); 179 } 180 } 181 182 195 protected abstract void mapRecipients(Map recipientsMap) throws MessagingException ; 196 197 204 private void processDSN(Mail mail, MailAddress address, String error) { 205 int msgPos = error.indexOf(' '); 207 try { 208 Integer code = Integer.valueOf(error.substring("error:".length(),msgPos)); 209 } catch (NumberFormatException e) { 210 log("Cannot send DSN. Exception parsing DSN code from: " + error, e); 211 return; 212 } 213 String msg = error.substring(msgPos + 1); 214 try { 216 getMailetContext().bounce(mail, error); 217 } 218 catch (MessagingException me) { 219 log("Cannot send DSN. Exception during DSN processing: ", me); 220 } 221 } 222 223 234 private String regexMap(Mail mail, MailAddress address, String targetString) { 235 String result = null; 236 237 try { 238 int msgPos = targetString.indexOf(':', "regex:".length() + 1); 239 240 246 Pattern pattern = new Perl5Compiler().compile(targetString.substring("regex:".length(), msgPos)); 247 Perl5Matcher matcher = new Perl5Matcher(); 248 249 if (matcher.matches(address.toString(), pattern)) { 250 MatchResult match = matcher.getMatch(); 251 Map parameters = new HashMap (match.groups()); 252 for (int i = 1; i < match.groups(); i++) { 253 parameters.put(Integer.toString(i), match.group(i)); 254 } 255 result = XMLResources.replaceParameters(targetString.substring(msgPos + 1), parameters); 256 } 257 } 258 catch (Exception e) { 259 log("Exception during regexMap processing: ", e); 260 } 261 262 return result; 264 } 265 266 272 private String getSeparator(String targetString) { 273 return (targetString.indexOf(',') > -1 ? "," : (targetString.indexOf(';') > -1 ? ";" : (targetString.indexOf("regex:") > -1? "" : ":" ))); 274 } 275 276 private static final java.util.Random random = new java.util.Random (); 278 284 private String newName(MailImpl mail) throws MessagingException { 285 String oldName = mail.getName(); 286 287 if (oldName.length() > 76) { 292 int count = 0; 293 int index = 0; 294 while ((index = oldName.indexOf('!', index + 1)) >= 0) { 295 count++; 296 } 297 if (count > 7) { 299 throw new MessagingException ("Unable to create a new message name: too long. Possible loop in config.xml."); 300 } 301 else { 302 oldName = oldName.substring(0, 76); 303 } 304 } 305 306 StringBuffer nameBuffer = 307 new StringBuffer (64) 308 .append(oldName) 309 .append("-!") 310 .append(random.nextInt(1048576)); 311 return nameBuffer.toString(); 312 } 313 } 314 | Popular Tags |