You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by sb...@apache.org on 2004/02/11 19:02:07 UTC

cvs commit: james-server/src/xdocs fetchmail_configuration_2_2.xml documentation_2_1.xml fetchpop_configuration_2_1.xml

sbrewin     2004/02/11 10:02:07

  Modified:    src/java/org/apache/james/fetchmail FetchMail.java
                        FetchScheduler.java FetchScheduler.xinfo
                        ReaderInputStream.java
               src/conf james-config.xml
               src/xdocs documentation_2_1.xml
                        fetchpop_configuration_2_1.xml
  Added:       src/java/org/apache/james/fetchmail StoreProcessor.java
                        Account.java DynamicAccount.java
                        MessageProcessor.java ProcessorAbstract.java
                        FolderProcessor.java ParsedConfiguration.java
               src/conf/samples/fetchmail maxMessageSize.xml
                        oneAccountManyUsers.xml
                        oneAccountPerUserDynamic.xml oneAccountPerUser.xml
                        oneAccountManyUsersDynamic.xml
               src/conf james-fetchmail.xml
               src/xdocs fetchmail_configuration_2_2.xml
  Log:
  Synchronized with the (previously) much more recent version of fetchmail in branch 2_1_fcs.
  Set copyright notices to 2003-2004.
  
  Revision  Changes    Path
  1.11      +858 -327  james-server/src/java/org/apache/james/fetchmail/FetchMail.java
  
  Index: FetchMail.java
  ===================================================================
  RCS file: /home/cvs/james-server/src/java/org/apache/james/fetchmail/FetchMail.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- FetchMail.java	30 Jan 2004 02:22:08 -0000	1.10
  +++ FetchMail.java	11 Feb 2004 18:02:06 -0000	1.11
  @@ -1,5 +1,5 @@
   /***********************************************************************
  - * Copyright (c) 2000-2004 The Apache Software Foundation.             *
  + * Copyright (c) 2003-2004 The Apache Software Foundation.             *
    * All rights reserved.                                                *
    * ------------------------------------------------------------------- *
    * Licensed under the Apache License, Version 2.0 (the "License"); you *
  @@ -18,20 +18,16 @@
   package org.apache.james.fetchmail;
   
   import java.util.ArrayList;
  -import java.util.Collection;
  +import java.util.Collections;
   import java.util.Enumeration;
  +import java.util.HashMap;
  +import java.util.Iterator;
  +import java.util.List;
  +import java.util.Map;
   import java.util.Properties;
   
  -import javax.mail.Address;
  -import javax.mail.Flags;
  -import javax.mail.Folder;
  -import javax.mail.Message;
   import javax.mail.MessagingException;
   import javax.mail.Session;
  -import javax.mail.Store;
  -import javax.mail.internet.InternetAddress;
  -import javax.mail.internet.MimeMessage;
  -import javax.mail.internet.ParseException;
   
   import org.apache.avalon.cornerstone.services.scheduler.Target;
   import org.apache.avalon.framework.configuration.Configurable;
  @@ -40,398 +36,933 @@
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.service.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
  -import org.apache.james.core.MailImpl;
   import org.apache.james.services.MailServer;
  -import org.apache.mailet.Mail;
  -import org.apache.mailet.MailAddress;
  +import org.apache.james.services.UsersStore;
  +import org.apache.mailet.UsersRepository;
   
   /**
  - *
  - * A class which fetches mail from a single account and inserts it
  - * into the incoming spool
  - *
  - * $Id$
  - *
  + * <p>Class <code>FetchMail</code> is an Avalon task that is periodically
  + * triggered to fetch mail from a JavaMail Message Store.</p>
  + * 
  + * <p>The lifecycle of an instance of <code>FetchMail</code> is managed by
  + * Avalon. The <code>configure(Configuration)</code> method is invoked to parse
  + * and validate Configuration properties. The targetTriggered(String) method is
  + * invoked to execute the task.</p>
  + *  
  + * <p>When triggered, a sorted list of Message Store Accounts to be processed is
  + * built. Each Message Store Account is processed by delegating to 
  + * <code>StoreProcessor</code>.</p>
  + * 
  + * <p>There are two kinds of Message Store Accounts, static and dynamic. Static 
  + * accounts are expliciltly declared in the Configuration. Dynamic accounts are
  + * built each time the task is executed, one per each user defined to James,
  + * using the James user name with a configurable prefix and suffix to define
  + * the host user identity and recipient identity for each Account. Dynamic
  + * accounts allow <code>FetchMail</code> to fetch mail for all James users
  + * without modifying the Configuration parameters or restarting the Avalon 
  + * server.</p>
  + * 
  + * <p>To fully understand the operations supported by this task, read the Class
  + * documention for each Class in the delegation chain starting with this 
  + * class' delegate, <code>StoreProcessor</code>. </p>
  + * 
  + * <p>Creation Date: 24-May-03</p>
  + * 
    */
  -public class FetchMail extends AbstractLogEnabled implements Configurable, Target {
  +public class FetchMail extends AbstractLogEnabled implements Configurable, Target
  +{
       /**
  -     * The MailServer service
  -     */
  -    private MailServer server;
  -    /**
  -     * The user to send the fetched mail to
  +     * Key fields for DynamicAccounts.
        */
  -    private MailAddress recipient;
  +    private class DynamicAccountKey
  +    {
  +        /**
  +         * The base user name without prfix or suffix
  +         */
  +        private String fieldUserName;
  +        
  +        /**
  +         * The sequence number of the parameters used to construct the Account
  +         */
  +        private int fieldSequenceNumber;                
  +
  +        /**
  +         * Constructor for DynamicAccountKey.
  +         */
  +        private DynamicAccountKey()
  +        {
  +            super();
  +        }
  +        
  +        /**
  +         * Constructor for DynamicAccountKey.
  +         */
  +        public DynamicAccountKey(String userName, int sequenceNumber)
  +        {
  +            this();
  +            setUserName(userName);
  +            setSequenceNumber(sequenceNumber);
  +        }        
  +
  +        /**
  +         * @see java.lang.Object#equals(Object)
  +         */
  +        public boolean equals(Object obj)
  +        {
  +            if (null == obj)
  +                return false;
  +            if (!(obj.getClass() == getClass()))
  +                return false;
  +            return (
  +                getUserName().equals(((DynamicAccountKey) obj).getUserName())
  +                    && getSequenceNumber()
  +                        == ((DynamicAccountKey) obj).getSequenceNumber());
  +        }
   
  -    /**
  -     * Don't parse header looking for recipient
  -     */
  -    private boolean ignoreOriginalRecipient;
  +        /**
  +         * @see java.lang.Object#hashCode()
  +         */
  +        public int hashCode()
  +        {
  +            return getUserName().hashCode() ^ getSequenceNumber();
  +        }
  +
  +        /**
  +         * Returns the sequenceNumber.
  +         * @return int
  +         */
  +        public int getSequenceNumber()
  +        {
  +            return fieldSequenceNumber;
  +        }
   
  +        /**
  +         * Returns the userName.
  +         * @return String
  +         */
  +        public String getUserName()
  +        {
  +            return fieldUserName;
  +        }
  +
  +        /**
  +         * Sets the sequenceNumber.
  +         * @param sequenceNumber The sequenceNumber to set
  +         */
  +        protected void setSequenceNumber(int sequenceNumber)
  +        {
  +            fieldSequenceNumber = sequenceNumber;
  +        }
  +
  +        /**
  +         * Sets the userName.
  +         * @param userName The userName to set
  +         */
  +        protected void setUserName(String userName)
  +        {
  +            fieldUserName = userName;
  +        }
  +
  +    }
       /**
  -     * The unique, identifying name for this task
  +     * Creation Date: 06-Jun-03
        */
  -    private String fetchTaskName;
  +    private class ParsedDynamicAccountParameters
  +    {
  +        private String fieldUserPrefix;
  +        private String fieldUserSuffix;
  +        
  +        private String fieldPassword;
  +        
  +        private int fieldSequenceNumber;
  +
  +        private boolean fieldIgnoreRecipientHeader;     
  +        private String fieldRecipientPrefix;
  +        private String fieldRecipientSuffix;
  +
  +        /**
  +         * Constructor for ParsedDynamicAccountParameters.
  +         */
  +        private ParsedDynamicAccountParameters()
  +        {
  +            super();
  +        }
  +
  +        /**
  +         * Constructor for ParsedDynamicAccountParameters.
  +         */
  +        public ParsedDynamicAccountParameters(
  +            int sequenceNumber,
  +            Configuration configuration)
  +            throws ConfigurationException
  +        {
  +            this();
  +            setSequenceNumber(sequenceNumber);
  +            setUserPrefix(configuration.getAttribute("userprefix", ""));
  +            setUserSuffix(configuration.getAttribute("usersuffix", ""));
  +            setRecipientPrefix(configuration.getAttribute("recipientprefix", ""));
  +            setRecipientSuffix(configuration.getAttribute("recipientsuffix", ""));
  +            setPassword(configuration.getAttribute("password"));
  +            setIgnoreRecipientHeader(
  +                configuration.getAttributeAsBoolean("ignorercpt-header"));
  +        }                       
  +
  +        /**
  +         * Returns the recipientprefix.
  +         * @return String
  +         */
  +        public String getRecipientPrefix()
  +        {
  +            return fieldRecipientPrefix;
  +        }
  +
  +        /**
  +         * Returns the recipientsuffix.
  +         * @return String
  +         */
  +        public String getRecipientSuffix()
  +        {
  +            return fieldRecipientSuffix;
  +        }
  +
  +        /**
  +         * Returns the userprefix.
  +         * @return String
  +         */
  +        public String getUserPrefix()
  +        {
  +            return fieldUserPrefix;
  +        }
  +
  +        /**
  +         * Returns the userSuffix.
  +         * @return String
  +         */
  +        public String getUserSuffix()
  +        {
  +            return fieldUserSuffix;
  +        }
  +
  +        /**
  +         * Sets the recipientprefix.
  +         * @param recipientprefix The recipientprefix to set
  +         */
  +        protected void setRecipientPrefix(String recipientprefix)
  +        {
  +            fieldRecipientPrefix = recipientprefix;
  +        }
  +
  +        /**
  +         * Sets the recipientsuffix.
  +         * @param recipientsuffix The recipientsuffix to set
  +         */
  +        protected void setRecipientSuffix(String recipientsuffix)
  +        {
  +            fieldRecipientSuffix = recipientsuffix;
  +        }
  +
  +        /**
  +         * Sets the userprefix.
  +         * @param userprefix The userprefix to set
  +         */
  +        protected void setUserPrefix(String userprefix)
  +        {
  +            fieldUserPrefix = userprefix;
  +        }
  +
  +        /**
  +         * Sets the userSuffix.
  +         * @param userSuffix The userSuffix to set
  +         */
  +        protected void setUserSuffix(String userSuffix)
  +        {
  +            fieldUserSuffix = userSuffix;
  +        }
  +
  +        /**
  +         * Returns the password.
  +         * @return String
  +         */
  +        public String getPassword()
  +        {
  +            return fieldPassword;
  +        }
  +
  +        /**
  +         * Sets the ignoreRecipientHeader.
  +         * @param ignoreRecipientHeader The ignoreRecipientHeader to set
  +         */
  +        protected void setIgnoreRecipientHeader(boolean ignoreRecipientHeader)
  +        {
  +            fieldIgnoreRecipientHeader = ignoreRecipientHeader;
  +        }
  +
  +        /**
  +         * Sets the password.
  +         * @param password The password to set
  +         */
  +        protected void setPassword(String password)
  +        {
  +            fieldPassword = password;
  +        }
  +
  +        /**
  +         * Returns the ignoreRecipientHeader.
  +         * @return boolean
  +         */
  +        public boolean isIgnoreRecipientHeader()
  +        {
  +            return fieldIgnoreRecipientHeader;
  +        }
  +
  +        /**
  +         * Returns the sequenceNumber.
  +         * @return int
  +         */
  +        public int getSequenceNumber()
  +        {
  +            return fieldSequenceNumber;
  +        }
  +
  +        /**
  +         * Sets the sequenceNumber.
  +         * @param sequenceNumber The sequenceNumber to set
  +         */
  +        protected void setSequenceNumber(int sequenceNumber)
  +        {
  +            fieldSequenceNumber = sequenceNumber;
  +        }
   
  +    }
       /**
  -     * The server host name for this fetch task
  +     * @see org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)
        */
  -    private String sHost;
  +    private boolean fieldFetching = false;
  +    
       /**
  -     * The user name for this fetch task
  +     * The Configuration for this task
        */
  -    private String sUser;
  -
  +    private ParsedConfiguration fieldConfiguration;
  +    
       /**
  -     * The user password for this fetch task
  +     * A List of ParsedDynamicAccountParameters, one for every <alllocal> entry
  +     * in the configuration.
        */
  -    private String sPass;
  -
  +    private List fieldParsedDynamicAccountParameters;    
  +    
       /**
  -     * Keep retrieved messages on the remote mailserver.  Normally, messages
  -     * are deleted from the folder on the mailserver after they have been retrieved
  +     * The Static Accounts for this task.
  +     * These are setup when the task is configured.
        */
  -    private boolean bKeep = false;
  -
  +    private List fieldStaticAccounts;
  +    
       /**
  -     * Retrieve both old (seen) and new messages from the mailserver.  The default
  -     * is to fetch only messages the server has not marked as seen.
  -     */
  -    private boolean bAll = false;
  +     * The JavaMail Session for this fetch task.
  +     */ 
   
  +    private Session fieldSession;
  +    
       /**
  -     * Recurse folders if available?
  +     * The Dynamic Accounts for this task.
  +     * These are setup each time the fetchtask is run.
  +     */
  +    private Map fieldDynamicAccounts;        
  +    
  +   /**
  +     * The MailServer service
  +     */
  +    private MailServer fieldServer;
  +    
  +   /**
  +     * The Local Users repository
        */
  -    private boolean bRecurse = false;
  +    private UsersRepository fieldLocalUsers;        
   
       /**
  -     * The name of the javamail provider we want to user (pop3,imap,nntp,etc...)
  -     *
  +     * Constructor for POP3mail.
        */
  -    private String javaMailProviderName = "pop3";
  +    public FetchMail()
  +    {
  +        super();
  +    }
   
       /**
  -     * The name of the folder to fetch from the javamail provider
  -     *
  +     * Method configure parses and validates the Configuration data and creates
  +     * a new <code>ParsedConfiguration</code>, an <code>Account</code> for each
  +     * configured static account and a <code>ParsedDynamicAccountParameters</code>
  +     * for each dynamic account.
  +     * 
  +     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
        */
  -    private String javaMailFolderName = "INBOX";
  +    public void configure(Configuration configuration)
  +        throws ConfigurationException
  +    {
  +        // Set any Session parameters passed in the Configuration
  +        setSessionParameters(configuration);
  +
  +        // Create the ParsedConfiguration used in the delegation chain
  +        ParsedConfiguration parsedConfiguration =
  +            new ParsedConfiguration(
  +                configuration,
  +                getLogger(),
  +                getServer(),
  +                getLocalUsers());
  +        setConfiguration(parsedConfiguration);
  +
  +        // Setup the Accounts
  +        Configuration[] allAccounts = configuration.getChildren("accounts");
  +        if (allAccounts.length < 1)
  +            throw new ConfigurationException("Missing <accounts> section.");
  +        if (allAccounts.length > 1)
  +            throw new ConfigurationException("Too many <accounts> sections, there must be exactly one");
  +        Configuration accounts = allAccounts[0];
  +
  +        // Create an Account for every configured account
  +        Configuration[] accountsChildren = accounts.getChildren();
  +        if (accountsChildren.length < 1)
  +            throw new ConfigurationException("Missing <account> section.");
  +
  +        for (int i = 0; i < accountsChildren.length; i++)
  +        {
  +            Configuration accountsChild = accountsChildren[i];
  +
  +            if (accountsChild.getName() == "alllocal")
  +            {
  +                // <allLocal> is dynamic, save the parameters for accounts to
  +                // be created when the task is triggered
  +                getParsedDynamicAccountParameters().add(
  +                    new ParsedDynamicAccountParameters(i, accountsChild));
  +                continue;
  +            }
   
  +            if (accountsChild.getName() == "account")
  +            {
  +                // Create an Account for the named user and
  +                // add it to the list of static accounts
  +                getStaticAccounts().add(
  +                    new Account(
  +                        i,
  +                        parsedConfiguration,
  +                        accountsChild.getAttribute("user"),
  +                        accountsChild.getAttribute("password"),
  +                        accountsChild.getAttribute("recipient"),
  +                        accountsChild.getAttributeAsBoolean(
  +                            "ignorercpt-header"),
  +                        getSession()));
  +                continue;
  +            }
  +
  +            throw new ConfigurationException(
  +                "Illegal token: <"
  +                    + accountsChild.getName()
  +                    + "> in <accounts>");
  +        }
  +    }
   
       /**
  +     * Method target triggered fetches mail for each configured account.
  +     * 
        * @see org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)
        */
  -    private boolean fetching = false;
  -
  -
  -    public boolean processMessage(Session session, MimeMessage message, MimeMessage received) {
  -
  -        Collection recipients = new ArrayList(1);
  -        try {
  -
  +    public void targetTriggered(String arg0)
  +    {
  +        // if we are already fetching then just return
  +        if (isFetching())
  +        {
  +            getLogger().info(
  +                "Triggered fetch cancelled. A fetch is already in progress.");
  +            return;
  +        }
   
  -            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);
  +        // Enter Fetching State
  +        try
  +        {
  +            setFetching(true);
  +            getLogger().info("Fetcher starting fetches");
  +
  +            // if debugging, list the JavaMail property key/value pairs
  +            // for this Session
  +            if (getLogger().isDebugEnabled())
  +            {
  +                getLogger().debug("Session properties:");
  +                Properties properties = getSession().getProperties();
  +                Enumeration e = properties.keys();
  +                while (e.hasMoreElements())
  +                {
  +                    String key = (String) e.nextElement();
  +                    String val = (String) properties.get(key);
  +                    if (val.length() > 40)
  +                    {
  +                        val = val.substring(0, 37) + "...";
                       }
  -                }
  -            } else {
  -                getLogger().info("Using configured recipient as new envelope recipient");
  -                recipients.add(recipient);
  -            }
  -
  -
  -
  -
  -            //
  -            // set the X-fetched-from header
  -            received.addHeader("X-fetched-from", fetchTaskName);
  -
  -            Mail mail = new MailImpl(server.getId(), new
  -                    MailAddress((InternetAddress) received.getFrom()[0]), recipients, received);
  -
  -
  -            // 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 FetchMail task " + fetchTaskName + " seems to be bounceing!");
  -                getLogger().error("A message from FetchMail task " + fetchTaskName + " seems to be bounceing! Moved to Error repository");
  -                return false;
  -            }
  +                    getLogger().debug(key + "=" + val);
   
  -            server.sendMail(mail);
  -            getLogger().debug("Spooled message to " +
  -                    recipients.toString());
  -
  -            //
  -            // logging if needed
  -            getLogger().debug("Sent message " + message.toString());
  -            return true;
  -        } catch (ParseException pe) {
  -            recipients.add(recipient);
  -        } catch (MessagingException innerE) {
  -            getLogger().error("can't insert message " + message.toString());
  -        }
  -        return false;
  -    }
  -
  -    public boolean processFolder(Session session, Folder folder) {
  -
  -        boolean ret = false;
  -
  -        try {
  -
  -            //
  -            // try to open read/write and if that fails try read-only
  -            try {
  -                folder.open(Folder.READ_WRITE);
  -            } catch (MessagingException ex) {
  -                try {
  -                    folder.open(Folder.READ_ONLY);
  -                } catch (MessagingException ex2) {
  -                    getLogger().debug(fetchTaskName + " Failed to open folder!");
                   }
               }
   
  -//            int totalMessages = folder.getMessageCount();
  -//            if (totalMessages == 0) {
  -//                getLogger().debug(fetchTaskName + " Empty folder");
  -//                folder.close(false);
  -//                fetching = false;
  -//                return false;
  -//            }
  -
  -            Message[] msgs = folder.getMessages();
  -            MimeMessage[] received = new MimeMessage[folder.getMessageCount()];
  -
  -            int j = 0;
  -            for (int i = 0; i < msgs.length; i++, j++) {
  -                Flags flags = msgs[i].getFlags();
  -                MimeMessage message = (MimeMessage) msgs[i];
  -
  -                //
  -                // saved recieved messages for further processing...
  -                received[j] = new MimeMessage(/*session,*/ message);
  -
  -                received[j].addHeader("X-fetched-folder", folder.getFullName());
  -
  -                if (bAll) {
  -                    ret = processMessage(session, message, received[j]);
  -                } else if (message.isSet(Flags.Flag.SEEN)) {
  -                    ret = processMessage(session, message, received[j]);
  -                }
  -
  -
  -                if (ret) {
  -                //
  -                // need to get the flags again just in case processMessage
  -                // has changed the flags....
  -                Flags f = received[j].getFlags();
  -
  -                if (!bKeep) {
  -
  -                    message.setFlag(Flags.Flag.DELETED, true);
  -                } else {
  -                    f.add(Flags.Flag.SEEN);
  -
  -                    received[j].setFlags(f, true);
  +            // Update the dynamic accounts,
  +            // merge with the static accounts and
  +            // sort the accounts so they are in the order
  +            // they were entered in config.xml
  +            updateDynamicAccounts();
  +            ArrayList mergedAccounts =
  +                new ArrayList(
  +                    getDynamicAccounts().size() + getStaticAccounts().size());
  +            mergedAccounts.addAll(getDynamicAccounts().values());
  +            mergedAccounts.addAll(getStaticAccounts());
  +            Collections.sort(mergedAccounts);
  +
  +            StringBuffer logMessage = new StringBuffer(64);
  +            logMessage.append("Processing ");
  +            logMessage.append(getStaticAccounts().size());
  +            logMessage.append(" static accounts and ");
  +            logMessage.append(getDynamicAccounts().size());
  +            logMessage.append(" dynamic accounts.");
  +            getLogger().info(logMessage.toString());
  +
  +            // Fetch each account
  +            Iterator accounts = mergedAccounts.iterator();
  +            while (accounts.hasNext())
  +            {
  +                try
  +                {
  +                    new StoreProcessor((Account) accounts.next()).process();
                   }
  +                catch (MessagingException ex)
  +                {
  +                    getLogger().error(
  +                        "A MessagingException has terminated processing of this Account",
  +                        ex);
                   }
               }
  -            folder.close(true);
  +        }
  +        catch (Exception ex)
  +        {
  +            getLogger().error("An Exception has terminated this fetch.", ex);
  +        }
  +        finally
  +        {
  +            getLogger().info("Fetcher completed fetches");
   
  -            //
  -            // see if this folder contains subfolders and recurse is true
  -            if (bRecurse) {
  -                if ((folder.getType() & Folder.HOLDS_FOLDERS) != 0) {
  -                    //
  -                    // folder contains subfolders...
  -                    Folder folders[] = folder.list();
  +            // Exit Fetching State
  +            setFetching(false);
  +        }
  +    }
   
  -                    for (int k = 0; k < folders.length; k++) {
  -                        processFolder(session, folders[k]);
  -                    }
  +    /**
  +     * Returns the fetching.
  +     * @return boolean
  +     */
  +    protected boolean isFetching()
  +    {
  +        return fieldFetching;
  +    }
   
  -                }
  -            }
  -            return true;
  -        } catch (MessagingException mex) {
  -            getLogger().debug(mex.toString());
  +    /**
  +     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
  +     */
  +    public void service(final ServiceManager manager) throws ServiceException
  +    {
  +        try
  +        {
  +            setServer((MailServer) manager.lookup(MailServer.ROLE));
  +        }
  +        catch (ClassCastException cce)
  +        {
  +            StringBuffer errorBuffer =
  +                new StringBuffer(128).append("Component ").append(
  +                    MailServer.ROLE).append(
  +                    "does not implement the required interface.");
  +            throw new ServiceException("", errorBuffer.toString());
  +        }
   
  -        } /*catch (IOException ioex) {
  -            getLogger().debug(ioex.toString());
  -        }   */
  -        fetching = false;
  -        return false;
  +        UsersStore usersStore =
  +            (UsersStore) manager.lookup("org.apache.james.services.UsersStore");
  +        setLocalUsers(usersStore.getRepository("LocalUsers"));
  +        if (getLocalUsers() == null)
  +            throw new ServiceException(
  +                "",
  +                "The user repository could not be found.");
       }
   
   
  -    public void targetTriggered(String arg0) {
  -        Store store = null;
  -        Session session = null;
  -        Folder folder = null;
   
  -        // Get a Properties object
  -        Properties props = System.getProperties();
  +            
   
   
  -        //
  -        // if we are already fetching then just return
  -        if (fetching) return;
  -        fetching = true;
  +    /**
  +     * Sets the fetching.
  +     * @param fetching The fetching to set
  +     */
  +    protected void setFetching(boolean fetching)
  +    {
  +        fieldFetching = fetching;
  +    }
   
  +    /**
  +     * Returns the server.
  +     * @return MailServer
  +     */
  +    protected MailServer getServer()
  +    {
  +        return fieldServer;
  +    }
   
  -        if (getLogger().isDebugEnabled()) {
  -            getLogger().debug(fetchTaskName + " fetcher starting fetch");
  -        }
  +    /**
  +     * Returns the configuration.
  +     * @return ParsedConfiguration
  +     */
  +    protected ParsedConfiguration getConfiguration()
  +    {
  +        return fieldConfiguration;
  +    }
   
  +    /**
  +     * Sets the configuration.
  +     * @param configuration The configuration to set
  +     */
  +    protected void setConfiguration(ParsedConfiguration configuration)
  +    {
  +        fieldConfiguration = configuration;
  +    }
   
  -        // Get a Session object
  -        session = Session.getDefaultInstance(props, null);
  -        //  session.setDebug(debug);
  +/**
  + * Sets the server.
  + * @param server The server to set
  + */
  +protected void setServer(MailServer server)
  +{
  +    fieldServer = server;
  +}
   
  -        // Get a Store object
  -        try {
  -            store = session.getStore(javaMailProviderName);
  +/**
  + * Returns the localUsers.
  + * @return UsersRepository
  + */
  +protected UsersRepository getLocalUsers()
  +{
  +    return fieldLocalUsers;
  +}
   
  -            // Connect
  -            if (sHost != null || sUser != null || sPass != null)
  -                store.connect(sHost, sUser, sPass);
  -            else
  -                store.connect();
  +/**
  + * Sets the localUsers.
  + * @param localUsers The localUsers to set
  + */
  +protected void setLocalUsers(UsersRepository localUsers)
  +{
  +    fieldLocalUsers = localUsers;
  +}
  +
  +    /**
  +     * Returns the accounts. Initializes if required.
  +     * @return List
  +     */
  +    protected List getStaticAccounts()
  +    {
  +        List accounts = null;
  +        if (null == (accounts = getStaticAccountsBasic()))
  +        {
  +            updateStaticAccounts();
  +            return getStaticAccounts();
  +        }   
  +        return fieldStaticAccounts;
  +    }
  +    
  +    /**
  +     * Returns the staticAccounts.
  +     * @return List
  +     */
  +    private List getStaticAccountsBasic()
  +    {
  +        return fieldStaticAccounts;
  +    }   
   
  -            // Open the Folder
  -            folder = store.getFolder(javaMailFolderName);
  -            if (folder == null) {
  -                getLogger().debug(fetchTaskName + " No default folder");
  +    /**
  +     * Sets the accounts.
  +     * @param accounts The accounts to set
  +     */
  +    protected void setStaticAccounts(List accounts)
  +    {
  +        fieldStaticAccounts = accounts;
  +    }
  +    
  +    /**
  +     * Updates the staticAccounts.
  +     */
  +    protected void updateStaticAccounts()
  +    {
  +        setStaticAccounts(computeStaticAccounts());
  +    }
  +    
  +    /**
  +     * Updates the ParsedDynamicAccountParameters.
  +     */
  +    protected void updateParsedDynamicAccountParameters()
  +    {
  +        setParsedDynamicAccountParameters(computeParsedDynamicAccountParameters());
  +    }   
  +    
  +    /**
  +     * Updates the dynamicAccounts.
  +     */
  +    protected void updateDynamicAccounts() throws ConfigurationException
  +    {
  +        setDynamicAccounts(computeDynamicAccounts());
  +    }   
  +    
  +    /**
  +     * Computes the staticAccounts.
  +     */
  +    protected List computeStaticAccounts()
  +    {
  +        return new ArrayList();
  +    }
  +    
  +    /**
  +     * Computes the ParsedDynamicAccountParameters.
  +     */
  +    protected List computeParsedDynamicAccountParameters()
  +    {
  +        return new ArrayList();
  +    }   
  +    
  +    /**
  +     * Computes the dynamicAccounts.
  +     */
  +    protected Map computeDynamicAccounts() throws ConfigurationException
  +    {
  +        Map newAccounts =
  +            new HashMap(
  +                getLocalUsers().countUsers()
  +                    * getParsedDynamicAccountParameters().size());
  +        Map oldAccounts = getDynamicAccountsBasic();
  +        if (null == oldAccounts)
  +            oldAccounts = new HashMap(0);
  +
  +        Iterator parameterIterator =
  +            getParsedDynamicAccountParameters().iterator();
  +
  +        // Process each ParsedDynamicParameters
  +        while (parameterIterator.hasNext())
  +        {
  +            Map accounts =
  +                computeDynamicAccounts(
  +                    oldAccounts,
  +                    (ParsedDynamicAccountParameters) parameterIterator.next());
  +            // Remove accounts from oldAccounts.
  +            // This avoids an average 2*N increase in heapspace used as the 
  +            // newAccounts are created. 
  +            Iterator oldAccountsIterator = oldAccounts.keySet().iterator();
  +            while (oldAccountsIterator.hasNext())
  +            {
  +                if (accounts.containsKey(oldAccountsIterator.next()))
  +                    oldAccountsIterator.remove();
               }
  -
  -
  -            processFolder(session, folder);
  -
  -            store.close();
  -        } catch (MessagingException ex) {
  -            getLogger().debug(fetchTaskName + ex.getMessage());
  +            // Add this parameter's accounts to newAccounts
  +            newAccounts.putAll(accounts);
           }
  -        fetching = false;
  +        return newAccounts;
       }
  +    
  +    /**
  +     * Returns the dynamicAccounts. Initializes if required.
  +     * @return Map
  +     */
  +    protected Map getDynamicAccounts() throws ConfigurationException
  +    {
  +        Map accounts = null;
  +        if (null == (accounts = getDynamicAccountsBasic()))
  +        {
  +            updateDynamicAccounts();
  +            return getDynamicAccounts();
  +        }   
  +        return fieldDynamicAccounts;
  +    }
  +    
  +    /**
  +     * Returns the dynamicAccounts.
  +     * @return Map
  +     */
  +    private Map getDynamicAccountsBasic()
  +    {
  +        return fieldDynamicAccounts;
  +    }   
   
       /**
  -     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
  +     * Sets the dynamicAccounts.
  +     * @param dynamicAccounts The dynamicAccounts to set
        */
  -    public void service(final ServiceManager manager ) throws ServiceException {
  -        try {
  -            server = (MailServer) manager.lookup(MailServer.ROLE);
  -        } catch (ClassCastException cce) {
  -            StringBuffer errorBuffer =
  -                    new StringBuffer(128).append("Component ").append(MailServer.ROLE).append(
  -                            "does not implement the required interface.");
  -            throw new ServiceException("",errorBuffer.toString());
  +    protected void setDynamicAccounts(Map dynamicAccounts)
  +    {
  +        fieldDynamicAccounts = dynamicAccounts;
  +    }
  +    
  +    /**
  +     * Compute the dynamicAccounts for the passed parameters.
  +     * Accounts for existing users are copied and accounts for new users are 
  +     * created.
  +     * @param oldAccounts
  +     * @param parameters
  +     * @return Map - The current Accounts
  +     * @throws ConfigurationException
  +     */
  +    protected Map computeDynamicAccounts(
  +        Map oldAccounts,
  +        ParsedDynamicAccountParameters parameters)
  +        throws ConfigurationException
  +    {
  +        Map accounts = new HashMap(getLocalUsers().countUsers());
  +        Iterator usersIterator = getLocalUsers().list();
  +        while (usersIterator.hasNext())
  +        {
  +            String userName = (String) usersIterator.next();
  +            DynamicAccountKey key =
  +                new DynamicAccountKey(userName, parameters.getSequenceNumber());
  +            Account account = (Account) oldAccounts.get(key);
  +            if (null == account)
  +            {
  +                // Create a new DynamicAccount
  +                account =
  +                    new DynamicAccount(
  +                        parameters.getSequenceNumber(),
  +                        getConfiguration(),
  +                        userName,
  +                        parameters.getUserPrefix(),
  +                        parameters.getUserSuffix(),
  +                        parameters.getPassword(),
  +                        parameters.getRecipientPrefix(),
  +                        parameters.getRecipientSuffix(),
  +                        parameters.isIgnoreRecipientHeader(),
  +                        getSession());
  +            }
  +            accounts.put(key, account);
           }
  +        return accounts;
       }
  +    /**
  +     * Resets the dynamicAccounts.
  +     */
  +    protected void resetDynamicAccounts()
  +    {
  +        setDynamicAccounts(null);
  +    }   
  +
  +    /**
  +     * Returns the ParsedDynamicAccountParameters.
  +     * @return List
  +     */
  +    protected List getParsedDynamicAccountParameters()
  +    {
  +        List accounts = null;
  +        if (null == (accounts = getParsedDynamicAccountParametersBasic()))
  +        {
  +            updateParsedDynamicAccountParameters();
  +            return getParsedDynamicAccountParameters();
  +        }   
  +        return fieldParsedDynamicAccountParameters;
  +    }
  +    
  +    /**
  +     * Returns the ParsedDynamicAccountParameters.
  +     * @return List
  +     */
  +    private List getParsedDynamicAccountParametersBasic()
  +    {
  +        return fieldParsedDynamicAccountParameters;
  +    }   
   
  +    /**
  +     * Sets the ParsedDynamicAccountParameters.
  +     * @param ParsedDynamicAccountParameters The ParsedDynamicAccountParametersto set
  +     */
  +    protected void setParsedDynamicAccountParameters(List parsedDynamicAccountParameters)
  +    {
  +        fieldParsedDynamicAccountParameters = parsedDynamicAccountParameters;
  +    }
   
       /**
  -     * 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));
  +     * Returns the session, lazily initialized if required.
  +     * @return Session
  +     */
  +    protected Session getSession()
  +    {
  +        Session session = null;
  +        if (null == (session = getSessionBasic()))
  +        {
  +            updateSession();
  +            return getSession();
  +        }    
  +        return session;
  +    }
  +    
  +    /**
  +     * Returns the session.
  +     * @return Session
  +     */
  +    private Session getSessionBasic()
  +    {
  +        return fieldSession;
  +    }    
   
  -                    return mailFor;
  -                }
  -            }
  -        } catch (MessagingException me) {
  -            getLogger().info("No Recieved headers found");
  -        }
  -        return null;
  +    /**
  +     * Answers a new Session.
  +     * @return Session
  +     */
  +    protected Session computeSession()
  +    {
  +        return Session.getInstance(System.getProperties());
       }
  +    
  +    /**
  +     * Updates the current Session.
  +     */
  +    protected void updateSession()
  +    {
  +        setSession(computeSession());
  +    }    
   
       /**
  -     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
  +     * Sets the session.
  +     * @param session The session to set
        */
  -    public void configure(Configuration conf) throws ConfigurationException {
  -        this.sHost = conf.getChild("host").getValue();
  -        this.sUser = conf.getChild("user").getValue();
  -        this.sPass = conf.getChild("password").getValue();
  -        this.fetchTaskName = conf.getAttribute("name");
  -        this.javaMailProviderName = conf.getChild("javaMailProviderName").getValue();
  -        this.javaMailFolderName = conf.getChild("javaMailFolderName").getValue();
  -        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");
  -        this.bAll = conf.getChild("fetchall").getValueAsBoolean();
  -        this.bKeep = conf.getChild("leaveonserver").getValueAsBoolean();
  -        this.bRecurse = conf.getChild("recursesubfolders").getValueAsBoolean();
  -        if (getLogger().isDebugEnabled()) {
  -            getLogger().info("Configured FetchMail fetch task " + fetchTaskName);
  -        }
  +    protected void setSession(Session session)
  +    {
  +        fieldSession = session;
       }
  +    
  +    
  +    /**
  +     * Propogate any Session parameters in the configuration to the Session.
  +     * @param configuration The configuration containing the parameters
  +     * @throws ConfigurationException
  +     */
  +    protected void setSessionParameters(Configuration configuration)
  +        throws ConfigurationException
  +    {
  +        Configuration javaMailProperties =
  +            configuration.getChild("javaMailProperties", false);
  +        if (null != javaMailProperties)
  +        {
  +            Properties properties = getSession().getProperties();
  +            Configuration[] allProperties =
  +                javaMailProperties.getChildren("property");
  +            for (int i = 0; i < allProperties.length; i++)
  +            {
  +                properties.setProperty(
  +                    allProperties[i].getAttribute("name"),
  +                    allProperties[i].getAttribute("value"));
  +                if (getLogger().isDebugEnabled())
  +                {
  +                    StringBuffer messageBuffer =
  +                        new StringBuffer("Set property name: ");
  +                    messageBuffer.append(allProperties[i].getAttribute("name"));
  +                    messageBuffer.append(" to: ");
  +                    messageBuffer.append(
  +                        allProperties[i].getAttribute("value"));
  +                    getLogger().debug(messageBuffer.toString());
  +                }
  +            }
  +        }
  +    }    
  +
   }
  
  
  
  1.10      +40 -28    james-server/src/java/org/apache/james/fetchmail/FetchScheduler.java
  
  Index: FetchScheduler.java
  ===================================================================
  RCS file: /home/cvs/james-server/src/java/org/apache/james/fetchmail/FetchScheduler.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- FetchScheduler.java	30 Jan 2004 02:22:08 -0000	1.9
  +++ FetchScheduler.java	11 Feb 2004 18:02:06 -0000	1.10
  @@ -1,5 +1,5 @@
   /***********************************************************************
  - * Copyright (c) 2000-2004 The Apache Software Foundation.             *
  + * Copyright (c) 2003-2004 The Apache Software Foundation.             *
    * All rights reserved.                                                *
    * ------------------------------------------------------------------- *
    * Licensed under the Apache License, Version 2.0 (the "License"); you *
  @@ -14,7 +14,7 @@
    * implied.  See the License for the specific language governing       *
    * permissions and limitations under the License.                      *
    ***********************************************************************/
  -
  + 
   package org.apache.james.fetchmail;
   
   import java.util.ArrayList;
  @@ -37,7 +37,7 @@
    *
    * $Id$
    *
  - *  @see org.apache.james.fetchmail.FetchMail#configure(Configuration) FetchMail
  + *  @see org.apache.james.fetchmail.FetchMailOriginal#configure(Configuration) FetchMailOriginal
    *  
    */
   public class FetchScheduler
  @@ -69,61 +69,73 @@
       /**
        * @see org.apache.avalon.framework.service.Serviceable#service( ServiceManager )
        */
  -    public void service(ServiceManager comp) throws ServiceException {
  +    public void service(ServiceManager comp) throws ServiceException
  +    {
           m_manager = comp;
       }
   
       /**
        * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
        */
  -    public void configure(Configuration conf) throws ConfigurationException {
  +    public void configure(Configuration conf) throws ConfigurationException
  +    {
           this.conf = conf;
       }
   
       /**
        * @see org.apache.avalon.framework.activity.Initializable#initialize()
        */
  -    public void initialize() throws Exception {
  +    public void initialize() throws Exception
  +    {
           enabled = conf.getAttributeAsBoolean("enabled", false);
  -        if (enabled) {
  +        if (enabled)
  +        {
               scheduler = (TimeScheduler) m_manager.lookup(TimeScheduler.ROLE);
               Configuration[] fetchConfs = conf.getChildren("fetch");
  -            for (int i = 0; i < fetchConfs.length; i++) {
  +            for (int i = 0; i < fetchConfs.length; i++)
  +            {
                   FetchMail fetcher = new FetchMail();
                   Configuration fetchConf = fetchConfs[i];
                   String fetchTaskName = fetchConf.getAttribute("name");
  -                fetcher.enableLogging(getLogger().getChildLogger(fetchTaskName));
  -                fetcher.service( m_manager );
  +                fetcher.enableLogging(
  +                    getLogger().getChildLogger(fetchTaskName));
  +                fetcher.service(m_manager);
                   fetcher.configure(fetchConf);
  -                Integer interval = new Integer(fetchConf.getChild("interval").getValue());
  -                PeriodicTimeTrigger fetchTrigger = new PeriodicTimeTrigger(0, interval.intValue());
  +                Integer interval =
  +                    new Integer(fetchConf.getChild("interval").getValue());
  +                PeriodicTimeTrigger fetchTrigger =
  +                    new PeriodicTimeTrigger(0, interval.intValue());
   
  -                scheduler.addTrigger(fetchTaskName, fetchTrigger, fetcher );
  +                scheduler.addTrigger(fetchTaskName, fetchTrigger, fetcher);
                   theFetchTaskNames.add(fetchTaskName);
               }
  -            if( getLogger().isInfoEnabled() )
  -            {
  +
  +            if (getLogger().isInfoEnabled())
                   getLogger().info("FetchMail Started");
  -            }
  -        } else {
  -            if( getLogger().isInfoEnabled() )
  -            {
  +            System.out.println("FetchMail Started");
  +        }
  +        else
  +        {
  +            if (getLogger().isInfoEnabled())
                   getLogger().info("FetchMail Disabled");
  -            }
  +            System.out.println("FetchMail Disabled");
           }
       }
   
       /**
        * @see org.apache.avalon.framework.activity.Disposable#dispose()
        */
  -    public void dispose() {
  -        if (enabled) {
  -            getLogger().info( "FetchMail dispose..." );
  +    public void dispose()
  +    {
  +        if (enabled)
  +        {
  +            getLogger().info("FetchMail dispose...");
               Iterator nameIterator = theFetchTaskNames.iterator();
  -            while (nameIterator.hasNext()) {
  -                scheduler.removeTrigger((String)nameIterator.next());
  +            while (nameIterator.hasNext())
  +            {
  +                scheduler.removeTrigger((String) nameIterator.next());
               }
  -            getLogger().info( "FetchMail ...dispose end" );
  +            getLogger().info("FetchMail ...dispose end");
           }
  -   }
  +    }
   }
  
  
  
  1.4       +3 -0      james-server/src/java/org/apache/james/fetchmail/FetchScheduler.xinfo
  
  Index: FetchScheduler.xinfo
  ===================================================================
  RCS file: /home/cvs/james-server/src/java/org/apache/james/fetchmail/FetchScheduler.xinfo,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- FetchScheduler.xinfo	8 Feb 2003 04:12:25 -0000	1.3
  +++ FetchScheduler.xinfo	11 Feb 2004 18:02:06 -0000	1.4
  @@ -14,6 +14,9 @@
       <dependency>
         <service name="org.apache.james.services.MailServer" version="1.0"/>
       </dependency>
  +    <dependency>
  +      <service name="org.apache.james.services.UsersStore" version="1.0"/>
  +    </dependency>    
       <dependency> 
         <service name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" version="1.0"/>
       </dependency> 
  
  
  
  1.6       +2 -12     james-server/src/java/org/apache/james/fetchmail/ReaderInputStream.java
  
  Index: ReaderInputStream.java
  ===================================================================
  RCS file: /home/cvs/james-server/src/java/org/apache/james/fetchmail/ReaderInputStream.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ReaderInputStream.java	30 Jan 2004 02:22:08 -0000	1.5
  +++ ReaderInputStream.java	11 Feb 2004 18:02:06 -0000	1.6
  @@ -1,5 +1,5 @@
   /***********************************************************************
  - * Copyright (c) 2000-2004 The Apache Software Foundation.             *
  + * Copyright (c) 2003-2004 The Apache Software Foundation.             *
    * All rights reserved.                                                *
    * ------------------------------------------------------------------- *
    * Licensed under the Apache License, Version 2.0 (the "License"); you *
  @@ -15,16 +15,6 @@
    * permissions and limitations under the License.                      *
    ***********************************************************************/
   
  -/**
  - * ReaderInputStream.java
  - * 
  - * Copyright (C) 24-Sep-2002 The Apache Software Foundation. All rights reserved.
  - *
  - * This software is published under the terms of the Apache Software License
  - * version 1.1, a copy of which has been included with this distribution in
  - * the LICENSE file. 
  - *
  - */
   package org.apache.james.fetchmail;
   import java.io.IOException;
   import java.io.InputStream;
  
  
  
  1.2       +117 -0    james-server/src/java/org/apache/james/fetchmail/StoreProcessor.java
  
  
  
  
  1.2       +337 -0    james-server/src/java/org/apache/james/fetchmail/Account.java
  
  
  
  
  1.2       +104 -0    james-server/src/java/org/apache/james/fetchmail/DynamicAccount.java
  
  
  
  
  1.2       +1476 -0   james-server/src/java/org/apache/james/fetchmail/MessageProcessor.java
  
  
  
  
  1.2       +541 -0    james-server/src/java/org/apache/james/fetchmail/ProcessorAbstract.java
  
  
  
  
  1.2       +301 -0    james-server/src/java/org/apache/james/fetchmail/FolderProcessor.java
  
  
  
  
  1.2       +1071 -0   james-server/src/java/org/apache/james/fetchmail/ParsedConfiguration.java
  
  
  
  
  1.2       +105 -0    james-server/src/conf/samples/fetchmail/maxMessageSize.xml
  
  
  
  
  1.2       +57 -0     james-server/src/conf/samples/fetchmail/oneAccountManyUsers.xml
  
  
  
  
  1.2       +59 -0     james-server/src/conf/samples/fetchmail/oneAccountPerUserDynamic.xml
  
  
  
  
  1.2       +67 -0     james-server/src/conf/samples/fetchmail/oneAccountPerUser.xml
  
  
  
  
  1.2       +65 -0     james-server/src/conf/samples/fetchmail/oneAccountManyUsersDynamic.xml
  
  
  
  
  1.56      +13 -49    james-server/src/conf/james-config.xml
  
  Index: james-config.xml
  ===================================================================
  RCS file: /home/cvs/james-server/src/conf/james-config.xml,v
  retrieving revision 1.55
  retrieving revision 1.56
  diff -u -r1.55 -r1.56
  --- james-config.xml	12 Sep 2003 13:42:40 -0000	1.55
  +++ james-config.xml	11 Feb 2004 18:02:06 -0000	1.56
  @@ -1,4 +1,7 @@
   <?xml version="1.0"?>
  +<!DOCTYPE config [
  +<!ENTITY fetchmailConfig SYSTEM "file:../apps/james/conf/james-fetchmail.xml">
  +]>
   <!--  Configuration file for the Apache Jakarta James server -->
   
   <!--  This file contains important settings that control the behaviour -->
  @@ -101,54 +104,15 @@
           </fetch>
       </fetchpop>
   
  -   <!-- Fetch mail block, fetches mail from message servers and inserts it into the incoming spool -->
  -   <!-- 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.                              -->
  -    <fetchmail enabled="false">
  -        <!-- You can have as many fetch tasks as you want, but each must have a -->
  -        <!-- unique name by which it identified -->
  -        <fetch name="mydomain.com">
  -            <!-- Host name or IP address -->
  -            <host>mail.mydomain.com</host>
  -            <!-- Account login username -->
  -            <user>username</user>
  -            <!-- Account login password -->
  -            <password>pass</password>
  -            <!-- How frequently this account is checked - in milliseconds. 600000 is every ten minutes -->
  -            <interval>600000</interval>
  -            <!-- Fetchmail will leave the fetched message unchanged and will add a new envelope     -->
  -            <!-- recipient before spooling the message in James.  -->
  -            <!-- Fetchmail 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">user@mydomain.com</recipient>
  -
  -            <!-- name of the javamail provider you wish to use -->
  -            <!-- (pop3, imap, etc. -->
  -            <javaMailProviderName>pop3</javaMailProviderName>
  -
  -            <!-- name of the folder to open -->
  -            <javaMailFolderName>INBOX</javaMailFolderName>
  -
  -            <!-- If "true" will leave the messages on the server           -->
  -            <!-- and mark them as SEEN if "false" will delete the messages -->
  -            <leaveonserver>false</leaveonserver>
  -
  -            <!-- Retrieve both old (seen) and new messages from mailserver.  The default -->
  -            <!-- is to fetch only messages the server has not marked as seen -->
  -            <fetchall>false</fetchall>
  -
  -            <!-- If the folder javaMailFolderName contains subfolders do you -->
  -            <!-- want to recurse into the subfolders as well? true = yes, false = no -->
  -            <recursesubfolders>false</recursesubfolders>
  -        </fetch>
  -    </fetchmail>
  +    <!-- This is an example configuration for FetchMail, a JavaMail based gateway  -->
  +    <!-- service that pulls messages from other sources, and inserts them into the -->
  +    <!-- spool.  They are then processed normally, although FetchMail generally    -->
  +    <!-- has to fabricate some of the envelope information.  FetchMail should be   -->
  +    <!-- considered a mail gateway, rather than a relay, in RFC terms.             -->
  +    <!-- Fetchmail is a functionally richer replacement for FetchPOP.              -->
  +    <!-- CHECKME: FetchMail is disabled by default, and must be configured to use. -->
  +    <!-- Edit the file referred to by fetchmailConfig to enable and configure.     -->
  +    &fetchmailConfig;    
   
      <!-- The James Spool Manager block  -->
      <!-- -->
  
  
  
  1.2       +232 -0    james-server/src/conf/james-fetchmail.xml
  
  
  
  
  1.10      +2 -1      james-server/src/xdocs/documentation_2_1.xml
  
  Index: documentation_2_1.xml
  ===================================================================
  RCS file: /home/cvs/james-server/src/xdocs/documentation_2_1.xml,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- documentation_2_1.xml	4 Feb 2004 20:11:56 -0000	1.9
  +++ documentation_2_1.xml	11 Feb 2004 18:02:06 -0000	1.10
  @@ -53,7 +53,8 @@
   <li><a href="pop3_configuration_2_1.html">POP3 Server Configuration</a></li>
   <li><a href="smtp_configuration_2_1.html">SMTP Server Configuration</a></li>
   <li><a href="nntp_configuration_2_1.html">NNTP Server Configuration</a></li>
  -<li><a href="fetchpop_configuration_2_1.html">FetchPOP Configuration</a></li>
  +<li><a href="fetchpop_configuration_2_1.html">FetchPOP Configuration <i>(deprecated)</i></a></li>
  +<li><a href="fetchmail_configuration_2_2.html">fetchMail Configuration</a></li>
   <li><a href="remotemanager_configuration_2_1.html">RemoteManager Configuration</a></li>
   <li><a href="repositories_2_1.html">Repository Configuration</a></li>
   <li><a href="spoolmanager_configuration_2_1.html">SpoolManager Configuration</a></li>
  
  
  
  1.4       +6 -0      james-server/src/xdocs/fetchpop_configuration_2_1.xml
  
  Index: fetchpop_configuration_2_1.xml
  ===================================================================
  RCS file: /home/cvs/james-server/src/xdocs/fetchpop_configuration_2_1.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- fetchpop_configuration_2_1.xml	7 Dec 2002 20:38:20 -0000	1.3
  +++ fetchpop_configuration_2_1.xml	11 Feb 2004 18:02:06 -0000	1.4
  @@ -7,6 +7,12 @@
    </properties>
   
   <body>
  +<section name="FetchPOP Is Being Deprecated">
  +<p>FetchPOP is being deprecated.
  +<a href="fetchmail_configuration_2_2.html">fetchMail</a> provides a superset of
  +FetchPOP's functionality and is the preferred solution.</p>
  +</section>
  +
   <section name="FetchPOP Configuration">
   <p>FetchPOP is controlled by a configuration block in the config.xml.
   The fetchpop tag defines the boundaries of the configuration block.  It encloses 
  
  
  
  1.2       +918 -0    james-server/src/xdocs/fetchmail_configuration_2_2.xml
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org