// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/autofill/phone_number.h" #include "base/basictypes.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/field_types.h" #include "chrome/browser/autofill/phone_number_i18n.h" namespace { const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; // The number of digits in a phone number. const size_t kPhoneNumberLength = 7; // The number of digits in an area code. const size_t kPhoneCityCodeLength = 3; void StripPunctuation(string16* number) { RemoveChars(*number, kPhoneNumberSeparators, number); } } // namespace PhoneNumber::PhoneNumber(AutofillProfile* profile) : profile_(profile) { } PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup(), profile_(NULL) { *this = number; } PhoneNumber::~PhoneNumber() {} PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { if (this == &number) return *this; number_ = number.number_; profile_ = number.profile_; cached_parsed_phone_ = number.cached_parsed_phone_; return *this; } void PhoneNumber::GetSupportedTypes(FieldTypeSet* supported_types) const { supported_types->insert(PHONE_HOME_WHOLE_NUMBER); supported_types->insert(PHONE_HOME_NUMBER); supported_types->insert(PHONE_HOME_CITY_CODE); supported_types->insert(PHONE_HOME_CITY_AND_NUMBER); supported_types->insert(PHONE_HOME_COUNTRY_CODE); } string16 PhoneNumber::GetInfo(AutofillFieldType type) const { if (type == PHONE_HOME_WHOLE_NUMBER) return number_; UpdateCacheIfNeeded(); if (!cached_parsed_phone_.IsValidNumber()) return string16(); if (type == PHONE_HOME_NUMBER) return cached_parsed_phone_.GetNumber(); if (type == PHONE_HOME_CITY_CODE) return cached_parsed_phone_.GetCityCode(); if (type == PHONE_HOME_COUNTRY_CODE) return cached_parsed_phone_.GetCountryCode(); if (type == PHONE_HOME_CITY_AND_NUMBER) { string16 city_and_local(cached_parsed_phone_.GetCityCode()); city_and_local.append(cached_parsed_phone_.GetNumber()); return city_and_local; } return string16(); } void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) { // Only full phone numbers should be set directly. The remaining field // field types are read-only. return; } number_ = value; cached_parsed_phone_ = autofill_i18n::PhoneObject(number_, GetLocale()); } // Normalize phones if |type| is a whole number: // (650)2345678 -> 6502345678 // 1-800-FLOWERS -> 18003569377 // If the phone cannot be normalized, returns the stored value verbatim. string16 PhoneNumber::GetCanonicalizedInfo(AutofillFieldType type) const { string16 phone = GetInfo(type); if (type != PHONE_HOME_WHOLE_NUMBER) return phone; string16 normalized_phone = autofill_i18n::NormalizePhoneNumber(phone, GetLocale()); if (!normalized_phone.empty()) return normalized_phone; return phone; } bool PhoneNumber::SetCanonicalizedInfo(AutofillFieldType type, const string16& value) { string16 number = value; StripPunctuation(&number); SetInfo(type, number); return NormalizePhone(); } void PhoneNumber::GetMatchingTypes(const string16& text, FieldTypeSet* matching_types) const { string16 stripped_text = text; StripPunctuation(&stripped_text); FormGroup::GetMatchingTypes(stripped_text, matching_types); // For US numbers, also compare to the three-digit prefix and the four-digit // suffix, since web sites often split numbers into these two fields. string16 number = GetCanonicalizedInfo(PHONE_HOME_NUMBER); if (GetLocale() == "US" && number.size() == (kPrefixLength + kSuffixLength)) { string16 prefix = number.substr(kPrefixOffset, kPrefixLength); string16 suffix = number.substr(kSuffixOffset, kSuffixLength); if (text == prefix || text == suffix) matching_types->insert(PHONE_HOME_NUMBER); } string16 whole_number = GetCanonicalizedInfo(PHONE_HOME_WHOLE_NUMBER); if (!whole_number.empty() && autofill_i18n::NormalizePhoneNumber(text, GetLocale()) == whole_number) { matching_types->insert(PHONE_HOME_WHOLE_NUMBER); } } bool PhoneNumber::NormalizePhone() { // Empty number does not need normalization. if (number_.empty()) return true; UpdateCacheIfNeeded(); number_ = cached_parsed_phone_.GetWholeNumber(); return !number_.empty(); } std::string PhoneNumber::GetLocale() const { if (!profile_) { NOTREACHED(); return "US"; } return profile_->CountryCode(); } void PhoneNumber::UpdateCacheIfNeeded() const { std::string locale = GetLocale(); if (!number_.empty() && cached_parsed_phone_.GetLocale() != locale) cached_parsed_phone_ = autofill_i18n::PhoneObject(number_, locale); } PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() { } PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() { } bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type, const string16& value) { if (field_type == PHONE_HOME_COUNTRY_CODE) { country_ = value; return true; } if (field_type == PHONE_HOME_CITY_CODE) { city_ = value; return true; } if (field_type == PHONE_HOME_CITY_AND_NUMBER) { phone_ = value; return true; } if (field_type == PHONE_HOME_WHOLE_NUMBER) { whole_number_ = value; return true; } if (field_type == PHONE_HOME_NUMBER) { phone_.append(value); return true; } return false; } bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale, string16* value) { if (!whole_number_.empty()) { *value = whole_number_; return true; } return autofill_i18n::ConstructPhoneNumber( country_, city_, phone_, locale, (country_.empty() ? autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL), value); } bool PhoneNumber::PhoneCombineHelper::IsEmpty() const { return phone_.empty() && whole_number_.empty(); }