i2p.bote.imap.ImapService.java Source code

Java tutorial

Introduction

Here is the source code for i2p.bote.imap.ImapService.java

Source

/**
 * Copyright (C) 2009  HungryHobo@mail.i2p
 * 
 * The GPG fingerprint for HungryHobo@mail.i2p is:
 * 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
 * 
 * This file is part of I2P-Bote.
 * I2P-Bote is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * I2P-Bote is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with I2P-Bote.  If not, see <http://www.gnu.org/licenses/>.
 */

package i2p.bote.imap;

import i2p.bote.Configuration;
import i2p.bote.fileencryption.PasswordException;
import i2p.bote.fileencryption.PasswordVerifier;
import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.EmailFolderManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import javax.mail.Flags;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import net.i2p.util.Log;
import net.i2p.util.StrongTls;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.james.filesystem.api.FileSystem;
import org.apache.james.imap.api.display.HumanReadableText;
import org.apache.james.imap.api.display.Locales;
import org.apache.james.imap.api.display.Localizer;
import org.apache.james.imap.api.process.ImapProcessor;
import org.apache.james.imap.encode.main.DefaultImapEncoderFactory;
import org.apache.james.imap.main.DefaultImapDecoderFactory;
import org.apache.james.imap.processor.main.DefaultImapProcessorFactory;
import org.apache.james.imapserver.netty.IMAPServer;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.SubscriptionManager;
import org.apache.james.mailbox.acl.GroupMembershipResolver;
import org.apache.james.mailbox.acl.MailboxACLResolver;
import org.apache.james.mailbox.exception.SubscriptionException;
import org.apache.james.mailbox.exception.UnsupportedRightException;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxACL.MailboxACLEntryKey;
import org.apache.james.mailbox.model.MailboxACL.MailboxACLRight;
import org.apache.james.mailbox.model.MailboxACL.MailboxACLRights;
import org.apache.james.mailbox.model.SimpleMailboxACL;
import org.apache.james.mailbox.store.Authenticator;
import org.apache.james.mailbox.store.HashMapDelegatingMailboxListener;
import org.apache.james.mailbox.store.RandomMailboxSessionIdGenerator;
import org.apache.james.mailbox.store.StoreMailboxManager;
import org.slf4j.LoggerFactory;

/**
 * IMAP implementation for I2P-Bote using <a href="http://james.apache.org/">
 * Apache James</a>.
 */
public class ImapService extends IMAPServer {
    private final static String IMAP_USER = "bote";
    private static final String SSL_KEYSTORE_FILE = "file:///BoteSSLKeyStore";

    private Log log = new Log(ImapService.class);
    private EmailFolderManager folderManager;
    private File sslKeyStore;
    private MapperFactory mailboxSessionMapperFactory;

    public ImapService(Configuration configuration, final PasswordVerifier passwordVerifier,
            EmailFolderManager folderManager) throws ConfigurationException {
        this.folderManager = folderManager;

        setLog(LoggerFactory.getLogger(ImapService.class));

        // Set up the keystore for the SSL certificate
        sslKeyStore = configuration.getSSLKeyStoreFile();
        setFileSystem(new FileSystem() {
            @Override
            public InputStream getResource(String resource) throws IOException {
                return null;
            }

            @Override
            public File getFile(String fileURL) throws FileNotFoundException {
                if (fileURL.equals(SSL_KEYSTORE_FILE))
                    return sslKeyStore;
                return null;
            }

            @Override
            public File getBasedir() throws FileNotFoundException {
                return null;
            }
        });

        HierarchicalConfiguration cfg = new HierarchicalConfiguration();
        SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket s = null;
        try {
            // Create an unconnected socket for getting supported cipher suites
            s = (SSLSocket) sf.createSocket();
            // enable STARTTLS using the above keystore
            cfg.setProperty("tls.[@startTLS]", true);
            cfg.setProperty("tls.keystore", SSL_KEYSTORE_FILE);
            cfg.setProperty("tls.secret", configuration.getSSLKeyStorePassword());
            // select strong cipher suites
            cfg.setProperty("tls.supportedCipherSuites.cipherSuite",
                    StrongTls.getRecommendedCipherSuites(s.getSupportedCipherSuites()));
        } catch (IOException e) {
            log.error("Couldn't determine supported cipher suites", e);
        } finally {
            if (s != null)
                try {
                    s.close();
                } catch (IOException e) {
                }
        }
        configure(cfg); // use the defaults for the rest

        setListenAddresses(new InetSocketAddress(configuration.getImapAddress(), configuration.getImapPort()));

        mailboxSessionMapperFactory = new MapperFactory(folderManager);
        MailboxACLResolver aclResolver = createMailboxACLResolver();
        GroupMembershipResolver groupMembershipResolver = new GroupMembershipResolver() {
            public boolean isMember(String user, String group) {
                return true;
            }
        };
        Authenticator authenticator = createAuthenticator(passwordVerifier);
        StoreMailboxManager<String> mailboxManager = new StoreMailboxManager<String>(mailboxSessionMapperFactory,
                authenticator, aclResolver, groupMembershipResolver);
        mailboxManager.setDelegatingMailboxListener(new HashMapDelegatingMailboxListener());
        mailboxManager.setMailboxSessionIdGenerator(new RandomMailboxSessionIdGenerator());

        SubscriptionManager subscriptionManager = createSubscriptionManager();

        ImapProcessor processor = DefaultImapProcessorFactory.createDefaultProcessor(mailboxManager,
                subscriptionManager);
        setImapProcessor(processor);

        setImapEncoder(DefaultImapEncoderFactory.createDefaultEncoder(new Localizer() {
            public String localize(HumanReadableText text, Locales locales) {
                return text.getDefaultValue();
            }
        }, true));
        setImapDecoder(DefaultImapDecoderFactory.createDecoder());
    }

