/** * Try to determine what address from the to address list should be used as main TO address for * the different EmailReceiver's. In case the references header is null we try to find a * matching email access point. * * @param recipients The recipients from the TO address list * @param references The references header * @return A hopefully valid email address as a string */ private String toaddress(final Address[] recipients, String references) { String result = ""; // No recipients found return n/a if (recipients == null || recipients.length == 0) return "n/a"; if (!hasStreamflowReference(references)) { Organizations.Data organizations = module .unitOfWorkFactory() .currentUnitOfWork() .get(Organizations.Data.class, OrganizationsEntity.ORGANIZATIONS_ID); EmailAccessPoints.Data emailAccessPoints = (EmailAccessPoints.Data) organizations.organization().get(); Iterable<EmailAccessPoint> possibleAccesspoints = Iterables.filter( new Specification<EmailAccessPoint>() { public boolean satisfiedBy(final EmailAccessPoint accessPoint) { return Iterables.matchesAny( new Specification<Address>() { public boolean satisfiedBy(Address address) { return ((InternetAddress) address) .getAddress() .equalsIgnoreCase(accessPoint.getDescription()); } }, Arrays.asList(recipients)); } }, emailAccessPoints.emailAccessPoints().toList()); if (Iterables.count(possibleAccesspoints) > 0) result = Iterables.first(possibleAccesspoints).getDescription(); else result = ((InternetAddress) recipients[0]).getAddress(); } else { result = ((InternetAddress) recipients[0]).getAddress(); } return Strings.empty(result) ? "n/a" : result.toLowerCase(); }
public void receivedEmail(ApplicationEvent event, EmailValue email) { UnitOfWork uow = module .unitOfWorkFactory() .newUnitOfWork(UsecaseBuilder.newUsecase("Receive email in conversation")); try { String references = email.headers().get().get("References"); if (hasStreamflowReference(references)) { // This is a response - handle it! List<String> refs = (List<String>) Iterables.addAll( (Collection<String>) new ArrayList<String>(), Iterables.iterable(references.split("[ \r\n\t]"))); // Hotmail handles refs a bit differently... String hotmailRefs = Iterables.first( Iterables.filter( new Specification<String>() { public boolean satisfiedBy(String item) { return item.contains(",") && item.endsWith("@Streamflow>"); } }, refs)); String lastRef = null; if (!Strings.empty(hotmailRefs)) { lastRef = hotmailRefs.split(",")[1]; } else { Collections.reverse(refs); Iterable<String> filter = Iterables.filter( new Specification<String>() { public boolean satisfiedBy(String item) { return item.endsWith("@Streamflow>"); } }, refs); lastRef = Iterables.first(filter); } if (lastRef == null) { ValueBuilder<EmailValue> builder = module .valueBuilderFactory() .newValueBuilder(EmailValue.class) .withPrototype(email); String subj = "Msg Ref missing: " + builder.prototype().subject().get(); builder.prototype().subject().set(subj.length() > 50 ? subj.substring(0, 50) : subj); systemDefaults.createCaseOnEmailFailure(builder.newInstance()); logger.error("Could not find message reference in email header:" + lastRef); uow.discard(); return; } Matcher matcher = Pattern.compile("<([^/]*)/([^@]*)@[^>]*>").matcher(lastRef); if (matcher.find()) { String conversationId = matcher.group(1); String participantId = URLDecoder.decode(matcher.group(2), "UTF-8"); if (!"".equals(conversationId) && !"".equals(participantId)) { ConversationParticipant from = uow.get(ConversationParticipant.class, participantId); Conversation conversation = uow.get(Conversation.class, conversationId); CaseEntity caze = (CaseEntity) conversation.conversationOwner().get(); String content = email.content().get(); // If we have an assignee, ensure it is a member of the conversation first if (caze.isAssigned()) { if (!conversation.isParticipant( (ConversationParticipant) caze.assignedTo().get())) conversation.addParticipant((ConversationParticipant) caze.assignedTo().get()); } // Create a new role map and fill it with relevant objects if (RoleMap.current() == null) RoleMap.newCurrentRoleMap(); RoleMap.current().set(from, ConversationParticipant.class); RoleMap.current().set(caze, CaseLoggable.Data.class); RoleMap.current().set(caze, Case.class); Message message = null; if (Translator.HTML.equalsIgnoreCase(email.contentType().get())) { message = conversation.createMessage(email.contentHtml().get(), MessageType.HTML, from); } else { message = conversation.createMessage(email.content().get(), MessageType.PLAIN, from); } // Create attachments for (AttachedFileValue attachedFileValue : email.attachments().get()) { if (!(attachedFileValue.mimeType().get().contains("text/x-vcard") || attachedFileValue.mimeType().get().contains("text/directory"))) { Attachment attachment = message.createAttachment(attachedFileValue.uri().get()); attachment.changeDescription("New Attachment"); attachment.changeName(attachedFileValue.name().get()); attachment.changeMimeType(attachedFileValue.mimeType().get()); attachment.changeModificationDate(attachedFileValue.modificationDate().get()); attachment.changeSize(attachedFileValue.size().get()); attachment.changeUri(attachedFileValue.uri().get()); } } try { if (caze.isStatus(CaseStates.CLOSED)) { RoleMap.newCurrentRoleMap(); RoleMap.current().set(caze); if (caze.assignedTo().get() != null) { RoleMap.current().set(caze.assignedTo().get()); } else { RoleMap.current() .set(uow.get(UserEntity.class, UserEntity.ADMINISTRATOR_USERNAME)); } CaseCommandsContext caseCommands = module.transientBuilderFactory().newTransient(CaseCommandsContext.class); caseCommands.reopen(); caseCommands.unassign(); RoleMap.clearCurrentRoleMap(); } } catch (Throwable e) { ValueBuilder<EmailValue> builder = module .valueBuilderFactory() .newValueBuilder(EmailValue.class) .withPrototype(email); String subj = "Create Case failed: " + builder.prototype().subject().get(); builder .prototype() .subject() .set(subj.length() > 50 ? subj.substring(0, 50) : subj); systemDefaults.createCaseOnEmailFailure(builder.newInstance()); // throw new IllegalStateException("Could not open case through new message.", e); } } } } uow.complete(); } catch (Exception ex) { ValueBuilder<EmailValue> builder = module.valueBuilderFactory().newValueBuilder(EmailValue.class).withPrototype(email); String subj = "Conversation Response Error: " + builder.prototype().subject().get(); builder.prototype().subject().set(subj.length() > 50 ? subj.substring(0, 50) : subj); StringBuilder content = new StringBuilder(); content.append("Error Message: " + ex.getMessage()); content.append("\n\rStackTrace:\n\r"); for (StackTraceElement trace : Arrays.asList(ex.getStackTrace())) { content.append(trace.toString() + "\n\r"); } builder.prototype().content().set(content.toString()); // since we create the content of the message our self it's ok to set content type always // to text/plain builder.prototype().contentType().set("text/plain"); // Make sure to address has some value before vi create a case!! if (builder.prototype().to().get() == null) { builder.prototype().to().set("n/a"); } systemDefaults.createCaseOnEmailFailure(builder.newInstance()); uow.discard(); // throw new ApplicationEventReplayException(event, ex); } }