Hi,

As discussed in the "FetchPOP configuration change" thread, here is patch
which adds an additional config parameter to the FetchPOP block.

The config parameter looks like this:
<recipient ignorercpt-header="false">[EMAIL PROTECTED]</recipient>

If ignorercpt-header = true then fetched mail will always be re-spooled with
the specified address as the envelope recipient.
If ignorercpt-header = false, the header is parsed as follows to try and
determine the envelope recipient to use when the mail is spooled
in James.

First the Received: header is parsed to try and find the "for" parameter, if
this fails the To: header is checked and if it contains only one recipient
then this is used as the new envelope recipient for the newly spooled mail.
If both of these fail, the specified recipient from the configuration
parameter is used.
It is possible to do additional checks to try and find who the original
recipient is and if I am going in the right direction with this I will look
at
maybe adding a few more possibilities. I have been reading about Fetchmail.

I have also added a failsafe to avoid mail loops, I simply count the number
of times the X-fetched-from header occurs and if it is more than three I
change the mail state to ERROR before spooling.

I welcome any feedback.

Thanks,
Sergei


Index: src/conf/james-config.xml
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/conf/james-config.xml,v
retrieving revision 1.40
diff -u -r1.40 james-config.xml
--- src/conf/james-config.xml   30 Dec 2002 00:01:34 -0000      1.40
+++ src/conf/james-config.xml   7 Jan 2003 22:46:46 -0000
@@ -76,6 +76,8 @@
    <!-- Warning: It is important to prevent mail from looping by setting the  -->
    <!-- fetched domains in the <servernames> section of the <James> block      -->
    <!-- above. This block is disabled by default.                              -->
+   <!-- As a safety net, fetchpop will attempt to detect looping and any messages -->
+   <!-- which have looped more than 3 times will be moved to the ERROR repository -->
     <fetchpop enabled="false">
         <!-- You can have as many fetch tasks as you want, but each must have a -->
         <!-- unique name by which it identified -->
@@ -88,6 +90,18 @@
             <password>pass</password>
             <!-- How frequently this account is checked - in milliseconds. 600000 is 
every ten minutes -->
             <interval>600000</interval>
+
+            <!-- Fetchpop will leave the fetched message unchanged and will add a new 
+envelope     -->
+            <!-- recipient before spooling the message in James.                      
+             -->
+            <!-- Fetchpop will try and determine the original recipient of the 
+message             -->
+            <!-- in the following ways:                                               
+             -->
+            <!-- First it tries to parse the Received: headers and look for the "for" 
+parameter    -->
+            <!-- If the "for" parameter is not found it will check the To: header and 
+if it only   -->
+            <!-- contains one address it will be used as the new envelope recipient.  
+             -->
+            <!-- If no recipient can be determined, the value defined in the 
+<recipient> parameter -->
+            <!-- will be used. Setting ignorercpt-header to true will force the 
+defined recipient  -->
+            <!-- to ALWAYS be used and the parsing of headers will be ignored  -->
+            <recipient ignorercpt-header="false">[EMAIL PROTECTED]</recipient>
         </fetch>
     </fetchpop>
Index: src/java/org/apache/james/fetchpop/FetchPOP.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-james/src/java/org/apache/james/fetchpop/FetchPOP.java,v
retrieving revision 1.5
diff -u -r1.5 FetchPOP.java
--- src/java/org/apache/james/fetchpop/FetchPOP.java    30 Oct 2002 12:45:11 -0000     
 1.5
+++ src/java/org/apache/james/fetchpop/FetchPOP.java    7 Jan 2003 22:46:51 -0000
@@ -9,30 +9,25 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.SocketException;
-import java.util.Enumeration;
-import java.util.Vector;
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
+import java.util.*;
+import javax.mail.*;
+import javax.mail.internet.*;
 import org.apache.avalon.cornerstone.services.scheduler.Target;
-import org.apache.avalon.framework.component.ComponentException;
-import org.apache.avalon.framework.component.ComponentManager;
-import org.apache.avalon.framework.component.Composable;
-import org.apache.avalon.framework.component.DefaultComponentManager;
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.component.*;
+import org.apache.avalon.framework.configuration.*;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.commons.net.pop3.POP3Client;
 import org.apache.commons.net.pop3.POP3MessageInfo;
 import org.apache.james.services.MailServer;
