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]

Reply via email to