de.xirp.mail.MailManager.java Source code

Java tutorial

Introduction

Here is the source code for de.xirp.mail.MailManager.java

Source

/** 
 * ============================================================================
 * Xirp 2: eXtendable interface for robotic purposes.
 * ============================================================================
 * 
 * Copyright (C) 2005-2007, by Authors and Contributors listed in CREDITS.txt
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at:
 *
 *             http://www.opensource.org/licenses/cpl1.0.php
 *
 * ----------------------------
 * MailManager.java
 * ----------------------------
 *
 * Original Author:  Matthias Gernand [matthias.gernand AT gmx.de]
 * Contributor(s):   
 *
 * Changes
 * -------
 * 20.01.2007:      Created by Matthias Gernand.
 */
package de.xirp.mail;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import javax.mail.MessagingException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.log4j.Logger;

import de.xirp.managers.AbstractManager;
import de.xirp.managers.DeleteManager;
import de.xirp.managers.ManagerException;
import de.xirp.managers.PrintManager;
import de.xirp.settings.PropertiesManager;
import de.xirp.util.Constants;
import de.xirp.util.I18n;
import de.xirp.util.Util;
import de.xirp.util.serialization.ObjectDeSerializer;
import de.xirp.util.serialization.ObjectSerializer;
import de.xirp.util.serialization.SerializationException;

/**
 * This manager provides several methods for saving, transporting and
 * editing mails generated by the application. The manager also
 * provides methods for the contact management. <br>
 * <br>
 * The manger used the Apache Commons mail API, which is wrapped
 * around Suns JavaMail Framework. <br>
 * <br>
 * <b>Note:</b> SSL is currently not supported.
 * 
 * @author Matthias Gernand
 * @see de.xirp.mail.MailDescriptor
 * @see de.xirp.mail.Contact
 * @see de.xirp.mail.Mail
 */
public final class MailManager extends AbstractManager {

    /**
     * The logger for this class.
     */
    private static final Logger logClass = Logger.getLogger(MailManager.class);
    /**
     * A hash map containing the mail descriptors.
     */
    private static HashMap<String, MailDescriptor> mailDescriptors = new HashMap<String, MailDescriptor>();
    /**
     * A list of contacts.
     */
    private static ArrayList<Contact> contacts;
    /**
     * A random number generator object.
     */
    private static Random rnd;

    /**
     * Constructs a new instance of this manager. <br>
     * <br>
     * The manager is initialized on startup. Never call this on your
     * own. Use the statically provided methods.
     * 
     * @throws InstantiationException
     *             if an instance already exists.
     */
    public MailManager() throws InstantiationException {
        super();
    }

    /**
     * Adds the given {@link de.xirp.mail.Contact} to the
     * list of contacts. The list is sorted after the contact was
     * added.
     * 
     * @param contact
     *            The contact to add.
     * @return <code>true</code> if adding was successful.<br>
     *         <code>false</code> if adding was not successful.
     * @see de.xirp.mail.Contact
     */
    public static boolean addContact(Contact contact) {
        boolean b = contacts.add(contact);
        Collections.sort(contacts);
        return b;
    }

    /**
     * Returns the list of contacts.
     * 
     * @return The list of contacts.
     * @see de.xirp.mail.Contact
     */
    public static List<Contact> getContacts() {
        if (contacts == null) {
            return Collections.emptyList();
        } else {
            return Collections.unmodifiableList(contacts);
        }
    }

    /**
     * Returns a single {@link de.xirp.mail.Contact} for
     * the given index in the list of contacts.
     * 
     * @param idx
     *            The index.
     * @return The desired contact or null if the index is out of
     *         bounds.
     * @see de.xirp.mail.Contact
     */
    public static Contact getContact(int idx) {
        Contact c = null;
        try {
            c = contacts.get(idx);
        } catch (IndexOutOfBoundsException e) {
            logClass.debug("Debug: " + e.getMessage() + Constants.LINE_SEPARATOR, e); //$NON-NLS-1$
        }
        return c;
    }

