436 lines
11 KiB
Java
436 lines
11 KiB
Java
/**
|
|
* Author: Timothy Prepscius
|
|
* License: GPLv3 Affero + keep my name in the code!
|
|
*/
|
|
package mail.client;
|
|
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
import core.callback.Callback;
|
|
import core.callback.CallbackChain;
|
|
import core.callback.CallbackDefault;
|
|
import core.callbacks.CountDown;
|
|
import core.callbacks.Single;
|
|
import core.callbacks.Split;
|
|
import core.util.LogNull;
|
|
import core.util.LogOut;
|
|
import mail.client.cache.ID;
|
|
import mail.client.cache.Type;
|
|
import mail.client.model.Body;
|
|
import mail.client.model.Conversation;
|
|
import mail.client.model.Dictionary;
|
|
import mail.client.model.Direction;
|
|
import mail.client.model.Folder;
|
|
import mail.client.model.FolderDefinition;
|
|
import mail.client.model.FolderFilter;
|
|
import mail.client.model.FolderMaster;
|
|
import mail.client.model.FolderRepository;
|
|
import mail.client.model.FolderSet;
|
|
import mail.client.model.Header;
|
|
import mail.client.model.Mail;
|
|
import mail.client.model.TransportState;
|
|
|
|
public class Indexer extends Servent<Master>
|
|
{
|
|
static LogNull log = new LogNull(Indexer.class);
|
|
|
|
public static class KnownFolderIds {
|
|
static final
|
|
ID RootCache = ID.fromLong(1),
|
|
SystemFoldersId = ID.combine(RootCache, ID.fromLong(1)),
|
|
RepositoryId = ID.combine(RootCache, ID.fromLong(2)),
|
|
AllId = ID.combine(RootCache, ID.fromLong(3)),
|
|
InboxId = ID.combine(RootCache, ID.fromLong(4)),
|
|
SentId = ID.combine(RootCache, ID.fromLong(5)),
|
|
DraftsId = ID.combine(RootCache, ID.fromLong(6)),
|
|
SpamId = ID.combine(RootCache, ID.fromLong(7)),
|
|
TrashId = ID.combine(RootCache, ID.fromLong(8)),
|
|
|
|
UserFoldersId = ID.combine(RootCache, ID.fromLong(100));
|
|
|
|
};
|
|
|
|
FolderMaster systemFolders;
|
|
FolderSet userFolders;
|
|
FolderRepository repository;
|
|
FolderFilter spam;
|
|
|
|
public Indexer ()
|
|
{
|
|
}
|
|
|
|
public void firstRunInitialization ()
|
|
{
|
|
log.debug("firstRunInitialization");
|
|
|
|
CacheManager cache = master.getCacheManager();
|
|
|
|
systemFolders = (FolderMaster)
|
|
cache.linkFolder(
|
|
KnownFolderIds.SystemFoldersId,
|
|
Type.FolderMaster,
|
|
new FolderDefinition("system")
|
|
);
|
|
systemFolders.markCreate();
|
|
|
|
userFolders = (FolderSet)
|
|
cache.linkFolder(
|
|
KnownFolderIds.UserFoldersId,
|
|
Type.FolderFilterSet,
|
|
new FolderDefinition("user")
|
|
);
|
|
userFolders.markCreate();
|
|
|
|
repository = (FolderRepository)cache.linkFolder(
|
|
KnownFolderIds.RepositoryId,
|
|
Type.FolderRepository,
|
|
new FolderDefinition(Constants.REPOSITORY)
|
|
);
|
|
repository.markCreate();
|
|
systemFolders.addFolder(repository);
|
|
|
|
Folder fs;
|
|
fs = cache.linkFolder(
|
|
KnownFolderIds.AllId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.ALL)
|
|
.setState(
|
|
null,
|
|
TransportState.fromList(TransportState.TRASH,TransportState.SPAM)
|
|
)
|
|
);
|
|
fs.markCreate();
|
|
systemFolders.addFolder(fs);
|
|
|
|
fs = cache.linkFolder(
|
|
KnownFolderIds.InboxId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.INBOX)
|
|
.setState(
|
|
TransportState.fromList(TransportState.RECEIVED),
|
|
TransportState.fromList(TransportState.TRASH,TransportState.SPAM)
|
|
)
|
|
);
|
|
fs.markCreate();
|
|
systemFolders.addFolder(fs);
|
|
|
|
fs = cache.linkFolder(
|
|
KnownFolderIds.SentId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.SENT)
|
|
.setState(
|
|
TransportState.fromList(TransportState.SENT),
|
|
TransportState.fromList(TransportState.TRASH,TransportState.SPAM)
|
|
)
|
|
);
|
|
fs.markCreate();
|
|
systemFolders.addFolder(fs);
|
|
|
|
fs = cache.linkFolder(
|
|
KnownFolderIds.DraftsId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.DRAFTS)
|
|
.setState(
|
|
TransportState.fromList(TransportState.DRAFT, TransportState.SENDING),
|
|
TransportState.fromList(TransportState.TRASH, TransportState.SPAM)
|
|
)
|
|
);
|
|
fs.markCreate();
|
|
systemFolders.addFolder(fs);
|
|
|
|
spam = (FolderFilter)
|
|
cache.linkFolder(
|
|
KnownFolderIds.SpamId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.SPAM)
|
|
.setState(
|
|
TransportState.fromList(TransportState.SPAM),
|
|
TransportState.fromList(TransportState.TRASH)
|
|
)
|
|
.setBayesianDictionary(new Dictionary())
|
|
.setAutoBayesian(false)
|
|
);
|
|
|
|
spam.markCreate();
|
|
systemFolders.addFolder(spam);
|
|
|
|
fs = cache.linkFolder(
|
|
KnownFolderIds.TrashId,
|
|
Type.FolderFilter,
|
|
new FolderDefinition(Constants.TRASH)
|
|
.setState(
|
|
TransportState.fromList(TransportState.TRASH),
|
|
null
|
|
)
|
|
);
|
|
fs.markCreate();
|
|
systemFolders.addFolder(fs);
|
|
|
|
master.getEventPropagator().signal(Events.Initialize_FolderLoadComplete, (Object[])null);
|
|
}
|
|
|
|
public void start ()
|
|
{
|
|
log.debug("indexer starting..");
|
|
|
|
CacheManager cache = master.getCacheManager();
|
|
|
|
systemFolders = (FolderMaster)cache.getFolder(
|
|
Type.FolderMaster,
|
|
KnownFolderIds.SystemFoldersId
|
|
);
|
|
|
|
systemFolders.apply(
|
|
new CallbackDefault() {
|
|
public void onSuccess(Object... arguments) throws Exception {
|
|
onMainFolderSucceeded((Folder)arguments[0]);
|
|
}
|
|
|
|
public void onFailure(Exception e) {
|
|
onMainFolderFailed(e);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
public void onMainFolderSucceeded (Folder f)
|
|
{
|
|
log.debug("onMainFolderSucceeded");
|
|
systemFolders = (FolderMaster)f;
|
|
CacheManager cache = master.getCacheManager();
|
|
repository = (FolderRepository)cache.getFolder(Type.FolderRepository, KnownFolderIds.RepositoryId);
|
|
spam = (FolderFilter)cache.getFolder(Type.FolderFilter, KnownFolderIds.SpamId);
|
|
userFolders = (FolderSet)cache.getFolder(Type.FolderFilterSet, KnownFolderIds.UserFoldersId);
|
|
|
|
// cause subfolders to instantiate right away
|
|
List<Folder> folders = systemFolders.getFolders();
|
|
Callback countDown =
|
|
new CountDown(
|
|
folders.size(),
|
|
getMaster().getEventPropagator().signal_(Events.Initialize_FolderLoadComplete)
|
|
);
|
|
|
|
for (Folder folder : folders)
|
|
folder.apply(new Split(countDown));
|
|
}
|
|
|
|
public void onMainFolderFailed (Exception e)
|
|
{
|
|
log.debug("onMainFolderFailed");
|
|
log.exception(e);
|
|
}
|
|
|
|
public synchronized Conversation addMail (Mail mail) throws Exception
|
|
{
|
|
Header header = mail.getHeader();
|
|
boolean isNewConversation;
|
|
Conversation conversation = repository.getMatchingConversation(header);
|
|
if (conversation != null)
|
|
{
|
|
log.debug("founding matching conversation");
|
|
conversation.addItem(mail);
|
|
isNewConversation = false;
|
|
}
|
|
else
|
|
{
|
|
log.debug("new conversation");
|
|
conversation = master.getCacheManager().newConversation(mail);
|
|
isNewConversation = true;
|
|
}
|
|
|
|
// before we do anything we do the spam detection
|
|
conversation.getHeader().getTransportState().mark(
|
|
TransportState.SPAM, spam.getFolderDefinition().bayesianMatches(conversation)
|
|
);
|
|
|
|
if (isNewConversation)
|
|
addConversation(conversation);
|
|
else
|
|
conversationChanged (conversation);
|
|
|
|
|
|
// if the mail is new, no external key yet
|
|
if (mail.getHeader().getExternalKey()!=null)
|
|
{
|
|
log.debug("adding externalKey", mail.getHeader().getExternalKey());
|
|
systemFolders.addExternalKey(mail.getHeader().getExternalKey(), mail.getHeader().getDate());
|
|
}
|
|
|
|
if (mail.getHeader().getUIDL() != null)
|
|
{
|
|
log.debug("adding UIDL", mail.getHeader().getUIDL());
|
|
systemFolders.addUIDL(mail.getHeader().getUIDL(), mail.getHeader().getDate());
|
|
}
|
|
|
|
return conversation;
|
|
}
|
|
|
|
protected void addFailure (Mail mail) throws Exception
|
|
{
|
|
addMail (mail);
|
|
}
|
|
|
|
protected void addFailure (String externalKey, Date date)
|
|
{
|
|
systemFolders.addExternalKey(externalKey, date);
|
|
}
|
|
|
|
public void addFailure (Direction direction, String path, Date date, Exception e)
|
|
{
|
|
try
|
|
{
|
|
e.printStackTrace();
|
|
|
|
Header header = new Header();
|
|
header.setSubject("Mail failed parsing. Look at original for file.");
|
|
header.setExternalKey(path);
|
|
header.setDate(date);
|
|
if (direction == Direction.IN)
|
|
header.setTransportState(TransportState.fromList(TransportState.RECEIVED));
|
|
else
|
|
header.setTransportState(TransportState.fromList(TransportState.SENT));
|
|
|
|
Body body = new Body();
|
|
body.setText("Failed to load: " + e);
|
|
|
|
Mail mail = master.getCacheManager().newMail(header, body, null);
|
|
addFailure(mail);
|
|
}
|
|
catch (Exception em)
|
|
{
|
|
em.printStackTrace();
|
|
addFailure(path, date);
|
|
}
|
|
}
|
|
|
|
public void addDuplicate (String externalKey, Date date)
|
|
{
|
|
systemFolders.addExternalKey(externalKey, date);
|
|
}
|
|
|
|
public boolean containsExternalKey (String externalKey)
|
|
{
|
|
return systemFolders.containsExternalKey(externalKey);
|
|
}
|
|
|
|
public boolean containsUIDL(String uidl)
|
|
{
|
|
return systemFolders.containsUIDL(uidl);
|
|
}
|
|
|
|
public synchronized void addConversation (Conversation conversation)
|
|
{
|
|
for (Folder e : systemFolders.getFolders())
|
|
e.conversationAdded(conversation);
|
|
|
|
for (Folder e : userFolders.getFolders())
|
|
e.conversationAdded(conversation);
|
|
}
|
|
|
|
public synchronized void removeConversation (Conversation conversation)
|
|
{
|
|
for (Folder e : systemFolders.getFolders())
|
|
e.conversationDeleted(conversation);
|
|
|
|
for (Folder e : userFolders.getFolders())
|
|
e.conversationDeleted(conversation);
|
|
}
|
|
|
|
public synchronized void conversationChanged (Conversation conversation)
|
|
{
|
|
if (conversation != null)
|
|
{
|
|
for (Folder f : systemFolders.getFolders())
|
|
f.conversationChanged(conversation);
|
|
|
|
for (Folder e : userFolders.getFolders())
|
|
e.conversationChanged(conversation);
|
|
}
|
|
|
|
master.getEventPropagator().signalOnce(Events.ChangedConversation);
|
|
}
|
|
|
|
public void replyMail (Conversation conversation, Mail mail)
|
|
{
|
|
systemFolders.addUIDL(mail.getHeader().getUIDL(), mail.getHeader().getDate());
|
|
|
|
conversationChanged(conversation);
|
|
}
|
|
|
|
public Conversation newMail (Mail mail) throws Exception
|
|
{
|
|
return addMail(mail);
|
|
}
|
|
|
|
public Folder getSystemFolder (String folderName)
|
|
{
|
|
for (Folder e : systemFolders.getFolders())
|
|
if (e.isLoaded())
|
|
if (e.getFolderDefinition().getName().equals(folderName))
|
|
return e;
|
|
|
|
return null;
|
|
}
|
|
|
|
public FolderFilter getUserFolder (String folderName)
|
|
{
|
|
for (Folder e: userFolders.getFolders())
|
|
if (e.isLoaded())
|
|
if (e.getFolderDefinition().getName().equals(folderName))
|
|
return (FolderFilter)e;
|
|
|
|
return null;
|
|
}
|
|
|
|
public List<Folder> getSystemFolders ()
|
|
{
|
|
return systemFolders.getFolders();
|
|
}
|
|
|
|
public List<Folder> getUserFolders ()
|
|
{
|
|
return userFolders.getFolders();
|
|
}
|
|
|
|
public Folder getRepository ()
|
|
{
|
|
return repository;
|
|
}
|
|
|
|
public void newUserFolder(String name)
|
|
{
|
|
userFolders.addFolder(
|
|
getMaster().getCacheManager().newFolder(
|
|
Type.FolderFilter,
|
|
new FolderDefinition(name)
|
|
.setBayesianDictionary(new Dictionary())
|
|
.setAutoBayesian(false)
|
|
.setState(null, TransportState.fromList(TransportState.SPAM, TransportState.TRASH))
|
|
)
|
|
);
|
|
}
|
|
|
|
public void deleteUserFolder(Folder userFolder)
|
|
{
|
|
userFolders.removeFolder(userFolder);
|
|
}
|
|
|
|
public void addToUserFolder(Folder userFolder, Conversation conversation)
|
|
{
|
|
FolderFilter folder = (FolderFilter)userFolder;
|
|
folder.manuallyAdd (conversation);
|
|
}
|
|
|
|
public void removeFromUserFolder(Folder userFolder, Conversation conversation)
|
|
{
|
|
FolderFilter folder = (FolderFilter)userFolder;
|
|
folder.manuallyRemove (conversation);
|
|
}
|
|
|
|
public FolderSet getInbox()
|
|
{
|
|
return (FolderSet)getMaster().getCacheManager().getFolder(Type.FolderFilter, KnownFolderIds.InboxId);
|
|
}
|
|
}
|