/* IMAPMailbox.java
Copyright (c) 2009 Juergen Schlierf, All Rights Reserved
This file is part of Cubusmail (http://code.google.com/p/cubusmail/).
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with Cubusmail. If not, see <http://www.gnu.org/licenses/>.
*/
package com.cubusmail.mail.imap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.event.FolderListener;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.sun.mail.imap.IMAPStore;
import com.sun.mail.imap.Rights.Right;
import com.cubusmail.core.BeanFactory;
import com.cubusmail.core.CubusConstants;
import com.cubusmail.gwtui.domain.UserAccount;
import com.cubusmail.mail.IMailFolder;
import com.cubusmail.mail.IMailbox;
import com.cubusmail.mail.SessionManager;
import com.cubusmail.mail.exceptions.IErrorCodes;
import com.cubusmail.mail.exceptions.MailFolderException;
import com.cubusmail.mail.security.MailboxAuthenticator;
/**
* Implementation of an imap mailbox.
*
* @author Juergen Schlierf
*/
@SuppressWarnings("serial")
public class IMAPMailbox implements IMailbox {
private Logger logger = Logger.getLogger( this.getClass() );
// Javamail session
private Session session;
private IMAPStore store = null;
private IMailFolder currentFolder = null;
private Map<String, IMailFolder> mailFolderMap;
private List<IMailFolder> mailFolderList;
private MailboxAuthenticator mailboxAuthenticator;
private String personalNameSpace;
private char folderSeparator;
private UserAccount userAccount;
private String username;
// configuration params
private boolean imapPartialfetch;
private long imapFetchsize;
private boolean imapSSL;
private String imapHost;
private int imapPort;
private boolean smtpSSL;
private String smtpHost;
private int smtpPort;
private String domainName;
public IMAPMailbox() {
this.mailFolderMap = new TreeMap<String, IMailFolder>();
this.mailFolderList = new ArrayList<IMailFolder>();
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#init(java.lang.String, java.lang.String)
*/
public void init( String username, String password ) {
this.username = username;
Properties props = new Properties();
props.put( "mail.user", username );
props.put( "mail.imap.partialfetch", this.imapPartialfetch );
props.put( "mail.imap.fetchsize", this.imapFetchsize );
String imapProtocol = this.imapSSL ? "imaps" : "imap";
props.put( "mail.store.protocol", imapProtocol );
props.put( "mail." + imapProtocol + ".port", this.imapPort );
props.put( "mail." + imapProtocol + ".host", this.imapHost );
String smtpProtocol = this.smtpSSL ? "smtps" : "smtp";
props.put( "mail.transport.protocol", smtpProtocol );
props.put( "mail." + smtpProtocol + ".port", this.smtpPort );
props.put( "mail." + smtpProtocol + ".host", this.smtpHost );
// avoid strange ssl exceptions
props.put( "mail." + smtpProtocol + ".quitwait", "false" );
props.put( "mail." + smtpProtocol + ".auth", "true" );
props.put( "mail.mime.decodetext.strict", "true" );
props.put( "mail.mime.address.strict", "false" );
props.put( "mail.mime.charset", CubusConstants.DEFAULT_CHARSET );
// Security.setProperty( "ssl.SocketFactory.provider",
// AllCertificatesSSLSocketFactory.class.getName() );
// props.put( "mail.imap.socketFactory.class",
// AllCertificatesSSLSocketFactory.class.getName() );
// props.put( "mail.imap.socketFactory.port",
// Configuration.get().imapPort );
// props.put( "mail.imap.socketFactory.fallback", "false" );
// props.put( "mail.smtp.starttls.enable", "true" );
this.mailboxAuthenticator.setUsername( username );
this.mailboxAuthenticator.setPassword( password );
Session session = Session.getInstance( props, this.mailboxAuthenticator );
session.setDebug( false );
this.session = session;
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#login()
*/
public void login() throws MessagingException {
if ( this.store == null ) {
this.store = createStore();
}
this.store.connect();
this.personalNameSpace = "";
try {
Folder[] namespaces = store.getPersonalNamespaces();
if ( namespaces != null && namespaces.length > 0 ) {
this.personalNameSpace = namespaces[0].getFullName();
if ( this.personalNameSpace.length() > 0 ) {
this.personalNameSpace += this.store.getDefaultFolder().getSeparator();
}
this.personalNameSpace = this.personalNameSpace.trim();
}
}
catch (Exception e) {
logger.error( e.getMessage(), e );
}
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#logout()
*/
public void logout() throws MessagingException {
if ( this.currentFolder != null && this.currentFolder.isOpen() ) {
this.currentFolder.close( true );
this.currentFolder = null;
}
if ( this.store != null ) {
this.store.close();
this.store = null;
}
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#isLoggedIn()
*/
public boolean isLoggedIn() {
if ( this.store != null && this.store.isConnected() ) {
return true;
}
else {
return false;
}
}
/*
* (non-Javadoc)
*
* @see
* org.grouplite.mail.ui.mail.IMailConnection#setCurrentFolder(org.grouplite
* .mail.ui.mail.IMailFolder)
*/
public void setCurrentFolder( IMailFolder folder ) throws MessagingException {
if ( this.currentFolder != null && this.currentFolder.isOpen() && !this.currentFolder.equals( folder ) ) {
this.currentFolder.close( false );
}
this.currentFolder = folder;
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#getCurrentFolder()
*/
public IMailFolder getCurrentFolder() {
return this.currentFolder;
}
/**
* Deliveres the inbox folder.
*
* @return
*/
private IMailFolder getInboxFolder() {
return this.mailFolderMap.get( SessionManager.get().getPreferences().getInboxFolderName() );
}
/**
* Deliveres the draft folder.
*
* @return
*/
public IMailFolder getDraftFolder() {
return getMailFolderById( this.personalNameSpace + SessionManager.get().getPreferences().getDraftFolderName() );
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getSentFolder()
*/
public IMailFolder getSentFolder() {
return getMailFolderById( this.personalNameSpace + SessionManager.get().getPreferences().getSentFolderName() );
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getTrashFolder()
*/
public IMailFolder getTrashFolder() {
return getMailFolderById( this.personalNameSpace + SessionManager.get().getPreferences().getTrashFolderName() );
}
/*
* (non-Javadoc)
*
* @see
* org.grouplite.mail.ui.mail.IMailConnection#moveFolder(org.grouplite.mail
* .ui.mail.IMailFolder, org.grouplite.mail.ui.mail.IMailFolder)
*/
public void moveFolder( String sourceFolderId, String targetFolderId ) throws MailFolderException {
IMailFolder sourceFolder = null;
IMailFolder targetFolder = null;
try {
String newFolderName;
sourceFolder = getMailFolderById( sourceFolderId );
targetFolder = getMailFolderById( targetFolderId );
if ( sourceFolder != null ) {
if ( targetFolder == null ) {
newFolderName = sourceFolder.getName();
}
else {
newFolderName = targetFolder.getId() + getFolderSeparator() + sourceFolder.getName();
}
if ( sourceFolder.isOpen() ) {
sourceFolder.close( false );
}
if ( targetFolder != null && targetFolder.isOpen() ) {
targetFolder.close( false );
}
Folder newFolder = this.store.getFolder( newFolderName );
if ( !newFolder.exists() ) {
sourceFolder.renameTo( newFolder );
}
else {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_ALREADY_EXIST, null, sourceFolder );
}
loadMailFolder();
}
}
catch (MessagingException e) {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_MOVE, e, sourceFolder );
}
}
/*
* (non-Javadoc)
*
* @see
* org.grouplite.mail.ui.mail.IMailConnection#renameFolder(org.grouplite
* .mail.ui.mail.IMailFolder, java.lang.String)
*/
public void renameFolder( String folderId, String folderName ) throws MailFolderException {
IMailFolder folder = getMailFolderById( folderId );
try {
String newName = folder.getId();
if ( newName.lastIndexOf( getFolderSeparator() ) >= 0 ) {
newName = newName.substring( 0, newName.lastIndexOf( getFolderSeparator() ) + 1 ) + folderName;
}
else {
newName = folderName;
}
if ( folder.isOpen() ) {
folder.close( false );
}
Folder newFolder = this.store.getFolder( newName );
if ( !newFolder.exists() ) {
folder.renameTo( newFolder );
}
else {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_ALREADY_EXIST, null,
createMailFolder( newFolder ) );
}
loadMailFolder();
}
catch (MessagingException ex) {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_RENAME, ex, folder );
}
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#emptyFolder(java.lang.String)
*/
public void emptyFolder( String folderId ) throws MailFolderException {
IMailFolder folder = getMailFolderById( folderId );
try {
if ( !folder.isOpen() ) {
folder.open( Folder.READ_WRITE );
}
if ( folder.getMessageCount() > 0 ) {
Message[] msgs = folder.retrieveMessages( null );
for (int i = 0; i < folder.getMessageCount(); i++) {
msgs[i].setFlag( Flags.Flag.DELETED, true );
}
}
folder.close( true );
}
catch (MessagingException ex) {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_EMPTY, ex, folder );
}
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#deleteFolder(java.lang.String)
*/
public void deleteFolder( String folderId ) throws MailFolderException {
IMailFolder folder = getMailFolderById( folderId );
try {
if ( folder.hasRight( Right.DELETE ) ) {
if ( folder.isOpen() ) {
folder.close( false );
}
if ( folder.delete( true ) ) {
loadMailFolder();
setCurrentFolder( getInboxFolder() );
}
else {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_DELETE, null, folder );
}
}
}
catch (MessagingException ex) {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_DELETE, ex, folder );
}
}
/*
* (non-Javadoc)
*
* @see
* org.grouplite.mail.ui.mail.IMailConnection#createFolder(org.grouplite
* .mail.ui.mail.IMailFolder, java.lang.String)
*/
public IMailFolder createFolder( String parentFolderId, String folderName ) throws MailFolderException {
try {
String newFolderName = null;
if ( !StringUtils.isEmpty( parentFolderId ) ) {
newFolderName = parentFolderId + getFolderSeparator() + folderName;
}
else {
newFolderName = folderName;
}
Folder newFolder = this.store.getFolder( newFolderName );
if ( !newFolder.exists() ) {
logger.debug( "Createing folder... " + newFolderName );
newFolder.create( Folder.HOLDS_MESSAGES );
}
else {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_ALREADY_EXIST, null );
}
loadMailFolder();
return createMailFolder( newFolder );
}
catch (MessagingException ex) {
throw new MailFolderException( IErrorCodes.EXCEPTION_FOLDER_CREATE, ex );
}
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#reloadFolder()
*/
public void reloadFolder() throws MessagingException {
this.loadMailFolder();
this.currentFolder = getInboxFolder();
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#copyMessages(long[], java.lang.String)
*/
public void copyMessages( long[] messageIds, String targetFolderId ) throws MessagingException {
if ( !this.currentFolder.isOpen() ) {
this.currentFolder.open( Folder.READ_WRITE );
}
IMailFolder targetFolder = getMailFolderById( targetFolderId );
if ( !targetFolder.isOpen() ) {
targetFolder.open( Folder.READ_WRITE );
}
this.currentFolder.copyMessages( messageIds, targetFolder );
targetFolder.close( false );
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#deleteMessages(long[])
*/
public void deleteMessages( long[] messageIds ) throws MessagingException {
if ( messageIds != null && messageIds.length > 0 ) {
if ( !this.currentFolder.isOpen() ) {
this.currentFolder.open( Folder.READ_WRITE );
}
Message[] msgs = this.currentFolder.getMessagesById( messageIds );
for (int i = 0; i < msgs.length; i++) {
msgs[i].setFlag( Flags.Flag.DELETED, true );
}
this.currentFolder.expunge( msgs );
}
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getMailFolderById(java.lang.String)
*/
public IMailFolder getMailFolderById( String id ) {
return this.mailFolderMap.get( id );
}
/*
* (non-Javadoc)
*
* @see
* org.grouplite.mail.ui.mail.IMailConnection#addFolderListener(javax.mail
* .event.FolderListener)
*/
public void addFolderListener( FolderListener listener ) {
this.store.addFolderListener( listener );
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#getConnectionName()
*/
public String getUserName() {
return this.username;
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getEmailAddress()
*/
public String getEmailAddress() {
if ( this.username.indexOf( "@" ) > 0 ) {
return this.username;
}
else {
return this.username + "@" + this.domainName;
}
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getFullName()
*/
public String getFullName() {
return "Juergen Schlierf";
}
/**
*
*/
private IMAPStore createStore() {
IMAPStore store = null;
try {
store = (IMAPStore) session.getStore();
}
catch (NoSuchProviderException e) {
logger.error( e.getMessage(), e );
}
return store;
}
/**
* @throws MessagingException
*/
private void loadMailFolder() throws MessagingException {
logger.debug( "loading folder tree..." );
long millis = System.currentTimeMillis();
this.mailFolderMap.clear();
this.mailFolderList.clear();
Folder defaultFolder = this.store.getDefaultFolder();
this.folderSeparator = defaultFolder.getSeparator();
// read all folders to a map
List<String> topFolderNames = new ArrayList<String>();
Folder[] allFolders = defaultFolder.list( "*" );
if ( allFolders != null && allFolders.length > 0 ) {
for (Folder folder : allFolders) {
this.mailFolderMap.put( folder.getFullName(), createMailFolder( folder ) );
if ( SessionManager.get().getPreferences().getInboxFolderName().equals( folder.getFullName() ) ) {
topFolderNames.add( 0, SessionManager.get().getPreferences().getInboxFolderName() );
}
else {
String folderName = folder.getFullName();
if ( !StringUtils.isEmpty( this.personalNameSpace )
&& folderName.startsWith( this.personalNameSpace ) ) {
folderName = StringUtils.substringAfter( folderName, this.personalNameSpace );
}
if ( StringUtils.countMatches( folderName, String.valueOf( getFolderSeparator() ) ) == 0 ) {
topFolderNames.add( folder.getFullName() );
}
}
}
}
// build the tree structure
for (String folderName : topFolderNames) {
IMailFolder mailFolder = this.mailFolderMap.get( folderName );
this.mailFolderList.add( mailFolder );
if ( !SessionManager.get().getPreferences().getInboxFolderName().equals( folderName )
&& mailFolder.hasChildren() ) {
mailFolder.setSubfolders( getSubfolders( mailFolder ) );
}
}
logger.debug( "...finish: " + (System.currentTimeMillis() - millis) + "ms" );
}
/**
* @param mailFolder
* @return
* @throws MessagingException
*/
private List<IMailFolder> getSubfolders( IMailFolder mailFolder ) throws MessagingException {
List<IMailFolder> subfolders = new ArrayList<IMailFolder>();
String searchKey = mailFolder.getId() + getFolderSeparator();
Set<String> keys = this.mailFolderMap.keySet();
for (String key : keys) {
if ( key.startsWith( searchKey )
&& !StringUtils.contains( StringUtils.substringAfter( key, searchKey ), getFolderSeparator() ) ) {
IMailFolder subfolder = this.mailFolderMap.get( key );
subfolders.add( subfolder );
if ( subfolder.hasChildren() ) {
subfolder.setSubfolders( getSubfolders( subfolder ) );
}
}
}
return subfolders;
}
/**
* @return
* @throws MessagingException
*/
private char getFolderSeparator() throws MessagingException {
return this.folderSeparator;
}
/*
* (non-Javadoc)
*
* @see org.grouplite.mail.ui.mail.IMailConnection#getSession()
*/
public Session getJavaMailSession() {
return session;
}
public List<IMailFolder> getMailFolderList() {
return this.mailFolderList;
}
/*
* (non-Javadoc)
*
* @see com.cubusmail.mail.IMailbox#getUserAccount()
*/
public UserAccount getUserAccount() {
return this.userAccount;
}
/*
* (non-Javadoc)
*
* @see
* com.cubusmail.mail.IMailbox#setUserAccount(com.cubusmail.user.UserAccount
* )
*/
public void setUserAccount( UserAccount userAccount ) {
this.userAccount = userAccount;
}
/**
* @param mailFolderList
* The mailFolderList to set.
*/
public void setMailFolderList( List<IMailFolder> mailFolderList ) {
this.mailFolderList = mailFolderList;
}
/**
* @param folderSeparator
* The folderSeparator to set.
*/
public void setFolderSeparator( char folderSeparator ) {
this.folderSeparator = folderSeparator;
}
/**
* @param imapPartialfetch
* The imapPartialfetch to set.
*/
public void setImapPartialfetch( boolean imapPartialfetch ) {
this.imapPartialfetch = imapPartialfetch;
}
/**
* @param imapFetchsize
* The imapFetchsize to set.
*/
public void setImapFetchsize( long imapFetchsize ) {
this.imapFetchsize = imapFetchsize;
}
/**
* @param imapSSL
* The imapSSL to set.
*/
public void setImapSSL( boolean imapSSL ) {
this.imapSSL = imapSSL;
}
/**
* @param imapHost
* The imapHost to set.
*/
public void setImapHost( String imapHost ) {
this.imapHost = imapHost;
}
/**
* @param imapPort
* The imapPort to set.
*/
public void setImapPort( int imapPort ) {
this.imapPort = imapPort;
}
/**
* @param smtpSSL
* The smtpSSL to set.
*/
public void setSmtpSSL( boolean smtpSSL ) {
this.smtpSSL = smtpSSL;
}
/**
* @param smtpHost
* The smtpHost to set.
*/
public void setSmtpHost( String smtpHost ) {
this.smtpHost = smtpHost;
}
/**
* @param smptPort
* The smptPort to set.
*/
public void setSmtpPort( int smtpPort ) {
this.smtpPort = smtpPort;
}
/**
* @param domainName
* The domainName to set.
*/
public void setDomainName( String domainName ) {
this.domainName = domainName;
}
/**
* @param mailboxAuthenticator
* The mailboxAuthenticator to set.
*/
public void setMailboxAuthenticator( MailboxAuthenticator mailboxAuthenticator ) {
this.mailboxAuthenticator = mailboxAuthenticator;
}
/**
* @param folder
* @return
*/
private IMailFolder createMailFolder( Folder folder ) {
IMAPMailFolder mailFolder = (IMAPMailFolder) BeanFactory.getBean( "imapMailFolder" );
mailFolder.init( folder );
return mailFolder;
}
}