blob: 2d1edcf221d952e5f44f71cb8563985295ae6aab [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// 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/autofill_data_model.h"
6
7#include "base/basictypes.h"
8#include "base/logging.h"
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "components/autofill/core/browser/autofill_country.h"
13#include "components/autofill/core/browser/autofill_field.h"
Ben Murdoch32409262013-08-07 11:04:47 +010014#include "components/autofill/core/browser/autofill_type.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010015#include "components/autofill/core/browser/state_names.h"
16#include "components/autofill/core/browser/validation.h"
17#include "components/autofill/core/common/form_field_data.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010018#include "grit/component_strings.h"
19#include "ui/base/l10n/l10n_util.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010020#include "url/gurl.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010021
22namespace autofill {
23namespace {
24
25const char* const kMonthsAbbreviated[] = {
26 NULL, // Padding so index 1 = month 1 = January.
27 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
28 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
29};
30
31const char* const kMonthsFull[] = {
32 NULL, // Padding so index 1 = month 1 = January.
33 "January", "February", "March", "April", "May", "June",
34 "July", "August", "September", "October", "November", "December",
35};
36
37const char* const kMonthsNumeric[] = {
38 NULL, // Padding so index 1 = month 1 = January.
39 "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
40};
41
42// Returns true if the value was successfully set, meaning |value| was found in
43// the list of select options in |field|.
44bool SetSelectControlValue(const base::string16& value,
45 FormFieldData* field) {
46 base::string16 value_lowercase = StringToLowerASCII(value);
47
48 DCHECK_EQ(field->option_values.size(), field->option_contents.size());
49 for (size_t i = 0; i < field->option_values.size(); ++i) {
50 if (value_lowercase == StringToLowerASCII(field->option_values[i]) ||
51 value_lowercase == StringToLowerASCII(field->option_contents[i])) {
52 field->value = field->option_values[i];
53 return true;
54 }
55 }
56
57 return false;
58}
59
60bool FillStateSelectControl(const base::string16& value,
61 FormFieldData* field) {
62 base::string16 full, abbreviation;
63 state_names::GetNameAndAbbreviation(value, &full, &abbreviation);
64
65 // Try the abbreviation first.
66 if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field))
67 return true;
68
69 return !full.empty() && SetSelectControlValue(full, field);
70}
71
72bool FillExpirationMonthSelectControl(const base::string16& value,
73 FormFieldData* field) {
74 int index = 0;
75 if (!base::StringToInt(value, &index) ||
76 index <= 0 ||
77 static_cast<size_t>(index) >= arraysize(kMonthsFull))
78 return false;
79
80 bool filled =
81 SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
82 SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
83 SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field);
84 return filled;
85}
86
87// Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the
88// given |field|.
89bool FillCreditCardTypeSelectControl(const base::string16& value,
90 FormFieldData* field) {
91 // Try stripping off spaces.
92 base::string16 value_stripped;
93 RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped);
94
95 for (size_t i = 0; i < field->option_values.size(); ++i) {
96 base::string16 option_value_lowercase;
97 RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16,
98 &option_value_lowercase);
99 base::string16 option_contents_lowercase;
100 RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16,
101 &option_contents_lowercase);
102
103 // Perform a case-insensitive comparison; but fill the form with the
104 // original text, not the lowercased version.
105 if (value_stripped == option_value_lowercase ||
106 value_stripped == option_contents_lowercase) {
107 field->value = field->option_values[i];
108 return true;
109 }
110 }
111
112 // For American Express, also try filling as "AmEx".
113 if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
114 return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field);
115
116 return false;
117}
118
119} // namespace
120
121AutofillDataModel::AutofillDataModel(const std::string& guid,
122 const std::string& origin)
123 : guid_(guid),
124 origin_(origin) {}
125AutofillDataModel::~AutofillDataModel() {}
126
Ben Murdoch32409262013-08-07 11:04:47 +0100127void AutofillDataModel::FillSelectControl(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100128 const std::string& app_locale,
129 FormFieldData* field) const {
130 DCHECK(field);
131 DCHECK_EQ("select-one", field->form_control_type);
132 DCHECK_EQ(field->option_values.size(), field->option_contents.size());
133
134 base::string16 field_text = GetInfo(type, app_locale);
135 base::string16 field_text_lower = StringToLowerASCII(field_text);
136 if (field_text.empty())
137 return;
138
139 base::string16 value;
140 for (size_t i = 0; i < field->option_values.size(); ++i) {
141 if (field_text == field->option_values[i] ||
142 field_text == field->option_contents[i]) {
143 // An exact match, use it.
144 value = field->option_values[i];
145 break;
146 }
147
148 if (field_text_lower == StringToLowerASCII(field->option_values[i]) ||
149 field_text_lower == StringToLowerASCII(field->option_contents[i])) {
150 // A match, but not in the same case. Save it in case an exact match is
151 // not found.
152 value = field->option_values[i];
153 }
154 }
155
156 if (!value.empty()) {
157 field->value = value;
158 return;
159 }
160
Ben Murdochbb1529c2013-08-08 10:24:53 +0100161 ServerFieldType storable_type = type.GetStorableType();
162 if (storable_type == ADDRESS_HOME_STATE) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100163 FillStateSelectControl(field_text, field);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100164 } else if (storable_type == ADDRESS_HOME_COUNTRY) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100165 FillCountrySelectControl(app_locale, field);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100166 } else if (storable_type == CREDIT_CARD_EXP_MONTH) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100167 FillExpirationMonthSelectControl(field_text, field);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100168 } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100169 // Attempt to fill the year as a 2-digit year. This compensates for the
170 // fact that our heuristics do not always correctly detect when a website
171 // requests a 2-digit rather than a 4-digit year.
Ben Murdoch32409262013-08-07 11:04:47 +0100172 FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale,
173 field);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100174 } else if (storable_type == CREDIT_CARD_TYPE) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100175 FillCreditCardTypeSelectControl(field_text, field);
176 }
177}
178
179bool AutofillDataModel::FillCountrySelectControl(
180 const std::string& app_locale,
181 FormFieldData* field_data) const {
182 return false;
183}
184
185bool AutofillDataModel::IsVerified() const {
186 return !origin_.empty() && !GURL(origin_).is_valid();
187}
188
189} // namespace autofill