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, ®ion_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 ®ion_, 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