autofill_data_model.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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"
14#include "components/autofill/core/browser/autofill_type.h"
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"
18#include "grit/component_strings.h"
19#include "ui/base/l10n/l10n_util.h"
20#include "url/gurl.h"
21
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
127void AutofillDataModel::FillSelectControl(const AutofillType& type,
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
161  ServerFieldType server_type = type.server_type();
162  if (server_type == ADDRESS_HOME_STATE ||
163      server_type == ADDRESS_BILLING_STATE) {
164    FillStateSelectControl(field_text, field);
165  } else if (server_type == ADDRESS_HOME_COUNTRY ||
166             server_type == ADDRESS_BILLING_COUNTRY) {
167    FillCountrySelectControl(app_locale, field);
168  } else if (server_type == CREDIT_CARD_EXP_MONTH) {
169    FillExpirationMonthSelectControl(field_text, field);
170  } else if (server_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
171    // Attempt to fill the year as a 2-digit year.  This compensates for the
172    // fact that our heuristics do not always correctly detect when a website
173    // requests a 2-digit rather than a 4-digit year.
174    FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale,
175                      field);
176  } else if (server_type == CREDIT_CARD_TYPE) {
177    FillCreditCardTypeSelectControl(field_text, field);
178  }
179}
180
181bool AutofillDataModel::FillCountrySelectControl(
182    const std::string& app_locale,
183    FormFieldData* field_data) const {
184  return false;
185}
186
187bool AutofillDataModel::IsVerified() const {
188  return !origin_.empty() && !GURL(origin_).is_valid();
189}
190
191}  // namespace autofill
192