    /**
     * Sends the given {@link de.xirp.mail.Mail}.
     * 
     * @param mail
     *            The <code>Mail</code> to send.
     * @throws MessagingException
     *             if something went wrong while sending.
     * @throws EmailException
     *             if something is wrong with the given mail.
     * @see de.xirp.mail.Mail
     */
    public static void sendMail(Mail mail) throws MessagingException, EmailException {
        try {
            checkMail(mail);
            mail.setSendDate(new Date());
            int folderKey = calcFolderKey();
            try {
                transport(mail);
                mail.setSent(true);
            } catch (EmailException e) {
                mail.setSent(false);
                throw e;
            } finally {
                saveMail(mail, folderKey);
                MailDescriptor md = mail.getMailDescriptor();
                md.setFolderKey(folderKey);
                mailDescriptors.put(mail.getMailDescriptorKey(), md);
            }
        } catch (MessagingException e) {
            throw e;
        }
    }

    /**
     * Transports the given {@link de.xirp.mail.Mail} via
     * a SMTP server.
     * 
     * @param mail
     *            The mail to transport.
     * @throws EmailException
     *             if something is wrong with the given mail or the
     *             mail settings.
     * @see de.xirp.mail.Mail
     * @see de.xirp.mail.Contact
     * @see de.xirp.mail.Attachment
     */
    private static void transport(Mail mail) throws EmailException {
        // Create the email message
        MultiPartEmail email = new MultiPartEmail();
        email.setHostName(PropertiesManager.getSmtpHost());
        email.setSmtpPort(PropertiesManager.getSmtpPort());

        if (PropertiesManager.isNeedsAuthentication()) {
            email.setAuthentication(PropertiesManager.getSmtpUser(),
                    Util.decrypt(PropertiesManager.getSmtpPassword()));
        }

        for (Contact c : mail.getTo()) {
            email.addTo(c.getMail(), c.getFirstName() + " " + c.getLastName()); //$NON-NLS-1$
        }
        for (Contact c : mail.getCc()) {
            email.addCc(c.getMail(), c.getFirstName() + " " + c.getLastName()); //$NON-NLS-1$
        }

        email.setFrom(PropertiesManager.getNoReplyAddress(), Constants.APP_NAME);
        email.setSubject(mail.getSubject());
        email.setMsg(mail.getText() + I18n.getString(I18n.getString("MailManager.mail.footer", //$NON-NLS-1$
                Constants.LINE_SEPARATOR, Constants.BASE_NAME_MAJOR_VERSION)));

        // Create attachment
        for (Attachment a : mail.getAttachments()) {
            File file = a.getFile();
            EmailAttachment attachment = new EmailAttachment();

            if (file != null) {
                attachment.setPath(file.getPath());
            } else {
                File tmpFile = null;
                try {
                    tmpFile = new File(Constants.TMP_DIR, a.getFileName());
                    FileUtils.writeByteArrayToFile(tmpFile, a.getAttachmentFileContent());
                    attachment.setPath(tmpFile.getPath());
                } catch (IOException e) {
                    tmpFile = null;
                }
            }
            attachment.setDisposition(EmailAttachment.ATTACHMENT);
            attachment.setDescription(a.getFileName());
            attachment.setName(a.getFileName());
            email.attach(attachment);
        }

        try {
            email.send();
        } catch (EmailException e) {
            logClass.error("Error: " + e.getMessage() + Constants.LINE_SEPARATOR, e); //$NON-NLS-1$
            throw e;
        }
    }

    /**
     * Calculates a random key for the sub folder. The mails are saved
     * to the hard disk in up to 16 folders.
     * 
     * @return An <code>int</code>: the folder key.
     */
    private static int calcFolderKey() {
        // 16 possible sub-folders
        final int BASE = 16;
        int result = rnd.nextInt(BASE);
        return result;
    }

