com.duroty.service.Mailet.java Source code

Java tutorial

Introduction

Here is the source code for com.duroty.service.Mailet.java

Source

/*
* Copyright (C) 2006 Jordi Marqus Ferr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file DUROTY.txt.
*
* Author: Jordi Marqus Ferr
* c/Mallorca 295 principal B 08037 Barcelona Spain
* Phone: +34 625397324
*/

/**
 *
 */
package com.duroty.service;

import com.duroty.application.mail.manager.SendMessageThread;

import com.duroty.hibernate.Attachment;
import com.duroty.hibernate.BuddyList;
import com.duroty.hibernate.Contact;
import com.duroty.hibernate.Identity;
import com.duroty.hibernate.MailPreferences;
import com.duroty.hibernate.Message;
import com.duroty.hibernate.Users;

import com.duroty.jmx.mbean.ApplicationConstants;
import com.duroty.jmx.mbean.Constants;

import com.duroty.lucene.mail.LuceneMessage;
import com.duroty.lucene.mail.MimeMessageToLuceneMessage;
import com.duroty.lucene.mail.indexer.MailIndexer;
import com.duroty.lucene.mail.indexer.MailIndexerConstants;

import com.duroty.service.analyzer.BayesianAnalysis;
import com.duroty.service.analyzer.LuceneFiltersAnalysis;

import com.duroty.utils.GeneralOperations;
import com.duroty.utils.log.DLog;
import com.duroty.utils.mail.MailPart;
import com.duroty.utils.mail.MessageUtilities;
import com.duroty.utils.mail.RFC2822Headers;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.mail.HtmlEmail;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import org.hibernate.criterion.Restrictions;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;

import java.nio.charset.Charset;

import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.mail.Address;
import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;

import javax.naming.Context;
import javax.naming.InitialContext;

/**
 * @author durot
 *
 */
public class Mailet implements Runnable, MailIndexerConstants {
    /**
     * DOCUMENT ME!
     */
    private Servible servible;

    /**
    * DOCUMENT ME!
    */
    private Context ctx = null;

    /**
     * DOCUMENT ME!
     */
    private String hibernateSessionFactory;

    /**
     * DOCUMENT ME!
     */
    private String smtpSessionFactory;

    /**
     * DOCUMENT ME!
     */
    private Analyzer analyzer = null;

    /**
     * DOCUMENT ME!
     */
    private MimeMessage mime = null;

    /**
     * DOCUMENT ME!
     */
    private String messageName = null;

    /**
     * DOCUMENT ME!
     */
    private String repositoryName = null;

    /**
     * DOCUMENT ME!
     */
    private int indexLimit = -1;

    /**
     * DOCUMENT ME!
     */
    private String defaultLucenePath = null;

