1 17 18 package org.apache.james.transport.mailets; 19 20 import java.io.PrintWriter ; 21 import java.io.StringWriter ; 22 import java.net.ConnectException ; 23 import java.net.InetAddress ; 24 import java.net.SocketException ; 25 import java.net.UnknownHostException ; 26 import java.util.Arrays ; 27 import java.util.Collection ; 28 import java.util.Date ; 29 import java.util.Hashtable ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.Locale ; 33 import java.util.Properties ; 34 import java.util.StringTokenizer ; 35 import java.util.Vector ; 36 import java.util.ArrayList ; 37 38 import javax.mail.Address ; 39 import javax.mail.MessagingException ; 40 import javax.mail.SendFailedException ; 41 import javax.mail.Session ; 42 import javax.mail.Transport ; 43 import javax.mail.URLName ; 44 import javax.mail.internet.AddressException ; 45 import javax.mail.internet.InternetAddress ; 46 import javax.mail.internet.MimeMessage ; 47 import javax.mail.internet.ParseException ; 48 49 import org.apache.avalon.framework.component.ComponentException; 50 import org.apache.avalon.framework.component.ComponentManager; 51 import org.apache.avalon.framework.configuration.DefaultConfiguration; 52 import org.apache.james.Constants; 53 import org.apache.james.core.MailImpl; 54 import org.apache.james.services.MailServer; 55 import org.apache.james.services.MailStore; 56 import org.apache.james.services.SpoolRepository; 57 import org.apache.mailet.MailetContext; 58 import org.apache.mailet.GenericMailet; 59 import org.apache.mailet.HostAddress; 60 import org.apache.mailet.Mail; 61 import org.apache.mailet.MailAddress; 62 63 import org.apache.oro.text.regex.MalformedPatternException; 64 import org.apache.oro.text.regex.Pattern; 65 import org.apache.oro.text.regex.Perl5Compiler; 66 import org.apache.oro.text.regex.Perl5Matcher; 67 import org.apache.oro.text.regex.MatchResult; 68 69 70 93 public class RemoteDelivery extends GenericMailet implements Runnable { 94 95 private static final long DEFAULT_DELAY_TIME = 21600000; private static final String PATTERN_STRING = 97 "\\s*([0-9]*\\s*[\\*])?\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*"; 100 private static Pattern PATTERN = null; private static final HashMap MULTIPLIERS = new HashMap (10); 104 109 static { 110 try { 111 Perl5Compiler compiler = new Perl5Compiler(); 112 PATTERN = compiler.compile(PATTERN_STRING, Perl5Compiler.READ_ONLY_MASK); 113 } catch(MalformedPatternException mpe) { 114 System.err.println ("Malformed pattern: " + PATTERN_STRING); 116 mpe.printStackTrace (System.err); 117 } 118 MULTIPLIERS.put ("msec", new Integer (1)); 120 MULTIPLIERS.put ("msecs", new Integer (1)); 121 MULTIPLIERS.put ("sec", new Integer (1000)); 122 MULTIPLIERS.put ("secs", new Integer (1000)); 123 MULTIPLIERS.put ("minute", new Integer (1000*60)); 124 MULTIPLIERS.put ("minutes", new Integer (1000*60)); 125 MULTIPLIERS.put ("hour", new Integer (1000*60*60)); 126 MULTIPLIERS.put ("hours", new Integer (1000*60*60)); 127 MULTIPLIERS.put ("day", new Integer (1000*60*60*24)); 128 MULTIPLIERS.put ("days", new Integer (1000*60*60*24)); 129 } 130 131 136 private class MultipleDelayFilter implements SpoolRepository.AcceptFilter 137 { 138 141 long youngest = 0; 142 143 151 public boolean accept (String key, String state, long lastUpdated, String errorMessage) { 152 if (state.equals(Mail.ERROR)) { 153 int retries = Integer.parseInt(errorMessage); 155 long delay = getNextDelay (retries); 156 long timeToProcess = delay + lastUpdated; 157 158 159 if (System.currentTimeMillis() > timeToProcess) { 160 return true; 162 } else { 163 if (youngest == 0 || youngest > timeToProcess) { 165 youngest = timeToProcess; 167 } 168 return false; 169 } 170 } else { 171 return true; 173 } 174 } 175 176 180 public long getWaitTime () { 181 if (youngest == 0) { 182 return 0; 183 } else { 184 long duration = youngest - System.currentTimeMillis(); 185 youngest = 0; return duration <= 0 ? 1 : duration; 187 } 188 } 189 } 190 191 194 private boolean isDebug = false; 195 196 private SpoolRepository outgoing; private long[] delayTimes; private int maxRetries = 5; private long smtpTimeout = 600000; private boolean sendPartial = false; private int connectionTimeout = 60000; private int deliveryThreadCount = 1; private Collection gatewayServer = null; private String bindAddress = null; private boolean isBindUsed = false; private Collection deliveryThreads = new Vector (); 209 private MailServer mailServer; 210 private volatile boolean destroyed = false; private String bounceProcessor = null; 213 private Perl5Matcher delayTimeMatcher; private MultipleDelayFilter delayFilter = new MultipleDelayFilter (); 216 219 public void init() throws MessagingException { 220 isDebug = (getInitParameter("debug") == null) ? false : new Boolean (getInitParameter("debug")).booleanValue(); 221 ArrayList delay_times_list = new ArrayList (); 222 try { 223 if (getInitParameter("delayTime") != null) { 224 delayTimeMatcher = new Perl5Matcher(); 225 String delay_times = getInitParameter("delayTime"); 226 StringTokenizer st = new StringTokenizer (delay_times,","); 228 while (st.hasMoreTokens()) { 229 String delay_time = st.nextToken(); 230 delay_times_list.add (new Delay(delay_time)); 231 } 232 } else { 233 delay_times_list.add (new Delay()); 235 } 236 } catch (Exception e) { 237 log("Invalid delayTime setting: " + getInitParameter("delayTime")); 238 } 239 try { 240 if (getInitParameter("maxRetries") != null) { 241 maxRetries = Integer.parseInt(getInitParameter("maxRetries")); 242 } 243 int total_attempts = calcTotalAttempts (delay_times_list); 245 if (total_attempts > maxRetries) { 246 log("Total number of delayTime attempts exceeds maxRetries specified. Increasing maxRetries from "+maxRetries+" to "+total_attempts); 247 maxRetries = total_attempts; 248 } else { 249 int extra = maxRetries - total_attempts; 250 if (extra != 0) { 251 log("maxRetries is larger than total number of attempts specified. Increasing last delayTime with "+extra+" attempts "); 252 253 if (delay_times_list.size() != 0) { 254 Delay delay = (Delay)delay_times_list.get (delay_times_list.size()-1); delay.setAttempts (delay.getAttempts()+extra); 256 log("Delay of "+delay.getDelayTime()+" msecs is now attempted: "+delay.getAttempts()+" times"); 257 } else { 258 log ("NO, delaytimes cannot continue"); 259 } 260 } 261 } 262 delayTimes = expandDelays (delay_times_list); 263 264 } catch (Exception e) { 265 log("Invalid maxRetries setting: " + getInitParameter("maxRetries")); 266 } 267 try { 268 if (getInitParameter("timeout") != null) { 269 smtpTimeout = Integer.parseInt(getInitParameter("timeout")); 270 } 271 } catch (Exception e) { 272 log("Invalid timeout setting: " + getInitParameter("timeout")); 273 } 274 275 try { 276 if (getInitParameter("connectiontimeout") != null) { 277 connectionTimeout = Integer.parseInt(getInitParameter("connectiontimeout")); 278 } 279 } catch (Exception e) { 280 log("Invalid timeout setting: " + getInitParameter("timeout")); 281 } 282 sendPartial = (getInitParameter("sendpartial") == null) ? false : new Boolean (getInitParameter("sendpartial")).booleanValue(); 283 284 bounceProcessor = getInitParameter("bounceProcessor"); 285 286 String gateway = getInitParameter("gateway"); 287 String gatewayPort = getInitParameter("gatewayPort"); 288 289 if (gateway != null) { 290 gatewayServer = new ArrayList (); 291 StringTokenizer st = new StringTokenizer (gateway, ",") ; 292 while (st.hasMoreTokens()) { 293 String server = st.nextToken().trim() ; 294 if (server.indexOf(':') < 0 && gatewayPort != null) { 295 server += ":"; 296 server += gatewayPort; 297 } 298 299 if (isDebug) log("Adding SMTP gateway: " + server) ; 300 gatewayServer.add(server); 301 } 302 } 303 304 ComponentManager compMgr = (ComponentManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER); 305 String outgoingPath = getInitParameter("outgoing"); 306 if (outgoingPath == null) { 307 outgoingPath = "file:///../var/mail/outgoing"; 308 } 309 310 try { 311 MailStore mailstore = (MailStore) compMgr.lookup("org.apache.james.services.MailStore"); 313 314 DefaultConfiguration spoolConf 315 = new DefaultConfiguration("repository", "generated:RemoteDelivery.java"); 316 spoolConf.setAttribute("destinationURL", outgoingPath); 317 spoolConf.setAttribute("type", "SPOOL"); 318 outgoing = (SpoolRepository) mailstore.select(spoolConf); 319 } catch (ComponentException cnfe) { 320 log("Failed to retrieve Store component:" + cnfe.getMessage()); 321 } catch (Exception e) { 322 log("Failed to retrieve Store component:" + e.getMessage()); 323 } 324 325 try { 327 deliveryThreadCount = Integer.parseInt(getInitParameter("deliveryThreads")); 328 } catch (Exception e) { 329 } 330 for (int i = 0; i < deliveryThreadCount; i++) { 331 StringBuffer nameBuffer = 332 new StringBuffer (32) 333 .append("Remote delivery thread (") 334 .append(i) 335 .append(")"); 336 Thread t = new Thread (this, nameBuffer.toString()); 337 t.start(); 338 deliveryThreads.add(t); 339 } 340 341 bindAddress = getInitParameter("bind"); 342 isBindUsed = bindAddress != null; 343 try { 344 if (isBindUsed) RemoteDeliverySocketFactory.setBindAdress(bindAddress); 345 } catch (UnknownHostException e) { 346 log("Invalid bind setting (" + bindAddress + "): " + e.toString()); 347 } 348 } 349 350 361 private boolean deliver(MailImpl mail, Session session) { 362 try { 363 if (isDebug) { 364 log("Attempting to deliver " + mail.getName()); 365 } 366 MimeMessage message = mail.getMessage(); 367 368 Collection recipients = mail.getRecipients(); 370 InternetAddress addr[] = new InternetAddress [recipients.size()]; 371 int j = 0; 372 for (Iterator i = recipients.iterator(); i.hasNext(); j++) { 373 MailAddress rcpt = (MailAddress)i.next(); 374 addr[j] = rcpt.toInternetAddress(); 375 } 376 377 if (addr.length <= 0) { 378 log("No recipients specified... not sure how this could have happened."); 379 return true; 380 } 381 382 Iterator targetServers = null; 385 if (gatewayServer == null) { 386 MailAddress rcpt = (MailAddress) recipients.iterator().next(); 387 String host = rcpt.getHost(); 388 389 targetServers = getMailetContext().getSMTPHostAddresses(host); 391 if (!targetServers.hasNext()) { 392 log("No mail server found for: " + host); 393 StringBuffer exceptionBuffer = 394 new StringBuffer (128) 395 .append("There are no DNS entries for the hostname ") 396 .append(host) 397 .append(". I cannot determine where to send this message."); 398 return failMessage(mail, new MessagingException (exceptionBuffer.toString()), false); 399 } 400 } else { 401 targetServers = getGatewaySMTPHostAddresses(gatewayServer); 402 } 403 404 MessagingException lastError = null; 405 406 while ( targetServers.hasNext()) { 407 try { 408 HostAddress outgoingMailServer = (HostAddress) targetServers.next(); 409 StringBuffer logMessageBuffer = 410 new StringBuffer (256) 411 .append("Attempting delivery of ") 412 .append(mail.getName()) 413 .append(" to host ") 414 .append(outgoingMailServer.getHostName()) 415 .append(" at ") 416 .append(outgoingMailServer.getHost()) 417 .append(" to addresses ") 418 .append(Arrays.asList(addr)); 419 log(logMessageBuffer.toString()); 420 421 Properties props = session.getProperties(); 422 if (mail.getSender() == null) { 423 props.put("mail.smtp.from", "<>"); 424 } else { 425 String sender = mail.getSender().toString(); 426 props.put("mail.smtp.from", sender); 427 } 428 429 435 Transport transport = null; 436 try { 437 transport = session.getTransport(outgoingMailServer); 438 try { 439 transport.connect(); 440 } catch (MessagingException me) { 441 log(me.getMessage()); 446 continue; 447 } 448 transport.sendMessage(message, addr); 449 } finally { 450 if (transport != null) { 451 transport.close(); 452 transport = null; 453 } 454 } 455 logMessageBuffer = 456 new StringBuffer (256) 457 .append("Mail (") 458 .append(mail.getName()) 459 .append(") sent successfully to ") 460 .append(outgoingMailServer.getHostName()) 461 .append(" at ") 462 .append(outgoingMailServer.getHost()); 463 log(logMessageBuffer.toString()); 464 return true; 465 } catch (SendFailedException sfe) { 466 if (sfe.getValidSentAddresses() == null 467 || sfe.getValidSentAddresses().length < 1) { 468 if (isDebug) log("Send failed, continuing with any other servers"); 469 lastError = sfe; 470 continue; 471 } else { 472 throw sfe; 475 } 476 } catch (MessagingException me) { 477 StringBuffer exceptionBuffer = 479 new StringBuffer (256) 480 .append("Exception delivering message (") 481 .append(mail.getName()) 482 .append(") - ") 483 .append(me.getMessage()); 484 log(exceptionBuffer.toString()); 485 if ((me.getNextException() != null) && 486 (me.getNextException() instanceof java.io.IOException )) { 487 489 lastError = me; 492 continue; 493 } 494 throw me; 501 } 502 } if (lastError != null) { 510 throw lastError; 511 } 512 } catch (SendFailedException sfe) { 513 boolean deleteMessage = false; 514 Collection recipients = mail.getRecipients(); 515 516 if (isDebug) log("Recipients: " + recipients); 518 519 535 536 556 557 if (sfe.getInvalidAddresses() != null) { 558 Address [] address = sfe.getInvalidAddresses(); 559 if (address.length > 0) { 560 recipients.clear(); 561 for (int i = 0; i < address.length; i++) { 562 try { 563 recipients.add(new MailAddress(address[i].toString())); 564 } catch (ParseException pe) { 565 log("Can't parse invalid address: " + pe.getMessage()); 569 } 570 } 571 if (isDebug) log("Invalid recipients: " + recipients); 572 deleteMessage = failMessage(mail, sfe, true); 573 } 574 } 575 576 if (sfe.getValidUnsentAddresses() != null) { 577 Address [] address = sfe.getValidUnsentAddresses(); 578 if (address.length > 0) { 579 recipients.clear(); 580 for (int i = 0; i < address.length; i++) { 581 try { 582 recipients.add(new MailAddress(address[i].toString())); 583 } catch (ParseException pe) { 584 log("Can't parse unsent address: " + pe.getMessage()); 588 } 589 } 590 if (isDebug) log("Unsent recipients: " + recipients); 591 deleteMessage = failMessage(mail, sfe, false); 592 } 593 } 594 595 return deleteMessage; 596 } catch (MessagingException ex) { 597 602 604 return failMessage(mail, ex, ('5' == ex.getMessage().charAt(0))); 609 } 610 611 617 return failMessage(mail, new MessagingException ("No mail server(s) available at this time."), false); 618 } 619 620 628 private boolean failMessage(MailImpl mail, MessagingException ex, boolean permanent) { 629 StringWriter sout = new StringWriter (); 630 PrintWriter out = new PrintWriter (sout, true); 631 if (permanent) { 632 out.print("Permanent"); 633 } else { 634 out.print("Temporary"); 635 } 636 StringBuffer logBuffer = 637 new StringBuffer (64) 638 .append(" exception delivering mail (") 639 .append(mail.getName()) 640 .append(": "); 641 out.print(logBuffer.toString()); 642 ex.printStackTrace(out); 643 log(sout.toString()); 644 if (!permanent) { 645 if (!mail.getState().equals(Mail.ERROR)) { 646 mail.setState(Mail.ERROR); 647 mail.setErrorMessage("0"); 648 mail.setLastUpdated(new Date ()); 649 } 650 int retries = Integer.parseInt(mail.getErrorMessage()); 651 if (retries < maxRetries) { 652 logBuffer = 653 new StringBuffer (128) 654 .append("Storing message ") 655 .append(mail.getName()) 656 .append(" into outgoing after ") 657 .append(retries) 658 .append(" retries"); 659 log(logBuffer.toString()); 660 ++retries; 661 mail.setErrorMessage(retries + ""); 662 mail.setLastUpdated(new Date ()); 663 return false; 664 } else { 665 logBuffer = 666 new StringBuffer (128) 667 .append("Bouncing message ") 668 .append(mail.getName()) 669 .append(" after ") 670 .append(retries) 671 .append(" retries"); 672 log(logBuffer.toString()); 673 } 674 } 675 if (bounceProcessor != null) { 676 mail.setAttribute("delivery-error", ex); 679 mail.setState(bounceProcessor); 680 MailetContext mc = getMailetContext(); 682 try { 683 mc.sendMail(mail); 684 } catch (MessagingException e) { 685 log("Exception re-inserting failed mail: ", e); 687 } 688 } else { 689 bounce(mail, ex); 691 } 692 return true; 693 } 694 695 private void bounce(MailImpl mail, MessagingException ex) { 696 StringWriter sout = new StringWriter (); 697 PrintWriter out = new PrintWriter (sout, true); 698 String machine = "[unknown]"; 699 try { 700 InetAddress me = InetAddress.getLocalHost(); 701 machine = me.getHostName(); 702 } catch(Exception e){ 703 machine = "[address unknown]"; 704 } 705 StringBuffer bounceBuffer = 706 new StringBuffer (128) 707 .append("Hi. This is the James mail server at ") 708 .append(machine) 709 .append("."); 710 out.println(bounceBuffer.toString()); 711 out.println("I'm afraid I wasn't able to deliver your message to the following addresses."); 712 out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below"); 713 out.println("I include the list of recipients and the reason why I was unable to deliver"); 714 out.println("your message."); 715 out.println(); 716 for (Iterator i = mail.getRecipients().iterator(); i.hasNext(); ) { 717 out.println(i.next()); 718 } 719 if (ex.getNextException() == null) { 720 out.println(ex.getMessage().trim()); 721 } else { 722 Exception ex1 = ex.getNextException(); 723 if (ex1 instanceof SendFailedException ) { 724 out.println("Remote mail server told me: " + ex1.getMessage().trim()); 725 } else if (ex1 instanceof UnknownHostException ) { 726 out.println("Unknown host: " + ex1.getMessage().trim()); 727 out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server."); 728 } else if (ex1 instanceof ConnectException ) { 729 out.println(ex1.getMessage().trim()); 731 } else if (ex1 instanceof SocketException ) { 732 out.println("Socket exception: " + ex1.getMessage().trim()); 733 } else { 734 out.println(ex1.getMessage().trim()); 735 } 736 } 737 out.println(); 738 out.println("The original message is attached."); 739 740 log("Sending failure message " + mail.getName()); 741 try { 742 getMailetContext().bounce(mail, sout.toString()); 743 } catch (MessagingException me) { 744 log("Encountered unexpected messaging exception while bouncing message: " + me.getMessage()); 745 } catch (Exception e) { 746 log("Encountered unexpected exception while bouncing message: " + e.getMessage()); 747 } 748 } 749 750 public String getMailetInfo() { 751 return "RemoteDelivery Mailet"; 752 } 753 754 762 public void service(Mail genericmail) throws MessagingException { 763 MailImpl mail = (MailImpl)genericmail; 764 765 if (isDebug) { 767 log("Remotely delivering mail " + mail.getName()); 768 } 769 Collection recipients = mail.getRecipients(); 770 771 if (gatewayServer == null) { 772 Hashtable targets = new Hashtable (); 774 for (Iterator i = recipients.iterator(); i.hasNext();) { 775 MailAddress target = (MailAddress)i.next(); 776 String targetServer = target.getHost().toLowerCase(Locale.US); 777 Collection temp = (Collection )targets.get(targetServer); 778 if (temp == null) { 779 temp = new ArrayList (); 780 targets.put(targetServer, temp); 781 } 782 temp.add(target); 783 } 784 785 788 String name = mail.getName(); 790 for (Iterator i = targets.keySet().iterator(); i.hasNext(); ) { 791 String host = (String ) i.next(); 792 Collection rec = (Collection ) targets.get(host); 793 if (isDebug) { 794 StringBuffer logMessageBuffer = 795 new StringBuffer (128) 796 .append("Sending mail to ") 797 .append(rec) 798 .append(" on host ") 799 .append(host); 800 log(logMessageBuffer.toString()); 801 } 802 mail.setRecipients(rec); 803 StringBuffer nameBuffer = 804 new StringBuffer (128) 805 .append(name) 806 .append("-to-") 807 .append(host); 808 mail.setName(nameBuffer.toString()); 809 outgoing.store(mail); 810 } 812 } else { 813 if (isDebug) { 815 StringBuffer logMessageBuffer = 816 new StringBuffer (128) 817 .append("Sending mail to ") 818 .append(mail.getRecipients()) 819 .append(" via ") 820 .append(gatewayServer); 821 log(logMessageBuffer.toString()); 822 } 823 824 outgoing.store(mail); 826 } 827 mail.setState(Mail.GHOST); 828 } 829 830 public synchronized void destroy() { 832 destroyed = true; 834 for (Iterator i = deliveryThreads.iterator(); i.hasNext(); ) { 836 Thread t = (Thread )i.next(); 837 t.interrupt(); 838 } 839 notifyAll(); 840 } 841 842 846 public void run() { 847 848 857 long stop = System.currentTimeMillis() + 60000; 858 while ((getMailetContext().getAttribute(Constants.HELLO_NAME) == null) 859 && stop > System.currentTimeMillis()) { 860 try { 861 Thread.sleep(1000); 862 } catch (Exception ignored) {} } 864 865 Properties props = new Properties (); 867 props.put("mail.debug", "false"); 869 props.put("mail.smtp.ehlo", "false"); 871 props.put("mail.smtp.timeout", smtpTimeout + ""); 873 874 props.put("mail.smtp.connectiontimeout", connectionTimeout + ""); 875 props.put("mail.smtp.sendpartial",String.valueOf(sendPartial)); 876 877 if (getMailetContext().getAttribute(Constants.HELLO_NAME) != null) { 879 props.put("mail.smtp.localhost", (String ) getMailetContext().getAttribute(Constants.HELLO_NAME)); 880 } 881 else { 882 Collection servernames = (Collection ) getMailetContext().getAttribute(Constants.SERVER_NAMES); 883 if ((servernames != null) && (servernames.size() > 0)) { 884 props.put("mail.smtp.localhost", (String ) servernames.iterator().next()); 885 } 886 } 887 888 if (isBindUsed) { 889 props.put("mail.smtp.socketFactory.class", 892 "org.apache.james.transport.mailets.RemoteDeliverySocketFactory"); 893 props.put("mail.smtp.socketFactory.fallback", "false"); 895 } 896 897 Session session = Session.getInstance(props, null); 898 try { 899 while (!Thread.currentThread().interrupted() && !destroyed) { 900 try { 901 MailImpl mail = (MailImpl)outgoing.accept(delayFilter); 902 String key = mail.getName(); 903 try { 904 if (isDebug) { 905 StringBuffer logMessageBuffer = 906 new StringBuffer (128) 907 .append(Thread.currentThread().getName()) 908 .append(" will process mail ") 909 .append(key); 910 log(logMessageBuffer.toString()); 911 } 912 if (deliver(mail, session)) { 913 outgoing.remove(key); 915 } else { 916 outgoing.store(mail); 918 } 919 mail = null; 921 } catch (Exception e) { 922 outgoing.remove(key); 925 throw e; 926 } 927 } catch (Throwable e) { 928 if (!destroyed) log("Exception caught in RemoteDelivery.run()", e); 929 } 930 } 931 } finally { 932 Thread.currentThread().interrupted(); 934 } 935 } 936 937 941 private int calcTotalAttempts (ArrayList list) { 942 int sum = 0; 943 Iterator i = list.iterator(); 944 while (i.hasNext()) { 945 Delay delay = (Delay)i.next(); 946 sum += delay.getAttempts(); 947 } 948 return sum; 949 } 950 951 962 private long[] expandDelays (ArrayList list) { 963 long[] delays = new long [calcTotalAttempts(list)]; 964 Iterator i = list.iterator(); 965 int idx = 0; 966 while (i.hasNext()) { 967 Delay delay = (Delay)i.next(); 968 for (int j=0; j<delay.getAttempts(); j++) { 969 delays[idx++]= delay.getDelayTime(); 970 } 971 } 972 return delays; 973 } 974 975 980 private long getNextDelay (int retry_count) { 981 return delayTimes[retry_count-1]; 982 } 983 984 988 private class Delay { 989 private int attempts = 1; 990 private long delayTime = DEFAULT_DELAY_TIME; 991 992 993 1001 public Delay (String init_string) throws MessagingException 1002 { 1003 String unit = "msec"; if (delayTimeMatcher.matches (init_string, PATTERN)) { 1005 MatchResult res = delayTimeMatcher.getMatch (); 1006 1011 if (res.group(1) != null && !res.group(1).equals ("")) { 1012 String attempt_match = res.group(1); 1014 attempt_match = attempt_match.substring (0,attempt_match.length()-1).trim(); 1016 attempts = Integer.parseInt (attempt_match); 1017 } 1018 1019 delayTime = Long.parseLong (res.group(2)); 1020 1021 if (!res.group(3).equals ("")) { 1022 unit = res.group(3).toLowerCase(); 1024 } 1025 } else { 1026 throw new MessagingException (init_string+" does not match "+PATTERN_STRING); 1027 } 1028 if (MULTIPLIERS.get (unit)!=null) { 1029 int multiplier = ((Integer )MULTIPLIERS.get (unit)).intValue(); 1030 delayTime *= multiplier; 1031 } else { 1032 throw new MessagingException ("Unknown unit: "+unit); 1033 } 1034 } 1035 1036 1039 public Delay () { 1040 } 1041 1042 1045 public long getDelayTime () { 1046 return delayTime; 1047 } 1048 1049 1052 public int getAttempts () { 1053 return attempts; 1054 } 1055 1056 1059 public void setAttempts (int value) { 1060 attempts = value; 1061 } 1062 1063 1066 public String toString () { 1067 StringBuffer buf = new StringBuffer (15); 1068 buf.append (getAttempts ()); 1069 buf.append ('*'); 1070 buf.append (getDelayTime()); 1071 buf.append ("msec"); 1072 return buf.toString(); 1073 } 1074 } 1075 1076 1091 private Iterator getGatewaySMTPHostAddresses(final Collection gatewayServers) { 1092 return new Iterator () { 1093 private Iterator gateways = gatewayServers.iterator(); 1094 private Iterator addresses = null; 1095 1096 public boolean hasNext() { 1097 return gateways.hasNext(); 1098 } 1099 1100 public Object next() { 1101 if (addresses == null || !addresses.hasNext()) 1102 { 1103 String server = (String ) gateways.next(); 1104 String port = "25"; 1105 1106 int idx = server.indexOf(':'); 1107 if ( idx > 0) { 1108 port = server.substring(idx+1); 1109 server = server.substring(0,idx); 1110 } 1111 1112 final String nextGateway = server; 1113 final String nextGatewayPort = port; 1114 try { 1115 final InetAddress [] ips = org.apache.james.dnsserver.DNSServer.getAllByName(nextGateway); 1116 addresses = new Iterator () { 1117 private InetAddress [] ipAddresses = ips; 1118 int i = 0; 1119 1120 public boolean hasNext() { 1121 return i < ipAddresses.length; 1122 } 1123 1124 public Object next() { 1125 return new org.apache.mailet.HostAddress(nextGateway, "smtp://" + (ipAddresses[i++]).getHostAddress() + ":" + nextGatewayPort); 1126 } 1127 1128 public void remove() { 1129 throw new UnsupportedOperationException ("remove not supported by this iterator"); 1130 } 1131 }; 1132 } 1133 catch (java.net.UnknownHostException uhe) { 1134 log("Unknown gateway host: " + uhe.getMessage().trim()); 1135 log("This could be a DNS server error or configuration error."); 1136 } 1137 } 1138 return (addresses != null) ? addresses.next() : null; 1139 } 1140 1141 public void remove() { 1142 throw new UnsupportedOperationException ("remove not supported by this iterator"); 1143 } 1144 }; 1145 } 1146} 1147 | Popular Tags |