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.h" 6 7 #include "base/basictypes.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "components/autofill/core/browser/autofill_country.h" 12 #include "components/autofill/core/browser/autofill_profile.h" 13 #include "components/autofill/core/browser/autofill_type.h" 14 #include "components/autofill/core/browser/field_types.h" 15 #include "components/autofill/core/browser/phone_number_i18n.h" 16 17 namespace autofill { 18 namespace { 19 20 // Returns the region code for this phone number, which is an ISO 3166 2-letter 21 // country code. The returned value is based on the |profile|; if the |profile| 22 // does not have a country code associated with it, falls back to the country 23 // code corresponding to the |app_locale|. 24 std::string GetRegion(const AutofillProfile& profile, 25 const std::string& app_locale) { 26 base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); 27 if (!country_code.empty()) 28 return base::UTF16ToASCII(country_code); 29 30 return AutofillCountry::CountryCodeForLocale(app_locale); 31 } 32 33 } // namespace 34 35 PhoneNumber::PhoneNumber(AutofillProfile* profile) 36 : profile_(profile) { 37 } 38 39 PhoneNumber::PhoneNumber(const PhoneNumber& number) 40 : profile_(NULL) { 41 *this = number; 42 } 43 44 PhoneNumber::~PhoneNumber() {} 45 46 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { 47 if (this == &number) 48 return *this; 49 50 number_ = number.number_; 51 profile_ = number.profile_; 52 cached_parsed_phone_ = number.cached_parsed_phone_; 53 return *this; 54 } 55 56 void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 57 supported_types->insert(PHONE_HOME_WHOLE_NUMBER); 58 supported_types->insert(PHONE_HOME_NUMBER); 59 supported_types->insert(PHONE_HOME_CITY_CODE); 60 supported_types->insert(PHONE_HOME_CITY_AND_NUMBER); 61 supported_types->insert(PHONE_HOME_COUNTRY_CODE); 62 } 63 64 base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const { 65 DCHECK_EQ(PHONE_HOME, AutofillType(type).group()); 66 if (type == PHONE_HOME_WHOLE_NUMBER) 67 return number_; 68 69 // Only the whole number is available as raw data. All of the other types are 70 // parsed from this raw info, and parsing requires knowledge of the phone 71 // number's region, which is only available via GetInfo(). 72 return base::string16(); 73 } 74 75 void PhoneNumber::SetRawInfo(ServerFieldType type, 76 const base::string16& value) { 77 DCHECK_EQ(PHONE_HOME, AutofillType(type).group()); 78 if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) { 79 // Only full phone numbers should be set directly. The remaining field 80 // field types are read-only. 81 return; 82 } 83 84 number_ = value; 85 86 // Invalidate the cached number. 87 cached_parsed_phone_ = i18n::PhoneObject(); 88 } 89 90 // Normalize phones if |type| is a whole number: 91 // (650)2345678 -> 6502345678 92 // 1-800-FLOWERS -> 18003569377 93 // If the phone cannot be normalized, returns the stored value verbatim. 94 base::string16 PhoneNumber::GetInfo(const AutofillType& type, 95 const std::string& app_locale) const { 96 ServerFieldType storable_type = type.GetStorableType(); 97 UpdateCacheIfNeeded(app_locale); 98 99 // Queries for whole numbers will return the non-normalized number if 100 // normalization for the number fails. All other field types require 101 // normalization. 102 if (storable_type != PHONE_HOME_WHOLE_NUMBER && 103 !cached_parsed_phone_.IsValidNumber()) 104 return base::string16(); 105 106 switch (storable_type) { 107 case PHONE_HOME_WHOLE_NUMBER: 108 return cached_parsed_phone_.GetWholeNumber(); 109 110 case PHONE_HOME_NUMBER: 111 return cached_parsed_phone_.number(); 112 113 case PHONE_HOME_CITY_CODE: 114 return cached_parsed_phone_.city_code(); 115 116 case PHONE_HOME_COUNTRY_CODE: 117 return cached_parsed_phone_.country_code(); 118 119 case PHONE_HOME_CITY_AND_NUMBER: 120 return 121 cached_parsed_phone_.city_code() + cached_parsed_phone_.number(); 122 123 default: 124 NOTREACHED(); 125 return base::string16(); 126 } 127 } 128 129 bool PhoneNumber::SetInfo(const AutofillType& type, 130 const base::string16& value, 131 const std::string& app_locale) { 132 SetRawInfo(type.GetStorableType(), value); 133 134 if (number_.empty()) 135 return true; 136 137 // Store a formatted (i.e., pretty printed) version of the number if either 138 // the number doesn't contain formatting marks. 139 UpdateCacheIfNeeded(app_locale); 140 if (base::ContainsOnlyChars(number_, base::ASCIIToUTF16("+0123456789"))) { 141 number_ = cached_parsed_phone_.GetFormattedNumber(); 142 } else if (i18n::NormalizePhoneNumber( 143 number_, GetRegion(*profile_, app_locale)).empty()) { 144 // The number doesn't make sense for this region; clear it. 145 number_.clear(); 146 } 147 return !number_.empty(); 148 } 149 150 void PhoneNumber::GetMatchingTypes(const base::string16& text, 151 const std::string& app_locale, 152 ServerFieldTypeSet* matching_types) const { 153 base::string16 stripped_text = text; 154 base::RemoveChars(stripped_text, base::ASCIIToUTF16(" .()-"), &stripped_text); 155 FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types); 156 157 // For US numbers, also compare to the three-digit prefix and the four-digit 158 // suffix, since web sites often split numbers into these two fields. 159 base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale); 160 if (GetRegion(*profile_, app_locale) == "US" && 161 number.size() == (kPrefixLength + kSuffixLength)) { 162 base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength); 163 base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength); 164 if (text == prefix || text == suffix) 165 matching_types->insert(PHONE_HOME_NUMBER); 166 } 167 168 base::string16 whole_number = 169 GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale); 170 if (!whole_number.empty()) { 171 base::string16 normalized_number = 172 i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale)); 173 if (normalized_number == whole_number) 174 matching_types->insert(PHONE_HOME_WHOLE_NUMBER); 175 } 176 } 177 178 void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const { 179 std::string region = GetRegion(*profile_, app_locale); 180 if (!number_.empty() && cached_parsed_phone_.region() != region) 181 cached_parsed_phone_ = i18n::PhoneObject(number_, region); 182 } 183 184 PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() { 185 } 186 187 PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() { 188 } 189 190 bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type, 191 const base::string16& value) { 192 ServerFieldType storable_type = type.GetStorableType(); 193 if (storable_type == PHONE_HOME_COUNTRY_CODE) { 194 country_ = value; 195 return true; 196 } 197 198 if (storable_type == PHONE_HOME_CITY_CODE) { 199 city_ = value; 200 return true; 201 } 202 203 if (storable_type == PHONE_HOME_CITY_AND_NUMBER) { 204 phone_ = value; 205 return true; 206 } 207 208 if (storable_type == PHONE_HOME_WHOLE_NUMBER) { 209 whole_number_ = value; 210 return true; 211 } 212 213 if (storable_type == PHONE_HOME_NUMBER) { 214 phone_.append(value); 215 return true; 216 } 217 218 return false; 219 } 220 221 bool PhoneNumber::PhoneCombineHelper::ParseNumber( 222 const AutofillProfile& profile, 223 const std::string& app_locale, 224 base::string16* value) { 225 if (IsEmpty()) 226 return false; 227 228 if (!whole_number_.empty()) { 229 *value = whole_number_; 230 return true; 231 } 232 233 return i18n::ConstructPhoneNumber( 234 country_, city_, phone_, GetRegion(profile, app_locale), value); 235 } 236 237 bool PhoneNumber::PhoneCombineHelper::IsEmpty() const { 238 return phone_.empty() && whole_number_.empty(); 239 } 240 241 } // namespace autofill 242