001: // Copyright © 2006-2007 ASERT. Released under the Canoo Webtest license.
002: package com.canoo.webtest.plugins.emailtest;
003:
004: import java.io.IOException;
005: import java.util.regex.Matcher;
006: import java.util.regex.Pattern;
007: import java.util.StringTokenizer;
008: import java.util.Enumeration;
009:
010: import javax.mail.Message;
011: import javax.mail.MessagingException;
012: import javax.mail.Multipart;
013: import javax.mail.Part;
014: import javax.mail.Header;
015:
016: import org.apache.log4j.Logger;
017: import org.apache.commons.lang.StringUtils;
018:
019: /**
020: * Returns the message structure.
021: *
022: * @author Paul King, ASERT
023: * @webtest.step category="Email"
024: * name="emailMessageStructureFilter"
025: * description="Returns the structure (expressed in XML) associated with a particular message as the current response."
026: */
027: public class EmailMessageStructureFilter extends AbstractEmailFilter {
028: private static final Logger LOG = Logger
029: .getLogger(EmailMessageStructureFilter.class);
030: private static final String LS = System
031: .getProperty("line.separator");
032: private String fHeaders;
033: private String[] fTokenizedHeaders;
034:
035: public String getHeaders() {
036: return fHeaders;
037: }
038:
039: /**
040: * @webtest.parameter
041: * required="no"
042: * default="no headers"
043: * description="A comma or space seperated list of headers to include in the structure description."
044: */
045: public void setHeaders(final String headers) {
046: fHeaders = headers;
047: }
048:
049: protected void filterContent(final Message message)
050: throws MessagingException {
051: if (!StringUtils.isEmpty(getHeaders())) {
052: prepareHeaders();
053: }
054: try {
055: final Object content = message.getContent();
056: if (content instanceof Multipart) {
057: filterMultiPartMessage(content, message);
058: return;
059: }
060: filterSimpleMessage((String) content, message);
061: } catch (IOException e) {
062: LOG.error("Error processing email message: ", e);
063: throw new MessagingException(
064: "Error processing email message: " + e.getMessage());
065: }
066: }
067:
068: private void prepareHeaders() {
069: final StringTokenizer tokens = new StringTokenizer(
070: getHeaders(), " ,");
071: fTokenizedHeaders = new String[tokens.countTokens()];
072: for (int i = 0; i < fTokenizedHeaders.length; i++) {
073: fTokenizedHeaders[i] = tokens.nextToken();
074: }
075: }
076:
077: private void filterMultiPartMessage(final Object content,
078: final Message message) throws MessagingException {
079: final Multipart parts = (Multipart) content;
080: final StringBuffer buf = new StringBuffer();
081: buf.append("<message type=\"MIME\" contentType=\"");
082: buf.append(extractBaseContentType(message.getContentType()))
083: .append("\">").append(LS);
084: processHeaders(buf, message);
085: int count = parts.getCount();
086: for (int i = 0; i < count; i++) {
087: buf.append(processMessagePart(parts.getBodyPart(i)));
088: }
089: buf.append("</message>");
090: defineAsCurrentResponse(buf.toString().getBytes(), "text/xml");
091: }
092:
093: private void processHeaders(final StringBuffer buf,
094: final Message message) throws MessagingException {
095: if (fTokenizedHeaders != null) {
096: final Enumeration allHeaders = message.getAllHeaders();
097: while (allHeaders.hasMoreElements()) {
098: final Header header = (Header) allHeaders.nextElement();
099: if (headerIsRequired(header)) {
100: buf.append(processHeader(header));
101: }
102: }
103: }
104: }
105:
106: private boolean headerIsRequired(final Header header) {
107: for (int i = 0; i < fTokenizedHeaders.length; i++) {
108: if (fTokenizedHeaders[i].equalsIgnoreCase(header.getName())) {
109: return true;
110: }
111: }
112: return false;
113: }
114:
115: private static String processHeader(final Header h) {
116: return " <header name=\"" + h.getName() + "\" value=\""
117: + h.getValue() + "\"/>" + LS;
118: }
119:
120: private void filterSimpleMessage(final String content,
121: final Message message) throws MessagingException {
122: final StringBuffer buf = new StringBuffer(
123: "<message type=\"Simple\" contentType=\"");
124: buf.append(extractBaseContentType(message.getContentType()))
125: .append("\">").append(LS);
126: processHeaders(buf, message);
127: appendUuencodedAttachments(buf, content);
128: buf.append("</message>");
129: defineAsCurrentResponse(buf.toString(), "text/xml");
130: }
131:
132: private static void appendUuencodedAttachments(
133: final StringBuffer buf, final String content) {
134: // iterate over string looking for ^begin ddd$
135: final String lineStr = "(^.*$)";
136: final String startUuencodeStr = "begin \\d\\d\\d .*";
137: final Pattern linePattern = Pattern.compile(lineStr,
138: Pattern.MULTILINE);
139: final Matcher matcher = linePattern.matcher(content);
140: while (matcher.find()) {
141: final String line = matcher.group(0);
142: if (line.matches(startUuencodeStr)) {
143: final int lastSpace = line.lastIndexOf(" ");
144: final String filename = line.substring(lastSpace + 1);
145: buf.append(" <part type=\"uuencoded\" filename=\"");
146: buf.append(filename).append("\"/>").append(LS);
147: }
148: }
149: }
150:
151: private static String processMessagePart(final Part part)
152: throws MessagingException {
153: final String disp = part.getDisposition();
154: final String contentType = part.getContentType();
155: if (Part.ATTACHMENT.equals(disp)) {
156: return " <part type=\"attachment\" filename=\""
157: + part.getFileName() + "\" contentType=\""
158: + extractBaseContentType(contentType) + "\"/>" + LS;
159: }
160: return " <part type=\"inline\" contentType=\""
161: + extractBaseContentType(contentType) + "\"/>" + LS;
162: }
163:
164: private static String extractBaseContentType(final String orig) {
165: final int colonStart = orig.indexOf(";");
166: if (colonStart == -1) {
167: return orig;
168: } else {
169: return orig.substring(0, colonStart);
170: }
171: }
172:
173: }
|