    /**
     * Saved the given {@link de.xirp.mail.Mail} to the
     * hard disk. The mails are saved to the
     * <code>mail/data/&lt;key&gt;</code> folders.
     * 
     * @param mail
     *            The mail to save.
     * @param folderKey
     *            The folder number to save the mail into.
     * @see de.xirp.mail.Mail
     */
    private static void saveMail(Mail mail, int folderKey) {
        File writeToDirectory = new File(Constants.MAIL_DATA_DIR + File.separator + folderKey);
        if (!writeToDirectory.exists()) {
            writeToDirectory.mkdir();
        }

        try {
            File writeTo = new File(writeToDirectory.getPath() + File.separator + mail.getMailDescriptorKey()
                    + Constants.DAT_POSTFIX);
            ObjectSerializer.<Mail>writeToDisk(mail, writeTo);
        } catch (IOException e) {
            logClass.error("Error: " + e.getMessage() //$NON-NLS-1$
                    + Constants.LINE_SEPARATOR, e);
        }
    }

    /**
     * Checks the given {@link de.xirp.mail.Mail}, if
     * the minimum requirements are met for sending the mail.
     * 
     * @param mail
     *            The mail to check.
     * @throws MessagingException
     *             if something is wrong with the mail.
     * @see de.xirp.mail.Mail
     */
    private static void checkMail(Mail mail) throws MessagingException {
        if (mail.getTo().size() <= 0) {
            throw new MessagingException(I18n.getString("MailManager.exception.noReceiver") //$NON-NLS-1$
                    + Constants.LINE_SEPARATOR);
        }
    }

    /**
     * Returns the collection of
     * {@link de.xirp.mail.MailDescriptor}.
     * 
     * @return The mail descriptors.
     * @see de.xirp.mail.MailDescriptor
     */
    public static Collection<MailDescriptor> getMailDescriptors() {
        try {
            return Collections.unmodifiableCollection((mailDescriptors.values()));
        } catch (NullPointerException e) {
            mailDescriptors = new HashMap<String, MailDescriptor>(0);
            return Collections.unmodifiableCollection(mailDescriptors.values());
        }
    }

    /**
     * Deletes the given {@link de.xirp.mail.Contact}
     * from the list of contacts.
     * 
     * @param contact
     *            The contact to delete.
     * @return <code>true</code> if deleting was successful.<br>
     *         <code>false</code> if deleting was not successful.
     * @see de.xirp.mail.Contact
     */
    public static boolean deleteContact(Contact contact) {
        return contacts.remove(contact);
    }

    /**
     * Deletes a {@link de.xirp.mail.Mail} from the hard
     * disk for the given corresponding
     * {@link de.xirp.mail.MailDescriptor}.
     * 
     * @param md
     *            The corresponding mail descriptor.
     * @return <code>true</code> if deleting was successful.<br>
     *         <code>false</code> if deleting was not successful.
     * @see de.xirp.mail.MailDescriptor
     */
    public static boolean deleteMail(MailDescriptor md) {
        MailDescriptor test = mailDescriptors.remove(md.getDescriptorKey());
        if ((test == null)) {
            return false;
        } else {
            File toDelete = new File(Constants.MAIL_DATA_DIR + File.separator + md.getFolderKey() + File.separator
                    + md.getDescriptorKey() + Constants.DAT_POSTFIX);
            toDelete.delete();
            return true;
        }
    }

    /**
     * Checks the mail settings for compleness.
     * 
     * @throws MessagingException
     *             if the settings are not sufficient.
     */
    public static void checkSettings() throws MessagingException {
        // TODO Check for net connection.
        if (Util.isEmpty(PropertiesManager.getSmtpHost())) {
            throw new MessagingException(I18n.getString("MailManager.exception.noSMTPHost")); //$NON-NLS-1$
        } else if (PropertiesManager.getSmtpPort() <= 0) {
            throw new MessagingException(I18n.getString("MailManager.exception.portError")); //$NON-NLS-1$
        }
        if (PropertiesManager.isNeedsAuthentication()) {
            if (Util.isEmpty(PropertiesManager.getSmtpUser())) {
                throw new MessagingException(I18n.getString("MailManager.exception.noUser")); //$NON-NLS-1$
            } else if (Util.isEmpty(PropertiesManager.getSmtpPassword())) {
                throw new MessagingException(I18n.getString("MailManager.exception.noPassword")); //$NON-NLS-1$
            }
        }
        if (Util.isEmpty(PropertiesManager.getNoReplyAddress())) {
            throw new MessagingException(I18n.getString("MailManager.exception.noNoReplyAddress")); //$NON-NLS-1$
        }
    }

