KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > imapserver > JamesImapHost


1 /***********************************************************************
2  * Copyright (c) 2000-2004 The Apache Software Foundation. *
3  * All rights reserved. *
4  * ------------------------------------------------------------------- *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you *
6  * may not use this file except in compliance with the License. You *
7  * may obtain a copy of the License at: *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14  * implied. See the License for the specific language governing *
15  * permissions and limitations under the License. *
16  ***********************************************************************/

17
18 package org.apache.james.imapserver;
19
20 import org.apache.james.services.User;
21 import org.apache.james.imapserver.store.ImapStore;
22 import org.apache.james.imapserver.store.InMemoryStore;
23 import org.apache.james.imapserver.store.ImapMailbox;
24 import org.apache.james.imapserver.store.MailboxException;
25 import org.apache.james.imapserver.store.SimpleImapMessage;
26 import org.apache.james.imapserver.store.MessageFlags;
27 import org.apache.avalon.framework.logger.AbstractLogEnabled;
28 import org.apache.avalon.framework.logger.ConsoleLogger;
29
30 import javax.mail.search.SearchTerm JavaDoc;
31 import javax.mail.internet.MimeMessage JavaDoc;
32 import javax.mail.MessagingException JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.StringTokenizer JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.Date JavaDoc;
40
41 /**
42  * An initial implementation of an ImapHost. By default, uses,
43  * the {@link org.apache.james.imapserver.store.InMemoryStore} implementation of {@link org.apache.james.imapserver.store.ImapStore}.
44  * TODO: Make the underlying store configurable with Phoenix.
45  *
46  *
47  * @version $Revision: 1.5.2.3 $
48  */

