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 ch...@apache.org on 2001/05/16 16:00:39 UTC

cvs commit: jakarta-james/proposals/v1.3/java/org/apache/james/userrepository DefaultJamesUser.java DefaultUser.java UsersFileRepository.java UsersLDAPRepository.java UsersTownRepository.java

charlesb    01/05/16 07:00:38

  Added:       proposals/v1.3/conf james-config.xml
               proposals/v1.3/java/org/apache/james James.java
               proposals/v1.3/java/org/apache/james/services JamesUser.java
                        User.java UsersRepository.java UsersStore.java
               proposals/v1.3/java/org/apache/james/userrepository
                        DefaultJamesUser.java DefaultUser.java
                        UsersFileRepository.java UsersLDAPRepository.java
                        UsersTownRepository.java
  Log:
  Add resettable passwords and case-insensitive capability
  
  Revision  Changes    Path
  1.1                  jakarta-james/proposals/v1.3/conf/james-config.xml
  
  Index: james-config.xml
  ===================================================================
  <?xml version="1.0"?>
  <!--
                                  README!
  
      This configuration file is designed to run without alteration, for simple
      tests.
      It assumes you have a DNS server on localhost and assigns a root pasword
      of root.
  
      For production use, or in case the defaults do not suit you, the items
      you are most likely to need to change are preceeded by a
      CHECKME! or
      CONFIRM? comment in the left
      margin.
  
  -->
  <config>
  
    <!-- The James block  -->
    <James>
  <!-- CHECKME! Set this to the right email address for error reports -->
        <postmaster> Postmaster@localhost </postmaster>
  
  <!-- CONFIRM? -->
        <!-- servernames identifies the DNS namespace served by this instance
        of James.
        If autodetect is TRUE, James wil attempt to discover its own name AND use
        any specified servernames.  If autodetect is FALSE, James will use only
        the specified servernames.  By default, the servername 'localhost' is
        specified. This can be removed, if required. -->
        <servernames autodetect="TRUE">
          <!--
          <servername>To override autodetected server names
                      uncomment this.  </servername>-->
          <servername>localhost</servername>
        </servernames>
  
        <!-- Set whether user names are case sensitive or insensitive -->
        <usernames ignoreCase="TRUE"/>
  
        <!-- Set the type of permanent mailfolders to be used.
        If IMAP service is to be provided, storage must be 'IMAP'; if only POP3
        service is being provided then use must be 'basic' (default) . At some
        stage POP3 will, hopefully, be able to use IMAP storage as well.  This
        choice is irrelevant if the only service provided is SMTP. -->
        <storage>basic</storage>
  
        <!-- If storage is set to IMAP, systemClass and hostClass must point to
        the appropriate classes. -->
        <imapSetup systemClass="org.apache.james.imapserver.SimpleSystem"
                   hostClass="org.apache.james.imapserver.JamesHost"/>
        <imapHost>
          <recordRepository>var/mail/folderRecords/</recordRepository>
          <mailboxRepository>var/mail/mailboxes/</mailboxRepository>
          <namespaces token="#">
            <privateNamespace separator=".">#mail</privateNamespace>
            <otherusersNamespace separator=".">#users</otherusersNamespace>
            <sharedNamespace separator=".">#shared</sharedNamespace>
          </namespaces>
        </imapHost> 
  
        <!-- The spool repository is a singular location where incoming mails
        are temporarily stored before being processed.
       (ex. file://c:/james/spool/) -->
        <spoolRepository>
          <repository destinationURL="file://var/mail/spool/"
                      type="SPOOL"
                      model="SYNCHRONOUS">
          </repository>
        </spoolRepository>
  
        <!-- Alternative spool repository definition for Town use
        <spoolRepository>
          <repository destinationURL="town://mainspool"
                      type="SPOOL"
                      model="SYNCHRONOUS">
            <conn>file:///dev/james/dist/var/maildatabase</conn>
            <table>Message</table>
          </repository>
        </spoolRepository>
        -->
  
        <!-- The inbox repository is the location for users inboxes -->
        <inboxRepository>
          <repository destinationURL="file://var/mail/inboxes/"
                      type="MAIL"
                      model="SYNCHRONOUS">
          </repository>
        </inboxRepository>
  
        <!-- Alternative inbox repository definition for Town use
        <inboxRepository>
          <repository destinationURL="town://inbox"
                      type="SPOOL"
                      model="SYNCHRONOUS">
            <conn>file:///dev/james/dist/var/maildatabase</conn>
            <table>Message</table>
          </repository>
        </inboxRepository>
        -->
    </James>
  
    <!-- The James Spool Manager block  -->
    <spoolmanager>
        <!-- The spool repository is a singular location where incoming mails
        are temporarily stored before being processed.
       (ex. file://c:/james/spool/) 
  	The Spoool Manager and James Block must point to the same repository
  	to add and process same messages. -->
        <spoolRepository>
          <repository destinationURL="file://var/mail/spool/"
                      type="SPOOL"
                      model="SYNCHRONOUS">
          </repository>
        </spoolRepository>
  
        <!-- Alternative spool repository definition for Town use
        <spoolRepository>
          <repository destinationURL="town://mainspool"
                      type="SPOOL"
                      model="SYNCHRONOUS">
            <conn>file:///dev/james/dist/../../store/maildatabase</conn>
            <table>Message</table>
          </repository>
        </spoolRepository>
        -->
  
        <!-- number of spool threads -->
        <threads> 1 </threads>
  
          <!-- Set the packages from which to load mailets and matches -->
          <mailetpackages>
            <mailetpackage>org.apache.james.transport.mailets.</mailetpackage>
          </mailetpackages>
          <matcherpackages>
            <matcherpackage>org.apache.james.transport.matchers.</matcherpackage>
          </matcherpackages>
  
          <!-- Processor CONFIGURATION SAMPLE:
               root is the first processor all mails enter -->
          <processor name="root">
            <!-- Checks that the MAIL FROM command was for a valid domain. 
            Important for spam prevention. -->
            <!-- 
            <mailet match="SenderInFakeDomain" class="ToProcessor">
              <processor> spam </processor>
            </mailet>
            -->
            <!-- Important check to avoid race conditions -->
            <mailet match="RelayLimit=30" class="Null">
            </mailet>
            
            <!-- Check for delivery from a known spam server -->
            <mailet match="InSpammerBlacklist=blackholes.mail-abuse.org"
                    class="ToProcessor">
              <processor> spam </processor>
              <notice> Rejected - see  http://www.mail-abuse.org/rbl/ </notice>
            </mailet>
  
            <mailet match="InSpammerBlacklist=dialups.mail-abuse.org"
                    class="ToProcessor">
              <processor> spam </processor>
              <notice> Dialup - see http://www.mail-abuse.org/dul/ </notice>
            </mailet>
  
            <mailet match="InSpammerBlacklist=relays.mail-abuse.org"
                    class="ToProcessor">
              <processor> spam </processor>
              <notice> Open spam relay - see http://www.mail-abuse.org/rss/ </notice>
            </mailet>
  
            <!-- Sample matching to kill a message (send to Null) -->
            <mailet match="RecipientIs=badboy@badhost" class="Null">
            </mailet>
  
            <!-- Sample listserv wrapping a local avalon list of users. -->
            <mailet match="CommandForListserv=james@localhost"
                    class="AvalonListservManager">
              <membersPath> file://var/users/list-james </membersPath>
            </mailet>
  
            <mailet match="RecipientIs=james@localhost" class="AvalonListserv">
              <membersonly> false </membersonly>
              <attachmentsallowed> true </attachmentsallowed>
              <replytolist> true </replytolist>
              <membersPath>file://var/users/list-james</membersPath>
            </mailet>
  
            <!-- Sends remaining mails to the transport processor for either
            local or remote delivery -->
            <mailet match="All" class="ToProcessor">
              <processor> transport </processor>
            </mailet>
          </processor>
  
          <!-- Processor CONFIGURATION SAMPLE: error is the processor mails with 
          failure conditions enter -->
          <processor name="error">
            <!-- Logs any messages to the repository specified -->
            <mailet match="All" class="ToRepository">
              <repositoryPath> file://var/mail/error/</repositoryPath>
              <!-- <repositoryPath> town://mail-error </repositoryPath>-->
              <passThrough> true </passThrough>
            </mailet>
  
            <!-- If you want to notify the sender their message was marked as
            spam, uncomment this
            <mailet match="All" class="NotifySender">
            </mailet> 
            -->
  
            <!-- If you want to notify the postmaster that a message was marked
            as spam, uncomment this
            <mailet match="All" class="NotifyPostmaster">
            </mailet> 
            -->
          </processor>
  
          <!--  Processor CONFIGURATION SAMPLE: transport is a sample custom 
          processor for local or remote delivery -->
          <processor name="transport">
            <!-- Is the recipient is for a local account, deliver it locally -->
            <mailet match="RecipientIsLocal" class="LocalDelivery">
            </mailet>
  
            <!-- If the host is handled by this server and it did not get
            locally delivered,  this is an invalid recipient -->
            <mailet match="HostIsLocal" class="ToProcessor">
              <processor>error</processor>
            </mailet>
  
  <!-- CHECKME! 
      Anti-relay mailet: Add your network address here, 
      e.g. "RemoteAddrNotInNetwork=127.0.0.1, abc.de.*"
  -->
  
            <!-- This matcher-mailet pair can prevent relaying... if you change
            this,  you risk making your mail server an open relay point for
            spammers .
            NOTE 1: the order of matcher-mailets is important: it must come after 
            valid local recipients have been dealt with but before any attempt is 
            made to delivery the mail remotely.
            NOTE 2: Add your own network, if you want to relay mail outwards -->
            <mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
              <processor> spam </processor>
            </mailet>
  
            <!-- Attempt remote delivery using the specified repository for the
            spool,
            using delay time to retry delivery and the maximum number of
            retries -->
            <mailet match="All" class="RemoteDelivery">
              <outgoing> file://var/mail/outgoing/ </outgoing>
              <!-- <outgoing> town://mail-outgoing </outgoing>-->
              <delayTime> 21600000 </delayTime>
              <maxRetries> 5 </maxRetries>
            </mailet>
          </processor>
  
          <!--  Processor CONFIGURATION SAMPLE: spam is where messages detected
          as relaying or other problems will get sent.  You can either log these,
          bounce these, or just ignore them. -->
          <processor name="spam">
            <!-- If you wanted, you could just destroy messages, uncomment this
            matcher/mailet
            <mailet match="All" class="Null">
            </mailet> 
            -->
  
            <!-- If you want to notify the sender their message was marked as 
            spam, uncomment this
            <mailet match="All" class="NotifySender">
            </mailet> 
            -->
  
            <!-- If you want to notify the postmaster that a message was marked
            as  spam, uncomment this
            <mailet match="All" class="NotifyPostmaster">
            </mailet> 
            -->
  
            <!-- Out of the box, this will log the message to a repository -->
            <mailet match="All" class="ToRepository">
              <repositoryPath>file://var/mail/spam/</repositoryPath>
              <!-- <repositoryPath> town://spam </repositoryPath> -->
            </mailet>
          </processor>
    </spoolmanager>
  
  
  <!-- CONFIRM? Enter ip address of your DNS server, one per element -->
    <dnsserver>
          <servers>
            <server>127.0.0.1</server>
            <!--<server> put extra dns server address here </server>-->
          </servers>
          <authoritative>false</authoritative>
    </dnsserver>
  
  <!-- CHECKME! Change the default password! -->
    <remotemanager>
          <port>4555</port>
          <!-- <bind>  </bind> uncomment this if you want to bind to a specific
          inetaddress -->
          <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
          on this port -->
          <handler>
            <!-- helloName is the single host name this instance of James will use to
             identify itself  for example, in SMTP and POP3 greetings.
             If autodetect is TRUE, James will attempt to discover its own name OR
             use 'localhost'. If autodetect is FALSE, James will use the value given
             OR 'localhost' -->
            <helloName autodetect="TRUE">myMailServer</helloName>
            <administrator_accounts>
  
              <!-- FILL ME!!!!!!  You must provide a password for your
               administrator accounts (cannot be blank) -->
              <account login="root" password="root"/>
  
             </administrator_accounts>
             <connectiontimeout> 60000 </connectiontimeout>
  	</handler>
    </remotemanager>
  
    <!-- WARNING - The IMAP server is only experimental, ie pre-alpha -->
    <imapserver>
  
          <port>143</port>
          <!-- <port>995</port> -->
          <!-- need to check what if any IMAP over SSL uses -->
          <!-- <bind>  </bind>  uncomment this if you want to bind to a specific
          inetaddress-->
          <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
          on this port -->
          <handler>
            <!-- helloName is the single host name this instance of James will use to
              identify itself  for example, in SMTP and POP3 greetings.
              If autodetect is TRUE, James will attempt to discover its own name OR
              use 'localhost'. If autodetect is FALSE, James will use the value given
              OR 'localhost' -->
            <helloName autodetect="TRUE">myMailServer</helloName>
            <connectiontimeout>1800000</connectiontimeout>
  	</handler>
    </imapserver>
  
    <pop3server>
          <port>110</port>
          <!-- <port>995</port> -->
          <!-- port 995 is the well-known/IANA registered port for POP3S
          ie over SSL/TLS -->
          <!-- <bind>  </bind>  uncomment this if you want to bind to a specific
          inetaddress-->
          <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
          on this port -->
          <handler>
            <!-- helloName is the single host name this instance of James will use to
              identify itself  for example, in SMTP and POP3 greetings.
              If autodetect is TRUE, James will attempt to discover its own name OR
              use 'localhost'. If autodetect is FALSE, James will use the value given
              OR 'localhost' -->
            <helloName autodetect="TRUE">myMailServer</helloName>
            <connectiontimeout>120000</connectiontimeout>
          </handler>
    </pop3server>
  
    <smtpserver>
          <port>25</port>
          <!--<bind></bind> uncomment this if you want to bind to a specific
          inetaddress -->
          <!--<useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
          on this port -->
          <handler>
            <!-- helloName is the single host name this instance of James will use to
              identify itself  for example, in SMTP and POP3 greetings.
              If autodetect is TRUE, James will attempt to discover its own name OR
              use 'localhost'. If autodetect is FALSE, James will use the value given
              OR 'localhost' -->
            <helloName autodetect="TRUE">myMailServer</helloName>
            <connectiontimeout>360000</connectiontimeout>
            <!-- This sets the maximum allowed message size for the smtphandler
            in KBytes.
            The value defaults to 0, which means no limit.
            <maxmessagesize>0</maxmessagesize>
             -->
          </handler>
    </smtpserver>
  
    <nntpserver>
          <port>119</port>
          <!-- <port>563</port> -->
          <!-- port 563 is the well-known/IANA registered port for NNTPS
          ie over SSL/TLS -->
          <!-- <bind>  </bind>  uncomment this if you want to bind to a specific
          inetaddress-->
          <!-- <useTLS>TRUE</useTLS> uncomment this if you want to use TLS (SSL)
          on this port -->
          <handler>
            <!-- helloName is the single host name this instance of James will use to
              identify itself  for example, in SMTP and POP3 greetings.
              If autodetect is TRUE, James will attempt to discover its own name OR
              use 'localhost'. If autodetect is FALSE, James will use the value given
              OR 'localhost' -->
            <helloName autodetect="TRUE">myMailServer</helloName>
            <connectiontimeout>120000</connectiontimeout>
  	  <!-- make this true, if you want only authenticated users to access NNTP-->
            <authRequired>false</authRequired>
          </handler>
    </nntpserver>
  
    <nntp-repository>
          <!-- make this true to disallow posting to all newsgroups-->
  	<readOnly>false</readOnly>
  	<rootPath>file:///var/nntp/groups</rootPath>
  	<tempPath>file:///var/nntp/temp</tempPath>
  	<articleIDPath>file:///var/nntp/articleid</articleIDPath>
  	<articleIDDomainSuffix>news.james.apache.org</articleIDDomainSuffix>
  	<!-- these additional news groups would be created and exposed-->
  	<newsgroups>
  	  <newsgroup>org.apache.james.dev</newsgroup>
  	  <newsgroup>org.apache.james.user</newsgroup>
  	  <newsgroup>org.apache.avalon.dev</newsgroup>
  	  <newsgroup>org.apache.avalon.user</newsgroup>
  	</newsgroups>
  	<spool>
            <configuration>
  	    <spoolPath>file:///var/nntp/spool</spoolPath>
  	    <!-- number of threads that process spooler related tasks -->
  	    <threadCount>1</threadCount>
  	    <!-- the spool thread(s) should idle for some time, 
  	        if it has nothing to do  -->
  	    <threadIdleTime>1000</threadIdleTime>
            </configuration>
  	</spool>
    </nntp-repository>
  
    <!-- The High Level Storage block -->
    <mailstore>
        <repositories>
          <repository
              class="org.apache.james.mailrepository.AvalonMailRepository">
            <protocols>
              <protocol>file</protocol>
            </protocols>
            <types>
              <type>MAIL</type>
            </types>
            <models>
              <model>SYNCHRONOUS</model>
              <model>ASYNCHRONOUS</model>
              <model>CACHE</model>
            </models>
          </repository>
          <repository
              class="org.apache.james.mailrepository.AvalonSpoolRepository">
            <protocols>
              <protocol>file</protocol>
            </protocols>
            <types>
              <type>SPOOL</type>
            </types>
            <models>
              <model>SYNCHRONOUS</model>
              <model>ASYNCHRONOUS</model>
              <model>CACHE</model>
            </models>
          </repository>
  
          <repository
              class="org.apache.james.mailrepository.TownSpoolRepository">
            <protocols>
              <protocol>town</protocol>
            </protocols>
            <types>
              <type>SPOOL</type>
              <type>MAIL</type>
            </types>
            <models>
              <model>SYNCHRONOUS</model>
              <model>ASYNCHRONOUS</model>
              <model>CACHE</model>
            </models>
          </repository>
        </repositories>
    </mailstore>
         
    <!-- The User Storage block -->
    <users-store>
        <repository name="LocalUsers"
                    class="org.apache.james.userrepository.UsersFileRepository">
          <destination URL="file://var/users/"/>
        </repository>
        
        <!-- Uncomment this to store users in an RDBMS
        <repository name="LocalUsers"
                    class="org.apache.james.userrepository.UsersTownRepository">
          <destination URL="town://users/">
          <conn>file:///var/maildatabase</conn>
          <table>Users</table>
        </repository>
        -->
        
        <repository name="list-james"
                    class="org.apache.james.userrepository.UsersFileRepository">
          <destination URL="file://var/lists/list-james/"/>
        </repository>
    </users-store>
  
    <!-- Configuration for Cornerstone Blocks only after here
         NOTHING BELOW THIS SHOULD NEED CHANGING,
         (unless you want secure sockets (TLS)) -->
  
    <!-- The Storage block -->
    <objectstorage>
        <repositories>
          <repository class="org.apache.avalon.cornerstone.blocks.masterstore.File_Persistent_Object_Repository">
          <protocols>
            <protocol>file</protocol>
          </protocols>
          <types>
            <type>OBJECT</type>
          </types>
          <models>
            <model>SYNCHRONOUS</model>
            <model>ASYNCHRONOUS</model>
            <model>CACHE</model>
          </models>
        </repository>
        <repository class="org.apache.avalon.cornerstone.blocks.masterstore.File_Persistent_Stream_Repository">
          <protocols>
            <protocol>file</protocol>
          </protocols>
          <types>
            <type>STREAM</type>
          </types>
          <models>
            <model>SYNCHRONOUS</model>
            <model>ASYNCHRONOUS</model>
            <model>CACHE</model>
          </models>
        </repository>
      </repositories>
    </objectstorage>
  
    <!-- The Socket Manager block -->
    <sockets>
        <server-sockets>
          <factory name="plain"
                   class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketFactory" />
          <!--
          <factory name="ssl" 
                   class="org.apache.avalon.cornerstone.blocks.sockets.TLSServerSocketFactory">
            <keystore>
              <file>conf/keystore</file> 
              <password>secret</password> 
              <type>JKS</type> 
              <protocol>TLS</protocol> 
              <algorithm>SunX509</algorithm> 
              <authenticate-client>false</authenticate-client> 
            </keystore>
          </factory>
          -->
        </server-sockets>
  
        <client-sockets>
          <factory name="plain" 
                   class="org.apache.avalon.cornerstone.blocks.sockets.DefaultSocketFactory" />
        </client-sockets>
    </sockets>
  
  </config>
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/James.java
  
  Index: James.java
  ===================================================================
  /*
   * Copyright (C) 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;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.mail.Address;
  import javax.mail.MessagingException;
  import javax.mail.Session;
  import javax.mail.internet.*;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.Component;
  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.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.context.DefaultContext;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  import org.apache.avalon.excalibur.thread.ThreadPool;
  import org.apache.james.core.*;
  import org.apache.james.imapserver.*;
  import org.apache.james.services.*;
  import org.apache.james.transport.*;
  import org.apache.james.userrepository.DefaultJamesUser;
  import org.apache.log.Logger;
  import org.apache.log.Priority;
  import org.apache.mailet.*;
  import org.apache.avalon.phoenix.Block;
  import org.apache.avalon.phoenix.BlockContext;
  
  /**
   * Core class for JAMES. Provides three primary services:
   * <br> 1) Instantiates resources, such as user repository, and protocol
   * handlers
   * <br> 2) Handles interactions between components
   * <br> 3) Provides container services for Mailets
   *
   * @version
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author Serge
   * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
   */
  public class James
      extends AbstractLoggable
      implements Block, Contextualizable, Composable, Configurable, Initializable, 
      MailServer, MailetContext {
  
      public final static String VERSION = "James 1.2.2 Alpha";
  
      private DefaultComponentManager compMgr; //Components shared
      private DefaultContext context;
      private Configuration conf;
  
      private Logger mailetLogger = null;
      //private ThreadPool workerPool;
      private MailStore mailstore;
      private UsersStore usersStore;
      private SpoolRepository spool;
      private MailRepository localInbox;
      private String inboxRootURL;
      private UsersRepository localusers;
      private Collection serverNames;
      private boolean ignoreCase;
  
      // this used to be long, but increment operations on long are not
      // thread safe. Changed to int. 'int' should be ok, because id generation
      // is based on System time and count
      private static int count;
      private MailAddress postmaster;
      private Map mailboxes; //Not to be shared!
      private Hashtable attributes = new Hashtable();
  
      // IMAP related fields
      private boolean useIMAPstorage = false;
      private IMAPSystem imapSystem;
      private Host imapHost;
      protected BlockContext           blockContext;
  
  
      public void contextualize( final Context context )
      {
          this.blockContext = (BlockContext)context;
      }
  
      public void configure(Configuration conf) {
          this.conf = conf;
      }
  
      /**
       * Override compose method of AbstractBlock to create new ComponentManager object
       */
      public void compose(ComponentManager comp) {
          //throws ConfigurationException {
          compMgr = new DefaultComponentManager(comp);
          mailboxes = new HashMap(31);
      }
  
      public void initialize() throws Exception {
  
          getLogger().info("JAMES init...");
  
          //TODO: This should retrieve a more specific named thread pool from BlockContext
          //that is set up in server.xml
          //workerPool = blockContext.getThreadPool( "default" );
          try {
              mailstore = (MailStore) compMgr.lookup("org.apache.james.services.MailStore");
          } catch (Exception e) {
              getLogger().warn("Can't get Store: " + e);
          }
          getLogger().debug("Using MailStore: " + mailstore.toString());
          try {
              usersStore = (UsersStore) compMgr.lookup("org.apache.james.services.UsersStore");
          } catch (Exception e) {
              getLogger().warn("Can't get Store: " + e);
          }
          getLogger().debug("Using UsersStore: " + usersStore.toString());
          context = new DefaultContext();
  
          String hostName = null;
          try {
              hostName = InetAddress.getLocalHost().getHostName();
          } catch  (UnknownHostException ue) {
              hostName = "localhost";
          }
          getLogger().info("Local host is: " + hostName);
  
          // Get the domains and hosts served by this instance
          serverNames = new Vector();
          Configuration serverConf = conf.getChild("servernames");
          if (serverConf.getAttribute("autodetect").equals("TRUE") && (!hostName.equals("localhost"))) {
              serverNames.add(hostName);
          }
  
          final Configuration[] serverNameConfs =
              conf.getChild( "servernames" ).getChildren( "servername" );
          for ( int i = 0; i < serverNameConfs.length; i++ )
          {
              serverNames.add( serverNameConfs[i].getValue() );
          }
          if (serverNames.isEmpty()) {
              throw new ConfigurationException( "Fatal configuration error: no servernames specified!");
          }
  
          for (Iterator i = serverNames.iterator(); i.hasNext(); ) {
              getLogger().info("Handling mail for: " + i.next());
          }
          context.put(Constants.SERVER_NAMES, this.serverNames);
  
  
          // Get postmaster
          String postMasterAddress = conf.getChild("postmaster").getValue("root@localhost");
          this.postmaster = new MailAddress( postMasterAddress );
          context.put( Constants.POSTMASTER, postmaster );
  
          Configuration userNamesConf = conf.getChild("usernames");
          if (userNamesConf.getAttribute("ignoreCase").equals("TRUE")) {
              ignoreCase = true;
          } else {
  	    ignoreCase = false;
  	}
  
          //Get localusers
          try {
              localusers = (UsersRepository) usersStore.getRepository("LocalUsers");
          } catch (Exception e) {
              getLogger().error("Cannot open private UserRepository");
              throw e;
          }
          //}
          compMgr.put("org.apache.james.services.UsersRepository", (Component)localusers);
          getLogger().info("Local users repository opened");
  
          // Get storage system
          if (conf.getChild("storage").getValue().equals("IMAP")) {
              useIMAPstorage = true;
          }
          
          //IMAPServer instance is controlled via assembly.xml. 
          //Assumption is that assembly.xml will set the correct IMAP Store 
          //if IMAP is enabled.
          //if (provideIMAP && (! useIMAPstorage)) {
          //    throw new ConfigurationException ("Fatal configuration error: IMAP service requires IMAP storage ");
          //}
  
          // Get the LocalInbox repository
          if (useIMAPstorage) {
              Configuration imapSetup = conf.getChild("imapSetup");
              String imapSystemClass = imapSetup.getAttribute("systemClass");
              String imapHostClass = imapSetup.getAttribute("hostClass");
  
              try {
                  // We will need to use a no-args constructor for flexibility
                  //imapSystem = new Class.forName(imapSystemClass).newInstance();
                  imapSystem = new SimpleSystem();
                  imapSystem.configure(conf.getChild("imapHost"));
                  imapSystem.contextualize(context);
                  imapSystem.compose(compMgr);
                  if (imapSystem instanceof Initializable) {
                      ((Initializable)imapSystem).initialize();
                  }
                  compMgr.put("org.apache.james.imapserver.IMAPSystem", (Component)imapSystem);
                  getLogger().info("Using SimpleSystem.");
                  imapHost = (Host) Class.forName(imapHostClass).newInstance();
                  //imapHost = new JamesHost();
                  imapHost.configure(conf.getChild("imapHost"));
                  imapHost.contextualize(context);
                  imapHost.compose(compMgr);
                  if (imapHost instanceof Initializable) {
                      ((Initializable)imapHost).initialize();
                  }
                  compMgr.put("org.apache.james.imapserver.Host", (Component)imapHost);
                  getLogger().info("Using: " + imapHostClass);
              } catch (Exception e) {
                  getLogger().error("Exception in IMAP Storage init: " + e.getMessage());
                  throw e;
              }
          } else {
              Configuration inboxConf = conf.getChild("inboxRepository");
              Configuration inboxRepConf = inboxConf.getChild("repository");
              try {
                  localInbox = (MailRepository) mailstore.select(inboxRepConf);
              } catch (Exception e) {
                  getLogger().error("Cannot open private MailRepository");
                  throw e;
              }
              inboxRootURL = inboxRepConf.getAttribute("destinationURL");
          }
          getLogger().info("Private Repository LocalInbox opened");
  
          // Add this to comp
          compMgr.put("org.apache.james.services.MailServer", this);
  
          Configuration spoolConf = conf.getChild("spoolRepository");
          Configuration spoolRepConf = spoolConf.getChild("repository");
          try {
              this.spool = (SpoolRepository) mailstore.select(spoolRepConf);
          } catch (Exception e) {
              getLogger().error("Cannot open private SpoolRepository");
              throw e;
          }
          getLogger().info("Private SpoolRepository Spool opened: "+spool.hashCode());
          //compMgr.put("org.apache.james.services.SpoolRepository", (Component)spool);
          // For mailet engine provide MailetContext
          //compMgr.put("org.apache.mailet.MailetContext", this);
          // For AVALON aware mailets and matchers, we put the Component object as
          // an attribute
          attributes.put(Constants.AVALON_COMPONENT_MANAGER, compMgr);
  
          // int threads = conf.getConfiguration("spoolmanagerthreads").getValueAsInt(1);
          //while (threads-- > 0) {
  /*
          try {
              JamesSpoolManager spoolMgr = new JamesSpoolManager();
              setupLogger( spoolMgr, "SpoolManager" );
              spoolMgr.configure(conf.getChild("spoolmanager"));
              spoolMgr.contextualize(context);
              spoolMgr.compose(compMgr);
              spoolMgr.initialize();
              workerPool.execute(spoolMgr);
              getLogger().info("SpoolManager started");
          } catch (Exception e) {
              getLogger().error("Exception in SpoolManager init: " + e.getMessage());
              throw e;
          }
  */
          System.out.println("James "+VERSION);
          getLogger().info("JAMES ...init end");
      }
  
  
      public void sendMail(MimeMessage message) throws MessagingException {
          MailAddress sender = new MailAddress((InternetAddress)message.getFrom()[0]);
          Collection recipients = new HashSet();
          Address addresses[] = message.getAllRecipients();
          for (int i = 0; i < addresses.length; i++) {
              recipients.add(new MailAddress((InternetAddress)addresses[i]));
          }
          sendMail(sender, recipients, message);
      }
  
  
      public void sendMail(MailAddress sender, Collection recipients, MimeMessage message)
          throws MessagingException {
          //FIX ME!!! we should validate here MimeMessage.  - why? (SK)
          sendMail(sender, recipients, message, Mail.DEFAULT);
      }
  
  
      public void sendMail(MailAddress sender, Collection recipients, MimeMessage message, String state)
          throws MessagingException {
          //FIX ME!!! we should validate here MimeMessage.
          MailImpl mail = new MailImpl(getId(), sender, recipients, message);
          mail.setState(state);
          sendMail(mail);
      }
  
  
      public synchronized void sendMail(MailAddress sender, Collection recipients, InputStream msg)
          throws MessagingException {
  
          // parse headers
          MailHeaders headers = new MailHeaders(msg);
          // if headers do not contains minimum REQUIRED headers fields throw Exception
          if (!headers.isValid()) {
              throw new MessagingException("Some REQURED header field is missing. Invalid Message");
          }
          //        headers.setReceivedStamp("Unknown", (String) serverNames.elementAt(0));
          ByteArrayInputStream headersIn = new ByteArrayInputStream(headers.toByteArray());
          sendMail(new MailImpl(getId(), sender, recipients, new SequenceInputStream(headersIn, msg)));
      }
  
  
      public synchronized void sendMail(Mail mail) throws MessagingException {
          MailImpl mailimpl = (MailImpl)mail;
          try {
              spool.store(mailimpl);
          } catch (Exception e) {
              try {
                  spool.remove(mailimpl);
              } catch (Exception ignored) {
              }
              throw new MessagingException("Exception spooling message: " + e.getMessage());
          }
          getLogger().info("Mail " + mailimpl.getName() + " pushed in spool");
      }
  
      /**
       * For POP3 server only - at the momment.
       */
      public synchronized MailRepository getUserInbox(String userName) {
  
          MailRepository userInbox = (MailRepository) null;
  
          userInbox = (MailRepository) mailboxes.get(userName);
  
          if (userInbox != null) {
              return userInbox;
          } else if (mailboxes.containsKey(userName)) {
              // we have a problem
              getLogger().error("Null mailbox for non-null key");
              throw new RuntimeException("Error in getUserInbox.");
          } else {
              // need mailbox object
              getLogger().info("Need inbox for " + userName );
              String destination = inboxRootURL + userName + File.separator;;
              DefaultConfiguration mboxConf
                  = new DefaultConfiguration("repository", "generated:AvalonFileRepository.compose()");
              mboxConf.addAttribute("destinationURL", destination);
              mboxConf.addAttribute("type", "MAIL");
              mboxConf.addAttribute("model", "SYNCHRONOUS");
              try {
                  userInbox = (MailRepository) mailstore.select(mboxConf);
                  mailboxes.put(userName, userInbox);
              } catch (Exception e) {
                  getLogger().error("Cannot open user Mailbox" + e);
                  throw new RuntimeException("Error in getUserInbox." + e);
              }
              return userInbox;
          }
      }
  
      public String getId() {
          return "Mail" + System.currentTimeMillis() + "-" + count++;
      }
  
      public static void main(String[] args) {
          System.out.println("ERROR!");
          System.out.println("Cannot execute James as a stand alone application.");
          System.out.println("To run James, you need to have the Avalon framework installed.");
          System.out.println("Please refer to the Readme file to know how to run James.");
      }
  
      //Methods for MailetContext
  
      public Collection getMailServers(String host) {
          DNSServer dnsServer = null;
          try {
              dnsServer = (DNSServer) compMgr.lookup("org.apache.james.services.DNSServer");
          } catch ( final ComponentException cme ) {
              getLogger().error("Fatal configuration error - DNS Servers lost!", cme );
              throw new RuntimeException("Fatal configuration error - DNS Servers lost!");
          }
          return dnsServer.findMXRecords(host);
      }
  
      public Object getAttribute(String key) {
          return attributes.get(key);
      }
  
      public void setAttribute(String key, Object object) {
          attributes.put(key, object);
      }
  
      public void removeAttribute(String key) {
          attributes.remove(key);
      }
  
      public Iterator getAttributeNames() {
          Vector names = new Vector();
          for (Enumeration e = attributes.keys(); e.hasMoreElements(); ) {
              names.add(e.nextElement());
          }
          return names.iterator();
      }
  
      public void bounce(Mail mail, String message) throws MessagingException {
          bounce(mail, message, getPostmaster());
      }
  
      public void bounce(Mail mail, String message, MailAddress bouncer) throws MessagingException {
          MimeMessage orig = mail.getMessage();
          //Create the reply message
          MimeMessage reply = (MimeMessage) orig.reply(false);
          //Create the list of recipients in our MailAddress format
          Collection recipients = new HashSet();
          Address addresses[] = reply.getAllRecipients();
          for (int i = 0; i < addresses.length; i++) {
              recipients.add(new MailAddress((InternetAddress)addresses[i]));
          }
          //Change the sender...
          reply.setFrom(bouncer.toInternetAddress());
          try {
              //Create the message body
              MimeMultipart multipart = new MimeMultipart();
              //Add message as the first mime body part
              MimeBodyPart part = new MimeBodyPart();
              part.setContent(message, "text/plain");
              part.setHeader("Content-Type", "text/plain");
              multipart.addBodyPart(part);
  
              //Add the original message as the second mime body part
              part = new MimeBodyPart();
              part.setContent(orig.getContent(), orig.getContentType());
              part.setHeader("Content-Type", orig.getContentType());
              multipart.addBodyPart(part);
  
              reply.setContent(multipart);
              reply.setHeader("Content-Type", multipart.getContentType());
          } catch (IOException ioe) {
              throw new MessagingException("Unable to create multipart body");
          }
          //Send it off...
          sendMail(bouncer, recipients, reply);
      }
  
      public boolean isLocalUser(String name) {
  	if (ignoreCase) {
  	    return localusers.containsCaseInsensitive(name);
  	} else {
              return localusers.contains(name);
  	}
      }
  
      public MailAddress getPostmaster() {
          return postmaster;
      }
  
      public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage message) {
  
          if (useIMAPstorage) {
              ACLMailbox mbox = null;
              try {
                  String folderName = "#users." + recipient.getUser() + ".INBOX";
                  getLogger().debug("Want to store to: " + folderName);
                  mbox = imapHost.getMailbox(MailServer.MDA, folderName);
                  if(mbox.store(message,MailServer.MDA)) {
                      getLogger().info("Message " + message.getMessageID() +" stored in " + folderName);
                  } else {
                      throw new RuntimeException("Failed to store mail: ");
                  }
                  imapHost.releaseMailbox(MailServer.MDA, mbox);
                  mbox = null;
              } catch (Exception e) {
                  getLogger().error("Exception storing mail: " + e);
                  e.printStackTrace();
                  if (mbox != null) {
                      imapHost.releaseMailbox(MailServer.MDA, mbox);
                      mbox = null;
                  }
                  throw new RuntimeException("Exception storing mail: " + e);
              }
          } else {
              Collection recipients = new HashSet();
              recipients.add(recipient);
              MailImpl mailImpl = new MailImpl(getId(), sender, recipients, message);
  	    String username;
  	    if (ignoreCase) {
  	        username = localusers.getRealName(recipient.getUser());
  	    } else {
  		username = recipient.getUser();
  	    }
              getUserInbox(username).store(mailImpl);
          }
      }
  
      public int getMajorVersion() {
          return 1;
      }
  
      public int getMinorVersion() {
          return 2;
      }
  
      public boolean isLocalServer( final String serverName ) {
          return serverNames.contains( serverName );
      }
  
      public String getServerInfo() {
          return "JAMES/1.2";
      }
  
      private Logger getMailetLogger() {
          if ( mailetLogger == null )
              mailetLogger = getLogger().getChildLogger("Mailet");
          return mailetLogger;
      }
      public void log(String message) {
          getMailetLogger().info(message);
      }
  
      public void log(String message, Throwable t) {
          //System.err.println(message);
          //t.printStackTrace(); //DEBUG
          getMailetLogger().log(Priority.INFO,message,t);
      }
  
      /**
       * Adds a user to this mail server. Currently just adds user to a
       * UsersRepository.
       * <p> As we move to IMAP support this will also create mailboxes and
       * access control lists.
       *
       * @param userName String representing user name, that is the portion of
       * an email address before the '@<domain>'.
       * @param password String plaintext password
       * @returns boolean true if user added succesfully, else false.
       */
      public boolean addUser(String userName, String password) {
  	boolean success;
  	DefaultJamesUser user = new DefaultJamesUser(userName, password);
  	user.initialize();
          success = localusers.addUser(user);
          if (useIMAPstorage && success) {
              JamesHost jh = (JamesHost) imapHost;
              if (jh.createPrivateMailAccount(userName)) {
                  getLogger().info("New MailAccount created for" + userName);
              }
          }
          return success;
      }
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/services/JamesUser.java
  
  Index: JamesUser.java
  ===================================================================
  /*
   * Copyright (C) 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.services;
  
  /**
   * Interface for objects representing users of an email/ messaging system.
   *
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:29 $
   * $Revision: 1.1 $
   */
  
  public interface JamesUser extends User {
  
      /**
       * Change password to pass. Return true if uccessful.
       */
      boolean setPassword(String pass);
  
      /**
       * Indicate if mail for this user should be forwarded to some other mail
       * server.
       */
      void setForwarding(boolean forward);
  
      /** 
       * Return true if mail for this user should be forwarded
       */
      boolean getForwarding();
  
      /**
       * Set destination for forwading mail
       * Should we use a MailAddress?
       */
      boolean setForwardingDestination(String address);
  
      /**
       * Return the destination to which email should be forwarded
       */
      String getForwardingDestination();
  
      /**
       * Indicate if mail received for this user should be delivered locally to
       * a different address.
       */
      void setAliasing(boolean alias);
  
      /**
       * Return true if emails should be dlivered locally to an alias.
       */
      boolean getAliasing();
  
      /**
       * Set local address to which email should be delivered.
       *
       * @returns true if successful
       */
      boolean setAlias(String address);
  
      /**
       * Get local address to which mail should be delivered.
       */
      String getAlias();
  
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/services/User.java
  
  Index: User.java
  ===================================================================
  /*
   * Copyright (C) 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.services;
  
  /**
   * Interface for objects representing users.
   *
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:30 $
   * $Revision: 1.1 $
   */
  
  public interface User {
  
      /**
       * Return the user name of this user
       */
      String getUserName();
  
      /**
       * Return true if pass matches password of this user.
       */
      boolean verifyPassword(String pass);
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/services/UsersRepository.java
  
  Index: UsersRepository.java
  ===================================================================
  /*
   * Copyright (C) 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.services;
  
  import java.util.Iterator;
  
  /**
   * Interface for a repository of users. A repository represents a logical
   * grouping of users, typically by common purpose. E.g. the users served by an
   * email server or the members of a mailing list.
   *
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:31 $
   * $Revision: 1.1 $
   */
  public interface UsersRepository {
  
      String USER = "USER";
  
      /**
       * Adds a user to the repository with the specified User object.
       *
       * @returns true if succesful, false otherwise
       * @since James 1.2.2
       */
      boolean addUser(User user);
  
      /**
       * Adds a user to the repository with the specified attributes.  In current
       * implementations, the Object attributes is generally a String password.
       */
      void addUser(String name, Object attributes);
  
      /**
       * Gets the attribute for a user.  Not clear on behavior.
       *
       * @deprecated As of James 1.2.2 . Use the {@link #getUserByName(String) getUserByName} method.
       */
      Object getAttributes(String name);
  
  
      /**
       * Get the user object with the specified user name.  Return null if no
       * such user.
       *
       * @since James 1.2.2
       */
      User getUserByName(String name);
  
      /**
       * Get the user object with the specified user name. Match user naems on
       * a case insensitive basis.  Return null if no such user.
       *
       * @since James 1.2.2
       */
      User getUserByNameCaseInsensitive(String name);
  
      /**
       * Returns the user name of the user matching name on an equalsIgnoreCase
       * basis. Returns null if no match.
       */
      String getRealName(String name);
  
      /**
       * Update the repository with the specified user object. A user object
       * with this username must already exist.
       *
       * @returns true if successful.
       */
      boolean updateUser(User user);
  
      /**
       * Removes a user from the repository
       */
      void removeUser(String name);
  
      /**
       * Returns whether or not this user is in the repository
       */
      boolean contains(String name);
  
      /**
       * Returns whether or not this user is in the repository. Names are
       * matched on a case insensitive basis.
       */
      boolean containsCaseInsensitive(String name);
  
  
      /**
       * Tests a user with the appropriate attributes.  In current implementations,
       * this typically means "check the password" where a String password is passed
       * as the Object attributes.
       *
       * @deprecated As of James 1.2.2, use {@link #test(String, String) test(String name, String password)}
       */
      boolean test(String name, Object attributes);
  
      /**
       * Test if user with name 'name' has password 'password'.
       *
       * @since James 1.2.2
       */
      boolean test(String name, String password);
  
      /**
       * Returns a count of the users in the repository.
       */
      int countUsers();
  
      /**
       * List users in repository.
       *
       * @returns Iterator over a collection of Strings, each being one user in the repository.
       */
      Iterator list();
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/services/UsersStore.java
  
  Index: UsersStore.java
  ===================================================================
  /*
   * Copyright (C) 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.services;
  
  import org.apache.avalon.phoenix.Service;
  
  /**
   * Interface for Phoenix blocks to access a store of Users. A UserStore
   * contains one or more UserRepositories. Multiple UserRepositories may or may
   * not have overlapping membership. 
   *
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
   */
  public interface UsersStore 
      extends Service {
  
      UsersRepository getRepository( String name );
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/userrepository/DefaultJamesUser.java
  
  Index: DefaultJamesUser.java
  ===================================================================
  /*
   * Copyright (C) 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.userrepository;
  
  import java.io.Serializable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.james.services.User;
  import org.apache.james.services.JamesUser;
  
  /**
   * Implementation of User Interface.
   *
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:35 $
   * $Revision: 1.1 $
   */
  
  public class DefaultJamesUser 
          extends DefaultUser
          implements JamesUser, Initializable {
  
      private boolean forwarding;
      private String forwardingDestination;
      private boolean aliasing;
      private String alias;
  
      public DefaultJamesUser(String name, String pass) {
  	super(name, pass);
      }
  
      /**
       * Call initialize when creating a new instance.
       */
      public void initialize() {
  	forwarding = false;
  	forwardingDestination = "";
  	aliasing = false;
  	alias = "";
      }
  
      public boolean setPassword(String pass) {
  	return setPass(pass);
      }
  
      public void setForwarding(boolean forward) {
  	forwarding = forward;
      }
  
      public boolean getForwarding() {
  	return forwarding;
      }
  
      
      public boolean setForwardingDestination(String address) {
  	/* Some verification would be good */
  	forwardingDestination = address;
  	return true;
      }
  
      public String getForwardingDestination() {
  	return forwardingDestination;
      }
  
      public void setAliasing(boolean alias) {
          aliasing = alias;
      }
  
      public boolean getAliasing() {
  	return aliasing;
      }
  
      public boolean setAlias(String address) {
  	/* Some verification would be good */
  	alias = address;
  	return true;
      }
  
      public String getAlias() {
  	return alias;
      }
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/userrepository/DefaultUser.java
  
  Index: DefaultUser.java
  ===================================================================
  /*
   * Copyright (C) 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.userrepository;
  
  import java.io.Serializable;
  import org.apache.james.services.User;
  
  /**
   * Implementation of User Interface. Instances of this class do not allow
   * the password to be reset.
   *
   * @author Charles Benett <ch...@benett1.demon.co.uk>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:35 $
   * $Revision: 1.1 $
   */
  
  public class DefaultUser implements User, Serializable {
  
      private String userName;
      private String password;
  
      public DefaultUser(String name, String pass) {
  	userName = name;
  	password = pass;
      }
  
      public String getUserName() {
  	return userName;
      }
  
      public boolean verifyPassword(String pass) {
  	return pass.equals(password);
      }
  
      protected boolean setPass(String newPass) {
       // Check that this is being called by a subclass not from package
  	String rtClass = getClass().getName();
  	if (rtClass.equals("org.apache.james.userrepository.DefaultUser")) {
  	    throw new RuntimeException("Attempt to call setPassword in DefaultUSer");
  	} else {
  	    password = newPass;
  	    return true;
  	}
      }
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/userrepository/UsersFileRepository.java
  
  Index: UsersFileRepository.java
  ===================================================================
  /*
   * Copyright (C) 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.userrepository;
  
  import java.io.File;
  import java.util.Iterator;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.Component;
  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.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  import org.apache.avalon.cornerstone.services.store.ObjectRepository;
  import org.apache.avalon.cornerstone.services.store.Store;
  import org.apache.avalon.excalibur.concurrent.Lock;
  import org.apache.james.services.UsersRepository;
  import org.apache.james.services.User;
  
  /**
   * Implementation of a Repository to store users on the File System.
   *
   * Requires a configuration element in the .conf.xml file of the form:
   *  <repository destinationURL="file://path-to-root-dir-for-repository"
   *              type="USERS"
   *              model="SYNCHRONOUS"/>
   * Requires a logger called UsersRepository.
   *
   * @version 1.0.0, 24/04/1999
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author  <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
   *
   * Last changed by: $Author: charlesb $ on $Date: 2001/05/16 14:00:36 $
   * $Revision: 1.1 $
   */
  public class UsersFileRepository
      extends AbstractLoggable
      implements UsersRepository, Component, Configurable, Composable, Initializable {
   
      protected static boolean DEEP_DEBUG = true;
  
      private static final String TYPE = "USERS";
  
      private Store store;
      private ObjectRepository or;
      private String destination;
      private Lock lock  = new Lock();
  
      public void configure( final Configuration configuration )
          throws ConfigurationException {
  
          destination = configuration.getChild( "destination" ).getAttribute( "URL" );
  
          if (!destination.endsWith(File.separator)) {
              destination += File.separator;
          }
      }
  
      public void compose( final ComponentManager componentManager )
          throws ComponentException {
  
  	try {
              store = (Store)componentManager.
                  lookup( "org.apache.avalon.cornerstone.services.store.Store" );
              lock = new Lock();
  
          } catch (Exception e) {
              final String message = "Failed to retrieve Store component:" + e.getMessage();
              getLogger().error( message, e );
              throw new ComponentException( message, e );
          }
      }
  
      public void initialize()
          throws Exception {
  
          try {
              //prepare Configurations for object and stream repositories
              final DefaultConfiguration objectConfiguration
                  = new DefaultConfiguration( "repository",
                                              "generated:UsersFileRepository.compose()" );
  
              objectConfiguration.addAttribute( "destinationURL", destination );
              objectConfiguration.addAttribute( "type", "OBJECT" );
              objectConfiguration.addAttribute( "model", "SYNCHRONOUS" );
  
              or = (ObjectRepository)store.select( objectConfiguration );
  	    getLogger().debug(this.getClass().getName() + " created in " + destination);
          } catch (Exception e) {
              getLogger().error("Failed to initialize repository:" + e.getMessage(), e );
              throw e;
          }
      }
  
      public Iterator list() {
          return or.list();
      }
  
      public synchronized boolean addUser(User user) {
  	String username = user.getUserName();
  	if (contains(username)) {
  	    return false;
  	}
          try {
              or.put(username, user);
          } catch (Exception e) {
              throw new RuntimeException("Exception caught while storing user: " + e );
          }
  	return true;
      }
  
      public synchronized void addUser(String name, Object attributes) {
  	if (attributes instanceof String)
          {
  	    User newbie = new DefaultUser(name, (String) attributes);
  	    addUser(newbie);
  	}
          else
          {
              throw new RuntimeException("Improper use of deprecated method - use addUser(User user)");
          }
      }
  
      public synchronized User getUserByName(String name) {
          try {
              return (User)or.get(name);
          } catch (Exception e) {
              throw new RuntimeException("Exception while retrieving user: " + e.getMessage());
          }
      }
  
      public User getUserByNameCaseInsensitive(String name) {
  	String realName = getRealName(name);
  	if (realName == null ) {
            throw new RuntimeException("No such user");
  	}
  	return getUserByName(realName);
      }
  
      public String getRealName(String name) {
          Iterator it = list();
  	while (it.hasNext()) {
  	    String temp = (String) it.next();
  	    if (name.equalsIgnoreCase(temp)) {
  		return temp;
  	    }
  	}
  	return null;
      }
      public Object getAttributes(String name) {
         
          throw new RuntimeException("Improper use of deprecated method - read javadocs");
          
      }
  
      public boolean updateUser(User user) {
  	String username = user.getUserName();
  	if (!contains(username)) {
  	    return false;
  	}
          try {
              or.put(username, user);
          } catch (Exception e) {
              throw new RuntimeException("Exception caught while storing user: " + e );
          }
  	return true;
      }
  
      public synchronized void removeUser(String name) {
          or.remove(name);
      }
  
      public boolean contains(String name) {
  	return or.containsKey(name);
      }
  
      public boolean containsCaseInsensitive(String name) {
  	Iterator it = list();
  	while (it.hasNext()) {
  	    if (name.equalsIgnoreCase((String)it.next())) {
  		return true;
  	    }
  	}
  	return false;
      }
  
      public boolean test(String name, Object attributes) {
          try {
              return attributes.equals(or.get(name));
          } catch (Exception e) {
              return false;
          }
      }
  
      public boolean test(String name, String password) {
  	User user;
  	try {
  	    if (contains(name)) {
  	        user = (User) or.get(name);
  	    } else {
                 return false;
  	    }
          } catch (Exception e) {
              throw new RuntimeException("Exception retrieving User" + e);
          }
  	return user.verifyPassword(password);
      }
  
      public int countUsers() {
          int count = 0;
          for (Iterator it = list(); it.hasNext(); it.next()) {
              count++;
          }
          return count;
      }
  
  }
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/userrepository/UsersLDAPRepository.java
  
  Index: UsersLDAPRepository.java
  ===================================================================
  /*
   * Copyright (C) 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.userrepository;
  
  import java.io.*;
  import java.util.*;
  import javax.naming.*;
  import javax.naming.directory.*;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.Composable;
  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.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.Loggable;
  import org.apache.james.Constants;
  import org.apache.james.services.User;
  import org.apache.james.services.UsersRepository;
  import org.apache.log.Logger;
  
  /**
   * Implementation of a Repository to store users.
   *
   * This clas is a dummy for the proposal!
   *
   * @version 1.0.0, 24/04/1999
   * @author  Charles Bennett
   */
  public class UsersLDAPRepository
      implements UsersRepository, Loggable, Configurable, Contextualizable, Initializable{
  
      private ComponentManager comp;
  
      private Logger logger;
      private String path;
      private String name;
      private String destination;
      private String type;
      private String model;
      private DirContext ctx;
  
      private String LDAPHost;
      private String rootNodeDN;
      private String rootURL;
      private String serverRDN;
      private String baseNodeDN;
      private String baseURL;
      private String mailAddressAttr;
      private String identAttr;
      private String authType;
      private String principal;
      private String password;
      private String usersDomain;
      private String membersAttr;
      private boolean manageGroupAttr;
      private String groupAttr;
      private boolean managePasswordAttr;
      private String passwordAttr;
  
  
      public void setLogger(final Logger a_Logger) {
          logger = a_Logger;
      }
  
      public void configure(Configuration conf)
          throws ConfigurationException {
  
          LDAPHost = conf.getChild("LDAPServer").getValue();
          rootNodeDN = conf.getChild("LDAPRoot").getValue();
          serverRDN = conf.getChild("ThisServerRDN").getValue();
          mailAddressAttr
              = conf.getChild("MailAddressAttribute").getValue();
          identAttr = conf.getChild("IdentityAttribute").getValue();
          authType = conf.getChild("AuthenticationType").getValue();
          principal = conf.getChild("Principal").getValue();
          password = conf.getChild("Password").getValue();
  
          membersAttr = conf.getChild("MembersAttribute").getValue();
          manageGroupAttr
              = conf.getChild("ManageGroupAttribute").getValue().equals("TRUE");
          groupAttr = conf.getChild("GroupAttribute").getValue();
          managePasswordAttr = conf.getChild("ManagePasswordAttribute").getValue().equals("TRUE");
          passwordAttr = conf.getChild("PasswordAttribute").getValue();
      }
  
      public void compose(ComponentManager compMgr) {
          this.comp = comp;
      }
  
      public void contextualize(Context context) 
          throws ContextException {
          Collection serverNames
              = (Collection)context.get(Constants.SERVER_NAMES);
          usersDomain = (String)serverNames.iterator().next();
      }
  
      public void setServerRoot() {
          this.setBase(serverRDN +", " + rootNodeDN);
      }
  
      public void setBase(String base) {
          baseNodeDN = base;
      }
  
      public void initialize() throws Exception {
          //setServerRoot();
          rootURL = LDAPHost + "/" + rootNodeDN;
          baseURL = LDAPHost + "/" + baseNodeDN;
  
          logger.info("Creating initial context from " + baseURL);
          //System.out.println("Creating initial context from " + baseURL);
  
          Hashtable env = new Hashtable();
          env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
                  "com.sun.jndi.ldap.LdapCtxFactory");
          env.put(javax.naming.Context.PROVIDER_URL, baseURL);
  
          try {
              ctx = new InitialDirContext(env); // Could throw a NamingExcpetion
          } catch (Exception e) {
              e.getMessage();
              e.printStackTrace();
          }
  
  
          logger.info("Initial context initialised from " + baseURL);
      }
  
  
  
      public String getChildDestination(String childName) {
  
          String destination = null;
          String filter = "cn=" + childName;
          SearchControls ctls = new SearchControls();
  
          try {
  
              NamingEnumeration result  = ctx.search("", filter, ctls);
  
              if (result.hasMore()) {
                  destination = "cn=" + childName + ", " + baseNodeDN;
                  logger.info("Pre-exisisting LDAP node: " + destination);
              } else {
                  Attributes attrs = new BasicAttributes(true);
                  Attribute objclass = new BasicAttribute("objectclass");
                  objclass.add("top");
                  objclass.add("rfc822MailGroup");
                  attrs.put(objclass);
                  Attribute cname = new BasicAttribute("cn");
                  cname.add(childName);
                  attrs.put(cname);
                  Attribute owner = new BasicAttribute("owner");
                  owner.add("JAMES-unassigned");
                  attrs.put(owner);
  
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
  
                  ctx.createSubcontext("cn="+childName, attrs);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
  
                  destination = "cn=" + childName + ", " + baseNodeDN;
                  logger.info("Created new LDAP node: " + destination);
              }
          } catch (NamingException e) {
              System.out.println("Problem with child nodes " + e.getMessage());
              e.printStackTrace();
          }
  
          return destination;
      }
  
      public Iterator list() {
  
          List result = new ArrayList();
          String filter = mailAddressAttr + "=*";
          String[] attrIDs = {membersAttr};
  
          try {
              Attribute members
                  = ctx.getAttributes("", attrIDs).get(membersAttr);
              if (members != null) {
                  NamingEnumeration enum = members.getAll();
                  while (enum.hasMore()) {
                      result.add((String)enum.next());
                  }
              }
          } catch (NamingException e) {
              logger.error("Problem listing mailboxes. " + e );
  
          }
          return result.iterator();
      }
  
  
  
  
      // Methods from interface UsersRepository --------------------------
  
      public boolean addUser(User user) {
  	return false;
      }
  
      public  User getUserByName(String name) {
  	return new DefaultUser("dummy", "dummy");
      }
  
      public User getUserByNameCaseInsensitive(String name) {
  	return getUserByName(name);
      }
  
      public boolean containsCaseInsensitive(String name) {
          return contains(name);
      }
  
      public String getRealName(String name) {
  	return null;
      }
  
      public boolean updateUser(User user) {
  	return false;
      }
  
      public boolean test(String name, String password) {
  	return false;
      }
  
      /**
       * Adds userName to the MemberAttribute (specified in conf.xml) of this
       * node.
       * If ManageGroupAttribute (conf.xml) is TRUE then calls addGroupToUser.
       */
      public synchronized void addUser(String userName, Object attributes) {
  
          String[] attrIDs = {membersAttr};
  
          // First, add username to mailGroup at baseNode
  
          try {
              Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
  
  
              if (members != null && members.contains(userName)) {//user already here
                  logger.info("Found " + userName + " already in mailGroup. " );
                  //System.out.println("Found " + userName + " already in mailGroup. ");
  
              } else {
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
  
                  ModificationItem[] mods = new ModificationItem[1];
                  mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute(membersAttr, userName));
  
                  ctx.modifyAttributes("", mods);
  
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
                  logger.info(userName + " added to mailGroup " + baseNodeDN );
                  //System.out.println(userName + " added to mailGroup " + baseNodeDN);
              }
          } catch (NamingException e) {
              logger.error("Problem adding user " + userName + " to: " + baseNodeDN + e);
              //System.out.println("Problem adding user " + userName + " to: " + baseNodeDN);
              //System.out.println(e.getMessage());
              //e.printStackTrace();
          }
  
          // Add attributes to user objects, if necessary
  
          if (manageGroupAttr) {
              addGroupToUser(userName);
          }
  
          if (managePasswordAttr) {
              String userPassword = (String) attributes; // Not yet implemented
          }
      }
  
      private void addGroupToUser(String userName) {
          String[] attrIDs = {membersAttr};
  
          Hashtable env = new Hashtable();
          env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
          env.put(javax.naming.Context.PROVIDER_URL, rootURL);
  
          try {
              DirContext rootCtx = new InitialDirContext(env);
  
              String[] returnAttrs = {groupAttr};
              SearchControls ctls = new SearchControls();
              ctls.setReturningAttributes(attrIDs);
              ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
              String filter = mailAddressAttr + "=" + userName + "@" + usersDomain;
  
              NamingEnumeration enum  = rootCtx.search("", filter, ctls);
  
              if (enum.hasMore()) { // ie User is in Directory
                  SearchResult newSr = (SearchResult)enum.next();
                  String userDN = newSr.getName();
                  Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr);
  
  
                  if (servers != null && servers.contains(baseNodeDN)) {//server already registered for user
                      logger.info(baseNodeDN + " already in user's Groups. " );
                      //System.out.println(baseNodeDN + " already in user's Groups. ");
  
                  } else {
  
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
  
                      rootCtx.modifyAttributes(userDN, DirContext.ADD_ATTRIBUTE, new BasicAttributes(groupAttr, baseNodeDN, true));
  
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
                      logger.info(baseNodeDN + " added to user's groups ");
                      //System.out.println(baseNodeDN + " added to users' groups ");
  
                  }
  
              } else {
                  logger.info("User " + userName + " not in Directory.");
                  // System.out.println("User " + userName + " not in Directory.");
  
              }
              rootCtx.close();
  
  
  
          } catch (NamingException e) {
              logger.error("Problem adding group to user " + userName);
              //System.out.println("Problem adding group to user " + userName);
              //System.out.println(e.getMessage());
              //e.printStackTrace();
          }
  
      }
  
  
  
  
      public synchronized Object getAttributes(String name) {
          return null;
      }
  
  
      public synchronized void removeUser(String userName) {
          String[] attrIDs = {membersAttr};
  
          try {
              Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
              if (members == null) {
                  System.out.println("UsersLDAPRepository - Null list attribute.");
  
              } else  if (!members.contains(userName)) {//user not here
                  logger.info(userName + " missing from mailGroup. ");
                  //System.out.println(userName + " missing from mailGroup. ");
  
              } else {
                  // First, remove username from mailGroup at baseNode
  
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
  
                  ModificationItem[] mods = new ModificationItem[1];
                  mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(membersAttr, userName));
  
                  ctx.modifyAttributes("", mods);
  
  
                  ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
                  logger.info(userName + " removed from mailGroup. ");
                  //System.out.println(userName + " removed from mailGroup. ");
              }
          } catch (NamingException e) {
              logger.error("Problem removing user " + userName + e);
              //System.out.println("Problem removing user " + userName);
              //System.out.println(e.getMessage());
              //e.printStackTrace();
          }
          if (manageGroupAttr) {
              removeGroupFromUser(userName);
          }
  
          if (managePasswordAttr) {
              // not yet implemented
          }
  
      }
  
      public void removeGroupFromUser(String userName) {
  
          Hashtable env = new Hashtable();
          env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
          env.put(javax.naming.Context.PROVIDER_URL, rootURL);
  
  
          try {
              DirContext rootCtx = new InitialDirContext(env);
  
              // Find directory entry
              String[] returnAttrs = {groupAttr};
              SearchControls ctls = new SearchControls();
              ctls.setReturningAttributes(returnAttrs);
              ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
              String filter = mailAddressAttr + "=" + userName + "@" + usersDomain;
  
              NamingEnumeration enum  = rootCtx.search("", filter, ctls);
  
              if (enum.hasMore()) { // ie User is in Directory
                  SearchResult newSr = (SearchResult)enum.next();
                  String userDN = newSr.getName();
  
                  System.out.println("Found user entry: " + userDN);
  
                  Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr);
                  if (servers == null) { //should not happen
                      logger.info("GroupAttribute missing from user: " + userName);
                      // System.out.println("GroupAttribute missing from user: " + userName );
  
                  } else if (!servers.contains(baseNodeDN)) {//server not registered for user
                      logger.info(baseNodeDN + " missing from users' Groups. " );
                      //System.out.println(baseNodeDN + " missing from users' Groups. ");
  
                  } else {
  
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType);
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal);
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password);
  
                      ModificationItem[] mods = new ModificationItem[1];
                      mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(groupAttr, baseNodeDN));
  
                      rootCtx.modifyAttributes(userDN, mods);
  
                      //rootCtx.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, changes);
  
                      rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none");
                      logger.info(baseNodeDN + " removed from users' groups " );
                      //System.out.println(baseNodeDN + " removed from users' groups ");
  
                  }
  
              } else {
                  logger.info("User " + userName + " not in Directory.");
                  //System.out.println("User " + userName + " not in Directory.");
  
              }
              rootCtx.close();
  
          } catch (NamingException e) {
              logger.error("Problem removing user " + userName + e);
              //System.out.println("Problem removing user " + userName);
              //System.out.println(e.getMessage());
              //e.printStackTrace();
          }
  
      }
  
  
      public boolean contains(String name) {
          boolean found = false;
          String[] attrIDs = {membersAttr};
  
          try {
              Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
              if (members != null && members.contains(name)) {
                  found = true;
                  logger.info("Found " + name + " in mailGroup. " );
                  //System.out.println("Found " + name + " in mailGroup. ");
              }
          } catch (NamingException e) {
              logger.error("Problem finding user " + name + e);
              //System.out.println("Problem finding user " + name + " : " + e);
          }
          return found;
      }
  
  
      public boolean test(String name, Object attributes) {
          boolean result = false;
          boolean foundFlag = false;
          String testPassword = (String) attributes;
          String userDN = null;
  
          try {
              String[] returnAttrs = {identAttr, passwordAttr};
              SearchControls ctls = new SearchControls();
              ctls.setReturningAttributes(returnAttrs);
              ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
              String filter = mailAddressAttr + "=" + name + "@" + usersDomain;
  
              Hashtable env = new Hashtable();
              env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
              env.put(javax.naming.Context.PROVIDER_URL, rootURL);
              DirContext rootCtx = new InitialDirContext(env);
  
              NamingEnumeration enum  = rootCtx.search("", filter, ctls);
              if (enum.hasMore()) { // ie User is in Directory
                  SearchResult sr = (SearchResult)enum.next();
                  String userRDN = sr.getName();
                  userDN = userRDN +", " + rootNodeDN;
                  foundFlag = true;
                  //System.out.println("UserDN is : " + userDN);
              }
  
              rootCtx.close();
          } catch (Exception e) {
              logger.error("Problem finding user " + name + " for password test." +e);
              //e.getMessage();
              //e.printStackTrace();
          }
  
          if (foundFlag) { // ie User is in Directory
              Hashtable env2 = new Hashtable();
              env2.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
              env2.put(javax.naming.Context.PROVIDER_URL, rootURL);
              env2.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple");
              env2.put(javax.naming.Context.SECURITY_PRINCIPAL, userDN);
              env2.put(javax.naming.Context.SECURITY_CREDENTIALS, testPassword);
              //System.out.println("Creating initial context from " + baseURL);
  
              try {
                  DirContext testCtx = new InitialDirContext(env2);
                  result = true;
                  testCtx.close();
  
              } catch (AuthenticationException ae) {
                  result = false;
                  logger.error("Attempt to authenticate with incorrect password for " + name + " : " + ae );
                  //System.out.println("Attempt to authenticate with incorrect password for " + name + " : " + ae);
                  //System.out.println(ae.getMessage());
                  //ae.printStackTrace();
              } catch (Exception e) {
                  logger.error("Problem checking password for " + name + " : " + e );
                  //System.out.println("Problem checking password for " + name + " : " + e);
                  //System.out.println(e.getMessage());
                  //e.printStackTrace();
              }
          }
          return result;
  
      }
  
      public int countUsers() {
  
          String[] attrIDs = {membersAttr};
          int result = -1;
  
          try {
              Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr);
              if (members != null) {
                  result = members.size();
              } else {
                  result = 0;
              }
          } catch (NamingException e) {
              logger.error("Problem counting users: "  + e);
              //System.out.println("Problem counting users. ");
          }
          return result;
      }
  
      public String getDomains() {
          return usersDomain;
      }
  
      /**
       * Disposes of all open directory contexts.
       * Based on signature from interface Disposable in new Avalon
       */
      public void dispose() throws Exception {
          ctx.close();
      }
  
  }
  
  
  
  
  
  1.1                  jakarta-james/proposals/v1.3/java/org/apache/james/userrepository/UsersTownRepository.java
  
  Index: UsersTownRepository.java
  ===================================================================
  /*
   * Copyright (C) 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.userrepository;
  
  import com.workingdogs.town.*;
  import java.io.*;
  import java.util.*;
  import org.apache.avalon.framework.component.Component;
  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.logger.Loggable;
  import org.apache.james.services.User;
  import org.apache.james.services.UsersRepository;
  import org.apache.log.LogKit;
  import org.apache.log.Logger;
  
  /**
   * Implementation of a Repository to store users in database.
   * @version 1.0.0, 10/01/2000
   * @author  Ivan Seskar, Upside Technologies <se...@winlab.rutgers.edu>
   */
  public class UsersTownRepository implements UsersRepository, Loggable, Component, Configurable {
  
      //private String destination;
      //private String repositoryName;
  
      private String conndefinition;
      private String tableName;
  
      //  System defined logger funtion
      //private ComponentManager comp;
      private Logger logger;
  
      // Constructor - empty
      public UsersTownRepository() {
      }
  
      public void setLogger(final Logger a_Logger) {
          logger = a_Logger;
      }
  
      public void configure(Configuration conf) throws ConfigurationException {
          //  destination = conf.getChild("destination").getAttribute("URL");
          //  repositoryName = destination.substring(destination.indexOf("//") + 2);
          conndefinition= conf.getChild("conn").getValue();
          tableName = conf.getChild("table").getValue("Users");
  
      }
  
      // Methods from interface Repository
  
      public boolean addUser(User user) {
  	return false;
      }
  
      public  User getUserByName(String name) {
  	return new DefaultUser("dummy", "dummy");
      }
  
      public User getUserByNameCaseInsensitive(String name) {
  	return getUserByName(name);
      }
  
      public boolean containsCaseInsensitive(String name) {
          return contains(name);
      }
  
      public String getRealName(String name) {
  	return null;
      }
  
      public boolean updateUser(User user) {
  	return false;
      }
  
      public boolean test(String name, String password) {
  	return false;
      }
  
      public synchronized void addUser(String strUserName, Object attributes) {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              MRUser.setWhere("username = '" + strUserName+"'");
              Record user = null;
              if (MRUser.size() == 0) {
                  // file://Add new user
                  user = MRUser.addRecord();
                  user.setValue("username", strUserName);
                  user.setValue("password", attributes.toString());
                  user.save();
              } else {
                  // file://User already exists: reject add
                  logger.warn("User "+strUserName+" already exists.");
              }
          } catch (Exception e) {
              e.printStackTrace();
              throw new RuntimeException("Exception caught while storing user: " + e);
          }
      }
  
      public synchronized Object getAttributes(String strUserName) {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              MRUser.setWhere("username = '" + strUserName+"'");
              if (MRUser.size() == 0) {
                  logger.warn("User "+strUserName+" could not be found while fetching password.");
                  return(null);
              } else {
                  Record user = MRUser.getRecord(0);
                  return ((Object) user.getAsString("Password"));
              }
          } catch (Exception e) {
              throw new RuntimeException("Exception while retrieving password: " + e.getMessage());
          }
      }
  
      public synchronized void removeUser(String strUserName) {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              MRUser.setWhere("username = '" + strUserName + "'");
              if (MRUser.size() == 0) {
                  // file://User doesn't exists: reject delete
                  logger.warn("User: " + strUserName + " does not exist.  Cannot delete");
              } else {
                  Record user = MRUser.getRecord(0);
                  user.markToBeDeleted();
                  user.save();
              }
          } catch (Exception e) {
              throw new RuntimeException("Exception while deleting user: " + e.getMessage());
          }
      }
  
      public boolean contains(String strUserName) {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              MRUser.setWhere("username = '" + strUserName + "'");
              if (MRUser.size() > 0) {
                  return true;   // User exists
              } else {
                  return false;  // User does not exist
              }
          } catch (Exception e) {
              throw new RuntimeException("Exception while retrieving user: " + e.getMessage());
          }
      }
  
      public boolean test(String strUserName, Object attributes) {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              MRUser.setWhere("username = '" + strUserName + "'");
              if (MRUser.size() > 0) {
                  // UserName exists - check if the password is OK
                  Record user = MRUser.getRecord(0);
                  return(user.getAsString("Password").equals(attributes.toString()));
              } else {
                  // file://UserName does not exist
                  logger.warn("User "+strUserName+" doesn't exist");
                  return(false);
              }
          } catch (Exception e) {
              e.printStackTrace();
              throw new RuntimeException("Exception caught while testing UserName: " + e.getMessage());
          }
      }
  
      public int countUsers() {
          try {
              TableDataSet MRUser = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              int nSize = MRUser.size();
              return (int) nSize;
          } catch (Exception e) {
              e.printStackTrace();
              throw new RuntimeException("Exception caught while testing UserName: " + e.getMessage());
          }
      }
  
      public Iterator list() {
          List list = new ArrayList();
  
          try {
              TableDataSet users = new TableDataSet(ConnDefinition.getInstance(conndefinition), tableName);
              for (int i = 0; i < users.size(); i++) {
                  list.add(users.getRecord(i).getAsString("username"));
              }
          } catch (Exception e) {
              logger.error("Problem listing mailboxes. " + e );
              e.printStackTrace();
              throw new RuntimeException("Exception while listing users: " + e.getMessage());
          }
          return list.iterator();
      }
  }
  
  
  

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