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   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.
     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 
    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 
    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 
    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 
    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 
    260 PhoneObject::PhoneObject(const PhoneObject& other) { *this = other; }
    261 
    262 PhoneObject::PhoneObject() {}
    263 
    264 PhoneObject::~PhoneObject() {}
    265 
    266 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 
    275 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 
    283 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 
    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