You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by an...@apache.org on 2003/08/21 18:15:56 UTC
cvs commit: ant/src/testcases/org/apache/tools/mail MailMessageTest.java
antoine 2003/08/21 09:15:56
Modified: . WHATSNEW
src/main/org/apache/tools/mail MailMessage.java
Added: src/testcases/org/apache/tools/mail MailMessageTest.java
Log:
Prevent empty headers from being sent in plain mail messages.
Make the order of the headers of plain mail predictable by using
two parallel vectors instead of a hashset to store the headers internally.
Style corrections
PR: 22088
Submitted by: Michael Davey (michael dot davey at coderage dot org)
Revision Changes Path
1.487 +5 -0 ant/WHATSNEW
Index: WHATSNEW
===================================================================
RCS file: /home/cvs/ant/WHATSNEW,v
retrieving revision 1.486
retrieving revision 1.487
diff -u -r1.486 -r1.487
--- WHATSNEW 21 Aug 2003 15:26:46 -0000 1.486
+++ WHATSNEW 21 Aug 2003 16:15:55 -0000 1.487
@@ -405,6 +405,11 @@
or (name) address@xyz.com
Bugzilla Report 22474.
+* <mail> (version PlainMail)
+ prevent blank headers from being sent,
+ make the order of the headers of plain mail messages predictable
+ Bugzilla Report 22088.
+
* <zipfileset> can now be defined in the main body of a project
and referred to with refid="xyz". Bugzilla Report 17007.
1.18 +65 -31 ant/src/main/org/apache/tools/mail/MailMessage.java
Index: MailMessage.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/mail/MailMessage.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- MailMessage.java 19 Jul 2003 11:20:23 -0000 1.17
+++ MailMessage.java 21 Aug 2003 16:15:55 -0000 1.18
@@ -69,7 +69,6 @@
import java.net.Socket;
import java.net.InetAddress;
import java.util.Vector;
-import java.util.Hashtable;
import java.util.Enumeration;
/**
@@ -131,6 +130,9 @@
*/
public class MailMessage {
+ /** default mailhost */
+ public static final String DEFAULT_HOST = "localhost";
+
/** default port for SMTP: 25 */
public static final int DEFAULT_PORT = 25;
@@ -153,13 +155,22 @@
private Vector cc;
/** headers to send in the mail */
- private Hashtable headers;
+ private Vector headersKeys;
+ private Vector headersValues;
private MailPrintStream out;
private SmtpResponseReader in;
private Socket socket;
+ private static final int OK_READY = 220;
+ private static final int OK_HELO = 250;
+ private static final int OK_FROM = 250;
+ private static final int OK_RCPT_1 = 250;
+ private static final int OK_RCPT_2 = 251;
+ private static final int OK_DATA = 354;
+ private static final int OK_DOT = 250;
+ private static final int OK_QUIT = 221;
/**
* Constructs a new MailMessage to send an email.
@@ -168,7 +179,7 @@
* @exception IOException if there's any problem contacting the mail server
*/
public MailMessage() throws IOException {
- this("localhost", DEFAULT_PORT);
+ this(DEFAULT_HOST, DEFAULT_PORT);
}
/**
@@ -179,7 +190,7 @@
* @exception IOException if there's any problem contacting the mail server
*/
public MailMessage(String host) throws IOException {
- this(host, DEFAULT_PORT);
+ this(host, DEFAULT_PORT);
}
/**
@@ -196,8 +207,8 @@
replyto = new Vector();
to = new Vector();
cc = new Vector();
- headers = new Hashtable();
- setHeader("X-Mailer", "org.apache.tools.mail.MailMessage (ant.apache.org)");
+ headersKeys = new Vector();
+ headersValues = new Vector();
connect();
sendHelo();
}
@@ -214,7 +225,7 @@
/**
* Sets the from address. Also sets the "From" header. This method should
* be called only once.
- *
+ * @param from the from address
* @exception IOException if there's any problem reported by the mail server
*/
public void from(String from) throws IOException {
@@ -226,6 +237,7 @@
* Sets the replyto address
* This method may be
* called multiple times.
+ * @param rto the replyto address
*
*/
public void replyto(String rto) {
@@ -236,6 +248,7 @@
* Sets the to address. Also sets the "To" header. This method may be
* called multiple times.
*
+ * @param to the to address
* @exception IOException if there's any problem reported by the mail server
*/
public void to(String to) throws IOException {
@@ -247,6 +260,7 @@
* Sets the cc address. Also sets the "Cc" header. This method may be
* called multiple times.
*
+ * @param cc the cc address
* @exception IOException if there's any problem reported by the mail server
*/
public void cc(String cc) throws IOException {
@@ -258,6 +272,7 @@
* Sets the bcc address. Does NOT set any header since it's a *blind* copy.
* This method may be called multiple times.
*
+ * @param bcc the bcc address
* @exception IOException if there's any problem reported by the mail server
*/
public void bcc(String bcc) throws IOException {
@@ -268,50 +283,69 @@
/**
* Sets the subject of the mail message. Actually sets the "Subject"
* header.
+ * @param subj the subject of the mail message
*/
public void setSubject(String subj) {
- headers.put("Subject", subj);
+ setHeader("Subject", subj);
}
/**
* Sets the named header to the given value. RFC 822 provides the rules for
* what text may constitute a header name and value.
+ * @param name name of the header
+ * @param value contents of the header
*/
public void setHeader(String name, String value) {
// Blindly trust the user doesn't set any invalid headers
- headers.put(name, value);
+ headersKeys.add(name);
+ headersValues.add(value);
}
/**
* Returns a PrintStream that can be used to write the body of the message.
- * A stream is used since email bodies are byte-oriented. A writer could
+ * A stream is used since email bodies are byte-oriented. A writer can
* be wrapped on top if necessary for internationalization.
+ * This is actually done in Message.java
*
+ * @return a printstream containing the data and the headers of the email
* @exception IOException if there's any problem reported by the mail server
+ * @see org.apache.tools.ant.taskdefs.email.Message
*/
public PrintStream getPrintStream() throws IOException {
setFromHeader();
setReplyToHeader();
setToHeader();
setCcHeader();
+ setHeader("X-Mailer", "org.apache.tools.mail.MailMessage (ant.apache.org)");
sendData();
flushHeaders();
return out;
}
+
+ // RFC 822 s4.1: "From:" header must be sent
+ // We rely on error checking by the MTA
void setFromHeader() {
setHeader("From", from);
}
+ // RFC 822 s4.1: "Reply-To:" header is optional
void setReplyToHeader() {
+ if (!replyto.isEmpty()) {
setHeader("Reply-To", vectorToList(replyto));
+ }
}
+
void setToHeader() {
- setHeader("To", vectorToList(to));
+ if (!to.isEmpty()) {
+ setHeader("To", vectorToList(to));
+ }
}
void setCcHeader() {
- setHeader("Cc", vectorToList(cc));
+ if (!cc.isEmpty()) {
+ setHeader("Cc", vectorToList(cc));
+ }
}
String vectorToList(Vector v) {
@@ -327,11 +361,13 @@
}
void flushHeaders() throws IOException {
- // XXX Should I care about order here?
- Enumeration e = headers.keys();
- while (e.hasMoreElements()) {
- String name = (String) e.nextElement();
- String value = (String) headers.get(name);
+ // RFC 822 s4.1:
+ // "Header fields are NOT required to occur in any particular order,
+ // except that the message body MUST occur AFTER the headers"
+ // (the same section specifies a reccommended order, which we ignore)
+ for (int i = 0; i < headersKeys.size(); i++) {
+ String name = (String) headersKeys.elementAt(i);
+ String value = (String) headersValues.elementAt(i);
out.println(name + ": " + value);
}
out.println();
@@ -400,41 +436,38 @@
void getReady() throws IOException {
String response = in.getResponse();
- int[] ok = {220};
+ int[] ok = {OK_READY};
if (!isResponseOK(response, ok)) {
throw new IOException(
"Didn't get introduction from server: " + response);
}
}
-
void sendHelo() throws IOException {
String local = InetAddress.getLocalHost().getHostName();
- int[] ok = {250};
+ int[] ok = {OK_HELO};
send("HELO " + local, ok);
}
-
void sendFrom(String from) throws IOException {
- int[] ok = {250};
+ int[] ok = {OK_FROM};
send("MAIL FROM: " + "<" + sanitizeAddress(from) + ">", ok);
}
-
void sendRcpt(String rcpt) throws IOException {
- int[] ok = {250, 251};
+ int[] ok = {OK_RCPT_1, OK_RCPT_2};
send("RCPT TO: " + "<" + sanitizeAddress(rcpt) + ">", ok);
}
void sendData() throws IOException {
- int[] ok = {354};
+ int[] ok = {OK_DATA};
send("DATA", ok);
}
void sendDot() throws IOException {
- int[] ok = {250};
+ int[] ok = {OK_DOT};
send("\r\n.", ok); // make sure dot is on new line
}
void sendQuit() throws IOException {
- int[] ok = {221};
+ int[] ok = {OK_QUIT};
try {
send("QUIT", ok);
} catch (IOException e) {
@@ -482,12 +515,13 @@
}
}
-// This PrintStream subclass makes sure that <CRLF>. becomes <CRLF>..
-// per RFC 821. It also ensures that new lines are always \r\n.
-//
+/**
+ * This PrintStream subclass makes sure that <CRLF>. becomes <CRLF>..
+ * per RFC 821. It also ensures that new lines are always \r\n.
+*/
class MailPrintStream extends PrintStream {
- int lastChar;
+ private int lastChar;
public MailPrintStream(OutputStream out) {
super(out, true); // deprecated, but email is byte-oriented
1.1 ant/src/testcases/org/apache/tools/mail/MailMessageTest.java
Index: MailMessageTest.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "Ant" and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
* ITS 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.mail;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.tools.mail.MailMessage;
import junit.framework.TestCase;
/**
* JUnit 3 testcases for org.apache.tools.mail.MailMessage.
*
* @author Michael Davey
* @since Ant 1.6
*/
public class MailMessageTest extends TestCase {
// 27224 = magic (a random port which is unlikely to be in use)
private static int TEST_PORT = 27224;
private String local = null;
public MailMessageTest(String name) {
super(name);
}
public void setUp() {
try {
local = InetAddress.getLocalHost().getHostName();
} catch (java.net.UnknownHostException uhe) {
// ignore
}
}
/**
* Test an example that is similar to the one given in the API
* If this testcase takes >90s to complete, it is very likely that
* the two threads are blocked waiting for each other and Thread.join()
* timed out.
*/
public void testAPIExample() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.to("to@you.com");
testMailClient.cc("cc1@you.com");
testMailClient.cc("cc2@you.com");
testMailClient.bcc("bcc@you.com");
testMailClient.setSubject("Test subject");
testMailClient.setMessage( "test line 1\n" +
"test line 2" );
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail( "InterruptedException: " + ie );
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <to...@you.com>\r\n" +
"250\r\n" +
"RCPT TO: <cc...@you.com>\r\n" +
"250\r\n" +
"RCPT TO: <cc...@you.com>\r\n" +
"250\r\n" +
"RCPT TO: <bc...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"To: to@you.com\r\n" +
"Cc: cc1@you.com, cc2@you.com\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"test line 1\r\n" +
"test line 2\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
for (int icounter = 0; icounter<expectedResult.length(); icounter++) {
if (icounter < result.length()) {
if (expectedResult.charAt(icounter) != result.charAt(icounter)) {
System.out.println("posit " + icounter + " expected "
+ expectedResult.charAt(icounter)
+ " result " + result.charAt(icounter));
}
}
}
if (expectedResult.length()>result.length()) {
System.out.println("excedent of expected result "
+ expectedResult.substring(result.length()));
}
if (expectedResult.length()<result.length()) {
System.out.println("excedent of result "
+ result.substring(expectedResult.length()));
}
assertEquals(expectedResult.length(), result.length());
assertEquals(expectedResult, result); // order of headers cannot be guaranteed
if (testMailClient.isFailed()) {
fail(testMailClient.getFailMessage());
}
}
/**
* Test a MailMessage with no cc or bcc lines
*/
public void testToOnly() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.to("to@you.com");
testMailClient.setSubject("Test subject");
testMailClient.setMessage( "test line 1\n" +
"test line 2" );
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail("InterruptedException: " + ie);
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <to...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"To: to@you.com\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"test line 1\r\n" +
"test line 2\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
assertEquals(expectedResult.length(), result.length());
assertEquals(expectedResult, result); // order of headers cannot be guaranteed
if (testMailClient.isFailed()) {
fail(testMailClient.getFailMessage());
}
}
/**
* Test a MailMessage with no to or bcc lines
*/
public void testCcOnly() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.cc("cc@you.com");
testMailClient.setSubject("Test subject");
testMailClient.setMessage( "test line 1\n" +
"test line 2" );
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail( "InterruptedException: " + ie );
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <cc...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"Cc: cc@you.com\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"test line 1\r\n" +
"test line 2\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
assertEquals(expectedResult.length(), result.length());
assertEquals(expectedResult, result);
if (testMailClient.isFailed()) {
fail(testMailClient.getFailMessage());
}
}
/**
* Test a MailMessage with no to or cc lines
*/
public void testBccOnly() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.bcc("bcc@you.com");
testMailClient.setSubject("Test subject");
testMailClient.setMessage( "test line 1\n" +
"test line 2" );
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail( "InterruptedException: " + ie );
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <bc...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"test line 1\r\n" +
"test line 2\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
assertEquals( expectedResult.length(), result.length() );
assertEquals( expectedResult, result );
if ( testMailClient.isFailed() ) {
fail( testMailClient.getFailMessage() );
}
}
/**
* Test a MailMessage with no subject line
* Subject is an optional field (RFC 822 s4.1)
*/
public void testNoSubject() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.to("to@you.com");
testMailClient.setMessage( "test line 1\n" +
"test line 2" );
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail( "InterruptedException: " + ie );
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <to...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"To: to@you.com\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"test line 1\r\n" +
"test line 2\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
assertEquals( expectedResult.length(), result.length() );
assertEquals( expectedResult, result );
if ( testMailClient.isFailed() ) {
fail( testMailClient.getFailMessage() );
}
}
/**
* Test a MailMessage with empty body message
*/
public void testEmptyBody() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.to("to@you.com");
testMailClient.setSubject("Test subject");
testMailClient.setMessage("");
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail( "InterruptedException: " + ie );
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <to...@you.com>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"To: to@you.com\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
assertEquals(expectedResult.length(), result.length());
assertEquals(expectedResult, result);
if (testMailClient.isFailed()) {
fail(testMailClient.getFailMessage());
}
}
/**
* Test a MailMessage with US-ASCII character set
* The next four testcase can be kinda hard to debug as Ant will often
* print the junit failure in US-ASCII.
*/
public void testAsciiCharset() {
ServerThread testMailServer = new ServerThread();
Thread server = new Thread(testMailServer);
server.start();
ClientThread testMailClient = new ClientThread();
testMailClient.from("Mail Message <Em...@ant.apache.org>");
testMailClient.to("Ceki G\u00fclc\u00fc <ab...@mail-abuse.org>");
testMailClient.setSubject("Test subject");
testMailClient.setMessage("");
Thread client = new Thread(testMailClient);
client.start();
try {
server.join(60 * 1000); // 60s
client.join(30 * 1000); // a further 30s
} catch (InterruptedException ie ) {
fail("InterruptedException: " + ie);
}
String result = testMailServer.getResult();
String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
"HELO " + local + "\r\n" +
"250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
"MAIL FROM: <Em...@ant.apache.org>\r\n" +
"250\r\n" +
"RCPT TO: <ab...@mail-abuse.org>\r\n" +
"250\r\n" +
"DATA\r\n" +
"354\r\n" +
"Subject: Test subject\r\n" +
"From: Mail Message <Em...@ant.apache.org>\r\n" +
"To: Ceki G\u00fclc\u00fc <ab...@mail-abuse.org>\r\n" +
"X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
"\r\n" +
"\r\n" +
"\r\n" +
".\r\n" +
"250\r\n" +
"QUIT\r\n" +
"221\r\n";
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
PrintStream bos1 = new PrintStream(baos1, true);
PrintStream bos2 = new PrintStream(baos2, true);
bos1.print(expectedResult);
bos2.print(result);
assertEquals( "expected message length != actual message length "
+ "in testAsciiCharset()", expectedResult.length(), result.length() );
assertEquals( "baos1 and baos2 should be the same in testAsciiCharset()",
baos1.toString(), baos2.toString() ); // order of headers cannot be guaranteed
if (testMailClient.isFailed()) {
fail(testMailClient.getFailMessage());
}
}
/**
* A private test class that pretends to be a mail transfer agent
*/
private class ServerThread implements Runnable {
private StringBuffer sb = null;
private boolean loop = false;
ServerSocket ssock = null;
Socket sock = null;
BufferedWriter out = null;
BufferedReader in = null;
private boolean data = false; // state engine: false=envelope, true=message
public void run() {
try {
ssock = new ServerSocket(TEST_PORT);
sock = ssock.accept(); // wait for connection
in = new BufferedReader( new InputStreamReader(
sock.getInputStream()) );
out = new BufferedWriter( new OutputStreamWriter(
sock.getOutputStream() ) );
sb = new StringBuffer();
send( "220 test SMTP EmailTaskTest\r\n" );
loop = true;
while ( loop ) {
String response = in.readLine();
if ( response == null ) {
loop = false;
break;
}
sb.append( response + "\r\n" );
if ( !data && response.startsWith( "HELO" ) ) {
send( "250 " + local + " Hello " + local + " " +
"[127.0.0.1], pleased to meet you\r\n" );
} else if ( !data && response.startsWith("MAIL") ) {
send( "250\r\n" );
} else if ( !data && response.startsWith("RCPT")) {
send( "250\r\n" );
} else if (!data && response.startsWith("DATA")) {
send( "354\r\n" );
data = true;
} else if (data && response.equals(".") ) {
send( "250\r\n" );
data = false;
} else if (!data && response.startsWith("QUIT")) {
send( "221\r\n" );
loop = false;
} else if (!data) {
//throw new IllegalStateException("Command unrecognized: "
// + response);
send( "500 5.5.1 Command unrecognized: \"" +
response + "\"\r\n" );
loop = false;
} else {
// sb.append( response + "\r\n" );
}
} // while
} catch (IOException ioe) {
fail();
} finally {
disconnect();
}
}
private void send(String retmsg) throws IOException {
out.write( retmsg );
out.flush();
sb.append( retmsg );
}
private void disconnect() {
if (out != null) {
try {
out.flush();
out.close();
out = null;
} catch (IOException e) {
// ignore
}
}
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
// ignore
}
}
if (sock != null) {
try {
sock.close();
sock = null;
} catch (IOException e) {
// ignore
}
}
if (ssock != null) {
try {
ssock.close();
ssock = null;
} catch (IOException e) {
// ignore
}
}
}
public synchronized String getResult() {
loop = false;
return sb.toString();
}
}
/**
* A private test class that wraps MailMessage
*/
private class ClientThread implements Runnable {
private MailMessage msg;
private boolean fail = false;
private String failMessage = null;
protected String from = null;
protected String subject = null;
protected String message = null;
protected Vector replyToList = new Vector();
protected Vector toList = new Vector();
protected Vector ccList = new Vector();
protected Vector bccList = new Vector();
public void run() {
for (int i = 9; i > 0; i--) {
try {
msg = new MailMessage("localhost", TEST_PORT);
} catch (java.net.ConnectException ce) {
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException ie) {
// ignore
}
} catch (IOException ioe) {
fail = true;
failMessage = "IOException: " + ioe;
return;
}
if (msg != null) {
break;
}
}
if (msg == null) {
fail = true;
failMessage = "java.net.ConnectException: Connection refused";
return;
}
try {
msg.from(from);
Enumeration e;
e = replyToList.elements();
while (e.hasMoreElements()) {
msg.replyto(e.nextElement().toString());
}
e = toList.elements();
while (e.hasMoreElements()) {
msg.to(e.nextElement().toString());
}
e = ccList.elements();
while (e.hasMoreElements()) {
msg.cc(e.nextElement().toString());
}
e = bccList.elements();
while (e.hasMoreElements()) {
msg.bcc(e.nextElement().toString());
}
if (subject != null) {
msg.setSubject(subject);
}
if (message != null ) {
PrintStream out = msg.getPrintStream();
out.println( message );
}
msg.sendAndClose();
} catch (IOException ioe) {
fail = true;
failMessage = "IOException: " + ioe;
return;
}
}
public boolean isFailed() {
return fail;
}
public String getFailMessage() {
return failMessage;
}
public void replyTo(String replyTo) {
replyToList.add(replyTo);
}
public void to(String to) {
toList.add(to);
}
public void cc(String cc) {
ccList.add(cc);
}
public void bcc(String bcc) {
bccList.add(bcc);
}
public void setSubject(String subject) {
this.subject = subject;
}
public void from(String from) {
this.from = from;
}
public void setMessage(String message) {
this.message = message;
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org