Package com.nilhcem.fakesmtp.server

Source Code of com.nilhcem.fakesmtp.server.MailSaver

package com.nilhcem.fakesmtp.server;

import com.nilhcem.fakesmtp.core.ArgsHandler;
import com.nilhcem.fakesmtp.core.Configuration;
import com.nilhcem.fakesmtp.core.I18n;
import com.nilhcem.fakesmtp.model.EmailModel;
import com.nilhcem.fakesmtp.model.UIModel;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Saves emails and notifies components so they can refresh their views with new data.
*
* @author Nilhcem
* @since 1.0
*/
public final class MailSaver extends Observable {

  private static final Logger LOGGER = LoggerFactory.getLogger(MailSaver.class);
  private static final String LINE_SEPARATOR = System.getProperty("line.separator");
  // This can be a static variable since it is Thread Safe
  private static final Pattern SUBJECT_PATTERN = Pattern.compile("^Subject: (.*)$");

  private final SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyyhhmmssSSS");

  /**
   * Saves incoming email in file system and notifies observers.
   *
   * @param from the user who send the email.
   * @param to the recipient of the email.
   * @param data an InputStream object containing the email.
   * @see com.nilhcem.fakesmtp.gui.MainPanel#addObservers to see which observers will be notified
   */
  public void saveEmailAndNotify(String from, String to, InputStream data) {
    List<String> relayDomains = UIModel.INSTANCE.getRelayDomains();

    if (relayDomains != null) {
      boolean matches = false;
      for (String domain : relayDomains) {
        if (to.endsWith(domain)) {
          matches = true;
          break;
        }
      }

      if (!matches) {
        LOGGER.debug("Destination {} doesn't match relay domains", to);
        return;
      }
    }

    // We move everything that we can move outside the synchronized block to limit the impact
    EmailModel model = new EmailModel();
    model.setFrom(from);
    model.setTo(to);
    String mailContent = convertStreamToString(data);
    model.setSubject(getSubjectFromStr(mailContent));
    model.setEmailStr(mailContent);

    synchronized (getLock()) {
      String filePath = saveEmailToFile(mailContent);

      model.setReceivedDate(new Date());
      model.setFilePath(filePath);

      setChanged();
      notifyObservers(model);
    }
  }

  /**
   * Deletes all received emails from file system.
   */
  public void deleteEmails() {
    Map<Integer, String> mails = UIModel.INSTANCE.getListMailsMap();
    if (ArgsHandler.INSTANCE.memoryModeEnabled()) {
      return;
    }
    for (String value : mails.values()) {
      File file = new File(value);
      if (file.exists()) {
        try {
          if (!file.delete()) {
            LOGGER.error("Impossible to delete file {}", value);
          }
        } catch (SecurityException e) {
          LOGGER.error("", e);
        }
      }
    }
  }

  /**
   * Returns a lock object.
   * <p>
   * This lock will be used to make the application thread-safe, and
   * avoid receiving and deleting emails in the same time.
   * </p>
   *
   * @return a lock object <i>(which is actually the current instance of the {@code MailSaver} object)</i>.
   */
  public Object getLock() {
    return this;
  }

  /**
   * Converts an {@code InputStream} into a {@code String} object.
   * <p>
   * The method will not copy the first 4 lines of the input stream.<br>
   * These 4 lines are SubEtha SMTP additional information.
   * </p>
   *
   * @param is the InputStream to be converted.
   * @return the converted string object, containing data from the InputStream passed in parameters.
   */
  private String convertStreamToString(InputStream is) {
    final long lineNbToStartCopy = 4; // Do not copy the first 4 lines (received part)
    BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName(I18n.UTF8)));
    StringBuilder sb = new StringBuilder();

    String line;
    long lineNb = 0;
    try {
      while ((line = reader.readLine()) != null) {
        if (++lineNb > lineNbToStartCopy) {
          sb.append(line).append(LINE_SEPARATOR);
        }
      }
    } catch (IOException e) {
      LOGGER.error("", e);
    }
    return sb.toString();
  }

  /**
   * Saves the content of the email passed in parameters in a file.
   *
   * @param mailContent the content of the email to be saved.
   * @return the path of the created file.
   */
  private String saveEmailToFile(String mailContent) {
    if (ArgsHandler.INSTANCE.memoryModeEnabled()) {
      return null;
    }
    String filePath = String.format("%s%s%s", UIModel.INSTANCE.getSavePath(), File.separator,
        dateFormat.format(new Date()));

    // Create file
    int i = 0;
    File file = null;
    while (file == null || file.exists()) {
      String iStr;
      if (i++ > 0) {
        iStr = Integer.toString(i);
      } else {
        iStr = "";
      }
      file = new File(filePath + iStr + Configuration.INSTANCE.get("emails.suffix"));
    }

    // Copy String to file
    try {
      FileUtils.writeStringToFile(file, mailContent);
    } catch (IOException e) {
      // If we can't save file, we display the error in the SMTP logs
      Logger smtpLogger = LoggerFactory.getLogger(org.subethamail.smtp.server.Session.class);
      smtpLogger.error("Error: Can't save email: {}", e.getMessage());
    }
    return file.getAbsolutePath();
  }

  /**
   * Gets the subject from the email data passed in parameters.
   *
   * @param data a string representing the email content.
   * @return the subject of the email, or an empty subject if not found.
   */
  private String getSubjectFromStr(String data) {
    try {
      BufferedReader reader = new BufferedReader(new StringReader(data));

      String line;
      while ((line = reader.readLine()) != null) {
         Matcher matcher = SUBJECT_PATTERN.matcher(line);
         if (matcher.matches()) {
           return matcher.group(1);
         }
      }
    } catch (IOException e) {
      LOGGER.error("", e);
    }
    return "";
  }
}
TOP

Related Classes of com.nilhcem.fakesmtp.server.MailSaver

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.