Java tutorial
/* * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.application.djigzo.james.mailets; import java.util.Collection; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.Message.RecipientType; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.ParseException; import mitm.application.djigzo.User; import mitm.application.djigzo.james.DjigzoMailAttributes; import mitm.application.djigzo.james.DjigzoMailAttributesImpl; import mitm.application.djigzo.james.MailAddressUtils; import mitm.application.djigzo.workflow.UserWorkflow; import mitm.common.mail.EmailAddressUtils; import mitm.common.properties.HierarchicalPropertiesException; import org.apache.commons.lang.StringUtils; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Notify is an extension of SendMailTemplate that allows some mail parameters to be set (like subject, from, to etc.). * * The following template parameters are supported: * * subject : Set to subject of source mail (String) * from : Set to from of source mail (only the first from is used) (Address) * replyTo : Set to replyTo of source mail (only the first replyTo is used) (Address) * to : Set to 'to' of the source mail (collection of Address) * cc : Set to 'cc' of the source mail (collection of Address) * sender : Set to the sender of the mail (MailAddress) * recipients : Set to recipients of the source mail (collection of MailAddress) * body : Set to null * date : Current date (Date) * mail : The source mail (Mail) * * Supported mailet parameters: * * template : Path to the Freemarker template file. The file must exist (no default, must be specified) * templateProperty : The user property from which a template is read * processor : The next processor for the new mail (default: root) * passThrough : If false the source message will be removed (ghost'ed) * subject : The subject of the notification * from : The from header of the notification * replyTo : The replyTo header of the notification * to : The to header of the notification * cc : The cc header of the notification * sender : The sender of the notification * recipients : The recipients of the notification * catchRuntimeExceptions : If true all RunTimeExceptions are caught (default: true) * catchErrors : If true all Errors are caught (default: true) * * Some parameters support the following special addresses: * * sameAsRecipients * sameAsMessage * originator * replyTo * sender * from * * @author Martijn Brinkers * */ public class Notify extends SenderTemplatePropertySendMail { private final static Logger logger = LoggerFactory.getLogger(Notify.class); /* * Pattern to detect user variable references in special email addresses (i.e., address * like #{some.var} */ private final static Pattern USER_VAR_PATTERN = Pattern.compile("#\\{\\s*(.*?)\\s*\\}"); /* * Pattern to detect Mail attribute pattern like ${some.var} */ private final static Pattern MAIL_ATTR_PATTERN = Pattern.compile("\\$\\{\\s*(.*?)\\s*\\}"); /* * Subject of the notification */ private String subject; /* * from of the notification */ private Address from; /* * replyTo of the notification */ private String replyTo; /* * to headers of the notification */ private String to; /* * cc headers of the notification */ private String cc; /* * The sender of the notification */ private MailAddress sender; /* * The recipients of the notification */ private String recipients; /* * The mailet initialization parameters used by this mailet. */ private enum Parameter { SUBJECT("subject"), FROM("from"), REPLY_TO("replyTo"), TO("to"), CC("cc"), SENDER("sender"), RECIPIENTS( "recipients"); private String name; private Parameter(String name) { this.name = name; } }; @Override protected Logger getLogger() { return logger; } private String checkNull(String input) { return input == null || SpecialAddress.fromName(input) == SpecialAddress.NULL ? null : input; } private Address toAddress(String email) throws AddressException { Address address = null; if (email != null) { address = new InternetAddress(email, false); } return address; } /* * We will override this method because we want the default setting for removal off * SMTP extensions from false to true for the Notify class. */ @Override protected boolean getInitRemoveSMTPExtensions() { return getBooleanInitParameter(SendMailTemplate.Parameter.REMOVE_SMTP_EXTENSIONS.getName(), true); } @Override public void initMailet() throws MessagingException { super.initMailet(); subject = getInitParameter(Parameter.SUBJECT.name); from = toAddress(checkNull(getInitParameter(Parameter.FROM.name))); replyTo = checkNull(getInitParameter(Parameter.REPLY_TO.name)); to = checkNull(getInitParameter(Parameter.TO.name)); cc = checkNull(getInitParameter(Parameter.CC.name)); String senderEmail = checkNull(getInitParameter(Parameter.SENDER.name)); if (senderEmail != null) { try { sender = new MailAddress(senderEmail); } catch (ParseException e) { throw new IllegalArgumentException("Sender address is not a valid email address: " + senderEmail); } } recipients = getInitParameter(Parameter.RECIPIENTS.name); if (recipients == null) { throw new IllegalArgumentException("recipients must be specified."); } } @Override protected String getSubject(Mail mail) throws MessagingException { return SpecialAddress.fromName(subject) == SpecialAddress.SAME_AS_MESSAGE ? mail.getMessage().getSubject() : subject; } @Override protected Address getFrom(Mail mail) throws MessagingException { return from; } @Override protected Address getReplyTo(Mail mail) throws MessagingException { return replyTo != null ? new InternetAddress(replyTo) : null; } @Override protected String getBody(Mail mail) throws MessagingException { DjigzoMailAttributes mailAttributes = new DjigzoMailAttributesImpl(mail); return mailAttributes.getMessage(); } private void copyAddresses(Collection<MailAddress> source, Collection<Address> target) { if (source != null) { for (MailAddress address : source) { if (address == null) { continue; } InternetAddress inetAddress = address.toInternetAddress(); /* * We never want the invalid@invalid.tld address */ if (EmailAddressUtils.isInvalidDummyAddress(inetAddress)) { continue; } if (inetAddress != null) { target.add(inetAddress); } } } } private void copyAddresses(Address[] source, Collection<Address> target) { if (source != null) { for (Address address : source) { if (address == null) { continue; } String email; if (address instanceof InternetAddress) { email = ((InternetAddress) address).getAddress(); } else { email = address.toString(); } /* * We never want the invalid@invalid.tld address */ if (EmailAddressUtils.isInvalidDummyAddress(email)) { continue; } target.add(address); } } } private void copyMailAddresses(Address address, Collection<MailAddress> target) throws ParseException { copyMailAddresses(new Address[] { address }, target); } private void copyMailAddresses(Address[] source, Collection<MailAddress> target) throws ParseException { if (source != null) { for (Address address : source) { if (address instanceof InternetAddress) { InternetAddress inetAddress = (InternetAddress) address; /* * We never want the invalid@invalid.tld address */ if (EmailAddressUtils.isInvalidDummyAddress(inetAddress)) { continue; } target.add(new MailAddress(inetAddress)); } } } } private Collection<Address> getHeaderRecipients(String value, RecipientType recipientType, Mail mail) throws MessagingException { Collection<Address> result = null; if (StringUtils.isNotEmpty(value)) { result = new LinkedList<Address>(); String[] stringRecipients = value.split("\\s*,\\s*"); for (String recipient : stringRecipients) { recipient = StringUtils.trimToNull(recipient); if (recipient == null) { continue; } SpecialAddress specialAddress = SpecialAddress.fromName(recipient); if (specialAddress == SpecialAddress.SAME_AS_RECIPIENTS) { copyAddresses(getRecipients(mail), result); } else if (specialAddress == SpecialAddress.SAME_AS_MESSAGE) { copyAddresses(mail.getMessage().getRecipients(recipientType), result); } else { result.addAll(MailAddressUtils.toInternetAddressList(parseAddress(recipient, mail))); } } } return result; } @Override protected Collection<Address> getTo(Mail mail) throws MessagingException { return getHeaderRecipients(to, RecipientType.TO, mail); } @Override protected Collection<Address> getCC(Mail mail) throws MessagingException { return getHeaderRecipients(cc, RecipientType.CC, mail); } @Override protected MailAddress getSender(Mail mail) throws MessagingException { return sender; } @Override protected Collection<MailAddress> getRecipients(Mail mail) throws MessagingException, MissingRecipientsException { Collection<MailAddress> result = new LinkedHashSet<MailAddress>(); String[] stringRecipients = recipients.split("\\s*,\\s*"); for (String recipient : stringRecipients) { result.addAll(parseAddress(recipient, mail)); } if (result.size() == 0) { throw new MissingRecipientsException("There are no recipients."); } return result; } /* * Parses the address and if it's a special address, the special address is converted into a * real email address. */ private Collection<MailAddress> parseAddress(String input, Mail mail) throws MessagingException { input = StringUtils.trimToNull(input); Collection<MailAddress> result = new LinkedHashSet<MailAddress>(); if (input != null) { SpecialAddress specialAddress = SpecialAddress.fromName(input); if (specialAddress != null) { handleSpecialAddress(mail, result, specialAddress); } else { /* * Check if the address is a mail attribute */ Matcher matcher = MAIL_ATTR_PATTERN.matcher(input); if (matcher.matches()) { handleMailAttribute(mail, matcher.group(1), result); } else { /* * Check if the address is a user property address */ matcher = USER_VAR_PATTERN.matcher(input); if (matcher.matches()) { handleUserProperty(mail, matcher.group(1), result); } else { /* * Assume the input is a normal email address. However, we never want * the invalid@invalid.tld address */ if (!EmailAddressUtils.isInvalidDummyAddress(input)) { result.add(new MailAddress(input)); } } } } } return result; } private void handleSpecialAddress(Mail mail, Collection<MailAddress> result, SpecialAddress specialAddress) throws MessagingException { switch (specialAddress) { case ORIGINATOR: copyMailAddresses(getMessageOriginatorIdentifier().getOriginator(mail), result); break; case REPLY_TO: copyMailAddresses(mail.getMessage().getReplyTo(), result); break; case SENDER: copyMailAddresses(MailAddressUtils.toInternetAddress(mail.getSender()), result); break; case FROM: copyMailAddresses(mail.getMessage().getFrom(), result); break; default: throw new MessagingException("Unsupported SpecialAddress."); } } /* * Tries to convert input to MailAddress's. */ private void addEmails(Object input, Collection<MailAddress> target) { if (input == null) { return; } if (input instanceof String) { String addresses = StringUtils.trimToNull((String) input); if (addresses != null) { try { InternetAddress[] emails = InternetAddress.parse(addresses, false); if (emails != null) { for (InternetAddress email : emails) { if (email == null) { continue; } /* * We never want the invalid@invalid.tld address */ if (EmailAddressUtils.isInvalidDummyAddress(email)) { continue; } try { target.add(new MailAddress(email)); } catch (ParseException e) { getLogger().warn("Email address is invalid. Skipping address: " + email); } } } } catch (AddressException e) { getLogger().warn("Email address(s) are invalid " + addresses); } } } else if (input instanceof MailAddress) { MailAddress mailAddress = (MailAddress) input; /* * We never want the invalid@invalid.tld address */ if (!EmailAddressUtils.isInvalidDummyAddress(mailAddress.toInternetAddress())) { target.add(mailAddress); } } else if (input instanceof InternetAddress) { InternetAddress inetAddress = (InternetAddress) input; /* * We never want the invalid@invalid.tld address */ if (!EmailAddressUtils.isInvalidDummyAddress(inetAddress)) { try { target.add(new MailAddress(inetAddress)); } catch (ParseException e) { getLogger().warn("Email address is invalid. Skipping address: " + input); } } } else if (input instanceof Collection) { for (Object o : (Collection<?>) input) { addEmails(o, target); } } else if (input instanceof Object[]) { for (Object o : (Object[]) input) { addEmails(o, target); } } else { /* * Fallback to #toString */ addEmails(input.toString(), target); } } private void handleUserProperty(Mail mail, String userProperty, Collection<MailAddress> result) throws MessagingException, AddressException { InternetAddress originator = getMessageOriginatorIdentifier().getOriginator(mail); if (originator != null) { try { User user = getUserWorkflow().getUser(originator.getAddress(), UserWorkflow.GetUserMode.CREATE_IF_NOT_EXIST); String userValue = user.getUserPreferences().getProperties().getProperty(userProperty, false); addEmails(userValue, result); } catch (HierarchicalPropertiesException e) { getLogger().error("Error getting user property " + userProperty, e); } } } private void handleMailAttribute(Mail mail, String attribute, Collection<MailAddress> result) { Object attributeValue = mail.getAttribute(attribute); if (getLogger().isDebugEnabled()) { getLogger().debug("Mail attr " + attribute + " value: " + attributeValue); } if (attributeValue != null) { addEmails(attributeValue, result); } } }