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