Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / components / autofill / core / browser / phone_number_i18n.cc
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
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.
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.
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   if (formatted_number)
69     *formatted_number = base::UTF8ToUTF16(processed_number);
70
71   if (normalized_number) {
72     phone_util->NormalizeDigitsOnly(&processed_number);
73     *normalized_number = base::UTF8ToUTF16(processed_number);
74   }
75 }
76
77 }  // namespace
78
79 namespace i18n {
80
81 // Parses the number stored in |value| as it should be interpreted in the given
82 // |region|, and stores the results into the remaining arguments.  The |region|
83 // should be sanitized prior to calling this function.
84 bool ParsePhoneNumber(const base::string16& value,
85                       const std::string& region,
86                       base::string16* country_code,
87                       base::string16* city_code,
88                       base::string16* number,
89                       PhoneNumber* i18n_number) {
90   country_code->clear();
91   city_code->clear();
92   number->clear();
93   *i18n_number = PhoneNumber();
94
95   std::string number_text(base::UTF16ToUTF8(value));
96
97   // Parse phone number based on the region.
98   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
99
100   // The |region| should already be sanitized.
101   DCHECK_EQ(2U, region.size());
102   if (phone_util->Parse(number_text, region.c_str(), i18n_number) !=
103           PhoneNumberUtil::NO_PARSING_ERROR) {
104     return false;
105   }
106
107   if (!IsValidPhoneNumber(*i18n_number))
108     return false;
109
110   std::string national_significant_number;
111   phone_util->GetNationalSignificantNumber(*i18n_number,
112                                            &national_significant_number);
113
114   int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
115   int destination_length =
116       phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
117   // Some phones have a destination code in lieu of area code: mobile operators
118   // in Europe, toll and toll-free numbers in USA, etc. From our point of view
119   // these two types of codes are the same.
120   if (destination_length > area_length)
121     area_length = destination_length;
122
123   std::string area_code;
124   std::string subscriber_number;
125   if (area_length > 0) {
126     area_code = national_significant_number.substr(0, area_length);
127     subscriber_number = national_significant_number.substr(area_length);
128   } else {
129     subscriber_number = national_significant_number;
130   }
131   *number = base::UTF8ToUTF16(subscriber_number);
132   *city_code = base::UTF8ToUTF16(area_code);
133   *country_code = base::string16();
134
135   phone_util->NormalizeDigitsOnly(&number_text);
136   base::string16 normalized_number(base::UTF8ToUTF16(number_text));
137
138   // Check if parsed number has a country code that was not inferred from the
139   // region.
140   if (i18n_number->has_country_code()) {
141     *country_code = base::UTF8ToUTF16(
142         base::StringPrintf("%d", i18n_number->country_code()));
143     if (normalized_number.length() <= national_significant_number.length() &&
144         !StartsWith(normalized_number, *country_code,
145                     true /* case_sensitive */)) {
146       country_code->clear();
147     }
148   }
149
150   return true;
151 }
152
153 base::string16 NormalizePhoneNumber(const base::string16& value,
154                                     const std::string& region) {
155   DCHECK_EQ(2u, region.size());
156   base::string16 country_code;
157   base::string16 unused_city_code;
158   base::string16 unused_number;
159   PhoneNumber phone_number;
160   if (!ParsePhoneNumber(value, region, &country_code, &unused_city_code,
161                         &unused_number, &phone_number)) {
162     return base::string16();  // Parsing failed - do not store phone.
163   }
164
165   base::string16 normalized_number;
166   FormatValidatedNumber(phone_number, country_code, NULL, &normalized_number);
167   return normalized_number;
168 }
169
170 bool ConstructPhoneNumber(const base::string16& country_code,
171                           const base::string16& city_code,
172                           const base::string16& number,
173                           const std::string& region,
174                           base::string16* whole_number) {
175   DCHECK_EQ(2u, region.size());
176   whole_number->clear();
177
178   base::string16 unused_country_code;
179   base::string16 unused_city_code;
180   base::string16 unused_number;
181   PhoneNumber phone_number;
182   if (!ParsePhoneNumber(country_code + city_code + number, region,
183                         &unused_country_code, &unused_city_code, &unused_number,
184                         &phone_number)) {
185     return false;
186   }
187
188   FormatValidatedNumber(phone_number, country_code, whole_number, NULL);
189   return true;
190 }
191
192 bool PhoneNumbersMatch(const base::string16& number_a,
193                        const base::string16& number_b,
194                        const std::string& raw_region,
195                        const std::string& app_locale) {
196   // Sanitize the provided |raw_region| before trying to use it for parsing.
197   const std::string region = SanitizeRegion(raw_region, app_locale);
198
199   PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
200
201   // Parse phone numbers based on the region
202   PhoneNumber i18n_number1;
203   if (phone_util->Parse(
204           base::UTF16ToUTF8(number_a), region.c_str(), &i18n_number1) !=
205               PhoneNumberUtil::NO_PARSING_ERROR) {
206     return false;
207   }
208
209   PhoneNumber i18n_number2;
210   if (phone_util->Parse(
211           base::UTF16ToUTF8(number_b), region.c_str(), &i18n_number2) !=
212               PhoneNumberUtil::NO_PARSING_ERROR) {
213     return false;
214   }
215
216   switch (phone_util->IsNumberMatch(i18n_number1, i18n_number2)) {
217     case PhoneNumberUtil::INVALID_NUMBER:
218     case PhoneNumberUtil::NO_MATCH:
219       return false;
220     case PhoneNumberUtil::SHORT_NSN_MATCH:
221       return false;
222     case PhoneNumberUtil::NSN_MATCH:
223     case PhoneNumberUtil::EXACT_MATCH:
224       return true;
225   }
226
227   NOTREACHED();
228   return false;
229 }
230
231 PhoneObject::PhoneObject(const base::string16& number,
232                          const std::string& region)
233     : region_(region) {
234   DCHECK_EQ(2u, region.size());
235   // TODO(isherman): Autofill profiles should always have a |region| set, but in
236   // some cases it should be marked as implicit.  Otherwise, phone numbers
237   // might behave differently when they are synced across computers:
238   // [ http://crbug.com/100845 ].  Once the bug is fixed, add a DCHECK here to
239   // verify.
240
241   scoped_ptr<PhoneNumber> i18n_number(new PhoneNumber);
242   if (ParsePhoneNumber(number, region_, &country_code_, &city_code_, &number_,
243                        i18n_number.get())) {
244     // The phone number was successfully parsed, so store the parsed version.
245     // The formatted and normalized versions will be set on the first call to
246     // the coresponding methods.
247     i18n_number_.reset(i18n_number.release());
248   } else {
249     // Parsing failed. Store passed phone "as is" into |whole_number_|.
250     whole_number_ = number;
251   }
252 }
253
254 PhoneObject::PhoneObject(const PhoneObject& other) { *this = other; }
255
256 PhoneObject::PhoneObject() {}
257
258 PhoneObject::~PhoneObject() {}
259
260 const base::string16& PhoneObject::GetFormattedNumber() const {
261   if (i18n_number_ && formatted_number_.empty()) {
262     FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
263                           &whole_number_);
264   }
265
266   return formatted_number_;
267 }
268
269 base::string16 PhoneObject::GetNationallyFormattedNumber() const {
270   base::string16 formatted = whole_number_;
271   if (i18n_number_)
272     FormatValidatedNumber(*i18n_number_, base::string16(), &formatted, NULL);
273
274   return formatted;
275 }
276
277 const base::string16& PhoneObject::GetWholeNumber() const {
278   if (i18n_number_ && whole_number_.empty()) {
279     FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
280                           &whole_number_);
281   }
282
283   return whole_number_;
284 }
285
286 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
287   if (this == &other)
288     return *this;
289
290   region_ = other.region_;
291
292   if (other.i18n_number_.get())
293     i18n_number_.reset(new PhoneNumber(*other.i18n_number_));
294   else
295     i18n_number_.reset();
296
297   country_code_ = other.country_code_;
298   city_code_ = other.city_code_;
299   number_ = other.number_;
300
301   formatted_number_ = other.formatted_number_;
302   whole_number_ = other.whole_number_;
303
304   return *this;
305 }
306
307 }  // namespace i18n
308 }  // namespace autofill