package won.bot.framework.eventbot.action.impl.mail.receive;
import won.bot.framework.eventbot.action.impl.mail.model.ActionType;
import won.protocol.model.NeedContentPropertyType;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Extracts need properties like title, description, need type, etc from mails. Configurable via regular expression
* patterns in spring xml
*/
public class MailContentExtractor
{
// check if mail is of type demand/supply/doTogether/critique?
private Pattern demandTypePattern;
private Pattern supplyTypePattern;
private Pattern doTogetherTypePattern;
private Pattern critiqueTypePattern;
// extract array of tags from the content
private Pattern tagExtractionPattern;
// extract text message from the mail (e.g. excluding the quoted parts of earlier mails)
private Pattern textMessageExtractionPattern;
// extract title from mail subject
private Pattern titleExtractionPattern;
// extract description from mail content
private Pattern descriptionExtractionPattern;
// check if the need created from the mail should is used for testing only
private Pattern usedForTestingPattern;
// check if the need created from the mail should be not matched with other needs
private Pattern doNotMatchPattern;
// check if this is a command mail of different action types
private Pattern cmdClosePattern;
private Pattern cmdConnectPattern;
private Pattern cmdSubscribePattern;
private Pattern cmdUnsubscribePattern;
private Pattern cmdTakenPattern;
public static String getMailReference(MimeMessage message) throws MessagingException {
// first search the mail reference is in the in-reply-to header in case user answered a mail
// e.g. in case of messages, implicit connect
String[] replyTo = message.getHeader("In-Reply-To");
if (replyTo != null && replyTo.length > 0) {
return replyTo[0];
}
// second search the mail reference in the subject written by predefined mailto links
// e.g. in case of close need
Pattern referenceMailPattern = Pattern.compile("Message-Id_(.+)");
Matcher m = referenceMailPattern.matcher(message.getSubject());
return m.find() ? m.group(1) : null;
}
public NeedContentPropertyType getNeedType(MimeMessage message) throws MessagingException {
return getNeedType(message.getSubject());
}
public NeedContentPropertyType getNeedType(String subject) {
if (demandTypePattern.matcher(subject).matches()) {
return NeedContentPropertyType.SEEKS;
} else if (supplyTypePattern.matcher(subject).matches()) {
return NeedContentPropertyType.IS;
} else if (doTogetherTypePattern.matcher(subject).matches()) {
return NeedContentPropertyType.IS_AND_SEEKS;
} else if (critiqueTypePattern.matcher(subject).matches()) {
return NeedContentPropertyType.IS_AND_SEEKS;
}
return null;
}
public static String getMailText(MimeMessage message) throws MessagingException, IOException {
if (message.isMimeType("text/plain")) {
return message.getContent().toString();
} else if (message.isMimeType("multipart/*")) {
return getMailTextFromMultiPart((MimeMultipart) message.getContent());
}
return null;
}
private static String getMailTextFromMultiPart(MimeMultipart mm) throws MessagingException, IOException {
for (int i = 0; i < mm.getCount(); i++) {
BodyPart part = mm.getBodyPart(i);
if (part.isMimeType("text/plain")) {
return part.getContent().toString();
} else if (part.isMimeType("multipart/*")) {
return getMailTextFromMultiPart((MimeMultipart) part.getContent());
}
}
return null;
}
public static String getMailSender(MimeMessage message) throws MessagingException {
Address[] froms = message.getFrom();
return (froms == null ? null : ((InternetAddress) froms[0]).getAddress());
}
public void setDemandTypePattern(final Pattern demandTypePattern) {
this.demandTypePattern = demandTypePattern;
}
public void setSupplyTypePattern(final Pattern supplyTypePattern) {
this.supplyTypePattern = supplyTypePattern;
}
public void setDoTogetherTypePattern(final Pattern doTogetherTypePattern) {
this.doTogetherTypePattern = doTogetherTypePattern;
}
public void setCritiqueTypePattern(final Pattern critiqueTypePattern) {
this.critiqueTypePattern = critiqueTypePattern;
}
public void setTagExtractionPattern(final Pattern tagExtractionPattern) {
this.tagExtractionPattern = tagExtractionPattern;
}
public void setTextMessageExtractionPattern(final Pattern textMessageExtractionPattern) {
this.textMessageExtractionPattern = textMessageExtractionPattern;
}
public void setTitleExtractionPattern(final Pattern titleExtractionPattern) {
this.titleExtractionPattern = titleExtractionPattern;
}
public void setDescriptionExtractionPattern(final Pattern descriptionExtractionPattern) {
this.descriptionExtractionPattern = descriptionExtractionPattern;
}
public void setUsedForTestingPattern(Pattern usedForTestingPattern) {
this.usedForTestingPattern = usedForTestingPattern;
}
public void setDoNotMatchPattern(Pattern doNotMatchPattern) {
this.doNotMatchPattern = doNotMatchPattern;
}
public void setCmdClosePattern(final Pattern cmdClosePattern) {
this.cmdClosePattern = cmdClosePattern;
}
public void setCmdConnectPattern(final Pattern cmdConnectPattern) {
this.cmdConnectPattern = cmdConnectPattern;
}
public void setCmdSubscribePattern(final Pattern cmdSubscribePattern) {
this.cmdSubscribePattern = cmdSubscribePattern;
}
public void setCmdUnsubscribePattern(final Pattern cmdUnsubscribePattern) {
this.cmdUnsubscribePattern = cmdUnsubscribePattern;
}
public void setCmdTakenPattern(final Pattern cmdTakenPattern) {
this.cmdTakenPattern = cmdTakenPattern;
}
public boolean isCreateNeedMail(MimeMessage messsage) throws MessagingException {
return getNeedType(messsage) != null;
}
public boolean isCommandMail(MimeMessage message) throws IOException, MessagingException {
// command mail is either an answer mail (with reference) to a previous mail (e.g. message, implicit connect) or an
// explicitly set action command (e.g. subscribe, unsubscribe, close need)
return getMailReference(message) != null || (getMailAction(message) != null && !ActionType.NO_ACTION.equals(getMailAction(message)));
}
public ActionType getMailAction(MimeMessage message) throws IOException, MessagingException {
if (cmdSubscribePattern.matcher(message.getSubject()).matches()) {
return ActionType.SUBSCRIBE;
} else if (cmdUnsubscribePattern.matcher(message.getSubject()).matches()) {
return ActionType.UNSUBSCRIBE;
} else if (cmdClosePattern.matcher(message.getSubject()).matches()) {
return ActionType.CLOSE_CONNECTION;
} else if (cmdConnectPattern.matcher(message.getSubject()).matches()) {
return ActionType.OPEN_CONNECTION;
} else if(cmdTakenPattern.matcher(message.getSubject()).matches()){
return ActionType.CLOSE_NEED;
} else {
return ActionType.NO_ACTION;
}
}
public boolean isDoNotMatch(MimeMessage message) throws MessagingException {
return doNotMatchPattern.matcher(message.getSubject()).matches();
}
public boolean isUsedForTesting(MimeMessage message) throws MessagingException {
return usedForTestingPattern.matcher(message.getSubject()).matches();
}
public String getTitle(MimeMessage message) throws MessagingException {
Matcher m = titleExtractionPattern.matcher(message.getSubject());
return m.find() ? m.group() : null;
}
public String getDescription(MimeMessage message) throws MessagingException, IOException {
String desc = getMailText(message);
if (desc != null) {
Matcher m = descriptionExtractionPattern.matcher(desc);
if (m.find()) {
return m.group().trim();
}
}
return null;
}
public String getTextMessage(MimeMessage message) throws MessagingException, IOException {
String textMessage = getMailText(message);
if (textMessage != null) {
Matcher m = textMessageExtractionPattern.matcher(textMessage);
if (m.find()) {
return m.group().trim();
}
}
return null;
}
public String[] getTags(MimeMessage message) throws MessagingException, IOException {
HashSet<String> tags = new HashSet<>();
Matcher m = tagExtractionPattern.matcher(new StringBuilder(message.getSubject()).append(" ").append(message.getContent()).toString());
while(m.find()) {
tags.add(m.group());
}
String[] tagArray = new String[tags.size()];
tagArray = tags.toArray(tagArray);
Arrays.sort(tagArray);
return tagArray;
}
public static String getFromAddressString(MimeMessage message) throws MessagingException{
Address[] froms = message.getFrom();
return (froms == null) ? null : ((InternetAddress) froms[0]).getAddress();
}
}