/*
 * $Id: Eml2Html.java,v 1.25 2006/04/07 09:41:46 korowa Exp $
 * 
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: Eml2Html.java,v $
 * Revision 1.25  2006/04/07 09:41:46  korowa
 * Falscher Pfad zu velocityLoader wurde  korregiert
 *
 * Revision 1.24  2006/02/23 09:20:32  lawern
 * Exceptions durch Leerzeichen in Absenderadressen abgefangen.
 *
 * Revision 1.23  2004/11/10 15:02:47  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.22  2004/07/20 08:46:28  jonyp
 * added copyright info + cvs log
 *
 * Revision 1.21  2004/06/27 17:33:38  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.20  2004/05/27 15:04:00  teng
 * *** empty log message ***
 *
 * Revision 1.19  2004/05/25 14:25:44  teng
 * attached messages werden jetzt angezeigt statt link
 *
 * Revision 1.18  2004/05/13 17:27:03  teng
 * Attachments titel wird ausgenommen falls es keinen Attachment gibt
 *
 * Revision 1.17  2004/05/13 17:12:32  teng
 * stopList fuer moegliche problematische buchstabe
 *
 * Revision 1.16  2004/05/13 16:35:16  teng
 * Behandlung von quoted-printable codierte Email und weitere Verbesserung
 *
 * Revision 1.15  2004/05/10 17:20:53  teng
 * Das Problem bei cid mit $ Zeichen wird geloest. 
 * image attachments werden beseitigt wenn diese Bilder in html file angezeigt werden. 
 * From-Adresse fehler wird beseitigt.
 *
 * Revision 1.14  2004/05/10 13:59:05  teng
 * Behandlung von newletter bzw. email mit Bilder aber ohne Bildnamen usw.
 *
 * Revision 1.13  2004/05/07 20:41:52  teng
 * handle attachment messages
 *
 * Revision 1.12  2004/05/07 20:33:01  teng
 * *** empty log message ***
 *
 * Revision 1.11  2004/05/04 17:48:28  teng
 * path problem bei Konvertierung von vkc-mail ist behoben
 *
 * Revision 1.10  2004/04/21 12:32:41  lawern
 * Tengs EML-Konverter eingefügt.
 *
 * Revision 1.9  2004/04/13 15:28:26  teng
 * *** empty log message ***
 *
 * Revision 1.8  2004/04/08 19:15:46  teng
 * *** empty log message ***
 *
 * Revision 1.7  2004/04/08 16:41:19  teng
 * *** empty log message ***
 *
 * Revision 1.6  2004/04/08 16:26:38  teng
 * *** empty log message ***
 *
 * Revision 1.5  2004/04/01 17:09:40  teng
 * *** empty log message ***
 *
 * Revision 1.4  2004/03/30 17:06:07  teng
 * *** empty log message ***
 *
 * Revision 1.3  2004/03/26 20:04:30  teng
 * *** empty log message ***
 *
 * Revision 1.2  2004/03/26 19:39:48  teng
 * *** empty log message ***
 *
 * Revision 1.1  2004/03/22 19:02:01  teng
 * *** empty log message ***
 *
 */
package vkc.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Properties;
//import java.util.Random;
import java.util.Vector;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import com.sun.mail.util.QPDecoderStream;

import vkc.misc.TemplateParser;
import vkc.misc.VKCLogManager;

/**
 * A class for transforming a eml file to html file
 * @author teng
 */

public class Eml2Html {

	private boolean debug = false;

	public static final String MIMETYPE_PLAIN = "text/plain";
	public static final String MIMETYPE_HTML = "text/html";
	public static final String MIMETYPE_IMAGE_GIF = "image/gif";
	public static final String MIMETYPE_IMAGE_JPEG = "image/jpeg";
	public static final String MIMETYPE_APPLICATION = "application/";
	public static final String MIMETYPE_MIX = "multipart/mixed";
	public static final String MIMETYPE_ALTERNATIVE = "multipart/alternative";
	public static final String MIMETYPE_RELATED = "multipart/related";
	public static final String MIMETYPE_DISPOSITION_ATTACHMENT = "attachment";
	public static final String MIMETYPE_MESSAGE = "message/rfc822";
	public static final String MIMETYPE_DISPOSITION_INLINE = "inline";
	public static final String MIMETYPE_HEADER_CONTENT_ID = "Content-Id";

