All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nhindirect.common.tx.impl.DefaultTxDetailParser Maven / Gradle / Ivy

/* 
Copyright (c) 2010, NHIN Direct Project
All rights reserved.

Authors:
   Greg Meyer      [email protected]
 
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 
in the documentation and/or other materials provided with the distribution.  Neither the name of the The NHIN Direct Project (nhindirect.org). 
nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.nhindirect.common.tx.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nhindirect.common.mail.MDNStandard;
import org.nhindirect.common.mail.MailStandard;
import org.nhindirect.common.mail.MailUtil;
import org.nhindirect.common.mail.dsn.DSNStandard;
import org.nhindirect.common.tx.TxDetailParser;
import org.nhindirect.common.tx.TxUtil;
import org.nhindirect.common.tx.model.TxDetail;
import org.nhindirect.common.tx.model.TxDetailType;
import org.nhindirect.common.tx.model.TxMessageType;

import com.sun.mail.dsn.DeliveryStatus;

public class DefaultTxDetailParser implements TxDetailParser
{
	private static final Log LOGGER = LogFactory.getFactory().getInstance(DefaultTxDetailParser.class);
	
	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Map getMessageDetails(InternetHeaders headers) 
	{
		Map retVal = null;
		
		try
		{
			// convert into a MimeMessage with only the headers
			final MimeMessage msg = new MimeMessage((Session)null);
			
			final Enumeration henum = headers.getAllHeaderLines();
			while (henum.hasMoreElements())
				msg.addHeaderLine(henum.nextElement());
			
			retVal = getMessageDetails(msg);
		}
		///CLOVER:OFF		
		catch (MessagingException e)
		{			

			LOGGER.warn("Failed to translate headers to MimeMessage.", e);

		}
		///CLOVER:ON
		
		return retVal;
	}

	public Map getMessageDetails(InputStream stream)
	{
		Map retVal = null;
		
		if (stream == null)
			throw new IllegalArgumentException("Input stream cannot be null");
		
		try
		{
			// convert into a MimeMessage
			final MimeMessage msg = new MimeMessage(null, stream);
			
			retVal = getMessageDetails(msg);
		}
		///CLOVER:OFF		
		catch (MessagingException e)
		{			

			LOGGER.warn("Failed to translate input stream into MimeMessage.", e);

		}
		///CLOVER:ON
		
		return retVal;		
	}
	
	@SuppressWarnings("incomplete-switch")
	@Override
	public Map getMessageDetails(MimeMessage msg) 
	{
		Map retVal = new HashMap();
		
		// get the message id
		final String msgId = MailStandard.getHeader(msg, MailStandard.Headers.MessageID);
		if (!msgId.isEmpty())
			retVal.put(TxDetailType.MSG_ID.getType(), new TxDetail(TxDetailType.MSG_ID.getType(), msgId));
		
		// get the subject
		final String subject = MailStandard.getHeader(msg, MailStandard.Headers.Subject);
		if (!subject.isEmpty())
			retVal.put(TxDetailType.SUBJECT.getType(), new TxDetail(TxDetailType.SUBJECT.getType(), subject));
		
		// get the full headers as a string
		final String fullHeaders = getHeadersAsStringInternal(msg);
		if (!fullHeaders.isEmpty())
			retVal.put(TxDetailType.MSG_FULL_HEADERS.getType(), new TxDetail(TxDetailType.MSG_FULL_HEADERS.getType(), fullHeaders));		

		// get the from addresses
		try
		{			
			final String from = MailStandard.getHeader(msg, MailStandard.Headers.From);
			if (!from.isEmpty())
			{
				StringBuilder builder = new StringBuilder();
				
				int cnt = 0;
				for (InternetAddress addr :  (InternetAddress[])msg.getFrom())
				{
					// comma delimit multiple addresses
					if (cnt > 0)
						builder.append(",");
					
					builder.append(addr.getAddress().toLowerCase(Locale.getDefault()));
					++cnt;
				}
				
				retVal.put(TxDetailType.FROM.getType(),new TxDetail(TxDetailType.FROM.getType(), builder.toString()));
			}
		}
		/// CLOVER:OFF
		catch (MessagingException e)
		{
			LOGGER.warn("Failed to retrieve message sender list.", e);
		}
		/// CLOVER:ON
		
		// get the sender if it exists
		try
		{
			final InternetAddress sender = (InternetAddress)msg.getSender();
			if (sender != null)
				retVal.put(TxDetailType.SENDER.getType(), new TxDetail(TxDetailType.SENDER.toString(), sender.getAddress().toLowerCase(Locale.getDefault())));
				
		}
		/// CLOVER:OFF
		catch (MessagingException e)
		{
			LOGGER.warn("Failed to retrieve message sender", e);
		}		
		/// CLOVER:ON
		
		// get the recipient addresses
		try
		{			
			if (msg.getAllRecipients() != null)
			{
				StringBuilder builder = new StringBuilder();
				
				int cnt = 0;
				
				for (Address addr :  msg.getAllRecipients())
				{
					// comma delimit multiple addresses
					if (cnt > 0)
						builder.append(",");
					
					
					if (addr instanceof InternetAddress)
						builder.append(((InternetAddress)addr).getAddress().toLowerCase(Locale.getDefault()));
					++cnt;
				}
				
				retVal.put(TxDetailType.RECIPIENTS.getType(), new TxDetail(TxDetailType.RECIPIENTS.getType(), builder.toString()));
			}
		}
		/// CLOVER:OFF
		catch (MessagingException e)
		{
			LOGGER.warn("Failed to retrieve message recipient list.", e);
		}
		/// CLOVER:ON
		
		// get the message type
		final TxMessageType messageType = TxUtil.getMessageType(msg);
		if (messageType != TxMessageType.UNKNOWN)
		{
			//retVal.put(HEMCTxConstants.MESSAGE_TYPE, messageType);
			
			switch (messageType)
			{
				case MDN: 
				{
					// the disposition if a field in the second part of the MDN message
					final String disposition = MDNStandard.getMDNField(msg, MDNStandard.Headers.Disposition);
					if (!disposition.isEmpty())
						retVal.put(TxDetailType.DISPOSITION.getType(), new TxDetail(TxDetailType.DISPOSITION.getType(), disposition.toLowerCase(Locale.getDefault())));
					
					// the final recipients is a field in the second part of the MDN message
					final String finalRecipient = MDNStandard.getMDNField(msg, MDNStandard.Headers.FinalRecipient);
					if (!finalRecipient.isEmpty())
						retVal.put(TxDetailType.FINAL_RECIPIENTS.getType(), new TxDetail(TxDetailType.FINAL_RECIPIENTS.getType(), finalRecipient.toLowerCase(Locale.getDefault())));
					
					// the original message id if a field in the second part of the MDN message
					String origMsgId = MDNStandard.getMDNField(msg, MDNStandard.Headers.OriginalMessageID);
					
					if (origMsgId.isEmpty())
					{
						// it might be in a reply to header
						origMsgId = MailStandard.getHeader(msg, MailStandard.Headers.InReplyTo);
					}
					
					if (!origMsgId.isEmpty())
						retVal.put(TxDetailType.PARENT_MSG_ID.getType(), new TxDetail(TxDetailType.PARENT_MSG_ID.getType(), origMsgId));
					
					// check for X-DIRECT-FINAL-DESTINATION-DELIVER extension
					try
					{
						final InternetHeaders mdnHeaders = MDNStandard.getNotificationFieldsAsHeaders(msg);
						if (mdnHeaders.getHeader(MDNStandard.DispositionOption_TimelyAndReliable, ",") != null)
						{
							retVal.put(TxDetailType.DISPOSITION_OPTIONS.getType(), 
									new TxDetail(TxDetailType.DISPOSITION_OPTIONS.getType(), MDNStandard.DispositionOption_TimelyAndReliable));	
						}
					}
					// CLOVER:OFF
					catch (Exception e)
					{
						LOGGER.warn("Failed to retrieve MDN headers from message.  Message may not be an MDN message.", e);
					}
					// CLOVER:ON
					break;
				}
				case DSN:
				{
					// DSN messages do not necessarily have the original message id... 
					// the Original-Envelope-ID header does not reflect the message id
					try
					{
						final DeliveryStatus status = new DeliveryStatus(new ByteArrayInputStream(MailUtil.serializeToBytes(msg)));
						retVal.put(TxDetailType.FINAL_RECIPIENTS.getType(), new TxDetail(TxDetailType.FINAL_RECIPIENTS.getType(), 
								DSNStandard.getFinalRecipients(status).toLowerCase(Locale.getDefault())));
						// check at the message level
						boolean parentFound = false;
						
						
						final String origMsgId = DSNStandard.getHeaderValueFromDeliveryStatus(status, DSNStandard.Headers.OriginalMessageID);
						if (!origMsgId.isEmpty())
						{
						    parentFound = true;
						    retVal.put(TxDetailType.PARENT_MSG_ID.getType(), new TxDetail(TxDetailType.PARENT_MSG_ID, origMsgId));
						}
						
						if (!parentFound)
						{
							// it might be in a reply to header
							final String parentMsgId = MailStandard.getHeader(msg, MailStandard.Headers.InReplyTo);
							if (!parentMsgId.isEmpty())
								retVal.put(TxDetailType.PARENT_MSG_ID.getType(), new TxDetail(TxDetailType.PARENT_MSG_ID.getType(), parentMsgId));
							
						}
						
						// get the action
						final String action = DSNStandard.getHeaderValueFromDeliveryStatus(status, DSNStandard.Headers.Action);
						if (!action.isEmpty())
							retVal.put(TxDetailType.DSN_ACTION.getType(), new TxDetail(TxDetailType.DSN_ACTION.getType(), action.toLowerCase(Locale.getDefault())));
						
						// get the status
						final String dsnStatus = DSNStandard.getHeaderValueFromDeliveryStatus(status, DSNStandard.Headers.Status);
						if (!dsnStatus.isEmpty())
							retVal.put(TxDetailType.DSN_STATUS.getType(), new TxDetail(TxDetailType.DSN_STATUS.getType(), dsnStatus.toLowerCase(Locale.getDefault())));
					}
					///CLOVER:OFF
					catch (Exception e) 
					{
						LOGGER.warn("Could not get a requested field from the DSN message", e);
					}
					///CLOVER:ON
					break;
				}
			}
		}
		
		// check for the existence of disposition request options
		final String dispOption = MailStandard.getHeader(msg, MDNStandard.Headers.DispositionNotificationOptions);
		if (!dispOption.isEmpty())
			retVal.put(TxDetailType.DISPOSITION_OPTIONS.getType(), 
					new TxDetail(TxDetailType.DISPOSITION_OPTIONS.getType(), dispOption.toLowerCase(Locale.getDefault())));		
		
		return retVal;
	}
	
	protected String getHeadersAsStringInternal(MimeMessage msg)
	{
		return getHeadersAsString(msg);
	}
	
	@SuppressWarnings("unchecked")
	public static String getHeadersAsString(MimeMessage msg)
	{
		StringBuilder builder = new StringBuilder();
		
		try
		{
			Enumeration headers = msg.getAllHeaderLines();
			while (headers.hasMoreElements())
				builder.append(headers.nextElement()).append("\r\n");
		}
		///CLOVER:OFF
		catch (MessagingException e)
		{
			// According to most SE runtimes, getAllHeaderLines will never thrown a MessagingException

			LOGGER.warn("Failed to builder message summary.", e);

		}
		///CLOVER:ON
		return builder.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy