Java tutorial
/* * Copyright (c) 2011-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.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.ParseException; import mitm.application.djigzo.User; import mitm.application.djigzo.james.MailAddressUtils; import mitm.application.djigzo.james.MessageOriginatorIdentifier; import mitm.application.djigzo.service.SystemServices; import mitm.application.djigzo.workflow.UserWorkflow; import mitm.common.properties.HierarchicalPropertiesException; import mitm.common.util.Base64Utils; import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.apache.mailet.Configuration; import org.apache.mailet.Mail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Mailet that can be used to set, add and delete mail attributes. For a more simple (and faster) * way to add mail attributes see {@link SetAttributes}. * * @author Martijn Brinkers * */ public class MailAttributes extends AbstractTransactedMailet { private final static Logger logger = LoggerFactory.getLogger(MailAttributes.class); /* * Pattern used for parsing the name and value */ private final static Pattern nameValuePattern = Pattern.compile("(?s)(.*?)\\s*=(.*)"); /* * Pattern to detect user variable references like #{some.var} */ private final static Pattern USER_VAR_PATTERN = Pattern.compile("#\\{\\s*(.*?)\\s*\\}"); /* * The mailet initialization parameters used by this mailet. */ private enum Parameter { SET("set"), ADD("add"), DELETE("delete"), SERIALIZED("serialized"), PROCESSOR("processor"); private String name; private Parameter(String name) { this.name = name; } }; /* * Used for adding and retrieving users */ private UserWorkflow userWorkflow; /* * Is used to identify the 'sender' (from or enveloped sender or...) of the message */ private MessageOriginatorIdentifier messageOriginatorIdentifier; /* * The attributes to delete */ private List<String> deleteAttributes; /* * The attributes to set */ private Map<String, String> setAttributes; /* * The attributes to add */ private Map<String, List<String>> addAttributes; /* * The deserialized to set */ private Map<String, Serializable> serializedAttributes; /* * The next processor (can be null in which case the processor is not changed) */ private String nextProcessor; @Override protected Logger getLogger() { return logger; } private String[] getValues(Configuration[] configurations) { if (configurations == null) { return null; } String[] values = new String[configurations.length]; for (int i = 0; i < configurations.length; i++) { values[i] = configurations[i].getValue(); } return values; } private void initDeleteAttributes() { deleteAttributes = new LinkedList<String>(); String[] deletes = getValues(getConfiguration().getChildren(Parameter.DELETE.name)); if (deletes != null) { for (String delete : deletes) { delete = StringUtils.trimToNull(delete); if (delete == null) { continue; } deleteAttributes.add(delete); } } } private String[] parseNameValue(String input) { String[] result = null; Matcher m = nameValuePattern.matcher(input); if (m.matches()) { result = new String[2]; result[0] = m.group(1); result[1] = m.group(2); } return result; } private void initSetAttributes() { setAttributes = new HashMap<String, String>(); String[] sets = getValues(getConfiguration().getChildren(Parameter.SET.name)); if (sets != null) { for (String set : sets) { set = StringUtils.trimToNull(set); if (set == null) { continue; } String[] nameValue = parseNameValue(set); if (nameValue == null) { throw new IllegalArgumentException(set + " is not a valid name value pair."); } setAttributes.put(nameValue[0], nameValue[1]); } } } private void initAddAttributes() { addAttributes = new HashMap<String, List<String>>(); String[] values = getValues(getConfiguration().getChildren(Parameter.ADD.name)); if (values != null) { for (String value : values) { value = StringUtils.trimToNull(value); if (value == null) { continue; } String[] nameValue = parseNameValue(value); if (nameValue == null) { throw new IllegalArgumentException(value + " is not a valid name value pair."); } String name = nameValue[0]; List<String> attrValues = addAttributes.get(name); if (attrValues == null) { attrValues = new LinkedList<String>(); addAttributes.put(name, attrValues); } attrValues.add(nameValue[1]); } } } private void initSerializedAttributes() { serializedAttributes = new HashMap<String, Serializable>(); String[] values = getValues(getConfiguration().getChildren(Parameter.SERIALIZED.name)); if (values != null) { for (String value : values) { value = StringUtils.trimToNull(value); if (value == null) { continue; } String[] nameValue = parseNameValue(value); if (nameValue == null) { throw new IllegalArgumentException(value + " is not a valid name value pair."); } Serializable serialized = (Serializable) SerializationUtils .deserialize(Base64Utils.decode(nameValue[1])); serializedAttributes.put(nameValue[0], serialized); } } } void initAttributes() { initDeleteAttributes(); initSetAttributes(); initAddAttributes(); initSerializedAttributes(); nextProcessor = getInitParameter(Parameter.PROCESSOR.name); } @Override public void initMailetTransacted() throws MessagingException { userWorkflow = SystemServices.getUserWorkflow(); messageOriginatorIdentifier = SystemServices.getMessageOriginatorIdentifier(); initAttributes(); } private void copyMailAddresses(Address address, Collection<String> target) throws ParseException { copyMailAddresses(new Address[] { address }, target); } private void copyMailAddresses(Address[] source, Collection<String> target) throws ParseException { if (source != null) { for (Address address : source) { if (address != null) { target.add(address.toString()); } } } } /* * Parses the address and if it's a special address, the special address is converted into a * real email address. */ private LinkedList<String> parseAttributes(Collection<String> attributes, Mail mail) throws MessagingException { LinkedList<String> result = new LinkedList<String>(); if (attributes != null) { for (String attribute : attributes) { result.addAll(parseAttribute(attribute, mail)); } } return result; } /* * Parses the address and if it's a special address, the special address is converted into a * real email address. */ private LinkedList<String> parseAttribute(String attribute, Mail mail) throws MessagingException { attribute = StringUtils.trimToNull(attribute); LinkedList<String> result = new LinkedList<String>(); if (attribute != null) { /* * Check if the input is a special address */ SpecialAddress specialAddress = SpecialAddress.fromName(attribute); if (specialAddress != null) { switch (specialAddress) { case ORIGINATOR: copyMailAddresses(messageOriginatorIdentifier.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."); } } else { /* * Check if the input is a user property */ Matcher matcher = USER_VAR_PATTERN.matcher(attribute); if (matcher.matches()) { InternetAddress originator = messageOriginatorIdentifier.getOriginator(mail); if (originator != null) { String userProperty = matcher.group(1); try { User user = userWorkflow.getUser(originator.getAddress(), UserWorkflow.GetUserMode.CREATE_IF_NOT_EXIST); String value = user.getUserPreferences().getProperties().getProperty(userProperty, false); value = StringUtils.trimToNull(value); if (value != null) { result.add(value); } } catch (HierarchicalPropertiesException e) { getLogger().error("Error getting user property " + userProperty, e); } } } else { result.add(attribute); } } } return result; } @SuppressWarnings("unchecked") @Override public void serviceMailTransacted(Mail mail) throws MessagingException { /* * First delete all attributes, then set and finally add */ for (String attribute : deleteAttributes) { mail.removeAttribute(attribute); } /* * Set attributes */ for (Entry<String, String> attribute : setAttributes.entrySet()) { LinkedList<String> attributes = parseAttribute(attribute.getValue(), mail); if (attributes.size() > 0) { mail.setAttribute(attribute.getKey(), StringUtils.join(attributes, ',')); } else { mail.removeAttribute(attribute.getKey()); } } /* * Serialized attributes */ for (Entry<String, Serializable> attribute : serializedAttributes.entrySet()) { mail.setAttribute(attribute.getKey(), attribute.getValue()); } /* * Add attributes. If an attribute already exists and is a Collection, the new value * will be added to the collection. If not, a LinkedList will be created and the * value will be added to the list. */ for (Entry<String, List<String>> attribute : addAttributes.entrySet()) { /* * Check if the attribute exists and is a collection */ Object existingAttr = mail.getAttribute(attribute.getKey()); Collection<Object> attributes; if (existingAttr == null || !(existingAttr instanceof Collection)) { attributes = new LinkedList<Object>(); } else { attributes = (Collection<Object>) existingAttr; } attributes.addAll(parseAttributes(attribute.getValue(), mail)); if (attributes.size() > 0) { mail.setAttribute(attribute.getKey(), (Serializable) attributes); } else { mail.removeAttribute(attribute.getKey()); } } if (nextProcessor != null) { mail.setState(nextProcessor); } } }