// Copyright � 2006-2007 ASERT. Released under the Canoo Webtest license. package com.canoo.webtest.plugins.emailtest; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.StringTokenizer; import java.util.Enumeration; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.Header; import org.apache.log4j.Logger; import org.apache.commons.lang.StringUtils; /** * Returns the message structure. * * @author Paul King, ASERT * @webtest.step category="Email" * name="emailMessageStructureFilter" * description="Returns the structure (expressed in XML) associated with a particular message as the current response." */ public class EmailMessageStructureFilter extends AbstractEmailFilter { private static final Logger LOG = Logger.getLogger(EmailMessageStructureFilter.class); private static final String LS = System.getProperty("line.separator"); private String fHeaders; private String[] fTokenizedHeaders; public String getHeaders() { return fHeaders; } /** * @webtest.parameter * required="no" * default="no headers" * description="A comma or space seperated list of headers to include in the structure description." */ public void setHeaders(final String headers) { fHeaders = headers; } protected void filterContent(final Message message) throws MessagingException { if (!StringUtils.isEmpty(getHeaders())) { prepareHeaders(); } try { final Object content = message.getContent(); if (content instanceof Multipart) { filterMultiPartMessage(content, message); return; } filterSimpleMessage((String) content, message); } catch (IOException e) { LOG.error("Error processing email message: ", e); throw new MessagingException("Error processing email message: " + e.getMessage()); } } private void prepareHeaders() { final StringTokenizer tokens = new StringTokenizer(getHeaders(), " ,"); fTokenizedHeaders = new String[tokens.countTokens()]; for (int i = 0; i < fTokenizedHeaders.length; i++) { fTokenizedHeaders[i] = tokens.nextToken(); } } private void filterMultiPartMessage(final Object content, final Message message) throws MessagingException { final Multipart parts = (Multipart) content; final StringBuffer buf = new StringBuffer(); buf.append("<message type=\"MIME\" contentType=\""); buf.append(extractBaseContentType(message.getContentType())).append("\">").append(LS); processHeaders(buf, message); int count = parts.getCount(); for (int i = 0; i < count; i++) { buf.append(processMessagePart(parts.getBodyPart(i))); } buf.append("</message>"); defineAsCurrentResponse(buf.toString().getBytes(), "text/xml"); } private void processHeaders(final StringBuffer buf, final Message message) throws MessagingException { if (fTokenizedHeaders != null) { final Enumeration allHeaders = message.getAllHeaders(); while (allHeaders.hasMoreElements()) { final Header header = (Header) allHeaders.nextElement(); if (headerIsRequired(header)) { buf.append(processHeader(header)); } } } } private boolean headerIsRequired(final Header header) { for (int i = 0; i < fTokenizedHeaders.length; i++) { if (fTokenizedHeaders[i].equalsIgnoreCase(header.getName())) { return true; } } return false; } private static String processHeader(final Header h) { return " <header name=\"" + h.getName() + "\" value=\"" + h.getValue() + "\"/>" + LS; } private void filterSimpleMessage(final String content, final Message message) throws MessagingException { final StringBuffer buf = new StringBuffer("<message type=\"Simple\" contentType=\""); buf.append(extractBaseContentType(message.getContentType())).append("\">").append(LS); processHeaders(buf, message); appendUuencodedAttachments(buf, content); buf.append("</message>"); defineAsCurrentResponse(buf.toString(), "text/xml"); } private static void appendUuencodedAttachments(final StringBuffer buf, final String content) { // iterate over string looking for ^begin ddd$ final String lineStr = "(^.*$)"; final String startUuencodeStr = "begin \\d\\d\\d .*"; final Pattern linePattern = Pattern.compile(lineStr, Pattern.MULTILINE); final Matcher matcher = linePattern.matcher(content); while (matcher.find()) { final String line = matcher.group(0); if (line.matches(startUuencodeStr)) { final int lastSpace = line.lastIndexOf(" "); final String filename = line.substring(lastSpace + 1); buf.append(" <part type=\"uuencoded\" filename=\""); buf.append(filename).append("\"/>").append(LS); } } } private static String processMessagePart(final Part part) throws MessagingException { final String disp = part.getDisposition(); final String contentType = part.getContentType(); if (Part.ATTACHMENT.equals(disp)) { return " <part type=\"attachment\" filename=\"" + part.getFileName() + "\" contentType=\"" + extractBaseContentType(contentType) + "\"/>" + LS; } return " <part type=\"inline\" contentType=\"" + extractBaseContentType(contentType) + "\"/>" + LS; } private static String extractBaseContentType(final String orig) { final int colonStart = orig.indexOf(";"); if (colonStart == -1) { return orig; } else { return orig.substring(0, colonStart); } } }