View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.mime4j.field.address;
21  
22  import java.io.StringReader;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Locale;
26  
27  import org.apache.james.mime4j.codec.EncoderUtil;
28  import org.apache.james.mime4j.field.address.parser.AddressListParser;
29  import org.apache.james.mime4j.field.address.parser.ParseException;
30  
31  /**
32   * Represents a single e-mail address.
33   */
34  public class Mailbox extends Address {
35  
36      private static final long serialVersionUID = 1L;
37  
38      private static final DomainList EMPTY_ROUTE_LIST = new DomainList(
39              Collections.<String> emptyList(), true);
40  
41      private final String name;
42      private final DomainList route;
43      private final String localPart;
44      private final String domain;
45  
46      /**
47       * Creates an unnamed mailbox without a route. Routes are obsolete.
48       * 
49       * @param localPart
50       *            The part of the e-mail address to the left of the "@".
51       * @param domain
52       *            The part of the e-mail address to the right of the "@".
53       */
54      public Mailbox(String localPart, String domain) {
55          this(null, null, localPart, domain);
56      }
57  
58      /**
59       * Creates an unnamed mailbox with a route. Routes are obsolete.
60       * 
61       * @param route
62       *            The zero or more domains that make up the route. May be
63       *            <code>null</code>.
64       * @param localPart
65       *            The part of the e-mail address to the left of the "@".
66       * @param domain
67       *            The part of the e-mail address to the right of the "@".
68       */
69      public Mailbox(DomainList route, String localPart, String domain) {
70          this(null, route, localPart, domain);
71      }
72  
73      /**
74       * Creates a named mailbox without a route. Routes are obsolete.
75       * 
76       * @param name
77       *            the name of the e-mail address. May be <code>null</code>.
78       * @param localPart
79       *            The part of the e-mail address to the left of the "@".
80       * @param domain
81       *            The part of the e-mail address to the right of the "@".
82       */
83      public Mailbox(String name, String localPart, String domain) {
84          this(name, null, localPart, domain);
85      }
86  
87      /**
88       * Creates a named mailbox with a route. Routes are obsolete.
89       * 
90       * @param name
91       *            the name of the e-mail address. May be <code>null</code>.
92       * @param route
93       *            The zero or more domains that make up the route. May be
94       *            <code>null</code>.
95       * @param localPart
96       *            The part of the e-mail address to the left of the "@".
97       * @param domain
98       *            The part of the e-mail address to the right of the "@".
99       */
100     public Mailbox(String name, DomainList route, String localPart,
101             String domain) {
102         if (localPart == null || localPart.length() == 0)
103             throw new IllegalArgumentException();
104 
105         this.name = name == null || name.length() == 0 ? null : name;
106         this.route = route == null ? EMPTY_ROUTE_LIST : route;
107         this.localPart = localPart;
108         this.domain = domain == null || domain.length() == 0 ? null : domain;
109     }
110 
111     /**
112      * Creates a named mailbox based on an unnamed mailbox. Package private;
113      * internally used by Builder.
114      */
115     Mailbox(String name, Mailbox baseMailbox) {
116         this(name, baseMailbox.getRoute(), baseMailbox.getLocalPart(),
117                 baseMailbox.getDomain());
118     }
119 
120     /**
121      * Parses the specified raw string into a mailbox address.
122      * 
123      * @param rawMailboxString
124      *            string to parse.
125      * @return a <code>Mailbox</code> object for the specified string.
126      * @throws IllegalArgumentException
127      *             if the raw string does not represent a single mailbox
128      *             address.
129      */
130     public static Mailbox parse(String rawMailboxString) {
131         AddressListParser parser = new AddressListParser(new StringReader(
132                 rawMailboxString));
133         try {
134             return Builder.getInstance().buildMailbox(parser.parseMailbox());
135         } catch (ParseException e) {
136             throw new IllegalArgumentException(e);
137         }
138     }
139 
140     /**
141      * Returns the name of the mailbox or <code>null</code> if it does not
142      * have a name.
143      */
144     public String getName() {
145         return name;
146     }
147 
148     /**
149      * Returns the route list. If the mailbox does not have a route an empty
150      * domain list is returned.
151      */
152     public DomainList getRoute() {
153         return route;
154     }
155 
156     /**
157      * Returns the left part of the e-mail address (before "@").
158      */
159     public String getLocalPart() {
160         return localPart;
161     }
162 
163     /**
164      * Returns the right part of the e-mail address (after "@").
165      */
166     public String getDomain() {
167         return domain;
168     }
169 
170     /**
171      * Returns the address in the form <i>localPart@domain</i>.
172      * 
173      * @return the address part of this mailbox.
174      */
175     public String getAddress() {
176         if (domain == null) {
177             return localPart;
178         } else {
179             return localPart + '@' + domain;
180         }
181     }
182 
183     @Override
184     public String getDisplayString(boolean includeRoute) {
185         includeRoute &= route != null;
186         boolean includeAngleBrackets = name != null || includeRoute;
187 
188         StringBuilder sb = new StringBuilder();
189 
190         if (name != null) {
191             sb.append(name);
192             sb.append(' ');
193         }
194 
195         if (includeAngleBrackets) {
196             sb.append('<');
197         }
198 
199         if (includeRoute) {
200             sb.append(route.toRouteString());
201             sb.append(':');
202         }
203 
204         sb.append(localPart);
205 
206         if (domain != null) {
207             sb.append('@');
208             sb.append(domain);
209         }
210 
211         if (includeAngleBrackets) {
212             sb.append('>');
213         }
214 
215         return sb.toString();
216     }
217 
218     @Override
219     public String getEncodedString() {
220         StringBuilder sb = new StringBuilder();
221 
222         if (name != null) {
223             sb.append(EncoderUtil.encodeAddressDisplayName(name));
224             sb.append(" <");
225         }
226 
227         sb.append(EncoderUtil.encodeAddressLocalPart(localPart));
228 
229         // domain = dot-atom / domain-literal
230         // domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
231         // dtext = %d33-90 / %d94-126
232         if (domain != null) {
233             sb.append('@');
234             sb.append(domain);
235         }
236 
237         if (name != null) {
238             sb.append('>');
239         }
240 
241         return sb.toString();
242     }
243 
244     @Override
245     public int hashCode() {
246         return getCanonicalizedAddress().hashCode();
247     }
248 
249     /**
250      * Indicates whether some other object is "equal to" this mailbox.
251      * <p>
252      * An object is considered to be equal to this mailbox if it is an instance
253      * of class <code>Mailbox</code> that holds the same address as this one.
254      * The domain is considered to be case-insensitive but the local-part is not
255      * (because of RFC 5321: <cite>the local-part of a mailbox MUST BE treated
256      * as case sensitive</cite>).
257      * 
258      * @param obj
259      *            the object to test for equality.
260      * @return <code>true</code> if the specified object is a
261      *         <code>Mailbox</code> that holds the same address as this one.
262      */
263     @Override
264     public boolean equals(Object obj) {
265         if (obj == this)
266             return true;
267         if (!(obj instanceof Mailbox))
268             return false;
269 
270         Mailbox other = (Mailbox) obj;
271         return getCanonicalizedAddress()
272                 .equals(other.getCanonicalizedAddress());
273     }
274 
275     @Override
276     protected final void doAddMailboxesTo(List<Mailbox> results) {
277         results.add(this);
278     }
279 
280     private Object getCanonicalizedAddress() {
281         if (domain == null) {
282             return localPart;
283         } else {
284             return localPart + '@' + domain.toLowerCase(Locale.US);
285         }
286     }
287 
288 }