1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text.util;
18 
19 import android.annotation.Nullable;
20 
21 /**
22  * This class stores an RFC 822-like name, address, and comment,
23  * and provides methods to convert them to quoted strings.
24  */
25 public class Rfc822Token {
26     @Nullable
27     private String mName, mAddress, mComment;
28 
29     /**
30      * Creates a new Rfc822Token with the specified name, address,
31      * and comment.
32      */
Rfc822Token(@ullable String name, @Nullable String address, @Nullable String comment)33     public Rfc822Token(@Nullable String name, @Nullable String address, @Nullable String comment) {
34         mName = name;
35         mAddress = address;
36         mComment = comment;
37     }
38 
39     /**
40      * Returns the name part.
41      */
42     @Nullable
getName()43     public String getName() {
44         return mName;
45     }
46 
47     /**
48      * Returns the address part.
49      */
50     @Nullable
getAddress()51     public String getAddress() {
52         return mAddress;
53     }
54 
55     /**
56      * Returns the comment part.
57      */
58     @Nullable
getComment()59     public String getComment() {
60         return mComment;
61     }
62 
63     /**
64      * Changes the name to the specified name.
65      */
setName(@ullable String name)66     public void setName(@Nullable String name) {
67         mName = name;
68     }
69 
70     /**
71      * Changes the address to the specified address.
72      */
setAddress(@ullable String address)73     public void setAddress(@Nullable String address) {
74         mAddress = address;
75     }
76 
77     /**
78      * Changes the comment to the specified comment.
79      */
setComment(@ullable String comment)80     public void setComment(@Nullable String comment) {
81         mComment = comment;
82     }
83 
84     /**
85      * Returns the name (with quoting added if necessary),
86      * the comment (in parentheses), and the address (in angle brackets).
87      * This should be suitable for inclusion in an RFC 822 address list.
88      */
toString()89     public String toString() {
90         StringBuilder sb = new StringBuilder();
91 
92         if (mName != null && mName.length() != 0) {
93             sb.append(quoteNameIfNecessary(mName));
94             sb.append(' ');
95         }
96 
97         if (mComment != null && mComment.length() != 0) {
98             sb.append('(');
99             sb.append(quoteComment(mComment));
100             sb.append(") ");
101         }
102 
103         if (mAddress != null && mAddress.length() != 0) {
104             sb.append('<');
105             sb.append(mAddress);
106             sb.append('>');
107         }
108 
109         return sb.toString();
110     }
111 
112     /**
113      * Returns the name, conservatively quoting it if there are any
114      * characters that are likely to cause trouble outside of a
115      * quoted string, or returning it literally if it seems safe.
116      */
quoteNameIfNecessary(String name)117     public static String quoteNameIfNecessary(String name) {
118         int len = name.length();
119 
120         for (int i = 0; i < len; i++) {
121             char c = name.charAt(i);
122 
123             if (! ((c >= 'A' && c <= 'Z') ||
124                    (c >= 'a' && c <= 'z') ||
125                    (c == ' ') ||
126                    (c >= '0' && c <= '9'))) {
127                 return '"' + quoteName(name) + '"';
128             }
129         }
130 
131         return name;
132     }
133 
134     /**
135      * Returns the name, with internal backslashes and quotation marks
136      * preceded by backslashes.  The outer quote marks themselves are not
137      * added by this method.
138      */
quoteName(String name)139     public static String quoteName(String name) {
140         StringBuilder sb = new StringBuilder();
141 
142         int len = name.length();
143         for (int i = 0; i < len; i++) {
144             char c = name.charAt(i);
145 
146             if (c == '\\' || c == '"') {
147                 sb.append('\\');
148             }
149 
150             sb.append(c);
151         }
152 
153         return sb.toString();
154     }
155 
156     /**
157      * Returns the comment, with internal backslashes and parentheses
158      * preceded by backslashes.  The outer parentheses themselves are
159      * not added by this method.
160      */
quoteComment(String comment)161     public static String quoteComment(String comment) {
162         int len = comment.length();
163         StringBuilder sb = new StringBuilder();
164 
165         for (int i = 0; i < len; i++) {
166             char c = comment.charAt(i);
167 
168             if (c == '(' || c == ')' || c == '\\') {
169                 sb.append('\\');
170             }
171 
172             sb.append(c);
173         }
174 
175         return sb.toString();
176     }
177 
hashCode()178     public int hashCode() {
179         int result = 17;
180         if (mName != null) result = 31 * result + mName.hashCode();
181         if (mAddress != null) result = 31 * result + mAddress.hashCode();
182         if (mComment != null) result = 31 * result + mComment.hashCode();
183         return result;
184     }
185 
stringEquals(String a, String b)186     private static boolean stringEquals(String a, String b) {
187         if (a == null) {
188             return (b == null);
189         } else {
190             return (a.equals(b));
191         }
192     }
193 
equals(Object o)194     public boolean equals(Object o) {
195         if (!(o instanceof Rfc822Token)) {
196             return false;
197         }
198         Rfc822Token other = (Rfc822Token) o;
199         return (stringEquals(mName, other.mName) &&
200                 stringEquals(mAddress, other.mAddress) &&
201                 stringEquals(mComment, other.mComment));
202     }
203 }
204 
205