    /**
     * Returns the corresponding
     * {@link de.xirp.mail.Mail} for the given
     * {@link de.xirp.mail.MailDescriptor}.
     * 
     * @param mailDescriptor
     *            The corresponding mail descriptor.
     * @return The desired mail.
     * @throws SerializationException
     *             if something went wrong while loading the mail.
     * @throws FileNotFoundException
     *             if the mail was not found.
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Mail
     */
    public static Mail getMail(MailDescriptor mailDescriptor) throws SerializationException, FileNotFoundException {
        Mail mail = null;
        try {
            File readFrom = getMailFile(mailDescriptor);
            // ObjectDeSerializer<Mail> ods = new
            // ObjectDeSerializer<Mail>( );
            mail = ObjectDeSerializer.<Mail>getObject(readFrom);
        } catch (SerializationException e) {
            logClass.error("Error: " + e.getMessage() //$NON-NLS-1$
                    + Constants.LINE_SEPARATOR, e);
            throw e;
        } catch (FileNotFoundException e) {
            logClass.error("Error: " + e.getMessage() //$NON-NLS-1$
                    + Constants.LINE_SEPARATOR, e);
            throw e;
        }
        return mail;
    }

    /**
     * Exports the corresponding
     * {@link de.xirp.mail.Mail} for the given
     * {@link de.xirp.mail.MailDescriptor} to the given
     * path. A new folder is created there, the folder will contain
     * the content of the mail: text and attachments.
     * 
     * @param path
     *            The path to export the mail to.
     * @param md
     *            The mail descriptor for the mail to export.
     * @throws SerializationException
     *             if something wnt wrong while loading the mail.
     * @throws IOException
     *             if something went wrong while loading the mail.
     * @see de.xirp.mail.MailDescriptor
     */
    public static void exportMail(String path, MailDescriptor md) throws SerializationException, IOException {

        Mail mail = getMail(md);
        File outputFolder = new File(path, "mailexport_" //$NON-NLS-1$
                + md.getDescriptorKey());

        File tempDir = new File(Constants.TMP_DIR);
        File tempOutputFolder = new File(tempDir, "xirpmailexport"); //$NON-NLS-1$
        tempOutputFolder.mkdir();

        File text = new File(tempOutputFolder, "mail.txt"); //$NON-NLS-1$
        text.createNewFile();

        /* write mailtext, encoding is Unicode */
        FileUtils.writeStringToFile(text,
                mail.getSubject() + Constants.LINE_SEPARATOR + Constants.LINE_SEPARATOR + mail.getText(),
                "Unicode"); //$NON-NLS-1$

        File attachmentFolder = new File(tempOutputFolder, "attachments"); //$NON-NLS-1$
        attachmentFolder.mkdir();

        for (Attachment a : mail.getAttachments()) {
            File attachment = new File(attachmentFolder, a.getFileName());
            attachment.createNewFile();
            FileUtils.writeByteArrayToFile(attachment, a.getAttachmentFileContent());
        }

        FileUtils.copyDirectory(tempOutputFolder, outputFolder);
    }

