001/****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one   *
003 * or more contributor license agreements.  See the NOTICE file *
004 * distributed with this work for additional information        *
005 * regarding copyright ownership.  The ASF licenses this file   *
006 * to you under the Apache License, Version 2.0 (the            *
007 * "License"); you may not use this file except in compliance   *
008 * with the License.  You may obtain a copy of the License at   *
009 *                                                              *
010 *   http://www.apache.org/licenses/LICENSE-2.0                 *
011 *                                                              *
012 * Unless required by applicable law or agreed to in writing,   *
013 * software distributed under the License is distributed on an  *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015 * KIND, either express or implied.  See the License for the    *
016 * specific language governing permissions and limitations      *
017 * under the License.                                           *
018 ****************************************************************/
019
020package org.apache.james.mime4j.field.address;
021
022import org.apache.james.mime4j.codec.EncoderUtil;
023import org.apache.james.mime4j.dom.address.Address;
024import org.apache.james.mime4j.dom.address.Group;
025import org.apache.james.mime4j.dom.address.Mailbox;
026
027/**
028 * Default formatter for {@link Address} and its subclasses.
029 */
030public class AddressFormatter {
031
032    public static final AddressFormatter DEFAULT = new AddressFormatter();
033
034    protected AddressFormatter() {
035        super();
036    }
037
038    /**
039     * Formats the address as a human readable string, not including the route.
040     * The resulting string is intended for display purposes only and cannot be
041     * used for transport purposes.
042     *
043     * For example, if the unparsed address was
044     *
045     * <"Joe Cheng"@joecheng.com>
046     *
047     * this method would return
048     *
049     * <Joe Cheng@joecheng.com>
050     *
051     * which is not valid for transport; the local part would need to be
052     * re-quoted.
053     *
054     * @param includeRoute
055     *            <code>true</code> if the route should be included if it
056     *            exists, <code>false</code> otherwise.
057     */
058    public void format(final StringBuilder sb, final Address address, boolean includeRoute) {
059        if (address == null) {
060            return;
061        }
062        if (address instanceof Mailbox) {
063            format(sb, (Mailbox) address, includeRoute);
064        } else if (address instanceof Group) {
065            format(sb, (Group) address, includeRoute);
066        } else {
067            throw new IllegalArgumentException("Unsuppported Address class: " + address.getClass());
068        }
069    }
070
071    /**
072     * Returns a string representation of this address that can be used for
073     * transport purposes. The route is never included in this representation
074     * because routes are obsolete and RFC 5322 states that obsolete syntactic
075     * forms MUST NOT be generated.
076     */
077    public void encode(final StringBuilder sb, final Address address) {
078        if (address == null) {
079            return;
080        }
081        if (address instanceof Mailbox) {
082            encode(sb, (Mailbox) address);
083        } else if (address instanceof Group) {
084            encode(sb, (Group) address);
085        } else {
086            throw new IllegalArgumentException("Unsuppported Address class: " + address.getClass());
087        }
088    }
089
090    public void format(final StringBuilder sb, final Mailbox mailbox, boolean includeRoute) {
091        if (sb == null) {
092            throw new IllegalArgumentException("StringBuilder may not be null");
093        }
094        if (mailbox == null) {
095            throw new IllegalArgumentException("Mailbox may not be null");
096        }
097        includeRoute &= mailbox.getRoute() != null;
098        boolean includeAngleBrackets = mailbox.getName() != null || includeRoute;
099        if (mailbox.getName() != null) {
100            sb.append(mailbox.getName());
101            sb.append(' ');
102        }
103        if (includeAngleBrackets) {
104            sb.append('<');
105        }
106        if (includeRoute) {
107            sb.append(mailbox.getRoute().toRouteString());
108            sb.append(':');
109        }
110        sb.append(mailbox.getLocalPart());
111        if (mailbox.getDomain() != null) {
112            sb.append('@');
113            sb.append(mailbox.getDomain());
114        }
115        if (includeAngleBrackets) {
116            sb.append('>');
117        }
118    }
119
120    public String format(final Mailbox mailbox, boolean includeRoute) {
121        StringBuilder sb = new StringBuilder();
122        format(sb, mailbox, includeRoute);
123        return sb.toString();
124    }
125
126    public void encode(final StringBuilder sb, final Mailbox mailbox) {
127        if (sb == null) {
128            throw new IllegalArgumentException("StringBuilder may not be null");
129        }
130        if (mailbox == null) {
131            throw new IllegalArgumentException("Mailbox may not be null");
132        }
133        if (mailbox.getName() != null) {
134            sb.append(EncoderUtil.encodeAddressDisplayName(mailbox.getName()));
135            sb.append(" <");
136        }
137        sb.append(EncoderUtil.encodeAddressLocalPart(mailbox.getLocalPart()));
138        // domain = dot-atom / domain-literal
139        // domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
140        // dtext = %d33-90 / %d94-126
141        if (mailbox.getDomain() != null) {
142            sb.append('@');
143            sb.append(mailbox.getDomain());
144        }
145        if (mailbox.getName() != null) {
146            sb.append('>');
147        }
148    }
149
150    public String encode(final Mailbox mailbox) {
151        StringBuilder sb = new StringBuilder();
152        encode(sb, mailbox);
153        return sb.toString();
154    }
155
156    public void format(final StringBuilder sb, final Group group, boolean includeRoute) {
157        if (sb == null) {
158            throw new IllegalArgumentException("StringBuilder may not be null");
159        }
160        if (group == null) {
161            throw new IllegalArgumentException("Group may not be null");
162        }
163        sb.append(group.getName());
164        sb.append(':');
165
166        boolean first = true;
167        for (Mailbox mailbox : group.getMailboxes()) {
168            if (first) {
169                first = false;
170            } else {
171                sb.append(',');
172            }
173            sb.append(' ');
174            format(sb, mailbox, includeRoute);
175        }
176        sb.append(";");
177    }
178
179    public String format(final Group group, boolean includeRoute) {
180        StringBuilder sb = new StringBuilder();
181        format(sb, group, includeRoute);
182        return sb.toString();
183    }
184
185    public void encode(final StringBuilder sb, final Group group) {
186        if (sb == null) {
187            throw new IllegalArgumentException("StringBuilder may not be null");
188        }
189        if (group == null) {
190            throw new IllegalArgumentException("Group may not be null");
191        }
192        sb.append(EncoderUtil.encodeAddressDisplayName(group.getName()));
193        sb.append(':');
194        boolean first = true;
195        for (Mailbox mailbox : group.getMailboxes()) {
196            if (first) {
197                first = false;
198            } else {
199                sb.append(',');
200            }
201
202            sb.append(' ');
203            encode(sb, mailbox);
204        }
205        sb.append(';');
206    }
207
208    public String encode(final Group group) {
209        StringBuilder sb = new StringBuilder();
210        encode(sb, group);
211        return sb.toString();
212    }
213
214}