/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.contrib.mail.internal;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.FolderNotFoundException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.internet.MimeMessage;
import javax.mail.search.MessageIDTerm;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.xwiki.contrib.mail.IStoreManager;
import org.xwiki.contrib.mail.SourceConnectionErrors;
import org.xwiki.contrib.mail.internal.source.StoreSource;
/**
* @version $Id$
*/
public abstract class AbstractMailStore extends AbstractMailReader implements IStoreManager
{
public abstract Logger getLogger();
public void setMailSource(StoreSource mailSource)
{
super.setMailSource(mailSource);
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mail.IMailReader#getMailSource()
*/
@Override
public StoreSource getMailSource()
{
return (StoreSource) super.getMailSource();
}
public abstract Properties getStoreProperties();
/**
* @param folder
* @param message
* @throws MessagingException
*/
public void write(String folder, Message message) throws MessagingException
{
// getLogger().info("Delivering " + message + " to " + this.location + " / " + folder);
final Store store = getJavamailStore(true);
store.connect();
final Folder mailFolder = store.getDefaultFolder().getFolder(folder);
if (!mailFolder.exists()) {
mailFolder.create(Folder.HOLDS_MESSAGES);
}
mailFolder.open(Folder.READ_WRITE);
// If message is already archived, do nothing
final Message existingMessage = read(folder, message.getHeader("Message-ID")[0]);
if (existingMessage == null) {
// The Store Provider may add some headers to the message to store, but IMAPMessage are read-only
// So we clone the message before storing it
final MimeMessage cloned = cloneEmail(message);
mailFolder.appendMessages(new Message[] {cloned});
}
mailFolder.close(true);
store.close();
}
/**
* {@inheritDoc}
*
* @throws MessagingException
* @see org.xwiki.contrib.mail.IMailReader#readFromStore(java.lang.String)
*/
public Message read(String folder, String messageid) throws MessagingException
{
Store store = getJavamailStore();
store.connect();
Folder mailFolder = store.getDefaultFolder().getFolder(folder);
mailFolder.open(Folder.READ_ONLY);
Message[] messages = mailFolder.search(new MessageIDTerm(messageid));
mailFolder.close(false);
store.close();
if (messages.length > 0) {
return messages[0];
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mail.IMailReader#readFromStore(java.lang.String)
*/
@Override
public List<Message> read(String folder, boolean onlyUnred, int max) throws MessagingException
{
Store store = getJavamailStore();
store.connect();
Folder mailFolder = store.getDefaultFolder();
if (StringUtils.isNotEmpty(folder)) {
mailFolder = mailFolder.getFolder(folder);
}
mailFolder.open(Folder.READ_WRITE);
Message[] msgsArray = mailFolder.getMessages();
if (max > 0 && msgsArray.length > max) {
msgsArray = (Message[]) ArrayUtils.subarray(msgsArray, 0, max);
}
List<Message> messages = new ArrayList<Message>(Arrays.asList(msgsArray));
mailFolder.close(false);
store.close();
return messages;
}
/**
* Creates appropriate javamail Store object.
*
* @param debug
* @return
* @throws NoSuchProviderException
*/
protected Store getJavamailStore(boolean debug) throws NoSuchProviderException
{
Properties props = getStoreProperties();
Session session = Session.getInstance(props);
if (debug) {
session.setDebug(true);
}
String url = getProvider() + ":" + getMailSource().getLocation();
return session.getStore(new URLName(url));
}
/**
* Creates appropriate javamail Store object.
*
* @return
* @throws NoSuchProviderException
*/
protected Store getJavamailStore() throws NoSuchProviderException
{
return getJavamailStore(false);
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mail.IMailReader#read(java.lang.String, boolean)
*/
@Override
public List<Message> read(String folder, boolean onlyUnread) throws MessagingException
{
return read(folder, onlyUnread, -1);
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mail.IMailReader#check(java.lang.String, boolean)
*/
@Override
public int check(String folder, boolean onlyUnread)
{
List<Message> messages = null;
File storePath = new File(getMailSource().getLocation());
if (!storePath.exists() || !storePath.canRead()) {
return SourceConnectionErrors.CONNECTION_ERROR.getCode();
}
try {
messages = read(folder, onlyUnread);
} catch (FolderNotFoundException e) {
return SourceConnectionErrors.FOLDER_NOT_FOUND.getCode();
} catch (MessagingException e) {
// TODO Very basic implementation of check() ...
e.printStackTrace();
return SourceConnectionErrors.UNEXPECTED_EXCEPTION.getCode();
}
return messages == null ? -1 : messages.size();
}
@Override
public ArrayList<FolderItem> getFolderTree() throws MessagingException
{
getLogger().debug("getFolderTree");
assert (getMailSource() != null);
ArrayList<FolderItem> folderItems = new ArrayList<FolderItem>();
Store store = getJavamailStore();
store.connect();
Folder defaultFolder = store.getDefaultFolder();
FolderItem item = new FolderItem();
item.setIndex(0);
item.setLevel(0);
item.setName(defaultFolder.getName());
item.setFullName(defaultFolder.getFullName());
if ((defaultFolder.getType() & javax.mail.Folder.HOLDS_MESSAGES) != 0) {
item.setMessageCount(defaultFolder.getMessageCount());
item.setUnreadMessageCount(defaultFolder.getUnreadMessageCount());
item.setNewMessageCount(defaultFolder.getNewMessageCount());
}
Folder[] folders = defaultFolder.list("*");
if (ArrayUtils.isEmpty(folders)) {
folders = defaultFolder.list();
}
getLogger().debug("Found folders {}", ArrayUtils.toString(folders));
int index = 1;
int level = 1;
// TODO not really managing folders here, just listing them
for (Folder folder : folders) {
item = new FolderItem();
item.setIndex(index);
item.setLevel(level);
item.setName(folder.getName());
item.setFullName(folder.getFullName());
if ((folder.getType() & javax.mail.Folder.HOLDS_MESSAGES) != 0) {
item.setMessageCount(folder.getMessageCount());
item.setUnreadMessageCount(folder.getUnreadMessageCount());
item.setNewMessageCount(folder.getNewMessageCount());
folderItems.add(item);
}
}
store.close();
return folderItems;
}
/**
* {@inheritDoc}
*
* @throws MessagingException
* @see org.xwiki.contrib.mail.IMailReader#cloneEmail(javax.mail.Message)
*/
@Override
public MimeMessage cloneEmail(Message mail)
{
MimeMessage copy = (MimeMessage) mail;
try {
copy = new MimeMessage((MimeMessage) mail);
} catch (MessagingException e) {
// failed to copy
}
return copy;
}
}