    /**
     * Saves the {@link de.xirp.mail.Attachment}
     * specifiend by the given
     * {@link de.xirp.mail.AttachmentDescriptor} from the
     * given {@link de.xirp.mail.MailDescriptor} to the
     * given path. The {@link de.xirp.mail.Attachment} is
     * existing in the {@link de.xirp.mail.Mail}, so
     * that the {@link de.xirp.mail.MailDescriptor} is
     * used to load the correct {@link de.xirp.mail.Mail}
     * and then the {@link de.xirp.mail.Attachment} is
     * extracted from the {@link de.xirp.mail.Mail}. The
     * {@link de.xirp.mail.Attachment} is found by using
     * the {@link de.xirp.mail.AttachmentDescriptor}.
     * 
     * @param path
     *            The path to save the file to.
     * @param md
     *            The mail descriptor.
     * @param ad
     *            The attachment descriptor.
     * @throws SerializationException
     *             if something went wrong saving the attachment.
     * @throws IOException
     *             if something went wrong saving the attachment.
     * @see de.xirp.mail.Mail
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Attachment
     * @see de.xirp.mail.AttachmentDescriptor
     */
    public static void saveAttachment(String path, MailDescriptor md, AttachmentDescriptor ad)
            throws SerializationException, IOException {

        Mail mail = getMail(md);

        File outputFolder = new File(path);
        File attachment = new File(outputFolder, ad.getFileName());
        attachment.createNewFile();

        for (Attachment a : mail.getAttachments()) {
            if ((a.getFileName().equals(ad.getFileName())) && a.getFileType().equals(ad.getFileType())
                    && a.getAttachmentFileContent().length == ad.getFileSize()) {
                FileUtils.writeByteArrayToFile(attachment, a.getAttachmentFileContent());
            }
        }
    }

    /**
     * Checks the consistency of the <code>mail.dat</code> and saved
     * mail files. If a mail was delete outside the application the
     * mail will be restored using the information from the mail
     * descriptor located in the mail.dat. Attachments can not be
     * resored. <br>
     * <br>
     * If more mails exist in the mail folders than descriptors exist
     * in <code>mail.dat</code>, the mail descriptors are restored.
     * 
     * @see de.xirp.mail.Mail
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Attachment
     * @see de.xirp.mail.AttachmentDescriptor
     */
    @SuppressWarnings({ "unchecked", "cast" })
    private void checkMailConsistency() {
        if (mailDescriptors != null) {
            File dir = new File(Constants.MAIL_DATA_DIR);
            String ext[] = new String[] { "dat" }; //$NON-NLS-1$
            Collection<File> filesSystem = (Collection<File>) FileUtils.listFiles(dir, ext, true);

            Collection<File> filesHashMap = new ArrayList<File>();
            for (MailDescriptor md : mailDescriptors.values()) {
                filesHashMap.add(new File(Constants.MAIL_DATA_DIR + File.separator + md.getFolderKey()
                        + File.separator + md.getDescriptorKey() + Constants.DAT_POSTFIX));
            }

            /*
             * restore descriptors in hash map if more files exists
             * than in hash map
             */
            Collection<File> toMuchInFilesystem = (Collection<File>) org.apache.commons.collections.CollectionUtils
                    .subtract(filesSystem, filesHashMap);
            for (File f : toMuchInFilesystem) {
                restoreMailDescriptor(f);
            }

            /*
             * restore manually deleted mails from infos in mail
             * descriptor, attachments can not be restored :(
             */
            Collection<File> toMuchInHashMap = (Collection<File>) org.apache.commons.collections.CollectionUtils
                    .subtract(filesHashMap, filesSystem);
            for (File f : toMuchInHashMap) {
                restoreMail(f);
            }
        }
    }

    /**
     * Restores the given mail {@link java.io.File}. The
     * {@link de.xirp.mail.Mail} is restored from the
     * corresponding {@link de.xirp.mail.MailDescriptor}.
     * The descriptor is found in the mail descriptors map. The file
     * name is used as keys in that map.
     * 
     * @param file
     *            The mail file to restore.
     * @see de.xirp.mail.Mail
     * @see de.xirp.mail.Contact
     * @see de.xirp.mail.MailDescriptor
     */
    private void restoreMail(File file) {
        String fileName = file.getName();
        fileName = fileName.substring(0, fileName.length() - 4);
        MailDescriptor md = mailDescriptors.get(fileName);

        Mail mail = new Mail();
        mail.setSendDate(md.getSendDate());
        mail.setSubject(md.getSubject());
        mail.setText(md.getText());

        try {
            Contact c = new Contact();
            c.setMail(md.getToMail());
            String name1 = md.getToName();
            String names1[] = name1.split(","); //$NON-NLS-1$
            c.setFirstName(names1[0]);
            c.setLastName(names1[1]);
            mail.addTo(c);

            c = new Contact();
            c.setMail(md.getCcMail());
            String name2 = md.getCcName();
            String names2[] = name2.split(","); //$NON-NLS-1$
            c.setFirstName(names2[0]);
            c.setLastName(names2[1]);
            mail.addCc(c);
        } catch (ArrayIndexOutOfBoundsException e) {

        }

        logClass.debug(I18n.getString("MailManager.log.restoredMail") + Constants.MAIL_DATA_DIR //$NON-NLS-1$
                + File.separator + md.getFolderKey() + File.separator + md.getDescriptorKey()
                + Constants.DAT_POSTFIX + Constants.LINE_SEPARATOR);

        saveMail(mail, md.getFolderKey());
        md.clearAttachmentDescriptorList();
    }

