/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.mime4j.field.address;
import java.io.StringReader;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.apache.james.mime4j.codec.EncoderUtil;
import org.apache.james.mime4j.field.address.parser.AddressListParser;
import org.apache.james.mime4j.field.address.parser.ParseException;
/**
* Represents a single e-mail address.
*/
public class Mailbox extends Address {
private static final long serialVersionUID = 1L;
private static final DomainList EMPTY_ROUTE_LIST = new DomainList(
Collections.<String> emptyList(), true);
private final String name;
private final DomainList route;
private final String localPart;
private final String domain;
/**
* Creates an unnamed mailbox without a route. Routes are obsolete.
*
* @param localPart
* The part of the e-mail address to the left of the "@".
* @param domain
* The part of the e-mail address to the right of the "@".
*/
public Mailbox(String localPart, String domain) {
this(null, null, localPart, domain);
}
/**
* Creates an unnamed mailbox with a route. Routes are obsolete.
*
* @param route
* The zero or more domains that make up the route. May be
* <code>null</code>.
* @param localPart
* The part of the e-mail address to the left of the "@".
* @param domain
* The part of the e-mail address to the right of the "@".
*/
public Mailbox(DomainList route, String localPart, String domain) {
this(null, route, localPart, domain);
}
/**
* Creates a named mailbox without a route. Routes are obsolete.
*
* @param name
* the name of the e-mail address. May be <code>null</code>.
* @param localPart
* The part of the e-mail address to the left of the "@".
* @param domain
* The part of the e-mail address to the right of the "@".
*/
public Mailbox(String name, String localPart, String domain) {
this(name, null, localPart, domain);
}
/**
* Creates a named mailbox with a route. Routes are obsolete.
*
* @param name
* the name of the e-mail address. May be <code>null</code>.
* @param route
* The zero or more domains that make up the route. May be
* <code>null</code>.
* @param localPart
* The part of the e-mail address to the left of the "@".
* @param domain
* The part of the e-mail address to the right of the "@".
*/
public Mailbox(String name, DomainList route, String localPart,
String domain) {
if (localPart == null || localPart.length() == 0)
throw new IllegalArgumentException();
this.name = name == null || name.length() == 0 ? null : name;
this.route = route == null ? EMPTY_ROUTE_LIST : route;
this.localPart = localPart;
this.domain = domain == null || domain.length() == 0 ? null : domain;
}
/**
* Creates a named mailbox based on an unnamed mailbox. Package private;
* internally used by Builder.
*/
Mailbox(String name, Mailbox baseMailbox) {
this(name, baseMailbox.getRoute(), baseMailbox.getLocalPart(),
baseMailbox.getDomain());
}
/**
* Parses the specified raw string into a mailbox address.
*
* @param rawMailboxString
* string to parse.
* @return a <code>Mailbox</code> object for the specified string.
* @throws IllegalArgumentException
* if the raw string does not represent a single mailbox
* address.
*/
public static Mailbox parse(String rawMailboxString) {
AddressListParser parser = new AddressListParser(new StringReader(
rawMailboxString));
try {
return Builder.getInstance().buildMailbox(parser.parseMailbox());
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Returns the name of the mailbox or <code>null</code> if it does not
* have a name.
*/
public String getName() {
return name;
}
/**
* Returns the route list. If the mailbox does not have a route an empty
* domain list is returned.
*/
public DomainList getRoute() {
return route;
}
/**
* Returns the left part of the e-mail address (before "@").
*/
public String getLocalPart() {
return localPart;
}
/**
* Returns the right part of the e-mail address (after "@").
*/
public String getDomain() {
return domain;
}
/**
* Returns the address in the form <i>localPart@domain</i>.
*
* @return the address part of this mailbox.
*/
public String getAddress() {
if (domain == null) {
return localPart;
} else {
return localPart + '@' + domain;
}
}
@Override
public String getDisplayString(boolean includeRoute) {
includeRoute &= route != null;
boolean includeAngleBrackets = name != null || includeRoute;
StringBuilder sb = new StringBuilder();
if (name != null) {
sb.append(name);
sb.append(' ');
}
if (includeAngleBrackets) {
sb.append('<');
}
if (includeRoute) {
sb.append(route.toRouteString());
sb.append(':');
}
sb.append(localPart);
if (domain != null) {
sb.append('@');
sb.append(domain);
}
if (includeAngleBrackets) {
sb.append('>');
}
return sb.toString();
}
@Override
public String getEncodedString() {
StringBuilder sb = new StringBuilder();
if (name != null) {
sb.append(EncoderUtil.encodeAddressDisplayName(name));
sb.append(" <");
}
sb.append(EncoderUtil.encodeAddressLocalPart(localPart));
// domain = dot-atom / domain-literal
// domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
// dtext = %d33-90 / %d94-126
if (domain != null) {
sb.append('@');
sb.append(domain);
}
if (name != null) {
sb.append('>');
}
return sb.toString();
}
@Override
public int hashCode() {
return getCanonicalizedAddress().hashCode();
}
/**
* Indicates whether some other object is "equal to" this mailbox.
* <p>
* An object is considered to be equal to this mailbox if it is an instance
* of class <code>Mailbox</code> that holds the same address as this one.
* The domain is considered to be case-insensitive but the local-part is not
* (because of RFC 5321: <cite>the local-part of a mailbox MUST BE treated
* as case sensitive</cite>).
*
* @param obj
* the object to test for equality.
* @return <code>true</code> if the specified object is a
* <code>Mailbox</code> that holds the same address as this one.
*/
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Mailbox))
return false;
Mailbox other = (Mailbox) obj;
return getCanonicalizedAddress()
.equals(other.getCanonicalizedAddress());
}
@Override
protected final void doAddMailboxesTo(List<Mailbox> results) {
results.add(this);
}
private Object getCanonicalizedAddress() {
if (domain == null) {
return localPart;
} else {
return localPart + '@' + domain.toLowerCase(Locale.US);
}
}
}