Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 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/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 Murdoch | 3240926 | 2013-08-07 11:04:47 +0100 | [diff] [blame] | 14 | #include "components/autofill/core/browser/autofill_type.h" |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 15 | #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 Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 18 | #include "grit/component_strings.h" |
| 19 | #include "ui/base/l10n/l10n_util.h" |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 20 | #include "url/gurl.h" |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 21 | |
| 22 | namespace autofill { |
| 23 | namespace { |
| 24 | |
| 25 | const 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 | |
| 31 | const 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 | |
| 37 | const 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|. |
| 44 | bool 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 | |
| 60 | bool 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 | |
| 72 | bool 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|. |
| 89 | bool 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 | |
| 121 | AutofillDataModel::AutofillDataModel(const std::string& guid, |
| 122 | const std::string& origin) |
| 123 | : guid_(guid), |
| 124 | origin_(origin) {} |
| 125 | AutofillDataModel::~AutofillDataModel() {} |
| 126 | |
Ben Murdoch | 3240926 | 2013-08-07 11:04:47 +0100 | [diff] [blame] | 127 | void AutofillDataModel::FillSelectControl(const AutofillType& type, |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 128 | 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 Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 161 | ServerFieldType storable_type = type.GetStorableType(); |
| 162 | if (storable_type == ADDRESS_HOME_STATE) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 163 | FillStateSelectControl(field_text, field); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 164 | } else if (storable_type == ADDRESS_HOME_COUNTRY) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 165 | FillCountrySelectControl(app_locale, field); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 166 | } else if (storable_type == CREDIT_CARD_EXP_MONTH) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 167 | FillExpirationMonthSelectControl(field_text, field); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 168 | } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 169 | // 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 Murdoch | 3240926 | 2013-08-07 11:04:47 +0100 | [diff] [blame] | 172 | FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale, |
| 173 | field); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 174 | } else if (storable_type == CREDIT_CARD_TYPE) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 175 | FillCreditCardTypeSelectControl(field_text, field); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | bool AutofillDataModel::FillCountrySelectControl( |
| 180 | const std::string& app_locale, |
| 181 | FormFieldData* field_data) const { |
| 182 | return false; |
| 183 | } |
| 184 | |
| 185 | bool AutofillDataModel::IsVerified() const { |
| 186 | return !origin_.empty() && !GURL(origin_).is_valid(); |
| 187 | } |
| 188 | |
| 189 | } // namespace autofill |