    /**
     * Restores the {@link de.xirp.mail.MailDescriptor}
     * for the given mail {@link java.io.File}. The mail file is
     * loaded and the {@link de.xirp.mail.MailDescriptor}
     * is build from the {@link de.xirp.mail.Mail}.
     * 
     * @param file
     *            The mail file.
     * @see de.xirp.mail.Mail
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.util.serialization.ObjectDeSerializer
     */
    private void restoreMailDescriptor(File file) {
        Mail mail = null;
        MailDescriptor md = null;

        File folder = new File(file.getParent());
        int folderKey = Integer.parseInt(folder.getName());

        try {
            mail = ObjectDeSerializer.<Mail>getObject(file);
            ;
            md = mail.getMailDescriptor();
            md.setFolderKey(folderKey);
            md.setDescriptorKey(mail.getMailDescriptorKey());
            mailDescriptors.put(md.getDescriptorKey(), md);

            logClass.debug(I18n.getString("MailManager.log.restoredDescriptor") //$NON-NLS-1$
                    + Constants.MAIL_DATA_DIR + File.separator + md.getFolderKey() + File.separator
                    + md.getDescriptorKey() + Constants.DAT_POSTFIX + Constants.LINE_SEPARATOR);
        } catch (SerializationException e) {
            logClass.error(I18n.getString("MailManager.log.corruptMailFound", //$NON-NLS-1$
                    (file.getAbsolutePath() + Constants.LINE_SEPARATOR),
                    (e.getMessage() + Constants.LINE_SEPARATOR), Constants.LINE_SEPARATOR));

            DeleteManager.deleteOnStartup(file);
        } catch (IOException e) {
            logClass.error("Error: " + e.getMessage() //$NON-NLS-1$
                    + Constants.LINE_SEPARATOR, e);
        }
    }

    /**
     * Returns a {@link java.io.File} object for the given
     * {@link de.xirp.mail.MailDescriptor}. The
     * descriptor contains the descriptor key, which is the file name
     * when it is concatenated with the <code>DAT_POSTFIX</code>.
     * <br>
     * <br>
     * The path is constructed from the folder key.
     * 
     * @param mailDescriptor
     *            The mail descriptor.
     * @return The constructed file.
     * @see de.xirp.mail.MailDescriptor
     */
    private static File getMailFile(MailDescriptor mailDescriptor) {
        return new File(Constants.MAIL_DATA_DIR + File.separator + mailDescriptor.getFolderKey() + File.separator
                + mailDescriptor.getDescriptorKey() + Constants.DAT_POSTFIX);
    }