+import org.apache.mailet.*;
+import org.apache.james.core.MailImpl;
 /**
  *
- * A class which fetches mail from a single POP account and inserts it 
+ * A class which fetches mail from a single POP account and inserts it
  * into the incoming spool<br>
  *
  * <br>$Id: FetchPOP.java,v 1.5 2002/10/30 12:45:11 danny Exp $
- * @author <A href="mailto:[EMAIL PROTECTED]";>Danny Angus</a>
- * 
+ *
  */
 public class FetchPOP extends AbstractLogEnabled implements Configurable, Target {
     /**
@@ -40,6 +35,14 @@
      */
     private MailServer server;
     /**
+     * The user to send the fetched mail to
+     */
+    private MailAddress recipient;
+    /**
+     * Don't parse header looking for recipient
+     */
+    private boolean ignoreOriginalRecipient;
+    /**
      * The unique, identifying name for this task
      */
     private String fetchTaskName;
@@ -82,9 +85,52 @@
                     in.close();
                     message.addHeader("X-fetched-from", fetchTaskName);
                     message.saveChanges();
+
+                    Collection recipients = new ArrayList(1);
                     try {
-                        server.sendMail(message);
-                        getLogger().debug("Sent message " + message.toString());
+                        if (!ignoreOriginalRecipient) {
+                            String er = getEnvelopeRecipient(message);
+                            if (er != null) {
+                                recipients.add(new MailAddress(er));
+                                getLogger().info("Using original envelope recipient 
+as new envelope recipient");
+                            } else {
+                                Address[] to = message.getAllRecipients();
+                                if (to.length == 1) {
+                                    recipients.add(new 
+MailAddress((InternetAddress)to[0]));
+                                    getLogger().info("Using To: header address as new 
+envelope recipient");
+                                } else {
+                                    getLogger().info("Using configured recipient as 
+new envelope recipient");
+                                    recipients.add(recipient);
+                                }
+                            }
+                        } else {
+                            getLogger().info("Using configured recipient as new 
+envelope recipient");
+                            recipients.add(recipient);
+                        }
+                    } catch(ParseException pe) {
+                        recipients.add(recipient);
+                    }
+
+                    MailImpl mail = new MailImpl(server.getId(), new 
+MailAddress((InternetAddress)message.getFrom()[0]) ,recipients, message);
+
+                    // Lets see if this mail has been bouncing by counting the 
+X-fetched-from headers
+                    // if it is then move it to the ERROR repository
+                    Enumeration enum = message.getMatchingHeaderLines(new 
+String[]{"X-fetched-from"});
+                    int count = 1;
+                    while(enum.hasMoreElements()) {
+                        Object o = enum.nextElement();
+                        count++;
+                    }
+                    if (count > 3) {
+                        mail.setState(mail.ERROR);
+                        mail.setErrorMessage("This mail from FetchPOP task 
+"+fetchTaskName+" seems to be bounceing!");
+                        getLogger().error("A message from FetchPOP task 
+"+fetchTaskName+" seems to be bounceing! Moved to Error repository");
+                    }
+
+                    // Send to spooler
+                    try {
+                        server.sendMail(mail);
+                        getLogger().debug("Spooled message to " + 
+recipients.toString());
                         received.add(messages[i]);
                     } catch (MessagingException innerE) {
                         getLogger().error("can't insert message " + 
message.toString() + "created from "+messages[i].identifier);
@@ -112,6 +158,69 @@
             getLogger().error(e.getMessage());
         }
     }
+
+    /**
+     * Try and parse the "for" parameter from a Received header
+     * Maybe not the most accurate parsing in the world but it should do
+     * I opted not to use ORO (maybe I should have)
+     */
+    private String getEnvelopeRecipient(MimeMessage msg) {
+        try {
+            Enumeration enum = msg.getMatchingHeaderLines(new String[]{"Received"});
+            while (enum.hasMoreElements()) {
+                String received = (String)enum.nextElement();
+
+                int nextSearchAt = 0;
+                int i = 0;
+                int start = 0;
+                int end = 0;
+                boolean hasBracket = false;
+                boolean usableAddress = false;
+                while (!usableAddress && (i != -1)) {
+                    hasBracket = false;
+                    i = received.indexOf("for ", nextSearchAt);
+                    if (i > 0) {
+                        start = i+4;
+                        end = 0;
+                        nextSearchAt = start;
+                        for (int c = start; c < received.length(); c++) {
+                            char ch = received.charAt(c);
+                            switch (ch) {
+                                case '<':
+                                    hasBracket = true;
+                                    continue;
+                                case '@':
+                                    usableAddress = true;
+                                    continue;
+                                case ' ':
+                                    end = c;
+                                    break;
+                                case ';':
+                                    end = c;
+                                    break;
+                            }
+                            if (end > 0)
+                                break;
+                        }
+                    }
+                }
+                if (usableAddress) {
+                    // lets try and grab the email address
+                    String mailFor = received.substring(start, end);
+
+                    // strip the <> around the address if there are any
+                    if (mailFor.startsWith("<") && mailFor.endsWith(">"))
+                        mailFor = mailFor.substring(1, (mailFor.length()-1));
+
+                    return mailFor;
+                }
+            }
+        } catch(MessagingException me) {
+            getLogger().info("No Recieved headers found");
+        }
+        return null;
+    }
+
     /**
      * @see org.apache.avalon.framework.component.Composable#compose(ComponentManager)
      */
@@ -133,6 +242,12 @@
         this.popUser = conf.getChild("user").getValue();
         this.popPass = conf.getChild("password").getValue();
         this.fetchTaskName = conf.getAttribute("name");
+        try {
+            this.recipient = new MailAddress(conf.getChild("recipient").getValue());
+        } catch (ParseException pe) {
+            throw new ConfigurationException("Invalid recipient address specified");
+        }
+        this.ignoreOriginalRecipient = 
+conf.getChild("recipient").getAttributeAsBoolean("ignorercpt-header");
         if (getLogger().isDebugEnabled()) {
             getLogger().info("Configured FetchPOP fetch task " + fetchTaskName);
         }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to