blob: d1ca32ac25a5a1c31bba9f477650b2d5a96e2297 [file] [log] [blame]
[email protected]7b37fbb2011-03-07 16:16:031// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]3db3ff62010-01-07 00:35:392// 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"
[email protected]9b435be92010-03-04 21:20:159#include "chrome/browser/autofill/autofill_profile.h"
[email protected]3db3ff62010-01-07 00:35:3910#include "chrome/browser/autofill/autofill_type.h"
11#include "chrome/browser/autofill/field_types.h"
12
[email protected]9b435be92010-03-04 21:20:1513namespace {
[email protected]3db3ff62010-01-07 00:35:3914
[email protected]9b435be92010-03-04 21:20:1515const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
16
17// The number of digits in a phone number.
18const size_t kPhoneNumberLength = 7;
19
20// The number of digits in an area code.
21const size_t kPhoneCityCodeLength = 3;
22
[email protected]663bd9e2011-03-21 01:07:0123const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
[email protected]7b37fbb2011-03-07 16:16:0324 AutofillType::PHONE_NUMBER,
25 AutofillType::PHONE_CITY_CODE,
26 AutofillType::PHONE_COUNTRY_CODE,
27 AutofillType::PHONE_CITY_AND_NUMBER,
28 AutofillType::PHONE_WHOLE_NUMBER,
[email protected]3db3ff62010-01-07 00:35:3929};
30
[email protected]663bd9e2011-03-21 01:07:0131const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
[email protected]9b435be92010-03-04 21:20:1532
33} // namespace
[email protected]3db3ff62010-01-07 00:35:3934
[email protected]8e383412010-10-19 16:57:0335PhoneNumber::PhoneNumber() {}
36
[email protected]43897242011-03-09 03:52:1137PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
38 *this = number;
39}
40
[email protected]8e383412010-10-19 16:57:0341PhoneNumber::~PhoneNumber() {}
42
[email protected]43897242011-03-09 03:52:1143PhoneNumber& 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
[email protected]1308c2832011-05-09 18:30:2353void PhoneNumber::GetMatchingTypes(const string16& text,
54 FieldTypeSet* matching_types) const {
[email protected]3db3ff62010-01-07 00:35:3955 string16 stripped_text(text);
56 StripPunctuation(&stripped_text);
57 if (!Validate(stripped_text))
58 return;
59
60 if (IsNumber(stripped_text))
[email protected]1308c2832011-05-09 18:30:2361 matching_types->insert(GetNumberType());
[email protected]3db3ff62010-01-07 00:35:3962
63 if (IsCityCode(stripped_text))
[email protected]1308c2832011-05-09 18:30:2364 matching_types->insert(GetCityCodeType());
[email protected]3db3ff62010-01-07 00:35:3965
66 if (IsCountryCode(stripped_text))
[email protected]1308c2832011-05-09 18:30:2367 matching_types->insert(GetCountryCodeType());
[email protected]3db3ff62010-01-07 00:35:3968
69 if (IsCityAndNumber(stripped_text))
[email protected]1308c2832011-05-09 18:30:2370 matching_types->insert(GetCityAndNumberType());
[email protected]3db3ff62010-01-07 00:35:3971
72 if (IsWholeNumber(stripped_text))
[email protected]1308c2832011-05-09 18:30:2373 matching_types->insert(GetWholeNumberType());
[email protected]3db3ff62010-01-07 00:35:3974}
75
[email protected]1308c2832011-05-09 18:30:2376void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_typess) const {
77 DCHECK(non_empty_typess);
[email protected]cea1d112010-07-01 00:57:3378
79 if (!number().empty())
[email protected]1308c2832011-05-09 18:30:2380 non_empty_typess->insert(GetNumberType());
[email protected]cea1d112010-07-01 00:57:3381
82 if (!city_code().empty())
[email protected]1308c2832011-05-09 18:30:2383 non_empty_typess->insert(GetCityCodeType());
[email protected]cea1d112010-07-01 00:57:3384
85 if (!country_code().empty())
[email protected]1308c2832011-05-09 18:30:2386 non_empty_typess->insert(GetCountryCodeType());
[email protected]cea1d112010-07-01 00:57:3387
88 if (!CityAndNumber().empty())
[email protected]1308c2832011-05-09 18:30:2389 non_empty_typess->insert(GetCityAndNumberType());
[email protected]cea1d112010-07-01 00:57:3390
91 if (!WholeNumber().empty())
[email protected]1308c2832011-05-09 18:30:2392 non_empty_typess->insert(GetWholeNumberType());
[email protected]cea1d112010-07-01 00:57:3393}
94
[email protected]3b3a0ca72011-03-17 23:04:5595string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
[email protected]1ffe8e992011-03-17 06:26:2996 if (type == GetNumberType())
[email protected]3db3ff62010-01-07 00:35:3997 return number();
98
[email protected]1ffe8e992011-03-17 06:26:2999 if (type == GetCityCodeType())
[email protected]3db3ff62010-01-07 00:35:39100 return city_code();
101
[email protected]1ffe8e992011-03-17 06:26:29102 if (type == GetCountryCodeType())
[email protected]3db3ff62010-01-07 00:35:39103 return country_code();
104
[email protected]1ffe8e992011-03-17 06:26:29105 if (type == GetCityAndNumberType())
[email protected]3db3ff62010-01-07 00:35:39106 return CityAndNumber();
107
[email protected]1ffe8e992011-03-17 06:26:29108 if (type == GetWholeNumberType())
[email protected]3db3ff62010-01-07 00:35:39109 return WholeNumber();
110
[email protected]cea1d112010-07-01 00:57:33111 return string16();
[email protected]3db3ff62010-01-07 00:35:39112}
113
[email protected]1ffe8e992011-03-17 06:26:29114void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
[email protected]3db3ff62010-01-07 00:35:39115 string16 number(value);
116 StripPunctuation(&number);
117 if (!Validate(number))
118 return;
119
[email protected]1ffe8e992011-03-17 06:26:29120 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
[email protected]7b37fbb2011-03-07 16:16:03121 if (subgroup == AutofillType::PHONE_NUMBER)
[email protected]3db3ff62010-01-07 00:35:39122 set_number(number);
[email protected]7b37fbb2011-03-07 16:16:03123 else if (subgroup == AutofillType::PHONE_CITY_CODE)
[email protected]3db3ff62010-01-07 00:35:39124 set_city_code(number);
[email protected]7b37fbb2011-03-07 16:16:03125 else if (subgroup == AutofillType::PHONE_COUNTRY_CODE)
[email protected]3db3ff62010-01-07 00:35:39126 set_country_code(number);
[email protected]7b37fbb2011-03-07 16:16:03127 else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
128 subgroup == AutofillType::PHONE_WHOLE_NUMBER)
[email protected]afbd3542010-03-17 20:31:07129 set_whole_number(number);
[email protected]3db3ff62010-01-07 00:35:39130 else
131 NOTREACHED();
[email protected]3db3ff62010-01-07 00:35:39132}
133
[email protected]9b435be92010-03-04 21:20:15134// Static.
[email protected]f8e7b62d2010-06-03 18:12:54135bool PhoneNumber::ParsePhoneNumber(const string16& value,
[email protected]9b435be92010-03-04 21:20:15136 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)
[email protected]f8e7b62d2010-06-03 18:12:54154 return false;
[email protected]9b435be92010-03-04 21:20:15155
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)
[email protected]f8e7b62d2010-06-03 18:12:54161 return true;
[email protected]9b435be92010-03-04 21:20:15162
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())
[email protected]f8e7b62d2010-06-03 18:12:54168 return true;
[email protected]9b435be92010-03-04 21:20:15169
170 // Treat any remaining digits as the country code.
171 *country_code = working;
[email protected]f8e7b62d2010-06-03 18:12:54172 return true;
[email protected]9b435be92010-03-04 21:20:15173}
174
[email protected]3db3ff62010-01-07 00:35:39175string16 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
189void PhoneNumber::set_number(const string16& number) {
190 string16 digits(number);
191 StripPunctuation(&digits);
192 number_ = digits;
193}
194
[email protected]afbd3542010-03-17 20:31:07195void 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
[email protected]3db3ff62010-01-07 00:35:39203bool PhoneNumber::IsNumber(const string16& text) const {
[email protected]c13014b2011-04-18 20:04:00204 // TODO(isherman): This will need to be updated once we add support for
205 // international phone numbers.
[email protected]4605a132011-04-29 00:42:40206 const size_t kPrefixLength = 3;
207 const size_t kSuffixLength = 4;
208
209 if (text == number_)
210 return true;
211 if (text.length() == kPrefixLength && StartsWith(number_, text, true))
212 return true;
213 if (text.length() == kSuffixLength && EndsWith(number_, text, true))
214 return true;
215
216 return false;
[email protected]3db3ff62010-01-07 00:35:39217}
218
219bool PhoneNumber::IsCityCode(const string16& text) const {
[email protected]c13014b2011-04-18 20:04:00220 return text == city_code_;
[email protected]3db3ff62010-01-07 00:35:39221}
222
223bool PhoneNumber::IsCountryCode(const string16& text) const {
[email protected]c13014b2011-04-18 20:04:00224 return text == country_code_;
[email protected]3db3ff62010-01-07 00:35:39225}
226
227bool PhoneNumber::IsCityAndNumber(const string16& text) const {
[email protected]c13014b2011-04-18 20:04:00228 return text == CityAndNumber();
[email protected]3db3ff62010-01-07 00:35:39229}
230
231bool PhoneNumber::IsWholeNumber(const string16& text) const {
[email protected]c13014b2011-04-18 20:04:00232 return text == WholeNumber();
[email protected]3db3ff62010-01-07 00:35:39233}
234
235bool PhoneNumber::Validate(const string16& number) const {
236 for (size_t i = 0; i < number.length(); ++i) {
237 if (!IsAsciiDigit(number[i]))
238 return false;
239 }
240
241 return true;
242}
243
[email protected]9b435be92010-03-04 21:20:15244// Static.
245void PhoneNumber::StripPunctuation(string16* number) {
246 RemoveChars(*number, kPhoneNumberSeparators, number);
[email protected]3db3ff62010-01-07 00:35:39247}