Package ch.entwine.weblounge.bridge.mail

Source Code of ch.entwine.weblounge.bridge.mail.MailAggregator

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.bridge.mail;

import ch.entwine.weblounge.common.content.ResourceURI;
import ch.entwine.weblounge.common.content.page.Page;
import ch.entwine.weblounge.common.content.page.PageTemplate;
import ch.entwine.weblounge.common.impl.content.page.PageImpl;
import ch.entwine.weblounge.common.impl.content.page.PageURIImpl;
import ch.entwine.weblounge.common.impl.content.page.PageletImpl;
import ch.entwine.weblounge.common.impl.security.UserImpl;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.repository.WritableContentRepository;
import ch.entwine.weblounge.common.scheduler.JobException;
import ch.entwine.weblounge.common.scheduler.JobWorker;
import ch.entwine.weblounge.common.site.Site;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Dictionary;
import java.util.Properties;
import java.util.UUID;

import javax.mail.Address;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;

/**
* Content aggregator based on the <code>POP3</code> protocol.
*/
public class MailAggregator implements JobWorker {

  /** Logging facility */
  private static final Logger logger = LoggerFactory.getLogger(MailAggregator.class);

  /** Name of the inbox */
  public static final String INBOX = "INBOX";

  /** Configuration key for the e-mail provider */
  public static final String OPT_PROVIDER = "provider";

