blob: 025f031f44db2e552f2882b4c19f16ff77f85470 [file] [log] [blame]
[email protected]3db3ff62010-01-07 00:35:391// Copyright (c) 2010 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"
[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
23const AutoFillType::FieldTypeSubGroup kAutoFillPhoneTypes[] = {
[email protected]3db3ff62010-01-07 00:35:3924 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
[email protected]9b435be92010-03-04 21:20:1531const int kAutoFillPhoneLength = arraysize(kAutoFillPhoneTypes);
32
33} // namespace
[email protected]3db3ff62010-01-07 00:35:3934
[email protected]8e383412010-10-19 16:57:0335PhoneNumber::PhoneNumber() {}
36
37PhoneNumber::~PhoneNumber() {}
38
[email protected]3db3ff62010-01-07 00:35:3939void PhoneNumber::GetPossibleFieldTypes(const string16& text,
40 FieldTypeSet* possible_types) const {
41 string16 stripped_text(text);
42 StripPunctuation(&stripped_text);
43 if (!Validate(stripped_text))
44 return;
45
46 if (IsNumber(stripped_text))
47 possible_types->insert(GetNumberType());
48
49 if (IsCityCode(stripped_text))
50 possible_types->insert(GetCityCodeType());
51
52 if (IsCountryCode(stripped_text))
53 possible_types->insert(GetCountryCodeType());
54
55 if (IsCityAndNumber(stripped_text))
56 possible_types->insert(GetCityAndNumberType());
57
58 if (IsWholeNumber(stripped_text))
59 possible_types->insert(GetWholeNumberType());
60}
61
[email protected]cea1d112010-07-01 00:57:3362void PhoneNumber::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
63 DCHECK(available_types);
64
65 if (!number().empty())
66 available_types->insert(GetNumberType());
67
68 if (!city_code().empty())
69 available_types->insert(GetCityCodeType());
70
71 if (!country_code().empty())
72 available_types->insert(GetCountryCodeType());
73
74 if (!CityAndNumber().empty())
75 available_types->insert(GetCityAndNumberType());
76
77 if (!WholeNumber().empty())
78 available_types->insert(GetWholeNumberType());
79}
80
[email protected]3db3ff62010-01-07 00:35:3981string16 PhoneNumber::GetFieldText(const AutoFillType& type) const {
82 AutoFillFieldType field_type = type.field_type();
83 if (field_type == GetNumberType())
84 return number();
85
86 if (field_type == GetCityCodeType())
87 return city_code();
88
89 if (field_type == GetCountryCodeType())
90 return country_code();
91
92 if (field_type == GetCityAndNumberType())
93 return CityAndNumber();
94
95 if (field_type == GetWholeNumberType())
96 return WholeNumber();
97
[email protected]cea1d112010-07-01 00:57:3398 return string16();
[email protected]3db3ff62010-01-07 00:35:3999}
100
101void PhoneNumber::FindInfoMatches(const AutoFillType& type,
102 const string16& info,
103 std::vector<string16>* matched_text) const {
104 if (matched_text == NULL) {
105 DLOG(ERROR) << "NULL matched vector passed in";
106 return;
107 }
108
109 string16 number(info);
110 StripPunctuation(&number);
111 if (!Validate(number))
112 return;
113
114 string16 match;
115 if (type.field_type() == UNKNOWN_TYPE) {
116 for (int i = 0; i < kAutoFillPhoneLength; ++i) {
117 if (FindInfoMatchesHelper(kAutoFillPhoneTypes[i], info, &match))
118 matched_text->push_back(match);
119 }
120 } else {
121 if (FindInfoMatchesHelper(type.subgroup(), info, &match))
122 matched_text->push_back(match);
123 }
124}
125
126void PhoneNumber::SetInfo(const AutoFillType& type, const string16& value) {
127 string16 number(value);
128 StripPunctuation(&number);
129 if (!Validate(number))
130 return;
131
132 FieldTypeSubGroup subgroup = type.subgroup();
133 if (subgroup == AutoFillType::PHONE_NUMBER)
134 set_number(number);
135 else if (subgroup == AutoFillType::PHONE_CITY_CODE)
136 set_city_code(number);
137 else if (subgroup == AutoFillType::PHONE_COUNTRY_CODE)
138 set_country_code(number);
[email protected]cea1d112010-07-01 00:57:33139 else if (subgroup == AutoFillType::PHONE_CITY_AND_NUMBER ||
140 subgroup == AutoFillType::PHONE_WHOLE_NUMBER)
[email protected]afbd3542010-03-17 20:31:07141 set_whole_number(number);
[email protected]3db3ff62010-01-07 00:35:39142 else
143 NOTREACHED();
[email protected]3db3ff62010-01-07 00:35:39144}
145
[email protected]9b435be92010-03-04 21:20:15146// Static.
[email protected]f8e7b62d2010-06-03 18:12:54147bool PhoneNumber::ParsePhoneNumber(const string16& value,
[email protected]9b435be92010-03-04 21:20:15148 string16* number,
149 string16* city_code,
150 string16* country_code) {
151 DCHECK(number);
152 DCHECK(city_code);
153 DCHECK(country_code);
154
155 // Make a working copy of value.
156 string16 working = value;
157
158 *number = string16();
159 *city_code = string16();
160 *country_code = string16();
161
162 // First remove any punctuation.
163 StripPunctuation(&working);
164
165 if (working.size() < kPhoneNumberLength)
[email protected]f8e7b62d2010-06-03 18:12:54166 return false;
[email protected]9b435be92010-03-04 21:20:15167
168 // Treat the last 7 digits as the number.
169 *number = working.substr(working.size() - kPhoneNumberLength,
170 kPhoneNumberLength);
171 working.resize(working.size() - kPhoneNumberLength);
172 if (working.size() < kPhoneCityCodeLength)
[email protected]f8e7b62d2010-06-03 18:12:54173 return true;
[email protected]9b435be92010-03-04 21:20:15174
175 // Treat the next three digits as the city code.
176 *city_code = working.substr(working.size() - kPhoneCityCodeLength,
177 kPhoneCityCodeLength);
178 working.resize(working.size() - kPhoneCityCodeLength);
179 if (working.empty())
[email protected]f8e7b62d2010-06-03 18:12:54180 return true;
[email protected]9b435be92010-03-04 21:20:15181
182 // Treat any remaining digits as the country code.
183 *country_code = working;
[email protected]f8e7b62d2010-06-03 18:12:54184 return true;
[email protected]9b435be92010-03-04 21:20:15185}
186
[email protected]3db3ff62010-01-07 00:35:39187string16 PhoneNumber::WholeNumber() const {
188 string16 whole_number;
189 if (!country_code_.empty())
190 whole_number.append(country_code_);
191
192 if (!city_code_.empty())
193 whole_number.append(city_code_);
194
195 if (!number_.empty())
196 whole_number.append(number_);
197
198 return whole_number;
199}
200
201void PhoneNumber::set_number(const string16& number) {
202 string16 digits(number);
203 StripPunctuation(&digits);
204 number_ = digits;
205}
206
[email protected]afbd3542010-03-17 20:31:07207void PhoneNumber::set_whole_number(const string16& whole_number) {
208 string16 number, city_code, country_code;
209 ParsePhoneNumber(whole_number, &number, &city_code, &country_code);
210 set_number(number);
211 set_city_code(city_code);
212 set_country_code(country_code);
213}
214
[email protected]3db3ff62010-01-07 00:35:39215PhoneNumber::PhoneNumber(const PhoneNumber& phone_number)
[email protected]225c8f52010-02-05 22:23:20216 : FormGroup(),
217 country_code_(phone_number.country_code_),
[email protected]3db3ff62010-01-07 00:35:39218 city_code_(phone_number.city_code_),
219 number_(phone_number.number_),
220 extension_(phone_number.extension_) {
221}
222
223bool PhoneNumber::FindInfoMatchesHelper(const FieldTypeSubGroup& subgroup,
224 const string16& info,
225 string16* match) const {
226 if (match == NULL) {
227 DLOG(ERROR) << "NULL match string passed in";
228 return false;
229 }
230
231 match->clear();
232 if (subgroup == AutoFillType::PHONE_NUMBER &&
233 StartsWith(number(), info, true)) {
234 *match = number();
235 } else if (subgroup == AutoFillType::PHONE_CITY_CODE &&
236 StartsWith(city_code(), info, true)) {
237 *match = city_code();
238 } else if (subgroup == AutoFillType::PHONE_COUNTRY_CODE &&
239 StartsWith(country_code(), info, true)) {
240 *match = country_code();
241 } else if (subgroup == AutoFillType::PHONE_CITY_AND_NUMBER &&
242 StartsWith(CityAndNumber(), info, true)) {
243 *match = CityAndNumber();
244 } else if (subgroup == AutoFillType::PHONE_WHOLE_NUMBER &&
245 StartsWith(WholeNumber(), info, true)) {
246 *match = WholeNumber();
247 }
248
249 return !match->empty();
250}
251
252bool PhoneNumber::IsNumber(const string16& text) const {
[email protected]48db6fb2010-05-25 16:48:01253 if (text.length() > number_.length())
[email protected]3db3ff62010-01-07 00:35:39254 return false;
255
256 return StartsWith(number_, text, false);
257}
258
259bool PhoneNumber::IsCityCode(const string16& text) const {
[email protected]48db6fb2010-05-25 16:48:01260 if (text.length() > city_code_.length())
[email protected]3db3ff62010-01-07 00:35:39261 return false;
262
263 return StartsWith(city_code_, text, false);
264}
265
266bool PhoneNumber::IsCountryCode(const string16& text) const {
[email protected]48db6fb2010-05-25 16:48:01267 if (text.length() > country_code_.length())
[email protected]3db3ff62010-01-07 00:35:39268 return false;
269
270 return StartsWith(country_code_, text, false);
271}
272
273bool PhoneNumber::IsCityAndNumber(const string16& text) const {
274 string16 city_and_number(CityAndNumber());
275 if (text.length() > city_and_number.length())
276 return false;
277
278 return StartsWith(city_and_number, text, false);
279}
280
281bool PhoneNumber::IsWholeNumber(const string16& text) const {
282 string16 whole_number(WholeNumber());
283 if (text.length() > whole_number.length())
284 return false;
285
286 return StartsWith(whole_number, text, false);
287}
288
289bool PhoneNumber::Validate(const string16& number) const {
290 for (size_t i = 0; i < number.length(); ++i) {
291 if (!IsAsciiDigit(number[i]))
292 return false;
293 }
294
295 return true;
296}
297
[email protected]9b435be92010-03-04 21:20:15298// Static.
299void PhoneNumber::StripPunctuation(string16* number) {
300 RemoveChars(*number, kPhoneNumberSeparators, number);
[email protected]3db3ff62010-01-07 00:35:39301}