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/data_model/address.h"
6
7 #include <stddef.h>
8 #include <algorithm>
9
10 #include "base/check_op.h"
11 #include "base/feature_list.h"
12 #include "base/i18n/case_conversion.h"
13 #include "base/notreached.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "components/autofill/core/browser/autofill_data_util.h"
19 #include "components/autofill/core/browser/autofill_field.h"
20 #include "components/autofill/core/browser/autofill_type.h"
21 #include "components/autofill/core/browser/data_model/autofill_profile.h"
22 #include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
23 #include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
24 #include "components/autofill/core/browser/geo/autofill_country.h"
25 #include "components/autofill/core/browser/geo/country_names.h"
26 #include "components/autofill/core/browser/geo/state_names.h"
27 #include "components/autofill/core/common/autofill_features.h"
28 #include "components/autofill/core/common/autofill_l10n_util.h"
29
30 namespace autofill {
31
32 using structured_address::VerificationStatus;
33
34 Address::Address() = default;
35
36 Address::Address(const Address& address) = default;
37
38 Address::~Address() = default;
39
40 Address& Address::operator=(const Address& address) = default;
41
operator ==(const Address & other) const42 bool Address::operator==(const Address& other) const {
43 if (this == &other)
44 return true;
45 // TODO(crbug.com/1130194): Clean legacy implementation once structured
46 // addresses are fully launched.
47 if (structured_address::StructuredAddressesEnabled()) {
48 return structured_address_ == other.structured_address_;
49 }
50
51 return street_address_ == other.street_address_ &&
52 dependent_locality_ == other.dependent_locality_ &&
53 city_ == other.city_ && state_ == other.state_ &&
54 zip_code_ == other.zip_code_ && sorting_code_ == other.sorting_code_ &&
55 country_code_ == other.country_code_ &&
56 street_name_ == other.street_name_ &&
57 dependent_street_name_ == other.dependent_street_name_ &&
58 house_number_ == other.house_number_ &&
59 premise_name_ == other.premise_name_ &&
60 subpremise_ == other.subpremise_;
61 }
62
FinalizeAfterImport(bool profile_is_verified)63 bool Address::FinalizeAfterImport(bool profile_is_verified) {
64 // TODO(crbug.com/1130194): Remove feature check once structured addresses are
65 // fully launched.
66 if (structured_address::StructuredAddressesEnabled()) {
67 structured_address_.MigrateLegacyStructure(profile_is_verified);
68 bool result = structured_address_.CompleteFullTree();
69 // If the address could not be completed, it is possible that it contains an
70 // invalid structure.
71 if (!result) {
72 if (structured_address_.WipeInvalidStructure()) {
73 // If the structure was wiped because it is invalid, try to complete the
74 // address again.
75 result = structured_address_.CompleteFullTree();
76 }
77 }
78 return result;
79 }
80 return true;
81 }
82
MergeStructuredAddress(const Address & newer,bool newer_was_more_recently_used)83 bool Address::MergeStructuredAddress(const Address& newer,
84 bool newer_was_more_recently_used) {
85 return structured_address_.MergeWithComponent(newer.GetStructuredAddress(),
86 newer_was_more_recently_used);
87 }
88
IsStructuredAddressMergeable(const Address & newer) const89 bool Address::IsStructuredAddressMergeable(const Address& newer) const {
90 return structured_address_.IsMergeableWithComponent(
91 newer.GetStructuredAddress());
92 }
93
GetStructuredAddress() const94 const structured_address::Address& Address::GetStructuredAddress() const {
95 return structured_address_;
96 }
97
GetRawInfo(ServerFieldType type) const98 base::string16 Address::GetRawInfo(ServerFieldType type) const {
99 DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
100
101 // For structured addresses, the value can be directly retrieved.
102 if (structured_address::StructuredAddressesEnabled())
103 return structured_address_.GetValueForType(type);
104
105 switch (type) {
106 case ADDRESS_HOME_LINE1:
107 return street_address_.size() > 0 ? street_address_[0] : base::string16();
108
109 case ADDRESS_HOME_LINE2:
110 return street_address_.size() > 1 ? street_address_[1] : base::string16();
111
112 case ADDRESS_HOME_LINE3:
113 return street_address_.size() > 2 ? street_address_[2] : base::string16();
114
115 case ADDRESS_HOME_DEPENDENT_LOCALITY:
116 return dependent_locality_;
117
118 case ADDRESS_HOME_CITY:
119 return city_;
120
121 case ADDRESS_HOME_STATE:
122 return state_;
123
124 case ADDRESS_HOME_ZIP:
125 return zip_code_;
126
127 case ADDRESS_HOME_SORTING_CODE:
128 return sorting_code_;
129
130 case ADDRESS_HOME_COUNTRY:
131 return base::ASCIIToUTF16(country_code_);
132
133 case ADDRESS_HOME_STREET_ADDRESS:
134 return base::JoinString(street_address_, base::ASCIIToUTF16("\n"));
135
136 case ADDRESS_HOME_APT_NUM:
137 return base::string16();
138
139 // The following tokens are used for creating new type votes but should not
140 // be filled into fields.
141 case ADDRESS_HOME_STREET_NAME:
142 return street_name_;
143
144 case ADDRESS_HOME_HOUSE_NUMBER:
145 return house_number_;
146
147 case ADDRESS_HOME_DEPENDENT_STREET_NAME:
148 return dependent_street_name_;
149
150 case ADDRESS_HOME_PREMISE_NAME:
151 return premise_name_;
152
153 case ADDRESS_HOME_SUBPREMISE:
154 return subpremise_;
155
156 default:
157 NOTREACHED() << "Unrecognized type: " << type;
158 return base::string16();
159 }
160 }
161
SetRawInfoWithVerificationStatus(ServerFieldType type,const base::string16 & value,VerificationStatus status)162 void Address::SetRawInfoWithVerificationStatus(ServerFieldType type,
163 const base::string16& value,
164 VerificationStatus status) {
165 DCHECK_EQ(ADDRESS_HOME, AutofillType(type).group());
166
167 // For structured addresses, the value can directly be set.
168 // TODO(crbug.com/1130194): Clean legacy implementation once structured
169 // addresses are fully launched.
170 if (structured_address::StructuredAddressesEnabled()) {
171 // The street address has a structure that may have already been set before
172 // using the settings dialog. In case the settings dialog was used to change
173 // the address to contain different tokens, the structure must be reset.
174 if (type == ADDRESS_HOME_STREET_ADDRESS) {
175 const base::string16 current_value =
176 structured_address_.GetValueForType(type);
177 if (!current_value.empty()) {
178 bool token_equivalent = structured_address::AreStringTokenEquivalent(
179 value, structured_address_.GetValueForType(type));
180 structured_address_.SetValueForTypeIfPossible(
181 ADDRESS_HOME_STREET_ADDRESS, value, status,
182 /*invalidate_child_nodes=*/!token_equivalent);
183 return;
184 }
185 }
186
187 structured_address_.SetValueForTypeIfPossible(type, value, status);
188 return;
189 }
190
191 switch (type) {
192 // If any of the address lines change, the structured tokens must be
193 // reset.
194 case ADDRESS_HOME_LINE1:
195 if (street_address_.empty())
196 street_address_.resize(1);
197 if (street_address_[0] != value)
198 ResetStructuredTokes();
199 street_address_[0] = value;
200 TrimStreetAddress();
201 break;
202
203 case ADDRESS_HOME_LINE2:
204 if (street_address_.size() < 2)
205 street_address_.resize(2);
206 if (street_address_[1] != value)
207 ResetStructuredTokes();
208 street_address_[1] = value;
209 TrimStreetAddress();
210 break;
211
212 case ADDRESS_HOME_LINE3:
213 if (street_address_.size() < 3)
214 street_address_.resize(3);
215 if (street_address_[2] != value)
216 ResetStructuredTokes();
217 street_address_[2] = value;
218 TrimStreetAddress();
219 break;
220
221 case ADDRESS_HOME_DEPENDENT_LOCALITY:
222 dependent_locality_ = value;
223 break;
224
225 case ADDRESS_HOME_CITY:
226 city_ = value;
227 break;
228
229 case ADDRESS_HOME_STATE:
230 state_ = value;
231 break;
232
233 case ADDRESS_HOME_COUNTRY:
234 DCHECK(value.empty() ||
235 data_util::IsValidCountryCode(base::i18n::ToUpper(value)));
236 country_code_ = base::ToUpperASCII(base::UTF16ToASCII(value));
237 break;
238
239 case ADDRESS_HOME_ZIP:
240 zip_code_ = value;
241 break;
242
243 case ADDRESS_HOME_SORTING_CODE:
244 sorting_code_ = value;
245 break;
246
247 case ADDRESS_HOME_STREET_ADDRESS:
248 // If the street address changes, the structured tokens must be reset.
249 if (base::SplitString(value, base::ASCIIToUTF16("\n"),
250 base::TRIM_WHITESPACE,
251 base::SPLIT_WANT_ALL) != street_address_) {
252 ResetStructuredTokes();
253 street_address_ =
254 base::SplitString(value, base::ASCIIToUTF16("\n"),
255 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
256 }
257 break;
258
259 // The following types are used to create type votes but should not be
260 // filled into fields.
261 case ADDRESS_HOME_STREET_NAME:
262 street_name_ = value;
263 break;
264
265 case ADDRESS_HOME_DEPENDENT_STREET_NAME:
266 dependent_street_name_ = value;
267 break;
268
269 case ADDRESS_HOME_HOUSE_NUMBER:
270 house_number_ = value;
271 break;
272
273 case ADDRESS_HOME_PREMISE_NAME:
274 premise_name_ = value;
275 break;
276
277 case ADDRESS_HOME_SUBPREMISE:
278 subpremise_ = value;
279 break;
280
281 default:
282 NOTREACHED();
283 }
284 }
285
ResetStructuredTokes()286 void Address::ResetStructuredTokes() {
287 street_name_.clear();
288 dependent_street_name_.clear();
289 house_number_.clear();
290 premise_name_.clear();
291 subpremise_.clear();
292 }
293
GetMatchingTypes(const base::string16 & text,const std::string & app_locale,ServerFieldTypeSet * matching_types) const294 void Address::GetMatchingTypes(const base::string16& text,
295 const std::string& app_locale,
296 ServerFieldTypeSet* matching_types) const {
297 FormGroup::GetMatchingTypes(text, app_locale, matching_types);
298
299 // Get the country code stored in the profile either from the structured
300 // address if enabled or from the legacy field.
301 // TODO(crbug.com/1130194): Clean legacy implementation once structured
302 // addresses are fully launched.
303 std::string country_code =
304 structured_address::StructuredAddressesEnabled()
305 ? base::UTF16ToUTF8(
306 structured_address_.GetValueForType(ADDRESS_HOME_COUNTRY))
307 : country_code_;
308
309 // Check to see if the |text| canonicalized as a country name is a match.
310 std::string entered_country_code =
311 CountryNames::GetInstance()->GetCountryCodeForLocalizedCountryName(
312 text, app_locale);
313 if (!entered_country_code.empty() && country_code == entered_country_code)
314 matching_types->insert(ADDRESS_HOME_COUNTRY);
315
316 AutofillProfileComparator comparator(app_locale);
317 // Check to see if the |text| could be the full name or abbreviation of a
318 // state.
319 base::string16 canon_text = comparator.NormalizeForComparison(text);
320 base::string16 state_name;
321 base::string16 state_abbreviation;
322 state_names::GetNameAndAbbreviation(canon_text, &state_name,
323 &state_abbreviation);
324 if (!state_name.empty() || !state_abbreviation.empty()) {
325 l10n::CaseInsensitiveCompare compare;
326 base::string16 canon_profile_state = comparator.NormalizeForComparison(
327 GetInfo(AutofillType(ADDRESS_HOME_STATE), app_locale));
328 if ((!state_name.empty() &&
329 compare.StringsEqual(state_name, canon_profile_state)) ||
330 (!state_abbreviation.empty() &&
331 compare.StringsEqual(state_abbreviation, canon_profile_state))) {
332 matching_types->insert(ADDRESS_HOME_STATE);
333 }
334 }
335 }
336
GetSupportedTypes(ServerFieldTypeSet * supported_types) const337 void Address::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
338 supported_types->insert(ADDRESS_HOME_LINE1);
339 supported_types->insert(ADDRESS_HOME_LINE2);
340 supported_types->insert(ADDRESS_HOME_LINE3);
341 supported_types->insert(ADDRESS_HOME_STREET_ADDRESS);
342 supported_types->insert(ADDRESS_HOME_DEPENDENT_LOCALITY);
343 supported_types->insert(ADDRESS_HOME_CITY);
344 supported_types->insert(ADDRESS_HOME_STATE);
345 supported_types->insert(ADDRESS_HOME_ZIP);
346 supported_types->insert(ADDRESS_HOME_SORTING_CODE);
347 supported_types->insert(ADDRESS_HOME_COUNTRY);
348 // If those types are not added, no votes will be generated.
349 if (base::FeatureList::IsEnabled(
350 features::kAutofillAddressEnhancementVotes) ||
351 structured_address::StructuredAddressesEnabled()) {
352 supported_types->insert(ADDRESS_HOME_STREET_NAME);
353 supported_types->insert(ADDRESS_HOME_DEPENDENT_STREET_NAME);
354 supported_types->insert(ADDRESS_HOME_HOUSE_NUMBER);
355 supported_types->insert(ADDRESS_HOME_PREMISE_NAME);
356 supported_types->insert(ADDRESS_HOME_SUBPREMISE);
357 }
358 }
359
GetInfoImpl(const AutofillType & type,const std::string & locale) const360 base::string16 Address::GetInfoImpl(const AutofillType& type,
361 const std::string& locale) const {
362 // Get the country code stored in the profile either from the structured
363 // address if enabled or from the legacy field.
364 // TODO(crbug.com/1130194): Clean legacy implementation once structured
365 // addresses are fully launched.
366 std::string country_code =
367 structured_address::StructuredAddressesEnabled()
368 ? base::UTF16ToUTF8(
369 structured_address_.GetValueForType(ADDRESS_HOME_COUNTRY))
370 : country_code_;
371
372 if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
373 return base::ASCIIToUTF16(country_code);
374 }
375
376 ServerFieldType storable_type = type.GetStorableType();
377 if (storable_type == ADDRESS_HOME_COUNTRY && !country_code.empty())
378 return AutofillCountry(country_code, locale).name();
379
380 return GetRawInfo(storable_type);
381 }
382
SetInfoWithVerificationStatusImpl(const AutofillType & type,const base::string16 & value,const std::string & locale,VerificationStatus status)383 bool Address::SetInfoWithVerificationStatusImpl(const AutofillType& type,
384 const base::string16& value,
385 const std::string& locale,
386 VerificationStatus status) {
387 // TODO(crbug.com/1130194): Clean legacy implementation once structured
388 // addresses are fully launched.
389 bool use_structured_address =
390 structured_address::StructuredAddressesEnabled();
391
392 if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
393 std::string country_code = base::ToUpperASCII(base::UTF16ToASCII(value));
394 if (!data_util::IsValidCountryCode(country_code)) {
395 // To counteract the misuse of autocomplete=country attribute when used
396 // with full country names, if the supplied country code is not a valid,
397 // it is tested if a country code can be derived from the value when it is
398 // interpreted as a full country name. Otherwise an empty string is
399 // assigned to |country_code|.
400 CountryNames* country_names =
401 !value.empty() ? CountryNames::GetInstance() : nullptr;
402 country_code = country_names
403 ? country_names->GetCountryCodeForLocalizedCountryName(
404 value, locale)
405 : std::string();
406 }
407
408 // TODO(crbug.com/1130194): Clean legacy implementation once structured
409 // addresses are fully launched.
410 if (use_structured_address) {
411 structured_address_.SetValueForTypeIfPossible(ADDRESS_HOME_COUNTRY,
412 country_code, status);
413 } else {
414 country_code_ = country_code;
415 }
416 return !country_code.empty();
417 }
418
419 if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
420 // Parsing a full address is too hard.
421 return false;
422 }
423
424 ServerFieldType storable_type = type.GetStorableType();
425 if (storable_type == ADDRESS_HOME_COUNTRY && !value.empty()) {
426 std::string country_code =
427 CountryNames::GetInstance()->GetCountryCodeForLocalizedCountryName(
428 value, locale);
429 // TODO(crbug.com/1130194): Clean legacy implementation once structured
430 // addresses are fully launched.
431 if (use_structured_address) {
432 structured_address_.SetValueForTypeIfPossible(ADDRESS_HOME_COUNTRY,
433 country_code, status);
434 } else {
435 country_code_ = country_code;
436 }
437 return !country_code_.empty();
438 }
439
440 SetRawInfoWithVerificationStatus(storable_type, value, status);
441
442 // Give up when importing addresses with any entirely blank lines.
443 // There's a good chance that this formatting is not intentional, but it's
444 // also not obviously safe to just strip the newlines.
445 if (storable_type == ADDRESS_HOME_STREET_ADDRESS) {
446 // TODO(crbug.com/1130194): Clean legacy implementation once structured
447 // addresses are fully launched.
448 if (structured_address::StructuredAddressesEnabled()) {
449 return structured_address_.IsValueForTypeValid(
450 ADDRESS_HOME_STREET_ADDRESS, /*wipe_if_not=*/true);
451 } else if (base::Contains(street_address_, base::string16())) {
452 street_address_.clear();
453 return false;
454 }
455 }
456
457 return true;
458 }
459
GetVerificationStatusImpl(ServerFieldType type) const460 VerificationStatus Address::GetVerificationStatusImpl(
461 ServerFieldType type) const {
462 // TODO(crbug.com/1130194): Clean legacy implementation once structured
463 // addresses are fully launched.
464 if (structured_address::StructuredAddressesEnabled())
465 return structured_address_.GetVerificationStatusForType(type);
466 return VerificationStatus::kNoStatus;
467 }
468
TrimStreetAddress()469 void Address::TrimStreetAddress() {
470 while (!street_address_.empty() && street_address_.back().empty()) {
471 street_address_.pop_back();
472 }
473 }
474
475 } // namespace autofill
476