/****************************************************************
 * 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.transport.matchers;

import java.util.Iterator;

import javax.annotation.Resource;
import javax.mail.MessagingException;

import org.apache.james.mailbox.BadCredentialsException;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MailboxPath;
import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MailboxConstants;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageRange;
import org.apache.james.mailbox.MessageResult;
import org.apache.james.mailbox.MessageResult.FetchGroup;
import org.apache.james.mailbox.util.FetchGroupImpl;
import org.apache.james.user.api.UsersRepository;
import org.apache.james.user.api.model.JamesUser;
import org.apache.james.transport.util.MailetContextLog;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;

/**
 * <P>Experimental: Abstract matcher checking whether a recipient has exceeded a maximum allowed
 * <I>storage</I> quota for messages standing in his inbox.</P>
 * <P>"Storage quota" at this level is still an abstraction whose specific interpretation
 * will be done by subclasses (e.g. could be specific for each user or common to all of them).</P> 
 *
 * <P>This matcher need to calculate the mailbox size everytime it is called. This can slow down things if there are many mails in
 * the mailbox. Some users also report big problems with the matcher if a JDBC based mailrepository is used. </P>
 *
 * @version CVS $Revision$ $Date$
 * @since 2.2.0
 */
abstract public class AbstractStorageQuota extends AbstractQuotaMatcher { 

    private MailboxManager manager;

    @Resource(name="mailboxmanager")
    public void setMailboxManager(MailboxManager manager) {
        this.manager = manager;
    }
    
    @Resource(name="usersrepository")
    public void setUsersRepository(UsersRepository localusers) {
        this.localusers = localusers;
    }
    /** The user repository for this mail server.  Contains all the users with inboxes
     * on this server.
     */
    private UsersRepository localusers;

    private MailetContextLog log;
    
    /** 
     * Checks the recipient.
     * Does a <CODE>super.isRecipientChecked</CODE> and checks that the recipient
     * is a known user in the local server.
     * If a subclass overrides this method it should "and" <CODE>super.isRecipientChecked</CODE>
     * to its check.
     *
     * @param recipient the recipient to check
     */    
    protected boolean isRecipientChecked(MailAddress recipient) throws MessagingException {
        MailetContext mailetContext = getMailetContext();
        return super.isRecipientChecked(recipient) && (mailetContext.isLocalEmail(recipient));
    }

    @Override
    public void init() throws MessagingException {
        super.init();
        
        // init the log
        log = new MailetContextLog(getMailetContext());
    }

    /** 
     * Gets the storage used in the recipient's inbox.
     *
     * @param recipient the recipient to check
     */    
    protected long getUsed(MailAddress recipient, Mail _) throws MessagingException {
        long size = 0;
        MailboxSession session;
        try {
            session = manager.createSystemSession(getPrimaryName(recipient.getLocalPart()),log); 
            manager.startProcessingRequest(session);
            MessageManager mailbox = manager.getMailbox(new MailboxPath(MailboxConstants.USER_NAMESPACE,
                                                session.getUser().getUserName(), "INBOX"),
                                                session);
            Iterator<MessageResult> results = mailbox.getMessages(MessageRange.all(), new FetchGroupImpl(FetchGroup.MINIMAL), session);
            
            while (results.hasNext()) {
            	size += results.next().getSize();
            }
            manager.endProcessingRequest(session);
            manager.logout(session, true);
        } catch (BadCredentialsException e) {
            throw new MessagingException("Unable to authenticate to mailbox", e);
        } catch (MailboxException e) {
            throw new MessagingException("Unable to get used space from mailbox", e);
        }

        return size;

    }

    /**
     * Gets the main name of a local customer, handling aliases.
     *
     * @param originalUsername the user name to look for; it can be already the primary name or an alias
     * @return the primary name, or originalUsername unchanged if not found
     */
    protected String getPrimaryName(String originalUsername) {
        String username;
        try {
            username = originalUsername;
            JamesUser user = (JamesUser) localusers.getUserByName(username);
            if (user.getAliasing()) {
                username = user.getAlias();
            }
        }
        catch (Exception e) {
            username = originalUsername;
        }
        return username;
    }
    
}

@@ -1257,16 +1257,41 @@
 terator;
+%0Aimport java.util.Locale;
 %0A%0Aimport
@@ -1994,23 +1994,32 @@
 api.
-model.JamesUser
+UsersRepositoryException
 ;%0Aim
@@ -4525,86 +4525,624 @@
     
-session = manager.createSystemSession(getPrimaryName(recipient.getLocalPart())
+String username;%0A            try %7B%0A                // see if we need use the full email address as username or not. %0A                // See JAMES-1197%0A                if (localusers.supportVirtualHosting()) %7B%0A                    username = recipient.toString().toLowerCase(Locale.US);%0A                %7D else %7B%0A                    username = recipient.getLocalPart().toLowerCase(Locale.US);%0A                %7D%0A            %7D catch (UsersRepositoryException e) %7B%0A                throw new MessagingException(%22Unable to access UsersRepository%22, e);%0A            %7D%0A            session = manager.createSystemSession(username
 ,log
@@ -6093,715 +6093,8 @@
  %7D%0A%0A
-    /**%0A     * Gets the main name of a local customer, handling aliases.%0A     *%0A     * @param originalUsername the user name to look for; it can be already the primary name or an alias%0A     * @return the primary name, or originalUsername unchanged if not found%0A     */%0A    protected String getPrimaryName(String originalUsername) %7B%0A        String username;%0A        try %7B%0A            username = originalUsername;%0A            JamesUser user = (JamesUser) localusers.getUserByName(username);%0A            if (user.getAliasing()) %7B%0A                username = user.getAlias();%0A            %7D%0A        %7D%0A        catch (Exception e) %7B%0A            username = originalUsername;%0A        %7D%0A        return username;%0A    %7D%0A
     

Use the right username to lookup Mailbox depending on useVirtualHosting setting. See JAMES-1197