	private static final char[] stopList = { '$', '.', '(', ')' };
	/**
	 * char for replacing the char '$'
	 */
	private static final char replaceStop = 'X';
	/**
	 * for replacing token in the html part. This map is only used for email contains images in the html part and has the content id in the image part with the char '$'.
	 * key:old token, value:replacement
	 */
	private HashMap replaceMap = null;

	/**
	 * for setting velocity template path other than the default
	 */
	private String velocityLoaderPath = new File("").getAbsolutePath();
	/**
	 * temporary path for creating temporary template file (this is only used for an email with image. In this case a cid in an email will be replaced with the html img tag)   
	 */
	private String velocityTmpPath = velocityLoaderPath + "/tmp";
	/**
	 * the name of the template file used by Templateparser
	 */
	private String templatefile = "mail2htmltemplate.html";
	/**
	 * temporary path for creating the result 
	 */
	private String temporaryPath = null; //"C:/temp/";
	/**
	 * @see <code>temporaryPath</code>
	 */
	private File tmpDir = null;

	/**
	 * the file name used for creating the result html file
	 */
	private String outputFile = "index.html";

	private File emlFile = null;

	//variables used by the templateparser
	private String subject = null;

	/**
	 * the email from name + from address
	 */
	private String from = null;

	/**
	 * the email from address 
	 */
	private String fromAddress = null;
	private HashMap[] to = null;
	private HashMap[] replyTo = null;
	//private String fromDate = " ";
	private String receivedDate = " ";
	/**
	 * for generating image file names if a image part has no file name.
	 */
	private int imgCount = 0;
	private Vector attachment = null;
	private Vector imageattachment = null;
	private Vector attachedMessages = null;
	/**
	 * print the title of attachment 
	 */
	private String attachmentStr = " ";

	/**
	 * use this map to replace the token cid:number with image path in a html document
	 * key:content id String, value:image resource path String
	 */
	private HashMap cid_img = null;
	/**
	 * the html part in the Email
	 */
	private String htmlPart = null;
	/**
	 * the plain part in the Email ( use this String only if Email does not contain a html part )
	 */
	private String plainPart = null;

