Home | History | Annotate | Download | only in autofill
      1 // Copyright (c) 2011 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 "chrome/browser/autofill/phone_number.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/string_util.h"
      9 #include "chrome/browser/autofill/autofill_profile.h"
     10 #include "chrome/browser/autofill/autofill_type.h"
     11 #include "chrome/browser/autofill/field_types.h"
     12 
     13 namespace {
     14 
     15 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
     16 
     17 // The number of digits in a phone number.
     18 const size_t kPhoneNumberLength = 7;
     19 
     20 // The number of digits in an area code.
     21 const size_t kPhoneCityCodeLength = 3;
     22 
     23 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
     24   AutofillType::PHONE_NUMBER,
     25   AutofillType::PHONE_CITY_CODE,
     26   AutofillType::PHONE_COUNTRY_CODE,
     27   AutofillType::PHONE_CITY_AND_NUMBER,
     28   AutofillType::PHONE_WHOLE_NUMBER,
     29 };
     30 
     31 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
     32 
     33 }  // namespace
     34 
     35 PhoneNumber::PhoneNumber() {}
     36 
     37 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
     38   *this = number;
     39 }
     40 
     41 PhoneNumber::~PhoneNumber() {}
     42 
     43 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
     44   if (this == &number)
     45     return *this;
     46   country_code_ = number.country_code_;
     47   city_code_ = number.city_code_;
     48   number_ = number.number_;
     49   extension_ = number.extension_;
     50   return *this;
     51 }
     52 
     53 void PhoneNumber::GetPossibleFieldTypes(const string16& text,
     54                                         FieldTypeSet* possible_types) const {
     55   string16 stripped_text(text);
     56   StripPunctuation(&stripped_text);
     57   if (!Validate(stripped_text))
     58     return;
     59 
     60   if (IsNumber(stripped_text))
     61     possible_types->insert(GetNumberType());
     62 
     63   if (IsCityCode(stripped_text))
     64     possible_types->insert(GetCityCodeType());
     65 
     66   if (IsCountryCode(stripped_text))
     67     possible_types->insert(GetCountryCodeType());
     68 
     69   if (IsCityAndNumber(stripped_text))
     70     possible_types->insert(GetCityAndNumberType());
     71 
     72   if (IsWholeNumber(stripped_text))
     73     possible_types->insert(GetWholeNumberType());
     74 }
     75 
     76 void PhoneNumber::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
     77   DCHECK(available_types);
     78 
     79   if (!number().empty())
     80     available_types->insert(GetNumberType());
     81 
     82   if (!city_code().empty())
     83     available_types->insert(GetCityCodeType());
     84 
     85   if (!country_code().empty())
     86     available_types->insert(GetCountryCodeType());
     87 
     88   if (!CityAndNumber().empty())
     89     available_types->insert(GetCityAndNumberType());
     90 
     91   if (!WholeNumber().empty())
     92     available_types->insert(GetWholeNumberType());
     93 }
     94 
     95 string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
     96   if (type == GetNumberType())
     97     return number();
     98 
     99   if (type == GetCityCodeType())
    100     return city_code();
    101 
    102   if (type == GetCountryCodeType())
    103     return country_code();
    104 
    105   if (type == GetCityAndNumberType())
    106     return CityAndNumber();
    107 
    108   if (type == GetWholeNumberType())
    109     return WholeNumber();
    110 
    111   return string16();
    112 }
    113 
    114 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
    115   string16 number(value);
    116   StripPunctuation(&number);
    117   if (!Validate(number))
    118     return;
    119 
    120   FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
    121   if (subgroup == AutofillType::PHONE_NUMBER)
    122     set_number(number);
    123   else if (subgroup == AutofillType::PHONE_CITY_CODE)
    124     set_city_code(number);
    125   else if (subgroup == AutofillType::PHONE_COUNTRY_CODE)
    126     set_country_code(number);
    127   else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
    128            subgroup == AutofillType::PHONE_WHOLE_NUMBER)
    129     set_whole_number(number);
    130   else
    131     NOTREACHED();
    132 }
    133 
    134 // Static.
    135 bool PhoneNumber::ParsePhoneNumber(const string16& value,
    136                                    string16* number,
    137                                    string16* city_code,
    138                                    string16* country_code) {
    139   DCHECK(number);
    140   DCHECK(city_code);
    141   DCHECK(country_code);
    142 
    143   // Make a working copy of value.
    144   string16 working = value;
    145 
    146   *number = string16();
    147   *city_code = string16();
    148   *country_code = string16();
    149 
    150   // First remove any punctuation.
    151   StripPunctuation(&working);
    152 
    153   if (working.size() < kPhoneNumberLength)
    154     return false;
    155 
    156   // Treat the last 7 digits as the number.
    157   *number = working.substr(working.size() - kPhoneNumberLength,
    158                            kPhoneNumberLength);
    159   working.resize(working.size() - kPhoneNumberLength);
    160   if (working.size() < kPhoneCityCodeLength)
    161     return true;
    162 
    163   // Treat the next three digits as the city code.
    164   *city_code = working.substr(working.size() - kPhoneCityCodeLength,
    165                               kPhoneCityCodeLength);
    166   working.resize(working.size() - kPhoneCityCodeLength);
    167   if (working.empty())
    168     return true;
    169 
    170   // Treat any remaining digits as the country code.
    171   *country_code = working;
    172   return true;
    173 }
    174 
    175 string16 PhoneNumber::WholeNumber() const {
    176   string16 whole_number;
    177   if (!country_code_.empty())
    178     whole_number.append(country_code_);
    179 
    180   if (!city_code_.empty())
    181     whole_number.append(city_code_);
    182 
    183   if (!number_.empty())
    184     whole_number.append(number_);
    185 
    186   return whole_number;
    187 }
    188 
    189 void PhoneNumber::set_number(const string16& number) {
    190   string16 digits(number);
    191   StripPunctuation(&digits);
    192   number_ = digits;
    193 }
    194 
    195 void PhoneNumber::set_whole_number(const string16& whole_number) {
    196   string16 number, city_code, country_code;
    197   ParsePhoneNumber(whole_number, &number, &city_code, &country_code);
    198   set_number(number);
    199   set_city_code(city_code);
    200   set_country_code(country_code);
    201 }
    202 
    203 bool PhoneNumber::IsNumber(const string16& text) const {
    204   // TODO(isherman): This will need to be updated once we add support for
    205   // international phone numbers.
    206   const size_t kPhoneNumberPrefixLength = 3;
    207   const size_t kPhoneNumberSuffixLength = 4;
    208   return
    209       (text == number_) ||
    210       (text.length() == kPhoneNumberPrefixLength &&
    211        StartsWith(number_, text, true)) ||
    212       (text.length() == kPhoneNumberSuffixLength &&
    213        EndsWith(number_, text, true));
    214 }
    215 
    216 bool PhoneNumber::IsCityCode(const string16& text) const {
    217   return text == city_code_;
    218 }
    219 
    220 bool PhoneNumber::IsCountryCode(const string16& text) const {
    221   return text == country_code_;
    222 }
    223 
    224 bool PhoneNumber::IsCityAndNumber(const string16& text) const {
    225   return text == CityAndNumber();
    226 }
    227 
    228 bool PhoneNumber::IsWholeNumber(const string16& text) const {
    229   return text == WholeNumber();
    230 }
    231 
    232 bool PhoneNumber::Validate(const string16& number) const {
    233   for (size_t i = 0; i < number.length(); ++i) {
    234     if (!IsAsciiDigit(number[i]))
    235       return false;
    236   }
    237 
    238   return true;
    239 }
    240 
    241 // Static.
    242 void PhoneNumber::StripPunctuation(string16* number) {
    243   RemoveChars(*number, kPhoneNumberSeparators, number);
    244 }
    245