1 /****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20
21
22 package org.apache.james.transport.matchers;
23
24 import org.apache.avalon.framework.container.ContainerUtil;
25 import org.apache.avalon.framework.service.ServiceException;
26 import org.apache.avalon.framework.service.ServiceManager;
27 import org.apache.james.Constants;
28 import org.apache.james.api.user.JamesUser;
29 import org.apache.james.api.user.UsersRepository;
30 import org.apache.james.services.MailRepository;
31 import org.apache.james.services.MailServer;
32 import org.apache.mailet.Mail;
33 import org.apache.mailet.MailAddress;
34 import org.apache.mailet.MailetContext;
35
36 import javax.mail.MessagingException;
37
38 import java.util.Iterator;
39
40 /**
41 * <P>Experimental: Abstract matcher checking whether a recipient has exceeded a maximum allowed
42 * <I>storage</I> quota for messages standing in his inbox.</P>
43 * <P>"Storage quota" at this level is still an abstraction whose specific interpretation
44 * will be done by subclasses (e.g. could be specific for each user or common to all of them).</P>
45 *
46 * <P>This matcher need to calculate the mailbox size everytime it is called. This can slow down things if there are many mails in
47 * the mailbox. Some users also report big problems with the matcher if a JDBC based mailrepository is used. </P>
48 *
49 * @version CVS $Revision: 684470 $ $Date: 2008-08-10 12:47:55 +0100 (Sun, 10 Aug 2008) $
50 * @since 2.2.0
51 */
52 abstract public class AbstractStorageQuota extends AbstractQuotaMatcher {
53
54 private MailServer mailServer;
55
56 /** The user repository for this mail server. Contains all the users with inboxes
57 * on this server.
58 */
59 private UsersRepository localusers;
60
61 /**
62 * Standard matcher initialization.
63 * Overriding classes must do a <CODE>super.init()</CODE>.
64 */
65 public void init() throws MessagingException {
66 super.init();
67 ServiceManager compMgr = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
68 try {
69 mailServer = (MailServer) compMgr.lookup(MailServer.ROLE);
70 } catch (ServiceException e) {
71 log("Exception in getting the MailServer: " + e.getMessage() + e.getKey());
72 }
73 try {
74 localusers = (UsersRepository) compMgr.lookup(UsersRepository.ROLE);
75 } catch (ServiceException e) {
76 log("Exception in getting the UsersStore: " + e.getMessage() + e.getKey());
77 }
78 }
79
80 /**
81 * Checks the recipient.
82 * Does a <CODE>super.isRecipientChecked</CODE> and checks that the recipient
83 * is a known user in the local server.
84 * If a subclass overrides this method it should "and" <CODE>super.isRecipientChecked</CODE>
85 * to its check.
86 *
87 * @param recipient the recipient to check
88 */
89 protected boolean isRecipientChecked(MailAddress recipient) throws MessagingException {
90 MailetContext mailetContext = getMailetContext();
91 return super.isRecipientChecked(recipient) && (mailetContext.isLocalEmail(recipient));
92 }
93
94 /**
95 * Gets the storage used in the recipient's inbox.
96 *
97 * @param recipient the recipient to check
98 */
99 protected long getUsed(MailAddress recipient, Mail _) throws MessagingException {
100 long size = 0;
101 MailRepository userInbox = mailServer.getUserInbox(getPrimaryName(recipient.getUser()));
102 for (Iterator it = userInbox.list(); it.hasNext(); ) {
103 String key = (String) it.next();
104 Mail mc = userInbox.retrieve(key);
105 // Retrieve can return null if the mail is no longer in the store.
106 if (mc != null) try {
107 size += mc.getMessageSize();
108 } catch (Throwable e) {
109 // MailRepository.retrieve() does NOT lock the message.
110 // It could be deleted while we're looping.
111 log("Exception in getting message size: " + e.getMessage());
112 }
113 ContainerUtil.dispose(mc);
114 }
115 return size;
116 }
117
118 /**
119 * Gets the main name of a local customer, handling aliases.
120 *
121 * @param originalUsername the user name to look for; it can be already the primary name or an alias
122 * @return the primary name, or originalUsername unchanged if not found
123 */
124 protected String getPrimaryName(String originalUsername) {
125 String username;
126 try {
127 username = localusers.getRealName(originalUsername);
128 JamesUser user = (JamesUser) localusers.getUserByName(username);
129 if (user.getAliasing()) {
130 username = user.getAlias();
131 }
132 }
133 catch (Exception e) {
134 username = originalUsername;
135 }
136 return username;
137 }
138
139 }