	/**
	 *  
	 * @param args The eml file, the temporary directory for creating html file
	 */
	public static void main(String[] args) {
	    VKCLogManager.init( "c:/temp/test_", ".log" );
        VKCLogManager.setEnableLogging(true);
        VKCLogManager.setLogToConsole(true);
        
		try {
			if (args.length == 2)
				new Eml2Html(new File(args[0]), args[1]).doEml2Html();
			else
				new Eml2Html(new File(args[0])).doEml2Html();

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

	}

	/**
	 * The result of this class is a zip file contains an html file presenting the email content
	 * and the attachment files of the email. 
	 * The zip file will use the temporary directory name.
	 * @param emlFile The eml file 
	 * @param tmpPath The temporary directory for creating the files.
	 */
	/*public Eml2Html(File emlFile, String tmpPath) throws IOException {
	
		this.emlFile = emlFile;
	
		if (!emlFile.exists())
			throw new IOException("Eml2Html: Eml file " + emlFile.getName() + " does not exist!");
	
		tmpDir = new File(tmpPath);
	
		if (!tmpDir.exists())
			throw new IOException("Eml2Html: Temp directory " + tmpPath + " does not exist!");
	
		tmpDir = createTempDir("eml", "tmp", tmpDir);
	
		temporaryPath = tmpDir.getCanonicalPath() + File.separator;
	
	}*/

	public Eml2Html(File emlFile, String loadPath) throws IOException {
		velocityLoaderPath = loadPath;
		velocityTmpPath = velocityLoaderPath + "/tmp";
		this.emlFile = emlFile;

		if (!emlFile.exists())
			throw new IOException("Eml2Html: Eml file " + emlFile.getName() + " does not exist!");

		tmpDir = createTempDir("eml", "tmp", null);

		temporaryPath = tmpDir.getCanonicalPath() + File.separator;

		if (debug)
			System.out.println("Using temporary path:" + temporaryPath);
	}

	public Eml2Html(File emlFile) throws IOException {
		this.emlFile = emlFile;

		if (!emlFile.exists())
			throw new IOException("Eml2Html: Eml file " + emlFile.getName() + " does not exist!");

		tmpDir = createTempDir("eml", "tmp", null);

		temporaryPath = tmpDir.getCanonicalPath() + File.separator;
	}

	public Eml2Html(String loadPath, String temporaryPath) {
		velocityLoaderPath = loadPath;
		velocityTmpPath = velocityLoaderPath + "/tmp";
		this.temporaryPath = temporaryPath;
	}

	/**
	 * start the convertion
	 *
	 */
	public void doEml2Html() {
		try {

			Properties properties = System.getProperties();

			Session session = Session.getDefaultInstance(properties, null);
			InputStream in = new FileInputStream(emlFile);
			MimeMessage message = new MimeMessage(session, in);
			in.close();
			message2Html(message, outputFile);

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

	/**
	 * transforming a MimeMessage into Html. This method is the start point of the convertion
	 * @param message
	 * @param outputFile The output file name
	 */
	public void message2Html(MimeMessage message, String outputFile) {
		try {

			/*java.util.Date date = message.getReceivedDate();//this underlying java implementation returns always null
				if( date != null )
					receivedDate = date.toString();*/

			String[] header = message.getHeader("Date");
			if (header != null && header.length > 0)
				receivedDate = header[0];

			if ((subject = message.getSubject()) == null)
				subject = " ";

			if (debug)
				System.out.println("Subject: " + subject);

            try{
                from = "" + message.getFrom()[0];
            } catch (javax.mail.internet.AddressException ae){
                from = "";
            }

			//creating adress for mailto
			int starti = from.indexOf('<');
			int endi;

			if (starti >= 0) {

				endi = from.indexOf('>');
				if (endi > 0)
					fromAddress = from.substring(starti + 1, endi);

			} else
				fromAddress = from;

			//replace char < > with "" because the brawser does not display the string within <> in a html document
			from = from.replaceAll("<", "&lt;");
			from = from.replaceAll(">", "&gt;");

			if (debug)
				System.out.println("From: " + from);

			Address[] addrs = message.getRecipients(Message.RecipientType.TO);
            Address[] replyToAddrs;
            try {
                replyToAddrs = message.getReplyTo();
            } catch (javax.mail.internet.AddressException ae){
                replyToAddrs = null;
            }

			String str;
			String address;

			if (addrs == null) { //it's possible if this mail is a newsletter

				to = new HashMap[0];

			} else {

				to = new HashMap[addrs.length];

				for (int i = 0; i < addrs.length; i++) {

					address = addrs[i].toString();

					str = address.replaceAll("<", "&lt;");
					str = str.replaceAll(">", "&gt;");

					starti = address.indexOf('<');

					if (starti >= 0) {

						endi = address.indexOf('>');

						if (endi > 0)
							address = address.substring(starti + 1, endi);

					}

					to[i] = new HashMap(2);
					to[i].put("addressForDisplay", str);
					to[i].put("emailAddress", address);

					if (debug)
						System.out.println("To: " + to[i].get("addressForDisplay").toString());

				}
			}

			if (replyToAddrs == null) {

				replyTo = new HashMap[0];

			} else {

				replyTo = new HashMap[replyToAddrs.length];

				for (int i = 0; i < replyToAddrs.length; i++) {

					address = replyToAddrs[i].toString();
					str = address.replaceAll("<", "&lt;");
					str = str.replaceAll(">", "&gt;");

					starti = address.indexOf('<');

					if (starti >= 0) {

						endi = address.indexOf('>');
						if (endi > 0)
							address = address.substring(starti + 1, endi);

					}
					replyTo[i] = new HashMap(2);
					replyTo[i].put("addressForDisplay", str);
					replyTo[i].put("emailAddress", address);

					if (debug)
						System.out.println("reply To: " + replyTo[i].get("addressForDisplay").toString());
				}

			}

			if (debug)
				System.out.println("-----------------------------------");

			if (debug)
				System.out.println(message.getContentType());

			Object obj = message.getContent();

			if (obj instanceof MimeMultipart) {

				handleMultiPart((MimeMultipart) obj);
				//createHtmlFile(outputFile);

			} else {

				if (message.getContentType().toLowerCase().startsWith(MIMETYPE_HTML))
					htmlPart = message.getContent().toString();
				else if (message.getContentType().toLowerCase().startsWith(MIMETYPE_PLAIN))
					plainPart = message.getContent().toString();
				//createHtmlFile(outputFile);

			}
			/*else if( obj instanceof BodyPart){
				if( ((BodyPart)obj).getContentType().toLowerCase().startsWith(MIMETYPE_HTML))
					handleHtmlPart( (BodyPart)obj );
				else if( ((BodyPart)obj).getContentType().toLowerCase().startsWith(MIMETYPE_PLAIN))
					handlePlainPart( (BodyPart)obj );
				//createHtmlFile();
			}*/
			if (outputFile != null)
				createHtmlFile(outputFile);

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

	private void handleMultiPart(MimeMultipart mpart) {
		BodyPart bpart;
		try {
			int k = mpart.getCount();
			for (int i = 0; i < k; i++) {
				bpart = mpart.getBodyPart(i);
				if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_PLAIN)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_PLAIN);
					plainPart = handlePlainPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_HTML)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_HTML);
					htmlPart = handleHtmlPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_RELATED)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_RELATED);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_APPLICATION)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_APPLICATION);
					handleApplicationPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_MIX)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_MIX);
					handleMixPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_MESSAGE)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_MESSAGE);
					handleMessage(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_ALTERNATIVE)) {

					if (debug)
						System.out.println(i + ":" + MIMETYPE_ALTERNATIVE);
					handleAlternativePart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_IMAGE_GIF)) {

					if (debug)
						System.out.println(i + ":" + "img");
					handleImagePart(bpart, ".gif");

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_IMAGE_JPEG)) {

					if (debug)
						System.out.println(i + ":" + "img");
					handleImagePart(bpart, ".jpg");

				} else if (debug)
					System.out.println(i + ":" + "unknown!");
			}
		} catch (Exception ex) {
			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
		}

	}

	/**
	 * handle message part. This method is useful if there are attached messages in the email
	 * @param bpart
	 */
	private void handleMessage(BodyPart bpart) {
		try {

			//String filename;
			String messagename = null;
			javax.mail.Header h;
			for (java.util.Enumeration enm = bpart.getAllHeaders(); enm.hasMoreElements();) {
				h = (javax.mail.Header) enm.nextElement();
				if (h.getName().startsWith("Content-Type")) { //this head contains the message name
					messagename = h.getValue();
					messagename = messagename.substring(messagename.indexOf('"') + 1, messagename.length());
					messagename = messagename.substring(0, messagename.indexOf('"'));
					break;
				} /*else if (h.getName().startsWith("Content-Disposition")) {
																		filename = h.getValue();
																		filename = filename.substring(filename.indexOf('"') + 1, filename.length());
																		filename = filename.substring(0, filename.indexOf('"'));
																}*/

				//System.out.println("header name:" + h.getName() + " header value:" + h.getValue());
			}

			Object obj = bpart.getContent();

			if (obj instanceof MimeMessage) {

				/*String outputFile = ((MimeMessage) obj).getMessageID().trim();
				outputFile = outputFile.replace('.', '_');
				outputFile = outputFile.replace('<', '0');
				outputFile = outputFile.replace('>', '0') + ".html";
				
				HashMap map = new HashMap(2);
				
				if (messagename != null)
					map.put("name", messagename);
				else
					map.put("name", outputFile);
				
				map.put("filename", outputFile);
				
				if (attachedMessages == null)
					attachedMessages = new Vector(5);
				
				attachedMessages.add(map);*/

				Eml2Html eml2html = new Eml2Html(velocityLoaderPath, temporaryPath);
				eml2html.message2Html((MimeMessage) obj, null);
				String messageContent = eml2html.createMessageContent();

				if (messageContent != null) {

					HashMap map = new HashMap(2);
					if (messagename == null)
						messagename = " ";
					map.put("name", messagename);
					map.put("messageContent", messageContent);
					if (attachedMessages == null)
						attachedMessages = new Vector(5);
					attachedMessages.add(map);

				}

			}

		} catch (Exception ex) {

			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);

		}
	}

	private void handleMixPart(BodyPart bpart) {
		try {
			Object obj = bpart.getContent();
			if (obj instanceof MimeMultipart)
				handleMultiPart((MimeMultipart) obj);
			else {
				if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_PLAIN)) {

					plainPart = handlePlainPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_HTML)) {

					htmlPart = handleHtmlPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_RELATED)) {

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_APPLICATION)) {

					handleApplicationPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_MIX)) {

					handleMixPart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_ALTERNATIVE)) {

					handleAlternativePart(bpart);

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_IMAGE_GIF)) {

					handleImagePart(bpart, ".gif");

				} else if (bpart.getContentType().toLowerCase().startsWith(MIMETYPE_IMAGE_JPEG)) {

					handleImagePart(bpart, ".jpg");

				}
			}
		} catch (Exception ex) {

			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);

		}
	}

	private void handleAlternativePart(BodyPart bodyPart) {
		handleMixPart(bodyPart);
	}

	/*private void handleRelatedPart(BodyPart bodyPart) {
		handleMixPart(bodyPart);
	}*/

	/*private String handleSimpleMessage(String message) {
		if(debug)System.out.println(message);
		return message;
	}*/

	private String handleHtmlPart(BodyPart bodyPart) {

		try {

			String htmlStr = bodyPart.getContent().toString();

			if (htmlStr.startsWith("com.sun.mail.util.QPDecoderStream@")) { //Content-Transfer-Encoding: QUOTED-PRINTABLE

				QPDecoderStream qp = new QPDecoderStream(bodyPart.getInputStream());
				byte[] strByte = new byte[qp.available()];
				qp.read(strByte);
				htmlPart = new String(strByte);
				if (debug)
					System.out.println("QUOTED-PRINTABLE decoded:\n" + htmlPart);

			} else
				htmlPart = parseHtmlPart(htmlStr);

			if (debug)
				System.out.println(htmlPart);

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

	private String parseHtmlPart(String htmlPart) {

		int i = indexOfStringIgnoreCase(htmlPart, "<HTML>");
		int j = indexOfStringIgnoreCase(htmlPart, "<BODY>");

		if (j < 0)
			j = indexOfStringIgnoreCase(htmlPart, "<BODY ");

		if (i >= 0 && j > 0) {

			String str = htmlPart.substring(i + 6, j); //str is content between <html> <body>
			String style = getHtmlContent(str, "<STYLE ", "</STYLE>");
			String script = getHtmlContent(str, "<SCRIPT>", "</SCRIPT>");

			str = htmlPart.substring(j); //str is substring from <body...
			i = str.indexOf('>'); //find the tag <body...> close position
			int k = indexOfStringIgnoreCase(str, "</BODY>");

			if (i > 0)
				htmlPart = str.substring(i + 1, k); //htmlPart is now substring between <body></body>
			else //error
				return null;

			if (style != null)
				htmlPart = style + htmlPart;
			if (script != null)
				htmlPart = script + htmlPart;

		}
		//replacing the cid: with Velocity variable $cid
		//the variable $cid will be prepared by the method handleImagePart(...)

		if (replaceMap != null && !replaceMap.isEmpty()) { // this case means the image parts have been handled before this html part

			java.util.Map.Entry entry;
			for (java.util.Iterator itr = replaceMap.entrySet().iterator(); itr.hasNext();) {
				entry = (java.util.Map.Entry) itr.next();
				htmlPart = StringUtils.replaceToken(htmlPart, (String) entry.getKey(), (String) entry.getValue());
			}

		}

		htmlPart = StringUtils.replaceToken(htmlPart, "cid:", "$cid");

		return htmlPart;
	}

	/**
	 * like String.indexOf(substring), but ingore the case of the substring
	 * @param string
	 * @param substring
	 * @return
	 */
	private int indexOfStringIgnoreCase(String string, String substring) {
		String str = string.toLowerCase();
		return str.indexOf(substring.toLowerCase());

	}

	/**
	 * 
	 * @param html
	 * @param htmlTag
	 * @param htmlCloseTag
	 * @return String between htmlTag and htmlCloseTage inclusive the both tags
	 */
	private String getHtmlContent(String html, String htmlTag, String htmlCloseTag) {

		String content = null;
		int i = indexOfStringIgnoreCase(html, htmlTag);
		int j = indexOfStringIgnoreCase(html, htmlCloseTag);

		if (i >= 0 && j > 0) {
			content = html.substring(i, j + htmlCloseTag.length());
		}

		return content;
	}

	/*private String parseHtmlHead(String head) {
		String headData = null;
	
		int i = indexOfStringIgnoreCase(head, "<style>");
		int j = indexOfStringIgnoreCase(head, "</style>");
		if (i >= 0 && j > 0) {
			headData = head.substring(i + 7, j);
		}
		return headData;
	}*/
	private String handlePlainPart(BodyPart bodyPart) {

		String plain = null;

		try {
			plain = bodyPart.getContent().toString();
			//plain = VKCStringUtils.replaceToken(plain, "\n", "<br>");
			if (debug)
				System.out.println(plain);
		} catch (Exception ex) {
			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
			return null;
		}
		return plain;
	}

	/**
	 * 
	 * @param bodyPart
	 * @param filetype It's possible there isnot file name for the attached image in an email. In this case need to generate file name. Therefor the file type is needed e.g. ".gif" ".jpg" 
	 * @return
	 */
	private boolean handleImagePart(BodyPart bodyPart, String filetype) {

		try {
			InputStream in = bodyPart.getInputStream();
			String fileName = bodyPart.getFileName();

			if (fileName == null) {
				fileName = imgCount + filetype;
				imgCount++;
			}

			File file;
			if ((file = createAttachmentFile(in, fileName, temporaryPath)) == null)
				return false;

			String disp = bodyPart.getDisposition();

			if (disp == null)
				return false;

			if (disp.indexOf(MIMETYPE_DISPOSITION_ATTACHMENT) >= 0) {
				//this is an attachment
				if (imageattachment == null)
					imageattachment = new Vector(5);
				imageattachment.add(fileName);

			} else if (disp.indexOf(MIMETYPE_DISPOSITION_INLINE) >= 0) {
				//this is an inline, prepare cid

				String cid;

				String[] ids = bodyPart.getHeader(MIMETYPE_HEADER_CONTENT_ID);

				if (ids != null && ids[0] != null) {

					cid = ids[0].substring(ids[0].indexOf('<') + 1, ids[0].indexOf('>'));

					if (cid != null) {
						//cid containing the chars in the stopList will make problem for Velocity
						//replacing it in the cid of this image part and html part 

						String cidTmp = cid; //keep original cid for possible use

						int stopCharIndex = -1;
						int strIndex;

						//replace all chars from the stopList in the cid string
						for (int i = 0; i < stopList.length; i++) {
							strIndex = cid.indexOf(stopList[i]);
							if (strIndex >= 0) {
								cid = cid.replace(stopList[i], replaceStop);
								stopCharIndex = strIndex;
							}
						}

						//these replaced chars should be replaced also in the html text
						if (stopCharIndex >= 0) {

							if (htmlPart != null) {

								htmlPart = StringUtils.replaceToken(htmlPart, cidTmp, cid);

							} else { // this case means the html part has been not jet handled.
								if (replaceMap == null)
									replaceMap = new HashMap();
								replaceMap.put(cidTmp, cid);
							}

						}
					}

					if (cid_img == null)
						cid_img = new HashMap();

					cid_img.put("cid" + cid, file.getName());
					//later use Templateparser to replace <img src="cid:cid"> in the html part with <img src="file.getName()">
					//The token <img src="cid:cid"> in the html part will be replaced with <img src="$cid"> by the method handleHtmlPart(BodyPart) 
				}

				if (imageattachment == null)
					imageattachment = new Vector(5);
				imageattachment.add(fileName);

			}

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

	private void handleApplicationPart(BodyPart bodyPart) {
		String type;
		//String disp;
		try {
			type = bodyPart.getContentType();
			//disp = bodyPart.getDisposition();

			//if (disp.indexOf(MIMETYPE_DISPOSITION_ATTACHMENT) >= 0) {//sometimes disp is inline but the part is attachment, therefor should not use this if condition
			InputStream in = bodyPart.getInputStream();
			String fileName = bodyPart.getFileName();

			if (createAttachmentFile(in, fileName, temporaryPath) != null) {
				if (attachment == null)
					attachment = new Vector(5);
				attachment.add(fileName);
			}

			//}

			if (debug)
				System.out.println(type);

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

	/**
	 * create file for an attachment in the specified temporary directory
	 * @param in
	 * @param fileName
	 * @param tmp temporary directory for creating the file
	 * @return
	 */
	private File createAttachmentFile(InputStream in, String fileName, String tmp) {

		File file = null;
		try {
			file = new File(tmp + fileName);
			if (file.exists())
				file.delete();
			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;
	}

	private void createHtmlFile(String outputFile) {

		try {

			TemplateParser tparser = null;
			if (velocityLoaderPath != null)
				tparser = TemplateParser.getTemplateParserStandalone(velocityLoaderPath);
			else
				tparser = TemplateParser.getTemplateParserStandalone(new File("").getAbsolutePath());

			tparser.setContextData("messagepartOnly", "0");
			tparser.setContextData("Subject", subject);
			tparser.setContextData("From", from);
			tparser.setContextData("FromAddress", fromAddress);
			tparser.setContextData("To", to);
			tparser.setContextData("replyto", replyTo);
			tparser.setContextData("receiveddate", receivedDate);

			if (htmlPart != null) {

				//remove image from imageattachment if it appears in the html (cid)
				if (cid_img != null && imageattachment != null && !imageattachment.isEmpty()) {

					java.util.Map.Entry entry;
					for (java.util.Iterator itr = cid_img.entrySet().iterator(); itr.hasNext();) {
						entry = (java.util.Map.Entry) itr.next();
						if (htmlPart.indexOf((String) entry.getKey()) >= 0)
							imageattachment.remove(entry.getValue());
					}

				}

				tparser.setContextData("htmlPart", htmlPart);
				tparser.setContextData("plainPart", " ");
			} else if (plainPart != null) {
				tparser.setContextData("htmlPart", " ");
				tparser.setContextData("plainPart", plainPart);
			} else {
				tparser.setContextData("htmlPart", " ");
				tparser.setContextData("plainPart", " ");
			}

			if (attachment != null && !attachment.isEmpty()) {
				attachmentStr = "Attachments:";
				tparser.setContextData("Attachment", attachment);
			}

			if (imageattachment != null && !imageattachment.isEmpty()) {
				attachmentStr = "Attachments:";
				tparser.setContextData("ImageAttachment", imageattachment);
			}

			tparser.setContextData("Attachments", attachmentStr);

			if (attachedMessages != null && !attachedMessages.isEmpty())
				tparser.setContextData("AttachedMessages", attachedMessages);

			//+++++++ replace the cid in the html file with image url
			if (cid_img != null) {
				tparser.setContextData(cid_img);

				//create a temporary template file
				//note: the template file should be found under the velocityLoaderPath or it's subdirectory. 
				File velocityTmpDir = new File(velocityTmpPath);
				if (!velocityTmpDir.exists())
					velocityTmpDir.mkdir();

				if (velocityTmpDir.exists()) {

					File tmpFile = File.createTempFile("eml_index", ".tmp", velocityTmpDir);

					tparser.createFile(templatefile, velocityTmpDir.getCanonicalPath() + File.separator + tmpFile.getName());
					tparser.createFile("tmp/" + tmpFile.getName(), temporaryPath + outputFile);
					tmpFile.delete();

				} else
					tparser.createFile(templatefile, temporaryPath + outputFile);

				//++++++++++++ 

			} else {

				//++++++++++++ create html without cid	
				if (debug)
					System.out.println("creating html file: " + temporaryPath + outputFile);
				tparser.createFile(templatefile, temporaryPath + outputFile);
			}

			/*if( tmpDir != null ){
			
				ZipUtils.zip( tmpDir, new File( tmpDir.getParent() + "/" + tmpDir.getName()+".zip") );
				FileUtils.deleteDirectory( tmpDir );
			
			}*/

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

	private String createMessageContent() {

		try {
			TemplateParser tparser = null;
			if (velocityLoaderPath != null)
				tparser = TemplateParser.getTemplateParserStandalone(velocityLoaderPath);
			else
				tparser = TemplateParser.getTemplateParserStandalone(new File("").getAbsolutePath());

			tparser.setContextData("messagepartOnly", "1");
			tparser.setContextData("Subject", subject);
			tparser.setContextData("From", from);
			tparser.setContextData("FromAddress", fromAddress);
			tparser.setContextData("To", to);
			tparser.setContextData("replyto", replyTo);
			tparser.setContextData("receiveddate", receivedDate);

			if (htmlPart != null) {

				//remove image from imageattachment if it appears in the html (cid)
				if (cid_img != null && imageattachment != null && !imageattachment.isEmpty()) {

					java.util.Map.Entry entry;
					for (java.util.Iterator itr = cid_img.entrySet().iterator(); itr.hasNext();) {
						entry = (java.util.Map.Entry) itr.next();
						if (htmlPart.indexOf((String) entry.getKey()) >= 0)
							imageattachment.remove(entry.getValue());
					}

				}

				tparser.setContextData("htmlPart", htmlPart);
				tparser.setContextData("plainPart", " ");
			} else if (plainPart != null) {
				tparser.setContextData("htmlPart", " ");
				tparser.setContextData("plainPart", plainPart);
			} else {
				tparser.setContextData("htmlPart", " ");
				tparser.setContextData("plainPart", " ");
			}

			if (attachment != null && !attachment.isEmpty()) {
				attachmentStr = "Attachments:";
				tparser.setContextData("Attachment", attachment);
			}

			if (imageattachment != null && !imageattachment.isEmpty()) {
				attachmentStr = "Attachments:";
				tparser.setContextData("ImageAttachment", imageattachment);
			}

			tparser.setContextData("Attachments", attachmentStr);

			if (attachedMessages != null && !attachedMessages.isEmpty()){
				attachmentStr = "Attachments:";
				tparser.setContextData("AttachedMessages", attachedMessages);
			}

			//+++++++ replace the cid in the html file with image url
			if (cid_img != null) {
				tparser.setContextData(cid_img);

				//create a temporary template file
				//note: the template file should be found under the velocityLoaderPath or it's subdirectory. 
				File velocityTmpDir = new File(velocityTmpPath);
				if (!velocityTmpDir.exists())
					velocityTmpDir.mkdir();

				if (velocityTmpDir.exists()) {

					File tmpFile = File.createTempFile("eml_index", ".tmp", velocityTmpDir);

					tparser.createFile(templatefile, velocityTmpDir.getCanonicalPath() + File.separator + tmpFile.getName());
					String result = tparser.createString("tmp/" + tmpFile.getName());
					tmpFile.delete();
					return result;
				} 

				return tparser.createString(templatefile);

				//++++++++++++ 

			} 

			//++++++++++++ create html without cid	
			if (debug)
				System.out.println("creating html String ");
			return tparser.createString(templatefile);
		} catch (Exception ex) {
			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
			return null;
		}
	}

	/**
	 * 
	 * @return temporary directory which contains the conversion result 
	 */
	public File getDirectory() {
		return tmpDir;
	}

	private File createTempDir(String prefix, String suffix, File dir) {
		File tempdir = null;
		try {
			if (dir == null)
				tempdir = File.createTempFile(prefix, suffix);
			else
				tempdir = File.createTempFile(prefix, suffix, dir);
			tempdir.delete();
			tempdir.mkdir();
		} catch (IOException ex) {
			VKCLogManager.errorLog(this, "", ex.getMessage(),ex);
		}
		return tempdir;
	}

	/**
	 * create a temporary directory in the specified directory
	 * @param prefix
	 * @param suffix
	 * @param dir
	 */
	/*
	private File createRandomDir(String prefix, String suffix, File dir) {
	
		File tempDir = null;
	
		try {
	
			Random random = new Random(); // seeded from the clock
	
			do {
				int randomNumber = (random.nextInt() & Integer.MAX_VALUE) % 90000000 + 10000000;
				tempDir = new File(dir.getCanonicalPath() + File.separator + prefix + Integer.toString(randomNumber) + suffix);
			} while (tempDir.exists());
	
			tempDir.mkdir();
			
			if(debug)System.out.println("temp dir created:"+tempDir.getCanonicalPath());
	
		} catch (Exception ex) {
			if(debug)System.out.println("" + ex);
			tempDir = null;
		}
		
		return tempDir;
	}*/

	/**
	 * create a temporary directory under the system temporary directory
	 * @param prefix
	 * @param suffix
	 * @return
	 */
	/*
	private File createRandomDir(String prefix, String suffix) {
		try {
	
			File tempFile = File.createTempFile(prefix, suffix);
			String tempPath = tempFile.getParent();
	
			return createRandomDir(prefix, suffix, new File(tempPath));
	
		} catch (Exception ex) {
			if(debug)System.out.println("" + ex);
		}
		return null;
	}*/

}
