View Javadoc

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  package org.apache.james.imapserver;
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.util.Date;
25  
26  import javax.mail.MessagingException;
27  import javax.mail.internet.MimeMessage;
28  
29  import org.apache.avalon.framework.configuration.Configuration;
30  import org.apache.avalon.framework.configuration.ConfigurationException;
31  import org.apache.avalon.framework.service.ServiceException;
32  import org.apache.avalon.framework.service.ServiceManager;
33  import org.apache.commons.logging.impl.AvalonLogger;
34  import org.apache.james.Constants;
35  import org.apache.james.api.user.UsersRepository;
36  import org.apache.james.imap.api.ImapConstants;
37  import org.apache.james.imap.mailbox.Mailbox;
38  import org.apache.james.imap.mailbox.MailboxManager;
39  import org.apache.james.imap.mailbox.MailboxSession;
40  import org.apache.james.imap.main.ImapRequestHandler;
41  import org.apache.james.services.FileSystem;
42  import org.apache.james.socket.AbstractJamesService;
43  import org.apache.james.socket.ProtocolHandler;
44  import org.apache.jsieve.mailet.Poster;
45  
46  /**
47   * TODO: this is a quick cut-and-paste hack from POP3Server. Should probably be
48   * rewritten from scratch, together with ImapHandler.
49   *
50   * <p>Accepts IMAP connections on a server socket and dispatches them to IMAPHandlers.</p>
51   *
52   * <p>Also responsible for loading and parsing IMAP specific configuration.</p>
53   */
54  public class ImapServer extends AbstractJamesService implements ImapConstants, Poster
55  {
56      private static final String softwaretype = "JAMES "+VERSION+" Server " + Constants.SOFTWARE_VERSION;
57       
58      private DefaultImapFactory factory;
59      
60      private String hello = softwaretype;
61      
62      
63      public void service(ServiceManager comp) throws ServiceException {
64          super.service(comp);
65          factory = new DefaultImapFactory((FileSystem) comp.lookup(FileSystem.ROLE), 
66                  (UsersRepository) comp.lookup(UsersRepository.ROLE), getLogger());
67      }
68  
69  
70      @Override
71      public void dispose() {
72          super.dispose();
73      }
74  
75  
76  
77      @Override
78      public void initialize() throws Exception {
79          getLogger().debug("Initialising...");
80          factory.initialize();
81          super.initialize();
82      }
83  
84  
85  
86      /**
87       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
88       */
89      public void configure( final Configuration configuration ) throws ConfigurationException {
90          super.configure( configuration );
91          factory.configure(configuration);
92          hello  = softwaretype + " Server " + helloName + " is ready.";
93      }
94      
95      /**
96       * @see AbstractJamesService#getDefaultPort()
97       */
98      protected int getDefaultPort() {
99          return 143;
100     }
101 
102     /**
103      * @see AbstractJamesService#getServiceType()
104      */
105     public String getServiceType() {
106         return "IMAP Service";
107     }
108 
109     /**
110      * Producing handlers.
111      * @see org.apache.avalon.excalibur.pool.ObjectFactory#newInstance()
112      */
113     public ProtocolHandler newProtocolHandlerInstance()
114     {  
115         final ImapRequestHandler handler = factory.createHandler();
116         final ImapHandler imapHandler = new ImapHandler(handler, hello); 
117         getLogger().debug("Create handler instance");
118         return imapHandler;
119     }
120 
121     // TODO: 
122     protected Object getConfigurationData() {
123         return null;
124     }
125     
126     public void post(String url, MimeMessage mail)throws MessagingException {
127         final int endOfScheme = url.indexOf(':');
128         if (endOfScheme < 0) {
129             throw new MessagingException("Malformed URI");
130         } else {
131             final String scheme = url.substring(0, endOfScheme);
132             if ("mailbox".equals(scheme)) {
133                 final int startOfUser = endOfScheme + 3;
134                 final int endOfUser = url.indexOf('@', startOfUser);
135                 if (endOfUser < 0) {
136                     // TODO: when user missing, append to a default location
137                     throw new MessagingException("Shared mailbox is not supported");
138                 } else {
139                     final String user = url.substring(startOfUser, endOfUser);
140                     final int startOfHost = endOfUser + 1;
141                     final int endOfHost  = url.indexOf('/', startOfHost);
142                     final String host = url.substring(startOfHost, endOfHost);
143                     if (!"localhost".equals(host)) {
144                         //TODO: possible support for clustering?
145                         throw new MessagingException("Only local mailboxes are supported");
146                     } else {
147                         final String urlPath;
148                         final int length = url.length();
149                         if (endOfHost + 1 == length) {
150                             urlPath = "INBOX";
151                         } else {
152                             urlPath = url.substring(endOfHost, length);
153                         }
154                         final MailboxManager mailboxManager = factory.getMailbox();
155                         final MailboxSession session = mailboxManager.createSystemSession(user, new AvalonLogger(getLogger()));
156                         // This allows Sieve scripts to use a standard delimiter regardless of mailbox implementation
157                         final String mailbox = urlPath.replace('/', session.getPersonalSpace().getDeliminator());
158                         postToMailbox(user, mail, mailbox, session, mailboxManager);
159                     }
160                 }
161             } else {
162                 // TODO: add support for more protocols
163                 // TODO: for example mailto: for forwarding over SMTP
164                 // TODO: for example xmpp: for forwarding over Jabber
165                 throw new MessagingException("Unsupported protocol");
166             }
167         }
168     }
169     
170     public void postToMailbox(String username, MimeMessage mail, String destination, final MailboxSession session, final MailboxManager mailboxManager) throws MessagingException {
171         if (destination == null || "".equals(destination)) {
172             destination = "INBOX";
173         }
174         final String name = mailboxManager.resolve(username, destination);
175         try
176         {
177             if ("INBOX".equalsIgnoreCase(destination) && !(mailboxManager.mailboxExists(name, session))) {
178                 mailboxManager.createMailbox(name, session);
179             }
180             final Mailbox mailbox = mailboxManager.getMailbox(name, session);
181             
182             if (mailbox == null) {
183                 final String error = "Mailbox for user " + username
184                         + " was not found on this server.";
185                 throw new MessagingException(error);
186             }
187 
188             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
189             mail.writeTo(baos);
190             mailbox.appendMessage(baos.toByteArray() , new Date(), session, true, null);
191         }
192         catch (IOException e)
193         {
194             throw new MessagingException("Failed to write mail message", e);
195         }
196         finally 
197         {
198             session.close();   
199             mailboxManager.logout(session, true);
200         }
201     }
202 }