hilmer 2003/12/12 14:48:19
Modified: src/java/org/apache/james Tag: branch_2_1_fcs James.java
src/java/org/apache/james/dnsserver Tag: branch_2_1_fcs
DNSServer.java
src/java/org/apache/james/services Tag: branch_2_1_fcs
DNSServer.java
src/java/org/apache/james/transport/mailets Tag:
branch_2_1_fcs RemoteDelivery.java
src/java/org/apache/mailet Tag: branch_2_1_fcs
MailetContext.java
Added: src/java/org/apache/james/dnsserver Tag: branch_2_1_fcs
SMTPHostAddressesImpl.java
Log:
PR:BUG 24885
Submitted by:"Richard O. Hammer" <[EMAIL PROTECTED]>
Reviewed by: Soeren Hilmer <[EMAIL PROTECTED]>
This commit fixes BUG 24885. James did not handle multihomedness of SMTP hosts.
The fix adds a new method and inner class to MailetContext of the mailet api.
Revision Changes Path
No revision
No revision
1.35.4.12 +25 -1 james-server/src/java/org/apache/james/James.java
Index: James.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/james/James.java,v
retrieving revision 1.35.4.11
retrieving revision 1.35.4.12
diff -u -r1.35.4.11 -r1.35.4.12
--- James.java 20 Oct 2003 06:03:15 -0000 1.35.4.11
+++ James.java 12 Dec 2003 22:48:18 -0000 1.35.4.12
@@ -945,4 +945,28 @@
success = localusers.addUser(user);
return success;
}
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP.
+ * Returns one SMTPHostAddresses for each such host discovered
+ * by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Iterator in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ public Iterator getSMTPHostAddresses(String domainName) {
+ DNSServer dnsServer = null;
+ try {
+ dnsServer = (DNSServer) compMgr.lookup( DNSServer.ROLE );
+ } catch ( final ComponentException cme ) {
+ getLogger().error("Fatal configuration error - DNS Servers lost!", cme
);
+ throw new RuntimeException("Fatal configuration error - DNS Servers
lost!");
+ }
+ return dnsServer.getSMTPHostAddresses(domainName);
+ }
+
}
No revision
No revision
1.9.4.9 +138 -0 james-server/src/java/org/apache/james/dnsserver/DNSServer.java
Index: DNSServer.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/james/dnsserver/DNSServer.java,v
retrieving revision 1.9.4.8
retrieving revision 1.9.4.9
diff -u -r1.9.4.8 -r1.9.4.9
--- DNSServer.java 29 Aug 2003 05:22:13 -0000 1.9.4.8
+++ DNSServer.java 12 Dec 2003 22:48:19 -0000 1.9.4.9
@@ -70,6 +70,7 @@
import org.xbill.DNS.FindServer;
import org.xbill.DNS.Message;
import org.xbill.DNS.MXRecord;
+import org.xbill.DNS.ARecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
@@ -380,4 +381,141 @@
return (pa == pb) ? (512 - random.nextInt(1024)) : pa - pb;
}
}
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP. Returns one SMTPHostAddresses for each such host
+ * discovered by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Enumeration in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ public Iterator getSMTPHostAddresses(final String domainName) {
+ return new Iterator() {
+ private Iterator mxHosts = new MxSorter(domainName);
+
+ public boolean hasNext(){
+ return mxHosts.hasNext();
+ }
+
+ public Object next(){
+ String nextHostname = (String)mxHosts.next();
+ Record[] aRecords = lookup(nextHostname, Type.A);
+ return new SMTPHostAddressesImpl(aRecords, nextHostname);
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported
by this iterator");
+ }
+ };
+ }
+
+ /** A way to get mail hosts to try. If any MX hosts are found for the
+ * domain name with which this is constructed, then these MX hostnames
+ * are returned in priority sorted order, lowest priority numbers coming
+ * first. And, whenever multiple hosts have the same priority then these
+ * are returned in a randomized order within that priority group, as
+ * specified in RFC 2821, Section 5.
+ *
+ * If no MX hosts are found for the domain name, then a DNS search is
+ * performed for an A record. If an A record is found then domainName itself
+ * will be returned by the Iterator, and it will be the only object in
+ * the Iterator. If however no A record is found (in addition to no MX
+ * record) then the Iterator constructed will be empty; the first call to
+ * its hasNext() will return false.
+ *
+ * This behavior attempts to satisfy the requirements of RFC 2821, Section 5.
+ */
+ private class MxSorter implements Iterator {
+ private int priorListPriority = Integer.MIN_VALUE;
+ private ArrayList equiPriorityList = new ArrayList();
+ private Record[] mxRecords;
+ private Random rnd = new Random ();
+
+ /* The implementation of this class attempts to achieve efficiency by
+ * performing no more sorting of the rawMxRecords than necessary. In the
+ * large majority of cases the first attempt, made by a client of this class
+ * to connect to an SMTP server for a given domain, will succeed. As such,
+ * in most cases only one call will be made to this Iterator's
+ * next(), and in that majority of cases there will have been no need
+ * to sort the array of MX Records. This implementation would, however, be
+ * relatively inefficient in the case where all hosts fail, when every
+ * Object is called out of a long Iterator.
+ */
+
+ private MxSorter(String domainName) {
+ mxRecords = lookup(domainName, Type.MX);
+ if (mxRecords == null || mxRecords.length == 0) {
+ //no MX records were found, so try to use the domainName
+ Record[] aRecords = lookup(domainName, Type.A);
+ if(aRecords != null && aRecords.length > 0) {
+ equiPriorityList.add(domainName);
+ }
+ }
+ }
+
+ /**
+ * Sets presentPriorityList to contain all hosts
+ * which have the least priority greater than pastPriority.
+ * When this is called, both (rawMxRecords.length > 0) and
+ * (presentPriorityList.size() == 0), by contract.
+ * In the case where this is called repeatedly, so that priorListPriority
+ * has already become the highest of the priorities in the rawMxRecords,
+ * then this returns without having added any elements to
+ * presentPriorityList; presentPriorityList.size remains zero.
+ */
+ private void createPriorityList(){
+ int leastPriorityFound = Integer.MAX_VALUE;
+ /* We loop once through the rawMxRecords, finding the lowest priority
+ * greater than priorListPriority, and collecting all the hostnames
+ * with that priority into equiPriorityList.
+ */
+ for (int i = 0; i < mxRecords.length; i++) {
+ MXRecord thisRecord = (MXRecord)mxRecords[i];
+ int thisRecordPriority = thisRecord.getPriority();
+ if (thisRecordPriority > priorListPriority) {
+ if (thisRecordPriority < leastPriorityFound) {
+ equiPriorityList.clear();
+ leastPriorityFound = thisRecordPriority;
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ } else if (thisRecordPriority == leastPriorityFound) {
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ }
+ }
+ }
+ priorListPriority = leastPriorityFound;
+ }
+
+ public boolean hasNext(){
+ if (equiPriorityList.size() > 0){
+ return true;
+ }else if (mxRecords != null && mxRecords.length > 0){
+ createPriorityList();
+ return equiPriorityList.size() > 0;
+ } else{
+ return false;
+ }
+ }
+
+ public Object next(){
+ if (hasNext()){
+ /* this randomization is done to comply with RFC-2821 */
+ /* Note: java.util.Random.nextInt(limit) is about twice as fast as
(int)(Math.random()*limit) */
+ int getIndex = rnd.nextInt(equiPriorityList.size());
+ Object returnElement = equiPriorityList.get(getIndex);
+ equiPriorityList.remove(getIndex);
+ return returnElement;
+ }else{
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported by this
iterator");
+ }
+ }
+
}
No revision
Index: DNSServer.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/james/dnsserver/DNSServer.java,v
retrieving revision 1.9.4.8
retrieving revision 1.9.4.9
diff -u -r1.9.4.8 -r1.9.4.9
--- DNSServer.java 29 Aug 2003 05:22:13 -0000 1.9.4.8
+++ DNSServer.java 12 Dec 2003 22:48:19 -0000 1.9.4.9
@@ -70,6 +70,7 @@
import org.xbill.DNS.FindServer;
import org.xbill.DNS.Message;
import org.xbill.DNS.MXRecord;
+import org.xbill.DNS.ARecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
@@ -380,4 +381,141 @@
return (pa == pb) ? (512 - random.nextInt(1024)) : pa - pb;
}
}
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP. Returns one SMTPHostAddresses for each such host
+ * discovered by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Enumeration in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ public Iterator getSMTPHostAddresses(final String domainName) {
+ return new Iterator() {
+ private Iterator mxHosts = new MxSorter(domainName);
+
+ public boolean hasNext(){
+ return mxHosts.hasNext();
+ }
+
+ public Object next(){
+ String nextHostname = (String)mxHosts.next();
+ Record[] aRecords = lookup(nextHostname, Type.A);
+ return new SMTPHostAddressesImpl(aRecords, nextHostname);
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported
by this iterator");
+ }
+ };
+ }
+
+ /** A way to get mail hosts to try. If any MX hosts are found for the
+ * domain name with which this is constructed, then these MX hostnames
+ * are returned in priority sorted order, lowest priority numbers coming
+ * first. And, whenever multiple hosts have the same priority then these
+ * are returned in a randomized order within that priority group, as
+ * specified in RFC 2821, Section 5.
+ *
+ * If no MX hosts are found for the domain name, then a DNS search is
+ * performed for an A record. If an A record is found then domainName itself
+ * will be returned by the Iterator, and it will be the only object in
+ * the Iterator. If however no A record is found (in addition to no MX
+ * record) then the Iterator constructed will be empty; the first call to
+ * its hasNext() will return false.
+ *
+ * This behavior attempts to satisfy the requirements of RFC 2821, Section 5.
+ */
+ private class MxSorter implements Iterator {
+ private int priorListPriority = Integer.MIN_VALUE;
+ private ArrayList equiPriorityList = new ArrayList();
+ private Record[] mxRecords;
+ private Random rnd = new Random ();
+
+ /* The implementation of this class attempts to achieve efficiency by
+ * performing no more sorting of the rawMxRecords than necessary. In the
+ * large majority of cases the first attempt, made by a client of this class
+ * to connect to an SMTP server for a given domain, will succeed. As such,
+ * in most cases only one call will be made to this Iterator's
+ * next(), and in that majority of cases there will have been no need
+ * to sort the array of MX Records. This implementation would, however, be
+ * relatively inefficient in the case where all hosts fail, when every
+ * Object is called out of a long Iterator.
+ */
+
+ private MxSorter(String domainName) {
+ mxRecords = lookup(domainName, Type.MX);
+ if (mxRecords == null || mxRecords.length == 0) {
+ //no MX records were found, so try to use the domainName
+ Record[] aRecords = lookup(domainName, Type.A);
+ if(aRecords != null && aRecords.length > 0) {
+ equiPriorityList.add(domainName);
+ }
+ }
+ }
+
+ /**
+ * Sets presentPriorityList to contain all hosts
+ * which have the least priority greater than pastPriority.
+ * When this is called, both (rawMxRecords.length > 0) and
+ * (presentPriorityList.size() == 0), by contract.
+ * In the case where this is called repeatedly, so that priorListPriority
+ * has already become the highest of the priorities in the rawMxRecords,
+ * then this returns without having added any elements to
+ * presentPriorityList; presentPriorityList.size remains zero.
+ */
+ private void createPriorityList(){
+ int leastPriorityFound = Integer.MAX_VALUE;
+ /* We loop once through the rawMxRecords, finding the lowest priority
+ * greater than priorListPriority, and collecting all the hostnames
+ * with that priority into equiPriorityList.
+ */
+ for (int i = 0; i < mxRecords.length; i++) {
+ MXRecord thisRecord = (MXRecord)mxRecords[i];
+ int thisRecordPriority = thisRecord.getPriority();
+ if (thisRecordPriority > priorListPriority) {
+ if (thisRecordPriority < leastPriorityFound) {
+ equiPriorityList.clear();
+ leastPriorityFound = thisRecordPriority;
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ } else if (thisRecordPriority == leastPriorityFound) {
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ }
+ }
+ }
+ priorListPriority = leastPriorityFound;
+ }
+
+ public boolean hasNext(){
+ if (equiPriorityList.size() > 0){
+ return true;
+ }else if (mxRecords != null && mxRecords.length > 0){
+ createPriorityList();
+ return equiPriorityList.size() > 0;
+ } else{
+ return false;
+ }
+ }
+
+ public Object next(){
+ if (hasNext()){
+ /* this randomization is done to comply with RFC-2821 */
+ /* Note: java.util.Random.nextInt(limit) is about twice as fast as
(int)(Math.random()*limit) */
+ int getIndex = rnd.nextInt(equiPriorityList.size());
+ Object returnElement = equiPriorityList.get(getIndex);
+ equiPriorityList.remove(getIndex);
+ return returnElement;
+ }else{
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported by this
iterator");
+ }
+ }
+
}
No revision
Index: DNSServer.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/james/dnsserver/DNSServer.java,v
retrieving revision 1.9.4.8
retrieving revision 1.9.4.9
diff -u -r1.9.4.8 -r1.9.4.9
--- DNSServer.java 29 Aug 2003 05:22:13 -0000 1.9.4.8
+++ DNSServer.java 12 Dec 2003 22:48:19 -0000 1.9.4.9
@@ -70,6 +70,7 @@
import org.xbill.DNS.FindServer;
import org.xbill.DNS.Message;
import org.xbill.DNS.MXRecord;
+import org.xbill.DNS.ARecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
@@ -380,4 +381,141 @@
return (pa == pb) ? (512 - random.nextInt(1024)) : pa - pb;
}
}
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP. Returns one SMTPHostAddresses for each such host
+ * discovered by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Enumeration in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ public Iterator getSMTPHostAddresses(final String domainName) {
+ return new Iterator() {
+ private Iterator mxHosts = new MxSorter(domainName);
+
+ public boolean hasNext(){
+ return mxHosts.hasNext();
+ }
+
+ public Object next(){
+ String nextHostname = (String)mxHosts.next();
+ Record[] aRecords = lookup(nextHostname, Type.A);
+ return new SMTPHostAddressesImpl(aRecords, nextHostname);
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported
by this iterator");
+ }
+ };
+ }
+
+ /** A way to get mail hosts to try. If any MX hosts are found for the
+ * domain name with which this is constructed, then these MX hostnames
+ * are returned in priority sorted order, lowest priority numbers coming
+ * first. And, whenever multiple hosts have the same priority then these
+ * are returned in a randomized order within that priority group, as
+ * specified in RFC 2821, Section 5.
+ *
+ * If no MX hosts are found for the domain name, then a DNS search is
+ * performed for an A record. If an A record is found then domainName itself
+ * will be returned by the Iterator, and it will be the only object in
+ * the Iterator. If however no A record is found (in addition to no MX
+ * record) then the Iterator constructed will be empty; the first call to
+ * its hasNext() will return false.
+ *
+ * This behavior attempts to satisfy the requirements of RFC 2821, Section 5.
+ */
+ private class MxSorter implements Iterator {
+ private int priorListPriority = Integer.MIN_VALUE;
+ private ArrayList equiPriorityList = new ArrayList();
+ private Record[] mxRecords;
+ private Random rnd = new Random ();
+
+ /* The implementation of this class attempts to achieve efficiency by
+ * performing no more sorting of the rawMxRecords than necessary. In the
+ * large majority of cases the first attempt, made by a client of this class
+ * to connect to an SMTP server for a given domain, will succeed. As such,
+ * in most cases only one call will be made to this Iterator's
+ * next(), and in that majority of cases there will have been no need
+ * to sort the array of MX Records. This implementation would, however, be
+ * relatively inefficient in the case where all hosts fail, when every
+ * Object is called out of a long Iterator.
+ */
+
+ private MxSorter(String domainName) {
+ mxRecords = lookup(domainName, Type.MX);
+ if (mxRecords == null || mxRecords.length == 0) {
+ //no MX records were found, so try to use the domainName
+ Record[] aRecords = lookup(domainName, Type.A);
+ if(aRecords != null && aRecords.length > 0) {
+ equiPriorityList.add(domainName);
+ }
+ }
+ }
+
+ /**
+ * Sets presentPriorityList to contain all hosts
+ * which have the least priority greater than pastPriority.
+ * When this is called, both (rawMxRecords.length > 0) and
+ * (presentPriorityList.size() == 0), by contract.
+ * In the case where this is called repeatedly, so that priorListPriority
+ * has already become the highest of the priorities in the rawMxRecords,
+ * then this returns without having added any elements to
+ * presentPriorityList; presentPriorityList.size remains zero.
+ */
+ private void createPriorityList(){
+ int leastPriorityFound = Integer.MAX_VALUE;
+ /* We loop once through the rawMxRecords, finding the lowest priority
+ * greater than priorListPriority, and collecting all the hostnames
+ * with that priority into equiPriorityList.
+ */
+ for (int i = 0; i < mxRecords.length; i++) {
+ MXRecord thisRecord = (MXRecord)mxRecords[i];
+ int thisRecordPriority = thisRecord.getPriority();
+ if (thisRecordPriority > priorListPriority) {
+ if (thisRecordPriority < leastPriorityFound) {
+ equiPriorityList.clear();
+ leastPriorityFound = thisRecordPriority;
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ } else if (thisRecordPriority == leastPriorityFound) {
+ equiPriorityList.add(thisRecord.getTarget().toString());
+ }
+ }
+ }
+ priorListPriority = leastPriorityFound;
+ }
+
+ public boolean hasNext(){
+ if (equiPriorityList.size() > 0){
+ return true;
+ }else if (mxRecords != null && mxRecords.length > 0){
+ createPriorityList();
+ return equiPriorityList.size() > 0;
+ } else{
+ return false;
+ }
+ }
+
+ public Object next(){
+ if (hasNext()){
+ /* this randomization is done to comply with RFC-2821 */
+ /* Note: java.util.Random.nextInt(limit) is about twice as fast as
(int)(Math.random()*limit) */
+ int getIndex = rnd.nextInt(equiPriorityList.size());
+ Object returnElement = equiPriorityList.get(getIndex);
+ equiPriorityList.remove(getIndex);
+ return returnElement;
+ }else{
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove () {
+ throw new UnsupportedOperationException ("remove not supported by this
iterator");
+ }
+ }
+
}
1.1.2.1 +117 -0
james-server/src/java/org/apache/james/dnsserver/Attic/SMTPHostAddressesImpl.java
No revision
No revision
1.4.4.3 +16 -0 james-server/src/java/org/apache/james/services/DNSServer.java
Index: DNSServer.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/james/services/DNSServer.java,v
retrieving revision 1.4.4.2
retrieving revision 1.4.4.3
diff -u -r1.4.4.2 -r1.4.4.3
--- DNSServer.java 8 Mar 2003 21:54:06 -0000 1.4.4.2
+++ DNSServer.java 12 Dec 2003 22:48:19 -0000 1.4.4.3
@@ -59,6 +59,7 @@
package org.apache.james.services;
import java.util.Collection;
+import java.util.Iterator;
/**
* Provides abstraction for DNS resolutions. The interface is Mail specific.
@@ -83,4 +84,19 @@
* @return collection of strings representing MX record values.
*/
Collection findMXRecords(String hostname);
+
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP. Returns one SMTPHostAddresses for each such host
+ * discovered by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Enumeration in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ Iterator getSMTPHostAddresses(String domainName);
+
}
No revision
No revision
1.33.4.15 +167 -94
james-server/src/java/org/apache/james/transport/mailets/RemoteDelivery.java
Index: RemoteDelivery.java
===================================================================
RCS file:
/home/cvs/james-server/src/java/org/apache/james/transport/mailets/RemoteDelivery.java,v
retrieving revision 1.33.4.14
retrieving revision 1.33.4.15
diff -u -r1.33.4.14 -r1.33.4.15
--- RemoteDelivery.java 16 Nov 2003 21:47:24 -0000 1.33.4.14
+++ RemoteDelivery.java 12 Dec 2003 22:48:19 -0000 1.33.4.15
@@ -97,6 +97,7 @@
import org.apache.james.services.SpoolRepository;
import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
+import org.apache.mailet.MailetContext;
import org.apache.mailet.MailAddress;
import org.apache.oro.text.regex.MalformedPatternException;
@@ -335,7 +336,11 @@
}
if (isDebug) log("Adding SMTP gateway: " + server) ;
- gatewayServer.add(server);
+ try {
+ gatewayServer.add(new GatewaySMTPHostAddresses(server));
+ } catch (UnknownHostException uhe) {
+ log("Invalid gateway address:" + uhe.getMessage());
+ }
}
}
@@ -419,14 +424,14 @@
//Figure out which servers to try to send to. This collection
// will hold all the possible target servers
- Collection targetServers = null;
+ Iterator targetServers = null;
if (gatewayServer == null) {
MailAddress rcpt = (MailAddress) recipients.iterator().next();
String host = rcpt.getHost();
//Lookup the possible targets
- targetServers = getMailetContext().getMailServers(host);
- if (targetServers.size() == 0) {
+ targetServers = getMailetContext().getSMTPHostAddresses(host);
+ if (!targetServers.hasNext()) {
log("No mail server found for: " + host);
StringBuffer exceptionBuffer =
new StringBuffer(128)
@@ -436,105 +441,124 @@
return failMessage(mail, new
MessagingException(exceptionBuffer.toString()), false);
}
} else {
- targetServers = gatewayServer;
+ targetServers = gatewayServer.iterator();
}
MessagingException lastError = null;
- Iterator i = targetServers.iterator();
- while ( i.hasNext()) {
- try {
- String outgoingMailServer = i.next().toString ();
- StringBuffer logMessageBuffer =
- new StringBuffer(256)
- .append("Attempting delivery of ")
- .append(mail.getName())
- .append(" to host ")
- .append(outgoingMailServer)
- .append(" to addresses ")
- .append(Arrays.asList(addr));
- log(logMessageBuffer.toString());
- URLName urlname = new URLName("smtp://" + outgoingMailServer);
-
- Properties props = session.getProperties();
- if (mail.getSender() == null) {
- props.put("mail.smtp.from", "<>");
- } else {
- String sender = mail.getSender().toString();
- props.put("mail.smtp.from", sender);
- }
-
- //Many of these properties are only in later JavaMail versions
- //"mail.smtp.ehlo" //default true
- //"mail.smtp.auth" //default false
- //"mail.smtp.dsn.ret" //default to nothing... appended as RET=
after MAIL FROM line.
- //"mail.smtp.dsn.notify" //default to nothing...appended as
NOTIFY= after RCPT TO line.
-
- Transport transport = null;
+ while ( targetServers.hasNext() ) {
+ MailetContext.SMTPHostAddresses thisHost =
+ (MailetContext.SMTPHostAddresses)targetServers.next();
+ String thisHostName = thisHost.getHostname();
+ InetAddress[] addresses = thisHost.getAddresses();
+ for (int addressIndex = 0; addressIndex < addresses.length;
addressIndex++){
try {
- transport = session.getTransport(urlname);
+ InetAddress thisAddress = addresses[addressIndex];
+ int thisPort = thisHost.getPort(thisAddress);
+
+ StringBuffer outgoingMailServerBuf =
+ new StringBuffer(256).append(thisAddress)
+ .append(':')
+ .append(thisPort);
+ if (outgoingMailServerBuf.charAt(0) == '/') {
+ outgoingMailServerBuf.deleteCharAt(0);
+ }
+ String outgoingMailServer =
outgoingMailServerBuf.toString();
+
+ StringBuffer logMessageBuffer =
+ new StringBuffer(256)
+ .append("Attempting delivery of ")
+ .append(mail.getName())
+ .append(" to host ")
+ .append(thisHostName)
+ .append(" at ")
+ .append(outgoingMailServer)
+ .append(" to addresses ")
+ .append(Arrays.asList(addr));
+ log(logMessageBuffer.toString());
+ URLName urlname = new URLName("smtp://" +
outgoingMailServer);
+
+ Properties props = session.getProperties();
+ if (mail.getSender() == null) {
+ props.put("mail.smtp.from", "<>");
+ } else {
+ String sender = mail.getSender().toString();
+ props.put("mail.smtp.from", sender);
+ }
+
+ //Many of these properties are only in later JavaMail
versions
+ //"mail.smtp.ehlo" //default true
+ //"mail.smtp.auth" //default false
+ //"mail.smtp.dsn.ret" //default to nothing... appended as
RET= after MAIL FROM line.
+ //"mail.smtp.dsn.notify" //default to nothing...appended as
NOTIFY= after RCPT TO line.
+ Transport transport = null;
try {
- transport.connect();
- } catch (MessagingException me) {
- // Any error on connect should cause the mailet to
attempt
- // to connect to the next SMTP server associated with
this
- // MX record. Just log the exception. We'll worry
about
- // failing the message at the end of the loop.
- log(me.getMessage());
+ transport = session.getTransport(urlname);
+ try {
+ transport.connect();
+ } catch (MessagingException me) {
+ // Any error on connect should cause the mailet to
attempt
+ // to connect to the next SMTP server associated
with this
+ // MX record. Just log the exception. We'll worry
about
+ // failing the message at the end of the loop.
+ log(me.getMessage());
+ continue;
+ }
+ transport.sendMessage(message, addr);
+ } finally {
+ if (transport != null) {
+ transport.close();
+ transport = null;
+ }
+ }
+ logMessageBuffer =
+ new StringBuffer(256)
+ .append("Mail (")
+ .append(mail.getName())
+ .append(") sent successfully to ")
+ .append(thisHostName)
+ .append(" at ")
+ .append(outgoingMailServer);
+ log(logMessageBuffer.toString());
+ return true;
+ } catch (SendFailedException sfe) {
+ if (sfe.getValidSentAddresses() == null
+ || sfe.getValidSentAddresses().length < 1) {
+ if (isDebug) log("Send failed, continuing with any
other servers");
+ lastError = sfe;
continue;
+ } else {
+ // If any mail was sent then the outgoing
+ // server config must be ok, therefore rethrow
+ throw sfe;
}
- transport.sendMessage(message, addr);
- } finally {
- if (transport != null) {
- transport.close();
- transport = null;
+ } catch (MessagingException me) {
+ //MessagingException are horribly difficult to figure out
what actually happened.
+ StringBuffer exceptionBuffer =
+ new StringBuffer(256)
+ .append("Exception delivering message (")
+ .append(mail.getName())
+ .append(") - ")
+ .append(me.getMessage());
+ log(exceptionBuffer.toString());
+ if ((me.getNextException() != null) &&
+ (me.getNextException() instanceof java.io.IOException))
{
+ //This is more than likely a temporary failure
+
+ // If it's an IO exception with no nested exception,
it's probably
+ // some socket or weird I/O related problem.
+ lastError = me;
+ continue;
}
+ // This was not a connection or I/O error particular to one
+ // SMTP server of an MX set. Instead, it is almost
certainly
+ // a protocol level error. In this case we assume that this
+ // is an error we'd encounter with any of the SMTP servers
+ // associated with this MX record, and we pass the exception
+ // to the code in the outer block that determines its
severity.
+ throw me;
}
- logMessageBuffer =
- new StringBuffer(256)
- .append("Mail (")
- .append(mail.getName())
- .append(") sent successfully to ")
- .append(outgoingMailServer);
- log(logMessageBuffer.toString());
- return true;
- } catch (SendFailedException sfe) {
- if (sfe.getValidSentAddresses() == null
- || sfe.getValidSentAddresses().length < 1) {
- if (isDebug) log("Send failed, continuing with any other
servers");
- lastError = sfe;
- continue;
- } else {
- // If any mail was sent then the outgoing
- // server config must be ok, therefore rethrow
- throw sfe;
- }
- } catch (MessagingException me) {
- //MessagingException are horribly difficult to figure out what
actually happened.
- StringBuffer exceptionBuffer =
- new StringBuffer(256)
- .append("Exception delivering message (")
- .append(mail.getName())
- .append(") - ")
- .append(me.getMessage());
- log(exceptionBuffer.toString());
- if ((me.getNextException() != null) &&
- (me.getNextException() instanceof java.io.IOException)) {
- //This is more than likely a temporary failure
-
- // If it's an IO exception with no nested exception, it's
probably
- // some socket or weird I/O related problem.
- lastError = me;
- continue;
- }
- // This was not a connection or I/O error particular to one
- // SMTP server of an MX set. Instead, it is almost certainly
- // a protocol level error. In this case we assume that this
- // is an error we'd encounter with any of the SMTP servers
- // associated with this MX record, and we pass the exception
- // to the code in the outer block that determines its severity.
- throw me;
- }
+ } //end for
} // end while
//If we encountered an exception while looping through,
//throw the last MessagingException we caught. We only
@@ -1092,5 +1116,54 @@
return buf.toString();
}
}
+
+ /**
+ * This implementation of MailetContext.SMTPHostAddresses is used for holding
gateway information
+ */
+ private class GatewaySMTPHostAddresses implements
MailetContext.SMTPHostAddresses
+ {
+ protected InetAddress[] ipAddresses;
+ protected int port;
+
+ /**
+ * @param server gateway to use the String is of the form "address<:port>"
+ */
+ public GatewaySMTPHostAddresses (String server) throws UnknownHostException
+ {
+ int idx = server.indexOf(':');
+ if ( idx > 0) {
+ port = Integer.parseInt (server.substring(idx+1));
+ server = server.substring(0,idx);
+ } else {
+ port = 25;
+ }
+ ipAddresses = new InetAddress[1];
+ ipAddresses[0] = InetAddress.getByName(server);
+ }
+
+ /**
+ * @return the hostName of the SMTP server (from the MX record lookup)
+ */
+ public String getHostname() {
+ return "Gateway";
+ }
+
+ /**
+ * @return an array with the ip addresses of the hostname. An array is
+ * used because a host can have multiple homes (addresses)
+ */
+ public InetAddress[] getAddresses() {
+ return ipAddresses;
+ }
+
+
+ /**
+ * @param address for which we need the port to use in SMTP connection
+ * @return the port number to use for the given address (this will usually
be 25 for SMTP)
+ */
+ public int getPort(InetAddress address) {
+ return port;
+ }
+ }
}
No revision
No revision
1.5.4.6 +39 -0 james-server/src/java/org/apache/mailet/MailetContext.java
Index: MailetContext.java
===================================================================
RCS file: /home/cvs/james-server/src/java/org/apache/mailet/MailetContext.java,v
retrieving revision 1.5.4.5
retrieving revision 1.5.4.6
diff -u -r1.5.4.5 -r1.5.4.6
--- MailetContext.java 21 Sep 2003 19:09:36 -0000 1.5.4.5
+++ MailetContext.java 12 Dec 2003 22:48:19 -0000 1.5.4.6
@@ -62,6 +62,7 @@
import javax.mail.internet.MimeMessage;
import java.util.Collection;
import java.util.Iterator;
+import java.net.InetAddress;
/**
* Defines a set of methods that a mailet or matcher uses to communicate
@@ -288,4 +289,42 @@
*/
void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg)
throws MessagingException;
+
+ /**
+ * Performs DNS lookups as needed to find servers which should or might
+ * support SMTP.
+ * Returns one SMTPHostAddresses for each such host discovered
+ * by DNS. If no host is found for domainName, the Iterator
+ * returned will be empty and the first call to hasNext() will return
+ * false.
+ * @param domainName the String domain for which SMTP host addresses are
+ * sought.
+ * @return an Iterator in which the Objects returned by next()
+ * are instances of SMTPHostAddresses.
+ */
+ Iterator getSMTPHostAddresses(String domainName);
+
+ /**
+ * The Iterator returned by getSMTPHostAddresses(host) holds instances
+ * of this interface.
+ */
+ interface SMTPHostAddresses {
+ /**
+ * @return the hostName of the SMTP server (from the MX record lookup)
+ */
+ String getHostname();
+
+ /**
+ * @return an array with the ip addresses of the hostname. An array is
+ * used because a host can have multiple homes (addresses)
+ */
+ InetAddress[] getAddresses();
+
+ /**
+ * @param address for which we need the port to use in SMTP connection
+ * @return the port number to use for the given address (this will usually
be 25 for SMTP)
+ */
+ int getPort(InetAddress address);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]