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