InternetAddresspublic class InternetAddress extends Address implements CloneableThis class represents an Internet email address using the syntax
of RFC822.
Typical address syntax is of the form "user@host.domain" or
"Personal Name ". |
Fields Summary |
---|
protected String | address | protected String | personalThe personal name. | protected String | encodedPersonalThe RFC 2047 encoded version of the personal name.
This field and the personal field track each
other, so if a subclass sets one of these fields directly, it
should set the other to null , so that it is
suitably recomputed. | private static final long | serialVersionUID | private static final String | rfc822phrase | private static final String | specialsNoDotNoAt | private static final String | specialsNoDot |
Constructors Summary |
---|
public InternetAddress()Default constructor.
| public InternetAddress(String address)Constructor.
Parse the given string and create an InternetAddress.
See the parse method for details of the parsing.
The address is parsed using "strict" parsing.
This constructor does not perform the additional
syntax checks that the
InternetAddress(String address, boolean strict)
constructor does when strict is true .
This constructor is equivalent to
InternetAddress(address, false) .
// use our address parsing utility routine to parse the string
InternetAddress a[] = parse(address, true);
// if we got back anything other than a single address, it's an error
if (a.length != 1)
throw new AddressException("Illegal address", address);
/*
* Now copy the contents of the single address we parsed
* into the current object, which will be returned from the
* constructor.
* XXX - this sure is a round-about way of getting this done.
*/
this.address = a[0].address;
this.personal = a[0].personal;
this.encodedPersonal = a[0].encodedPersonal;
| public InternetAddress(String address, boolean strict)Parse the given string and create an InternetAddress.
If strict is false, the detailed syntax of the
address isn't checked.
this(address);
if (strict)
checkAddress(this.address, true, true);
| public InternetAddress(String address, String personal)Construct an InternetAddress given the address and personal name.
The address is assumed to be a syntactically valid RFC822 address.
this(address, personal, null);
| public InternetAddress(String address, String personal, String charset)Construct an InternetAddress given the address and personal name.
The address is assumed to be a syntactically valid RFC822 address.
this.address = address;
setPersonal(personal, charset);
|
Methods Summary |
---|
private static void | checkAddress(java.lang.String addr, boolean routeAddr, boolean validate)Check that the address is a valid "mailbox" per RFC822.
(We also allow simple names.)
XXX - much more to check
XXX - doesn't handle domain-literals properly (but no one uses them)
int i, start = 0;
if (addr.indexOf('"") >= 0)
return; // quote in address, too hard to check
if (routeAddr) {
/*
* Check for a legal "route-addr":
* [@domain[,@domain ...]:]local@domain
*/
for (start = 0; (i = indexOfAny(addr, ",:", start)) >= 0;
start = i+1) {
if (addr.charAt(start) != '@")
throw new AddressException("Illegal route-addr", addr);
if (addr.charAt(i) == ':") {
// end of route-addr
start = i + 1;
break;
}
}
}
/*
* The rest should be "local@domain", but we allow simply "local"
* unless called from validate.
*/
String local;
String domain;
if ((i = addr.indexOf('@", start)) >= 0) {
if (i == start)
throw new AddressException("Missing local name", addr);
if (i == addr.length() - 1)
throw new AddressException("Missing domain", addr);
local = addr.substring(start, i);
domain = addr.substring(i + 1);
} else {
/*
* Note that the MimeMessage class doesn't remember addresses
* as separate objects; it writes them out as headers and then
* parses the headers when the addresses are requested.
* In order to support the case where a "simple" address is used,
* but the address also has a personal name and thus looks like
* it should be a valid RFC822 address when parsed, we only check
* this if we're explicitly called from the validate method.
*/
if (validate)
throw new AddressException("Missing final '@domain'", addr);
/*
* No '@' so it's not *really* an RFC822 address, but still
* we allow some simple forms.
*/
local = addr;
domain = null;
}
// there better not be any whitespace in it
if (indexOfAny(addr, " \t\n\r") >= 0)
throw new AddressException("Illegal whitespace in address", addr);
// local-part must follow RFC822, no specials except '.'
if (indexOfAny(local, specialsNoDot) >= 0)
throw new AddressException("Illegal character in local name", addr);
// check for illegal chars in the domain, but ignore domain literals
if (domain != null && domain.indexOf('[") < 0) {
if (indexOfAny(domain, specialsNoDot) >= 0)
throw new AddressException("Illegal character in domain", addr);
}
| public java.lang.Object | clone()Return a copy of this InternetAddress object.
InternetAddress a = null;
try {
a = (InternetAddress)super.clone();
} catch (CloneNotSupportedException e) {} // Won't happen
return a;
| public boolean | equals(java.lang.Object a)The equality operator.
if (!(a instanceof InternetAddress))
return false;
String s = ((InternetAddress)a).getAddress();
if (s == address)
return true;
if (address != null && address.equalsIgnoreCase(s))
return true;
return false;
| public java.lang.String | getAddress()Get the email address.
return address;
| public javax.mail.internet.InternetAddress[] | getGroup(boolean strict)Return the members of a group address. A group may have zero,
one, or more members. If this address is not a group, null
is returned. The strict parameter controls whether
the group list is parsed using strict RFC 822 rules or not.
The parsing is done using the parseHeader method.
Vector groups = null;
String addr = getAddress();
// groups are of the form "name:addr,addr,...;"
if (!addr.endsWith(";"))
return null;
int ix = addr.indexOf(':");
if (ix < 0)
return null;
// extract the list
String list = addr.substring(ix + 1, addr.length() - 1);
// parse it and return the individual addresses
return InternetAddress.parseHeader(list, strict);
| public static javax.mail.internet.InternetAddress | getLocalAddress(javax.mail.Session session)Return an InternetAddress object representing the current user.
The entire email address may be specified in the "mail.from"
property. If not set, the "mail.user" and "mail.host" properties
are tried. If those are not set, the "user.name" property and
InetAddress.getLocalHost method are tried.
Security exceptions that may occur while accessing this information
are ignored. If it is not possible to determine an email address,
null is returned.
String user=null, host=null, address=null;
try {
if (session == null) {
user = System.getProperty("user.name");
host = InetAddress.getLocalHost().getHostName();
} else {
address = session.getProperty("mail.from");
if (address == null) {
user = session.getProperty("mail.user");
if (user == null || user.length() == 0)
user = session.getProperty("user.name");
if (user == null || user.length() == 0)
user = System.getProperty("user.name");
host = session.getProperty("mail.host");
if (host == null || host.length() == 0) {
InetAddress me = InetAddress.getLocalHost();
if (me != null)
host = me.getHostName();
}
}
}
if (address == null && user != null && user.length() != 0 &&
host != null && host.length() != 0)
address = user + "@" + host;
if (address != null)
return new InternetAddress(address);
} catch (SecurityException sex) { // ignore it
} catch (AddressException ex) { // ignore it
} catch (UnknownHostException ex) { } // ignore it
return null;
| public java.lang.String | getPersonal()Get the personal name. If the name is encoded as per RFC 2047,
it is decoded and converted into Unicode. If the decoding or
conversion fails, the raw data is returned as is.
if (personal != null)
return personal;
if (encodedPersonal != null) {
try {
personal = MimeUtility.decodeText(encodedPersonal);
return personal;
} catch (Exception ex) {
// 1. ParseException: either its an unencoded string or
// it can't be parsed
// 2. UnsupportedEncodingException: can't decode it.
return encodedPersonal;
}
}
// No personal or encodedPersonal, return null
return null;
| public java.lang.String | getType()Return the type of this address. The type of an InternetAddress
is "rfc822".
return "rfc822";
| public int | hashCode()Compute a hash code for the address.
if (address == null)
return 0;
else
return address.toLowerCase(Locale.ENGLISH).hashCode();
| private static int | indexOfAny(java.lang.String s, java.lang.String any)Return the first index of any of the characters in "any" in "s",
or -1 if none are found.
This should be a method on String.
return indexOfAny(s, any, 0);
| private static int | indexOfAny(java.lang.String s, java.lang.String any, int start)
try {
int len = s.length();
for (int i = start; i < len; i++) {
if (any.indexOf(s.charAt(i)) >= 0)
return i;
}
return -1;
} catch (StringIndexOutOfBoundsException e) {
return -1;
}
| public boolean | isGroup()Indicates whether this address is an RFC 822 group address.
Note that a group address is different than the mailing
list addresses supported by most mail servers. Group addresses
are rarely used; see RFC 822 for details.
// quick and dirty check
return address != null &&
address.endsWith(";") && address.indexOf(':") > 0;
| private boolean | isSimple()Is this a "simple" address? Simple addresses don't contain quotes
or any RFC822 special characters other than '@' and '.'.
return address == null || indexOfAny(address, specialsNoDotNoAt) < 0;
| private static int | lengthOfFirstSegment(java.lang.String s)
int pos;
if ((pos = s.indexOf("\r\n")) != -1)
return pos;
else
return s.length();
| private static int | lengthOfLastSegment(java.lang.String s, int used)
int pos;
if ((pos = s.lastIndexOf("\r\n")) != -1)
return s.length() - pos - 2;
else
return s.length() + used;
| public static javax.mail.internet.InternetAddress[] | parse(java.lang.String addresslist)Parse the given comma separated sequence of addresses into
InternetAddress objects. Addresses must follow RFC822 syntax.
return parse(addresslist, true);
| public static javax.mail.internet.InternetAddress[] | parse(java.lang.String addresslist, boolean strict)Parse the given sequence of addresses into InternetAddress
objects. If strict is false, simple email addresses
separated by spaces are also allowed. If strict is
true, many (but not all) of the RFC822 syntax rules are enforced.
In particular, even if strict is true, addresses
composed of simple names (with no "@domain" part) are allowed.
Such "illegal" addresses are not uncommon in real messages.
Non-strict parsing is typically used when parsing a list of
mail addresses entered by a human. Strict parsing is typically
used when parsing address headers in mail messages.
return parse(addresslist, strict, false);
| private static javax.mail.internet.InternetAddress[] | parse(java.lang.String s, boolean strict, boolean parseHdr)
int start, end, index, nesting;
int start_personal = -1, end_personal = -1;
int length = s.length();
boolean in_group = false; // we're processing a group term
boolean route_addr = false; // address came from route-addr term
boolean rfc822 = false; // looks like an RFC822 address
char c;
Vector v = new Vector();
InternetAddress ma;
for (start = end = -1, index = 0; index < length; index++) {
c = s.charAt(index);
switch (c) {
case '(": // We are parsing a Comment. Ignore everything inside.
// XXX - comment fields should be parsed as whitespace,
// more than one allowed per address
rfc822 = true;
if (start >= 0 && end == -1)
end = index;
if (start_personal == -1)
start_personal = index + 1;
for (index++, nesting = 1; index < length && nesting > 0;
index++) {
c = s.charAt(index);
switch (c) {
case '\\":
index++; // skip both '\' and the escaped char
break;
case '(":
nesting++;
break;
case ')":
nesting--;
break;
default:
break;
}
}
if (nesting > 0)
throw new AddressException("Missing ')'", s, index);
index--; // point to closing paren
if (end_personal == -1)
end_personal = index;
break;
case ')":
throw new AddressException("Missing '('", s, index);
case '<":
rfc822 = true;
if (route_addr)
throw new AddressException("Extra route-addr", s, index);
if (!in_group) {
start_personal = start;
if (start_personal >= 0)
end_personal = index;
start = index + 1;
}
boolean inquote = false;
outf:
for (index++; index < length; index++) {
c = s.charAt(index);
switch (c) {
case '\\": // XXX - is this needed?
index++; // skip both '\' and the escaped char
break;
case '"":
inquote = !inquote;
break;
case '>":
if (inquote)
continue;
break outf; // out of for loop
default:
break;
}
}
if (index >= length) {
if (inquote)
throw new AddressException("Missing '\"'", s, index);
else
throw new AddressException("Missing '>'", s, index);
}
route_addr = true;
end = index;
break;
case '>":
throw new AddressException("Missing '<'", s, index);
case '"": // parse quoted string
rfc822 = true;
if (start == -1)
start = index;
outq:
for (index++; index < length; index++) {
c = s.charAt(index);
switch (c) {
case '\\":
index++; // skip both '\' and the escaped char
break;
case '"":
break outq; // out of for loop
default:
break;
}
}
if (index >= length)
throw new AddressException("Missing '\"'", s, index);
break;
case '[": // a domain-literal, probably
rfc822 = true;
outb:
for (index++; index < length; index++) {
c = s.charAt(index);
switch (c) {
case '\\":
index++; // skip both '\' and the escaped char
break;
case ']":
break outb; // out of for loop
default:
break;
}
}
if (index >= length)
throw new AddressException("Missing ']'", s, index);
break;
case ',": // end of an address, probably
if (start == -1) {
route_addr = false;
rfc822 = false;
start = end = -1;
break; // nope, nothing there
}
if (in_group) {
route_addr = false;
break;
}
// got a token, add this to our InternetAddress vector
if (end == -1)
end = index;
String addr = s.substring(start, end).trim();
if (rfc822 || strict || parseHdr) {
if (strict || !parseHdr)
checkAddress(addr, route_addr, false);
ma = new InternetAddress();
ma.setAddress(addr);
if (start_personal >= 0) {
ma.encodedPersonal = unquote(
s.substring(start_personal, end_personal).trim());
start_personal = end_personal = -1;
}
v.addElement(ma);
} else {
// maybe we passed over more than one space-separated addr
StringTokenizer st = new StringTokenizer(addr);
while (st.hasMoreTokens()) {
String a = st.nextToken();
checkAddress(a, false, false);
ma = new InternetAddress();
ma.setAddress(a);
v.addElement(ma);
}
}
route_addr = false;
rfc822 = false;
start = end = -1;
break;
case ':":
rfc822 = true;
if (in_group)
throw new AddressException("Nested group", s, index);
in_group = true;
if (start == -1)
start = index;
break;
case ';":
if (start == -1)
start = index;
if (!in_group)
throw new AddressException(
"Illegal semicolon, not in group", s, index);
in_group = false;
if (start == -1)
start = index;
ma = new InternetAddress();
end = index + 1;
ma.setAddress(s.substring(start, end).trim());
v.addElement(ma);
route_addr = false;
start = end = -1;
break;
// Ignore whitespace
case ' ":
case '\t":
case '\r":
case '\n":
break;
default:
if (start == -1)
start = index;
break;
}
}
if (start >= 0) {
/*
* The last token, add this to our InternetAddress vector.
* Note that this block of code should be identical to the
* block above for "case ','".
*/
if (end == -1)
end = index;
String addr = s.substring(start, end).trim();
if (rfc822 || strict || parseHdr) {
if (strict || !parseHdr)
checkAddress(addr, route_addr, false);
ma = new InternetAddress();
ma.setAddress(addr);
if (start_personal >= 0) {
ma.encodedPersonal = unquote(
s.substring(start_personal, end_personal).trim());
}
v.addElement(ma);
} else {
// maybe we passed over more than one space-separated addr
StringTokenizer st = new StringTokenizer(addr);
while (st.hasMoreTokens()) {
String a = st.nextToken();
checkAddress(a, false, false);
ma = new InternetAddress();
ma.setAddress(a);
v.addElement(ma);
}
}
}
InternetAddress[] a = new InternetAddress[v.size()];
v.copyInto(a);
return a;
| public static javax.mail.internet.InternetAddress[] | parseHeader(java.lang.String addresslist, boolean strict)Parse the given sequence of addresses into InternetAddress
objects. If strict is false, the full syntax rules for
individual addresses are not enforced. If strict is
true, many (but not all) of the RFC822 syntax rules are enforced.
To better support the range of "invalid" addresses seen in real
messages, this method enforces fewer syntax rules than the
parse method when the strict flag is false
and enforces more rules when the strict flag is true. If the
strict flag is false and the parse is successful in separating out an
email address or addresses, the syntax of the addresses themselves
is not checked.
return parse(addresslist, strict, true);
| private static java.lang.String | quotePhrase(java.lang.String phrase)
int len = phrase.length();
boolean needQuoting = false;
for (int i = 0; i < len; i++) {
char c = phrase.charAt(i);
if (c == '"" || c == '\\") {
// need to escape them and then quote the whole string
StringBuffer sb = new StringBuffer(len + 3);
sb.append('"");
for (int j = 0; j < len; j++) {
char cc = phrase.charAt(j);
if (cc == '"" || cc == '\\")
// Escape the character
sb.append('\\");
sb.append(cc);
}
sb.append('"");
return sb.toString();
} else if ((c < 040 && c != '\r" && c != '\n" && c != '\t") ||
c >= 0177 || rfc822phrase.indexOf(c) >= 0)
// These characters cause the string to be quoted
needQuoting = true;
}
if (needQuoting) {
StringBuffer sb = new StringBuffer(len + 2);
sb.append('"").append(phrase).append('"");
return sb.toString();
} else
return phrase;
| public void | setAddress(java.lang.String address)Set the email address.
this.address = address;
| public void | setPersonal(java.lang.String name)Set the personal name. If the name contains non US-ASCII
characters, then the name will be encoded using the platform's
default charset. If the name contains only US-ASCII characters,
no encoding is done and the name is used as is.
personal = name;
if (name != null)
encodedPersonal = MimeUtility.encodeWord(name);
else
encodedPersonal = null;
| public void | setPersonal(java.lang.String name, java.lang.String charset)Set the personal name. If the name contains non US-ASCII
characters, then the name will be encoded using the specified
charset as per RFC 2047. If the name contains only US-ASCII
characters, no encoding is done and the name is used as is.
personal = name;
if (name != null)
encodedPersonal = MimeUtility.encodeWord(name, charset, null);
else
encodedPersonal = null;
| public java.lang.String | toString()Convert this address into a RFC 822 / RFC 2047 encoded address.
The resulting string contains only US-ASCII characters, and
hence is mail-safe.
if (encodedPersonal == null && personal != null)
try {
encodedPersonal = MimeUtility.encodeWord(personal);
} catch (UnsupportedEncodingException ex) { }
if (encodedPersonal != null)
return quotePhrase(encodedPersonal) + " <" + address + ">";
else if (isGroup() || isSimple())
return address;
else
return "<" + address + ">";
| public static java.lang.String | toString(javax.mail.Address[] addresses)Convert the given array of InternetAddress objects into
a comma separated sequence of address strings. The
resulting string contains only US-ASCII characters, and
hence is mail-safe.
return toString(addresses, 0);
| public static java.lang.String | toString(javax.mail.Address[] addresses, int used)Convert the given array of InternetAddress objects into
a comma separated sequence of address strings. The
resulting string contains only US-ASCII characters, and
hence is mail-safe.
The 'used' parameter specifies the number of character positions
already taken up in the field into which the resulting address
sequence string is to be inserted. It is used to determine the
line-break positions in the resulting address sequence string.
if (addresses == null || addresses.length == 0)
return null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < addresses.length; i++) {
if (i != 0) { // need to append comma
sb.append(", ");
used += 2;
}
String s = addresses[i].toString();
int len = lengthOfFirstSegment(s); // length till CRLF
if (used + len > 76) { // overflows ...
sb.append("\r\n\t"); // .. start new continuation line
used = 8; // account for the starting <tab> char
}
sb.append(s);
used = lengthOfLastSegment(s, used);
}
return sb.toString();
| public java.lang.String | toUnicodeString()Returns a properly formatted address (RFC 822 syntax) of
Unicode characters.
String p = getPersonal();
if (p != null)
return quotePhrase(p) + " <" + address + ">";
else if (isGroup() || isSimple())
return address;
else
return "<" + address + ">";
| private static java.lang.String | unquote(java.lang.String s)
if (s.startsWith("\"") && s.endsWith("\"")) {
s = s.substring(1, s.length() - 1);
// check for any escaped characters
if (s.indexOf('\\") >= 0) {
StringBuffer sb = new StringBuffer(s.length()); // approx
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\" && i < s.length() - 1)
c = s.charAt(++i);
sb.append(c);
}
s = sb.toString();
}
}
return s;
| public void | validate()Validate that this address conforms to the syntax rules of
RFC 822. The current implementation checks many, but not
all, syntax rules. Note that even though the syntax of
the address may be correct, there's no guarantee that a
mailbox of that name exists.
checkAddress(getAddress(), true, true);
|
|