    /** Creates a <code>MailboxACLResolver</code> that grants a logged in user full rights to everything */
    private MailboxACLResolver createMailboxACLResolver() {
        return new MailboxACLResolver() {

            @Override
            public MailboxACL applyGlobalACL(MailboxACL resourceACL, boolean resourceOwnerIsGroup)
                    throws UnsupportedRightException {
                return SimpleMailboxACL.OWNER_FULL_ACL;
            }

            @Override
            public boolean hasRight(String requestUser, GroupMembershipResolver groupMembershipResolver,
                    MailboxACLRight right, MailboxACL resourceACL, String resourceOwner,
                    boolean resourceOwnerIsGroup) throws UnsupportedRightException {
                return true;
            }

            @Override
            public boolean isReadWrite(MailboxACLRights mailboxACLRights, Flags sharedFlags)
                    throws UnsupportedRightException {
                return true;
            }

            @Override
            public MailboxACLRights[] listRights(MailboxACLEntryKey key,
                    GroupMembershipResolver groupMembershipResolver, String resourceOwner,
                    boolean resourceOwnerIsGroup) throws UnsupportedRightException {
                return new MailboxACLRights[] { SimpleMailboxACL.FULL_RIGHTS };
            }

            @Override
            public MailboxACLRights resolveRights(String requestUser,
                    GroupMembershipResolver groupMembershipResolver, MailboxACL resourceACL, String resourceOwner,
                    boolean resourceOwnerIsGroup) throws UnsupportedRightException {
                return SimpleMailboxACL.FULL_RIGHTS;
            }
        };
    }

    /**
     * Creates a <code>SubscriptionManager</code> that subscribes to all folders.
     * It does not support unsubscribing.
     */
    private SubscriptionManager createSubscriptionManager() {
        return new SubscriptionManager() {

            @Override
            public void startProcessingRequest(MailboxSession session) {
            }

            @Override
            public void endProcessingRequest(MailboxSession session) {
            }

            @Override
            public void unsubscribe(MailboxSession session, String mailbox) throws SubscriptionException {
            }

            @Override
            public Collection<String> subscriptions(MailboxSession session) throws SubscriptionException {
                Collection<String> folderNames = new ArrayList<String>();
                for (EmailFolder folder : ImapService.this.folderManager.getEmailFolders())
                    folderNames.add(folder.getName());
                return folderNames;
            }

            @Override
            public void subscribe(MailboxSession session, String mailbox) throws SubscriptionException {
            }
        };
    }

    /** Creates an <code>Authenticator</code> that checks the I2P-Bote password. */
    private Authenticator createAuthenticator(final PasswordVerifier passwordVerifier) {
        return new Authenticator() {

            @Override
            public boolean isAuthentic(String userid, CharSequence passwd) {
                if (!IMAP_USER.equals(userid))
                    return false;

                byte[] passwordBytes = passwd.toString().getBytes();
                try {
                    passwordVerifier.tryPassword(passwordBytes);
                } catch (PasswordException e) {
                    return false;
                } catch (Exception e) {
                    log.error("Can't check password", e);
                }

                return true;
            }
        };
    };

    /** Starts the IMAP server in a new thread and returns. */
    @Override
    public boolean start() {
        try {
            super.init();
            log.info("IMAP service listening on " + Arrays.toString(getBoundAddresses()));
            return true;
        } catch (Exception e) {
            log.error("IMAP service failed to start", e);
        }
        return false;
    }

    @Override
    protected void registerMBean() {
        // no-op to prevent RuntimeException
    }

    @Override
    public boolean stop() {
        mailboxSessionMapperFactory.stopListening();
        super.destroy();
        return true;
    }

    @Override
    protected void unregisterMBean() {
        // no-op to prevent RuntimeException
    }
}