Author: danny
Date: Tue Aug 14 07:34:48 2007
New Revision: 565772
URL: http://svn.apache.org/viewvc?view=rev&rev=565772
Log:
Sorry, three changes in one commit :(
1/ resolved MAILET-7 applied changes per robert's patch.
2/ Renamed "user" and "host" to "localPart" and "domain" to align with
definitions in RFC2822 3.4. Address
Specification. Deprecated "old-named" accessors.
3/ Made unvalidating constructor - MailAddress(String String) call a parsing
constructor to apply the same greedy validation to all constructors.
Modified:
james/mailet/trunk/src/main/java/org/apache/mailet/MailAddress.java
Modified: james/mailet/trunk/src/main/java/org/apache/mailet/MailAddress.java
URL:
http://svn.apache.org/viewvc/james/mailet/trunk/src/main/java/org/apache/mailet/MailAddress.java?view=diff&rev=565772&r1=565771&r2=565772
==============================================================================
--- james/mailet/trunk/src/main/java/org/apache/mailet/MailAddress.java
(original)
+++ james/mailet/trunk/src/main/java/org/apache/mailet/MailAddress.java Tue Aug
14 07:34:48 2007
@@ -41,18 +41,17 @@
* (SMTP) p. 30 and 31 where addresses are defined in BNF convention.
* As the mailet API does not support the aged "SMTP-relayed mail"
* addressing protocol, this leaves all addresses to be a <mailbox>,
- * as per the spec. The MailAddress's "user" is the <local-part> of
- * the <mailbox> and "host" is the <domain> of the mailbox.</p>
+ * as per the spec.
*
* <p>This class is a good way to validate email addresses as there are
* some valid addresses which would fail with a simpler approach
* to parsing address. It also removes parsing burden from
* mailets and matchers that might not realize the flexibility of an
* SMTP address. For instance, "[EMAIL PROTECTED]"@lokitech.com is a valid
- * SMTP address (the quoted text [EMAIL PROTECTED] is the user and
- * lokitech.com is the host). This means all current parsing to date
+ * SMTP address (the quoted text [EMAIL PROTECTED] is the local-part and
+ * lokitech.com is the domain). This means all current parsing to date
* is incorrect as we just find the first @ and use that to separate
- * user from host.</p>
+ * local-part from domain.</p>
*
* <p>This parses an address as per the BNF specification for <mailbox>
* from RFC 821 on page 30 and 31, section 4.1.2. COMMAND SYNTAX.
@@ -68,8 +67,8 @@
private final static char[] SPECIAL =
{'<', '>', '(', ')', '[', ']', '\\', '.', ',', ';', ':', '@', '\"'};
- private String user = null;
- private String host = null;
+ private String localPart = null;
+ private String domain = null;
//Used for parsing
private int pos = 0;
@@ -93,7 +92,7 @@
*
* <p>The <code>personal</code> variable is left empty.</p>
*
- * @param address the email address compliant to the RFC822 format
+ * @param address the email address compliant to the RFC2822 3.4.1.
Addr-spec specification
* @throws ParseException if the parse failed
*/
public MailAddress(String address) throws ParseException {
@@ -103,8 +102,8 @@
//must be called first!! (or at least prior to updating pos)
stripSourceRoute(address);
- StringBuffer userSB = new StringBuffer();
- StringBuffer hostSB = new StringBuffer();
+ StringBuffer localPartSB = new StringBuffer();
+ StringBuffer domainSB = new StringBuffer();
//Begin parsing
//<mailbox> ::= <local-part> "@" <domain>
@@ -112,20 +111,20 @@
//parse local-part
//<local-part> ::= <dot-string> | <quoted-string>
if (address.charAt(pos) == '\"') {
- userSB.append(parseQuotedLocalPart(address));
- if (userSB.toString().length() == 2) {
- throw new ParseException("No quoted local-part (user
account) found at position " + (pos + 2));
+ localPartSB.append(parseQuotedLocalPart(address));
+ if (localPartSB.toString().length() == 2) {
+ throw new ParseException("No quoted local-part (user
account) found at position " + (pos + 2) + " in '" + address + "'");
}
} else {
- userSB.append(parseUnquotedLocalPart(address));
- if (userSB.toString().length() == 0) {
- throw new ParseException("No local-part (user account)
found at position " + (pos + 1));
+ localPartSB.append(parseUnquotedLocalPart(address));
+ if (localPartSB.toString().length() == 0) {
+ throw new ParseException("No local-part (user account)
found at position " + (pos + 1) + " in '" + address + "'");
}
}
//find @
if (pos >= address.length() || address.charAt(pos) != '@') {
- throw new ParseException("Did not find @ between local-part
and domain at position " + (pos + 1));
+ throw new ParseException("Did not find @ between local-part
and domain at position " + (pos + 1) + " in '" + address + "'");
}
pos++;
@@ -134,49 +133,51 @@
//<element> ::= <name> | "#" <number> | "[" <dotnum> "]"
while (true) {
if (address.charAt(pos) == '#') {
- hostSB.append(parseNumber(address));
+ domainSB.append(parseNumber(address));
} else if (address.charAt(pos) == '[') {
- hostSB.append(parseDotNum(address));
+ domainSB.append(parseDomainLiteral(address));
} else {
- hostSB.append(parseDomainName(address));
+ domainSB.append(parseDomain(address));
}
if (pos >= address.length()) {
break;
}
if (address.charAt(pos) == '.') {
- hostSB.append('.');
+ domainSB.append('.');
pos++;
continue;
}
break;
}
- if (hostSB.toString().length() == 0) {
- throw new ParseException("No domain found at position " + (pos
+ 1));
+ if (domainSB.toString().length() == 0) {
+ throw new ParseException("No domain found at position " + (pos
+ 1) + " in '" + address + "'");
}
} catch (IndexOutOfBoundsException ioobe) {
- throw new ParseException("Out of data at position " + (pos + 1));
+ throw new ParseException("Out of data at position " + (pos + 1) +
" in '" + address + "'");
}
- user = userSB.toString();
- host = hostSB.toString();
+ localPart = localPartSB.toString();
+ domain = domainSB.toString();
}
/**
* Construct a MailAddress with the provided personal name and email
* address.
*
- * @param newUser the username or account name on the mail server
- * @param newHost the server that should accept messages for this
user
+ * @param localPart The local-part portion is a domain dependent
string. In addresses, it is simply interpreted on the particular host as a
name of a particular mailbox. per RFC2822 3.4.1. Addr-spec specification
+ * @param domain The domain portion identifies the point to which
the mail is delivered per RFC2822 3.4.1. Addr-spec specification
* @throws ParseException if the parse failed
*/
- public MailAddress(String newUser, String newHost) throws ParseException {
- this(newUser+ "@" + newHost);
+ public MailAddress(String localPart, String domain) throws ParseException {
+ this(new InternetAddress(localPart+"@"+domain));
}
/**
* Constructs a MailAddress from a JavaMail InternetAddress, using only the
- * email address portion, discarding the personal name.
+ * email address portion, discarding the personal name. (an "addr-spec"
not a "name-addr" as defined in RFC2822 3.4. Address Specification
+ * @param address
+ * @throws ParseException
*/
public MailAddress(InternetAddress address) throws ParseException {
this(address.getAddress());
@@ -188,13 +189,24 @@
* @return a <code>String</code> object representing the host part
* of this email address. If the host is of the dotNum form
* (e.g. [yyy.yyy.yyy.yyy]) then strip the braces first.
+ * @deprecated use getDomain() - name change to align with RFC2821 3.4.1.
Addr-spec specification
*/
public String getHost() {
- if (!(host.startsWith("[") && host.endsWith("]"))) {
- return host;
- } else {
- return host.substring(1, host.length() -1);
- }
+ return getDomain();
+ }
+
+ /**
+ * Return the domain part per RFC2821 3.4.1. Addr-spec specification
+ *
+ * @return a <code>String</code> object representing the domain part
+ * of this email address. If the domain is of the domain-literal
form (e.g. [yyy.yyy.yyy.yyy]) the braces will have been stripped returning
the raw IP address.
+ */
+ public String getDomain() {
+ if (!(domain.startsWith("[") && domain.endsWith("]"))) {
+ return domain;
+ }
+ return domain.substring(1, domain.length() -1);
+
}
/**
@@ -202,17 +214,32 @@
*
* @return a <code>String</code> object representing the user part
* of this email address.
+ * @throws AddressException if the parse failed
+ * @deprecated use getLocalPart() - name change to align with RFC2821
3.4.1. Addr-spec specification
*/
public String getUser() {
- return user;
+ return getLocalPart();
+ }
+
+ /**
+ * Return the local-part per RFC2821 3.4.1. Addr-spec specification
+ *
+ * @return a <code>String</code> object representing the local-part
+ * of this email address as defined by RFC2821 3.4.1. Addr-spec
specification.
+ * The local-part portion is a domain dependent string. In
addresses, it is simply interpreted on the particular host as a name of a
particular mailbox.
+ * It is the part before the "@"
+ * @throws AddressException if the parse failed
+ */
+ public String getLocalPart() {
+ return localPart;
}
public String toString() {
StringBuffer addressBuffer =
new StringBuffer(128)
- .append(user)
+ .append(localPart)
.append("@")
- .append(host);
+ .append(domain);
return addressBuffer.toString();
}
@@ -239,7 +266,7 @@
return toString().equalsIgnoreCase(theString);
} else if (obj instanceof MailAddress) {
MailAddress addr = (MailAddress)obj;
- return getUser().equalsIgnoreCase(addr.getUser()) &&
getHost().equalsIgnoreCase(addr.getHost());
+ return getLocalPart().equalsIgnoreCase(addr.getLocalPart()) &&
getDomain().equalsIgnoreCase(addr.getDomain());
}
return false;
}
@@ -276,7 +303,7 @@
//<x> ::= any one of the 128 ASCII characters (no exceptions)
char x = address.charAt(pos);
if (x < 0 || x > 127) {
- throw new ParseException("Invalid \\ syntaxed character at
position " + (pos + 1));
+ throw new ParseException("Invalid \\ syntaxed character at
position " + (pos + 1) + " in '" + address + "'");
}
resultSB.append(x);
pos++;
@@ -285,7 +312,7 @@
//<LF>, quote ("), or backslash (\)
char q = address.charAt(pos);
if (q <= 0 || q == '\n' || q == '\r' || q == '\"' || q ==
'\\') {
- throw new ParseException("Unquoted local-part (user
account) must be one of the 128 ASCI characters exception <CR>, <LF>, quote
(\"), or backslash (\\) at position " + (pos + 1));
+ throw new ParseException("Unquoted local-part (user
account) must be one of the 128 ASCI characters exception <CR>, <LF>, quote
(\"), or backslash (\\) at position " + (pos + 1) + " in '" + address + "'");
}
resultSB.append(q);
pos++;
@@ -307,7 +334,7 @@
//<x> ::= any one of the 128 ASCII characters (no exceptions)
char x = address.charAt(pos);
if (x < 0 || x > 127) {
- throw new ParseException("Invalid \\ syntaxed character at
position " + (pos + 1));
+ throw new ParseException("Invalid \\ syntaxed character at
position " + (pos + 1) + " in '" + address + "'");
}
resultSB.append(x);
pos++;
@@ -329,11 +356,11 @@
//<SP> ::= the space character (ASCII code 32)
char c = address.charAt(pos);
if (c <= 31 || c >= 127 || c == ' ') {
- throw new ParseException("Invalid character in local-part
(user account) at position " + (pos + 1));
+ throw new ParseException("Invalid character in local-part
(user account) at position " + (pos + 1) + " in '" + address + "'");
}
for (int i = 0; i < SPECIAL.length; i++) {
if (c == SPECIAL[i]) {
- throw new ParseException("Invalid character in
local-part (user account) at position " + (pos + 1));
+ throw new ParseException("Invalid character in
local-part (user account) at position " + (pos + 1) + " in '" + address + "'");
}
}
resultSB.append(c);
@@ -342,7 +369,7 @@
}
}
if (lastCharDot) {
- throw new ParseException("local-part (user account) ended with a
\".\", which is invalid.");
+ throw new ParseException("local-part (user account) ended with a
\".\", which is invalid in address '" + address + "'");
}
return resultSB.toString();
}
@@ -362,7 +389,7 @@
break;
}
if (d < '0' || d > '9') {
- throw new ParseException("In domain, did not find a number in
# address at position " + (pos + 1));
+ throw new ParseException("In domain, did not find a number in
# address at position " + (pos + 1) + " in '" + address + "'");
}
resultSB.append(d);
pos++;
@@ -370,7 +397,7 @@
return resultSB.toString();
}
- private String parseDotNum(String address) throws ParseException {
+ private String parseDomainLiteral(String address) throws ParseException {
//throw away all irrelevant '\' they're not necessary for escaping of
'.' or digits, and are illegal as part of the domain-literal
while(address.indexOf("\\")>-1){
address= address.substring(0,address.indexOf("\\")) +
address.substring(address.indexOf("\\")+1);
@@ -396,29 +423,28 @@
break;
}
if (d < '0' || d > '9') {
- throw new ParseException("Invalid number at position " +
(pos + 1));
+ throw new ParseException("Invalid number at position " +
(pos + 1) + " in '" + address + "'");
}
snumSB.append(d);
pos++;
}
if (snumSB.toString().length() == 0) {
- throw new ParseException("Number not found at position " +
(pos + 1));
+ throw new ParseException("Number not found at position " +
(pos + 1) + " in '" + address + "'");
}
try {
int snum = Integer.parseInt(snumSB.toString());
if (snum > 255) {
- throw new ParseException("Invalid number at position " +
(pos + 1));
+ throw new ParseException("Invalid number at position " +
(pos + 1) + " in '" + address + "'");
}
} catch (NumberFormatException nfe) {
- throw new ParseException("Invalid number at position " + (pos
+ 1));
+ throw new ParseException("Invalid number at position " + (pos
+ 1) + " in '" + address + "'");
}
resultSB.append(snumSB.toString());
if (address.charAt(pos) == ']') {
if (octet < 3) {
- throw new ParseException("End of number reached too
quickly at " + (pos + 1));
- } else {
- break;
- }
+ throw new ParseException("End of number reached too
quickly at " + (pos + 1) + " in '" + address + "'");
+ }
+ break;
}
if (address.charAt(pos) == '.') {
resultSB.append('.');
@@ -426,14 +452,14 @@
}
}
if (address.charAt(pos) != ']') {
- throw new ParseException("Did not find closing bracket \"]\" in
domain at position " + (pos + 1));
+ throw new ParseException("Did not find closing bracket \"]\" in
domain at position " + (pos + 1) + " in '" + address + "'");
}
resultSB.append(']');
pos++;
return resultSB.toString();
}
- private String parseDomainName(String address) throws ParseException {
+ private String parseDomain(String address) throws ParseException {
StringBuffer resultSB = new StringBuffer();
//<name> ::= <a> <ldh-str> <let-dig>
//<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
@@ -470,7 +496,7 @@
}
String result = resultSB.toString();
if (result.startsWith("-") || result.endsWith("-")) {
- throw new ParseException("Domain name cannot begin or end with a
hyphen \"-\" at position " + (pos + 1));
+ throw new ParseException("Domain name cannot begin or end with a
hyphen \"-\" at position " + (pos + 1) + " in '" + address + "'");
}
return result;
}