You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by jo...@apache.org on 2006/10/09 19:15:42 UTC

svn commit: r454432 [12/14] - in /james/server/sandbox/imap-integration: ./ lib/ src/java/ src/java/org/apache/james/imapserver/ src/java/org/apache/james/imapserver/commands/ src/java/org/apache/james/imapserver/debug/ src/java/org/apache/james/imapse...

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/util/SqlResources.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/util/SqlResources.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/util/SqlResources.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/util/SqlResources.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,371 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+package org.apache.james.mailboxmanager.util;
+
+import org.apache.oro.text.perl.MalformedPerl5PatternException;
+import org.apache.oro.text.perl.Perl5Util;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * Provides a set of SQL String resources (eg SQL Strings)
+ * to use for a database connection.
+ * This class allows SQL strings to be customised to particular
+ * database products, by detecting product information from the
+ * jdbc DatabaseMetaData object.
+ * 
+ */
+public class SqlResources
+{
+    /**
+     * A map of statement types to SQL statements
+     */
+    private Map m_sql = new HashMap();
+
+    /**
+     * A map of engine specific options
+     */
+    private Map m_dbOptions = new HashMap();
+
+    /**
+     * A set of all used String values
+     */
+    static private Map stringTable = java.util.Collections.synchronizedMap(new HashMap());
+
+    /**
+     * A Perl5 regexp matching helper class
+     */
+    private Perl5Util m_perl5Util = new Perl5Util();
+
+    /**
+     * Configures a DbResources object to provide SQL statements from a file.
+     * 
+     * SQL statements returned may be specific to the particular type
+     * and version of the connected database, as well as the database driver.
+     * 
+     * Parameters encoded as $(parameter} in the input file are
+     * replace by values from the parameters Map, if the named parameter exists.
+     * Parameter values may also be specified in the resourceSection element.
+     * 
+     * @param sqlFile    the input file containing the string definitions
+     * @param sqlDefsSection
+     *                   the xml element containing the strings to be used
+     * @param conn the Jdbc DatabaseMetaData, taken from a database connection
+     * @param configParameters a map of parameters (name-value string pairs) which are
+     *                   replaced where found in the input strings
+     */
+    public void init(URL url, String sqlDefsSection,
+                     Connection conn, Map configParameters)
+        throws Exception
+    {
+        // Parse the sqlFile as an XML document.
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document sqlDoc = builder.parse(url.openStream());
+
+        // First process the database matcher, to determine the
+        //  sql statements to use.
+        Element dbMatcherElement = 
+            (Element)(sqlDoc.getElementsByTagName("dbMatchers").item(0));
+        String dbProduct = null;
+        if ( dbMatcherElement != null ) {
+            dbProduct = matchDbConnection(conn, dbMatcherElement);
+            m_perl5Util = null;     // release the PERL matcher!
+        }
+
+        // Now get the options valid for the database product used.
+        Element dbOptionsElement = 
+            (Element)(sqlDoc.getElementsByTagName("dbOptions").item(0));
+        if ( dbOptionsElement != null ) {
+            // First populate the map with default values 
+            populateDbOptions("", dbOptionsElement, m_dbOptions);
+            // Now update the map with specific product values
+            if ( dbProduct != null ) {
+                populateDbOptions(dbProduct, dbOptionsElement, m_dbOptions);
+            }
+        }
+
+        
+        // Now get the section defining sql for the repository required.
+        NodeList sections = sqlDoc.getElementsByTagName("sqlDefs");
+        int sectionsCount = sections.getLength();
+        Element sectionElement = null;
+        boolean found = false;
+        for (int i = 0; i < sectionsCount; i++ ) {
+            sectionElement = (Element)(sections.item(i));
+            String sectionName = sectionElement.getAttribute("name");
+            if ( sectionName != null && sectionName.equals(sqlDefsSection) ) {
+                found = true;
+                break;
+            }
+
+        }
+        if ( !found ) {
+            StringBuffer exceptionBuffer =
+                new StringBuffer(64)
+                        .append("Error loading sql definition file. ")
+                        .append("The element named \'")
+                        .append(sqlDefsSection)
+                        .append("\' does not exist.");
+            throw new RuntimeException(exceptionBuffer.toString());
+        }
+
+        // Get parameters defined within the file as defaults,
+        // and use supplied parameters as overrides.
+        Map parameters = new HashMap();
+        // First read from the <params> element, if it exists.
+        Element parametersElement = 
+            (Element)(sectionElement.getElementsByTagName("parameters").item(0));
+        if ( parametersElement != null ) {
+            NamedNodeMap params = parametersElement.getAttributes();
+            int paramCount = params.getLength();
+            for (int i = 0; i < paramCount; i++ ) {
+                Attr param = (Attr)params.item(i);
+                String paramName = param.getName();
+                String paramValue = param.getValue();
+                parameters.put(paramName, paramValue);
+            }
+        }
+        // Then copy in the parameters supplied with the call.
+        parameters.putAll(configParameters);
+
+        // 2 maps - one for storing default statements,
+        // the other for statements with a "db" attribute matching this 
+        // connection.
+        Map defaultSqlStatements = new HashMap();
+        Map dbProductSqlStatements = new HashMap();
+
+        // Process each sql statement, replacing string parameters,
+        // and adding to the appropriate map..
+        NodeList sqlDefs = sectionElement.getElementsByTagName("sql");
+        int sqlCount = sqlDefs.getLength();
+        for ( int i = 0; i < sqlCount; i++ ) {
+            // See if this needs to be processed (is default or product specific)
+            Element sqlElement = (Element)(sqlDefs.item(i));
+            String sqlDb = sqlElement.getAttribute("db");
+            Map sqlMap;
+            if ( sqlDb.equals("")) {
+                // default
+                sqlMap = defaultSqlStatements;
+            }
+            else if (sqlDb.equals(dbProduct) ) {
+                // Specific to this product
+                sqlMap = dbProductSqlStatements;
+            }
+            else {
+                // for a different product
+                continue;
+            }
+
+            // Get the key and value for this SQL statement.
+            String sqlKey = sqlElement.getAttribute("name");
+            if ( sqlKey == null ) {
+                // ignore statements without a "name" attribute.
+                continue;
+            }
+            String sqlString = sqlElement.getFirstChild().getNodeValue();
+
+            // Do parameter replacements for this sql string.
+            Iterator paramNames = parameters.keySet().iterator();
+            StringBuffer replaceBuffer = new StringBuffer(64);
+            while ( paramNames.hasNext() ) {
+                String paramName = (String)paramNames.next();
+                String paramValue = (String)parameters.get(paramName);
+                replaceBuffer.append("${").append(paramName).append("}");
+                sqlString = substituteSubString(sqlString, replaceBuffer.toString(), paramValue);
+                if (paramNames.hasNext()) replaceBuffer.setLength(0);
+            }
+
+            // See if we already have registered a string of this value
+            String shared = (String) stringTable.get(sqlString);
+            // If not, register it -- we will use it next time
+            if (shared == null) {
+                stringTable.put(sqlString, sqlString);
+            } else {
+                sqlString = shared;
+            }
+
+            // Add to the sqlMap - either the "default" or the "product" map
+            sqlMap.put(sqlKey, sqlString);
+        }
+
+        // Copy in default strings, then overwrite product-specific ones.
+        m_sql.putAll(defaultSqlStatements);
+        m_sql.putAll(dbProductSqlStatements);
+    }
+
+    /**
+     * Compares the DatabaseProductName value for a jdbc Connection
+     * against a set of regular expressions defined in XML.
+     * The first successful match defines the name of the database product
+     * connected to. This value is then used to choose the specific SQL 
+     * expressions to use.
+     *
+     * @param conn the JDBC connection being tested
+     * @param dbMatchersElement the XML element containing the database type information
+     *
+     * @return the type of database to which James is connected
+     *
+     */
+    private String matchDbConnection(Connection conn, 
+                                     Element dbMatchersElement)
+        throws MalformedPerl5PatternException, SQLException
+    {
+        String dbProductName = conn.getMetaData().getDatabaseProductName();
+    
+        NodeList dbMatchers = 
+            dbMatchersElement.getElementsByTagName("dbMatcher");
+        for ( int i = 0; i < dbMatchers.getLength(); i++ ) {
+            // Get the values for this matcher element.
+            Element dbMatcher = (Element)dbMatchers.item(i);
+            String dbMatchName = dbMatcher.getAttribute("db");
+            StringBuffer dbProductPatternBuffer =
+                new StringBuffer(64)
+                        .append("/")
+                        .append(dbMatcher.getAttribute("databaseProductName"))
+                        .append("/i");
+
+            // If the connection databaseProcuctName matches the pattern,
+            // use the match name from this matcher.
+            if ( m_perl5Util.match(dbProductPatternBuffer.toString(), dbProductName) ) {
+                return dbMatchName;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets all the name/value pair db option couples related to the dbProduct,
+     * and put them into the dbOptionsMap.
+     *
+     * @param dbProduct the db product used
+     * @param dbOptionsElement the XML element containing the options
+     * @param dbOptionsMap the <CODE>Map</CODE> to populate
+     *
+     */
+    private void populateDbOptions(String dbProduct, Element dbOptionsElement, Map dbOptionsMap)
+    {
+        NodeList dbOptions = 
+            dbOptionsElement.getElementsByTagName("dbOption");
+        for ( int i = 0; i < dbOptions.getLength(); i++ ) {
+            // Get the values for this option element.
+            Element dbOption = (Element)dbOptions.item(i);
+            // Check is this element is pertinent to the dbProduct
+            // Notice that a missing attribute returns "", good for defaults
+            if (!dbProduct.equalsIgnoreCase(dbOption.getAttribute("db"))) {
+                continue;
+            }
+            // Put into the map
+            dbOptionsMap.put(dbOption.getAttribute("name"), dbOption.getAttribute("value"));
+        }
+    }
+
+    /**
+     * Replace substrings of one string with another string and return altered string.
+     * @param input input string
+     * @param find the string to replace
+     * @param replace the string to replace with
+     * @return the substituted string
+     */
+    private String substituteSubString( String input, 
+                                        String find,
+                                        String replace )
+    {
+        int find_length = find.length();
+        int replace_length = replace.length();
+
+        StringBuffer output = new StringBuffer(input);
+        int index = input.indexOf(find);
+        int outputOffset = 0;
+
+        while ( index > -1 ) {
+            output.replace(index + outputOffset, index + outputOffset + find_length, replace);
+            outputOffset = outputOffset + (replace_length - find_length);
+
+            index = input.indexOf(find, index + find_length);
+        }
+
+        String result = output.toString();
+        return result;
+    }
+
+    /**
+     * Returns a named SQL string for the specified connection,
+     * replacing parameters with the values set.
+     * 
+     * @param name   the name of the SQL resource required.
+     * @return the requested resource
+     */
+    public String getSqlString(String name)
+    {
+        return (String)m_sql.get(name);
+    }
+
+    /**
+     * Returns a named SQL string for the specified connection,
+     * replacing parameters with the values set.
+     * 
+     * @param name     the name of the SQL resource required.
+     * @param required true if the resource is required
+     * @return the requested resource
+     * @throws ConfigurationException
+     *         if a required resource cannot be found.
+     */
+    public String getSqlString(String name, boolean required)
+    {
+        String sql = getSqlString(name);
+
+        if (sql == null && required) {
+            StringBuffer exceptionBuffer =
+                new StringBuffer(64)
+                        .append("Required SQL resource: '")
+                        .append(name)
+                        .append("' was not found.");
+            throw new RuntimeException(exceptionBuffer.toString());
+        }
+        return sql;
+    }
+    
+    /**
+     * Returns the dbOption string value set for the specified dbOption name.
+     * 
+     * @param name the name of the dbOption required.
+     * @return the requested dbOption value
+     */
+    public String getDbOption(String name)
+    {
+        return (String)m_dbOptions.get(name);
+    }
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/FlaggedSessionMailboxWrapper.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/FlaggedSessionMailboxWrapper.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/FlaggedSessionMailboxWrapper.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/FlaggedSessionMailboxWrapper.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,43 @@
+package org.apache.james.mailboxmanager.wrapper;
+
+import javax.mail.Flags;
+
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxListener;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.mailbox.FlaggedMailbox;
+
+public class FlaggedSessionMailboxWrapper extends SessionMailboxWrapper {
+    
+    public FlaggedSessionMailboxWrapper(FlaggedMailbox flaggedMailbox) throws MailboxManagerException {
+    	super(flaggedMailbox);
+    }
+    
+    
+    public synchronized MessageResult[] expunge(GeneralMessageSet set, int result) throws MailboxManagerException {
+        return addMsnToResults(((FlaggedMailbox) mailbox).expunge(toUidSet(set), noMsnResult(result)),result);
+    }
+
+    public MessageResult getFirstUnseen(int result) throws MailboxManagerException {
+        return addMsnResult(((FlaggedMailbox) mailbox).getFirstUnseen(noMsnResult(result)),result);
+    }
+
+    public Flags getPermanentFlags() {
+        return ((FlaggedMailbox) mailbox).getPermanentFlags();
+    }
+
+    public int getRecentCount(boolean reset) throws MailboxManagerException {
+        return ((FlaggedMailbox) mailbox).getRecentCount(reset);
+    }
+
+    public int getUnseenCount() throws MailboxManagerException {
+        return ((FlaggedMailbox) mailbox).getUnseenCount();
+    }
+
+    public void setFlags(Flags flags, boolean value, boolean replace, GeneralMessageSet set, MailboxListener silentListener) throws MailboxManagerException {
+        ((FlaggedMailbox) mailbox).setFlags(flags, value, replace,toUidSet(set), silentListener);
+    }
+    
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/ImapMailboxSessionWrapper.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/ImapMailboxSessionWrapper.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/ImapMailboxSessionWrapper.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/ImapMailboxSessionWrapper.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,58 @@
+package org.apache.james.mailboxmanager.wrapper;
+
+import javax.mail.search.SearchTerm;
+
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxListener;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.Quota;
+import org.apache.james.mailboxmanager.acl.MailboxRights;
+import org.apache.james.mailboxmanager.impl.MailboxEventDispatcher;
+import org.apache.james.mailboxmanager.mailbox.ImapMailbox;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+public class ImapMailboxSessionWrapper extends FlaggedSessionMailboxWrapper
+        implements ImapMailboxSession {
+
+    protected MailboxEventDispatcher eventDispatcher = new MailboxEventDispatcher();
+
+    public ImapMailboxSessionWrapper(ImapMailbox imapMailbox) throws MailboxManagerException {
+        super(imapMailbox);
+    }
+
+    public MailboxRights myRights() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Quota[] getQuota() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+
+
+    public boolean isSelectable() {
+        // TODO Auto-generated method stub
+        return true;
+    }
+
+    public long getUidValidity() throws MailboxManagerException {
+        return ((ImapMailbox) mailbox).getUidValidity();
+    }
+
+    public long getUidNext() throws MailboxManagerException {
+        return ((ImapMailbox) mailbox).getUidNext();
+    }
+
+	public MessageResult[] search(GeneralMessageSet set, SearchTerm searchTerm, int result) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+
+
+
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/NumberStableSessionWrapper.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/NumberStableSessionWrapper.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/NumberStableSessionWrapper.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/NumberStableSessionWrapper.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,169 @@
+package org.apache.james.mailboxmanager.wrapper;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxListener;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.impl.MailboxEventDispatcher;
+import org.apache.james.mailboxmanager.impl.MessageResultImpl;
+import org.apache.james.mailboxmanager.mailbox.EventQueueingSessionMailbox;
+import org.apache.james.mailboxmanager.mailbox.EventTriggerMailbox;
+import org.apache.james.mailboxmanager.mailbox.GeneralMailbox;
+import org.apache.james.mailboxmanager.util.AbstractLogEnabled;
+
+public class NumberStableSessionWrapper extends AbstractLogEnabled implements EventQueueingSessionMailbox,
+		MailboxListener {
+
+	protected GeneralMailbox mailbox;
+
+	private UidToMsnBidiMap numberCache = null;
+	
+    protected Map flagEventMap = new TreeMap();
+
+    protected SortedSet expungedEventList = new TreeSet();
+
+	private MailboxEventDispatcher eventDispatcher = new MailboxEventDispatcher();
+    
+    public NumberStableSessionWrapper(GeneralMailbox generalMailbox) throws MailboxManagerException {
+    	this.mailbox=generalMailbox;
+    	((EventTriggerMailbox)mailbox).addListener(eventDispatcher, MessageResult.UID);
+    	getNumberCache();
+    	eventDispatcher.addMailboxListener(this);
+    }
+
+	protected UidToMsnBidiMap getNumberCache() throws MailboxManagerException {
+		if (numberCache == null) {
+			MessageResult[] mr = mailbox.getMessages(GeneralMessageSetImpl
+					.all(), MessageResult.UID);
+			numberCache = new UidToMsnBidiMap();
+			for (int i = 0; i < mr.length; i++) {
+				numberCache.add(mr[i].getUid());
+			}
+		}
+		return numberCache;
+	}
+
+	protected GeneralMessageSet toUidSet(GeneralMessageSet set)
+			throws MailboxManagerException {
+
+		if (set.getType() == GeneralMessageSet.TYPE_MSN) {
+			set = GeneralMessageSetImpl.uidRange(getNumberCache().getUid(
+					set.getMsnFrom()), getNumberCache().getUid(set.getMsnTo()));
+		}
+		return set;
+	}
+
+	protected static int noMsnResult(int result) {
+		if ((result & MessageResult.MSN) > 0) {
+			result |= MessageResult.UID;
+			result -= MessageResult.MSN;
+		}
+		return result;
+	}
+
+	protected MessageResult[] addMsnToResults(MessageResult[] mr, int result)
+			throws MailboxManagerException {
+		MessageResult[] translated = new MessageResult[mr.length];
+		for (int i = 0; i < translated.length; i++) {
+			translated[i] = addMsnResult(mr[i], result);
+		}
+		return translated;
+	}
+
+	protected MessageResult addMsnResult(MessageResult mr, int result)
+			throws MailboxManagerException {
+		if (mr != null) {
+			if ((result & MessageResult.MSN) > 0) {
+				// TODO copy the MessageResult because it could be another class
+				int msn = getNumberCache().getMsn(mr.getUid());
+				((MessageResultImpl) mr).setMsn(msn);
+			}
+		}
+		return mr;
+	}
+
+	public synchronized MessageResult[] getFlagEvents(boolean reset)
+			throws MailboxManagerException {
+		final MessageResult[] msnFlagEvents = buildMsnEvents(flagEventMap.values(),false);
+		if (reset) {
+			flagEventMap = new TreeMap();
+		}
+		return msnFlagEvents;
+	}
+
+	public synchronized MessageResult[] getExpungedEvents(boolean reset)
+			throws MailboxManagerException {
+		final MessageResult[] msnExpungedEvents  = buildMsnEvents(expungedEventList,reset);
+		if (reset) {
+			expungedEventList = new TreeSet();
+		} 
+		return msnExpungedEvents;
+	}
+
+	protected MessageResult[]  buildMsnEvents(Collection collection,boolean expunge)
+			throws MailboxManagerException {
+		final MessageResult[]  msnEvents = new MessageResult[collection.size()];
+		int i=0;
+		for (Iterator iter = collection.iterator(); iter.hasNext();) {
+			MessageResult origMr = (MessageResult) iter.next();
+			MessageResultImpl newMr = new MessageResultImpl(origMr);
+			newMr.setMsn(getNumberCache().getMsn(origMr.getUid()));
+			if (expunge) {
+				getNumberCache().expunge(origMr.getUid());
+			}
+			msnEvents[i++]=newMr;
+		}
+		return msnEvents;
+	}
+
+	public void added(MessageResult result) {
+		try {
+			getNumberCache().add(result.getUid());
+		} catch (MailboxManagerException e) {
+			getLog().error("This should not happen",e);
+		}
+	}
+
+	public void expunged(MessageResult mr) {
+		getLog().debug("Expunged: "+mr);
+       expungedEventList.add(mr);
+	}
+
+    public synchronized void flagsUpdated(MessageResult mr,
+            MailboxListener silentListener) {
+        if (silentListener != this
+                || flagEventMap.containsKey(new Long(mr.getUid()))) {
+            // if there has been an external update in the past we should inform
+            // about the newest value, even if in silent mode
+            flagEventMap.put(new Long(mr.getUid()), mr);
+        }
+    }
+
+	public void mailboxDeleted() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void mailboxRenamed(String origName, String newName) {
+		// TODO Auto-generated method stub
+
+	}
+	
+    public void addListener(MailboxListener listener, int result) {
+        eventDispatcher.addMailboxListener(listener);
+    }
+
+    public void removeListener(MailboxListener listener) {
+        eventDispatcher.removeMailboxListener(listener);
+    }
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/SessionMailboxWrapper.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/SessionMailboxWrapper.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/SessionMailboxWrapper.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/SessionMailboxWrapper.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,59 @@
+package org.apache.james.mailboxmanager.wrapper;
+
+import java.util.Date;
+
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.mailbox.FlaggedMailbox;
+import org.apache.james.mailboxmanager.mailbox.GeneralMailbox;
+import org.apache.james.mailboxmanager.mailbox.MailboxSession;
+
+public class SessionMailboxWrapper extends NumberStableSessionWrapper implements MailboxSession {
+
+    public SessionMailboxWrapper(GeneralMailbox generalMailbox) throws MailboxManagerException {
+		super(generalMailbox);
+	}
+
+	public MessageResult appendMessage(MimeMessage message, Date internalDate,
+            int result) throws MailboxManagerException {
+        return addMsnResult(mailbox.appendMessage(message, internalDate, noMsnResult(result)),result);
+    }
+
+    public int getMessageCount() throws MailboxManagerException {
+        return mailbox.getMessageCount();
+    }
+
+    public int getMessageResultTypes() {
+        return mailbox.getMessageResultTypes() | MessageResult.MSN;
+    }
+
+    public MessageResult[] getMessages(GeneralMessageSet set, int result)
+            throws MailboxManagerException {
+        return addMsnToResults(mailbox.getMessages(toUidSet(set),
+                noMsnResult(result)), result);
+    }
+
+    public int getMessageSetTypes() {
+        return mailbox.getMessageSetTypes() | GeneralMessageSet.TYPE_MSN;
+    }
+
+    public String getName() throws MailboxManagerException {
+        return mailbox.getName();
+    }
+
+    public MessageResult updateMessage(GeneralMessageSet messageSet, MimeMessage message, int result) throws MailboxManagerException {
+        return addMsnResult(mailbox.updateMessage(toUidSet(messageSet), message, noMsnResult(result)),result);
+    }
+
+    public void close() {
+        // TODO Auto-generated method stub
+    }
+
+	public boolean isWriteable() {
+		return true;
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/UidToMsnBidiMap.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/UidToMsnBidiMap.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/UidToMsnBidiMap.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/mailboxmanager/wrapper/UidToMsnBidiMap.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,110 @@
+package org.apache.james.mailboxmanager.wrapper;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+public class UidToMsnBidiMap {
+
+	protected SortedMap msnToUid;
+
+	protected SortedMap uidToMsn;
+
+	protected long highestUid = 0;
+	
+	protected int highestMsn = 0;
+
+	public UidToMsnBidiMap() {
+		msnToUid = new TreeMap();
+		uidToMsn = new TreeMap();
+	}
+
+	public synchronized long getUid(int msn) {
+		if (msn == -1) {
+			return -1;
+		}
+		Long uid = (Long) msnToUid.get(new Integer(msn));
+		if (uid != null) {
+			return uid.longValue();
+		} else {
+			if (msn > 0) {
+				return highestUid;
+			} else {
+				return 0;
+			}
+		}
+	}
+
+	public synchronized int getMsn(long uid) {
+		Integer msn = (Integer) uidToMsn.get(new Long(uid));
+		if (msn != null) {
+			return msn.intValue();
+		} else {
+			return -1;
+		}
+
+	}
+
+	protected synchronized void add(int msn, long uid) {
+		if (uid > highestUid) {
+			highestUid = uid;
+		}
+		msnToUid.put(new Integer(msn), new Long(uid));
+		uidToMsn.put(new Long(uid), new Integer(msn));
+	}
+
+	
+	
+	public synchronized void expunge(long uid) {
+		int msn=getMsn(uid);
+		remove(msn,uid);
+		List renumberMsns=new ArrayList(msnToUid.tailMap(new Integer(msn+1)).keySet());
+		for (Iterator iter = renumberMsns.iterator(); iter.hasNext();) {
+			int aMsn = ((Integer) iter.next()).intValue();
+			long aUid= getUid(aMsn);
+			remove(aMsn,aUid);
+			add(aMsn-1,aUid);
+		}
+		highestMsn--;
+		assertValidity();
+	}
+	
+	protected void remove(int msn,long uid) {
+		uidToMsn.remove(new Long(uid));
+		msnToUid.remove(new Integer(msn));
+	}
+	
+    synchronized void assertValidity() {
+    	Integer[] msns=(Integer[])msnToUid.keySet().toArray(new Integer[0]);
+    	for (int i = 0; i < msns.length; i++) {
+			if (msns[i].intValue()!=(i+1)) {
+				throw new AssertionError("Msn at position "+(i+1)+" was "+msns[i].intValue());
+			}
+		}
+    	if (msns[msns.length-1].intValue()!=highestMsn) {
+    		throw new AssertionError("highestMsn "+highestMsn+" msns[msns.length-1] "+msns[msns.length-1]);
+    	}
+		if (!msnToUid.keySet().equals(new TreeSet(uidToMsn.values()))) {
+			System.out.println(msnToUid.keySet());
+			System.out.println(uidToMsn.values());
+			throw new AssertionError("msnToUid.keySet() does not equal uidToMsn.values()");
+		}
+		if (!uidToMsn.keySet().equals(new TreeSet(msnToUid.values()))) {
+			System.out.println(uidToMsn.keySet());
+			System.out.println(msnToUid.values());
+			throw new AssertionError("uidToMsn.keySet() does not equal msnToUid.values()");
+		}
+
+	}
+
+	public synchronized void add(long uid) {
+		if (!uidToMsn.containsKey(new Long(uid))) {
+			highestMsn++;
+			add(highestMsn, uid);
+		}
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/util/Assert.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/util/Assert.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/util/Assert.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/util/Assert.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,59 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.util;
+
+
+/**
+ * A set of debugging utilities.
+ */
+public final class Assert
+{
+    public static final boolean ON = true;
+
+    // Can't instantiate.
+    private Assert()
+    {
+    };
+
+    /**
+     * Checks the supplied boolean expression, throwing an AssertionException if false;
+     */
+    public static void isTrue( boolean expression )
+    {
+        if ( !expression ) {
+            throw new RuntimeException( "Assertion Failed." );
+        }
+    }
+
+    /**
+     * Fails with an assertion exception.
+     */
+    public static void fail()
+    {
+        throw new RuntimeException( "Assertion error - should not reach here." );
+    }
+
+    /**
+     * Fails, indicating not-yet-implemented features.
+     */
+    public static void notImplemented()
+    {
+        throw new RuntimeException( "Not implemented" );
+    }
+
+}

Added: james/server/sandbox/imap-integration/src/schema/project-schema.xml
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/schema/project-schema.xml?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/schema/project-schema.xml (added)
+++ james/server/sandbox/imap-integration/src/schema/project-schema.xml Mon Oct  9 10:15:30 2006
@@ -0,0 +1,85 @@
+<!DOCTYPE database SYSTEM
+ "http://db.apache.org/torque/dtd/database_3_2.dtd">
+
+<database
+  name="mailboxmanager">
+
+	<table name="mailbox" javaName="MailboxRow" description="Mailbox Table" idMethod="native">
+		<column name="mailbox_id" required="true" primaryKey="true" type="BIGINT" autoIncrement="true"
+			description="Mailbox Id"/>
+		<column name="name" required="true" type="VARCHAR" size="255"
+			description="full-namespace-name"/>
+		<column name="uid_validity" required="true" type="BIGINT"
+			description="the last used uid (default 0)"/>
+		<column name="last_uid" required="true" type="BIGINT"
+			description="the last used uid (default 0)"/>
+		<column name="message_count" type="INTEGER" default="0"
+			description="total message number"/>
+		<column name="size" type="BIGINT" default="0"
+			description="size of this mailbox in byte"/>
+		<unique>
+			<unique-column name="name" />
+		</unique>
+	</table>
+	<table name="message" javaName="MessageRow" idMethod="none" description="">
+		<column name="mailbox_id" required="true" primaryKey="true" type="BIGINT"
+			description="Mailbox Id"/>
+		<column name="uid" required="true" primaryKey="true" type="BIGINT"
+			description="the last used uid (default 0)"/>
+		<column name="internal_date" type="DATE" description="internal date" />
+		<column name="size" type="INTEGER" description="message size" />
+		<foreign-key foreignTable="mailbox" onDelete="cascade">
+			<reference local="mailbox_id" foreign="mailbox_id"/>
+		</foreign-key>
+	</table>
+	<table name="message_flags" idMethod="none">
+		<column name="mailbox_id" required="true" primaryKey="true" type="BIGINT"
+			description="Mailbox Id"/>
+		<column name="uid" required="true" primaryKey="true" type="BIGINT"
+			description=""/>		
+		<column name="answered" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<column name="deleted" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<column name="draft" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<column name="flagged" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<column name="recent" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<column name="seen" required="true" default="0" type="BOOLEANINT"
+    		description=""/>		
+		<foreign-key foreignTable="message" onDelete="cascade">
+			<reference local="mailbox_id" foreign="mailbox_id"/>
+			<reference local="uid" foreign="uid"/>
+		</foreign-key>
+	</table>
+	<table name="message_header" idMethod="none">
+		<column name="mailbox_id" required="true" primaryKey="true" type="BIGINT"
+			description="Mailbox Id"/>
+		<column name="uid" required="true" primaryKey="true" type="BIGINT"
+			description=""/>
+		<column name="line_number" required="true" primaryKey="true" type="INTEGER"
+			description=""/>
+		<column name="field" required="true" type="VARCHAR" size="256"
+			description="field"/>
+		<column name="value" required="true" type="VARCHAR" size="1024"
+			description="value"/>
+		<foreign-key foreignTable="message" onDelete="cascade">
+			<reference local="mailbox_id" foreign="mailbox_id"/>
+			<reference local="uid" foreign="uid"/>
+		</foreign-key>
+	</table>
+	<table name="message_body" idMethod="none">
+		<column name="mailbox_id" required="true" primaryKey="true" type="BIGINT"
+			description="Mailbox Id"/>
+		<column name="uid" required="true" primaryKey="true" type="BIGINT"
+			description=""/>
+		<column name="body" required="true" type="BLOB" 
+			description="value"/>
+		<foreign-key foreignTable="message" onDelete="cascade">
+			<reference local="mailbox_id" foreign="mailbox_id"/>
+			<reference local="uid" foreign="uid"/>
+		</foreign-key>
+	</table>
+</database>

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/TestConstants.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/TestConstants.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/TestConstants.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/TestConstants.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,16 @@
+package org.apache.james.imapserver;
+
+public interface TestConstants
+{
+	final static String USER_NAME="tuser";
+    final static String USER_MAILBOX_ROOT=ImapConstants.USER_NAMESPACE+"."+USER_NAME;
+	final static String USER_PASSWORD="abc";
+	final static String USER_REALNAME="Test User";
+	
+	final static String HOST_NAME="localhost";
+	final static String HOST_ADDRESS="127.0.0.1";
+	final static int HOST_PORT=10143;
+	
+
+	
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/AbstractCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/AbstractCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/AbstractCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/AbstractCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,27 @@
+package org.apache.james.imapserver.client;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.mail.MessagingException;
+
+public abstract class AbstractCommand implements Command {
+
+	protected List responseList = new LinkedList();
+	protected String statusResponse = null;
+	protected String command = null; 
+
+	public List getExpectedResponseList() throws MessagingException, IOException {
+		return responseList ;
+	}
+
+	public String getExpectedStatusResponse() {
+		return statusResponse;
+	}
+
+	public String getCommand() {
+		return command;
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/Command.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/Command.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/Command.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/Command.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,24 @@
+package org.apache.james.imapserver.client;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.mail.MessagingException;
+
+public interface Command {
+
+	public List getExpectedResponseList() throws MessagingException, IOException;
+
+	/**
+	 * Untagged, without leading space or trailing newline.<br>
+	 * e.g. : "OK LOGIN completed."
+	 */
+	public String getExpectedStatusResponse();
+
+	/**
+	 * Untagged, without leading space with trailing newline. <br>
+	 *  e.g. : "LOGIN user password\n"
+	 */
+	public String getCommand();
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CopyClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CopyClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CopyClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CopyClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,14 @@
+package org.apache.james.imapserver.client;
+
+public class CopyClientCommand extends AbstractCommand {
+	
+	public CopyClientCommand(MessageSet set,String destination) {
+		command = "";
+		if (set.isUid())  { 
+			command ="UID ";
+		}
+		command += "COPY "+set + " \""+destination+"\"";
+		statusResponse="OK COPY completed.";
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CreateClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CreateClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CreateClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/CreateClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,9 @@
+package org.apache.james.imapserver.client;
+
+public class CreateClientCommand extends AbstractCommand {
+
+	public CreateClientCommand(String folder) {
+		command = "CREATE \""+folder+"\"";
+		statusResponse="OK CREATE completed.";
+	}
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/DeleteClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/DeleteClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/DeleteClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/DeleteClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,9 @@
+package org.apache.james.imapserver.client;
+
+public class DeleteClientCommand extends AbstractCommand {
+
+	public DeleteClientCommand(String folder) {
+		command = "DELETE \""+folder+"\"";
+		statusResponse="OK DELETE completed.";
+	}
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/FetchCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/FetchCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/FetchCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/FetchCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,225 @@
+package org.apache.james.imapserver.client;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.mail.Flags;
+import javax.mail.MessagingException;
+import javax.mail.Flags.Flag;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.imapserver.client.fetch.FetchBody;
+
+public class FetchCommand extends AbstractCommand {
+
+	final long from;
+
+	final long to;
+
+	boolean uid;
+
+	private MimeMessage[] msgs;
+
+	private long[] uids;
+
+	private boolean fetchFlags;
+
+	private boolean fetchRfc822Size;
+	
+	private FetchBody body;
+
+	public FetchCommand(MimeMessage[] msgs, long from, long to) {
+		statusResponse = "OK FETCH completed.";
+		this.msgs = msgs;
+		this.from = from;
+		this.to = to;
+	}
+	
+	public void setUids(long[] uids) {
+		this.uids=uids;
+		this.uid=true;
+	}
+
+	public String getCommand() {
+		String command = "";
+		if (uid) {
+			command += "UID ";
+		}
+		command += "fetch " + from + ":";
+		if (to > 0) {
+			command += to;
+		} else {
+			command += "*";
+		}
+		command += " (";
+		String items="";
+		// FLAGS
+		if (fetchFlags) {
+			items += " FLAGS";	
+		}
+		// RFC822.SIZE
+		if (fetchRfc822Size) {
+			items += " RFC822.SIZE";
+		}
+		// BODY
+		if (body!=null) {
+			items += " "+body.getCommand();
+		}
+		
+		
+		if (items.length()>0) {
+			items=items.substring(1);
+		}
+
+		command += items+")\n";
+		return command;
+	}
+
+	private List getSelectedMessageNumbers() {
+		List selectedNumbers = new ArrayList();
+		
+		
+		if (uid) {
+			final long to;
+			if (this.to>0) {
+				to=this.to;
+			} else {
+				to=Long.MAX_VALUE;
+			}
+			for (int i=0; i< msgs.length; i++) {
+				if (uids[i]>=from && uids[i]<=to)  {
+					selectedNumbers.add(new Integer((int)i+1));
+				}
+			}
+
+		} else {
+			final long from;
+			if (this.from > 0) {
+				from = this.from;
+			} else {
+				from = 1;
+			}
+
+			final long to;
+			if (this.to > 0) {
+				if (this.to > msgs.length) {
+					to = msgs.length;
+				} else {
+					to = this.to;
+				}
+			} else {
+				to = msgs.length;
+			}
+
+			for (long i = from; i <= to; i++) {
+				selectedNumbers.add(new Integer((int)i));
+			}
+		}
+		
+		return selectedNumbers;
+	}
+	public String getResultForMessageNumber(int no) throws MessagingException, IOException {
+		final MimeMessage mm = msgs[no-1];
+		String result = "";
+		
+		// FLAGS
+		if (fetchFlags) {
+			result +=" FLAGS ("+flagsToString(mm.getFlags())+")";
+		}
+		
+		// UID
+		if (uid) {
+			final long uid=uids[no-1];
+			result += " UID "+uid;
+		}
+		
+		// RFC822.SIZE
+		if (fetchRfc822Size) {
+			final int size=mm.getSize();
+			result += " RFC822.SIZE "+size;
+		}
+
+        // BODY
+		if (body!=null) {
+			result += " "+body.getResult(mm);
+		}
+		
+		if (result.length()>0) {
+    		 // without leading space
+			result=result.substring(1);
+		}
+		return result;
+	}
+	
+	public List getExpectedResponseList() throws MessagingException, IOException {
+		List responseList = new LinkedList();
+
+		List selectedNumbers = getSelectedMessageNumbers();
+		
+		for (Iterator it = selectedNumbers.iterator(); it.hasNext();) {
+			final int no=((Integer)it.next()).intValue();
+			String line = "* " + no + " FETCH (";
+			line += getResultForMessageNumber(no);
+			line += ")";
+			responseList.add(line);
+		}
+		return responseList;
+
+	}
+
+	public static String flagToString(Flag flag) {
+		if (flag.equals(Flag.ANSWERED)) {
+			return "\\Answered";
+		}
+        if (flag.equals(Flag.DELETED)) {
+            return "\\Deleted";
+        }
+        if (flag.equals(Flag.DRAFT)) {
+            return "\\Draft";
+        }
+		if (flag.equals(Flag.FLAGGED)) {
+			return "\\Flagged";
+		}
+		if (flag.equals(Flag.RECENT)) {
+			return "\\Recent";
+		}
+		if (flag.equals(Flag.SEEN)) {
+			return "\\Seen";
+		}
+		throw new IllegalArgumentException("unknown Flag: "+flag);
+
+	}
+	
+	public static  String flagsToString(Flags flags) {
+		String result="";
+		Flag[] f=flags.getSystemFlags();
+		for (int i = 0; i < f.length; i++) {
+			result +=" "+flagToString(f[i]);
+		}
+		if (result.length()>0) {
+     		 // without leading space
+			result=result.substring(1);
+		}
+		return result;
+	}
+
+	public void setFetchFlags(boolean fetchFlags) {
+		this.fetchFlags=fetchFlags;
+		
+	}
+
+	public void setFetchRfc822Size(boolean fetchRfc822Size) {
+		this.fetchRfc822Size=fetchRfc822Size;
+		
+	}
+	
+
+	public void setFetchBody(FetchBody body) {
+		this.body=body;
+		
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LoginCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LoginCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LoginCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LoginCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,14 @@
+package org.apache.james.imapserver.client;
+
+
+public class LoginCommand extends AbstractCommand {
+
+	
+	public LoginCommand(String userName, String password) {
+		command="LOGIN "+userName+" "+password+"\n";
+		statusResponse="OK LOGIN completed.";
+	}
+
+
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LogoutClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LogoutClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LogoutClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/LogoutClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,11 @@
+package org.apache.james.imapserver.client;
+
+public class LogoutClientCommand extends AbstractCommand {
+
+	public LogoutClientCommand() {
+		command="LOGOUT\n";
+		statusResponse="OK LOGOUT completed.";
+		responseList.add("* BYE IMAP4rev1 Server logging out");
+	}
+	
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/MessageSet.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/MessageSet.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/MessageSet.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/MessageSet.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,134 @@
+package org.apache.james.imapserver.client;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.mail.internet.MimeMessage;
+
+public class MessageSet {
+	
+	private final long from;
+	private final long to;
+    private boolean useUid=false;
+	private long[] uids;
+	private MimeMessage[] msgs;
+	private ArrayList selectedMessageNumbers;
+
+	public MessageSet(MimeMessage[] msgs,long[] uids,long from,long to) {
+		this(msgs,from,to);
+		this.uids=uids;
+        this.useUid=true;
+	}
+	public MessageSet(MimeMessage[] msgs,long[] uids,long number) {
+		this(msgs,number);
+		this.uids=uids;
+        this.useUid=true;
+	}
+	
+	public MessageSet(MimeMessage[] msgs,long from,long to) {
+		this(from,to);
+		this.msgs=msgs;
+	}
+	public MessageSet(MimeMessage[] msgs,long number) {
+		this(number);
+		this.msgs=msgs;
+	}
+	public MessageSet(long from,long to) {
+		this.from=from;
+		this.to=to;
+	}
+	public MessageSet(long number) {
+		this.from=-1;
+		this.to=number;
+	}
+	
+	public MessageSet(MimeMessage[] msgs, long from, long to, int[] numbers, long[] uids, boolean useUid) {
+        if (useUid) {
+            from=uids[(int)from-1];
+            to=uids[(int)to-1];
+        }
+        this.msgs=msgs;
+        this.from=from;
+        this.to=to;
+        this.uids=uids;
+        this.useUid=useUid;
+        selectedMessageNumbers=new ArrayList(numbers.length);
+        for (int i = 0; i < numbers.length; i++) {
+            selectedMessageNumbers.add(new Integer(numbers[i]));
+        }
+
+    }
+    public String toString() {
+		String result="";
+		if (from>0)  {
+			result += from +":";
+		}
+		if (to>0) {
+			result += to;
+		} else {
+			result += "*";
+		}
+		return result;
+	}
+	
+	public boolean isUid() {
+		return useUid;
+	}
+	
+	public List getSelectedMessageNumbers() {
+		if (selectedMessageNumbers==null) {
+			selectedMessageNumbers=new ArrayList();
+			if (isUid()) {
+				final long from;
+				if (this.from>0) {
+					from=this.from;
+				} else {
+					from=this.to;
+				}
+				final long to;
+				if (this.to>0) {
+					to=this.to;
+				} else {
+					to=Long.MAX_VALUE;
+				}
+				for (int i=0; i< msgs.length; i++) {
+					if (uids[i]>=from && uids[i]<=to)  {
+						selectedMessageNumbers.add(new Integer((int)i+1));
+					}
+				}
+
+			} else {
+				final long from;
+				if (this.from > 0) {
+					from = this.from;
+				} else {
+					from = this.to;
+				}
+
+				final long to;
+				if (this.to > 0) {
+					if (this.to > msgs.length) {
+						to = msgs.length;
+					} else {
+						to = this.to;
+					}
+				} else {
+					to = msgs.length;
+				}
+
+				for (long i = from; i <= to; i++) {
+					selectedMessageNumbers.add(new Integer((int)i));
+				}
+			}
+		}
+		return selectedMessageNumbers;
+	}
+	public MimeMessage getMessage(int no) {
+		return msgs[no-1];
+	}
+	public long getUid(int no) {
+		return uids[no-1];
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/RenameClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/RenameClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/RenameClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/RenameClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,9 @@
+package org.apache.james.imapserver.client;
+
+public class RenameClientCommand extends AbstractCommand {
+	
+	public RenameClientCommand(String folder,String destination) {
+		command = "RENAME \""+folder+"\" \""+destination+"\"";
+		statusResponse="OK RENAME completed.";
+	}
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/SelectCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/SelectCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/SelectCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/SelectCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,31 @@
+package org.apache.james.imapserver.client;
+
+import java.util.ArrayList;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.imapserver.util.UnsolicitedResponseGenerator;
+
+public class SelectCommand extends AbstractCommand {
+	
+	int recentCount =0;
+
+	public SelectCommand(String folder,MimeMessage[] msgs,long uidv) throws MessagingException {
+		
+		command="SELECT \""+folder+"\"";
+
+		UnsolicitedResponseGenerator rg=new UnsolicitedResponseGenerator();
+		rg.addByMessages(msgs);
+		recentCount = rg.getRecent();
+		rg.addUidValidity(uidv);
+		responseList=new ArrayList(rg.getResponseSet());
+		statusResponse="OK [READ-WRITE] SELECT completed.";
+		
+	}
+
+	public int getRecentCount() {
+		return recentCount;
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/StoreClientCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/StoreClientCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/StoreClientCommand.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/StoreClientCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,80 @@
+package org.apache.james.imapserver.client;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.mail.Flags;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+public class StoreClientCommand extends AbstractCommand {
+
+	public static final int MODE_SET = 0;
+
+	public static final int MODE_ADD = 1;
+
+	public static final int MODE_REMOVE = 2;
+
+	private final int mode;
+
+	private final boolean silent;
+
+	private final Flags flags;
+
+	private MessageSet set;
+
+	public StoreClientCommand(int mode, boolean silent, Flags flags,
+			MessageSet set) {
+		this.mode = mode;
+		this.silent = silent;
+		this.flags = flags;
+		this.set = set;
+		this.statusResponse = "OK STORE completed.";
+	}
+
+	public String getCommand() {
+		command = "";
+		if (set.isUid()) {
+			command = "UID ";
+		}
+		command += "STORE ";
+		command += set + " ";
+
+		if (mode == MODE_ADD) {
+			command += "+";
+		} else if (mode == MODE_REMOVE) {
+			command += "-";
+		}
+		command += "FLAGS";
+		if (silent) {
+			command += ".SILENT";
+		}
+		command += " (";
+		command += FetchCommand.flagsToString(flags);
+		command += ")";
+
+		return command;
+
+	}
+
+	public List getExpectedResponseList() throws MessagingException {
+		List responseList = new LinkedList();
+		if (!silent) {
+			List selectedNumbers = set.getSelectedMessageNumbers();
+			for (Iterator it = selectedNumbers.iterator(); it.hasNext();) {
+				final int no = ((Integer) it.next()).intValue();
+				final MimeMessage mm = set.getMessage(no);
+				String line = "* " + no + " FETCH (";
+				line += "FLAGS (" + FetchCommand.flagsToString(mm.getFlags())
+						+ ")";
+				if (set.isUid()) {
+					line += " UID " + set.getUid(no);
+				}
+				line += ")";
+				responseList.add(line);
+			}
+		}
+		return responseList;
+	}
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchBody.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchBody.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchBody.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchBody.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,61 @@
+package org.apache.james.imapserver.client.fetch;
+
+import java.io.IOException;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.imapserver.util.MessageGenerator;
+
+public class FetchBody {
+
+	final boolean peek;
+
+	private FetchHeader fetchHeader;
+
+	public FetchBody(boolean peek) {
+		this.peek = peek;
+	}
+
+	public String getCommand() {
+		String result= "";
+		if (peek) {
+			result += "BODY.PEEK[";
+		} else {
+			result += "BODY[";
+		}
+		if (fetchHeader!=null) {
+			result += fetchHeader.getCommand();
+		}
+		result += "]";
+		return result;
+	}
+
+	public String getResult(MimeMessage m) throws IOException,
+			MessagingException {
+		// TODO decide whether it should be BODY.PEEK when peek!
+		String result = "BODY[";
+		final String data;
+		if (fetchHeader != null) {
+			result += fetchHeader.getCommand();
+			data = fetchHeader.getData(m);
+		} else {
+			data = getData(m);
+		}
+		result += "] {" + data.length() + "}\r\n" + data;
+		// TODO Shouldn't we append another CRLF?
+		return result;
+	}
+
+	private String getData(MimeMessage m) throws IOException,
+			MessagingException {
+		String data = MessageGenerator.messageContentToString(m);
+		return data;
+	}
+
+	public void setFetchHeader(FetchHeader fetchHeader) {
+		this.fetchHeader = fetchHeader;
+
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchHeader.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchHeader.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchHeader.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/client/fetch/FetchHeader.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,53 @@
+package org.apache.james.imapserver.client.fetch;
+
+import java.util.Enumeration;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+public class FetchHeader {
+
+	private String[] fields;
+
+	public String getCommand() {
+		if (fields == null) {
+			return "HEADER";
+		} else {
+			return "HEADER.FIELDS ("+getFormattedFieldList()+")";
+		}
+	}
+
+	private String getFormattedFieldList() {
+		String result ="";
+		for (int i = 0; i < fields.length; i++) {
+			result +=" "+fields[i];
+			
+		}
+		if (result.length()>0) {
+			result=result.substring(1);
+		}
+		return result;
+	}
+
+	public String getData(MimeMessage m) throws MessagingException {
+		String result = "";
+		final Enumeration e;
+		if (fields==null) {
+		e= m.getAllHeaderLines();
+		} else {
+			e = m.getMatchingHeaderLines(fields);
+		}
+		while (e.hasMoreElements()) {
+			String line = (String) e.nextElement();
+			result += line + "\r\n";
+		}
+		result += "\r\n"; // TODO Should this be counted for size?
+		return result;
+	}
+
+	public void setFields(String[] fields) {
+		this.fields = fields;
+
+	}
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/AbstractCommandTest.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/AbstractCommandTest.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/AbstractCommandTest.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/AbstractCommandTest.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,40 @@
+package org.apache.james.imapserver.handler.commands;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.apache.james.imapserver.ImapRequestHandler;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.services.User;
+import org.apache.james.services.UsersRepository;
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+
+public abstract class AbstractCommandTest extends MockObjectTestCase
+{
+
+	ImapRequestHandler handler;
+	Mock mockSession;
+	Mock mockUsersRepository;
+	Mock mockUser;
+
+	public void setUp() {
+		handler=new ImapRequestHandler();
+		mockSession = mock ( ImapSession.class);
+		mockUsersRepository = mock ( UsersRepository.class );
+		mockUser = mock (User.class );
+	}
+	
+	public String handleRequest(String s) throws ProtocolException {
+		ByteArrayInputStream is=new ByteArrayInputStream(s.getBytes());
+		ByteArrayOutputStream os=new ByteArrayOutputStream();
+		System.out.println("IN :"+s);
+		handler.handleRequest(is,os,(ImapSession) mockSession.proxy());
+		String out=os.toString();
+		System.out.println("OUT:"+out);
+		return out;
+	}
+	
+
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/LoginTest.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/LoginTest.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/LoginTest.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/commands/LoginTest.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,53 @@
+package org.apache.james.imapserver.handler.commands;
+
+import org.apache.james.imapserver.ImapSessionState;
+import org.apache.james.imapserver.ProtocolException;
+
+
+
+public class LoginTest extends AbstractCommandTest
+{
+
+	public void testValidUserStateNonAuth() throws ProtocolException {
+		mockSession.expects(atLeastOnce()).method("getState").will(returnValue(ImapSessionState.NON_AUTHENTICATED));
+		mockSession.expects(atLeastOnce()).method("getUsers").will(returnValue(mockUsersRepository.proxy()));
+		
+		mockUsersRepository.expects(once()).method("test").with( eq("joachim2"),eq("abc")).will(returnValue(true));
+		mockUsersRepository.expects(once()).method("getUserByName").with( eq("joachim2")).will(returnValue(mockUser.proxy()));
+		
+		mockSession.expects(once()).method("setAuthenticated").with( same(mockUser.proxy()));
+
+		String response = handleRequest("1 LOGIN joachim2 abc\n");
+
+		assertEquals("1 OK LOGIN completed.\r\n",response);
+	}
+	public void testInvalidUserStateNonAuth() throws ProtocolException {
+		mockSession.expects(atLeastOnce()).method("getState").will(returnValue(ImapSessionState.NON_AUTHENTICATED));
+		mockSession.expects(atLeastOnce()).method("getUsers").will(returnValue(mockUsersRepository.proxy()));
+		
+		mockUsersRepository.expects(once()).method("test").with( eq("joachim2"),eq("abc")).will(returnValue(false));
+
+		String response = handleRequest("1 LOGIN joachim2 abc\n");
+
+		assertEquals("1 NO LOGIN failed. Invalid login/password\r\n",response);
+	}
+	public void testValidUserStateAuth() throws ProtocolException {
+		mockSession.expects(atLeastOnce()).method("getState").will(returnValue(ImapSessionState.AUTHENTICATED));
+
+		String response = handleRequest("1 LOGIN joachim2 abc\n");
+		assertEquals("1 NO LOGIN failed. Command not valid in this state\r\n",response);
+	}
+
+	public void testValidUserStateLogout() throws ProtocolException {
+		mockSession.expects(atLeastOnce()).method("getState").will(returnValue(ImapSessionState.LOGOUT));
+
+		String response = handleRequest("1 LOGIN joachim2 abc\n");
+		assertEquals("1 NO LOGIN failed. Command not valid in this state\r\n",response);
+	}
+	public void testValidUserStateSelected() throws ProtocolException {
+		mockSession.expects(atLeastOnce()).method("getState").will(returnValue(ImapSessionState.SELECTED));
+
+		String response = handleRequest("1 LOGIN joachim2 abc\n");
+		assertEquals("1 NO LOGIN failed. Command not valid in this state\r\n",response);
+	}
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/AbstractSessionTest.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/AbstractSessionTest.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/AbstractSessionTest.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/AbstractSessionTest.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,255 @@
+package org.apache.james.imapserver.handler.session;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.mail.Flags;
+import javax.mail.MessagingException;
+import javax.mail.Flags.Flag;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.imapserver.ImapRequestHandler;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ImapSessionImpl;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.TestConstants;
+import org.apache.james.imapserver.client.Command;
+import org.apache.james.imapserver.mock.MockImapHandler;
+import org.apache.james.imapserver.mock.MockImapHandlerConfigurationData;
+import org.apache.james.imapserver.mock.MockUser;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.ListResult;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.mailbox.GeneralMailboxSession;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+import org.apache.james.mailboxmanager.manager.GeneralManager;
+import org.jmock.MockObjectTestCase;
+
+public abstract class AbstractSessionTest extends MockObjectTestCase implements TestConstants {
+	
+	GeneralManager mailboxManager;
+	
+	private ImapRequestHandler handler;
+	private ImapSession session;
+	
+	int counter=0;
+	
+	public AbstractSessionTest() {
+	}
+	
+	public void setUp() throws MailboxException, MessagingException, IOException, MailboxManagerException
+	{
+        
+		MockImapHandlerConfigurationData theConfigData = new MockImapHandlerConfigurationData();
+        theConfigData.getMailboxManagerProvider().deleteEverything();
+		session = new ImapSessionImpl(theConfigData.getMailboxManagerProvider(),
+				theConfigData.getUsersRepository(), new MockImapHandler(),
+				HOST_NAME, HOST_ADDRESS);
+		handler = new ImapRequestHandler();
+        mailboxManager=theConfigData.getMailboxManagerProvider().getGeneralManagerInstance(new MockUser());
+
+	}
+	
+	void createFolders(String[] folders) throws MailboxManagerException {
+		for (int i=0; i<folders.length; i++) {
+			mailboxManager.createMailbox(folders[i]);
+		}
+	}
+	
+	public void appendMessagesClosed(String folder,MimeMessage[] msgs) throws MailboxManagerException, MessagingException {
+        GeneralMailboxSession mailbox=getImapMailboxSession(folder);
+        for (int i = 0; i < msgs.length; i++) {
+            msgs[i].setFlags(new Flags(Flags.Flag.RECENT), true);
+            mailbox.appendMessage(msgs[i],new Date(),MessageResult.NOTHING);
+            
+        }
+		mailbox.close();
+	}
+
+	public long[] addUIDMessagesOpen(String folder,MimeMessage[] msgs) throws MailboxManagerException, MessagingException {
+		GeneralMailboxSession mailbox=getImapMailboxSession(folder);
+        long[] uids=new long[msgs.length];
+        for (int i = 0; i < msgs.length; i++) {
+            msgs[i].setFlags(new Flags(Flags.Flag.RECENT), false);
+            uids[i]=mailbox.appendMessage(msgs[i],new Date(),MessageResult.UID).getUid();
+        }
+        mailbox.close();
+		return uids;
+	}
+	public long getUidValidity(String folder) throws MailboxManagerException {
+        ImapMailboxSession mailbox=getImapMailboxSession(folder);
+        long uidv=mailbox.getUidValidity();
+        mailbox.close();
+		return uidv;
+	}
+	
+	public MimeMessage[] getMessages(String folder) throws MailboxManagerException {
+		GeneralMailboxSession mailbox=getImapMailboxSession(folder);
+        MessageResult[] messageResults=mailbox.getMessages(GeneralMessageSetImpl.all(),MessageResult.MIME_MESSAGE);
+		MimeMessage[] mms=new MimeMessage[messageResults.length];
+		for (int i = 0; i < messageResults.length; i++) {
+			mms[i]=messageResults[i].getMimeMessage();
+		}
+        mailbox.close();
+		return mms;
+	}
+	
+	public long[] getUids(String folder) throws MailboxManagerException {
+        GeneralMailboxSession mailbox=getImapMailboxSession(folder);
+        MessageResult[] messageResults=mailbox.getMessages(GeneralMessageSetImpl.all(),MessageResult.UID);
+
+        long[] uids=new long[messageResults.length];
+        for (int i = 0; i < messageResults.length; i++) {
+            uids[i]=messageResults[i].getUid();
+        }
+        mailbox.close();
+        return uids;
+	}
+	
+	public boolean folderExists(String folder) throws MailboxManagerException {
+		return mailboxManager.existsMailbox(folder);
+	}
+	
+	public String[] getFolderNames() throws MailboxManagerException {
+        ListResult[] listResults=mailboxManager.list("","*",false);
+		String[] names=new String[listResults.length];
+		for (int i = 0; i < listResults.length; i++) {
+			names[i]=listResults[i].getName();
+		}
+		return names;
+	}
+	
+	public void verifyFolderList(String[] expected,String[] found) {
+		Set expectedSet=new HashSet(Arrays.asList(expected));
+		Set foundSet=new HashSet(Arrays.asList(found));
+		Set missing=new HashSet(expectedSet);
+		missing.removeAll(foundSet);
+		Set notExpected=new HashSet(foundSet);
+		notExpected.removeAll(expectedSet);
+		assertEquals("Missing folders :"+missing,0,missing.size());
+		assertEquals("Not expected folders :"+notExpected,0,notExpected.size());
+	}
+	
+	public boolean isOpen(String folder)  throws MessagingException {
+        // TODO implement this
+		return false;
+	}
+    public void useFolder(String folder) {
+        
+    }
+    public void freeFolder(String folder) {
+        
+    }
+    
+	public void deleteAll(String folder) throws MailboxManagerException {
+		ImapMailboxSession mailbox=getImapMailboxSession(folder);
+        mailbox.setFlags(new Flags(Flag.DELETED),true,false,GeneralMessageSetImpl.all(),null);
+        mailbox.expunge(GeneralMessageSetImpl.all(),MessageResult.NOTHING);
+        mailbox.close();
+	}
+	public BufferedReader handleRequestReader(String s) throws ProtocolException
+	{
+		return new BufferedReader(new StringReader(handleRequest(s)));
+	}
+
+	public String handleRequest(String s) throws ProtocolException
+	{
+		ByteArrayInputStream is = new ByteArrayInputStream(s.getBytes());
+		ByteArrayOutputStream os = new ByteArrayOutputStream();
+		System.out.println("IN :" + s);
+		handler.handleRequest(is, os, session);
+		String out = os.toString();
+		System.out.println("OUT:" + out);
+		return out;
+		
+	}
+	protected void verify(final String command, final Set requiredResponseSet, final String requiredStatusResponse) throws ProtocolException, IOException, MessagingException {
+		Command c=new Command() {
+			public List getExpectedResponseList() throws MessagingException, IOException {
+				return new LinkedList(requiredResponseSet);
+			}
+			public String getExpectedStatusResponse() {
+				return requiredStatusResponse;
+			}
+			public String getCommand() {
+				return command;
+			}
+	    };
+		verifyCommand(c);
+	}
+	
+	protected void verifyCommand(Command command) throws ProtocolException, IOException, MessagingException {
+		
+		BufferedReader br=handleRequestReader((++counter)+" "+command.getCommand()+"\n");
+		Set	requiredResponseSet=new HashSet(command.getExpectedResponseList());
+		List rec=new ArrayList();
+		String line;
+		while ((line=br.readLine())!=null) {
+			 rec.add(line);
+		}
+		assertFalse("nothing received",rec.isEmpty());
+		String statusResponse=(String)rec.get(rec.size()-1);
+		rec.remove(rec.size()-1);
+		Set responseSet=new HashSet(rec);
+		responseSet.removeAll(requiredResponseSet);
+		requiredResponseSet.removeAll(new HashSet(rec));
+		if (responseSet.size()>0) {
+			System.out.println("Not awaitet responses: "+responseSet);
+		}
+		if (requiredResponseSet.size()>0) {
+			System.out.println("Missed responses: "+requiredResponseSet);
+		}
+		assertEquals("Missed responses: "+requiredResponseSet,0,requiredResponseSet.size());
+		assertEquals("Not awaitet responses: "+responseSet,0,responseSet.size());
+		assertEquals("Status respons differs",counter+" "+command.getExpectedStatusResponse(),statusResponse);
+	}
+	
+	protected void  verifyCommandOrdered(Command command)  throws ProtocolException, IOException, MessagingException
+	{
+		BufferedReader br=handleRequestReader((++counter)+" "+command.getCommand()+"\n");
+		
+		int c=0;
+		for (Iterator it = command.getExpectedResponseList().iterator(); it.hasNext();) {
+			c++;
+			String expectedResponse = (String) it.next();
+//			System.out.println("Expected: "+expectedResponse);
+			String[] expectedLines=expectedResponse.split("\r\n");
+			for (int i = 0; i < expectedLines.length; i++) {
+				String readLine=br.readLine();
+				assertNotNull("Unexpected end of response (response "+c+" line "+i+")",readLine);
+				assertEquals("Unexpected response line (response "+c+" line "+i+")",expectedLines[i],readLine);				
+			}
+		}
+		
+		String statusResponse=(String)br.readLine();;
+		assertEquals("Status response differs",counter+" "+command.getExpectedStatusResponse(),statusResponse);
+		String notExpected=br.readLine();
+		assertNull("did expect eof",notExpected);
+	}
+    
+    public void setFlags(String mailboxName,long fromUid,long toUid,Flags flags, boolean value, boolean replace) throws MailboxManagerException {
+    	ImapMailboxSession mailbox=getImapMailboxSession(mailboxName);
+        mailbox.setFlags(flags, value, replace, GeneralMessageSetImpl.uidRange(fromUid, toUid), null);
+        mailbox.close();
+    }
+    private ImapMailboxSession getImapMailboxSession(String mailboxName) throws MailboxManagerException {
+    	int[] neededSets = new int[] {GeneralMessageSet.TYPE_UID};
+    	int neededResults= MessageResult.UID + MessageResult.MIME_MESSAGE + MessageResult.FLAGS;
+    	ImapMailboxSession mailboxSession= (ImapMailboxSession) mailboxManager.getMailboxSession(mailboxName, ImapMailboxSession.class, neededSets, neededResults);
+    	return mailboxSession;
+    }
+}

Added: james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/BodyFetchSessionTest.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/BodyFetchSessionTest.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/BodyFetchSessionTest.java (added)
+++ james/server/sandbox/imap-integration/src/test/org/apache/james/imapserver/handler/session/BodyFetchSessionTest.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,107 @@
+package org.apache.james.imapserver.handler.session;
+
+import java.io.IOException;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.client.FetchCommand;
+import org.apache.james.imapserver.client.LoginCommand;
+import org.apache.james.imapserver.client.SelectCommand;
+import org.apache.james.imapserver.client.fetch.FetchBody;
+import org.apache.james.imapserver.client.fetch.FetchHeader;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.imapserver.util.MessageGenerator;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+
+/**
+ * 
+ * 
+ * 
+ * TODO test one message number instead of message sets (1 instead of 1:1)
+ *
+ */
+
+public class BodyFetchSessionTest extends AbstractSessionTest {
+	
+	String[] onlyInbox = {USER_MAILBOX_ROOT+".INBOX"};
+	MimeMessage[] msgs= null;
+	long[] uids = null;
+	
+	public void setUp() throws MailboxException, MessagingException, IOException, MailboxManagerException {
+		super.setUp();
+		msgs=MessageGenerator.generateSimplesMessages(4);
+		createFolders(onlyInbox);
+		// increase the uid
+		appendMessagesClosed(USER_MAILBOX_ROOT+".INBOX",msgs);
+		deleteAll(USER_MAILBOX_ROOT+".INBOX");
+		uids=addUIDMessagesOpen(USER_MAILBOX_ROOT+".INBOX",msgs);
+	}
+	
+	
+	public void testFetchCompleteAndSize() throws ProtocolException, IOException, MessagingException, MailboxManagerException {
+		verifyCommand(new LoginCommand(USER_NAME,USER_PASSWORD));
+		verifyCommand(new SelectCommand("INBOX", msgs, getUidValidity(USER_MAILBOX_ROOT+".INBOX")));
+		msgs=getMessages(USER_MAILBOX_ROOT+".INBOX");
+		FetchCommand fc=new FetchCommand(msgs,1,-1);
+		fc.setFetchRfc822Size(true);
+		fc.setFetchBody(new FetchBody(true));
+		// TODO test \Seen get's not set because of peek and vice versa
+		verifyCommandOrdered(fc);
+	}
+	public void testFetchCompleteHeader() throws ProtocolException, IOException, MessagingException, MailboxManagerException {
+		verifyCommand(new LoginCommand(USER_NAME,USER_PASSWORD));
+		verifyCommand(new SelectCommand("INBOX", msgs, getUidValidity(USER_MAILBOX_ROOT+".INBOX")));
+		msgs=getMessages(USER_MAILBOX_ROOT+".INBOX");
+		FetchCommand fc=new FetchCommand(msgs,1,-1);
+		fc.setFetchRfc822Size(true);
+		FetchBody fetchBody=new FetchBody(true);
+		fetchBody.setFetchHeader(new FetchHeader());
+		fc.setFetchBody(fetchBody);
+		verifyCommandOrdered(fc);
+	}
+	public void testFetchSomeExistingHeader() throws ProtocolException, IOException, MessagingException, MailboxManagerException {
+		verifyCommand(new LoginCommand(USER_NAME,USER_PASSWORD));
+		verifyCommand(new SelectCommand("INBOX", msgs, getUidValidity(USER_MAILBOX_ROOT+".INBOX")));
+		msgs=getMessages(USER_MAILBOX_ROOT+".INBOX");
+		FetchCommand fc=new FetchCommand(msgs,1,-1);
+		fc.setFetchRfc822Size(true);
+		FetchHeader fetchHeader=new FetchHeader();
+		fetchHeader.setFields(new String[] {"Date","From","To"});
+		FetchBody fetchBody=new FetchBody(true);
+		fetchBody.setFetchHeader(fetchHeader);
+		fc.setFetchBody(fetchBody);
+		verifyCommandOrdered(fc);
+	}
+	public void testFetchSomeNonExistingHeader() throws ProtocolException, IOException, MessagingException, MailboxManagerException {
+		verifyCommand(new LoginCommand(USER_NAME,USER_PASSWORD));
+		verifyCommand(new SelectCommand("INBOX", msgs, getUidValidity(USER_MAILBOX_ROOT+".INBOX")));
+		msgs=getMessages(USER_MAILBOX_ROOT+".INBOX");
+		FetchCommand fc=new FetchCommand(msgs,1,-1);
+		fc.setFetchRfc822Size(true);
+		FetchHeader fetchHeader=new FetchHeader();
+		fetchHeader.setFields(new String[] {"Blob","Test","Oh"});
+		FetchBody fetchBody=new FetchBody(true);
+		fetchBody.setFetchHeader(fetchHeader);
+		fc.setFetchBody(fetchBody);
+		verifyCommandOrdered(fc);
+	}
+	public void testFetchSomeNoneAndExistingHeader() throws ProtocolException, IOException, MessagingException, MailboxManagerException {
+		verifyCommand(new LoginCommand(USER_NAME,USER_PASSWORD));
+		verifyCommand(new SelectCommand("INBOX", msgs, getUidValidity(USER_MAILBOX_ROOT+".INBOX")));
+		msgs=getMessages(USER_MAILBOX_ROOT+".INBOX");
+		FetchCommand fc=new FetchCommand(msgs,1,-1);
+		fc.setFetchRfc822Size(true);
+		FetchHeader fetchHeader=new FetchHeader();
+		fetchHeader.setFields(new String[] {"To","Message-ID","Blob","Test","Oh"});
+		FetchBody fetchBody=new FetchBody(true);
+		fetchBody.setFetchHeader(fetchHeader);
+		fc.setFetchBody(fetchBody);
+		verifyCommandOrdered(fc);
+	}
+
+	
+		
+
+}



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