/*
 * $Id: JavaMailUtils.java,v 1.12 2009/01/05 08:40:21 korowa Exp $
 * 
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: JavaMailUtils.java,v $
 * Revision 1.12  2009/01/05 08:40:21  korowa
 * Der MailServer ist auf mail.uni-paderborn.de umgezogen
 *
 * Revision 1.11  2006/04/24 11:28:36  lawern
 * Date im Message-Body wurde nicht gesetzt.
 *
 * Revision 1.10  2005/12/22 15:43:49  marbobo
 * + SSL-Unterstützung und Port-Auswahl für Mailsystem implementiert
 *
 * Revision 1.9  2005/12/20 14:04:16  marbobo
 * + Smtp-Auth korrigiert
 *
 * Revision 1.8  2005/12/15 15:28:54  marbobo
 * + Benutzername und Passwort für Mailserver implementiert
 *
 * Revision 1.7  2005/02/15 18:44:53  marbobo
 * + Unicode-Konforme E-Mails
 *
 * Revision 1.6  2004/11/10 15:02:46  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.5  2004/07/20 08:46:28  jonyp
 * added copyright info + cvs log
 *
 * Revision 1.4  2004/06/27 17:33:38  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.3  2004/06/03 15:59:07  teng
 * delete email
 *
 * Revision 1.2  2004/06/02 17:30:08  teng
 * kleine Aenderung bzgl. getMessages()
 *
 * Revision 1.1  2004/05/28 10:43:33  teng
 * *** empty log message ***
 *
 */
package vkc.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Folder;
//import javax.mail.Flags;
import javax.mail.FetchProfile;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;

/**
 * A utilities class for sending and receiving email
 * @author teng
 */
public class JavaMailUtils {

	private boolean debug = true;
	public static final String INBOX = "INBOX";
	//public static final String POP = "pop3";
	//public static final String SMTP = "smtp";
	public static final String IMAP = "imap";

	/**
	 * 
	 * @param serverType
	 * @param server
	 * @param user
	 * @param password
	 * @param msgHandler
	 * @throws Exception
	 */
	public void getMessages(String serverType, String server, String user, String password, MessageHandler msgHandler) throws Exception {
		Properties sysProperties = System.getProperties();
		Session session = Session.getDefaultInstance(sysProperties, null);

		Store store = session.getStore(serverType);
		store.connect(server, -1, user, password);

		Folder folder = store.getDefaultFolder();
		if (folder == null)
			throw new NullPointerException("Getting default folder failed!");

		folder = folder.getFolder(INBOX);
		if (folder == null)
			throw new NullPointerException("Getting folder failed!");

		folder.open(Folder.READ_WRITE);
		if (folder.getMessageCount() == 0) {
			System.out.println(folder + ": no messages in the folder!");
			folder.close(false);
			store.close();
			return;
		}

		Message[] messages = folder.getMessages();
		FetchProfile fp = new FetchProfile();
		fp.add(FetchProfile.Item.ENVELOPE);
		fp.add(FetchProfile.Item.FLAGS);
		fp.add("X-Mailer");
		folder.fetch(messages, fp);

		msgHandler.handleMessages(messages);

		folder.close(true);
		store.close();

	}

	/**
	 * delete a mail. After the folder is closed this message will be deleted from the server. 
	 * @param message
	 * @throws Exception
	 */
	public void deleteMessage( Message message ) throws Exception{
		message.setFlag(Flags.Flag.DELETED, true); 
	}
	
	/**
	 * method for sending smtp mail
	 * @param sender
	 * @param recepient
	 * @param subject
	 * @param asciiText
	 * @param htmlText
	 * @param files contains <code>File</code>
	 * @param displayedFilename
	 * @param smtpServer
	 * @param smtpUsername
	 * @param smtpPassword
	 * @throws IllegalArgumentException
	 * @throws MessagingException
	 * @throws SendFailedException
	 */
	public void sendSMTPMail(String sender, String recepient, String subject, String asciiText, String htmlText, Vector files, String displayedFilename, String smtpServer, String smtpUsername, String smtpPassword) throws IllegalArgumentException, MessagingException, SendFailedException {

		sendSMTPMail(sender, recepient, subject, asciiText, htmlText, files, displayedFilename, null, smtpServer, smtpUsername, smtpPassword);

	}

