View Javadoc
1   package org.nhindirect.gateway.util;
2   
3   import java.util.Collection;
4   import java.util.Locale;
5   import java.util.Map;
6   
7   import javax.mail.Address;
8   import javax.mail.MessagingException;
9   import javax.mail.internet.InternetAddress;
10  import javax.mail.internet.MimeMessage;
11  
12  import org.nhindirect.common.mail.SMTPMailMessage;
13  import org.nhindirect.common.rest.exceptions.ServiceException;
14  import org.nhindirect.common.tx.TxDetailParser;
15  import org.nhindirect.common.tx.TxService;
16  import org.nhindirect.common.tx.TxUtil;
17  import org.nhindirect.common.tx.model.Tx;
18  import org.nhindirect.common.tx.model.TxDetail;
19  import org.nhindirect.common.tx.model.TxDetailType;
20  import org.nhindirect.stagent.AddressSource;
21  import org.nhindirect.stagent.NHINDAddress;
22  import org.nhindirect.stagent.NHINDAddressCollection;
23  import org.nhindirect.stagent.NHINDAgent;
24  import org.nhindirect.stagent.cryptography.SMIMEStandard;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  /**
29   * Common methods used for inspecting and gathering information about messages
30   * @author Greg Meyer
31   * @Since 6.0
32   */
33  public class MessageUtils
34  {
35  	private static final Logger LOGGER = LoggerFactory.getLogger(MessageUtils.class);	
36  	
37  	/**
38  	 * Gets the sender of the message.
39  	 * @param mail The mail object to get the mail information from.
40  	 * @return The sender of the message.
41  	 * @throws MessagingException
42  	 */
43  	public static NHINDAddress getMailSender(SMTPMailMessage mail) throws MessagingException
44  	{
45  		// get the sender
46  		final InternetAddress senderAddr = getSender(mail);
47  		if (senderAddr == null)
48  			throw new MessagingException("Failed to process message.  The sender cannot be null or empty.");
49  						
50  			// not the best way to do this
51  		return new NHINDAddress(senderAddr, AddressSource.From);
52  	}
53  	
54  	/**
55  	 * Gets the sender attribute of a Mail message
56  	 * @param mail The message to retrive the sender from
57  	 * @return The message sender.
58  	 */
59  	public static InternetAddress getSender(SMTPMailMessage mail) 
60  	{
61  		InternetAddress retVal = null;
62  		
63  		if (mail.getMailFrom() != null)
64  			retVal = mail.getMailFrom();	
65  		else
66  		{
67  			// try to get the sender from the message
68  			Address[] senderAddr = null;
69  			try
70  			{
71  				if (mail.getMimeMessage() == null)
72  					return null;
73  				
74  				senderAddr = mail.getMimeMessage().getFrom();
75  				if (senderAddr == null || senderAddr.length == 0)
76  					return null;
77  			}
78  			catch (MessagingException e)
79  			{
80  				return null;
81  			}
82  						
83  			// not the best way to do this
84  			retVal = (InternetAddress)senderAddr[0];	
85  		}
86  	
87  		return retVal;
88  	}	
89  	
90  	/**
91  	 * Get the recipients of a message by retrieving the recipient list from the SMTP envelope first, then falling back to the recipients
92  	 * in the message if the recipients cannot be retrieved from the SMTP envelope.
93  	 * @param mail The mail object that contains information from the SMTP envelope.
94  	 * @return Collection of message recipients.
95  	 * @throws MessagingException
96  	 */
97  	public static NHINDAddressCollection getMailRecipients(SMTPMailMessage mail) throws MessagingException
98  	{
99  		final NHINDAddressCollection recipients = new NHINDAddressCollection();		
100 		
101 		// uses the RCPT TO commands
102 		final Collection<InternetAddress> recips = mail.getRecipientAddresses();
103 		if (recips == null || recips.size() == 0)
104 		{
105 			// fall back to the mime message list of recipients
106 			final Address[] recipsAddr = mail.getMimeMessage().getAllRecipients();
107 			for (Address addr : recipsAddr)
108 			{
109 				recipients.add(new NHINDAddress(addr.toString(), (AddressSource)null));
110 			}
111 		}
112 		else
113 			for (InternetAddress addr : recips)
114 				recipients.add(new NHINDAddress(addr));
115 
116 		return recipients;
117 	}	
118 	
119 	/**
120 	 * Determines if a message is incoming or outgoing based on the domains available in the configured agent
121 	 * and the sender of the message.
122 	 * @param msg The message that is being processed.
123 	 * @param sender The sender of the message.
124 	 * @param agent The STA that contains the available domains.
125 	 * @return true if the message is determined to be outgoing; false otherwise
126 	 */
127 	public static boolean isOutgoing(MimeMessage msg, NHINDAddress sender, NHINDAgent agent)
128 	{		
129 		if (agent == null || agent.getDomains() == null)
130 			return false;
131 		
132 		// if the sender is not from our domain, then is has to be an incoming message
133 		if (!sender.isInDomain(agent.getDomains()))
134 			return false;
135 		else
136 		{
137 			// depending on the SMTP stack configuration, a message with a sender from our domain
138 			// may still be an incoming message... check if the message is encrypted
139 			if (SMIMEStandard.isEncrypted(msg))
140 			{
141 				return false;
142 			}
143 		}
144 		
145 		return true;
146 	}	
147 	
148 	/**
149 	 * Creates a trackable monitoring object for a message. 
150 	 * @param msg The message that is being processed
151 	 * @param sender The sender of the message
152 	 * @param recipients The message recipients
153 	 * @param txParser Parser to extract Tx details from the memssage.
154 	 * @return A trackable Tx object.
155 	 */
156 	public static Tx getTxToTrack(MimeMessage msg, NHINDAddress sender, NHINDAddressCollection recipients, TxDetailParser txParser)
157 	{		
158 		if (txParser == null)
159 			return null;
160 				
161 		try
162 		{	
163 			
164 			final Map<String, TxDetail> details = txParser.getMessageDetails(msg);
165 			
166 			if (sender != null)
167 				details.put(TxDetailType.FROM.getType(), new TxDetail(TxDetailType.FROM, sender.getAddress().toLowerCase(Locale.getDefault())));
168 			if (recipients != null && !recipients.isEmpty())
169 				details.put(TxDetailType.RECIPIENTS.getType(), new TxDetail(TxDetailType.RECIPIENTS, recipients.toString().toLowerCase(Locale.getDefault())));
170 			
171 			
172 			return new Tx(TxUtil.getMessageType(msg), details);
173 		}
174 		///CLOVER:OFF
175 		catch (Exception e)
176 		{
177 			LOGGER.warn("Failed to parse message to Tx object.", e);
178 			return null;
179 		}
180 		///CLOVER:ON
181 	}	
182 	
183 	/**
184 	 * 
185 	 * Determine if the recipient has been rejected
186 	 * 
187 	 * @param rctpAdd
188 	 * @param rejectedRecips
189 	 * @return
190 	 */
191 	public static boolean isRcptRejected(InternetAddress rctpAdd, NHINDAddressCollection rejectedRecips)
192 	{
193 		for (NHINDAddress rejectedRecip : rejectedRecips)
194 			if (rejectedRecip.getAddress().equals(rctpAdd.toString()))
195 				return true;
196 		
197 		return false;
198 	}	
199 	
200 	/**
201 	 * Tracks message that meet the following qualifications
202 	 * <br>
203 	 * 1. Outgoing IMF message
204 	 * @param tx The message to monitor and track
205 	 * @param isOutgoing Indicates the message direction: incoming or outgoing
206 	 * @param txService the tracking service
207 	 */
208 	@SuppressWarnings("incomplete-switch")
209 	public static void trackMessage(Tx tx, boolean isOutgoing, TxService txService)
210 	{
211 		// only track the following message..
212 		// 1. Outgoing IMF message
213 		boolean track = false;
214 		if (tx != null)
215 		{
216 			switch (tx.getMsgType())
217 			{
218 				case IMF:
219 				{
220 					track = isOutgoing;
221 					break;
222 				}
223 			}
224 		}
225 		
226 		if (track)
227 		{
228 			try
229 			{
230 				txService.trackMessage(tx);
231 			}
232 			catch (ServiceException ex)
233 			{
234 				LOGGER.warn("Failed to submit message to monitoring service.", ex);
235 			}
236 		}
237 		
238 	}	
239 }