  /** Default mail provider */
  public static final String DEFAULT_PROVIDER = "pop3";

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.scheduler.JobWorker#execute(java.lang.String,
   *      java.util.Dictionary)
   */
  public void execute(String name, Dictionary<String, Serializable> ctx)
      throws JobException {

    Site site = (Site) ctx.get(Site.class.getName());

    // Make sure the site is ready to accept content
    if (site.getContentRepository().isReadOnly()) {
      logger.warn("Unable to publish e-mail messages to site '{}': repository is read only", site);
      return;
    }

    WritableContentRepository repository = (WritableContentRepository)site.getContentRepository();

    // Extract the configuration from the job properties
    String provider = (String) ctx.get(OPT_PROVIDER);
    Account account = null;
    try {
      if (StringUtils.isBlank(provider)) {
        provider = DEFAULT_PROVIDER;
      }
      account = new Account(ctx);
    } catch (IllegalArgumentException e) {
      throw new JobException(this, e);
    }

    // Connect to the server
    Properties sessionProperties = new Properties();
    Session session = Session.getDefaultInstance(sessionProperties, null);
    Store store = null;
    Folder inbox = null;

    try {

      // Connect to the server
      try {
        store = session.getStore(provider);
        store.connect(account.getHost(), account.getLogin(), account.getPassword());
      } catch (NoSuchProviderException e) {
        throw new JobException(this, "Unable to connect using unknown e-mail provider '" + provider + "'", e);
      } catch (MessagingException e) {
        throw new JobException(this, "Error connecting to " + provider + " account " + account, e);
      }

      // Open the account's inbox
      try {
        inbox = store.getFolder(INBOX);
        if (inbox == null)
          throw new JobException(this, "No inbox found at " + account);
        inbox.open(Folder.READ_WRITE);
      } catch (MessagingException e) {
        throw new JobException(this, "Error connecting to inbox at " + account, e);
      }

      // Get the messages from the server
      try {
        for (Message message : inbox.getMessages()) {
          if (!message.isSet(Flag.SEEN)) {
            try {
              Page page = aggregate(message, site);
              message.setFlag(Flag.DELETED, true);
              repository.put(page, true);
              logger.info("E-Mail message published at {}", page.getURI());
            } catch (Exception e) {
              logger.info("E-Mail message discarded: {}", e.getMessage());
              message.setFlag(Flag.SEEN, true);
              // TODO: Reply to sender if the "from" field exists
            }
          }
        }
      } catch (MessagingException e) {
        throw new JobException(this, "Error loading e-mail messages from inbox", e);
      }

      // Close the connection
      // but don't remove the messages from the server
    } finally {
      if (inbox != null) {
        try {
          inbox.close(true);
        } catch (MessagingException e) {
          throw new JobException(this, "Error closing inbox", e);
        }
      }
      if (store != null) {
        try {
          store.close();
        } catch (MessagingException e) {
          throw new JobException(this, "Error closing connection to e-mail server", e);
        }
      }
    }

  }

  /**
   * Aggregates the e-mail message by reading it and turning it either into a
   * page or a file upload.
   *
   * @param message
   *          the e-mail message
   * @param site
   *          the site to publish to
   * @throws MessagingException
   *           if fetching the message data fails
   * @throws IOException
   *           if writing the contents to the output stream fails
   */
  protected Page aggregate(Message message, Site site) throws IOException,
  MessagingException, IllegalArgumentException {

    ResourceURI uri = new PageURIImpl(site, UUID.randomUUID().toString());
    Page page = new PageImpl(uri);
    Language language = site.getDefaultLanguage();

    // Extract title and subject. Without these two, creating a page is not
    // feasible, therefore both messages throw an IllegalArgumentException if
    // the fields are not present.
    String title = getSubject(message);
    String author = getAuthor(message);

    // Collect default settings
    PageTemplate template = site.getDefaultTemplate();
    if (template == null)
      throw new IllegalStateException("Missing default template in site '" + site + "'");
    String stage = template.getStage();
    if (StringUtils.isBlank(stage))
      throw new IllegalStateException("Missing stage definition in template '" + template.getIdentifier() + "'");

    // Standard fields
    page.setTitle(title, language);
    page.setTemplate(template.getIdentifier());
    page.setPublished(new UserImpl(site.getAdministrator()), message.getReceivedDate(), null);

    // TODO: Translate e-mail "from" into site user and throw if no such
    // user can be found
    page.setCreated(site.getAdministrator(), message.getSentDate());

    // Start looking at the message body
    String contentType = message.getContentType();
    if (StringUtils.isBlank(contentType))
      throw new IllegalArgumentException("Message content type is unspecified");

    // Text body
    if (contentType.startsWith("text/plain")) {
      // TODO: Evaluate charset
      String body = null;
      if (message.getContent() instanceof String)
        body = (String)message.getContent();
      else if (message.getContent() instanceof InputStream)
        body = IOUtils.toString((InputStream)message.getContent());
      else
        throw new IllegalArgumentException("Message body is of unknown type");
      return handleTextPlain(body, page, language);
    }

    // HTML body
    if (contentType.startsWith("text/html")) {
      // TODO: Evaluate charset
      return handleTextHtml((String) message.getContent(), page, null);
    }

    // Multipart body
    else if ("mime/multipart".equalsIgnoreCase(contentType)) {
      Multipart mp = (Multipart) message.getContent();
      for (int i = 0, n = mp.getCount(); i < n; i++) {
        Part part = mp.getBodyPart(i);
        String disposition = part.getDisposition();
        if (disposition == null) {
          MimeBodyPart mbp = (MimeBodyPart) part;
          if (mbp.isMimeType("text/plain")) {
            return handleTextPlain((String) mbp.getContent(), page, null);
          } else {
            // TODO: Implement special non-attachment cases here of
            // image/gif, text/html, ...
            throw new UnsupportedOperationException("Multipart message bodies of type '" + mbp.getContentType() + "' are not yet supported");
          }
        } else if (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE)) {
          logger.info("Skipping message attachment " + part.getFileName());
          // saveFile(part.getFileName(), part.getInputStream());
        }
      }

      throw new IllegalArgumentException("Multipart message did not contain any recognizable content");
    }

    // ?
    else {
      throw new IllegalArgumentException("Message body is of unknown type '" + contentType + "'");
    }
  }

  /**
   * Handles the creation of a page based on an e-mail body of type
   * <code>text/plain</code>.
   *
   * @param content
   *          the message body
   * @param page
   *          the page
   * @param language
   *          the content language
   * @return the page
   */
  private Page handleTextPlain(String content, Page page, Language language) {
    for (String paragraph : content.split("\r\n")) {
      if (StringUtils.isBlank(paragraph))
        continue;
      PageletImpl p = new PageletImpl("text", "paragraph");
      p.setContent("text", StringUtils.trim(paragraph), language);
      page.addPagelet(p, page.getStage().getIdentifier());
    }
    return page;
  }

  /**
   * Handles the creation of a page based on an e-mail body of type
   * <code>text/html</code>.
   *
   * @param content
   *          the message body
   * @param page
   *          the page
   * @param language
   *          the content language
   * @return the page
   */
  private Page handleTextHtml(String content, Page page, Language language) {
    // TODO: Implement HTML message handling
    throw new UnsupportedOperationException("Message bodies of type 'text/html' are not yet supported");
  }

  /**
   * Returns the author of this message. If the message does not have a
   * <code>from</code> field, an {@link IllegalArgumentException} is thrown.
   *
   * @param message
   *          the e-mail message
   * @return the sender
   * @throws MessagingException
   *           if reading the message's author fails
   * @throws IllegalArgumentException
   *           if no author can be found
   */
  private String getAuthor(Message message) throws MessagingException,
  IllegalArgumentException {
    Address[] address = message.getFrom();
    if (address == null || address.length == 0)
      throw new MessagingException("Message has no author");
    return address[0].toString();
  }

  /**
   * Returns the subject of this message. If the message does not have a
   * <code>subject</code> field, an {@link IllegalArgumentException} is thrown.
   *
   * @param message
   *          the e-mail message
   * @return the subject
   * @throws MessagingException
   *           if reading the message's subject fails
   * @throws IllegalArgumentException
   *           if no subject can be found
   */
  private String getSubject(Message message) throws MessagingException,
  IllegalArgumentException {
    String subject = message.getSubject();
    if (StringUtils.isBlank(subject))
      throw new MessagingException("Message has no subject");
    return subject;
  }

}
TOP

Related Classes of ch.entwine.weblounge.bridge.mail.MailAggregator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.