	/**
	 * method for sending smtp mail with image part
	 * @param sender email address of the sender
	 * @param recepient email address of the recepient
	 * @param subject
	 * @param asciiText the plain text part
	 * @param htmlText the html part 
	 * @param files contains files for attachment. If null, send without any attachment
	 * @param displayedFilename the name displayed for the attachment files. If null, the file name will be used.
	 * @param images contains MailImage. If null send email without image part
	 * @param smtpServer the smtp server name
	 * @param smtpUsername the smtp server username
	 * @param smtpPassword the smtp server password
	 * @throws IllegalArgumentException
	 * @throws MessagingException
	 * @throws SendFailedException
	 */
	public void sendSMTPMail(String sender, String recepient, String subject, String asciiText, String htmlText, Vector files, String displayedFilename, Vector images, String smtpServer, String smtpUsername, String smtpPassword)
		throws IllegalArgumentException, MessagingException, SendFailedException {
		if ((sender == null) || ((sender = sender.trim()).length() == 0)) {
			throw new IllegalArgumentException("mail sender can't be null or empty!");
		}

		if ((recepient == null) || ((recepient = recepient.trim()).length() == 0)) {
			throw new IllegalArgumentException("recepient can't be null or empty!");
		}

		if ((smtpServer == null) || ((smtpServer = smtpServer.trim()).length() == 0)) {
			throw new IllegalArgumentException("smtpServer can't be null or empty!");
		}

		if ((subject == null) || ((subject = subject.trim()).length() == 0)) {
			throw new IllegalArgumentException("subject can't be null or empty!");
		}

		if (asciiText == null) {
			throw new IllegalArgumentException("Ascii part can't be null");
		}

		File file = null;
		final String username = smtpUsername;
		final String password = smtpPassword;
		int smtpPort  = 25;
		boolean smtpSSL = false;
		boolean smtpUntrustedCert = false;

		try {
			smtpPort  = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailPort", 25);
			smtpSSL = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailSsl", 0) != 0 ? true : false;
			smtpUntrustedCert = VKCSysParameterSerializer.retrieveIntValue("MAIL", "MailUntrustedCertificate", 0) != 0 ? true : false;
		} catch (DBException e) {
			smtpPort  = 25;
			smtpSSL = false;
			smtpUntrustedCert = false;
		}

		Authenticator auth = new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password);
			}
		};
		
		Properties props = new Properties();
		props = new Properties();
		
		if (smtpSSL) {
			props.put("mail.transport.protocol", "smtps");
			
			if (smtpUntrustedCert) {
				props.put("mail.smtps.socketFactory.class", "vkc.messenger.mail.VKCSSLSocketFactory");
				props.put("mail.smtps.socketFactory.fallback", "false");
			}

			props.put("mail.smtps.host", smtpServer);
			props.put("mail.smtps.auth", "true");
			props.put("mail.smtps.port", String.valueOf(smtpPort));
		} else {
			props.put("mail.transport.protocol", "smtp");
			props.put("mail.smtp.host", smtpServer);
			props.put("mail.smtp.auth", "true");
			props.put("mail.smtp.port", String.valueOf(smtpPort));
		}
		
		Session session = Session.getInstance(props, auth);

		// Mailheader zusammensetzen
		MimeMessage message = new MimeMessage(session);
		message.setSubject(subject, "UTF8");
		message.setFrom(new InternetAddress(sender));

		message.addRecipient(Message.RecipientType.TO, new InternetAddress(recepient));

		// create bodypart for images 
		MimeBodyPart[] imageParts = null;
		if (images != null && !images.isEmpty()) {
			imageParts = new MimeBodyPart[images.size()];
			MimeBodyPart imagePart = null;
			MailImage mImg = null;
			int i = 0;
			for (Iterator itr = images.iterator(); itr.hasNext(); i++) {
				mImg = (MailImage) itr.next();
				try {
					imagePart = new MimeBodyPart();
					DataSource fds = new FileDataSource(mImg.getPath());
					imagePart.setFileName(mImg.getName());
					imagePart.setContent(mImg.getImage(), "image/gif; name=" + mImg.getName());
					//imagePart.setContentID(fds.getName());//mImg.getId());
					imagePart.setHeader("Content-ID", "<" + mImg.getId() + ">");
					imagePart.setDisposition(javax.mail.Part.INLINE);
					imagePart.setDataHandler(new DataHandler(fds));
					imageParts[i] = imagePart;

				} catch (Exception ex) {
					VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
				}
			}
		}
		//imageParts containts all bodyparts of the images now

		MimeBodyPart plainPart = new MimeBodyPart();
		plainPart.setContent(asciiText, "text/plain; charset=utf-8");

		MimeBodyPart htmlPart = null;

		if (htmlText != null) {
			htmlPart = new MimeBodyPart();
			htmlPart.setContent(htmlText, "text/html; charset=utf-8");
		}

		// Mail als Multipart verschicken
		MimeMultipart multiPart = new MimeMultipart("related"); // store all possible parts

		MimeMultipart textPart = null; // for text contents e.g. html+plain

		if (htmlPart == null) {
			textPart = new MimeMultipart("mixed");
			textPart.addBodyPart(plainPart);
		} else {
			textPart = new MimeMultipart("alternative");
			textPart.addBodyPart(plainPart);
			textPart.addBodyPart(htmlPart);
		}

		MimeBodyPart wrapper = new MimeBodyPart();
		wrapper.setContent(textPart);
		multiPart.addBodyPart(wrapper);

		if (imageParts != null) {
			for (int i = 0; i < imageParts.length; i++)
				multiPart.addBodyPart(imageParts[i]);
		}

		if (files == null || files.isEmpty()) {
			message.setContent(multiPart);
		} else {

			Multipart mixed = new MimeMultipart("mixed");
			MimeBodyPart wrapper2 = new MimeBodyPart();
			wrapper2.setContent(multiPart);
			mixed.addBodyPart(wrapper2);

			for (int i = 0; i < files.size(); i++) {
				file = (File) files.get(i);
				// Datei als Attachment anhängen
				if (!file.exists() || !file.canRead()) {
					throw new IllegalArgumentException("Session-document not found: " + file);
				}

				BodyPart fileBodyPart = new MimeBodyPart();
				DataSource fds = new FileDataSource(file);
				fileBodyPart.setDataHandler(new DataHandler(fds));
				if (displayedFilename != null) {
					fileBodyPart.setFileName(displayedFilename);
				} else {
					fileBodyPart.setFileName(file.getName());
				}

				mixed.addBodyPart(fileBodyPart);
				if (debug) {
					System.out.println("ATTACHED FILE: " + file.getName());
				}
			}
			message.setContent(mixed);

		} // message.saveChanges();
		Transport transport = session.getTransport();
		transport.connect(smtpServer, smtpPort, smtpUsername, smtpPassword);
        message.setSentDate(new Date());
		transport.sendMessage(message, message.getAllRecipients());
		transport.close();

		if (files != null && !files.isEmpty()) {
			while (!files.isEmpty()) {
				((File) files.remove(0)).delete();
			}
		}

	}

	/**
	 * Create an attachment file for email
	 * @param in Write data from the <code>InputStream</code> in into the attachment file 
	 * @param docName The file name of this attachment
	 * @param tmp the path for creating the temp file of the attachment
	 * @return the attachment file
	 */
	public File createAttachmentFile(InputStream in, String docName, String tmp) {

		File file = null;
		try {

			file = new File(tmp + docName);
			if (!file.createNewFile())
				return null;
			//write the stream to the file specified
			OutputStream out = new FileOutputStream(file);
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
				out.write(buffer, 0, bytesRead);
			}
			out.close();

		} catch (Exception ex) {
			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
		}

		return file;
	}

	/**
	 * Image attachment.
	 * @author teng
	 *
	 */
	public class MailImage {

		File image;
		String name;
		String path;
		int cid;

		/**
		 * 
		 * @param imageFile File name denotes this image file 
		 * @param cid Content-Id in the mail (in the template file use <img src="cid:0" > to reference the image part with the content-Id 0)
		 * @throws FileNotFoundException
		 */
		public MailImage(String imageFile, int cid) throws FileNotFoundException {
			image = createImage(imageFile);
			if (image == null)
				throw new FileNotFoundException("Image file does not exist");
			path = imageFile;
			name = image.getName();
			this.cid = cid;
		}
		private File createImage(String file) {
			File imgfile = new File(file);
			if (imgfile.exists())
				return imgfile;

			return null;
		}
		public File getImage() {
			return image;
		}
		/**
		 * @return image file name
		 */
		public String getName() {
			return name;
		}
		/**
		 * @return image file path
		 */
		public String getPath() {
			return path;
		}
		/**
		 * @return content id (cid) in the email
		 */
		public int getId() {
			return cid;
		}
	}

	/**
	 * Interface to handle JavaMail Message
	 * @author teng
	 *
	 */
	public interface MessageHandler {
		/**
		 * Handle Message[]. JavaMailUtils.getMessages(String serverType, String host, String user, String password, MessageHandler msgHandler) will call this method.
		 * @param messages
		 * @see JavaMailUtils.getMessages(String serverType, String host, String user, String password, MessageHandler msgHandler)
		 */
		public void handleMessages(Message[] messages);
	}

	public static void main(String args[]) {
	    VKCLogManager.init( "c:/temp/test_", ".log" );
        VKCLogManager.setEnableLogging(true);
        VKCLogManager.setLogToConsole(true);
        
		try {
			MessageHandler msgHandler = new MessageHandler() {
				public void handleMessages(Message[] msgs) {
					for (int i = 0; i < msgs.length; i++) {
						Message message = msgs[i];
						try {

							Object obj = message.getContent();
							if (!(obj instanceof MimeMultipart)) {

								if ((message.getContentType().toLowerCase().startsWith("text/html")) || (message.getContentType().toLowerCase().startsWith("text/plain")))
									System.out.println(message.getContent().toString());

							}
						} catch (Exception ex) {
							System.out.println("" + ex);
						}
					}
				}
			};
			new JavaMailUtils().getMessages(IMAP, "mail.uni-paderborn.de", args[0], args[1], msgHandler);
		} catch (Exception ex) {
			System.out.println("" + ex);
		}
	}
}
