parent
f2c4dde8bc
commit
7cc5658c89
@ -0,0 +1,23 @@
|
|||||||
|
package com.olexyn.burnsmail.flow;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.flow.action.Action;
|
||||||
|
import com.olexyn.burnsmail.flow.cleanup.Cleanup;
|
||||||
|
import com.olexyn.burnsmail.flow.filter.FilterAMail;
|
||||||
|
import com.olexyn.burnsmail.flow.map.ToAMailMapper;
|
||||||
|
import com.olexyn.burnsmail.flow.search.SearchFolder;
|
||||||
|
import com.olexyn.burnsmail.flow.transform.TransformAMail;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Flow {
|
||||||
|
|
||||||
|
private SearchFolder searchFolder;
|
||||||
|
private ToAMailMapper toAMailMapper;
|
||||||
|
private FilterAMail filterAMail;
|
||||||
|
private TransformAMail transformAMail;
|
||||||
|
private Action action;
|
||||||
|
private Cleanup cleanup;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.action;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
|
||||||
|
import javax.mail.Store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first step in the flow.
|
||||||
|
*/
|
||||||
|
public interface Action {
|
||||||
|
|
||||||
|
|
||||||
|
void execute(AMail aMail, Store store);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.action;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.MiscU;
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import com.olexyn.min.log.LogU;
|
||||||
|
|
||||||
|
import javax.mail.Flags;
|
||||||
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.Store;
|
||||||
|
|
||||||
|
public class CopyToDst implements Action {
|
||||||
|
|
||||||
|
private final String src;
|
||||||
|
private final String dst;
|
||||||
|
private Folder srcF;
|
||||||
|
private Folder dstF;
|
||||||
|
|
||||||
|
public CopyToDst(String src, String dst) {
|
||||||
|
this.src = src;
|
||||||
|
this.dst = dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(AMail aMail, Store store) {
|
||||||
|
try {
|
||||||
|
if (srcF == null) {
|
||||||
|
srcF = MiscU.open(store, src);
|
||||||
|
}
|
||||||
|
if (dstF == null) {
|
||||||
|
dstF = MiscU.open(store, dst);
|
||||||
|
}
|
||||||
|
srcF.copyMessages(new Message[]{aMail.getImapMessage()}, dstF);
|
||||||
|
aMail.getImapMessage().setFlag(Flags.Flag.DELETED, true);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
LogU.warnPlain("Could not copy mail." + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.cleanup;
|
||||||
|
|
||||||
|
import javax.mail.Store;
|
||||||
|
|
||||||
|
public interface Cleanup {
|
||||||
|
|
||||||
|
void cleanUp(Store store);
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.cleanup;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.MiscU;
|
||||||
|
import com.olexyn.min.log.LogU;
|
||||||
|
|
||||||
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.Store;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class FlushFolders implements Cleanup {
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, Folder> folders = new HashMap<>();
|
||||||
|
|
||||||
|
public FlushFolders(String... folders) {
|
||||||
|
for (String folder : folders) {
|
||||||
|
this.folders.put(folder, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanUp(Store store) {
|
||||||
|
for (var entry : folders.entrySet()) {
|
||||||
|
String src = entry.getKey();
|
||||||
|
Folder srcF = entry.getValue();
|
||||||
|
try {
|
||||||
|
if (srcF == null) {
|
||||||
|
srcF = MiscU.open(store, src);
|
||||||
|
}
|
||||||
|
srcF.exists();
|
||||||
|
srcF.close(false);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
LogU.warnPlain("Could not flush folder " + src + " " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.filter;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AnyFromContains implements FilterAMail {
|
||||||
|
|
||||||
|
private final List<String> froms;
|
||||||
|
|
||||||
|
public AnyFromContains(String... froms) {
|
||||||
|
this.froms = List.of(froms);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doKeep(AMail aMail) {
|
||||||
|
if (aMail != null && aMail.getSubject() != null) {
|
||||||
|
return froms.contains(aMail.getFrom());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.filter;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AnySubjectContains implements FilterAMail {
|
||||||
|
|
||||||
|
private final List<String> subjects;
|
||||||
|
|
||||||
|
public AnySubjectContains(String... subjects) {
|
||||||
|
this.subjects = List.of(subjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doKeep(AMail aMail) {
|
||||||
|
if (aMail != null && aMail.getSubject() != null) {
|
||||||
|
return subjects.contains(aMail.getSubject());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.filter;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
|
||||||
|
public interface FilterAMail {
|
||||||
|
|
||||||
|
|
||||||
|
boolean doKeep(AMail aMail);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.filter;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
|
||||||
|
|
||||||
|
public class NoFilter implements FilterAMail {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doKeep(AMail aMail) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.map;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import com.olexyn.min.log.LogU;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.internet.MimeMultipart;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
public class FullToAMailMapper implements ToAMailMapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AMail map(Message message) {
|
||||||
|
var aMail = new LazyToAMailMapper().map(message);
|
||||||
|
if (aMail == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var imapMessage = aMail.getImapMessage();
|
||||||
|
try {
|
||||||
|
var imapContent = imapMessage.getContent();
|
||||||
|
String htmlContent = null;
|
||||||
|
if (imapContent instanceof String str) {
|
||||||
|
htmlContent = str;
|
||||||
|
} else if (imapContent instanceof MimeMultipart multi) {
|
||||||
|
var out = new ByteArrayOutputStream();
|
||||||
|
multi.writeTo(out);
|
||||||
|
htmlContent = out.toString(UTF_8);
|
||||||
|
}
|
||||||
|
htmlContent = Optional.ofNullable(htmlContent).orElse("");
|
||||||
|
aMail.setContent(Jsoup.parse(htmlContent).text());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogU.warnPlain("Could not parse." + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aMail;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.map;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import com.sun.mail.imap.IMAPMessage;
|
||||||
|
|
||||||
|
import javax.mail.Message;
|
||||||
|
|
||||||
|
import static com.olexyn.burnsmail.MiscU.extractEmail;
|
||||||
|
|
||||||
|
public class LazyToAMailMapper implements ToAMailMapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AMail map(Message message) {
|
||||||
|
if (!(message instanceof IMAPMessage imapMessage)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var aMail = new AMail();
|
||||||
|
aMail.setImapMessage(imapMessage);
|
||||||
|
try {
|
||||||
|
if (imapMessage.getFrom() != null && imapMessage.getFrom().length > 0) {
|
||||||
|
var rawFrom = imapMessage.getFrom()[0].toString();
|
||||||
|
aMail.setFrom(extractEmail(rawFrom));
|
||||||
|
}
|
||||||
|
if (imapMessage.getAllRecipients() != null && imapMessage.getAllRecipients().length > 0) {
|
||||||
|
var rawTo = imapMessage.getAllRecipients()[0].toString();
|
||||||
|
aMail.setTo(extractEmail(rawTo));
|
||||||
|
}
|
||||||
|
aMail.setSubject(imapMessage.getSubject());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aMail;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.map;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.mail.Message;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ToAMailMapper {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
AMail map(Message message);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.search;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.MiscU;
|
||||||
|
|
||||||
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.Store;
|
||||||
|
|
||||||
|
public class FetchAll implements SearchFolder {
|
||||||
|
|
||||||
|
|
||||||
|
private final String src;
|
||||||
|
private Folder srcF;
|
||||||
|
|
||||||
|
public FetchAll(String src) {
|
||||||
|
this.src = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] search(Store store) {
|
||||||
|
try {
|
||||||
|
if (srcF == null) {
|
||||||
|
srcF = MiscU.open(store, src);
|
||||||
|
}
|
||||||
|
return srcF.getMessages();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Message[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.search;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.MiscU;
|
||||||
|
|
||||||
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.Store;
|
||||||
|
import javax.mail.search.OrTerm;
|
||||||
|
import javax.mail.search.SearchTerm;
|
||||||
|
import javax.mail.search.SubjectTerm;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class SearchAnySubject implements SearchFolder {
|
||||||
|
|
||||||
|
private final String src;
|
||||||
|
private Folder srcF;
|
||||||
|
private final SearchTerm searchTerm;
|
||||||
|
|
||||||
|
public SearchAnySubject(String src, String... subjects) {
|
||||||
|
this.src = src;
|
||||||
|
var subjectTerms = Arrays.stream(subjects)
|
||||||
|
.map(SubjectTerm::new)
|
||||||
|
.toArray(SubjectTerm[]::new);
|
||||||
|
this.searchTerm = new OrTerm(subjectTerms);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] search(Store store) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (srcF == null) {
|
||||||
|
srcF = MiscU.open(store, src);
|
||||||
|
}
|
||||||
|
return srcF.search(searchTerm);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Message[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.search;
|
||||||
|
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.Store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first step in the flow.
|
||||||
|
*/
|
||||||
|
public interface SearchFolder {
|
||||||
|
|
||||||
|
|
||||||
|
Message[] search(Store store);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.transform;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
import com.olexyn.burnsmail.openai.OpenAiAMailClassifier;
|
||||||
|
|
||||||
|
import static com.olexyn.burnsmail.model.ClassifyCategory.SPAM;
|
||||||
|
|
||||||
|
public class SetOpenAiScore implements TransformAMail {
|
||||||
|
|
||||||
|
private final OpenAiAMailClassifier openAiAMailClassifier;
|
||||||
|
|
||||||
|
public SetOpenAiScore(OpenAiAMailClassifier openAiAMailClassifier) {
|
||||||
|
this.openAiAMailClassifier = openAiAMailClassifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AMail transform(AMail aMail) {
|
||||||
|
aMail.setSpamScore(openAiAMailClassifier.classifyAMail(aMail, SPAM));
|
||||||
|
return aMail;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.olexyn.burnsmail.flow.transform;
|
||||||
|
|
||||||
|
import com.olexyn.burnsmail.model.AMail;
|
||||||
|
|
||||||
|
public interface TransformAMail {
|
||||||
|
|
||||||
|
|
||||||
|
AMail transform(AMail aMail);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue