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