mitm.application.djigzo.james.mailets.MailAttributes.java Source code

Java tutorial

Introduction

Here is the source code for mitm.application.djigzo.james.mailets.MailAttributes.java

Source

/*
 * 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);
        }
    }
}