package won.bot.framework.eventbot.action.impl.mail.receive; import org.apache.commons.lang.StringUtils; import org.apache.jena.query.Dataset; import won.bot.framework.bot.context.MailBotContextWrapper; import won.bot.framework.eventbot.EventListenerContext; import won.bot.framework.eventbot.action.BaseEventBotAction; import won.bot.framework.eventbot.action.EventBotActionUtils; import won.bot.framework.eventbot.action.impl.mail.model.ActionType; import won.bot.framework.eventbot.action.impl.mail.model.SubscribeStatus; import won.bot.framework.eventbot.action.impl.mail.model.WonURI; import won.bot.framework.eventbot.bus.EventBus; import won.bot.framework.eventbot.event.Event; import won.bot.framework.eventbot.event.impl.command.deactivate.DeactivateNeedCommandEvent; import won.bot.framework.eventbot.event.impl.command.SendTextMessageOnConnectionEvent; import won.bot.framework.eventbot.event.impl.mail.CloseConnectionEvent; import won.bot.framework.eventbot.event.impl.mail.MailCommandEvent; import won.bot.framework.eventbot.event.impl.mail.OpenConnectionEvent; import won.bot.framework.eventbot.event.impl.mail.SubscribeUnsubscribeEvent; import won.bot.framework.eventbot.listener.EventListener; import won.protocol.model.NeedState; import won.protocol.util.DefaultNeedModelWrapper; import won.protocol.util.WonRdfUtils; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.IOException; import java.net.URI; import java.security.AccessControlException; import java.util.List; /** * Created by fsuda on 18.10.2016. */ public class MailCommandAction extends BaseEventBotAction { private MailContentExtractor mailContentExtractor; public MailCommandAction(EventListenerContext eventListenerContext, MailContentExtractor mailContentExtractor) { super(eventListenerContext); this.mailContentExtractor = mailContentExtractor; } @Override protected void doRun(Event event, EventListener executingListener) throws Exception { EventListenerContext ctx = getEventListenerContext(); if(event instanceof MailCommandEvent && ctx.getBotContextWrapper() instanceof MailBotContextWrapper){ MailBotContextWrapper botContextWrapper = (MailBotContextWrapper) ctx.getBotContextWrapper(); MimeMessage message = ((MailCommandEvent) event).getMessage(); String referenceId = MailContentExtractor.getMailReference(message); WonURI wonUri = botContextWrapper.getWonURIForMailId(referenceId); // determine if the mail is referring to some other mail/need/connection or not if(wonUri != null){ processReferenceMailCommands(message, wonUri); } else { processNonReferenceMailCommand(message); } } } private void processNonReferenceMailCommand(MimeMessage message) throws IOException, MessagingException { EventBus bus = getEventListenerContext().getEventBus(); ActionType mailAction = mailContentExtractor.getMailAction(message); switch(mailAction) { case SUBSCRIBE: bus.publish(new SubscribeUnsubscribeEvent(message, SubscribeStatus.SUBSCRIBED)); break; case UNSUBSCRIBE: bus.publish(new SubscribeUnsubscribeEvent(message, SubscribeStatus.UNSUBSCRIBED)); break; case CLOSE_NEED: /*A need can be closed with a mail that matches the takenCmdPattern in its subject and has the same title as a previously created need by the user*/ URI needUri = retrieveCorrespondingNeedUriFromMailByTitle(message); if(needUri != null) { bus.publish(new DeactivateNeedCommandEvent(needUri)); } break; case NO_ACTION: default: //INVALID COMMAND logger.error("No command was given or assumed"); break; } } private void processReferenceMailCommands(MimeMessage message, WonURI wonUri) { MailBotContextWrapper botContextWrapper = ((MailBotContextWrapper) getEventListenerContext().getBotContextWrapper()); EventBus bus = getEventListenerContext().getEventBus(); try{ if(wonUri == null){ throw new NullPointerException("No corresponding wonUri found"); } URI needUri; switch(wonUri.getType()){ case CONNECTION: Dataset connectionRDF = getEventListenerContext().getLinkedDataSource().getDataForResource(wonUri.getUri()); needUri = WonRdfUtils.ConnectionUtils.getLocalNeedURIFromConnection(connectionRDF, wonUri.getUri()); break; case NEED: default: needUri = wonUri.getUri(); break; } MimeMessage originalMessage = botContextWrapper.getMimeMessageForURI(needUri); if(originalMessage == null) { throw new NullPointerException("no originalmessage found"); } logger.debug("Validate mailorigin with originalmail:"); logger.debug("Command Message Sender: "+message.getFrom()); logger.debug("Original Message Sender: "+originalMessage.getFrom()); String senderNew = ((InternetAddress) message.getFrom()[0]).getAddress(); String senderOriginal = ((InternetAddress) originalMessage.getFrom()[0]).getAddress(); if(!senderNew.equals(senderOriginal)) { throw new AccessControlException("Sender of original and command mail are not equal"); }else{ logger.debug("Sender of original and command mail are not equal, continue with command processing"); } ActionType actionType = determineAction(getEventListenerContext(), message, wonUri); logger.debug("Executing " + actionType + " on uri: " + wonUri.getUri() + " of type " + wonUri.getType()); switch(actionType) { case CLOSE_CONNECTION: bus.publish(new CloseConnectionEvent(wonUri.getUri())); break; case OPEN_CONNECTION: bus.publish(new OpenConnectionEvent(wonUri.getUri())); break; case IMPLICIT_OPEN_CONNECTION: bus.publish(new OpenConnectionEvent(wonUri.getUri(), mailContentExtractor.getTextMessage(message))); break; case SENDMESSAGE: bus.publish(new SendTextMessageOnConnectionEvent(mailContentExtractor.getTextMessage(message), wonUri.getUri())); break; case CLOSE_NEED: bus.publish(new DeactivateNeedCommandEvent(needUri)); break; case NO_ACTION: default: //INVALID COMMAND logger.error("No command was given or assumed"); break; } }catch (AccessControlException ace){ logger.error("ACCESS RESTRICTION: sender of original and command mail are not equal, command will be blocked"); } catch(Exception e){ logger.error("no reply mail was set or found: "+e.getMessage()); } } /** * This Method tries to find a corresponding open need uri from a user(given by the from adress) and returns the * corresponding need uri if there was an open need with the same title * @param message used to extract sender adress and subject(title) * @return */ private URI retrieveCorrespondingNeedUriFromMailByTitle(MimeMessage message){ try { MailBotContextWrapper botContextWrapper = ((MailBotContextWrapper) getEventListenerContext().getBotContextWrapper()); String sender = ((InternetAddress) message.getFrom()[0]).getAddress(); URI needURI = null; String titleToClose = mailContentExtractor.getTitle(message).trim(); if (sender != null) { List<WonURI> needUris = botContextWrapper.getWonURIsForMailAddress(sender); for(WonURI u : needUris) { Dataset needRDF = getEventListenerContext().getLinkedDataSource().getDataForResource(u.getUri()); DefaultNeedModelWrapper needModelWrapper = new DefaultNeedModelWrapper(needRDF); String needTitle = StringUtils.trim(needModelWrapper.getSomeTitleFromIsOrAll("en","de")); if(titleToClose.equals(needTitle) && needModelWrapper.getNeedState().equals(NeedState.ACTIVE)){ return u.getUri(); } } } return needURI; }catch (MessagingException me){ logger.error("could not extract information from mimemessage"); return null; } } private ActionType determineAction(EventListenerContext ctx, MimeMessage message, WonURI wonUri) { try { ActionType mailAction = mailContentExtractor.getMailAction(message); switch(wonUri.getType()) { case CONNECTION: boolean connected = WonRdfUtils.ConnectionUtils.isConnected( ctx.getLinkedDataSource().getDataForResource(wonUri.getUri()), wonUri.getUri()); if (ActionType.CLOSE_CONNECTION.equals(mailAction)) { return ActionType.CLOSE_CONNECTION; }else if(!connected && ActionType.OPEN_CONNECTION.equals(mailAction)){ return ActionType.OPEN_CONNECTION; }else if(connected){ return ActionType.SENDMESSAGE; }else if(ActionType.CLOSE_NEED.equals(mailAction)){ return ActionType.CLOSE_NEED; }else{ //if the connection is not connected yet and we do not parse any command we assume that the mailsender wants to establish a connection return ActionType.IMPLICIT_OPEN_CONNECTION; } case NEED: if(ActionType.CLOSE_NEED.equals(mailAction)){ return ActionType.CLOSE_NEED; } default: return mailAction; } }catch(MessagingException me){ logger.error("exception occurred checking command mail: {}", me); return ActionType.NO_ACTION; }catch(IOException ioe){ logger.error("exception occurred checking command mail: {}", ioe); return ActionType.NO_ACTION; } } }