james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pgoldst...@apache.org
Subject cvs commit: jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands AppendCommand.java CommandFetch.java FileMailbox.java FileStoreHighestUID.java HighestUID.java
Date Sat, 14 Sep 2002 08:35:21 GMT
pgoldstein    2002/09/14 01:35:21

  Modified:    proposals/imap/java/org/apache/james/imapserver
                        CommandFetch.java FileMailbox.java
               proposals/imap/java/org/apache/james/imapserver/commands
                        AppendCommand.java
  Added:       proposals/imap/java/org/apache/james/imapserver
                        FileStoreHighestUID.java HighestUID.java
  Removed:     proposals/imap/java/org/apache/james/imapserver/commands
                        CommandFetch.java FileMailbox.java
                        FileStoreHighestUID.java HighestUID.java
  Log:
  Latest changes to IMAP.  Thanks to Beat Christen, Sascha Kulawik.
  
  Revision  Changes    Path
  1.6       +2 -3      jakarta-james/proposals/imap/java/org/apache/james/imapserver/CommandFetch.java
  
  Index: CommandFetch.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap/java/org/apache/james/imapserver/CommandFetch.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- CommandFetch.java	9 Aug 2002 16:48:05 -0000	1.5
  +++ CommandFetch.java	14 Sep 2002 08:35:20 -0000	1.6
  @@ -152,7 +152,6 @@
           }
   
           fetchAttrs = convertMacroCommands( fetchAttrs );
  -        System.out.println("Starting TRY");
           try {
               for (int i = 0; i < set.size(); i++) {
                   Integer uidObject = null;
  @@ -179,10 +178,10 @@
                       if (arg.equalsIgnoreCase("FLAGS")) {
                           if (flags == null) {
                               if (useUIDs) {
  -                                System.out.println("TRIING UIDFLAGS"+uid);
  +                                System.out.println("TRYING UIDFLAGS"+uid);
                                   flags = currentMailbox.getFlagsUID(uid, user);
                               } else {
  -                                System.out.println("TRIING MSNFLAGS"+msn);
  +                                System.out.println("TRYING MSNFLAGS"+msn);
                                   flags = currentMailbox.getFlags(msn, user);
                               }
                           }
  
  
  
  1.6       +1863 -1863jakarta-james/proposals/imap/java/org/apache/james/imapserver/FileMailbox.java
  
  Index: FileMailbox.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap/java/org/apache/james/imapserver/FileMailbox.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- FileMailbox.java	9 Aug 2002 16:48:05 -0000	1.5
  +++ FileMailbox.java	14 Sep 2002 08:35:20 -0000	1.6
  @@ -1,1863 +1,1863 @@
  -/*
  - * 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.imapserver;
  -
  -import org.apache.avalon.cornerstone.services.store.ObjectRepository;
  -import org.apache.avalon.cornerstone.services.store.Store;
  -import org.apache.avalon.framework.component.ComponentManager;
  -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.logger.AbstractLogEnabled;
  -import org.apache.avalon.phoenix.BlockContext;
  -import org.apache.james.AccessControlException;
  -import org.apache.james.AuthorizationException;
  -import org.apache.james.core.MimeMessageWrapper;
  -import org.apache.james.services.UsersRepository;
  -import org.apache.james.services.UsersStore;
  -import org.apache.james.util.Assert;
  -
  -import javax.mail.internet.InternetHeaders;
  -import javax.mail.internet.MimeMessage;
  -import javax.mail.MessagingException;
  -import java.io.*;
  -import java.util.*;
  -
  -/**
  - * Object representing an IMAP4rev1 mailbox (folder) on a local file system.
  - * The mailbox contains messages, message attributes and an access control
  - * list.
  - *
  - * <p> from Interface Mailbox
  - *
  - * <p>Mailbox Related Flags (rfc2060 name attributes)
  - * <br>    \Noinferiors   It is not possible for any child levels of hierarchy
  - * to exist under this name; no child levels exist now and none can be created
  - * in the future.
  - * <br>    \Noselect      It is not possible to use this name as a selectable
  - * mailbox.
  - * <br>    \Marked        The mailbox has been marked "interesting" by the
  - * server; the mailbox probably contains messages that have been added since
  - * the last time the mailbox was selected.
  - * <br>      \Unmarked      The mailbox does not contain any additional
  - * messages since the last time the mailbox was selected.
  - *
  - * <p>Message related flags.
  - * <br>The flags allowed per message are specific to each mailbox.
  - * <br>The minimum list (rfc2060 system flags) is:
  - * <br> \Seen       Message has been read
  - * <br> \Answered   Message has been answered
  - * <br> \Flagged    Message is "flagged" for urgent/special attention
  - * <br> \Deleted    Message is "deleted" for removal by later EXPUNGE
  - * <br> \Draft      Message has not completed composition (marked as a draft).
  - * <br> \Recent     Message is "recently" arrived in this mailbox.  This
  - * session is the first session to have been notified about this message;
  - * subsequent sessions will not see \Recent set for this message.  This flag
  - * can not be altered by the client.
  - *  <br>            If it is not possible to determine whether or not this
  - * session is the first session to be notified about a message, then that
  - * message SHOULD be considered recent.
  - *
  - * <p> From interface ACL </p>
  - *
  - * The standard rights in RFC2086 are:
  - * <br>l - lookup (mailbox is visible to LIST/LSUB commands)
  - * <br>r - read (SELECT the mailbox, perform CHECK, FETCH, PARTIAL, SEARCH,
  - * COPY from mailbox)
  - * <br>s - keep seen/unseen information across sessions (STORE SEEN flag)
  - * <br>w - write (STORE flags other than SEEN and DELETED)
  - * <br>i - insert (perform APPEND, COPY into mailbox)
  - * <br>p - post (send mail to submission address for mailbox, not enforced by
  - * IMAP4 itself)
  - * <br>c - create (CREATE new sub-mailboxes in any implementation-defined
  - * hierarchy)
  - * <br>d - delete (STORE DELETED flag, perform EXPUNGE)
  - * <br>a - administer (perform SETACL)
  - *
  - * <p> Serialization. Not all fields are serialized. Dispose() must be called to
  - * write serialized fiels to disc before finishing with this object.
  - *
  - * <p> Deserialization. On recover from disc, configure, compose,
  - * contextualize and reInit must be called before object is ready for use.
  - *
  - * Reference: RFC 2060
  - * @author <a href="mailto:sascha@kulawik.de">Sascha Kulawik</a>
  - * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
  - * @version 0.2 on 04 Aug 2002
  - */
  -public class FileMailbox
  -    extends AbstractLogEnabled
  -    implements ACLMailbox, Serializable {
  -
  -    public static final String MAILBOX_FILE_NAME = "mailbox.mbr";
  -
  -    private static final String MESSAGE_EXTENSION = ".msg";
  -    private static final String ATTRIBUTES_EXTENSION = ".att";
  -    private static final String FLAGS_EXTENSION = ".flags";
  -
  -    private static final int NUMBER_OF_RIGHTS = 9;
  -    // Map string identities to boolean[NUMBER_OF_RIGHTS] arrays of rights
  -    //The rights are, in order: l,r,s,w,i,p,c,d,a
  -    private static final int LOOKUP = 0;
  -    private static final int READ = 1;
  -    private static final int KEEP_SEEN = 2;
  -    private static final int WRITE = 3;
  -    private static final int INSERT = 4;
  -    private static final int POST = 5;
  -    private static final int CREATE = 6;
  -    private static final int DELETE = 7;
  -    private static final int ADMIN = 8;
  -    private static final boolean[] NO_RIGHTS
  -        = {false, false, false, false, false, false, false, false, false};
  -    private static final boolean[] ALL_RIGHTS
  -        = {true, true, true, true, true, true, true, true, true};
  -    private static final String DENY_ACCESS = "Access denied by ACL";
  -    private static final String DENY_AUTH = "Action not authorized for: ";
  -    private static final String OPTIONAL_RIGHTS = "l r s w i p c d a";
  -    private static final char[] DELETE_MODS
  -        = {'-', 'l', 'r', 's', 'w', 'i', 'p', 'c', 'd', 'a'};
  -
  -    /* Transient fields - reInit must be called on recover from disc. */
  -    private transient BlockContext context;
  -    private transient Configuration conf;
  -    private transient ComponentManager compMgr;
  -    private transient UsersRepository localUsers;
  -    private transient HashSet listeners;
  -
  -    /* Serialized fileds */
  -    private String path; // does not end with File.separator
  -    private String rootPath; // does not end with File.separator
  -    private File directory ;
  -    private String owner;
  -    private String absoluteName;
  -    private Map acl;
  -    private String name;
  -    private int uidValidity;
  -    private int highestUID;
  -    private int mailboxSize; // octets
  -    private boolean inferiorsAllowed;
  -    private boolean marked;
  -    private boolean notSelectableByAnyone;
  -
  -    // The message sequence number of a msg is its index in List sequence + 1
  -    private List sequence; //List of UIDs of messages in mailbox
  -
  -    // Set of UIDs of messages with recent flag set
  -    private Set recentMessages;
  -
  -    // Set of UIDs of messages with delete flag set
  -    private Set messagesForDeletion;
  -
  -    //map of user String to Integer uid, 0 for no unseen messages
  -    private Map oldestUnseenMessage;
  -
  -    // Set of subscribed users.
  -    private Set subscribedUsers = new HashSet(1000);
  -
  -    public void configure(Configuration conf) throws ConfigurationException {
  -        this.conf = conf;
  -    }
  -
  -    public void contextualize(Context context) {
  -        this.context = (BlockContext)context;
  -    }
  -
  -    public void compose(ComponentManager comp) {
  -        compMgr = comp;
  -    }
  -
  -    public void prepareMailbox(String user, String absName, String initialAdminUser, int uidValidity ) {
  -        Assert.isTrue( Assert.ON && user != null && user.length() > 0 );
  -        owner = user;
  -
  -        Assert.isTrue( Assert.ON && absName != null && (absName.length() > 0));
  -        absoluteName = absName;
  -
  -        Assert.isTrue( Assert.ON && initialAdminUser != null && initialAdminUser.length() > 0 );
  -        acl = new HashMap(7);
  -        acl.put(initialAdminUser, ALL_RIGHTS);
  -
  -        Assert.isTrue( Assert.ON && uidValidity > 0 );
  -        this.uidValidity = uidValidity;
  -    }
  -
  -    public void initialize() throws Exception {
  -        java.util.Date dt = new java.util.Date();
  -        
  -        highestUID = (int) dt.getTime();
  -        
  -        mailboxSize = 0;
  -        inferiorsAllowed = true;
  -        marked = false;
  -        notSelectableByAnyone = false;
  -        oldestUnseenMessage = new HashMap();
  -        listeners = new HashSet();
  -        sequence = new ArrayList();
  -        recentMessages = new HashSet();
  -        messagesForDeletion = new HashSet();
  -        getLogger().info("FileMailbox init for " + absoluteName);
  -        UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
  -        localUsers = usersStore.getRepository("LocalUsers");
  -        rootPath = conf.getChild( "mailboxRepository" ).getValue();
  -        if (!rootPath.endsWith(File.separator)) {
  -            rootPath = rootPath + File.separator;
  -        }
  -        
  -        path = getPath( absoluteName, owner, rootPath );
  -        name = absoluteName.substring(absoluteName.lastIndexOf( JamesHost.HIERARCHY_SEPARATOR ) + 1);
  -        if (name.equals(owner)) {
  -            name = "";
  -        }
  -        //Check for writable directory
  -        getLogger().info("MailboxDir " + path);
  -        System.out.println("MailboxDir TO WRITE TO " + path);
  -        File mailboxDir = new File(path);
  -        if (mailboxDir.exists()) {
  -            throw new RuntimeException("Error: Attempt to overwrite mailbox directory at " + path);
  -        } else if (! mailboxDir.mkdir()){
  -            throw new RuntimeException("Error: Cannot create mailbox directory at " + path);
  -        } else if (!mailboxDir.canWrite()) {
  -            throw new RuntimeException("Error: Cannot write to directory at " + path);
  -        }
  -        writeMailbox();
  -        getLogger().info("FileMailbox init complete: " + absoluteName);
  -    }
  -
  -
  -
  -    /**
  -     * Return the file-system path to a given absoluteName mailbox.
  -     *
  -     * @param absoluteName the user-independent name of the mailbox
  -     * @param owner string name of owner of mailbox
  -     */
  -    private String getPath( String absoluteName, String owner, String rootPath )
  -    {
  -        Assert.isTrue( Assert.ON &&
  -                       absoluteName.startsWith( JamesHost.NAMESPACE_TOKEN ) );
  -
  -        // Remove the leading '#' and replace Hierarchy separators with file separators.
  -        String filePath = absoluteName.substring( JamesHost.NAMESPACE_TOKEN.length() );
  -        filePath = filePath.replace( JamesHost.HIERARCHY_SEPARATOR_CHAR, File.separatorChar );
  -        return rootPath + filePath;
  -    }
  -    
  -    /**
  -     * Re-initialises mailbox after reading from file-system. Cannot assume that this is the same instance of James that wrote it.
  -     *
  -     * <p> Contract is that re-init must be called after configure, contextualize, compose.
  -     */
  -    public void reinitialize() throws Exception {
  -        listeners = new HashSet();
  -        getLogger().info("FileMailbox reInit for " + absoluteName);
  -        UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
  -        localUsers = usersStore.getRepository("LocalUsers");
  -        rootPath
  -            = conf.getChild("mailboxRepository").getValue();
  -        if (!rootPath.endsWith(File.separator)) {
  -            rootPath = rootPath + File.separator;
  -        }
  -        path = getPath( absoluteName, owner, rootPath );
  -    }
  -
  -    /**
  -     * Call when host has finished with a mailbox.
  -     * This is really a stop rather than destroy.
  -     * Writes current mailbox object to disc.
  -     */
  -    public void dispose() {
  -        writeMailbox();
  -        getLogger().info("FileMailbox object destroyed: " + absoluteName);
  -    }
  -
  -    /**
  -     * Permanently deletes the mailbox.
  -     */
  -    public void removeMailbox()
  -    {
  -        // First delete the mailbox file
  -        path = getPath( absoluteName, owner, rootPath );
  -        String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
  -        File mailboxRecord = new File( mailboxRecordFile );
  -        Assert.isTrue( Assert.ON &&
  -                       mailboxRecord.exists() &&
  -                       mailboxRecord.isFile() );
  -        mailboxRecord.delete();
  -
  -        // Check for empty directory before deleting.
  -        File mailboxDir = new File(path);
  -        Assert.isTrue( Assert.ON &&
  -                       mailboxDir.exists() );
  -        Assert.isTrue( Assert.ON &&
  -                       mailboxDir.isDirectory() );
  -        Assert.isTrue( Assert.ON &&
  -                       mailboxDir.list().length == 0 );
  -        mailboxDir.delete();
  -    }
  -    
  -    /**
  -     * Renames this Mailbox.
  -     * @param usernmae The Username who calles this Command.
  -     * @param newmailboxname The new name for this Mailbox.
  -     * @returns true if everythink was sucessfully, else false.
  -     * @throws MailboxException if mailbox does not exist locally.
  -     * @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
  -     */
  -    public boolean renameMailbox(String username, String newmailboxname) throws MailboxException, AuthorizationException {
  -        try {
  -            path = getPath( absoluteName, owner, rootPath );
  -            
  -            StringTokenizer strt = new StringTokenizer(newmailboxname,".");
  -            String lastnameofmailbox="";
  -            while(strt.hasMoreTokens())
  -                lastnameofmailbox=strt.nextToken();
  -            
  -            File fle = new File(this.path);
  -            fle.renameTo(new File(fle.getParent(), lastnameofmailbox));
  -            
  -            this.path=fle.getParent()+File.separator+lastnameofmailbox;
  -            this.absoluteName = this.absoluteName.substring(0,this.absoluteName.length()-this.name.length())+lastnameofmailbox;
  -            this.name=lastnameofmailbox;
  -            
  -            
  -            this.writeMailbox();
  -            return true;
  -        }catch(Exception e) {
  -            e.printStackTrace();
  -            return false;
  -        }
  -    }
  -    
  -    /**
  -     * THIS IS AN INTERIM SOLUTION !
  -     *
  -     * @param usernmae The Username who calles this Command.
  -     * @param oldabsolutename The old name of the parent.
  -     * @param newabsolutename The new name for the parent.
  -     * @returns true if everythink was sucessfully, else false.
  -     * @throws MailboxException if mailbox does not exist locally.
  -     * @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
  -     */
  -    public boolean renameSubMailbox(String username, String oldabsolutename, String newname) {
  -        try {
  -            System.out.println("renameSubMailbox ABSOLUTE NAME "+this.absoluteName);
  -            StringTokenizer strt = new StringTokenizer(oldabsolutename,".");
  -            StringBuffer strbuff = new StringBuffer();
  -            
  -            for(int i=0;i<strt.countTokens();i++){
  -                String token = strt.nextToken();
  -                if(strbuff.length()>0) strbuff.append(".");
  -                strbuff.append(token);
  -            }
  -            strbuff.append(".");
  -            strbuff.append(newname);
  -
  -            this.absoluteName = strbuff.toString()+this.absoluteName.substring(oldabsolutename.length());
  -            System.out.println("renameSubMailbox TOKEN CONVERTED: "+this.absoluteName);            
  -            this.writeMailbox();
  -            return true;
  -        }catch(Exception e) {
  -            e.printStackTrace();
  -            return false;
  -        }
  -    }
  -    
  -    /**
  -     * Returns true once this Mailbox has been checkpointed.
  -     * This implementation just writes its mailbox record to disc.  Unless something is
  -     * broken all messages added, amended or removed from this mailbox will have been
  -     * handled by this object.
  -     * <br> This implementation always returns true.
  -     *
  -     * @returns true
  -     */
  -    public synchronized  boolean checkpoint() {
  -        writeMailbox();
  -        getLogger().info("FileMailbox: " + absoluteName + " checkpointed.");
  -        return true;
  -    }
  -
  -    /**
  -     * Remove \Recent flag from all messages in mailbox. Should be called
  -     * whenever a user session finishes.
  -     */
  -    public synchronized void unsetRecent() {
  -        Iterator it = recentMessages.iterator();
  -        while(it.hasNext()) {
  -            Integer uidObj =(Integer)it.next();
  -            int uid = uidObj.intValue();
  -            Flags flags = readFlags(uid);
  -            if (flags != null) {
  -                flags.setRecent(false);
  -                writeFlags(uid, flags);
  -            }
  -        }
  -        recentMessages.clear();
  -    }
  -
  -
  -    // Methods that don't involve the ACL ------------------
  -
  -    /**
  -     * Returns name of this mailbox relative to its parent in the mailbox
  -     * hierarchy.
  -     * Example: 'NewIdeas'
  -     *
  -     * @returns String name of mailbox relative to its immeadiate parent in
  -     * the mailbox hierarchy.
  -     */
  -    public String getName() {
  -        return name;
  -    }
  -
  -    /**
  -     * Returns absolute, that is user-independent, hierarchical name of
  -     * mailbox (including namespace)
  -     * Example: '#mail.fred.flintstone.apache.James.NewIdeas'
  -     *
  -     * @returns String name of mailbox in absolute form
  -     */
  -    public String getAbsoluteName() {
  -        return absoluteName;
  -    }
  -
  -    /** Returns namespace starting with namespace token.
  -     * Example: '#mail'
  -     *
  -     * @returns String containing user-independent namespace of this mailbox.
  -     */
  -    //  public String getNamespace();
  -
  -    /** Returns true if the argument is the relative or absolute name of
  -     * this mailbox
  -     *
  -     * @param name possible name for this Mailbox
  -     * @returns true if name matches either getName() or getAbsoluteName()
  -     */
  -    public boolean matchesName(String testName) {
  -        return (name.equals(testName) || name.equals(absoluteName));
  -    }
  -
  -    /**
  -     * Returns the current unique id validity value of this mailbox.
  -     *
  -     * @returns int current 32 bit unique id validity value of this mailbox
  -     */
  -    public int getUIDValidity() {
  -        return uidValidity;
  -    }
  -
  -    /**
  -     * Returns the 32 bit uid available for the next message.
  -     *
  -     * @returns int the next UID that would be used.
  -     */
  -    public int getNextUID() {
  -        return highestUID + 1;
  -    }
  -
  -    /**
  -     * Returns mailbox size in octets. Should only include actual messages
  -     * and not any implementation-specific data, such as message attributes.
  -     *
  -     * @returns int mailbox size in octets
  -     */
  -    public synchronized int getMailboxSize() {
  -        return mailboxSize;
  -    }
  -
  -    /**
  -     * Indicates if child folders may be created. It does not indicate which
  -     * users can create child folders.
  -     *
  -     * @returns boolean TRUE if inferiors aree allowed
  -     */
  -    public boolean getInferiorsAllowed() {
  -        return inferiorsAllowed;
  -    }
  -
  -    /**
  -     * Indicates that messages have been added since this mailbox was last
  -     * selected by any user.
  -     *
  -     * @returns boolean TRUE if new messages since any user last selected
  -     * mailbox
  -     */
  -    public  synchronized  boolean isMarked() {
  -        return marked;
  -    }
  -
  -    /**
  -     * Returns all flags supported by this mailbox.
  -     * e.g. \Answered \Deleted
  -     *
  -     * @returns String a space seperated list of message flags which are
  -     * supported by this mailbox.
  -     */
  -    public String getSupportedFlags() {
  -        return SYSTEM_FLAGS;
  -    }
  -    /**
  -     * Indicates no of messages with \Recent flag set
  -     *
  -     * @returns int no of messages with \Recent flag set
  -     */
  -    public  synchronized  int getRecent() {
  -        return recentMessages.size();
  -    }
  -
  -    /**
  -     * Indicates the oldest unseen message for the specified user.
  -     *
  -     * @returns int Message Sequence Number of first message without \Seen
  -     * flag set for this User.  0 means no unseen messages in this mailbox.
  -     */
  -    public  synchronized  int getOldestUnseen(String user) {
  -        int response = 0;
  -        if (oldestUnseenMessage.containsKey(user)) {
  -            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  -            if (! (uidObj.intValue() == 0)) {
  -                response = sequence.indexOf(uidObj) + 1;
  -            }
  -        } else {
  -            if (sequence.size() > 0) {
  -                response = 1;
  -                oldestUnseenMessage.put(user, (Integer)sequence.get(0));
  -            } else {
  -                oldestUnseenMessage.put(user, (new Integer(0)));
  -            }
  -        }
  -        return response;
  -    }
  -
  -    /**
  -     * Indicates number of messages in folder
  -     *
  -     * @returns int number of messages
  -     */
  -    public  synchronized  int getExists() {
  -        return sequence.size();
  -    }
  -
  -    /**
  -     * Indicates the number of  unseen messages for the specified user.
  -     *
  -     * @returns int number of messages without \Seen flag set for this User.
  -     */
  -    public int getUnseen(String user) {
  -        if (oldestUnseenMessage.containsKey(user)) {
  -            int response = 0; //indicates no unseen messages
  -            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  -            int oldUID = uidObj.intValue();
  -            if (oldUID != 0) {
  -                ListIterator lit
  -                    = sequence.listIterator(sequence.indexOf(uidObj));
  -                while (lit.hasNext() ) {
  -                    int uid = ((Integer)lit.next()).intValue();
  -                    Flags flags = readFlags(uid);
  -                    if (!flags.isSeen(user)) {
  -                        response ++;
  -                    }
  -                }
  -            }
  -            return response;
  -        } else { // user has never selected mailbox
  -            return sequence.size();
  -        }
  -    }
  -
  -    /** Mailbox Events are used to inform registered listeners of events in the Mailbox.
  -     * E.g. if mail is delivered to an Inbox or if another user appends/ deletes a message.
  -     */
  -    public synchronized void addMailboxEventListener(MailboxEventListener mel) {
  -        listeners.add(mel);
  -    }
  -
  -
  -    public synchronized void removeMailboxEventListener(MailboxEventListener mel) {
  -        listeners.remove(mel);
  -    }
  -
  -    /**
  -     * Mark this mailbox as not selectable by anyone.
  -     * Example folders at the roots of hierarchies, e. #mail for each user.
  -     *
  -     * @param state true if folder is not selectable by anyone
  -     */
  -    public void setNotSelectableByAnyone(boolean state) {
  -        notSelectableByAnyone = state;
  -    }
  -
  -    public boolean isNotSelectableByAnyone() {
  -        return notSelectableByAnyone;
  -    }
  -
  -    // Methods for the embedded ACL ------------------------
  -
  -    /**
  -     * Store access rights for a given identity.
  -     * The setter is the user setting the rights, the identifier is the user
  -     * whose rights are affected.
  -     * The setter and identifier arguments must be non-null and non-empty.
  -     * The modification argument must be non-null and follow the syntax of the
  -     * third argument to a SETACL command.
  -     * If the modification argument is an empty string, that identifier is
  -     * removed from the ACL, if currently present.
  -     *
  -     * @param setter String representing user attempting to set rights, must
  -     * be non-null and non-empty
  -     * @param identity String representing user whose rights are being set,
  -     * must be non-null and non-empty
  -     * @param modification String representing the change in rights, following
  -     * the syntax specified in rfc 2086. Note a blank string means delete all
  -     * rights for given identity.
  -     * @returns true if requested modification succeeded. A return value of
  -     * false means an error other than an AccessControlException or
  -     * AuthorizationException.
  -     * @throws AccessControlException if setter does not have lookup rights for
  -     * this mailbox (ie they should not know this mailbox exists).
  -     * @throws AuthorizationException if specified setter does not have the
  -     * administer right (ie the right to write ACL rights), or if the result
  -     * of this method would leave no identities with admin rights.
  -     */
  -    public boolean setRights(String setter, String identifier,
  -                             String modification)
  -        throws AccessControlException, AuthorizationException {
  -
  -        boolean[] settersRights = (boolean[]) acl.get(setter);
  -        if (settersRights == null
  -            || (settersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        } else if (settersRights[ADMIN] == false) {
  -            throw new AuthorizationException(DENY_AUTH + setter);
  -        }
  -        boolean[] existingRights = (boolean[]) acl.get(identifier);
  -        char[] mods = modification.toCharArray();
  -        if (mods.length == 0) { // means delete all
  -            mods = DELETE_MODS;
  -        }
  -        if(existingRights == null) {
  -            if ( mods[0] == REMOVE_RIGHTS ) {
  -                return false;
  -            } else {
  -                existingRights = new boolean[NUMBER_OF_RIGHTS];
  -                System.arraycopy(NO_RIGHTS, 0, existingRights, 0,
  -                                 NUMBER_OF_RIGHTS);
  -            }
  -        }
  -
  -        boolean change;
  -        boolean[] rights = new boolean[NUMBER_OF_RIGHTS];
  -
  -        if (mods[0] == ADD_RIGHTS) {
  -            change = true;
  -            System.arraycopy(existingRights, 0, rights, 0,
  -                             NUMBER_OF_RIGHTS);
  -        } else if (mods[0] == REMOVE_RIGHTS) {
  -            change = false;
  -            System.arraycopy(existingRights, 0, rights, 0,
  -                             NUMBER_OF_RIGHTS);
  -        } else {                                             // means replace
  -            System.arraycopy(NO_RIGHTS, 0, rights, 0,
  -                             NUMBER_OF_RIGHTS);
  -            char[] new_mods = new char[mods.length + 1];
  -            System.arraycopy(mods, 0, new_mods, 1, mods.length);
  -            mods = new_mods;
  -            change = true;
  -        }
  -
  -        for (int i=1; i <mods.length; i++) {
  -            switch(mods[i]) {
  -            case LOOKUP_RIGHTS: rights[LOOKUP] = change;
  -                break;
  -            case READ_RIGHTS: rights[READ] = change;
  -                break;
  -            case KEEP_SEEN_RIGHTS: rights[KEEP_SEEN] = change;
  -                break;
  -            case WRITE_RIGHTS: rights[WRITE] = change;
  -                break;
  -            case INSERT_RIGHTS: rights[INSERT] = change;
  -                break;
  -            case POST_RIGHTS: rights[POST] = change;
  -                break;
  -            case CREATE_RIGHTS: rights[CREATE] = change;
  -                break;
  -            case DELETE_RIGHTS: rights[DELETE] = change;
  -                break;
  -            case ADMIN_RIGHTS: rights[ADMIN] = change;
  -                break;
  -            default: return false;
  -            }
  -        }
  -
  -        //  All rights above lookup require lookup
  -        if(rights[LOOKUP] == false  &&  !Arrays.equals(rights, NO_RIGHTS)) {
  -            return false;
  -        }
  -        // Each right requires all the rights before it.
  -        int count = 0;
  -        for (int i=1; i< NUMBER_OF_RIGHTS; i++) {
  -            if(rights[i-1] ^ rights[i]) {
  -                count++;
  -            }
  -        }
  -        switch (count) {
  -        case 0:                              // now Admin or deleted
  -            if (rights[ADMIN]) {
  -                acl.put(identifier, rights);
  -                break;
  -            } else {
  -                if (otherAdmin(identifier)) {
  -                    acl.remove(identifier);
  -                    break;
  -                } else {
  -                    return false;
  -                }
  -            }
  -        case 2:              // not allowed
  -            return false;
  -        case 1:             // not Admin, check there remains an Admin
  -            // Iterator namesIt = acl.keySet().iterator();
  -            //boolean otherAdmin = false;
  -            //while(namesIt.hasNext() && !otherAdmin) {
  -            //String name = (String)namesIt.next();
  -            //if (name != identifier) {
  -            //    boolean[] otherRights = (boolean[]) acl.get(name);
  -            //        otherAdmin = otherRights[ADMIN];
  -            //}
  -            //}
  -            if (otherAdmin(identifier)) {
  -                acl.put(identifier, rights);
  -                break;
  -            } else {
  -                return false;
  -            }
  -        default:             // not allowed
  -            return false;
  -        }
  -        writeMailbox();
  -        return true;
  -    }
  -
  -    /**
  -     * Check there is a person other than identifier who has Admin rights.
  -     */
  -    private boolean otherAdmin(String identifier) {
  -        Iterator namesIt = acl.keySet().iterator();
  -        boolean result = false;
  -        while(namesIt.hasNext() && !result) {
  -            String name = (String)namesIt.next();
  -            if (!name.equals(identifier)) {
  -                boolean[] otherRights = (boolean[]) acl.get(name);
  -                result = otherRights[ADMIN];
  -            }
  -        }
  -        return result;
  -    }
  -
  -    /**
  -     * Retrieve access rights for a specific identity.
  -     *
  -     * @param getter String representing user attempting to get the rights,
  -     * must be non-null and non-empty
  -     * @param identity String representing user whose rights are being got,
  -     * must be non-null and non-empty
  -     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  -     * rights in this mailbox.
  -     * @throws AccessControlException if getter does not have lookup rights for
  -     * this mailbox (ie they should not know this mailbox exists).
  -     * @throws AuthorizationException if implementation does not wish to expose
  -     * ACL for this identity to this getter.
  -     */
  -    public String getRights(String getter, String identity)
  -        throws AccessControlException, AuthorizationException {
  -        boolean[] gettersRights = (boolean[])  acl.get(getter);
  -        if (gettersRights == null
  -            || (gettersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  -            throw new AuthorizationException(DENY_AUTH + getter);
  -        }
  -        boolean[] rights = (boolean[]) acl.get(identity);
  -        if (rights == null) {
  -            return null;
  -        } else {
  -            StringBuffer buf = new StringBuffer(NUMBER_OF_RIGHTS);
  -            for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
  -                if (rights[i]) {
  -                    buf.append(RIGHTS[i]);
  -                }
  -            }
  -            return buf.toString();
  -        }
  -    }
  -
  -    /**
  -     * Retrieves a String of one or more <identity space rights> who have
  -     * rights in this ACL
  -     *
  -     * @param getter String representing user attempting to get the rights,
  -     * must be non-null and non-empty
  -     * @returns String of rights sets usingrfc2086 syntax
  -     * @throws AccessControlException if getter does not have lookup rights for
  -     * this mailbox (ie they should not know this mailbox exists).
  -     * @throws AuthorizationException if implementation does not wish to expose
  -     * ACL to this getter.
  -     */
  -    public String getAllRights(String getter)
  -        throws AccessControlException, AuthorizationException {
  -        boolean[] gettersRights = (boolean[]) acl.get(getter);
  -        if (gettersRights == null
  -            || (gettersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        } else if ( gettersRights[ADMIN] == false) {
  -            throw new AuthorizationException(DENY_AUTH + getter);
  -        }
  -        Iterator namesIt = acl.keySet().iterator();
  -        StringBuffer response = new StringBuffer(20*acl.size());
  -        while(namesIt.hasNext()) {
  -            String name = (String)namesIt.next();
  -            response.append("<" + name + " ");
  -            boolean[] rights = (boolean[]) acl.get(name);
  -            for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
  -                if (rights[i]) {
  -                    response.append(RIGHTS[i]);
  -                }
  -            }
  -            response.append("> ");
  -        }
  -
  -        return response.toString();
  -    }
  -
  -    /**
  -     * Retrieve rights which will always be granted to the specified identity.
  -     *
  -     * @param getter String representing user attempting to get the rights,
  -     * must be non-null and non-empty
  -     * @param identity String representing user whose rights are being got,
  -     * must be non-null and non-empty
  -     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  -     * guaranteed rights in this mailbox.
  -     * @throws AccessControlException if getter does not have lookup rights for
  -     * this mailbox (ie they should not know this mailbox exists).
  -     * @throws AuthorizationException if implementation does not wish to expose
  -     * ACL for this identity to this getter.
  -     */
  -    public String getRequiredRights(String getter, String identity)
  -        throws AccessControlException, AuthorizationException {
  -        boolean[] gettersRights = (boolean[]) acl.get(getter);
  -        if (gettersRights == null
  -            || (gettersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  -            throw new AuthorizationException(DENY_AUTH + getter);
  -        }
  -
  -        return "\"\"";
  -    }
  -
  -    /**
  -     * Retrieve rights which may be granted to the specified identity.
  -     * @param getter String representing user attempting to get the rights,
  -     * must be non-null and non-empty
  -     * @param identity String representing user whose rights are being got,
  -     * must be non-null and non-empty
  -     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  -     * guaranteed rights in this mailbox.
  -     * @throws AccessControlException if getter does not have lookup rights for
  -     * this mailbox (ie they should not know this mailbox exists).
  -     * @throws AuthorizationException if implementation does not wish to expose
  -     * ACL for this identity to this getter.
  -     */
  -    public String getOptionalRights(String getter, String identity)
  -        throws AccessControlException, AuthorizationException {
  -        boolean[] gettersRights = (boolean[]) acl.get(getter);
  -        if (gettersRights == null
  -            || (gettersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  -            throw new AuthorizationException(DENY_AUTH + getter);
  -        }
  -
  -        return OPTIONAL_RIGHTS;
  -    }
  -
  -    /**
  -     * Helper boolean methods.
  -     * Provided for cases where you need to check the ACL before selecting the
  -     * mailbox.
  -     *
  -     * @param username String representing user
  -     * @returns true if user has the requested right.
  -     * &throws AccessControlException if username does not have lookup rights.
  -     * (Except for hasLookupRights which just returns false.
  -     */
  -    public boolean hasLookupRights(String username) {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        return (( usersRights == null || (usersRights[LOOKUP] == false))
  -                ? false : true);
  -    }
  -
  -    public boolean hasReadRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[READ];
  -    }
  -
  -    public boolean hasKeepSeenRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[KEEP_SEEN];
  -    }
  -
  -    public boolean hasWriteRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[WRITE];
  -    }
  -
  -    public boolean hasInsertRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[INSERT];
  -    }
  -
  -    public boolean hasCreateRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[CREATE];
  -    }
  -
  -    public boolean hasDeleteRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[DELETE];
  -    }
  -
  -    public boolean hasAdminRights(String username)
  -        throws AccessControlException {
  -        boolean[] usersRights = (boolean[]) acl.get(username);
  -        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  -            throw new AccessControlException(DENY_ACCESS);
  -        }
  -        return usersRights[ADMIN];
  -    }
  -
  -    // Mailbox methods using the ACL ---------------------------
  -
  -    /**
  -     * Indicates if this folder may be selected by the specified user. Requires
  -     * user to have at least read rights. It does not indicate whether user
  -     * can write to mailbox
  -     *
  -     * @param username String represnting user
  -     * @returns boolean TRUE if specified user can Select mailbox.
  -     * @throws AccessControlException if username does not have lookup rights
  -     */
  -    public  synchronized  boolean isSelectable(String username)
  -        throws AccessControlException {
  -        return ( ! notSelectableByAnyone && hasReadRights(username) );
  -    }
  -
  -    /**
  -     * Indicates if specified user can change any flag on a permanent basis,
  -     * except for \Recent which can never be changed by a user.
  -     *
  -     * @param username String represnting user
  -     * @returns true if specified user can change all flags permanently.
  -     */
  -    public synchronized boolean allFlags(String username)
  -        throws AccessControlException {
  -        // relies on implementation that each right implies those
  -        // before it in list:  l,r,s,w,i,p,c,d,a
  -        return hasDeleteRights(username);
  -    }
  -
  -    /**
  -     * Indicates which flags this user can change permanently. If allFlags()
  -     * returns true for this user, then this method must have the same return
  -     * value as getSupportedFlags.
  -     *
  -     * @param username String represnting user
  -     * @returns String a space seperated list of message flags which this user
  -     * can set permanently
  -     */
  -    public  synchronized  String getPermanentFlags(String username)
  -        throws AccessControlException {
  -        if (hasDeleteRights(username)) {
  -            return SYSTEM_FLAGS;
  -        } else if (hasWriteRights(username)) {
  -            return "\\Seen \\Answered \\Flagged \\Draft";
  -        } else if (hasKeepSeenRights(username)) {
  -            return "\\Seen";
  -        } else {
  -            return "";
  -        }
  -    }
  -
  -    /**
  -     * Provides a reference to the access control list for this mailbox.
  -     *
  -     * @returns the AccessControlList for this Mailbox
  -     */
  -    //   public ACL getACL();
  -
  -    /**
  -     * Indicates state in which  the mailbox will be opened by specified user.
  -     * A return value of true indicates Read Only, false indicates Read-Write
  -     * and an AccessControlException is thrown if user does not have read
  -     * rights.
  -     * <p>Implementations decide if Read Only means only lookup and read
  -     * rights (lr) or lookup, read and keep seen rights (lrs). This may even
  -     * vary between mailboxes.
  -     *
  -     * @param username String represnting user
  -     * @returns true if specified user can only open the mailbox Read-Only.
  -     * @throws AccessControlException if the user can not open this mailbox
  -     * at least Read-Only.
  -     */
  -    public synchronized boolean isReadOnly(String username)
  -        throws AccessControlException {
  -        return (! hasWriteRights(username));
  -    }
  -
  -    // Message handling methods ---------------------------
  -
  -    /**
  -     * Stores a message in this mailbox. User must have insert rights.
  -     *
  -     * @param message the MimeMessage to be stored
  -     * @param username String represnting user
  -     * @returns boolean true if successful
  -     * @throws AccessControlException if username does not have lookup rights
  -     * for this mailbox.
  -     * @throws AuthorizationException if username has lookup rights but does
  -     * not have insert rights.
  -     */
  -    public synchronized boolean store(MimeMessage message, String username)
  -        throws AccessControlException, AuthorizationException,
  -               IllegalArgumentException {
  -
  -        if (message == null || username == null) {
  -            getLogger().error("Null argument received in store.");
  -            throw new IllegalArgumentException("Null argument received in store.");
  -        }
  -        if (!hasInsertRights(username)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to insert.");
  -        }
  -
  -        SimpleMessageAttributes attrs = new SimpleMessageAttributes();
  -        try {
  -            setupLogger(attrs);
  -            attrs.setAttributesFor(message);
  -        } catch (javax.mail.MessagingException me) {
  -            throw new RuntimeException("Exception creating SimpleMessageAttributes: " + me);
  -        }
  -        Flags flags = new Flags();
  -        flags.initialize();
  -        return store(message, username, attrs, flags);
  -    }
  -
  -    /**
  -     * Stores a message in this mailbox, using passed MessageAttributes and
  -     * Flags. User must have insert rights.
  -     * <br>Current implementation requires MessageAttributs to be of
  -     * class SimpleMessageAttributes
  -     *
  -     * @param mail the message to be stored
  -     * @param username String represnting user
  -     * @param msgAttrs non-null MessageAttributes for use with this Message
  -     * @returns boolean true if successful
  -     * @throws AccessControlException if username does not have lookup
  -     * rights for this mailbox.
  -     * @throws AuthorizationException if username has lookup rights but does
  -     * not have insert rights.
  -     */
  -    public boolean store(MimeMessage message, String username,
  -                         MessageAttributes msgAttrs, Flags flags)
  -        throws AccessControlException, AuthorizationException,
  -               IllegalArgumentException {
  -
  -        if (msgAttrs == null || message == null || username == null) {
  -            getLogger().error("Null argument received in store.");
  -            throw new IllegalArgumentException("Null argument received in store.");
  -        }
  -        if (! (msgAttrs instanceof SimpleMessageAttributes)) {
  -            getLogger().error("Wrong class for Attributes");
  -            throw new IllegalArgumentException("Wrong class for Attributes");
  -        }
  -        SimpleMessageAttributes attrs = (SimpleMessageAttributes)msgAttrs;
  -
  -        int newUID = ++highestUID;
  -        attrs.setUID(newUID);
  -        sequence.add(new Integer(newUID));
  -        attrs.setMessageSequenceNumber(sequence.size());
  -
  -        BufferedOutputStream outMsg = null;
  -        ObjectOutputStream outAttrs = null;
  -
  -        try {
  -            // SK:UPDATE
  -            path = getPath( absoluteName, owner, rootPath );
  -            outMsg = new BufferedOutputStream( new FileOutputStream(path + File.separator + newUID + MESSAGE_EXTENSION));
  -            message.writeTo(outMsg);
  -            outMsg.close();
  -            outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + newUID + ATTRIBUTES_EXTENSION));
  -            outAttrs.writeObject(attrs);
  -            outAttrs.close();
  -        } catch(Exception e) {
  -            getLogger().error("Error writing message to disc: " + e);
  -            e.printStackTrace();
  -            throw new
  -                RuntimeException("Exception caught while storing Mail: "
  -                                 + e);
  -        } finally {
  -            try {
  -                outMsg.close();
  -                outAttrs.close();
  -            } catch (IOException ie) {
  -                getLogger().error("Error closing streams: " + ie);
  -            }
  -        }
  -        marked = true;
  -        if (flags.isRecent()) {
  -            recentMessages.add(new Integer(newUID));
  -        }
  -        if (flags.isDeleted()) {
  -            messagesForDeletion.add(new Integer(newUID));
  -        }
  -        //if (!flags.isSeen(username)) {
  -        //If a user had no unseen messages, they do, now.
  -        Iterator it = oldestUnseenMessage.keySet().iterator();
  -        while (it.hasNext()) {
  -            String user = (String)it.next();
  -            if ( ((Integer)oldestUnseenMessage.get(user)).intValue() == -1) {
  -                oldestUnseenMessage.put(user, new Integer(newUID));
  -            }
  -        }
  -        //}
  -        writeFlags(newUID, flags);
  -        getLogger().info("Mail " + newUID + " written in " + absoluteName);
  -
  -        return true;
  -    }
  -
  -    /**
  -     * Retrieves a message given a message sequence number.
  -     *
  -     * @param msn the message sequence number
  -     * @param username String represnting user
  -     * @returns an  MimeMessageWrapper object containing the message, null if no message with
  -     * the given msn.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have read rights.
  -     */
  -    public synchronized MimeMessageWrapper retrieve(int msn, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -
  -        if (msn > sequence.size()) {
  -            return null;
  -        } else {
  -            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  -            return retrieveUID(uid, user);
  -        }
  -    }
  -
  -
  -    /**
  -     * Retrieves a message given a unique identifier.
  -     *
  -     * @param uid the unique identifier of a message
  -     * @param username String represnting user
  -     * @returns an MimeMessageWrapper object containing the message, null if no message with
  -     * the given msn.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have read rights.
  -     */
  -    public synchronized MimeMessageWrapper retrieveUID(int uid, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        MimeMessageWrapper response = null;
  -        if (sequence.contains(new Integer(uid))) {
  -            //BufferedInputStream inMsg = null;
  -            try {
  -                path = getPath( absoluteName, owner, rootPath );
  -		MimeMessageFileSource source = new MimeMessageFileSource(path + File.separator + uid + MESSAGE_EXTENSION);
  -                response = new MimeMessageWrapper(source);
  -             //   inMsg.close();
  -            } catch(Exception e) {
  -                getLogger().error("Error reading message from disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caught while retrieving Mail: "
  -                                     + e);
  -            } //finally {
  -          //      try {
  -            //        inMsg.close();
  -          //      } catch (IOException ie) {
  -          //          getLogger().error("Error closing streams: " + ie);
  -          //      }
  -          //  }
  -            getLogger().info("MimeMessageWrapper " + uid + " read from " + absoluteName);
  -            return response;
  -        } else {
  -            return null;
  -        }
  -    }
  -
  -    /**
  -     * Marks a message for deletion given a message sequence number.
  -     *
  -     * @param msn the message sequence number
  -     * @param username String represnting user
  -     * @returns boolean true if successful.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized boolean markDeleted(int msn, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasDeleteRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to delete.");
  -        }
  -
  -        Assert.notImplemented();
  -        //TBD
  -        return false;
  -    }
  -
  -    /**
  -     * Marks a message for deletion given a unique identifier.
  -     *
  -     * @param uidunique identifier
  -     * @param username String represnting user
  -     * @returns boolean true if successful, false if failed including no
  -     * message with the given uid.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized boolean markDeletedUID(int uid, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasDeleteRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to delete.");
  -        }
  -
  -        Assert.notImplemented();
  -        //TBD
  -        return false;
  -    }
  -
  -    /**
  -     * Returns the message attributes for a message.
  -     *
  -     * @param msn message sequence number
  -     * @param username String represnting user
  -     * @returns MessageAttributes for message, null if no such message.
  -     * Changing the MessageAttributes object must not affect the actual
  -     * MessageAttributes.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized MessageAttributes getMessageAttributes(int msn, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        System.out.println("msn: "+msn);
  -        System.out.println("sequence.size: "+sequence.size());
  -        if (msn > sequence.size()) {
  -            return null;
  -        } else {
  -            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  -            return getMessageAttributesUID(uid, user);
  -        }
  -    }
  -
  -    /**
  -     * Returns the message attributes for a message.
  -     *
  -     * @param uid unique identifier
  -     * @param username String represnting user
  -     * @returns MessageAttributes for message, null if no such message.
  -     * Changing the MessageAttributes object must not affect the actual
  -     * MessageAttributes.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized MessageAttributes getMessageAttributesUID(int uid, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        System.out.println("getMessageAttributesUID()");
  -        System.out.println("uid: "+uid);
  -        System.out.println("user: "+user);
  -        System.out.println("sequence.size: "+sequence.size());
  -        SimpleMessageAttributes response = null;
  -        if (sequence.contains(new Integer(uid))) {
  -                System.out.println("reading from disk");
  -
  -            ObjectInputStream inAttrs = null;
  -            try {
  -                path = getPath( absoluteName, owner, rootPath );
  -                System.out.println( "FileInputStream("+(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  -                inAttrs = new ObjectInputStream( new FileInputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  -                System.out.println("inAttrs="+inAttrs);
  -                response = (SimpleMessageAttributes)inAttrs.readObject();
  -                System.out.println("response="+response);
  -                if (response != null) {
  -                System.out.println("response.parts="+response.parts);
  -                if (response.parts != null) {
  -                System.out.println("response.parts.len="+response.parts.length);
  -                System.out.println("response.parts[0]="+response.parts[0]);
  -                }
  -                }
  -                setupLogger(response);
  -            } catch(Exception e) {
  -                getLogger().error("Error reading attributes from disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caught while retrieving Message attributes: "
  -                                     + e);
  -            } finally {
  -                try {
  -                    inAttrs.close();
  -                } catch (IOException ie) {
  -                    getLogger().error("Error closing streams: " + ie);
  -                }
  -            }
  -            getLogger().info("MessageAttributes for " + uid + " read from " + absoluteName);
  -            return response;
  -        } else {
  -            return null;
  -        }
  -    }
  -
  -    /**
  -     * Updates the attributes of a message.This may be incorporated into setFlags().
  -     *
  -     * @param MessageAttributes of a message already in this Mailbox
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public boolean updateMessageAttributes(MessageAttributes attrs, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to store flags.");
  -        }
  -        int uid = attrs.getUID();
  -        if (sequence.contains(new Integer(uid))) {
  -
  -            // Really, we should check whether the exact change is authorized.
  -            ObjectOutputStream outAttrs = null;
  -            try {
  -                path = getPath( absoluteName, owner, rootPath );
  -                outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  -                outAttrs.writeObject(attrs);
  -                outAttrs.close();
  -            } catch(Exception e) {
  -                getLogger().error("Error writing message to disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caught while storing Attributes: "
  -                                     + e);
  -            } finally {
  -                try {
  -                    outAttrs.close();
  -                } catch (IOException ie) {
  -                    getLogger().error("Error closing streams: " + ie);
  -                }
  -            }
  -            getLogger().info("MessageAttributes for " + uid + " written in " + absoluteName);
  -
  -            return true;
  -        } else {
  -            return false;
  -        }
  -    }
  -
  -    /**
  -     * Get the IMAP-formatted String of flags for specified message.
  -     *
  -     * @param msn message sequence number for a message in this mailbox
  -     * @param username String represnting user
  -     * @returns flags for this message and user, null if no such message.
  -     * @throws AccessControlException if user does not have lookup rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have read rights.
  -     */
  -    public synchronized  String getFlags(int msn, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        if (msn > sequence.size()) {
  -            return null;
  -        } else {
  -            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  -            return getFlagsUID(uid, user);
  -        }
  -    }
  -
  -    /**
  -     * Get the IMAP-formatted String of flags for specified message.
  -     *
  -     * @param uid UniqueIdentifier for a message in this mailbox
  -     * @param username String represnting user
  -     * @returns flags for this message and user, null if no such message.
  -     * @throws AccessControlException if user does not have lookup rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have read rights.
  -     */
  -    public synchronized  String getFlagsUID(int uid, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        java.util.Iterator it = sequence.iterator();
  -        while(it.hasNext()) 
  -            System.out.println("FILEMESSAGES...."+it.next().toString());
  -            
  -        
  -        if (!sequence.contains(new Integer(uid))) {
  -            System.out.println("SEQUENCENOOO");
  -            return null;
  -        } else {
  -            System.out.println("FLAGSRETURNED");
  -            Flags flags = readFlags(uid);
  -            return flags.getFlags(user);
  -        }
  -    }
  -    /**
  -     * Updates the flags for a message.
  -     *
  -     * @param msn MessageSequenceNumber of a message already in this Mailbox
  -     * @param username String represnting user
  -     * @param request IMAP-formatted String representing requested change to
  -     * flags.
  -     * @returns true if succeeded, false otherwise, including no such message
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized  boolean setFlags(int msn, String user, String request)
  -        throws AccessControlException, AuthorizationException,
  -               IllegalArgumentException {
  -        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to store any flags.");
  -        }
  -        if (msn > sequence.size()) {
  -            return false;
  -        } else {
  -            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  -            return setFlagsUID(uid, user, request);
  -        }
  -    }
  -
  -    /**
  -     * Updates the flags for a message.
  -     *
  -     * @param uid Unique Identifier of a message already in this Mailbox
  -     * @param username String represnting user
  -     * @param request IMAP-formatted String representing requested change to
  -     * flags.
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has lookup rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized boolean setFlagsUID(int uid, String user, String request)
  -        throws AccessControlException, AuthorizationException,
  -               IllegalArgumentException {
  -        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to store any flags.");
  -        }
  -        if ((request.toUpperCase().indexOf("DELETED") != -1) && (!hasDeleteRights(user))) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to delete.");
  -        }
  -        if (sequence.contains(new Integer(uid))) {
  -
  -            Flags flags = readFlags(uid);
  -            boolean wasRecent = flags.isRecent();
  -            boolean wasDeleted = flags.isDeleted();
  -            boolean wasSeen = flags.isSeen(user);
  -
  -            if  (flags.setFlags(request, user)) {
  -
  -                if (flags.isDeleted()) {
  -                    if (! wasDeleted) { messagesForDeletion.add(new Integer(uid)); }
  -                }
  -                if (flags.isSeen(user) != wasSeen) {
  -                    if (flags.isSeen(user)) {
  -                        int previousOld = ((Integer)oldestUnseenMessage.get(user)).intValue();
  -                        if (uid == previousOld) {
  -                            int newOld = findOldestUnseen(user, previousOld);
  -                            oldestUnseenMessage.put(user, (new Integer(newOld)));
  -                        }
  -                    } else { // seen flag unset
  -                        if (uid < ((Integer)oldestUnseenMessage.get(user)).intValue()) {
  -                            oldestUnseenMessage.put(user, (new Integer(uid)));
  -                        }
  -                    }
  -                }
  -
  -                writeFlags(uid, flags);
  -                getLogger().debug("Flags for message uid " + uid + " in " + absoluteName + " updated.");
  -                return true;
  -            } else {
  -                return false;
  -            }
  -        } else {
  -            return false;
  -        }
  -
  -    }
  -
  -    private int findOldestUnseen(String user, int previousOld)
  -        throws AccessControlException, AuthorizationException {
  -        int response = 0; //indicates no unseen messages
  -        try {
  -            ListIterator lit = sequence.listIterator(previousOld);
  -            boolean found = false;
  -            while (!found && lit.hasNext() ) {
  -                int uid = ((Integer)lit.next()).intValue();
  -                Flags flags = readFlags(uid);
  -                if (!flags.isSeen(user)) {
  -                    response = uid;
  -                    found = true;
  -                }
  -            }
  -        }catch(Exception e) { 
  -            // (because) BUG: Do nothing. Have investigated an error on fetching sequence.listIterator(previousOld);
  -            // with an error - but currently I don't know why :)
  -        }finally{
  -            return response;
  -        }
  -    }
  -
  -    private Flags readFlags(int uid) {
  -        Flags response = null;
  -        if (sequence.contains(new Integer(uid))) {
  -            ObjectInputStream inFlags = null;
  -            try {
  -                path = getPath( absoluteName, owner, rootPath );
  -                inFlags = new ObjectInputStream( new FileInputStream(path + File.separator + uid + FLAGS_EXTENSION));
  -                response = (Flags)inFlags.readObject();
  -            } catch(Exception e) {
  -                getLogger().error("Error reading flags from disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caught while retrieving Message flags: "
  -                                     + e);
  -            } finally {
  -                try {
  -                    inFlags.close();
  -                } catch (IOException ie) {
  -                    getLogger().error("Error closing streams: " + ie);
  -                }
  -            }
  -            getLogger().info("Flags for " + uid + " read from " + absoluteName);
  -        }
  -        return response;
  -    }
  -
  -    private boolean writeFlags(int uid, Flags flags) {
  -        if (sequence.contains(new Integer(uid))) {
  -            ObjectOutputStream outFlags = null;
  -            try {
  -                path = getPath( absoluteName, owner, rootPath );
  -                outFlags = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + FLAGS_EXTENSION));
  -                outFlags.writeObject(flags);
  -                outFlags.close();
  -            } catch(Exception e) {
  -                getLogger().error("Error writing message to disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caught while storing Flags: "
  -                                     + e);
  -            } finally {
  -                try {
  -                    outFlags.close();
  -                } catch (IOException ie) {
  -                    getLogger().error("Error closing streams: " + ie);
  -                }
  -            }
  -            getLogger().info("Flags for " + uid + " written in " + absoluteName);
  -            writeMailbox();
  -            return true;
  -        } else {
  -            writeMailbox();
  -            return false;
  -        }
  -    }
  -
  -    /**
  -     * Removes all messages marked Deleted.  User must have delete rights.
  -     *
  -     * @param username String represnting user
  -     * @returns true if successful
  -     * @throws AccessControlException if user does not have read rights for
  -     * this mailbox.
  -     * @throws AuthorizationException if user has delete rights but does not
  -     * have delete rights.
  -     */
  -    public synchronized boolean expunge(String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasDeleteRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to delete for user '" + user + "'.");
  -        }
  -        Iterator it = messagesForDeletion.iterator();
  -
  -        while (it.hasNext()) {
  -            Integer uidObj = (Integer)it.next();
  -            int uid = uidObj.intValue();
  -            if (sequence.contains(uidObj)) {
  -                try  {
  -                    //SAM
  -                    try
  -                    {
  -                        MimeMessageWrapper message = retrieveUID(uid, user);
  -                        System.out.println("(before)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
  -                        System.out.println("decre message.getMessageSize() = " + (int)message.getMessageSize());
  -                        mailboxSize -= (int)message.getMessageSize();
  -                        System.out.println("(after)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
  -                    }
  -                    catch (MessagingException me)
  -                    {
  -                            //ignore
  -                    }
  -                    //END
  -                    path = getPath( absoluteName, owner, rootPath );
  -                    final File msgFile = new File(path + File.separator + uid + MESSAGE_EXTENSION );
  -                    msgFile.delete();
  -                    final File attrFile = new File(path + File.separator + uid + ATTRIBUTES_EXTENSION );
  -                    attrFile.delete();
  -                    //SAM
  -                    final File flagFile = new File(path + File.separator + uid + FLAGS_EXTENSION );
  -                    flagFile.delete();
  -                    //END
  -                    sequence.remove(uidObj);
  -                } catch ( final Exception e )  {
  -                    throw new RuntimeException( "Exception caught while removing" +
  -                                                " a message: " + e );
  -                }
  -            }
  -        }
  -
  -        for (int i = 0; i < sequence.size(); i++) {
  -            System.err.println("Message with msn " + i + " has uid " + sequence.get(i));
  -        }
  -        writeMailbox();
  -        return true;
  -    }
  -
  -    private void writeMailbox() {
  -        String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
  -        ObjectOutputStream out = null;
  -        FileOutputStream fout = null;
  -        try {
  -            fout = new FileOutputStream( mailboxRecordFile );
  -            out = new ObjectOutputStream( fout );
  -            out.writeObject(this);
  -            out.flush();
  -            out.close();
  -            fout.flush();
  -            fout.close();
  -        } catch(Exception e) {
  -            if (out != null) {
  -                try {
  -                    out.close();
  -                } catch (Exception ignored) {
  -                }
  -            }
  -            if (fout != null) {
  -                try {
  -                    fout.close();
  -                } catch (Exception ignored) {
  -                }
  -            }
  -            e.printStackTrace();
  -            throw new
  -                RuntimeException("Exception caught while storing Mailbox: " + e);
  -        }
  -        getLogger().info("FileMailbox written: " + absoluteName);
  -    }
  -
  -
  -    /**
  -     * Lists uids of messages in mailbox indexed by MSN.
  -     *
  -     * @param username String represnting user
  -     * @returns List of Integers wrapping uids of message
  -     */
  -    public List listUIDs(String user) {
  -        return new ArrayList(Collections.unmodifiableList(sequence));
  -    }
  -
  -    public Set getUsersWithLookupRights() {
  -        Set response = new  HashSet();
  -        Iterator it = acl.keySet().iterator();
  -        while (it.hasNext()) {
  -            String user = (String) it.next();
  -            boolean[] rights = (boolean[]) acl.get(user);
  -            if (rights[LOOKUP] == true) {
  -                response.add(user);
  -            }
  -        }
  -        return response;
  -    }
  -
  -    public Set getUsersWithReadRights() {
  -        Set response = new  HashSet();
  -        Iterator it = acl.keySet().iterator();
  -        while (it.hasNext()) {
  -            String user = (String) it.next();
  -            boolean[] rights = (boolean[]) acl.get(user);
  -            if (rights[READ] == true) {
  -                response.add(user);
  -            }
  -        }
  -        return response;
  -    }
  -
  -    public Map getUnseenByUser() {
  -        Map response = new HashMap();
  -        Iterator it = oldestUnseenMessage.keySet().iterator();
  -        while (it.hasNext()) {
  -            String user = (String) it.next();
  -            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  -            int oldUID = uidObj.intValue();
  -            if (oldUID == 0) {
  -                response.put(user, uidObj);
  -            } else {
  -                int count = 0;
  -                ListIterator lit
  -                    = sequence.listIterator(sequence.indexOf(uidObj));
  -                while (lit.hasNext() ) {
  -                    int uid = ((Integer)lit.next()).intValue();
  -                    Flags flags = readFlags(uid);
  -                    if (!flags.isSeen(user)) {
  -                        count ++;
  -                    }
  -                }
  -                response.put(user, new Integer(count));
  -            }
  -        }
  -        return response;
  -    }
  -
  -
  -    public InternetHeaders getInternetHeaders(int msn, String user)
  -        throws AccessControlException, AuthorizationException {
  -        if (!hasReadRights(user)) { //throws AccessControlException
  -            throw new AuthorizationException("Not authorized to read.");
  -        }
  -        if (msn > sequence.size()) {
  -            return null;
  -        } else {
  -            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  -            return getInternetHeadersUID(uid, user);
  -        }
  -    }
  -
  -    public InternetHeaders getInternetHeadersUID(int uid, String user)
  -        throws AccessControlException, AuthorizationException {
  -        InternetHeaders response = null;
  -        if (sequence.contains(new Integer(uid))) {
  -            BufferedInputStream inMsg = null;
  -            try {
  -                inMsg = new BufferedInputStream( new FileInputStream(path + File.separator + uid + MESSAGE_EXTENSION));
  -                response = new InternetHeaders(inMsg);
  -                inMsg.close();
  -            } catch(Exception e) {
  -                getLogger().error("Error reading headers of message from disc: " + e);
  -                e.printStackTrace();
  -                throw new
  -                    RuntimeException("Exception caughtt while retrieving InternetHeaders: "    + e);
  -            } finally {
  -                try {
  -                    inMsg.close();
  -                } catch (IOException ie) {
  -                    getLogger().error("Error closing streams: " + ie);
  -                }
  -            }
  -            getLogger().info("InternetHeaders for message " + uid + " read from "
  -                        + absoluteName);
  -            return response;
  -        } else {
  -            return null;
  -        }
  -    }
  -
  -    /**
  -     * Returns true if the named user is subscribed to this Mailbox.
  -     */
  -    public boolean isSubscribed( String userName )
  -    {
  -        return subscribedUsers.contains( userName.toLowerCase() );
  -    }
  -
  -    /**
  -     * Subscribes a user to this Mailbox.
  -     */
  -    public void subscribe( String userName )
  -    {
  -        subscribedUsers.add( userName.toLowerCase() );
  -    }
  -
  -    /**
  -     * Unsubscrive a user from this Mailbox.
  -     */
  -    public void unsubscribe( String userName )
  -    {
  -        subscribedUsers.remove( userName.toLowerCase() );
  -    }
  -}
  -
  -
  -
  +/*
  + * 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.imapserver;
  +
  +import org.apache.avalon.cornerstone.services.store.ObjectRepository;
  +import org.apache.avalon.cornerstone.services.store.Store;
  +import org.apache.avalon.framework.component.ComponentManager;
  +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.logger.AbstractLogEnabled;
  +import org.apache.avalon.phoenix.BlockContext;
  +import org.apache.james.AccessControlException;
  +import org.apache.james.AuthorizationException;
  +import org.apache.james.core.MimeMessageWrapper;
  +import org.apache.james.services.UsersRepository;
  +import org.apache.james.services.UsersStore;
  +import org.apache.james.util.Assert;
  +
  +import javax.mail.internet.InternetHeaders;
  +import javax.mail.internet.MimeMessage;
  +import javax.mail.MessagingException;
  +import java.io.*;
  +import java.util.*;
  +
  +/**
  + * Object representing an IMAP4rev1 mailbox (folder) on a local file system.
  + * The mailbox contains messages, message attributes and an access control
  + * list.
  + *
  + * <p> from Interface Mailbox
  + *
  + * <p>Mailbox Related Flags (rfc2060 name attributes)
  + * <br>    \Noinferiors   It is not possible for any child levels of hierarchy
  + * to exist under this name; no child levels exist now and none can be created
  + * in the future.
  + * <br>    \Noselect      It is not possible to use this name as a selectable
  + * mailbox.
  + * <br>    \Marked        The mailbox has been marked "interesting" by the
  + * server; the mailbox probably contains messages that have been added since
  + * the last time the mailbox was selected.
  + * <br>      \Unmarked      The mailbox does not contain any additional
  + * messages since the last time the mailbox was selected.
  + *
  + * <p>Message related flags.
  + * <br>The flags allowed per message are specific to each mailbox.
  + * <br>The minimum list (rfc2060 system flags) is:
  + * <br> \Seen       Message has been read
  + * <br> \Answered   Message has been answered
  + * <br> \Flagged    Message is "flagged" for urgent/special attention
  + * <br> \Deleted    Message is "deleted" for removal by later EXPUNGE
  + * <br> \Draft      Message has not completed composition (marked as a draft).
  + * <br> \Recent     Message is "recently" arrived in this mailbox.  This
  + * session is the first session to have been notified about this message;
  + * subsequent sessions will not see \Recent set for this message.  This flag
  + * can not be altered by the client.
  + *  <br>            If it is not possible to determine whether or not this
  + * session is the first session to be notified about a message, then that
  + * message SHOULD be considered recent.
  + *
  + * <p> From interface ACL </p>
  + *
  + * The standard rights in RFC2086 are:
  + * <br>l - lookup (mailbox is visible to LIST/LSUB commands)
  + * <br>r - read (SELECT the mailbox, perform CHECK, FETCH, PARTIAL, SEARCH,
  + * COPY from mailbox)
  + * <br>s - keep seen/unseen information across sessions (STORE SEEN flag)
  + * <br>w - write (STORE flags other than SEEN and DELETED)
  + * <br>i - insert (perform APPEND, COPY into mailbox)
  + * <br>p - post (send mail to submission address for mailbox, not enforced by
  + * IMAP4 itself)
  + * <br>c - create (CREATE new sub-mailboxes in any implementation-defined
  + * hierarchy)
  + * <br>d - delete (STORE DELETED flag, perform EXPUNGE)
  + * <br>a - administer (perform SETACL)
  + *
  + * <p> Serialization. Not all fields are serialized. Dispose() must be called to
  + * write serialized fiels to disc before finishing with this object.
  + *
  + * <p> Deserialization. On recover from disc, configure, compose,
  + * contextualize and reInit must be called before object is ready for use.
  + *
  + * Reference: RFC 2060
  + * @author <a href="mailto:sascha@kulawik.de">Sascha Kulawik</a>
  + * @author <a href="mailto:charles@benett1.demon.co.uk">Charles Benett</a>
  + * @version 0.2 on 04 Aug 2002
  + */
  +public class FileMailbox
  +    extends AbstractLogEnabled
  +    implements ACLMailbox, Serializable {
  +
  +    public static final String MAILBOX_FILE_NAME = "mailbox.mbr";
  +
  +    private static final String MESSAGE_EXTENSION = ".msg";
  +    private static final String ATTRIBUTES_EXTENSION = ".att";
  +    private static final String FLAGS_EXTENSION = ".flags";
  +
  +    private static final int NUMBER_OF_RIGHTS = 9;
  +    // Map string identities to boolean[NUMBER_OF_RIGHTS] arrays of rights
  +    //The rights are, in order: l,r,s,w,i,p,c,d,a
  +    private static final int LOOKUP = 0;
  +    private static final int READ = 1;
  +    private static final int KEEP_SEEN = 2;
  +    private static final int WRITE = 3;
  +    private static final int INSERT = 4;
  +    private static final int POST = 5;
  +    private static final int CREATE = 6;
  +    private static final int DELETE = 7;
  +    private static final int ADMIN = 8;
  +    private static final boolean[] NO_RIGHTS
  +        = {false, false, false, false, false, false, false, false, false};
  +    private static final boolean[] ALL_RIGHTS
  +        = {true, true, true, true, true, true, true, true, true};
  +    private static final String DENY_ACCESS = "Access denied by ACL";
  +    private static final String DENY_AUTH = "Action not authorized for: ";
  +    private static final String OPTIONAL_RIGHTS = "l r s w i p c d a";
  +    private static final char[] DELETE_MODS
  +        = {'-', 'l', 'r', 's', 'w', 'i', 'p', 'c', 'd', 'a'};
  +
  +    /* Transient fields - reInit must be called on recover from disc. */
  +    private transient BlockContext context;
  +    private transient Configuration conf;
  +    private transient ComponentManager compMgr;
  +    private transient UsersRepository localUsers;
  +    private transient HashSet listeners;
  +
  +    /* Serialized fileds */
  +    private String path; // does not end with File.separator
  +    private String rootPath; // does not end with File.separator
  +    private File directory ;
  +    private String owner;
  +    private String absoluteName;
  +    private Map acl;
  +    private String name;
  +    private int uidValidity;
  +    private int mailboxSize; // octets
  +    private boolean inferiorsAllowed;
  +    private boolean marked;
  +    private boolean notSelectableByAnyone;
  +
  +    // Sets the UID for all Mailboxes
  +    private static HighestUID highestUID;
  +
  +    // The message sequence number of a msg is its index in List sequence + 1
  +    private List sequence; //List of UIDs of messages in mailbox
  +
  +    // Set of UIDs of messages with recent flag set
  +    private Set recentMessages;
  +
  +    // Set of UIDs of messages with delete flag set
  +    private Set messagesForDeletion;
  +
  +    //map of user String to Integer uid, 0 for no unseen messages
  +    private Map oldestUnseenMessage;
  +
  +    // Set of subscribed users.
  +    private Set subscribedUsers = new HashSet(1000);
  +
  +    public void configure(Configuration conf) throws ConfigurationException {
  +        this.conf = conf;
  +    }
  +
  +    public void contextualize(Context context) {
  +        this.context = (BlockContext)context;
  +    }
  +
  +    public void compose(ComponentManager comp) {
  +        compMgr = comp;
  +    }
  +
  +    public void prepareMailbox(String user, String absName, String initialAdminUser, int uidValidity ) {
  +        Assert.isTrue( Assert.ON && user != null && user.length() > 0 );
  +        owner = user;
  +
  +        Assert.isTrue( Assert.ON && absName != null && (absName.length() > 0));
  +        absoluteName = absName;
  +
  +        Assert.isTrue( Assert.ON && initialAdminUser != null && initialAdminUser.length() > 0 );
  +        acl = new HashMap(7);
  +        acl.put(initialAdminUser, ALL_RIGHTS);
  +
  +        Assert.isTrue( Assert.ON && uidValidity > 0 );
  +        this.uidValidity = uidValidity;
  +    }
  +
  +    public void initialize() throws Exception {
  +        
  +        mailboxSize = 0;
  +        inferiorsAllowed = true;
  +        marked = false;
  +        notSelectableByAnyone = false;
  +        oldestUnseenMessage = new HashMap();
  +        listeners = new HashSet();
  +        sequence = new ArrayList();
  +        recentMessages = new HashSet();
  +        messagesForDeletion = new HashSet();
  +        getLogger().info("FileMailbox init for " + absoluteName);
  +        UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
  +        localUsers = usersStore.getRepository("LocalUsers");
  +        rootPath = conf.getChild( "mailboxRepository" ).getValue();
  +        if (!rootPath.endsWith(File.separator)) {
  +            rootPath = rootPath + File.separator;
  +        }
  +        
  +        path = getPath( absoluteName, owner, rootPath );
  +        name = absoluteName.substring(absoluteName.lastIndexOf( JamesHost.HIERARCHY_SEPARATOR ) + 1);
  +        if (name.equals(owner)) {
  +            name = "";
  +        }
  +        //Check for writable directory
  +        getLogger().info("MailboxDir " + path);
  +        System.out.println("MailboxDir TO WRITE TO " + path);
  +        File mailboxDir = new File(path);
  +        if (mailboxDir.exists()) {
  +            throw new RuntimeException("Error: Attempt to overwrite mailbox directory at " + path);
  +        } else if (! mailboxDir.mkdir()){
  +            throw new RuntimeException("Error: Cannot create mailbox directory at " + path);
  +        } else if (!mailboxDir.canWrite()) {
  +            throw new RuntimeException("Error: Cannot write to directory at " + path);
  +        }
  +        writeMailbox();
  +        getLogger().info("FileMailbox init complete: " + absoluteName);
  +    }
  +
  +
  +
  +    /**
  +     * Return the file-system path to a given absoluteName mailbox.
  +     *
  +     * @param absoluteName the user-independent name of the mailbox
  +     * @param owner string name of owner of mailbox
  +     */
  +    private String getPath( String absoluteName, String owner, String rootPath )
  +    {
  +        Assert.isTrue( Assert.ON &&
  +                       absoluteName.startsWith( JamesHost.NAMESPACE_TOKEN ) );
  +
  +        // Remove the leading '#' and replace Hierarchy separators with file separators.
  +        String filePath = absoluteName.substring( JamesHost.NAMESPACE_TOKEN.length() );
  +        filePath = filePath.replace( JamesHost.HIERARCHY_SEPARATOR_CHAR, File.separatorChar );
  +        return rootPath + filePath;
  +    }
  +    
  +    /**
  +     * Re-initialises mailbox after reading from file-system. Cannot assume that this is the same instance of James that wrote it.
  +     *
  +     * <p> Contract is that re-init must be called after configure, contextualize, compose.
  +     */
  +    public void reinitialize() throws Exception {
  +        listeners = new HashSet();
  +        getLogger().info("FileMailbox reInit for " + absoluteName);
  +        UsersStore usersStore = (UsersStore)compMgr.lookup( "org.apache.james.services.UsersStore" );
  +        localUsers = usersStore.getRepository("LocalUsers");
  +        rootPath
  +            = conf.getChild("mailboxRepository").getValue();
  +        if (!rootPath.endsWith(File.separator)) {
  +            rootPath = rootPath + File.separator;
  +        }
  +        path = getPath( absoluteName, owner, rootPath );
  +    }
  +
  +    /**
  +     * Call when host has finished with a mailbox.
  +     * This is really a stop rather than destroy.
  +     * Writes current mailbox object to disc.
  +     */
  +    public void dispose() {
  +        writeMailbox();
  +        getLogger().info("FileMailbox object destroyed: " + absoluteName);
  +    }
  +
  +    /**
  +     * Permanently deletes the mailbox.
  +     */
  +    public void removeMailbox()
  +    {
  +        // First delete the mailbox file
  +        path = getPath( absoluteName, owner, rootPath );
  +        String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
  +        File mailboxRecord = new File( mailboxRecordFile );
  +        Assert.isTrue( Assert.ON &&
  +                       mailboxRecord.exists() &&
  +                       mailboxRecord.isFile() );
  +        mailboxRecord.delete();
  +
  +        // Check for empty directory before deleting.
  +        File mailboxDir = new File(path);
  +        Assert.isTrue( Assert.ON &&
  +                       mailboxDir.exists() );
  +        Assert.isTrue( Assert.ON &&
  +                       mailboxDir.isDirectory() );
  +        Assert.isTrue( Assert.ON &&
  +                       mailboxDir.list().length == 0 );
  +        mailboxDir.delete();
  +    }
  +    
  +    /**
  +     * Renames this Mailbox.
  +     * @param usernmae The Username who calles this Command.
  +     * @param newmailboxname The new name for this Mailbox.
  +     * @returns true if everythink was sucessfully, else false.
  +     * @throws MailboxException if mailbox does not exist locally.
  +     * @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
  +     */
  +    public boolean renameMailbox(String username, String newmailboxname) throws MailboxException, AuthorizationException {
  +        try {
  +            path = getPath( absoluteName, owner, rootPath );
  +            
  +            StringTokenizer strt = new StringTokenizer(newmailboxname,".");
  +            String lastnameofmailbox="";
  +            while(strt.hasMoreTokens())
  +                lastnameofmailbox=strt.nextToken();
  +            
  +            File fle = new File(this.path);
  +            fle.renameTo(new File(fle.getParent(), lastnameofmailbox));
  +            
  +            this.path=fle.getParent()+File.separator+lastnameofmailbox;
  +            this.absoluteName = this.absoluteName.substring(0,this.absoluteName.length()-this.name.length())+lastnameofmailbox;
  +            this.name=lastnameofmailbox;
  +            
  +            
  +            this.writeMailbox();
  +            return true;
  +        }catch(Exception e) {
  +            e.printStackTrace();
  +            return false;
  +        }
  +    }
  +    
  +    /**
  +     * THIS IS AN INTERIM SOLUTION !
  +     *
  +     * @param usernmae The Username who calles this Command.
  +     * @param oldabsolutename The old name of the parent.
  +     * @param newabsolutename The new name for the parent.
  +     * @returns true if everythink was sucessfully, else false.
  +     * @throws MailboxException if mailbox does not exist locally.
  +     * @throws AuthorizationException if the user has no rights for changing the name of the Mailbox.
  +     */
  +    public boolean renameSubMailbox(String username, String oldabsolutename, String newname) {
  +        try {
  +            System.out.println("renameSubMailbox ABSOLUTE NAME "+this.absoluteName);
  +            StringTokenizer strt = new StringTokenizer(oldabsolutename,".");
  +            StringBuffer strbuff = new StringBuffer();
  +            
  +            for(int i=0;i<strt.countTokens();i++){
  +                String token = strt.nextToken();
  +                if(strbuff.length()>0) strbuff.append(".");
  +                strbuff.append(token);
  +            }
  +            strbuff.append(".");
  +            strbuff.append(newname);
  +
  +            this.absoluteName = strbuff.toString()+this.absoluteName.substring(oldabsolutename.length());
  +            System.out.println("renameSubMailbox TOKEN CONVERTED: "+this.absoluteName);            
  +            this.writeMailbox();
  +            return true;
  +        }catch(Exception e) {
  +            e.printStackTrace();
  +            return false;
  +        }
  +    }
  +    
  +    /**
  +     * Returns true once this Mailbox has been checkpointed.
  +     * This implementation just writes its mailbox record to disc.  Unless something is
  +     * broken all messages added, amended or removed from this mailbox will have been
  +     * handled by this object.
  +     * <br> This implementation always returns true.
  +     *
  +     * @returns true
  +     */
  +    public synchronized  boolean checkpoint() {
  +        writeMailbox();
  +        getLogger().info("FileMailbox: " + absoluteName + " checkpointed.");
  +        return true;
  +    }
  +
  +    /**
  +     * Remove \Recent flag from all messages in mailbox. Should be called
  +     * whenever a user session finishes.
  +     */
  +    public synchronized void unsetRecent() {
  +        Iterator it = recentMessages.iterator();
  +        while(it.hasNext()) {
  +            Integer uidObj =(Integer)it.next();
  +            int uid = uidObj.intValue();
  +            Flags flags = readFlags(uid);
  +            if (flags != null) {
  +                flags.setRecent(false);
  +                writeFlags(uid, flags);
  +            }
  +        }
  +        recentMessages.clear();
  +    }
  +
  +
  +    // Methods that don't involve the ACL ------------------
  +
  +    /**
  +     * Returns name of this mailbox relative to its parent in the mailbox
  +     * hierarchy.
  +     * Example: 'NewIdeas'
  +     *
  +     * @returns String name of mailbox relative to its immeadiate parent in
  +     * the mailbox hierarchy.
  +     */
  +    public String getName() {
  +        return name;
  +    }
  +
  +    /**
  +     * Returns absolute, that is user-independent, hierarchical name of
  +     * mailbox (including namespace)
  +     * Example: '#mail.fred.flintstone.apache.James.NewIdeas'
  +     *
  +     * @returns String name of mailbox in absolute form
  +     */
  +    public String getAbsoluteName() {
  +        return absoluteName;
  +    }
  +
  +    /** Returns namespace starting with namespace token.
  +     * Example: '#mail'
  +     *
  +     * @returns String containing user-independent namespace of this mailbox.
  +     */
  +    //  public String getNamespace();
  +
  +    /** Returns true if the argument is the relative or absolute name of
  +     * this mailbox
  +     *
  +     * @param name possible name for this Mailbox
  +     * @returns true if name matches either getName() or getAbsoluteName()
  +     */
  +    public boolean matchesName(String testName) {
  +        return (name.equals(testName) || name.equals(absoluteName));
  +    }
  +
  +    /**
  +     * Returns the current unique id validity value of this mailbox.
  +     *
  +     * @returns int current 32 bit unique id validity value of this mailbox
  +     */
  +    public int getUIDValidity() {
  +        return uidValidity;
  +    }
  +
  +    /**
  +     * Returns the 32 bit uid available for the next message.
  +     *
  +     * @returns int the next UID that would be used.
  +     */
  +    public int getNextUID() {
  +        return highestUID.get() + 1;
  +    }
  +
  +    /**
  +     * Returns mailbox size in octets. Should only include actual messages
  +     * and not any implementation-specific data, such as message attributes.
  +     *
  +     * @returns int mailbox size in octets
  +     */
  +    public synchronized int getMailboxSize() {
  +        return mailboxSize;
  +    }
  +
  +    /**
  +     * Indicates if child folders may be created. It does not indicate which
  +     * users can create child folders.
  +     *
  +     * @returns boolean TRUE if inferiors aree allowed
  +     */
  +    public boolean getInferiorsAllowed() {
  +        return inferiorsAllowed;
  +    }
  +
  +    /**
  +     * Indicates that messages have been added since this mailbox was last
  +     * selected by any user.
  +     *
  +     * @returns boolean TRUE if new messages since any user last selected
  +     * mailbox
  +     */
  +    public  synchronized  boolean isMarked() {
  +        return marked;
  +    }
  +
  +    /**
  +     * Returns all flags supported by this mailbox.
  +     * e.g. \Answered \Deleted
  +     *
  +     * @returns String a space seperated list of message flags which are
  +     * supported by this mailbox.
  +     */
  +    public String getSupportedFlags() {
  +        return SYSTEM_FLAGS;
  +    }
  +    /**
  +     * Indicates no of messages with \Recent flag set
  +     *
  +     * @returns int no of messages with \Recent flag set
  +     */
  +    public  synchronized  int getRecent() {
  +        return recentMessages.size();
  +    }
  +
  +    /**
  +     * Indicates the oldest unseen message for the specified user.
  +     *
  +     * @returns int Message Sequence Number of first message without \Seen
  +     * flag set for this User.  0 means no unseen messages in this mailbox.
  +     */
  +    public  synchronized  int getOldestUnseen(String user) {
  +        int response = 0;
  +        if (oldestUnseenMessage.containsKey(user)) {
  +            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  +            if (! (uidObj.intValue() == 0)) {
  +                response = sequence.indexOf(uidObj) + 1;
  +            }
  +        } else {
  +            if (sequence.size() > 0) {
  +                response = 1;
  +                oldestUnseenMessage.put(user, (Integer)sequence.get(0));
  +            } else {
  +                oldestUnseenMessage.put(user, (new Integer(0)));
  +            }
  +        }
  +        return response;
  +    }
  +
  +    /**
  +     * Indicates number of messages in folder
  +     *
  +     * @returns int number of messages
  +     */
  +    public  synchronized  int getExists() {
  +        return sequence.size();
  +    }
  +
  +    /**
  +     * Indicates the number of  unseen messages for the specified user.
  +     *
  +     * @returns int number of messages without \Seen flag set for this User.
  +     */
  +    public int getUnseen(String user) {
  +        if (oldestUnseenMessage.containsKey(user)) {
  +            int response = 0; //indicates no unseen messages
  +            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  +            int oldUID = uidObj.intValue();
  +            if (oldUID != 0) {
  +                ListIterator lit
  +                    = sequence.listIterator(sequence.indexOf(uidObj));
  +                while (lit.hasNext() ) {
  +                    int uid = ((Integer)lit.next()).intValue();
  +                    Flags flags = readFlags(uid);
  +                    if (!flags.isSeen(user)) {
  +                        response ++;
  +                    }
  +                }
  +            }
  +            return response;
  +        } else { // user has never selected mailbox
  +            return sequence.size();
  +        }
  +    }
  +
  +    /** Mailbox Events are used to inform registered listeners of events in the Mailbox.
  +     * E.g. if mail is delivered to an Inbox or if another user appends/ deletes a message.
  +     */
  +    public synchronized void addMailboxEventListener(MailboxEventListener mel) {
  +        listeners.add(mel);
  +    }
  +
  +
  +    public synchronized void removeMailboxEventListener(MailboxEventListener mel) {
  +        listeners.remove(mel);
  +    }
  +
  +    /**
  +     * Mark this mailbox as not selectable by anyone.
  +     * Example folders at the roots of hierarchies, e. #mail for each user.
  +     *
  +     * @param state true if folder is not selectable by anyone
  +     */
  +    public void setNotSelectableByAnyone(boolean state) {
  +        notSelectableByAnyone = state;
  +    }
  +
  +    public boolean isNotSelectableByAnyone() {
  +        return notSelectableByAnyone;
  +    }
  +
  +    // Methods for the embedded ACL ------------------------
  +
  +    /**
  +     * Store access rights for a given identity.
  +     * The setter is the user setting the rights, the identifier is the user
  +     * whose rights are affected.
  +     * The setter and identifier arguments must be non-null and non-empty.
  +     * The modification argument must be non-null and follow the syntax of the
  +     * third argument to a SETACL command.
  +     * If the modification argument is an empty string, that identifier is
  +     * removed from the ACL, if currently present.
  +     *
  +     * @param setter String representing user attempting to set rights, must
  +     * be non-null and non-empty
  +     * @param identity String representing user whose rights are being set,
  +     * must be non-null and non-empty
  +     * @param modification String representing the change in rights, following
  +     * the syntax specified in rfc 2086. Note a blank string means delete all
  +     * rights for given identity.
  +     * @returns true if requested modification succeeded. A return value of
  +     * false means an error other than an AccessControlException or
  +     * AuthorizationException.
  +     * @throws AccessControlException if setter does not have lookup rights for
  +     * this mailbox (ie they should not know this mailbox exists).
  +     * @throws AuthorizationException if specified setter does not have the
  +     * administer right (ie the right to write ACL rights), or if the result
  +     * of this method would leave no identities with admin rights.
  +     */
  +    public boolean setRights(String setter, String identifier,
  +                             String modification)
  +        throws AccessControlException, AuthorizationException {
  +
  +        boolean[] settersRights = (boolean[]) acl.get(setter);
  +        if (settersRights == null
  +            || (settersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        } else if (settersRights[ADMIN] == false) {
  +            throw new AuthorizationException(DENY_AUTH + setter);
  +        }
  +        boolean[] existingRights = (boolean[]) acl.get(identifier);
  +        char[] mods = modification.toCharArray();
  +        if (mods.length == 0) { // means delete all
  +            mods = DELETE_MODS;
  +        }
  +        if(existingRights == null) {
  +            if ( mods[0] == REMOVE_RIGHTS ) {
  +                return false;
  +            } else {
  +                existingRights = new boolean[NUMBER_OF_RIGHTS];
  +                System.arraycopy(NO_RIGHTS, 0, existingRights, 0,
  +                                 NUMBER_OF_RIGHTS);
  +            }
  +        }
  +
  +        boolean change;
  +        boolean[] rights = new boolean[NUMBER_OF_RIGHTS];
  +
  +        if (mods[0] == ADD_RIGHTS) {
  +            change = true;
  +            System.arraycopy(existingRights, 0, rights, 0,
  +                             NUMBER_OF_RIGHTS);
  +        } else if (mods[0] == REMOVE_RIGHTS) {
  +            change = false;
  +            System.arraycopy(existingRights, 0, rights, 0,
  +                             NUMBER_OF_RIGHTS);
  +        } else {                                             // means replace
  +            System.arraycopy(NO_RIGHTS, 0, rights, 0,
  +                             NUMBER_OF_RIGHTS);
  +            char[] new_mods = new char[mods.length + 1];
  +            System.arraycopy(mods, 0, new_mods, 1, mods.length);
  +            mods = new_mods;
  +            change = true;
  +        }
  +
  +        for (int i=1; i <mods.length; i++) {
  +            switch(mods[i]) {
  +            case LOOKUP_RIGHTS: rights[LOOKUP] = change;
  +                break;
  +            case READ_RIGHTS: rights[READ] = change;
  +                break;
  +            case KEEP_SEEN_RIGHTS: rights[KEEP_SEEN] = change;
  +                break;
  +            case WRITE_RIGHTS: rights[WRITE] = change;
  +                break;
  +            case INSERT_RIGHTS: rights[INSERT] = change;
  +                break;
  +            case POST_RIGHTS: rights[POST] = change;
  +                break;
  +            case CREATE_RIGHTS: rights[CREATE] = change;
  +                break;
  +            case DELETE_RIGHTS: rights[DELETE] = change;
  +                break;
  +            case ADMIN_RIGHTS: rights[ADMIN] = change;
  +                break;
  +            default: return false;
  +            }
  +        }
  +
  +        //  All rights above lookup require lookup
  +        if(rights[LOOKUP] == false  &&  !Arrays.equals(rights, NO_RIGHTS)) {
  +            return false;
  +        }
  +        // Each right requires all the rights before it.
  +        int count = 0;
  +        for (int i=1; i< NUMBER_OF_RIGHTS; i++) {
  +            if(rights[i-1] ^ rights[i]) {
  +                count++;
  +            }
  +        }
  +        switch (count) {
  +        case 0:                              // now Admin or deleted
  +            if (rights[ADMIN]) {
  +                acl.put(identifier, rights);
  +                break;
  +            } else {
  +                if (otherAdmin(identifier)) {
  +                    acl.remove(identifier);
  +                    break;
  +                } else {
  +                    return false;
  +                }
  +            }
  +        case 2:              // not allowed
  +            return false;
  +        case 1:             // not Admin, check there remains an Admin
  +            // Iterator namesIt = acl.keySet().iterator();
  +            //boolean otherAdmin = false;
  +            //while(namesIt.hasNext() && !otherAdmin) {
  +            //String name = (String)namesIt.next();
  +            //if (name != identifier) {
  +            //    boolean[] otherRights = (boolean[]) acl.get(name);
  +            //        otherAdmin = otherRights[ADMIN];
  +            //}
  +            //}
  +            if (otherAdmin(identifier)) {
  +                acl.put(identifier, rights);
  +                break;
  +            } else {
  +                return false;
  +            }
  +        default:             // not allowed
  +            return false;
  +        }
  +        writeMailbox();
  +        return true;
  +    }
  +
  +    /**
  +     * Check there is a person other than identifier who has Admin rights.
  +     */
  +    private boolean otherAdmin(String identifier) {
  +        Iterator namesIt = acl.keySet().iterator();
  +        boolean result = false;
  +        while(namesIt.hasNext() && !result) {
  +            String name = (String)namesIt.next();
  +            if (!name.equals(identifier)) {
  +                boolean[] otherRights = (boolean[]) acl.get(name);
  +                result = otherRights[ADMIN];
  +            }
  +        }
  +        return result;
  +    }
  +
  +    /**
  +     * Retrieve access rights for a specific identity.
  +     *
  +     * @param getter String representing user attempting to get the rights,
  +     * must be non-null and non-empty
  +     * @param identity String representing user whose rights are being got,
  +     * must be non-null and non-empty
  +     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  +     * rights in this mailbox.
  +     * @throws AccessControlException if getter does not have lookup rights for
  +     * this mailbox (ie they should not know this mailbox exists).
  +     * @throws AuthorizationException if implementation does not wish to expose
  +     * ACL for this identity to this getter.
  +     */
  +    public String getRights(String getter, String identity)
  +        throws AccessControlException, AuthorizationException {
  +        boolean[] gettersRights = (boolean[])  acl.get(getter);
  +        if (gettersRights == null
  +            || (gettersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  +            throw new AuthorizationException(DENY_AUTH + getter);
  +        }
  +        boolean[] rights = (boolean[]) acl.get(identity);
  +        if (rights == null) {
  +            return null;
  +        } else {
  +            StringBuffer buf = new StringBuffer(NUMBER_OF_RIGHTS);
  +            for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
  +                if (rights[i]) {
  +                    buf.append(RIGHTS[i]);
  +                }
  +            }
  +            return buf.toString();
  +        }
  +    }
  +
  +    /**
  +     * Retrieves a String of one or more <identity space rights> who have
  +     * rights in this ACL
  +     *
  +     * @param getter String representing user attempting to get the rights,
  +     * must be non-null and non-empty
  +     * @returns String of rights sets usingrfc2086 syntax
  +     * @throws AccessControlException if getter does not have lookup rights for
  +     * this mailbox (ie they should not know this mailbox exists).
  +     * @throws AuthorizationException if implementation does not wish to expose
  +     * ACL to this getter.
  +     */
  +    public String getAllRights(String getter)
  +        throws AccessControlException, AuthorizationException {
  +        boolean[] gettersRights = (boolean[]) acl.get(getter);
  +        if (gettersRights == null
  +            || (gettersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        } else if ( gettersRights[ADMIN] == false) {
  +            throw new AuthorizationException(DENY_AUTH + getter);
  +        }
  +        Iterator namesIt = acl.keySet().iterator();
  +        StringBuffer response = new StringBuffer(20*acl.size());
  +        while(namesIt.hasNext()) {
  +            String name = (String)namesIt.next();
  +            response.append("<" + name + " ");
  +            boolean[] rights = (boolean[]) acl.get(name);
  +            for (int i = 0; i<NUMBER_OF_RIGHTS; i++) {
  +                if (rights[i]) {
  +                    response.append(RIGHTS[i]);
  +                }
  +            }
  +            response.append("> ");
  +        }
  +
  +        return response.toString();
  +    }
  +
  +    /**
  +     * Retrieve rights which will always be granted to the specified identity.
  +     *
  +     * @param getter String representing user attempting to get the rights,
  +     * must be non-null and non-empty
  +     * @param identity String representing user whose rights are being got,
  +     * must be non-null and non-empty
  +     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  +     * guaranteed rights in this mailbox.
  +     * @throws AccessControlException if getter does not have lookup rights for
  +     * this mailbox (ie they should not know this mailbox exists).
  +     * @throws AuthorizationException if implementation does not wish to expose
  +     * ACL for this identity to this getter.
  +     */
  +    public String getRequiredRights(String getter, String identity)
  +        throws AccessControlException, AuthorizationException {
  +        boolean[] gettersRights = (boolean[]) acl.get(getter);
  +        if (gettersRights == null
  +            || (gettersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  +            throw new AuthorizationException(DENY_AUTH + getter);
  +        }
  +
  +        return "\"\"";
  +    }
  +
  +    /**
  +     * Retrieve rights which may be granted to the specified identity.
  +     * @param getter String representing user attempting to get the rights,
  +     * must be non-null and non-empty
  +     * @param identity String representing user whose rights are being got,
  +     * must be non-null and non-empty
  +     * @returns String of rights usingrfc2086 syntax, empty if identity has no
  +     * guaranteed rights in this mailbox.
  +     * @throws AccessControlException if getter does not have lookup rights for
  +     * this mailbox (ie they should not know this mailbox exists).
  +     * @throws AuthorizationException if implementation does not wish to expose
  +     * ACL for this identity to this getter.
  +     */
  +    public String getOptionalRights(String getter, String identity)
  +        throws AccessControlException, AuthorizationException {
  +        boolean[] gettersRights = (boolean[]) acl.get(getter);
  +        if (gettersRights == null
  +            || (gettersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        } else if (!getter.equals(identity) && gettersRights[ADMIN] == false) {
  +            throw new AuthorizationException(DENY_AUTH + getter);
  +        }
  +
  +        return OPTIONAL_RIGHTS;
  +    }
  +
  +    /**
  +     * Helper boolean methods.
  +     * Provided for cases where you need to check the ACL before selecting the
  +     * mailbox.
  +     *
  +     * @param username String representing user
  +     * @returns true if user has the requested right.
  +     * &throws AccessControlException if username does not have lookup rights.
  +     * (Except for hasLookupRights which just returns false.
  +     */
  +    public boolean hasLookupRights(String username) {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        return (( usersRights == null || (usersRights[LOOKUP] == false))
  +                ? false : true);
  +    }
  +
  +    public boolean hasReadRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[READ];
  +    }
  +
  +    public boolean hasKeepSeenRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[KEEP_SEEN];
  +    }
  +
  +    public boolean hasWriteRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[WRITE];
  +    }
  +
  +    public boolean hasInsertRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[INSERT];
  +    }
  +
  +    public boolean hasCreateRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[CREATE];
  +    }
  +
  +    public boolean hasDeleteRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[DELETE];
  +    }
  +
  +    public boolean hasAdminRights(String username)
  +        throws AccessControlException {
  +        boolean[] usersRights = (boolean[]) acl.get(username);
  +        if (usersRights == null  || (usersRights[LOOKUP] == false)) {
  +            throw new AccessControlException(DENY_ACCESS);
  +        }
  +        return usersRights[ADMIN];
  +    }
  +
  +    // Mailbox methods using the ACL ---------------------------
  +
  +    /**
  +     * Indicates if this folder may be selected by the specified user. Requires
  +     * user to have at least read rights. It does not indicate whether user
  +     * can write to mailbox
  +     *
  +     * @param username String represnting user
  +     * @returns boolean TRUE if specified user can Select mailbox.
  +     * @throws AccessControlException if username does not have lookup rights
  +     */
  +    public  synchronized  boolean isSelectable(String username)
  +        throws AccessControlException {
  +        return ( ! notSelectableByAnyone && hasReadRights(username) );
  +    }
  +
  +    /**
  +     * Indicates if specified user can change any flag on a permanent basis,
  +     * except for \Recent which can never be changed by a user.
  +     *
  +     * @param username String represnting user
  +     * @returns true if specified user can change all flags permanently.
  +     */
  +    public synchronized boolean allFlags(String username)
  +        throws AccessControlException {
  +        // relies on implementation that each right implies those
  +        // before it in list:  l,r,s,w,i,p,c,d,a
  +        return hasDeleteRights(username);
  +    }
  +
  +    /**
  +     * Indicates which flags this user can change permanently. If allFlags()
  +     * returns true for this user, then this method must have the same return
  +     * value as getSupportedFlags.
  +     *
  +     * @param username String represnting user
  +     * @returns String a space seperated list of message flags which this user
  +     * can set permanently
  +     */
  +    public  synchronized  String getPermanentFlags(String username)
  +        throws AccessControlException {
  +        if (hasDeleteRights(username)) {
  +            return SYSTEM_FLAGS;
  +        } else if (hasWriteRights(username)) {
  +            return "\\Seen \\Answered \\Flagged \\Draft";
  +        } else if (hasKeepSeenRights(username)) {
  +            return "\\Seen";
  +        } else {
  +            return "";
  +        }
  +    }
  +
  +    /**
  +     * Provides a reference to the access control list for this mailbox.
  +     *
  +     * @returns the AccessControlList for this Mailbox
  +     */
  +    //   public ACL getACL();
  +
  +    /**
  +     * Indicates state in which  the mailbox will be opened by specified user.
  +     * A return value of true indicates Read Only, false indicates Read-Write
  +     * and an AccessControlException is thrown if user does not have read
  +     * rights.
  +     * <p>Implementations decide if Read Only means only lookup and read
  +     * rights (lr) or lookup, read and keep seen rights (lrs). This may even
  +     * vary between mailboxes.
  +     *
  +     * @param username String represnting user
  +     * @returns true if specified user can only open the mailbox Read-Only.
  +     * @throws AccessControlException if the user can not open this mailbox
  +     * at least Read-Only.
  +     */
  +    public synchronized boolean isReadOnly(String username)
  +        throws AccessControlException {
  +        return (! hasWriteRights(username));
  +    }
  +
  +    // Message handling methods ---------------------------
  +
  +    /**
  +     * Stores a message in this mailbox. User must have insert rights.
  +     *
  +     * @param message the MimeMessage to be stored
  +     * @param username String represnting user
  +     * @returns boolean true if successful
  +     * @throws AccessControlException if username does not have lookup rights
  +     * for this mailbox.
  +     * @throws AuthorizationException if username has lookup rights but does
  +     * not have insert rights.
  +     */
  +    public synchronized boolean store(MimeMessage message, String username)
  +        throws AccessControlException, AuthorizationException,
  +               IllegalArgumentException {
  +
  +        if (message == null || username == null) {
  +            getLogger().error("Null argument received in store.");
  +            throw new IllegalArgumentException("Null argument received in store.");
  +        }
  +        if (!hasInsertRights(username)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to insert.");
  +        }
  +
  +        SimpleMessageAttributes attrs = new SimpleMessageAttributes();
  +        try {
  +            setupLogger(attrs);
  +            attrs.setAttributesFor(message);
  +        } catch (javax.mail.MessagingException me) {
  +            throw new RuntimeException("Exception creating SimpleMessageAttributes: " + me);
  +        }
  +        Flags flags = new Flags();
  +        flags.initialize();
  +        return store(message, username, attrs, flags);
  +    }
  +
  +    /**
  +     * Stores a message in this mailbox, using passed MessageAttributes and
  +     * Flags. User must have insert rights.
  +     * <br>Current implementation requires MessageAttributs to be of
  +     * class SimpleMessageAttributes
  +     *
  +     * @param mail the message to be stored
  +     * @param username String represnting user
  +     * @param msgAttrs non-null MessageAttributes for use with this Message
  +     * @returns boolean true if successful
  +     * @throws AccessControlException if username does not have lookup
  +     * rights for this mailbox.
  +     * @throws AuthorizationException if username has lookup rights but does
  +     * not have insert rights.
  +     */
  +    public boolean store(MimeMessage message, String username,
  +                         MessageAttributes msgAttrs, Flags flags)
  +        throws AccessControlException, AuthorizationException,
  +               IllegalArgumentException {
  +
  +        if (msgAttrs == null || message == null || username == null) {
  +            getLogger().error("Null argument received in store.");
  +            throw new IllegalArgumentException("Null argument received in store.");
  +        }
  +        if (! (msgAttrs instanceof SimpleMessageAttributes)) {
  +            getLogger().error("Wrong class for Attributes");
  +            throw new IllegalArgumentException("Wrong class for Attributes");
  +        }
  +        SimpleMessageAttributes attrs = (SimpleMessageAttributes)msgAttrs;
  +
  +        highestUID.increase();
  +        int newUID = highestUID.get();
  +        attrs.setUID(newUID);
  +        sequence.add(new Integer(newUID));
  +        attrs.setMessageSequenceNumber(sequence.size());
  +
  +        BufferedOutputStream outMsg = null;
  +        ObjectOutputStream outAttrs = null;
  +
  +        try {
  +            // SK:UPDATE
  +            path = getPath( absoluteName, owner, rootPath );
  +            outMsg = new BufferedOutputStream( new FileOutputStream(path + File.separator + newUID + MESSAGE_EXTENSION));
  +            message.writeTo(outMsg);
  +            outMsg.close();
  +            outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + newUID + ATTRIBUTES_EXTENSION));
  +            outAttrs.writeObject(attrs);
  +            outAttrs.close();
  +        } catch(Exception e) {
  +            getLogger().error("Error writing message to disc: " + e);
  +            e.printStackTrace();
  +            throw new
  +                RuntimeException("Exception caught while storing Mail: "
  +                                 + e);
  +        } finally {
  +            try {
  +                outMsg.close();
  +                outAttrs.close();
  +            } catch (IOException ie) {
  +                getLogger().error("Error closing streams: " + ie);
  +            }
  +        }
  +        marked = true;
  +        if (flags.isRecent()) {
  +            recentMessages.add(new Integer(newUID));
  +        }
  +        if (flags.isDeleted()) {
  +            messagesForDeletion.add(new Integer(newUID));
  +        }
  +        //if (!flags.isSeen(username)) {
  +        //If a user had no unseen messages, they do, now.
  +        Iterator it = oldestUnseenMessage.keySet().iterator();
  +        while (it.hasNext()) {
  +            String user = (String)it.next();
  +            if ( ((Integer)oldestUnseenMessage.get(user)).intValue() == -1) {
  +                oldestUnseenMessage.put(user, new Integer(newUID));
  +            }
  +        }
  +        //}
  +        writeFlags(newUID, flags);
  +        getLogger().info("Mail " + newUID + " written in " + absoluteName);
  +
  +        return true;
  +    }
  +
  +    /**
  +     * Retrieves a message given a message sequence number.
  +     *
  +     * @param msn the message sequence number
  +     * @param username String represnting user
  +     * @returns an  MimeMessageWrapper object containing the message, null if no message with
  +     * the given msn.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have read rights.
  +     */
  +    public synchronized MimeMessageWrapper retrieve(int msn, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +
  +        if (msn > sequence.size()) {
  +            return null;
  +        } else {
  +            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  +            return retrieveUID(uid, user);
  +        }
  +    }
  +
  +
  +    /**
  +     * Retrieves a message given a unique identifier.
  +     *
  +     * @param uid the unique identifier of a message
  +     * @param username String represnting user
  +     * @returns an MimeMessageWrapper object containing the message, null if no message with
  +     * the given msn.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have read rights.
  +     */
  +    public synchronized MimeMessageWrapper retrieveUID(int uid, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        MimeMessageWrapper response = null;
  +        if (sequence.contains(new Integer(uid))) {
  +            //BufferedInputStream inMsg = null;
  +            try {
  +                path = getPath( absoluteName, owner, rootPath );
  +		MimeMessageFileSource source = new MimeMessageFileSource(path + File.separator + uid + MESSAGE_EXTENSION);
  +                response = new MimeMessageWrapper(source);
  +             //   inMsg.close();
  +            } catch(Exception e) {
  +                getLogger().error("Error reading message from disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caught while retrieving Mail: "
  +                                     + e);
  +            } //finally {
  +          //      try {
  +            //        inMsg.close();
  +          //      } catch (IOException ie) {
  +          //          getLogger().error("Error closing streams: " + ie);
  +          //      }
  +          //  }
  +            getLogger().info("MimeMessageWrapper " + uid + " read from " + absoluteName);
  +            return response;
  +        } else {
  +            return null;
  +        }
  +    }
  +
  +    /**
  +     * Marks a message for deletion given a message sequence number.
  +     *
  +     * @param msn the message sequence number
  +     * @param username String represnting user
  +     * @returns boolean true if successful.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized boolean markDeleted(int msn, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasDeleteRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to delete.");
  +        }
  +
  +        Assert.notImplemented();
  +        //TBD
  +        return false;
  +    }
  +
  +    /**
  +     * Marks a message for deletion given a unique identifier.
  +     *
  +     * @param uidunique identifier
  +     * @param username String represnting user
  +     * @returns boolean true if successful, false if failed including no
  +     * message with the given uid.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized boolean markDeletedUID(int uid, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasDeleteRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to delete.");
  +        }
  +
  +        Assert.notImplemented();
  +        //TBD
  +        return false;
  +    }
  +
  +    /**
  +     * Returns the message attributes for a message.
  +     *
  +     * @param msn message sequence number
  +     * @param username String represnting user
  +     * @returns MessageAttributes for message, null if no such message.
  +     * Changing the MessageAttributes object must not affect the actual
  +     * MessageAttributes.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized MessageAttributes getMessageAttributes(int msn, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        System.out.println("msn: "+msn);
  +        System.out.println("sequence.size: "+sequence.size());
  +        if (msn > sequence.size()) {
  +            return null;
  +        } else {
  +            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  +            return getMessageAttributesUID(uid, user);
  +        }
  +    }
  +
  +    /**
  +     * Returns the message attributes for a message.
  +     *
  +     * @param uid unique identifier
  +     * @param username String represnting user
  +     * @returns MessageAttributes for message, null if no such message.
  +     * Changing the MessageAttributes object must not affect the actual
  +     * MessageAttributes.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized MessageAttributes getMessageAttributesUID(int uid, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        System.out.println("getMessageAttributesUID()");
  +        System.out.println("uid: "+uid);
  +        System.out.println("user: "+user);
  +        System.out.println("sequence.size: "+sequence.size());
  +        SimpleMessageAttributes response = null;
  +        if (sequence.contains(new Integer(uid))) {
  +                System.out.println("reading from disk");
  +
  +            ObjectInputStream inAttrs = null;
  +            try {
  +                path = getPath( absoluteName, owner, rootPath );
  +                System.out.println( "FileInputStream("+(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  +                inAttrs = new ObjectInputStream( new FileInputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  +                System.out.println("inAttrs="+inAttrs);
  +                response = (SimpleMessageAttributes)inAttrs.readObject();
  +                System.out.println("response="+response);
  +                if (response != null) {
  +                System.out.println("response.parts="+response.parts);
  +                if (response.parts != null) {
  +                System.out.println("response.parts.len="+response.parts.length);
  +                System.out.println("response.parts[0]="+response.parts[0]);
  +                }
  +                }
  +                setupLogger(response);
  +            } catch(Exception e) {
  +                getLogger().error("Error reading attributes from disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caught while retrieving Message attributes: "
  +                                     + e);
  +            } finally {
  +                try {
  +                    inAttrs.close();
  +                } catch (IOException ie) {
  +                    getLogger().error("Error closing streams: " + ie);
  +                }
  +            }
  +            getLogger().info("MessageAttributes for " + uid + " read from " + absoluteName);
  +            return response;
  +        } else {
  +            return null;
  +        }
  +    }
  +
  +    /**
  +     * Updates the attributes of a message.This may be incorporated into setFlags().
  +     *
  +     * @param MessageAttributes of a message already in this Mailbox
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public boolean updateMessageAttributes(MessageAttributes attrs, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to store flags.");
  +        }
  +        int uid = attrs.getUID();
  +        if (sequence.contains(new Integer(uid))) {
  +
  +            // Really, we should check whether the exact change is authorized.
  +            ObjectOutputStream outAttrs = null;
  +            try {
  +                path = getPath( absoluteName, owner, rootPath );
  +                outAttrs = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + ATTRIBUTES_EXTENSION));
  +                outAttrs.writeObject(attrs);
  +                outAttrs.close();
  +            } catch(Exception e) {
  +                getLogger().error("Error writing message to disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caught while storing Attributes: "
  +                                     + e);
  +            } finally {
  +                try {
  +                    outAttrs.close();
  +                } catch (IOException ie) {
  +                    getLogger().error("Error closing streams: " + ie);
  +                }
  +            }
  +            getLogger().info("MessageAttributes for " + uid + " written in " + absoluteName);
  +
  +            return true;
  +        } else {
  +            return false;
  +        }
  +    }
  +
  +    /**
  +     * Get the IMAP-formatted String of flags for specified message.
  +     *
  +     * @param msn message sequence number for a message in this mailbox
  +     * @param username String represnting user
  +     * @returns flags for this message and user, null if no such message.
  +     * @throws AccessControlException if user does not have lookup rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have read rights.
  +     */
  +    public synchronized  String getFlags(int msn, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        if (msn > sequence.size()) {
  +            return null;
  +        } else {
  +            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  +            return getFlagsUID(uid, user);
  +        }
  +    }
  +
  +    /**
  +     * Get the IMAP-formatted String of flags for specified message.
  +     *
  +     * @param uid UniqueIdentifier for a message in this mailbox
  +     * @param username String represnting user
  +     * @returns flags for this message and user, null if no such message.
  +     * @throws AccessControlException if user does not have lookup rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have read rights.
  +     */
  +    public synchronized  String getFlagsUID(int uid, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        java.util.Iterator it = sequence.iterator();
  +        while(it.hasNext()) 
  +            System.out.println("FILEMESSAGES...."+it.next().toString());
  +            
  +        
  +        if (!sequence.contains(new Integer(uid))) {
  +            System.out.println("SEQUENCENOOO");
  +            return null;
  +        } else {
  +            System.out.println("FLAGSRETURNED");
  +            Flags flags = readFlags(uid);
  +            return flags.getFlags(user);
  +        }
  +    }
  +    /**
  +     * Updates the flags for a message.
  +     *
  +     * @param msn MessageSequenceNumber of a message already in this Mailbox
  +     * @param username String represnting user
  +     * @param request IMAP-formatted String representing requested change to
  +     * flags.
  +     * @returns true if succeeded, false otherwise, including no such message
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized  boolean setFlags(int msn, String user, String request)
  +        throws AccessControlException, AuthorizationException,
  +               IllegalArgumentException {
  +        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to store any flags.");
  +        }
  +        if (msn > sequence.size()) {
  +            return false;
  +        } else {
  +            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  +            return setFlagsUID(uid, user, request);
  +        }
  +    }
  +
  +    /**
  +     * Updates the flags for a message.
  +     *
  +     * @param uid Unique Identifier of a message already in this Mailbox
  +     * @param username String represnting user
  +     * @param request IMAP-formatted String representing requested change to
  +     * flags.
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has lookup rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized boolean setFlagsUID(int uid, String user, String request)
  +        throws AccessControlException, AuthorizationException,
  +               IllegalArgumentException {
  +        if (!hasKeepSeenRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to store any flags.");
  +        }
  +        if ((request.toUpperCase().indexOf("DELETED") != -1) && (!hasDeleteRights(user))) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to delete.");
  +        }
  +        if (sequence.contains(new Integer(uid))) {
  +
  +            Flags flags = readFlags(uid);
  +            boolean wasRecent = flags.isRecent();
  +            boolean wasDeleted = flags.isDeleted();
  +            boolean wasSeen = flags.isSeen(user);
  +
  +            if  (flags.setFlags(request, user)) {
  +
  +                if (flags.isDeleted()) {
  +                    if (! wasDeleted) { messagesForDeletion.add(new Integer(uid)); }
  +                }
  +                if (flags.isSeen(user) != wasSeen) {
  +                    if (flags.isSeen(user)) {
  +                        int previousOld = ((Integer)oldestUnseenMessage.get(user)).intValue();
  +                        if (uid == previousOld) {
  +                            int newOld = findOldestUnseen(user, previousOld);
  +                            oldestUnseenMessage.put(user, (new Integer(newOld)));
  +                        }
  +                    } else { // seen flag unset
  +                        if (uid < ((Integer)oldestUnseenMessage.get(user)).intValue()) {
  +                            oldestUnseenMessage.put(user, (new Integer(uid)));
  +                        }
  +                    }
  +                }
  +
  +                writeFlags(uid, flags);
  +                getLogger().debug("Flags for message uid " + uid + " in " + absoluteName + " updated.");
  +                return true;
  +            } else {
  +                return false;
  +            }
  +        } else {
  +            return false;
  +        }
  +
  +    }
  +
  +    private int findOldestUnseen(String user, int previousOld)
  +        throws AccessControlException, AuthorizationException {
  +        int response = 0; //indicates no unseen messages
  +        try {
  +            ListIterator lit = sequence.listIterator(previousOld);
  +            boolean found = false;
  +            while (!found && lit.hasNext() ) {
  +                int uid = ((Integer)lit.next()).intValue();
  +                Flags flags = readFlags(uid);
  +                if (!flags.isSeen(user)) {
  +                    response = uid;
  +                    found = true;
  +                }
  +            }
  +        }catch(Exception e) { 
  +            // (because) BUG: Do nothing. Have investigated an error on fetching sequence.listIterator(previousOld);
  +            // with an error - but currently I don't know why :)
  +        }finally{
  +            return response;
  +        }
  +    }
  +
  +    private Flags readFlags(int uid) {
  +        Flags response = null;
  +        if (sequence.contains(new Integer(uid))) {
  +            ObjectInputStream inFlags = null;
  +            try {
  +                path = getPath( absoluteName, owner, rootPath );
  +                inFlags = new ObjectInputStream( new FileInputStream(path + File.separator + uid + FLAGS_EXTENSION));
  +                response = (Flags)inFlags.readObject();
  +            } catch(Exception e) {
  +                getLogger().error("Error reading flags from disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caught while retrieving Message flags: "
  +                                     + e);
  +            } finally {
  +                try {
  +                    inFlags.close();
  +                } catch (IOException ie) {
  +                    getLogger().error("Error closing streams: " + ie);
  +                }
  +            }
  +            getLogger().info("Flags for " + uid + " read from " + absoluteName);
  +        }
  +        return response;
  +    }
  +
  +    private boolean writeFlags(int uid, Flags flags) {
  +        if (sequence.contains(new Integer(uid))) {
  +            ObjectOutputStream outFlags = null;
  +            try {
  +                path = getPath( absoluteName, owner, rootPath );
  +                outFlags = new ObjectOutputStream( new FileOutputStream(path + File.separator + uid + FLAGS_EXTENSION));
  +                outFlags.writeObject(flags);
  +                outFlags.close();
  +            } catch(Exception e) {
  +                getLogger().error("Error writing message to disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caught while storing Flags: "
  +                                     + e);
  +            } finally {
  +                try {
  +                    outFlags.close();
  +                } catch (IOException ie) {
  +                    getLogger().error("Error closing streams: " + ie);
  +                }
  +            }
  +            getLogger().info("Flags for " + uid + " written in " + absoluteName);
  +            writeMailbox();
  +            return true;
  +        } else {
  +            writeMailbox();
  +            return false;
  +        }
  +    }
  +
  +    /**
  +     * Removes all messages marked Deleted.  User must have delete rights.
  +     *
  +     * @param username String represnting user
  +     * @returns true if successful
  +     * @throws AccessControlException if user does not have read rights for
  +     * this mailbox.
  +     * @throws AuthorizationException if user has delete rights but does not
  +     * have delete rights.
  +     */
  +    public synchronized boolean expunge(String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasDeleteRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to delete for user '" + user + "'.");
  +        }
  +        Iterator it = messagesForDeletion.iterator();
  +
  +        while (it.hasNext()) {
  +            Integer uidObj = (Integer)it.next();
  +            int uid = uidObj.intValue();
  +            if (sequence.contains(uidObj)) {
  +                try  {
  +                    //SAM
  +                    try
  +                    {
  +                        MimeMessageWrapper message = retrieveUID(uid, user);
  +                        System.out.println("(before)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
  +                        System.out.println("decre message.getMessageSize() = " + (int)message.getMessageSize());
  +                        mailboxSize -= (int)message.getMessageSize();
  +                        System.out.println("(after)decrementing mailboxSize ("+getName()+") = " + mailboxSize);
  +                    }
  +                    catch (MessagingException me)
  +                    {
  +                            //ignore
  +                    }
  +                    //END
  +                    path = getPath( absoluteName, owner, rootPath );
  +                    final File msgFile = new File(path + File.separator + uid + MESSAGE_EXTENSION );
  +                    msgFile.delete();
  +                    final File attrFile = new File(path + File.separator + uid + ATTRIBUTES_EXTENSION );
  +                    attrFile.delete();
  +                    //SAM
  +                    final File flagFile = new File(path + File.separator + uid + FLAGS_EXTENSION );
  +                    flagFile.delete();
  +                    //END
  +                    sequence.remove(uidObj);
  +                } catch ( final Exception e )  {
  +                    throw new RuntimeException( "Exception caught while removing" +
  +                                                " a message: " + e );
  +                }
  +            }
  +        }
  +
  +        for (int i = 0; i < sequence.size(); i++) {
  +            System.err.println("Message with msn " + i + " has uid " + sequence.get(i));
  +        }
  +        writeMailbox();
  +        return true;
  +    }
  +
  +    private void writeMailbox() {
  +        String mailboxRecordFile = path + File.separator + MAILBOX_FILE_NAME;
  +        ObjectOutputStream out = null;
  +        FileOutputStream fout = null;
  +        try {
  +            fout = new FileOutputStream( mailboxRecordFile );
  +            out = new ObjectOutputStream( fout );
  +            out.writeObject(this);
  +            out.flush();
  +            out.close();
  +            fout.flush();
  +            fout.close();
  +        } catch(Exception e) {
  +            if (out != null) {
  +                try {
  +                    out.close();
  +                } catch (Exception ignored) {
  +                }
  +            }
  +            if (fout != null) {
  +                try {
  +                    fout.close();
  +                } catch (Exception ignored) {
  +                }
  +            }
  +            e.printStackTrace();
  +            throw new
  +                RuntimeException("Exception caught while storing Mailbox: " + e);
  +        }
  +        getLogger().info("FileMailbox written: " + absoluteName);
  +    }
  +
  +
  +    /**
  +     * Lists uids of messages in mailbox indexed by MSN.
  +     *
  +     * @param username String represnting user
  +     * @returns List of Integers wrapping uids of message
  +     */
  +    public List listUIDs(String user) {
  +        return new ArrayList(Collections.unmodifiableList(sequence));
  +    }
  +
  +    public Set getUsersWithLookupRights() {
  +        Set response = new  HashSet();
  +        Iterator it = acl.keySet().iterator();
  +        while (it.hasNext()) {
  +            String user = (String) it.next();
  +            boolean[] rights = (boolean[]) acl.get(user);
  +            if (rights[LOOKUP] == true) {
  +                response.add(user);
  +            }
  +        }
  +        return response;
  +    }
  +
  +    public Set getUsersWithReadRights() {
  +        Set response = new  HashSet();
  +        Iterator it = acl.keySet().iterator();
  +        while (it.hasNext()) {
  +            String user = (String) it.next();
  +            boolean[] rights = (boolean[]) acl.get(user);
  +            if (rights[READ] == true) {
  +                response.add(user);
  +            }
  +        }
  +        return response;
  +    }
  +
  +    public Map getUnseenByUser() {
  +        Map response = new HashMap();
  +        Iterator it = oldestUnseenMessage.keySet().iterator();
  +        while (it.hasNext()) {
  +            String user = (String) it.next();
  +            Integer uidObj = ((Integer)oldestUnseenMessage.get(user));
  +            int oldUID = uidObj.intValue();
  +            if (oldUID == 0) {
  +                response.put(user, uidObj);
  +            } else {
  +                int count = 0;
  +                ListIterator lit
  +                    = sequence.listIterator(sequence.indexOf(uidObj));
  +                while (lit.hasNext() ) {
  +                    int uid = ((Integer)lit.next()).intValue();
  +                    Flags flags = readFlags(uid);
  +                    if (!flags.isSeen(user)) {
  +                        count ++;
  +                    }
  +                }
  +                response.put(user, new Integer(count));
  +            }
  +        }
  +        return response;
  +    }
  +
  +
  +    public InternetHeaders getInternetHeaders(int msn, String user)
  +        throws AccessControlException, AuthorizationException {
  +        if (!hasReadRights(user)) { //throws AccessControlException
  +            throw new AuthorizationException("Not authorized to read.");
  +        }
  +        if (msn > sequence.size()) {
  +            return null;
  +        } else {
  +            int uid = ((Integer)sequence.get(msn - 1)).intValue();
  +            return getInternetHeadersUID(uid, user);
  +        }
  +    }
  +
  +    public InternetHeaders getInternetHeadersUID(int uid, String user)
  +        throws AccessControlException, AuthorizationException {
  +        InternetHeaders response = null;
  +        if (sequence.contains(new Integer(uid))) {
  +            BufferedInputStream inMsg = null;
  +            try {
  +                inMsg = new BufferedInputStream( new FileInputStream(path + File.separator + uid + MESSAGE_EXTENSION));
  +                response = new InternetHeaders(inMsg);
  +                inMsg.close();
  +            } catch(Exception e) {
  +                getLogger().error("Error reading headers of message from disc: " + e);
  +                e.printStackTrace();
  +                throw new
  +                    RuntimeException("Exception caughtt while retrieving InternetHeaders: "    + e);
  +            } finally {
  +                try {
  +                    inMsg.close();
  +                } catch (IOException ie) {
  +                    getLogger().error("Error closing streams: " + ie);
  +                }
  +            }
  +            getLogger().info("InternetHeaders for message " + uid + " read from "
  +                        + absoluteName);
  +            return response;
  +        } else {
  +            return null;
  +        }
  +    }
  +
  +    /**
  +     * Returns true if the named user is subscribed to this Mailbox.
  +     */
  +    public boolean isSubscribed( String userName )
  +    {
  +        return subscribedUsers.contains( userName.toLowerCase() );
  +    }
  +
  +    /**
  +     * Subscribes a user to this Mailbox.
  +     */
  +    public void subscribe( String userName )
  +    {
  +        subscribedUsers.add( userName.toLowerCase() );
  +    }
  +
  +    /**
  +     * Unsubscrive a user from this Mailbox.
  +     */
  +    public void unsubscribe( String userName )
  +    {
  +        subscribedUsers.remove( userName.toLowerCase() );
  +    }
  +}
  +
  +
  +
  
  
  
  1.1                  jakarta-james/proposals/imap/java/org/apache/james/imapserver/FileStoreHighestUID.java
  
  Index: FileStoreHighestUID.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.imapserver;
  
  import java.io.*;
  import java.util.*;
  
  /**
   * Reference: RFC 2060
   * @author <a href="mailto:s@rapi.com">Stephan Schiessling</a>
   * @version 0.1 on 15 Aug 2002
   */
  public class FileStoreHighestUID implements HighestUID {
  
      private int highestUID;
      private int whenToWrite;
      private static final int WRITE_STEP = 3;
      private File file;
    
      public FileStoreHighestUID(File f) {
          file = f;
          highestUID = 0;
      
          if (file.exists()) {
              ObjectInputStream is = null;
              try {
                  is = new ObjectInputStream(new FileInputStream(file));
                  Integer i = (Integer) is.readObject();
                  highestUID = i.intValue();
                  is.close();
                  is = null;
              } catch (Exception ex) {
                  // log here
                  ex.printStackTrace();
                  if (is != null) {
                      try {
                          is.close();
                      } catch (Exception ignored) {}
                  }
                  throw new RuntimeException("Could not load highestUID!");
              }
              // maybe james was stopped without writing correct highestUID, therefore add
              // STEP_HIGHEST_UID, to ensure uniqeness of highestUID.
              highestUID += WRITE_STEP;
          }
          write();
          whenToWrite = highestUID+WRITE_STEP;
          System.out.println("Initialized highestUID="+highestUID);
      }
    
      public synchronized int get() {
          return highestUID;
      }
    
      public synchronized void increase() {
          highestUID++;
          if (highestUID >= whenToWrite) {
              // save this highestUID
              whenToWrite = highestUID+WRITE_STEP;
              // make it persistent
              write();
          }
      }
    
      private void write() {
          ObjectOutputStream os = null;
          try {
              os = new ObjectOutputStream( new FileOutputStream(file));
              os.writeObject(new Integer(highestUID));
              os.close();
              os = null;
          } catch (Exception ex) {
              // log here
              ex.printStackTrace();
              if (os != null) {
                  try {
                      os.close();
                  } catch (Exception ignored) {}
              }
              throw new RuntimeException("Failed to save highestUID!");
          }
      }
  }
  
  
  
  1.1                  jakarta-james/proposals/imap/java/org/apache/james/imapserver/HighestUID.java
  
  Index: HighestUID.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.imapserver;
  
  /**
   * Reference: RFC 2060
   * @author <a href="mailto:s@rapi.com">Stephan Schiessling</a>
   * @version 0.1 on 15 Aug 2002
   */
  public interface HighestUID {
  
     int get();
     void increase();
  
  }
  
  
  
  1.3       +9 -1      jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/AppendCommand.java
  
  Index: AppendCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap/java/org/apache/james/imapserver/commands/AppendCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AppendCommand.java	9 Aug 2002 19:03:50 -0000	1.2
  +++ AppendCommand.java	14 Sep 2002 08:35:21 -0000	1.3
  @@ -160,7 +160,15 @@
                   return true;
               }
               
  -            MimeMessageInputStreamSource source = new MimeMessageInputStreamSource("Mail" + System.currentTimeMillis() + "-" + mailbox.getNextUID(), new ByteArrayInputStream(byteout.toByteArray()));
  +            MimeMessageInputStreamSource source;
  +            try {
  +                source =
  +                    new MimeMessageInputStreamSource("Mail" + System.currentTimeMillis() + "-" + mailbox.getNextUID(), 
  +                                                     new ByteArrayInputStream(byteout.toByteArray()));
  +            } catch (MessagingException me) {
  +                me.printStackTrace();
  +                return false;
  +            }
               MimeMessageWrapper msg = new MimeMessageWrapper(source);
   
               try{
  
  
  

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


Mime
View raw message