    /**
     * Creates a new Mailet object.
     *
     * @param servible DOCUMENT ME!
     * @param messageName DOCUMENT ME!
     * @param repositoryName DOCUMENT ME!
     * @param mime DOCUMENT ME!
     */
    public Mailet(Servible servible, String messageName, String repositoryName, MimeMessage mime) {
        super();
        this.servible = servible;
        this.messageName = messageName;
        this.repositoryName = repositoryName;
        this.mime = mime;

        Map options = ApplicationConstants.options;

        try {
            ctx = new InitialContext();

            HashMap mail = (HashMap) ctx.lookup((String) options.get(Constants.MAIL_CONFIG));

            this.hibernateSessionFactory = (String) mail.get(Constants.HIBERNATE_SESSION_FACTORY);
            this.smtpSessionFactory = (String) mail.get(Constants.DUROTY_MAIL_FACTOTY);
            this.defaultLucenePath = (String) mail.get(Constants.MAIL_LUCENE_PATH);

            parseIndexLimit((String) mail.get(Constants.MAIL_ATTACHMENT_SIZE));

            String clazzAnalyzerName = (String) mail.get(Constants.MAIL_LUCENE_ANALYZER);

            if ((clazzAnalyzerName != null) && !clazzAnalyzerName.trim().equals("")) {
                Class clazz = null;
                clazz = Class.forName(clazzAnalyzerName.trim());
                this.analyzer = (Analyzer) clazz.newInstance();
            } else {
                this.analyzer = new StandardAnalyzer();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
        try {
            flush();
        } catch (Exception e2) {
            System.gc();
        } catch (OutOfMemoryError e2) {
            System.gc();
        } catch (Throwable e2) {
            if (mime != null) {
                sendError(mime, e2);
            }

            System.gc();
        } finally {
            if (servible != null) {
                servible.removePool(messageName + "--" + repositoryName);
            }
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @throws Throwable DOCUMENT ME!
     * @throws OutOfMemoryError DOCUMENT ME!
     */
    private void flush() throws Exception, Throwable, OutOfMemoryError {
        SessionFactory hfactory = null;
        Session hsession = null;

        try {
            hfactory = (SessionFactory) ctx.lookup(hibernateSessionFactory);
            hsession = hfactory.openSession();

            Users user = getUser(hsession, repositoryName);

            this.saveInReplyTo(messageName, mime);

            Message message = new Message();

            message.setMesBox(getBoxName(mime, user));

            mime.removeHeader("X-DBox");
            mime.saveChanges();

            StringBuffer bodyBuffer = new StringBuffer();
            Vector mailParts = new Vector();

            //Apply label/filter analysis to mimemessage
            LuceneMessage luceneMessage = prepareLuceneMessage(messageName, mime, bodyBuffer, mailParts);

            LuceneFiltersAnalysis luceneFiltersAnalysis = new LuceneFiltersAnalysis(luceneMessage, message);
            luceneFiltersAnalysis.init(null);
            luceneFiltersAnalysis.service(repositoryName, messageName, mime);

            message.setMesReferences(getParentId(messageName, mime));
            message.setUsers(user);
            message.setMesName(messageName);

            String from = "unknown from";

            try {
                from = MessageUtilities.decodeAddresses(mime.getFrom());
            } catch (Exception e) {
            }

            message.setMesFrom(from);

            String to = "unknown to";

            try {
                to = MessageUtilities.decodeAddresses(mime, javax.mail.Message.RecipientType.TO);
            } catch (Exception e) {
            }

            message.setMesTo(to);

            String cc = "unknown cc";

            try {
                cc = MessageUtilities.decodeAddresses(mime, javax.mail.Message.RecipientType.CC);
            } catch (Exception e) {
            }

            message.setMesCc(cc);

            String replyTo = "unknown replyTo";

            try {
                replyTo = MessageUtilities.decodeAddresses(mime.getReplyTo());
            } catch (Exception e) {
                replyTo = from;
            }

            message.setMesReplyTo(replyTo);

            try {
                message.setMesSubject(mime.getSubject());
            } catch (Exception e2) {
                message.setMesSubject("unknown subject");
            }

            message.setMesBody(bodyBuffer.toString());

            if (mime.getSentDate() == null) {
                if (mime.getReceivedDate() == null) {
                    message.setMesDate(new Date());
                } else {
                    message.setMesDate(mime.getReceivedDate());
                }
            } else {
                message.setMesDate(mime.getSentDate());
            }

            if ((message.getMesBox() != null) && message.getMesBox().equals("SENT")) {
                message.setMesRecent(new Boolean(false));
            } else {
                if (isRecent(mime)) {
                    message.setMesRecent(new Boolean(true));
                } else {
                    message.setMesRecent(new Boolean(false));
                }
            }

            int size = mime.getSize();
            Enumeration e = mime.getAllHeaders();

            while (e.hasMoreElements()) {
                size += ((Header) e.nextElement()).toString().length();
            }

            message.setMesSize(new Integer(size));

            try {
                InternetHeaders xheaders = MessageUtilities.getHeadersWithFrom(mime);
                Enumeration xenum = xheaders.getAllHeaderLines();
                StringBuffer buff = new StringBuffer();

                while (xenum.hasMoreElements()) {
                    buff.append(xenum.nextElement());
                    buff.append('\n');
                }

                message.setMesHeaders(buff.toString());
            } catch (Exception e2) {
                message.setMesHeaders("");
            }

            if ((mailParts != null) && (mailParts.size() > 0)) {
                for (int j = 0; j < mailParts.size(); j++) {
                    MailPart part = (MailPart) mailParts.get(j);
                    Attachment attachment = new Attachment();
                    attachment.setAttContentType(part.getContentType());
                    attachment.setAttName(part.getName());
                    attachment.setAttPart(part.getId());
                    attachment.setAttSize(part.getSize());
                    attachment.setMessage(message);

                    message.addAttachment(attachment);
                }
            }

            if (!message.getMesBox().equals("SPAM")) {
                parseContacts(hsession, user, mime, message.getMesBox());
            }

            //Inserto el dmail message i els attachments corresponents
            hsession.save(message);
            hsession.flush();

            indexerLucene(messageName, luceneMessage, mime);

            try {
                Iterator it = user.getMailPreferenceses().iterator();
                MailPreferences mailPreferences = (MailPreferences) it.next();

                if (mailPreferences.isMaprVacationActive()) {
                    sendVacationMessage(repositoryName, from);
                }
            } catch (Exception ex) {
            }
        } finally {
            GeneralOperations.closeHibernateSession(hsession);
        }
    }

    /**
     * Utility method that parses an amount string.
     * You can use 'k' and 'm' as optional postfixes to the amount (both upper and lowercase).
     * In other words, "1m" is the same as writing "1024k", which is the same as
     * "1048576".
     *
     * @param amount the amount string to parse
     */
    private void parseIndexLimit(String limit) {
        try {
            limit = limit.toLowerCase();

            if (limit.endsWith("k")) {
                limit = limit.substring(0, limit.length() - 1);
                this.indexLimit = Integer.parseInt(limit) * 1024;
            } else if (limit.endsWith("m")) {
                limit = limit.substring(0, limit.length() - 1);
                this.indexLimit = Integer.parseInt(limit) * 1024 * 1024;
            } else {
                this.indexLimit = Integer.parseInt(limit);
            }
        } catch (Exception e) {
            this.indexLimit = -1;
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param id DOCUMENT ME!
     * @param message DOCUMENT ME!
     */
    private void saveInReplyTo(String id, MimeMessage message) {
        try {
            String[] inReplyTos = message.getHeader(RFC2822Headers.IN_REPLY_TO);

            String messageId = message.getMessageID();

            if ((inReplyTos == null) || (inReplyTos.length <= 0)) {
                if (messageId != null) {
                    message.addHeader(RFC2822Headers.IN_REPLY_TO, messageId);
                    message.saveChanges();
                }
            }

            String[] references = message.getHeader(RFC2822Headers.REFERENCES);

            if ((references == null) || (references.length <= 0)) {
                message.addHeader(RFC2822Headers.REFERENCES, messageId);
                message.saveChanges();
            }
        } catch (Exception e) {
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param mime DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    private String getBoxName(MimeMessage mime, Users user) {
        String _box = null;

        try {
            if (_box == null) {
                String[] aux = mime.getHeader(BayesianAnalysis.messageIsSpam);

                if ((aux != null) && (aux.length > 0)) {
                    if (controlSpam(user, mime)) {
                        _box = "SPAM";
                    }
                } else {
                    aux = mime.getHeader("X-DBox");

                    if ((aux != null) && (aux.length > 0)) {
                        _box = aux[0];
                    }
                }
            }
        } catch (Exception e) {
            _box = "INBOX";
        }

        if (_box == null) {
            _box = "INBOX";
        }

        return _box;
    }

    /**
     * DOCUMENT ME!
     *
     * @param id DOCUMENT ME!
     * @param message DOCUMENT ME!
     * @param bodyBuffer DOCUMENT ME!
     * @param attachments DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws Exception DOCUMENT ME!
     */
    private LuceneMessage prepareLuceneMessage(String id, MimeMessage message, StringBuffer bodyBuffer,
            Vector attachments) throws Exception {
        MimeMessageToLuceneMessage mmlm = MimeMessageToLuceneMessage.getInstance();

        LuceneMessage lmsg = mmlm.parse(id, message, bodyBuffer, attachments, indexLimit);

        return lmsg;
    }

    /**
     * DOCUMENT ME!
     *
     * @param hsession DOCUMENT ME!
     * @param username DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     *
     * @throws Exception DOCUMENT ME!
     */
    protected Users getUser(org.hibernate.Session hsession, String username) throws Exception {
        try {
            Criteria criteria = hsession.createCriteria(Users.class);
            criteria.add(Restrictions.eq("useUsername", username));
            criteria.add(Restrictions.eq("useActive", new Boolean(true)));

            return (Users) criteria.uniqueResult();
        } finally {
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param id DOCUMENT ME!
     * @param mime DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    private String getParentId(String id, MimeMessage mime) {
        String references = null;

        try {
            if (references == null) {
                String[] aux = mime.getHeader(RFC2822Headers.REFERENCES);

                //Cal controlar que portem un array
                if ((aux != null) && (aux.length > 0)) {
                    if (aux[0] != null) {
                        String[] ref = aux[0].split("\\s+");

                        if ((ref != null) && (ref.length > 1)) {
                            references = ref[0];
                        }
                    }

                    if (references == null) {
                        references = aux[0];
                    }
                }
            }

            if (references == null) {
                String[] aux = mime.getHeader(RFC2822Headers.IN_REPLY_TO);

                //Cal veure que portem un array
                if ((aux != null) && (aux.length > 0)) {
                    references = aux[0];
                }
            }

            if (references == null) {
                references = mime.getMessageID();

                mime.addHeader(RFC2822Headers.IN_REPLY_TO, references);
                mime.addHeader(RFC2822Headers.REFERENCES, references);
            }
        } catch (MessagingException e) {
            references = null;
        }

        return references;
    }

    /**
     * DOCUMENT ME!
     *
     * @param mime DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    private boolean isRecent(MimeMessage mime) {
        boolean control = true;

        try {
            String[] aux = mime.getHeader("X-DRecent");

            if ((aux != null) && (aux.length > 0)) {
                for (int i = 0; i < aux.length; i++) {
                    control = Boolean.parseBoolean(aux[i].trim());

                    break;
                }
            }
        } catch (Exception e) {
            control = true;
        }

        return control;
    }

    /**
     * DOCUMENT ME!
     *
     * @param hfactory DOCUMENT ME!
     * @param username DOCUMENT ME!
     * @param mime DOCUMENT ME!
     */
    private void parseContacts(Session hsession, Users user, MimeMessage mime, String box) {
        try {
            Address[] addresses = null;

            Date sentDate = null;
            Date receivedDate = null;

            if (box.equals("SENT")) {
                addresses = mime.getAllRecipients();
                sentDate = mime.getSentDate();

                if (sentDate == null) {
                    sentDate = new Date();
                }
            } else {
                addresses = mime.getFrom();
                receivedDate = mime.getReceivedDate();

                if (receivedDate == null) {
                    receivedDate = new Date();
                }
            }

            if ((addresses != null) && (addresses.length > 0)) {
                String name = null;
                String email = null;

                for (int i = 0; i < addresses.length; i++) {
                    if (addresses[i] instanceof InternetAddress) {
                        InternetAddress xinet = (InternetAddress) addresses[i];

                        name = xinet.getPersonal();

                        if ((name != null) && (name.length() > 49)) {
                            name = name.substring(0, 49);
                        }

                        email = xinet.getAddress();
                    } else {
                        email = addresses[i].toString();
                    }

                    Criteria crit1 = hsession.createCriteria(Contact.class);
                    crit1.add(Restrictions.eq("users", user));
                    crit1.add(Restrictions.eq("conEmail", email));

                    Contact contact = (Contact) crit1.uniqueResult();

                    if (contact != null) {
                        if (receivedDate != null) {
                            contact.setConReceivedDate(receivedDate);
                        }

                        if (sentDate != null) {
                            contact.setConSentDate(sentDate);
                        }

                        int freq = contact.getConCount();

                        contact.setConCount(freq + 1);

                        if (!StringUtils.isBlank(name)) {
                            name = name.replaceAll(",", " ");
                            name = name.replaceAll(";", " ");
                            contact.setConName(name);
                        }

                        hsession.update(contact);
                    } else {
                        contact = new Contact();
                        contact.setConEmail(email);
                        contact.setConName(name);
                        contact.setConReceivedDate(receivedDate);
                        contact.setConSentDate(sentDate);
                        contact.setConCount(new Integer(1));
                        contact.setUsers(user);

                        hsession.save(contact);
                    }

                    hsession.flush();

                    try {
                        if ((contact.getConSentDate() != null) && (contact.getConReceivedDate() != null)) {
                            Criteria crit2 = hsession.createCriteria(Identity.class);
                            crit2.add(Restrictions.eq("ideEmail", email));
                            crit2.add(Restrictions.eq("ideActive", new Boolean(true)));

                            List list = crit2.list();

                            if (list != null) {
                                Iterator scroll = list.iterator();

                                while (scroll.hasNext()) {
                                    Identity identity = (Identity) scroll.next();
                                    Users buddy = identity.getUsers();

                                    if ((buddy != null) && (user.getUseIdint() != buddy.getUseIdint())) {
                                        Criteria auxCrit = hsession.createCriteria(BuddyList.class);
                                        auxCrit.add(Restrictions.eq("usersByBuliOwnerIdint", user));
                                        auxCrit.add(Restrictions.eq("usersByBuliBuddyIdint", buddy));

                                        BuddyList buddyList = (BuddyList) auxCrit.uniqueResult();

                                        if (buddyList != null) {
                                            buddyList.setBuliActive(true);
                                            buddyList.setBuliLastDate(new Date());
                                            hsession.update(buddyList);
                                        } else {
                                            buddyList = new BuddyList();
                                            buddyList.setBuliActive(true);
                                            buddyList.setBuliLastDate(new Date());
                                            buddyList.setUsersByBuliBuddyIdint(buddy);
                                            buddyList.setUsersByBuliOwnerIdint(user);
                                            hsession.save(buddyList);
                                        }
                                    }
                                }
                            }

                            hsession.flush();
                        }
                    } catch (Exception e) {
                    }
                }
            }
        } catch (Exception e) {
        } finally {
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param id DOCUMENT ME!
     * @param luceneMessage DOCUMENT ME!
     * @param message DOCUMENT ME!
     *
     * @throws Exception DOCUMENT ME!
     */
    private void indexerLucene(String id, LuceneMessage luceneMessage, MimeMessage message) throws Exception {
        MailIndexer indexer = new MailIndexer();

        String userLucenePathMessages = null;

        if (!defaultLucenePath.endsWith(File.separator)) {
            userLucenePathMessages = defaultLucenePath + File.separator + repositoryName + File.separator
                    + MESSAGES;
        } else {
            userLucenePathMessages = defaultLucenePath + repositoryName + File.separator + MESSAGES;
        }

        indexer.insertDocument(userLucenePathMessages, id, luceneMessage.getDocPrincipal(), analyzer);
    }

    /**
     * DOCUMENT ME!
     *
     * @param message DOCUMENT ME!
     * @param exception DOCUMENT ME!
     */
    private void sendError(MimeMessage message, Throwable exception) {
        if (true) {
            return;
        }

        StringWriter sw = null;
        PrintWriter writer = null;
        javax.mail.Session msession = null;

        try {
            msession = (javax.mail.Session) ctx.lookup(smtpSessionFactory);

            InternetAddress sender = new InternetAddress("postmaster@duroty.com", "Postmaster");
            InternetAddress errorTo = new InternetAddress(message.getFrom()[0].toString());

            sw = new StringWriter();
            writer = new PrintWriter(sw);

            if (exception != null) {
                exception.printStackTrace(writer);
            }

            //Create the message to forward
            MimeMessage forward = MessageUtilities.createNewMessage(sender, new Address[] { errorTo }, "[ERROR: ",
                    " ]", sw.toString(), message, msession);

            //MimeMessage newMessage = MessageUtilities.createForward(sender, forwardTo, message, this.mailSession);
            Thread thread = new Thread(new SendMessageThread(forward));
            thread.start();

            System.gc();
        } catch (Exception e) {
            DLog.log(DLog.ERROR, this.getClass(), "Impossible sent error: " + e.getMessage());
        } catch (java.lang.OutOfMemoryError ex) {
            System.gc();
            DLog.log(DLog.ERROR, this.getClass(), "Impossible sent error: " + ex.getMessage());
        } catch (Throwable e) {
            DLog.log(DLog.ERROR, this.getClass(), "Impossible sent error: " + e.getMessage());
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param username DOCUMENT ME!
     * @param to DOCUMENT ME!
     */
    private void sendVacationMessage(String username, String to) {
        SessionFactory hfactory = null;
        Session hsession = null;
        javax.mail.Session msession = null;

        try {
            hfactory = (SessionFactory) ctx.lookup(hibernateSessionFactory);
            hsession = hfactory.openSession();
            msession = (javax.mail.Session) ctx.lookup(smtpSessionFactory);

            Users user = getUser(hsession, username);

            Criteria crit = hsession.createCriteria(Identity.class);
            crit.add(Restrictions.eq("users", getUser(hsession, username)));
            crit.add(Restrictions.eq("ideActive", new Boolean(true)));
            crit.add(Restrictions.eq("ideDefault", new Boolean(true)));

            Identity identity = (Identity) crit.uniqueResult();

            if (identity != null) {
                InternetAddress _from = new InternetAddress(identity.getIdeEmail(), identity.getIdeName());
                InternetAddress _to = InternetAddress.parse(to)[0];

                if (_from.getAddress().equals(_to.getAddress())) {
                    return;
                }

                HtmlEmail email = new HtmlEmail();
                email.setMailSession(msession);

                email.setFrom(_from.getAddress(), _from.getPersonal());
                email.addTo(_to.getAddress(), _to.getPersonal());

                Iterator it = user.getMailPreferenceses().iterator();
                MailPreferences mailPreferences = (MailPreferences) it.next();

                email.setSubject(mailPreferences.getMaprVacationSubject());
                email.setHtmlMsg("<p>" + mailPreferences.getMaprVacationBody() + "</p><p>"
                        + mailPreferences.getMaprSignature() + "</p>");

                email.setCharset(Charset.defaultCharset().displayName());

                email.send();
            }
        } catch (Exception e) {
        } finally {
        }
    }

    /**
     * DOCUMENT ME!
     *
     * @param user DOCUMENT ME!
     * @param mime DOCUMENT ME!
     *
     * @return DOCUMENT ME!
     */
    private boolean controlSpam(Users user, MimeMessage mime) {
        try {
            Iterator it = user.getMailPreferenceses().iterator();

            MailPreferences mailPreferences = (MailPreferences) it.next();

            if (mailPreferences.getMaprSpamTolerance() == -1) {
                return false;
            } else {
                return true;
            }
        } catch (Exception ex) {
            return false;
        }
    }
}