diff --git a/WHATSNEW b/WHATSNEW index 4baa812a9..8150502a7 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -400,6 +400,11 @@ Other changes: * and mailloger support SMTP over TLS/SSL Bugzilla Report 19180. +* the attributes from, replyto ,tolist, cclist, bcclist + can now contain email addresses of the form name + or (name) address@xyz.com + Bugzilla Report 22474. + * can now be defined in the main body of a project and referred to with refid="xyz". Bugzilla Report 17007. diff --git a/docs/manual/CoreTasks/mail.html b/docs/manual/CoreTasks/mail.html index 63564a26b..05dacc12f 100644 --- a/docs/manual/CoreTasks/mail.html +++ b/docs/manual/CoreTasks/mail.html @@ -141,6 +141,19 @@ Library Dependencies for more information. +

Note regarding the attributes containing email addresses

+Since ant 1.6, the attributes from, replyto, tolist, cclist, bcclist +can contain email addresses of the form : +
    +
  • address@xyz.com
  • +
  • name <address@xyz.com>
  • +
  • <address@xyz.com> name
  • +
  • (name) address@xyz.com
  • +
  • address@xyz.com (name)
  • +
+

You need to enter the angle brackets as XML entities +&gt; and &lt;.

+

Parameters specified as nested elements

to / cc / bcc / from/ replyto

diff --git a/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java b/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java index 852797b15..28bd918a1 100644 --- a/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java +++ b/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2002 The Apache Software Foundation. All rights + * Copyright (c) 2002-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ package org.apache.tools.ant.taskdefs.email; * Holds an email address. * * @author roxspring@yahoo.com Rob Oxspring + * @author Michael Davey * @since Ant 1.5 */ public class EmailAddress { @@ -72,10 +73,109 @@ public class EmailAddress { /** * Creates a new email address based on the given string * - * @param address the email address + * @param email the email address (with or without <>) + * Acceptable forms include: + * address + *
+ * name
+ *
name + * (name) address + * address (name) */ - public EmailAddress(String address) { - this.address = address; + // Make a limited attempt to extract a sanitized name and email address + // Algorithm based on the one found in Ant's MailMessage.java + public EmailAddress(String email) { + final int minLen = 9; + int len = email.length(); + + // shortcut for "
" + if (len > minLen) { + if ((email.charAt(0) == '<' || email.charAt(1) == '<') + && (email.charAt(len - 1) == '>' || email.charAt(len - 2) == '>')) { + this.address = trim(email, true); + return; + } + } + + int paramDepth = 0; + int start = 0; + int end = 0; + int nStart = 0; + int nEnd = 0; + + for (int i = 0; i < len; i++) { + char c = email.charAt(i); + if (c == '(') { + paramDepth++; + if (start == 0) { + end = i; // support "address (name)" + nStart = i + 1; + } + } else if (c == ')') { + paramDepth--; + if (end == 0) { + start = i + 1; // support "(name) address" + nEnd = i; + } + } else if (paramDepth == 0 && c == '<') { + if (start == 0) { + nEnd = i; + } + start = i + 1; + } else if (paramDepth == 0 && c == '>') { + end = i; + if (end != len - 1) { + nStart = i + 1; + } + } + } + + // DEBUG: System.out.println( email ); + if (end == 0) { + end = len; + } + // DEBUG: System.out.println( "address: " + start + " " + end ); + if (nEnd == 0) { + nEnd = len; + } + // DEBUG: System.out.println( "name: " + nStart + " " + nEnd ); + + this.address = trim(email.substring(start, end), true); + this.name = trim(email.substring(nStart, nEnd), false); + + // if the two substrings are longer than the original, then name + // contains address - so reset the name to null + if (this.name.length() + this.address.length() > len) { + this.name = null; + } + } + + /** + * A specialised trim() that trims whitespace, + * '(', ')', '"', '<', '>' from the start and end of strings + */ + private String trim(String t, boolean trimAngleBrackets) { + int start = 0; + int end = t.length(); + boolean trim = false; + do { + trim = false; + if (t.charAt(end - 1) == ')' + || (t.charAt(end - 1) == '>' && trimAngleBrackets) + || (t.charAt(end - 1) == '"' && t.charAt(end - 2) != '\\') + || t.charAt(end - 1) <= '\u0020') { + trim = true; + end--; + } + if (t.charAt(start) == '(' + || (t.charAt(start) == '<' && trimAngleBrackets) + || t.charAt(start) == '"' + || t.charAt(start) <= '\u0020') { + trim = true; + start++; + } + } while (trim); + return t.substring(start, end); } @@ -92,7 +192,7 @@ public class EmailAddress { /** * Sets the email address * - * @param address the actual email address + * @param address the actual email address (without <>) */ public void setAddress(String address) { this.address = address; diff --git a/src/testcases/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java b/src/testcases/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java new file mode 100644 index 000000000..40a2a3213 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java @@ -0,0 +1,141 @@ +/* + * 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 + * . + */ + +package org.apache.tools.ant.taskdefs.email; + +import junit.framework.TestCase; + +/** + * @author Michael Davey + * @since Ant 1.6 + */ +public class EmailAddressTest extends TestCase { + + public EmailAddressTest(String name) { + super(name); + } + + public void setUp() { + } + + public void test1() { + expectNameAddress( new EmailAddress("address (name)") ); + } + + public void test2() { + expectNameAddress( new EmailAddress("(name) address") ); + } + + public void test3() { + expectNameAddress( new EmailAddress("name
") ); + } + + public void test4() { + expectNameAddress( new EmailAddress("
name") ); + } + + public void test5() { + expectNameAddress( new EmailAddress("
(name)") ); + } + + public void test6() { + expectNameAddress( new EmailAddress("(name)
") ); + } + + public void test7() { + expectNameAddress2( new EmailAddress("address ()") ); + } + + public void test8() { + expectNameAddress2( new EmailAddress("() address") ); + } + + public void test9() { + expectNameAddress3( new EmailAddress("address") ); + } + + public void testA() { + expectNameAddress3( new EmailAddress("
") ); + } + + public void testB() { + expectNameAddress3( new EmailAddress("
") ); + } + + public void testC() { + expectNameAddress3( new EmailAddress("< address >") ); + } + + public void testD() { + expectNameAddress3( new EmailAddress(" < address > ") ); + } + + private void expectNameAddress(EmailAddress e) { + assertEquals( "name", e.getName() ); + assertEquals( "address", e.getAddress() ); + } + + // where the name contains <> + private void expectNameAddress2(EmailAddress e) { + assertEquals( "", e.getName() ); + assertEquals( "address", e.getAddress() ); + } + + // where only an address is supplied + private void expectNameAddress3(EmailAddress e) { + assertTrue( "Expected null, found <" + e.getName() + ">", + e.getName() == null ); + assertEquals( "address", e.getAddress() ); + } +}