    /**
     * Loads the mail descriptors and the contact list from the file
     * system. <br>
     * <br>
     * This method is called from the
     * {@link de.xirp.managers.ManagerFactory} on
     * startup. Do not call it on your own.
     * 
     * @see de.xirp.managers.AbstractManager#start()
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Contact
     * @see de.xirp.util.serialization.ObjectDeSerializer
     */
    @Override
    protected void start() throws ManagerException {
        super.start();

        rnd = new Random(System.nanoTime());

        mailDescriptors = new HashMap<String, MailDescriptor>(0);
        contacts = new ArrayList<Contact>(0);

        File readMailFrom = null;
        try {
            readMailFrom = new File(Constants.MAIL_DESCRIPTORS_FILE);
            mailDescriptors = ObjectDeSerializer.<HashMap<String, MailDescriptor>>getObject(readMailFrom);
        } catch (SerializationException e) {
            throw new ManagerException(e);
        } catch (FileNotFoundException e) {
            try {
                readMailFrom.createNewFile();
            } catch (IOException ex) {
                throw new ManagerException(ex);
            }
        } catch (IOException e) {
            throw new ManagerException(e);
        }

        File readContactFrom = null;
        try {
            readContactFrom = new File(Constants.MAIL_CONTACTS_FILE);
            contacts = ObjectDeSerializer.<ArrayList<Contact>>getObject(readContactFrom);
        } catch (SerializationException e) {
            throw new ManagerException(e);
        } catch (FileNotFoundException e) {
            try {
                readContactFrom.createNewFile();
            } catch (IOException e1) {
                throw new ManagerException(e1);
            }
        }

        checkMailConsistency();
    }

    /**
     * Saves the map of
     * {@link de.xirp.mail.MailDescriptor} and the list
     * of {@link de.xirp.mail.Contact} to the file
     * system. <br>
     * <br>
     * This method is called from the
     * {@link de.xirp.managers.ManagerFactory} on
     * shutdown. Do not call it on your own.
     * 
     * @see de.xirp.managers.AbstractManager#stop()
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Contact
     * @see de.xirp.util.serialization.ObjectSerializer
     */
    @Override
    protected void stop() throws ManagerException {
        super.stop();

        try {
            File writeMailTo = new File(Constants.MAIL_DESCRIPTORS_FILE);
            ObjectSerializer.<HashMap<String, MailDescriptor>>writeToDisk(mailDescriptors, writeMailTo);
        } catch (IOException e) {
            throw new ManagerException(e);
        }

        try {
            File writeContactTo = new File(Constants.MAIL_CONTACTS_FILE);
            ObjectSerializer.<ArrayList<Contact>>writeToDisk(contacts, writeContactTo);
        } catch (IOException e) {
            throw new ManagerException(e);
        }
    }

    /**
     * Prints the corresponding {@link de.xirp.mail.Mail}
     * of the given {@link de.xirp.mail.MailDescriptor}.
     * 
     * @param md
     *            The mail descriptor.
     * @throws MessagingException
     *             if something went wrong while printing.
     * @see de.xirp.mail.MailDescriptor
     * @see de.xirp.mail.Mail
     */
    public static void printMail(MailDescriptor md) throws MessagingException {
        try {
            Mail mail = getMail(md);

            List<File> docs = new ArrayList<File>();

            long millis = System.currentTimeMillis();

            File text = new File(Constants.TMP_DIR, millis + "_printtmp_mailtext.txt"); //$NON-NLS-1$
            text.createNewFile();
            docs.add(text);
            DeleteManager.deleteOnShutdown(text);
            FileUtils.writeStringToFile(text, md.getSubject(), "Unicode"); //$NON-NLS-1$

            for (Attachment a : mail.getAttachments()) {
                if (a.isPrintable()) {
                    File attachment = new File(Constants.TMP_DIR, millis + "_printtmp_" + a.getFileName()); //$NON-NLS-1$
                    attachment.createNewFile();
                    docs.add(attachment);
                    DeleteManager.deleteOnShutdown(attachment);
                    FileUtils.writeByteArrayToFile(attachment, a.getAttachmentFileContent());
                }
            }
            PrintManager.print(docs);
        } catch (FileNotFoundException e) {
            logClass.error("Error: " + e.getMessage() + Constants.LINE_SEPARATOR, e); //$NON-NLS-1$
            throw new MessagingException(e.getMessage());
        } catch (SerializationException e) {
            logClass.error("Error: " + e.getMessage() + Constants.LINE_SEPARATOR, e); //$NON-NLS-1$
            throw new MessagingException(e.getMessage());
        } catch (IOException e) {
            logClass.error("Error: " + e.getMessage() + Constants.LINE_SEPARATOR, e); //$NON-NLS-1$
            throw new MessagingException(e.getMessage());
        }
    }
}