org.silverpeas.components.mailinglist.service.job.MailProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.silverpeas.components.mailinglist.service.job.MailProcessor.java

Source

/*
 * Copyright (C) 2000 - 2018 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception. You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.silverpeas.components.mailinglist.service.job;

import org.silverpeas.components.mailinglist.service.event.MessageEvent;
import org.silverpeas.components.mailinglist.service.event.MessageListener;
import org.silverpeas.components.mailinglist.service.model.beans.Attachment;
import org.silverpeas.components.mailinglist.service.model.beans.Message;
import org.silverpeas.components.mailinglist.service.util.HtmlCleaner;
import org.silverpeas.core.silvertrace.SilverTrace;
import org.apache.commons.io.IOUtils;
import org.silverpeas.core.util.file.FileRepositoryManager;
import org.silverpeas.core.util.file.FileUtil;
import org.silverpeas.core.util.MimeTypes;
import org.silverpeas.core.util.logging.SilverLogger;

import javax.inject.Inject;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.ParseException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;

public class MailProcessor {

    public static final int SUMMARY_SIZE = 200;
    public static final String MAIL_HEADER_IN_REPLY_TO = "In-Reply-To";
    public static final String MAIL_HEADER_REFERENCES = "References";

    private SilverLogger logger = SilverLogger.getLogger(this);

    @Inject
    private HtmlCleaner cleaner;

    public void setCleaner(HtmlCleaner cleaner) {
        this.cleaner = cleaner;
        this.cleaner.setSummarySize(SUMMARY_SIZE);
    }

    /**
     * Processes a part for a multi-part email.
     * @param part the part to be processed.
     * @param message the message corresponding to the email.
     * @throws MessagingException
     * @throws IOException
     */
    public void processMailPart(Part part, Message message) throws MessagingException, IOException {
        if (!isTextPart(part)) {
            Object content = part.getContent();
            if (content instanceof Multipart) {
                processMultipart((Multipart) content, message);
            } else {
                String fileName = getFileName(part);
                if (fileName != null) {
                    Attachment attachment = new Attachment();
                    attachment.setSize(part.getSize());
                    attachment.setFileName(fileName);
                    attachment.setContentType(extractContentType(part.getContentType()));
                    String attachmentPath = saveAttachment(part, message.getComponentId(), message.getMessageId());
                    attachment.setPath(attachmentPath);
                    message.getAttachments().add(attachment);
                }
            }
        } else {
            processBody((String) part.getContent(), extractContentType(part.getContentType()), message);
        }
    }

    /**
     * Processes the body (text) part of an email.
     * @param content the text content of the email.
     * @param contentType the content type for this text.
     * @param message the message corresponding to this part
     * @throws IOException
     * @throws MessagingException
     */
    public void processBody(String content, String contentType, Message message)
            throws IOException, MessagingException {
        if (message.getContentType() != null && message.getContentType().contains(MimeTypes.HTML_MIME_TYPE)) {
            // this is the text-part of an HTMLmultipart message
            return;
        }
        message.setContentType(contentType);
        if (contentType == null) {
            message.setContentType(MimeTypes.PLAIN_TEXT_MIME_TYPE);
        }
        if (message.getContentType().contains(MimeTypes.PLAIN_TEXT_MIME_TYPE)) {
            message.setBody(content);
            if (message.getBody().length() > SUMMARY_SIZE) {
                message.setSummary(message.getBody().substring(0, SUMMARY_SIZE));
            } else {
                message.setSummary(message.getBody());
            }
        } else if (message.getContentType().contains(MimeTypes.HTML_MIME_TYPE)) {
            message.setBody(content);
            Reader reader = null;
            try {
                reader = new StringReader(content);
                cleaner.parse(reader);
                message.setSummary(cleaner.getSummary());
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
        } else { // Managing as text/plain
            message.setContentType(MimeTypes.PLAIN_TEXT_MIME_TYPE);
            message.setBody(content);
            if (message.getBody().length() > SUMMARY_SIZE) {
                message.setSummary(message.getBody().substring(0, SUMMARY_SIZE));
            } else {
                message.setSummary(message.getBody());
            }
        }
    }

    /**
     * Replaces special chars.
     * @param toParse the String whose chars are to be replaced.
     * @return the String without its special chars. Empty String if toParse is null.
     */
    public String replaceSpecialChars(String toParse) {
        if (toParse == null) {
            return "";
        }
        String newLogicalName = toParse.replace(' ', '_');
        newLogicalName = newLogicalName.replace('\'', '_');
        newLogicalName = newLogicalName.replace('-', '_');
        newLogicalName = newLogicalName.replace('#', '_');
        newLogicalName = newLogicalName.replace('%', '_');
        newLogicalName = newLogicalName.replace('>', '_');
        newLogicalName = newLogicalName.replace('<', '_');
        newLogicalName = newLogicalName.replace('\\', '_');
        newLogicalName = newLogicalName.replace('/', '_');
        newLogicalName = newLogicalName.replace('?', '_');
        newLogicalName = newLogicalName.replace(':', '_');
        newLogicalName = newLogicalName.replace('|', '_');
        newLogicalName = newLogicalName.replace('"', '_');
        return newLogicalName;
    }

    /**
     * Saves an attachment as a file, and stores the path in the message.
     * @param part the part corresponding to the attachment.
     * @param componentId the id of the mailing list component.
     * @param messageId the id of the message (email id).
     * @return the absolute path to the file.
     * @throws IOException
     * @throws MessagingException
     */
    public String saveAttachment(Part part, String componentId, String messageId)
            throws IOException, MessagingException {
        File parentDir = new File(
                FileRepositoryManager.getAbsolutePath(componentId) + replaceSpecialChars(messageId));
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        File targetFile = new File(parentDir, getFileName(part));
        InputStream partIn = part.getInputStream();
        try {

            FileUtil.writeFile(targetFile, partIn);

        } finally {
            IOUtils.closeQuietly(partIn);
        }
        return targetFile.getAbsolutePath();
    }

    /**
     * Process an email, extracting attachments and constructing a Message.
     * @param mail the email to be processed.
     * @param mailingList the mailing list it is going to be affected to.
     * @param event the event which will be send at the end of all processing.
     * @throws MessagingException
     * @throws IOException
     */
    public void prepareMessage(MimeMessage mail, MessageListener mailingList, MessageEvent event)
            throws MessagingException, IOException {
        String sender = ((InternetAddress[]) mail.getFrom())[0].getAddress();
        if (!mailingList.checkSender(sender)) {
            return;
        }
        Message message = new Message();
        message.setComponentId(mailingList.getComponentId());
        message.setSender(sender);
        message.setSentDate(mail.getSentDate());
        message.setMessageId(mail.getMessageID());
        String[] referenceId = mail.getHeader(MAIL_HEADER_IN_REPLY_TO);
        if (referenceId == null || referenceId.length == 0) {
            referenceId = mail.getHeader(MAIL_HEADER_REFERENCES);
        }
        if (referenceId == null || referenceId.length == 0) {
            message.setReferenceId(null);
        } else {
            message.setReferenceId(referenceId[0]);
        }
        message.setTitle(mail.getSubject());
        Object content = mail.getContent();
        if (content instanceof Multipart) {
            processMultipart((Multipart) content, message);
        } else if (content instanceof String) {
            processBody((String) content, mail.getContentType(), message);
        }
        event.addMessage(message);
    }

    protected static String extractContentType(String contentType) {
        try {
            ContentType type = new ContentType(contentType);
            return type.getBaseType();
        } catch (ParseException e) {
            SilverTrace.error("mailinglist", "MailProcessor.extractContentType()", "mailinglist.notification.error",
                    e);
        }
        return contentType;
    }

    protected String getFileName(Part part) throws MessagingException {
        String fileName = part.getFileName();
        if (fileName == null) {
            try {
                ContentType type = new ContentType(part.getContentType());
                fileName = type.getParameter("name");
            } catch (ParseException e) {
                logger.error(e.getMessage(), e);
            }
        }
        return fileName;
    }

    /**
     * Analyze the part to check if it is an attachment, a base64 encoded file or some text.
     * @param part the part to be analyzed.
     * @return true if it is some text - false otherwise.
     * @throws MessagingException
     */
    protected boolean isTextPart(Part part) throws MessagingException {
        String disposition = part.getDisposition();
        if (!Part.ATTACHMENT.equals(disposition) && !Part.INLINE.equals(disposition)) {
            try {
                ContentType type = new ContentType(part.getContentType());
                return "text".equalsIgnoreCase(type.getPrimaryType());
            } catch (ParseException e) {
                logger.error(e.getMessage(), e);
            }
        } else if (Part.INLINE.equals(disposition)) {
            try {
                ContentType type = new ContentType(part.getContentType());
                return "text".equalsIgnoreCase(type.getPrimaryType()) && getFileName(part) == null;
            } catch (ParseException e) {
                logger.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public void processMultipart(Multipart multipart, Message message) throws MessagingException, IOException {
        int partsNumber = multipart.getCount();
        for (int i = 0; i < partsNumber; i++) {
            Part part = multipart.getBodyPart(i);
            processMailPart(part, message);
        }
    }
}