• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/phone_number_i18n.h"
6 
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "components/autofill/core/browser/autofill_country.h"
14 #include "third_party/libphonenumber/src/phonenumber_api.h"
15 
16 using i18n::phonenumbers::PhoneNumber;
17 using i18n::phonenumbers::PhoneNumberUtil;
18 
19 namespace autofill {
20 
21 namespace {
22 
SanitizeRegion(const std::string & region,const std::string & app_locale)23 std::string SanitizeRegion(const std::string& region,
24                            const std::string& app_locale) {
25   if (region.length() == 2)
26     return region;
27 
28   return AutofillCountry::CountryCodeForLocale(app_locale);
29 }
30 
31 // Returns true if |phone_number| is valid.
IsValidPhoneNumber(const PhoneNumber & phone_number)32 bool IsValidPhoneNumber(const PhoneNumber& phone_number) {
33   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
34   if (!phone_util->IsPossibleNumber(phone_number))
35     return false;
36 
37   // Verify that the number has a valid area code (that in some cases could be
38   // empty) for the parsed country code.  Also verify that this is a valid
39   // number (for example, in the US 1234567 is not valid, because numbers do not
40   // start with 1).
41   if (!phone_util->IsValidNumber(phone_number))
42     return false;
43 
44   return true;
45 }
46 
47 // Formats the given |number| as a human-readable string, and writes the result
48 // into |formatted_number|.  Also, normalizes the formatted number, and writes
49 // that result into |normalized_number|.  This function should only be called
50 // with numbers already known to be valid, i.e. validation should be done prior
51 // to calling this function.  Note that the |country_code|, which determines
52 // whether to format in the national or in the international format, is passed
53 // in explicitly, as |number| might have an implicit country code set, even
54 // though the original input lacked a country code.
FormatValidatedNumber(const PhoneNumber & number,const base::string16 & country_code,base::string16 * formatted_number,base::string16 * normalized_number)55 void FormatValidatedNumber(const PhoneNumber& number,
56                            const base::string16& country_code,
57                            base::string16* formatted_number,
58                            base::string16* normalized_number) {
59   PhoneNumberUtil::PhoneNumberFormat format =
60       country_code.empty() ?
61       PhoneNumberUtil::NATIONAL :
62       PhoneNumberUtil::INTERNATIONAL;
63 
64   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
65   std::string processed_number;
66   phone_util->Format(number, format, &processed_number);
67 
68   std::string region_code;
69   phone_util->GetRegionCodeForNumber(number, &region_code);
70 
71   // Drop the leading '+' for US numbers as some US sites can't handle the "+",
72   // and in the US dialing "+1..." is the same as dialing "1...".
73   std::string prefix;
74   if (processed_number[0] == '+') {
75     processed_number = processed_number.substr(1);
76     if (region_code != "US")
77       prefix = "+";
78   }
79 
80   if (formatted_number)
81     *formatted_number = base::UTF8ToUTF16(prefix + processed_number);
82 
83   if (normalized_number) {
84     phone_util->NormalizeDigitsOnly(&processed_number);
85     *normalized_number = base::UTF8ToUTF16(prefix + processed_number);
86   }
87 }
88 
89 }  // namespace
90 
91 namespace i18n {
92 
93 // Parses the number stored in |value| as it should be interpreted in the given
94 // |default_region|, and stores the results into the remaining arguments.
95 // The |default_region| should be sanitized prior to calling this function.
ParsePhoneNumber(const base::string16 & value,const std::string & default_region,base::string16 * country_code,base::string16 * city_code,base::string16 * number,std::string * inferred_region,PhoneNumber * i18n_number)96 bool ParsePhoneNumber(const base::string16& value,
97                       const std::string& default_region,
98                       base::string16* country_code,
99                       base::string16* city_code,
100                       base::string16* number,
101                       std::string* inferred_region,
102                       PhoneNumber* i18n_number) {
103   country_code->clear();
104   city_code->clear();
105   number->clear();
106   *i18n_number = PhoneNumber();
107 
108   std::string number_text(base::UTF16ToUTF8(value));
109 
110   // Parse phone number based on the region.
111   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
112 
113   // The |default_region| should already be sanitized.
114   DCHECK_EQ(2U, default_region.size());
115   if (phone_util->ParseAndKeepRawInput(
116           number_text, default_region, i18n_number) !=
117       PhoneNumberUtil::NO_PARSING_ERROR) {
118     return false;
119   }
120 
121   if (!IsValidPhoneNumber(*i18n_number))
122     return false;
123 
124   std::string national_significant_number;
125   phone_util->GetNationalSignificantNumber(*i18n_number,
126                                            &national_significant_number);
127 
128   int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
129   int destination_length =
130       phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
131   // Some phones have a destination code in lieu of area code: mobile operators
132   // in Europe, toll and toll-free numbers in USA, etc. From our point of view
133   // these two types of codes are the same.
134   if (destination_length > area_length)
135     area_length = destination_length;
136 
137   std::string area_code;
138   std::string subscriber_number;
139   if (area_length > 0) {
140     area_code = national_significant_number.substr(0, area_length);
141     subscriber_number = national_significant_number.substr(area_length);
142   } else {
143     subscriber_number = national_significant_number;
144   }
145   *number = base::UTF8ToUTF16(subscriber_number);
146   *city_code = base::UTF8ToUTF16(area_code);
147 
148   // Check if parsed number has a country code that was not inferred from the
149   // region.
150   if (i18n_number->has_country_code() &&
151       i18n_number->country_code_source() != PhoneNumber::FROM_DEFAULT_COUNTRY) {
152     *country_code = base::UTF8ToUTF16(
153         base::StringPrintf("%d", i18n_number->country_code()));
154   }
155 
156   // The region might be different from what we started with.
157   phone_util->GetRegionCodeForNumber(*i18n_number, inferred_region);
158 
159   return true;
160 }
161 
NormalizePhoneNumber(const base::string16 & value,const std::string & region)162 base::string16 NormalizePhoneNumber(const base::string16& value,
163                                     const std::string& region) {
164   DCHECK_EQ(2u, region.size());
165   base::string16 country_code, unused_city_code, unused_number;
166   std::string unused_region;
167   PhoneNumber phone_number;
168   if (!ParsePhoneNumber(value, region, &country_code, &unused_city_code,
169                         &unused_number, &unused_region, &phone_number)) {
170     return base::string16();  // Parsing failed - do not store phone.
171   }
172 
173   base::string16 normalized_number;
174   FormatValidatedNumber(phone_number, country_code, NULL, &normalized_number);
175   return normalized_number;
176 }
177 
ConstructPhoneNumber(const base::string16 & country_code,const base::string16 & city_code,const base::string16 & number,const std::string & region,base::string16 * whole_number)178 bool ConstructPhoneNumber(const base::string16& country_code,
179                           const base::string16& city_code,
180                           const base::string16& number,
181                           const std::string& region,
182                           base::string16* whole_number) {
183   DCHECK_EQ(2u, region.size());
184   whole_number->clear();
185 
186   base::string16 unused_country_code, unused_city_code, unused_number;
187   std::string unused_region;
188   PhoneNumber phone_number;
189   if (!ParsePhoneNumber(country_code + city_code + number, region,
190                         &unused_country_code, &unused_city_code, &unused_number,
191                         &unused_region, &phone_number)) {
192     return false;
193   }
194 
195   FormatValidatedNumber(phone_number, country_code, whole_number, NULL);
196   return true;
197 }
198 
PhoneNumbersMatch(const base::string16 & number_a,const base::string16 & number_b,const std::string & raw_region,const std::string & app_locale)199 bool PhoneNumbersMatch(const base::string16& number_a,
200                        const base::string16& number_b,
201                        const std::string& raw_region,
202                        const std::string& app_locale) {
203   // Sanitize the provided |raw_region| before trying to use it for parsing.
204   const std::string region = SanitizeRegion(raw_region, app_locale);
205 
206   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
207 
208   // Parse phone numbers based on the region
209   PhoneNumber i18n_number1;
210   if (phone_util->Parse(
211           base::UTF16ToUTF8(number_a), region.c_str(), &i18n_number1) !=
212               PhoneNumberUtil::NO_PARSING_ERROR) {
213     return false;
214   }
215 
216   PhoneNumber i18n_number2;
217   if (phone_util->Parse(
218           base::UTF16ToUTF8(number_b), region.c_str(), &i18n_number2) !=
219               PhoneNumberUtil::NO_PARSING_ERROR) {
220     return false;
221   }
222 
223   switch (phone_util->IsNumberMatch(i18n_number1, i18n_number2)) {
224     case PhoneNumberUtil::INVALID_NUMBER:
225     case PhoneNumberUtil::NO_MATCH:
226       return false;
227     case PhoneNumberUtil::SHORT_NSN_MATCH:
228       return false;
229     case PhoneNumberUtil::NSN_MATCH:
230     case PhoneNumberUtil::EXACT_MATCH:
231       return true;
232   }
233 
234   NOTREACHED();
235   return false;
236 }
237 
PhoneObject(const base::string16 & number,const std::string & region)238 PhoneObject::PhoneObject(const base::string16& number,
239                          const std::string& region) {
240   DCHECK_EQ(2u, region.size());
241   // TODO(isherman): Autofill profiles should always have a |region| set, but in
242   // some cases it should be marked as implicit.  Otherwise, phone numbers
243   // might behave differently when they are synced across computers:
244   // [ http://crbug.com/100845 ].  Once the bug is fixed, add a DCHECK here to
245   // verify.
246 
247   scoped_ptr<PhoneNumber> i18n_number(new PhoneNumber);
248   if (ParsePhoneNumber(number, region, &country_code_, &city_code_, &number_,
249                        &region_, i18n_number.get())) {
250     // The phone number was successfully parsed, so store the parsed version.
251     // The formatted and normalized versions will be set on the first call to
252     // the coresponding methods.
253     i18n_number_ = i18n_number.Pass();
254   } else {
255     // Parsing failed. Store passed phone "as is" into |whole_number_|.
256     whole_number_ = number;
257   }
258 }
259 
PhoneObject(const PhoneObject & other)260 PhoneObject::PhoneObject(const PhoneObject& other) { *this = other; }
261 
PhoneObject()262 PhoneObject::PhoneObject() {}
263 
~PhoneObject()264 PhoneObject::~PhoneObject() {}
265 
GetFormattedNumber() const266 const base::string16& PhoneObject::GetFormattedNumber() const {
267   if (i18n_number_ && formatted_number_.empty()) {
268     FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
269                           &whole_number_);
270   }
271 
272   return formatted_number_;
273 }
274 
GetNationallyFormattedNumber() const275 base::string16 PhoneObject::GetNationallyFormattedNumber() const {
276   base::string16 formatted = whole_number_;
277   if (i18n_number_)
278     FormatValidatedNumber(*i18n_number_, base::string16(), &formatted, NULL);
279 
280   return formatted;
281 }
282 
GetWholeNumber() const283 const base::string16& PhoneObject::GetWholeNumber() const {
284   if (i18n_number_ && whole_number_.empty()) {
285     FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
286                           &whole_number_);
287   }
288 
289   return whole_number_;
290 }
291 
operator =(const PhoneObject & other)292 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
293   if (this == &other)
294     return *this;
295 
296   region_ = other.region_;
297 
298   if (other.i18n_number_.get())
299     i18n_number_.reset(new PhoneNumber(*other.i18n_number_));
300   else
301     i18n_number_.reset();
302 
303   country_code_ = other.country_code_;
304   city_code_ = other.city_code_;
305   number_ = other.number_;
306 
307   formatted_number_ = other.formatted_number_;
308   whole_number_ = other.whole_number_;
309 
310   return *this;
311 }
312 
313 }  // namespace i18n
314 }  // namespace autofill
315