Too bad you can't use LinkedHashMap. OTOH, you could use List instead of Vector, now that Java 1.2 is OK...
--DD > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > Sent: Thursday, August 21, 2003 11:16 AM > To: [EMAIL PROTECTED] > Subject: 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) [EMAIL PROTECTED] > 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 [EMAIL PROTECTED] > * > * 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 > <[EMAIL PROTECTED]>"); > testMailClient.to("[EMAIL PROTECTED]"); > testMailClient.cc("[EMAIL PROTECTED]"); > testMailClient.cc("[EMAIL PROTECTED]"); > testMailClient.bcc("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "To: [EMAIL PROTECTED]" + > "Cc: [EMAIL PROTECTED], [EMAIL PROTECTED]" + > "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 > <[EMAIL PROTECTED]>"); > testMailClient.to("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "To: [EMAIL PROTECTED]" + > "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 > <[EMAIL PROTECTED]>"); > testMailClient.cc("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "Cc: [EMAIL PROTECTED]" + > "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 > <[EMAIL PROTECTED]>"); > testMailClient.bcc("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\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 > <[EMAIL PROTECTED]>"); > testMailClient.to("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "To: [EMAIL PROTECTED]" + > "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 > <[EMAIL PROTECTED]>"); > testMailClient.to("[EMAIL PROTECTED]"); > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "To: [EMAIL PROTECTED]" + > "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 > <[EMAIL PROTECTED]>"); > testMailClient.to("Ceki G\u00fclc\u00fc <[EMAIL PROTECTED] > 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: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "RCPT TO: <[EMAIL PROTECTED]>\r\n" + > "250\r\n" + > "DATA\r\n" + > "354\r\n" + > "Subject: Test subject\r\n" + > "From: Mail Message <[EMAIL PROTECTED]>\r\n" + > "To: Ceki G\u00fclc\u00fc <[EMAIL PROTECTED]>\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: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]