| /**************************************************************** |
| * 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.hupa.server; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import javax.mail.Authenticator; |
| import javax.mail.Message; |
| import javax.mail.MessagingException; |
| import javax.mail.NoSuchProviderException; |
| import javax.mail.PasswordAuthentication; |
| import javax.mail.Session; |
| import javax.mail.Transport; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.hupa.shared.domain.Settings; |
| import org.apache.hupa.shared.domain.User; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Singleton; |
| import com.google.inject.name.Named; |
| import com.sun.mail.iap.ProtocolException; |
| import com.sun.mail.imap.IMAPFolder; |
| import com.sun.mail.imap.IMAPFolder.ProtocolCommand; |
| import com.sun.mail.imap.IMAPStore; |
| import com.sun.mail.imap.protocol.IMAPProtocol; |
| import com.sun.mail.imap.protocol.ListInfo; |
| |
| @Singleton |
| public class InMemoryIMAPStoreCache implements IMAPStoreCache { |
| |
| private final Map<String, CachedIMAPStore> pool = new HashMap<String, CachedIMAPStore>(); |
| |
| private Log logger; |
| private int connectionPoolSize; |
| private int timeout; |
| private boolean debug; |
| private boolean trustSSL; |
| |
| @Inject |
| public InMemoryIMAPStoreCache( |
| Log logger, |
| @Named("IMAPConnectionPoolSize") int connectionPoolSize, |
| @Named("IMAPConnectionPoolTimeout") int timeout, |
| @Named("SessionDebug") boolean debug, |
| @Named("TrustStore") String truststore, |
| @Named("TrustStorePassword") String truststorePassword, |
| @Named("TrustSSL") boolean trustSSL) |
| { |
| this.logger = logger; |
| this.connectionPoolSize = connectionPoolSize; |
| this.timeout = timeout; |
| this.debug = debug; |
| this.trustSSL = trustSSL; |
| if (!truststore.isEmpty()) { |
| System.setProperty("javax.net.ssl.trustStore", truststore); |
| } |
| if (!truststorePassword.isEmpty()) { |
| System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword); |
| } |
| System.setProperty("mail.mime.decodetext.strict", "false"); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.apache.hupa.server.IMAPStoreCache#get(org.apache.hupa.shared.data.User) |
| */ |
| public IMAPStore get(User user) throws MessagingException { |
| // FIXME, there will be a NullPointerException thrown here when user session expired |
| |
| String id = user.getId(); |
| String username = user.getName(); |
| String password = user.getPassword(); |
| Settings settings = user.getSettings(); |
| |
| CachedIMAPStore cstore = pool.get(username); |
| if (cstore == null) { |
| logger.debug("No cached store found for user " +username); |
| } else { |
| if (cstore.isExpired() == false) { |
| try { |
| cstore.validate(); |
| } catch (MessagingException e) { |
| } |
| } else { |
| pool.remove(username); |
| try { |
| cstore.getStore().close(); |
| cstore = null; |
| } catch (MessagingException e) { |
| } |
| } |
| } |
| |
| if (cstore == null) { |
| cstore = createCachedIMAPStore(user); |
| } |
| |
| if (cstore.getStore().isConnected() == false) { |
| cstore.getStore().connect(settings.getImapServer(), settings.getImapPort(), id, password); |
| } |
| |
| pool.put(username, cstore); |
| IMAPStore ret = cstore.getStore(); |
| |
| // TODO: this is a hack for gmail |
| if (settings.getImapServer().contains("gmail.com")) { |
| internationalizeGmailFolders(user, ret); |
| } |
| |
| return ret; |
| } |
| |
| public void internationalizeGmailFolders(User user, IMAPStore store) { |
| // TODO: this is a hack, we should have a default domain suffix in configuration files |
| if (!user.getName().contains("@")) { |
| user.setName(user.getName() + "@gmail.com"); |
| } |
| try { |
| final IMAPFolder folder = (IMAPFolder) store.getDefaultFolder(); |
| final char c = folder.getSeparator(); |
| |
| ListInfo[] li = (ListInfo[])folder.doCommandIgnoreFailure(new ProtocolCommand() { |
| public Object doCommand(IMAPProtocol p) throws ProtocolException { |
| String arg = folder.getFullName() + c + "*"; |
| return p.lsub("", arg); |
| } |
| }); |
| |
| for (ListInfo l : li) { |
| if (l.attrs != null && l.attrs.length > 1) { |
| // * LIST (\HasNoChildren \Drafts) "/" "[Gmail]/Borradores" |
| String n = l.attrs[1]; |
| if ("\\Drafts".equals(n)) { |
| user.getSettings().setDraftsFolderName(l.name); |
| } else if ("\\Sent".equals(n)) { |
| user.getSettings().setSentFolderName(l.name); |
| } else if ("\\Trash".equals(n)) { |
| user.getSettings().setTrashFolderName(l.name); |
| } else if ("\\Junk".equals(n)) { |
| } |
| } |
| } |
| } catch (Exception e) { |
| } |
| } |
| |
| public CachedIMAPStore createCachedIMAPStore(User user) throws NoSuchProviderException { |
| Session ses = createSession(user); |
| IMAPStore store = (IMAPStore)ses.getStore(user.getSettings().getImapSecure() ? "imaps" : "imap"); |
| CachedIMAPStore ret = new CachedIMAPStore(store, 300); |
| ret.setSession(ses); |
| return ret; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.apache.hupa.server.IMAPStoreCache#delete(org.apache.hupa.shared.data.User) |
| */ |
| public synchronized void delete(User user) { |
| delete(user.getName()); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.apache.hupa.server.IMAPStoreCache#delete(java.lang.String) |
| */ |
| public synchronized void delete(String username) { |
| CachedIMAPStore cstore = pool.get(username); |
| if (cstore != null && cstore.getStore().isConnected()) { |
| try { |
| cstore.getStore().close(); |
| } catch (MessagingException e) { |
| // Ignore on close |
| } |
| } |
| pool.remove(username); |
| } |
| |
| public void sendMessage(Message msg) throws MessagingException { |
| Transport.send(msg); |
| } |
| |
| public Session getMailSession(User user) { |
| CachedIMAPStore cstore = pool.get(user.getName()); |
| return cstore.getSession(); |
| } |
| |
| private Session createSession(final User user) { |
| Properties props = new Properties(); |
| Settings settings = user.getSettings(); |
| |
| props.setProperty("mail.mime.decodetext.strict", "false"); |
| if (settings.getImapSecure()) { |
| props.setProperty("mail.store.protocol", "imaps"); |
| props.setProperty("mail.imaps.connectionpoolsize", connectionPoolSize + ""); |
| props.setProperty("mail.imaps.connectionpooltimeout", timeout + ""); |
| if (trustSSL) { |
| props.setProperty("mail.imaps.ssl.trust", settings.getImapServer()); |
| } |
| } else { |
| props.setProperty("mail.imap.connectionpoolsize", connectionPoolSize + ""); |
| props.setProperty("mail.imap.connectionpooltimeout", timeout + ""); |
| } |
| |
| if (settings.getSmtpSecure()) { |
| if (settings.getSmtpPort() == 587) { |
| props.setProperty("mail.smtp.starttls.enable", "true"); |
| props.setProperty("mail.transport.protocol.rfc822", "smtp"); |
| } else { |
| props.setProperty("mail.transport.protocol.rfc822", "smtps"); |
| props.setProperty("mail.smtps.ssl.enable", "true"); |
| if (trustSSL) { |
| props.setProperty("mail.smtps.ssl.trust", settings.getSmtpServer()); |
| } |
| } |
| } else { |
| props.setProperty("mail.transport.protocol.rfc822", "smtp"); |
| } |
| |
| props.setProperty("mail.smtp.host", settings.getSmtpServer()); |
| props.setProperty("mail.smtps.host", settings.getSmtpServer()); |
| props.setProperty("mail.smtp.port", settings.getSmtpPort() + ""); |
| props.setProperty("mail.smtps.port", settings.getSmtpPort() + ""); |
| |
| Authenticator auth = null; |
| if (settings.getSmtpAuth() && user.getPassword() != null && user.getName() != null) { |
| props.setProperty("mail.smtp.auth", "true"); |
| props.setProperty("mail.smtps.auth", "true"); |
| auth = new javax.mail.Authenticator() { |
| protected PasswordAuthentication getPasswordAuthentication() { |
| String userId = user.getId(); |
| StackTraceElement[] sElms = Thread.currentThread().getStackTrace(); |
| for (StackTraceElement e : sElms) { |
| if (e.getClassName().equals(InMemoryIMAPStoreCache.class.getName()) && e.getMethodName().equals("get")) { |
| // We try with the id part the second time (unix imap/smtp auth compatible) |
| if (userId.matches(".*@.*")) { |
| userId = userId.replaceFirst("@.*", ""); |
| user.setId(userId); |
| break; |
| } else { |
| return null; |
| } |
| } |
| } |
| return new PasswordAuthentication(userId, user.getPassword()); |
| } |
| }; |
| } |
| |
| Session ses = Session.getInstance(props, auth); |
| ses.setDebug(debug && logger.isDebugEnabled()); |
| logger.debug("Created session " + user.getName() + "\n" + settings + "\n"+ props.toString().replaceAll(",", ",\n ")); |
| return ses; |
| } |
| } |