49 public class JamesImapHost
50         extends AbstractLogEnabled
51         implements ImapHost, ImapConstants
52 {
53     private ImapStore store;
54     private MailboxSubscriptions subscriptions;
55
56     /**
57      * Hack constructor which creates an in-memory store, and creates a console logger.
58      */

59     public JamesImapHost()
60     {
61         enableLogging( new ConsoleLogger() );
62         store = new InMemoryStore();
63         setupLogger( store );
64         subscriptions = new MailboxSubscriptions();
65     }
66
67     public JamesImapHost( ImapStore store )
68     {
69         this.store = store;
70         subscriptions = new MailboxSubscriptions();
71     }
72
73     public char getHierarchyDelimiter()
74     {
75         return HIERARCHY_DELIMITER_CHAR;
76     }
77
78     /** @see ImapHost#getMailbox */
79     public ImapMailbox getMailbox( User user, String JavaDoc mailboxName )
80     {
81         String JavaDoc name = getQualifiedMailboxName( user, mailboxName );
82         ImapMailbox mailbox = store.getMailbox( name );
83         return ( checkViewable( mailbox ) );
84     }
85
86     public ImapMailbox getMailbox( User user, String JavaDoc mailboxName, boolean mustExist )
87             throws MailboxException
88     {
89         ImapMailbox mailbox = getMailbox( user, mailboxName );
90         if ( mustExist && mailbox == null )
91         {
92             throw new MailboxException( "No such mailbox." );
93         }
94         return mailbox;
95     }
96
97     private ImapMailbox checkViewable( ImapMailbox mailbox )
98     {
99         // TODO implement this.
100
return mailbox;
101     }
102
103     /** @see ImapHost#getInbox */
104     public ImapMailbox getInbox( User user ) throws MailboxException
105     {
106         return getMailbox( user, INBOX_NAME );
107     }
108
109     /** @see ImapHost#createPrivateMailAccount */
110     public void createPrivateMailAccount( User user ) throws MailboxException
111     {
112         ImapMailbox root = store.getMailbox( USER_NAMESPACE );
113         ImapMailbox userRoot = store.createMailbox( root, user.getUserName(), false );
114         store.createMailbox( userRoot, INBOX_NAME, true );
115     }
116
117     /** @see ImapHost#createMailbox */
118     public ImapMailbox createMailbox( User user, String JavaDoc mailboxName )
119             throws AuthorizationException, MailboxException
120     {
121         String JavaDoc qualifiedName = getQualifiedMailboxName( user, mailboxName );
122         if ( store.getMailbox( qualifiedName ) != null )
123         {
124             throw new MailboxException( "Mailbox already exists." );
125         }
126
127         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc( qualifiedName,
128                                                       HIERARCHY_DELIMITER );
129
130         if ( tokens.countTokens() < 2 ) {
131             throw new MailboxException( "Cannot create mailbox at namespace level." );
132         }
133
134         String JavaDoc namespaceRoot = tokens.nextToken();
135         ImapMailbox mailbox = store.getMailbox( namespaceRoot );
136         if ( mailbox == null ) {
137             throw new MailboxException( "Invalid namespace." );
138         }
139
140         while ( tokens.hasMoreTokens() ) {
141             // Get the next name from the list, and find the child
142
String JavaDoc childName = tokens.nextToken();
143             ImapMailbox child = store.getMailbox( mailbox, childName );
144             // Create if neccessary
145
if ( child == null ) {
146                 // TODO check permissions.
147
boolean makeSelectable = ( !tokens.hasMoreTokens() );
148                 child = store.createMailbox( mailbox, childName, makeSelectable );
149             }
150             mailbox = child;
151         }
152
153         return mailbox;
154     }
155
156     /** @see ImapHost#deleteMailbox */
157     public void deleteMailbox( User user, String JavaDoc mailboxName )
158             throws MailboxException, AuthorizationException
159     {
160         ImapMailbox toDelete = getMailbox( user, mailboxName, true );
161
162         if ( store.getChildren( toDelete ).isEmpty() ) {
163             long[] uids = toDelete.getMessageUids();
164             for ( int i = 0; i < uids.length; i++ ) {
165                 long uid = uids[i];
166                 SimpleImapMessage imapMessage = toDelete.getMessage( uid );
167                 toDelete.deleteMessage( imapMessage.getUid() );
168             }
169             store.deleteMailbox( toDelete );
170         }
171         else {
172             if ( toDelete.isSelectable() ) {
173                 // TODO delete all messages.
174
store.setSelectable( toDelete, false );
175             }
176             else {
177                 throw new MailboxException( "Can't delete a non-selectable mailbox with children." );
178             }
179         }
180     }
181
182     /** @see ImapHost#renameMailbox */
183     public void renameMailbox( User user,
184                                String JavaDoc oldMailboxName,
185                                String JavaDoc newMailboxName )
186             throws MailboxException, AuthorizationException
187     {
188
189         ImapMailbox existingMailbox = getMailbox( user, oldMailboxName, true );
190
191         // TODO: check permissions.
192

193         // Handle case where existing is INBOX
194
// - just create new folder, move all messages,
195
// and leave INBOX (with children) intact.
196
String JavaDoc userInboxName = getQualifiedMailboxName( user, INBOX_NAME );
197         if ( userInboxName.equals( existingMailbox.getFullName() ) ) {
198             ImapMailbox newBox = createMailbox( user, newMailboxName );
199             // TODO copy all messages from INBOX.
200
return;
201         }
202
203         store.renameMailbox( existingMailbox, newMailboxName );
204     }
205
206     /** @see ImapHost#listSubscribedMailboxes */
207     public Collection JavaDoc listSubscribedMailboxes( User user,
208                                                String JavaDoc mailboxPattern )
209             throws MailboxException
210     {
211         return listMailboxes( user, mailboxPattern, true );
212     }
213
214     /** @see ImapHost#listMailboxes */
215     public Collection JavaDoc listMailboxes( User user,
216                                      String JavaDoc mailboxPattern )
217             throws MailboxException
218     {
219         return listMailboxes( user, mailboxPattern, false );
220     }
221
222     /**
223      * Partial implementation of list functionality.
224      * TODO: Handle wildcards anywhere in mailbox pattern
225      * (currently only supported as last character of pattern)
226      * @see org.apache.james.imapserver.ImapHost#listMailboxes
227      */

228     private Collection JavaDoc listMailboxes( User user,
229                                      String JavaDoc mailboxPattern,
230                                      boolean subscribedOnly )
231             throws MailboxException
232     {
233 // System.out.println( "Listing for user: '" + user.getUserName() + "'" +
234
// " pattern:'" + mailboxPattern + "'" );
235

236         ArrayList JavaDoc mailboxes = new ArrayList JavaDoc();
237         String JavaDoc qualifiedPattern = getQualifiedMailboxName( user, mailboxPattern );
238
239         Iterator JavaDoc iter = store.listMailboxes( qualifiedPattern ).iterator();
240         while ( iter.hasNext() ) {
241             ImapMailbox mailbox = ( ImapMailbox ) iter.next();
242
243             // TODO check subscriptions.
244
if ( subscribedOnly ) {
245                 if ( ! subscriptions.isSubscribed( user, mailbox ) ) {
246                     // if not subscribed
247
mailbox = null;
248                 }
249             }
250
251             // Sets the mailbox to null if it's not viewable.
252
mailbox = checkViewable( mailbox );
253
254             if ( mailbox != null ) {
255                 mailboxes.add( mailbox );
256             }
257         }
258
259         return mailboxes;
260     }
261
262     /** @see ImapHost#subscribe */
263     public void subscribe( User user, String JavaDoc mailboxName )
264             throws MailboxException
265     {
266         ImapMailbox mailbox = getMailbox( user, mailboxName, true );
267         subscriptions.subscribe( user, mailbox );
268     }
269
270     /** @see ImapHost#unsubscribe */
271     public void unsubscribe( User user, String JavaDoc mailboxName )
272             throws MailboxException
273     {
274         ImapMailbox mailbox = getMailbox( user, mailboxName, true );
275         subscriptions.unsubscribe( user, mailbox );
276     }
277
278     public int[] expunge( ImapMailbox mailbox )
279             throws MailboxException
280     {
281         ArrayList JavaDoc deletedMessages = new ArrayList JavaDoc();
282
283         long[] uids = mailbox.getMessageUids();
284         for ( int i = 0; i < uids.length; i++ ) {
285             long uid = uids[i];
286             SimpleImapMessage message = mailbox.getMessage( uid );
287             if ( message.getFlags().isDeleted() ) {
288                 deletedMessages.add( message );
289             }
290         }
291
292         int[] ids = new int[ deletedMessages.size() ];
293         for ( int i = 0; i < ids.length; i++ ) {
294             SimpleImapMessage imapMessage = ( SimpleImapMessage ) deletedMessages.get( i );
295             long uid = imapMessage.getUid();
296             int msn = mailbox.getMsn( uid );
297             ids[i] = msn;
298             mailbox.deleteMessage( uid );
299         }
300
301         return ids;
302     }
303
304     public long[] search( SearchTerm JavaDoc searchTerm, ImapMailbox mailbox )
305     {
306         ArrayList JavaDoc matchedMessages = new ArrayList JavaDoc();
307
308         long[] allUids = mailbox.getMessageUids();
309         for ( int i = 0; i < allUids.length; i++ ) {
310             long uid = allUids[i];
311             SimpleImapMessage message = mailbox.getMessage( uid );
312             if ( searchTerm.match( message.getMimeMessage() ) ) {
313                 matchedMessages.add( message );
314             }
315         }
316
317         long[] matchedUids = new long[ matchedMessages.size() ];
318         for ( int i = 0; i < matchedUids.length; i++ ) {
319             SimpleImapMessage imapMessage = ( SimpleImapMessage ) matchedMessages.get( i );
320             long uid = imapMessage.getUid();
321             matchedUids[i] = uid;
322         }
323         return matchedUids;
324     }
325
326     /** @see {@link ImapHost#copyMessage } */
327     public void copyMessage( long uid, ImapMailbox currentMailbox, ImapMailbox toMailbox )
328             throws MailboxException
329     {
330         SimpleImapMessage originalMessage = currentMailbox.getMessage( uid );
331         MimeMessage JavaDoc newMime = null;
332         try {
333             newMime = new MimeMessage JavaDoc( originalMessage.getMimeMessage() );
334         }
335         catch ( MessagingException JavaDoc e ) {
336             // TODO chain.
337
throw new MailboxException( "Messaging exception: " + e.getMessage() );
338         }
339         MessageFlags newFlags = new MessageFlags();
340         newFlags.setAll( originalMessage.getFlags() );
341         Date JavaDoc newDate = originalMessage.getInternalDate();
342
343         toMailbox.createMessage( newMime, newFlags, newDate);
344     }
345
346     /**
347      * Convert a user specified mailbox name into a server absolute name.
348      * If the mailboxName begins with the namespace token,
349      * return as-is.
350      * If not, need to resolve the Mailbox name for this user.
351      * Example:
352      * <br> Convert "INBOX" for user "Fred.Flinstone" into
353      * absolute name: "#user.Fred.Flintstone.INBOX"
354      *
355      * @return String of absoluteName, null if not valid selection
356      */

357     private String JavaDoc getQualifiedMailboxName( User user, String JavaDoc mailboxName )
358     {
359         String JavaDoc userName = user.getUserName();
360
361         if ( "INBOX".equalsIgnoreCase( mailboxName ) ) {
362             return USER_NAMESPACE + HIERARCHY_DELIMITER + userName +
363                     HIERARCHY_DELIMITER + INBOX_NAME;
364         }
365
366         if ( mailboxName.startsWith( NAMESPACE_PREFIX ) ) {
367             return mailboxName;
368         }
369         else {
370             if ( mailboxName.length() == 0 ) {
371                 return USER_NAMESPACE + HIERARCHY_DELIMITER + userName;
372             }
373             else {
374                 return USER_NAMESPACE + HIERARCHY_DELIMITER + userName +
375                         HIERARCHY_DELIMITER + mailboxName;
376             }
377         }
378     }
379
380     /**
381      * Handles all user subscriptions.
382      * TODO make this a proper class
383      * TODO persist
384      */

385     private class MailboxSubscriptions
386     {
387         private Map JavaDoc userSubs = new HashMap JavaDoc();
388
389         /**
390          * Subscribes the user to the mailbox.
391          * TODO should this fail if already subscribed?
392          * @param user The user making the subscription
393          * @param mailbox The mailbox to subscribe
394          * @throws MailboxException ??? doesn't yet.
395          */

396         void subscribe( User user, ImapMailbox mailbox )
397                 throws MailboxException
398         {
399             getUserSubs( user ).add( mailbox.getFullName() );
400         }
401
402         /**
403          * Unsubscribes the user from this mailbox.
404          * TODO should this fail if not already subscribed?
405          * @param user The user making the request.
406          * @param mailbox The mailbox to unsubscribe
407          * @throws MailboxException ?? doesn't yet
408          */

409         void unsubscribe( User user, ImapMailbox mailbox )
410                 throws MailboxException
411         {
412             getUserSubs( user ).remove( mailbox.getFullName() );
413         }
414
415         /**
416          * Returns whether the user is subscribed to the specified mailbox.
417          * @param user The user to test.
418          * @param mailbox The mailbox to test.
419          * @return <code>true</code> if the user is subscribed.
420          */

421         boolean isSubscribed( User user, ImapMailbox mailbox )
422         {
423             return getUserSubs( user ).contains( mailbox.getFullName() );
424         }
425
426         private Collection JavaDoc getUserSubs( User user )
427         {
428             Collection JavaDoc subs = (Collection JavaDoc)userSubs.get( user.getUserName() );
429             if ( subs == null ) {
430                 subs = new ArrayList JavaDoc();
431                 userSubs.put( user.getUserName(), subs );
432             }
433             return subs;
434         }
435     }
436
437
438 }
439
Popular Tags