1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/autofill/core/browser/data_model/phone_number.h"
6
7 #include <algorithm>
8
9 #include "base/check_op.h"
10 #include "base/notreached.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/autofill/core/browser/autofill_type.h"
15 #include "components/autofill/core/browser/data_model/autofill_profile.h"
16 #include "components/autofill/core/browser/data_model/data_model_utils.h"
17 #include "components/autofill/core/browser/field_types.h"
18 #include "components/autofill/core/browser/geo/autofill_country.h"
19 #include "components/autofill/core/browser/geo/phone_number_i18n.h"
20 #include "components/autofill/core/common/autofill_features.h"
21
22 namespace autofill {
23
24 using structured_address::VerificationStatus;
25
26 namespace {
27
28 // Returns the region code for this phone number, which is an ISO 3166 2-letter
29 // country code. The returned value is based on the |profile|; if the |profile|
30 // does not have a country code associated with it, falls back to the country
31 // code corresponding to the |app_locale|.
GetRegion(const AutofillProfile & profile,const std::string & app_locale)32 std::string GetRegion(const AutofillProfile& profile,
33 const std::string& app_locale) {
34 base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
35 if (!country_code.empty())
36 return base::UTF16ToASCII(country_code);
37
38 return AutofillCountry::CountryCodeForLocale(app_locale);
39 }
40
41 } // namespace
42
PhoneNumber(const AutofillProfile * profile)43 PhoneNumber::PhoneNumber(const AutofillProfile* profile) : profile_(profile) {}
44
PhoneNumber(const PhoneNumber & number)45 PhoneNumber::PhoneNumber(const PhoneNumber& number) : profile_(nullptr) {
46 *this = number;
47 }
48
~PhoneNumber()49 PhoneNumber::~PhoneNumber() {}
50
operator =(const PhoneNumber & number)51 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
52 if (this == &number)
53 return *this;
54
55 number_ = number.number_;
56 profile_ = number.profile_;
57 cached_parsed_phone_ = number.cached_parsed_phone_;
58 return *this;
59 }
60
operator ==(const PhoneNumber & other) const61 bool PhoneNumber::operator==(const PhoneNumber& other) const {
62 if (this == &other)
63 return true;
64
65 return number_ == other.number_ && profile_ == other.profile_;
66 }
67
GetSupportedTypes(ServerFieldTypeSet * supported_types) const68 void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
69 supported_types->insert(PHONE_HOME_WHOLE_NUMBER);
70 supported_types->insert(PHONE_HOME_NUMBER);
71 supported_types->insert(PHONE_HOME_CITY_CODE);
72 supported_types->insert(PHONE_HOME_CITY_AND_NUMBER);
73 supported_types->insert(PHONE_HOME_COUNTRY_CODE);
74 }
75
GetRawInfo(ServerFieldType type) const76 base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
77 DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
78 if (type == PHONE_HOME_WHOLE_NUMBER)
79 return number_;
80
81 // Only the whole number is available as raw data. All of the other types are
82 // parsed from this raw info, and parsing requires knowledge of the phone
83 // number's region, which is only available via GetInfo().
84 return base::string16();
85 }
86
SetRawInfoWithVerificationStatus(ServerFieldType type,const base::string16 & value,VerificationStatus status)87 void PhoneNumber::SetRawInfoWithVerificationStatus(ServerFieldType type,
88 const base::string16& value,
89 VerificationStatus status) {
90 DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
91 if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
92 // Only full phone numbers should be set directly. The remaining field
93 // field types are read-only.
94 return;
95 }
96
97 number_ = value;
98
99 // Invalidate the cached number.
100 cached_parsed_phone_ = i18n::PhoneObject();
101 }
102
GetMatchingTypes(const base::string16 & text,const std::string & app_locale,ServerFieldTypeSet * matching_types) const103 void PhoneNumber::GetMatchingTypes(const base::string16& text,
104 const std::string& app_locale,
105 ServerFieldTypeSet* matching_types) const {
106 // Strip the common phone number non numerical characters before calling the
107 // base matching type function. For example, the |text| "(514) 121-1523"
108 // would become the stripped text "5141211523". Since the base matching
109 // function only does simple canonicalization to match against the stored
110 // data, some domain specific cases will be covered below.
111 base::string16 stripped_text = text;
112 base::RemoveChars(stripped_text, base::ASCIIToUTF16(" .()-"), &stripped_text);
113 FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
114
115 // For US numbers, also compare to the three-digit prefix and the four-digit
116 // suffix, since web sites often split numbers into these two fields.
117 base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
118 if (GetRegion(*profile_, app_locale) == "US" &&
119 number.size() == (kPrefixLength + kSuffixLength)) {
120 base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
121 base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
122 if (text == prefix || text == suffix)
123 matching_types->insert(PHONE_HOME_NUMBER);
124 }
125
126 // TODO(crbug.com/581391): Investigate the use of PhoneNumberUtil when
127 // matching phone numbers for upload.
128 // If there is not already a match for PHONE_HOME_WHOLE_NUMBER, normalize the
129 // |text| based on the app_locale before comparing it to the whole number. For
130 // example, the France number "33 2 49 19 70 70" would be normalized to
131 // "+33249197070" whereas the US number "+1 (234) 567-8901" would be
132 // normalized to "12345678901".
133 if (matching_types->find(PHONE_HOME_WHOLE_NUMBER) == matching_types->end()) {
134 base::string16 whole_number =
135 GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
136 if (!whole_number.empty()) {
137 base::string16 normalized_number =
138 i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
139 if (normalized_number == whole_number)
140 matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
141 }
142 }
143
144 // |PHONE_HOME_COUNTRY_CODE| is added to the set of the |matching_types| when
145 // the digits extracted from the |stripped_text| match the |country_code|.
146 if (base::FeatureList::IsEnabled(
147 features::kAutofillEnableAugmentedPhoneCountryCode)) {
148 base::string16 candidate =
149 data_util::FindPossiblePhoneCountryCode(stripped_text);
150 base::string16 country_code =
151 GetInfo(AutofillType(PHONE_HOME_COUNTRY_CODE), app_locale);
152 if (candidate.size() > 0 && candidate == country_code)
153 matching_types->insert(PHONE_HOME_COUNTRY_CODE);
154 }
155 }
156
157 // Normalize phones if |type| is a whole number:
158 // (650)2345678 -> 6502345678
159 // 1-800-FLOWERS -> 18003569377
160 // If the phone cannot be normalized, returns the stored value verbatim.
GetInfoImpl(const AutofillType & type,const std::string & app_locale) const161 base::string16 PhoneNumber::GetInfoImpl(const AutofillType& type,
162 const std::string& app_locale) const {
163 ServerFieldType storable_type = type.GetStorableType();
164 UpdateCacheIfNeeded(app_locale);
165
166 // When the phone number autofill has stored cannot be normalized, it
167 // responds to queries for complete numbers with whatever the raw stored value
168 // is, and simply return empty string for any queries for phone components.
169 if (!cached_parsed_phone_.IsValidNumber()) {
170 if (storable_type == PHONE_HOME_WHOLE_NUMBER ||
171 storable_type == PHONE_HOME_CITY_AND_NUMBER) {
172 return cached_parsed_phone_.GetWholeNumber();
173 }
174 return base::string16();
175 }
176
177 switch (storable_type) {
178 case PHONE_HOME_WHOLE_NUMBER:
179 return cached_parsed_phone_.GetWholeNumber();
180
181 case PHONE_HOME_NUMBER:
182 return cached_parsed_phone_.number();
183
184 case PHONE_HOME_CITY_CODE:
185 return cached_parsed_phone_.city_code();
186
187 case PHONE_HOME_COUNTRY_CODE:
188 return cached_parsed_phone_.country_code();
189
190 case PHONE_HOME_CITY_AND_NUMBER: {
191 // Just concatenating city code and phone number is insufficient because
192 // a number of non-US countries (e.g. Germany and France) use a leading 0
193 // to indicate that the next digits represent a city code.
194 base::string16 national_number =
195 cached_parsed_phone_.GetNationallyFormattedNumber();
196 // GetNationallyFormattedNumber optimizes for screen display, e.g. it
197 // shows a US number as (888) 123-1234. The following retains only the
198 // digits.
199 national_number.erase(
200 std::remove_if(national_number.begin(), national_number.end(),
201 [](auto c) { return !std::isdigit(c); }),
202 national_number.end());
203 return national_number;
204 }
205
206 case PHONE_HOME_EXTENSION:
207 return base::string16();
208
209 default:
210 NOTREACHED();
211 return base::string16();
212 }
213 }
214
SetInfoWithVerificationStatusImpl(const AutofillType & type,const base::string16 & value,const std::string & app_locale,VerificationStatus status)215 bool PhoneNumber::SetInfoWithVerificationStatusImpl(
216 const AutofillType& type,
217 const base::string16& value,
218 const std::string& app_locale,
219 VerificationStatus status) {
220 SetRawInfoWithVerificationStatus(type.GetStorableType(), value, status);
221
222 if (number_.empty())
223 return true;
224
225 // Store a formatted (i.e., pretty printed) version of the number if either
226 // the number doesn't contain formatting marks.
227 UpdateCacheIfNeeded(app_locale);
228 if (base::ContainsOnlyChars(number_, base::ASCIIToUTF16("+0123456789"))) {
229 number_ = cached_parsed_phone_.GetFormattedNumber();
230 } else if (i18n::NormalizePhoneNumber(number_,
231 GetRegion(*profile_, app_locale))
232 .empty()) {
233 // The number doesn't make sense for this region; clear it.
234 number_.clear();
235 }
236 return !number_.empty();
237 }
238
UpdateCacheIfNeeded(const std::string & app_locale) const239 void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const {
240 std::string region = GetRegion(*profile_, app_locale);
241 if (!number_.empty() && cached_parsed_phone_.region() != region)
242 cached_parsed_phone_ = i18n::PhoneObject(number_, region);
243 }
244
PhoneCombineHelper()245 PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() {}
246
~PhoneCombineHelper()247 PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() {}
248
SetInfo(const AutofillType & type,const base::string16 & value)249 bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
250 const base::string16& value) {
251 ServerFieldType storable_type = type.GetStorableType();
252 if (storable_type == PHONE_HOME_COUNTRY_CODE) {
253 country_ = value;
254 return true;
255 }
256
257 if (storable_type == PHONE_HOME_CITY_CODE) {
258 city_ = value;
259 return true;
260 }
261
262 if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
263 phone_ = value;
264 return true;
265 }
266
267 if (storable_type == PHONE_HOME_WHOLE_NUMBER) {
268 whole_number_ = value;
269 return true;
270 }
271
272 if (storable_type == PHONE_HOME_NUMBER) {
273 phone_.append(value);
274 return true;
275 }
276
277 return false;
278 }
279
ParseNumber(const AutofillProfile & profile,const std::string & app_locale,base::string16 * value)280 bool PhoneNumber::PhoneCombineHelper::ParseNumber(
281 const AutofillProfile& profile,
282 const std::string& app_locale,
283 base::string16* value) {
284 if (IsEmpty())
285 return false;
286
287 if (!whole_number_.empty()) {
288 *value = whole_number_;
289 return true;
290 }
291
292 return i18n::ConstructPhoneNumber(country_, city_, phone_,
293 GetRegion(profile, app_locale), value);
294 }
295
IsEmpty() const296 bool PhoneNumber::PhoneCombineHelper::IsEmpty() const {
297 return phone_.empty() && whole_number_.empty();
298 }
299
300 } // namespace autofill
301