| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/autofill/credit_card_field.h" | 5 #include "chrome/browser/autofill/credit_card_field.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/string16.h" | 11 #include "base/string16.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "chrome/browser/autofill/autofill_ecml.h" |
| 14 #include "chrome/browser/autofill/autofill_field.h" | 15 #include "chrome/browser/autofill/autofill_field.h" |
| 15 #include "chrome/browser/autofill/autofill_scanner.h" | 16 #include "chrome/browser/autofill/autofill_scanner.h" |
| 16 #include "chrome/browser/autofill/field_types.h" | 17 #include "chrome/browser/autofill/field_types.h" |
| 17 #include "grit/autofill_resources.h" | 18 #include "grit/autofill_resources.h" |
| 18 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
| 19 | 20 |
| 20 bool CreditCardField::GetFieldInfo(FieldTypeMap* field_type_map) const { | 21 using autofill::GetEcmlPattern; |
| 21 bool ok = Add(field_type_map, number_, CREDIT_CARD_NUMBER); | |
| 22 | |
| 23 // If the heuristics detected first and last name in separate fields, | |
| 24 // then ignore both fields. Putting them into separate fields is probably | |
| 25 // wrong, because the credit card can also contain a middle name or middle | |
| 26 // initial. | |
| 27 if (cardholder_last_ == NULL) | |
| 28 ok = ok && Add(field_type_map, cardholder_, CREDIT_CARD_NAME); | |
| 29 | |
| 30 ok = ok && Add(field_type_map, type_, CREDIT_CARD_TYPE); | |
| 31 ok = ok && Add(field_type_map, expiration_month_, CREDIT_CARD_EXP_MONTH); | |
| 32 ok = ok && Add(field_type_map, expiration_year_, | |
| 33 CREDIT_CARD_EXP_4_DIGIT_YEAR); | |
| 34 return ok; | |
| 35 } | |
| 36 | 22 |
| 37 // static | 23 // static |
| 38 CreditCardField* CreditCardField::Parse(AutofillScanner* scanner, | 24 CreditCardField* CreditCardField::Parse(AutofillScanner* scanner, |
| 39 bool is_ecml) { | 25 bool is_ecml) { |
| 40 if (scanner->IsEnd()) | 26 if (scanner->IsEnd()) |
| 41 return NULL; | 27 return NULL; |
| 42 | 28 |
| 43 scoped_ptr<CreditCardField> credit_card_field(new CreditCardField); | 29 scoped_ptr<CreditCardField> credit_card_field(new CreditCardField); |
| 44 scanner->SaveCursor(); | 30 scanner->SaveCursor(); |
| 45 | 31 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 61 if (fields == 0 || credit_card_field->expiration_month_) { | 47 if (fields == 0 || credit_card_field->expiration_month_) { |
| 62 // at beginning or end | 48 // at beginning or end |
| 63 name_pattern = l10n_util::GetStringUTF16( | 49 name_pattern = l10n_util::GetStringUTF16( |
| 64 IDS_AUTOFILL_NAME_ON_CARD_RE); | 50 IDS_AUTOFILL_NAME_ON_CARD_RE); |
| 65 } else { | 51 } else { |
| 66 name_pattern = l10n_util::GetStringUTF16( | 52 name_pattern = l10n_util::GetStringUTF16( |
| 67 IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE); | 53 IDS_AUTOFILL_NAME_ON_CARD_CONTEXTUAL_RE); |
| 68 } | 54 } |
| 69 } | 55 } |
| 70 | 56 |
| 71 if (ParseText(scanner, name_pattern, &credit_card_field->cardholder_)) | 57 if (ParseField(scanner, name_pattern, &credit_card_field->cardholder_)) |
| 72 continue; | 58 continue; |
| 73 | 59 |
| 74 // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html | 60 // As a hard-coded hack for Expedia's billing pages (expedia_checkout.html |
| 75 // and ExpediaBilling.html in our test suite), recognize separate fields | 61 // and ExpediaBilling.html in our test suite), recognize separate fields |
| 76 // for the cardholder's first and last name if they have the labels "cfnm" | 62 // for the cardholder's first and last name if they have the labels "cfnm" |
| 77 // and "clnm". | 63 // and "clnm". |
| 78 scanner->SaveCursor(); | 64 scanner->SaveCursor(); |
| 79 const AutofillField* first; | 65 const AutofillField* first; |
| 80 if (!is_ecml && ParseText(scanner, ASCIIToUTF16("^cfnm"), &first) && | 66 if (!is_ecml && ParseField(scanner, ASCIIToUTF16("^cfnm"), &first) && |
| 81 ParseText(scanner, ASCIIToUTF16("^clnm"), | 67 ParseField(scanner, ASCIIToUTF16("^clnm"), |
| 82 &credit_card_field->cardholder_last_)) { | 68 &credit_card_field->cardholder_last_)) { |
| 83 credit_card_field->cardholder_ = first; | 69 credit_card_field->cardholder_ = first; |
| 84 continue; | 70 continue; |
| 85 } | 71 } |
| 86 scanner->Rewind(); | 72 scanner->Rewind(); |
| 87 } | 73 } |
| 88 | 74 |
| 89 // We look for a card security code before we look for a credit | 75 // We look for a card security code before we look for a credit |
| 90 // card number and match the general term "number". The security code | 76 // card number and match the general term "number". The security code |
| 91 // has a plethora of names; we've seen "verification #", | 77 // has a plethora of names; we've seen "verification #", |
| 92 // "verification number", "card identification number" and others listed | 78 // "verification number", "card identification number" and others listed |
| 93 // in the |pattern| below. | 79 // in the |pattern| below. |
| 94 string16 pattern; | 80 string16 pattern; |
| 95 if (is_ecml) | 81 if (is_ecml) |
| 96 pattern = GetEcmlPattern(kEcmlCardVerification); | 82 pattern = GetEcmlPattern(kEcmlCardVerification); |
| 97 else | 83 else |
| 98 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE); | 84 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_CVC_RE); |
| 99 | 85 |
| 100 if (!credit_card_field->verification_ && | 86 if (!credit_card_field->verification_ && |
| 101 ParseText(scanner, pattern, &credit_card_field->verification_)) | 87 ParseField(scanner, pattern, &credit_card_field->verification_)) { |
| 102 continue; | 88 continue; |
| 103 | 89 } |
| 104 // TODO(jhawkins): Parse the type select control. | 90 // TODO(jhawkins): Parse the type select control. |
| 105 | 91 |
| 106 if (is_ecml) | 92 if (is_ecml) |
| 107 pattern = GetEcmlPattern(kEcmlCardNumber); | 93 pattern = GetEcmlPattern(kEcmlCardNumber); |
| 108 else | 94 else |
| 109 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE); | 95 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_NUMBER_RE); |
| 110 | 96 |
| 111 if (!credit_card_field->number_ && | 97 if (!credit_card_field->number_ && |
| 112 ParseText(scanner, pattern, &credit_card_field->number_)) | 98 ParseField(scanner, pattern, &credit_card_field->number_)) { |
| 113 continue; | 99 continue; |
| 100 } |
| 114 | 101 |
| 115 if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) { | 102 if (LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) { |
| 116 credit_card_field->expiration_month_ = scanner->Cursor(); | 103 credit_card_field->expiration_month_ = scanner->Cursor(); |
| 117 scanner->Advance(); | 104 scanner->Advance(); |
| 118 } else { | 105 } else { |
| 119 // "Expiration date" is the most common label here, but some pages have | 106 // "Expiration date" is the most common label here, but some pages have |
| 120 // "Expires", "exp. date" or "exp. month" and "exp. year". We also look | 107 // "Expires", "exp. date" or "exp. month" and "exp. year". We also look |
| 121 // for the field names ccmonth and ccyear, which appear on at least 4 of | 108 // for the field names ccmonth and ccyear, which appear on at least 4 of |
| 122 // our test pages. | 109 // our test pages. |
| 123 // | 110 // |
| 124 // -> On at least one page (The China Shop2.html) we find only the labels | 111 // -> On at least one page (The China Shop2.html) we find only the labels |
| 125 // "month" and "year". So for now we match these words directly; we'll | 112 // "month" and "year". So for now we match these words directly; we'll |
| 126 // see if this turns out to be too general. | 113 // see if this turns out to be too general. |
| 127 // | 114 // |
| 128 // Toolbar Bug 51451: indeed, simply matching "month" is too general for | 115 // Toolbar Bug 51451: indeed, simply matching "month" is too general for |
| 129 // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init. | 116 // https://rps.fidelity.com/ftgw/rps/RtlCust/CreatePIN/Init. |
| 130 // Instead, we match only words beginning with "month". | 117 // Instead, we match only words beginning with "month". |
| 131 if (is_ecml) | 118 if (is_ecml) |
| 132 pattern = GetEcmlPattern(kEcmlCardExpireMonth); | 119 pattern = GetEcmlPattern(kEcmlCardExpireMonth); |
| 133 else | 120 else |
| 134 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE); | 121 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_MONTH_RE); |
| 135 | 122 |
| 136 if ((!credit_card_field->expiration_month_ || | 123 if ((!credit_card_field->expiration_month_ || |
| 137 credit_card_field->expiration_month_->IsEmpty()) && | 124 credit_card_field->expiration_month_->IsEmpty()) && |
| 138 ParseText(scanner, pattern, &credit_card_field->expiration_month_)) { | 125 ParseField(scanner, pattern, &credit_card_field->expiration_month_)) { |
| 139 if (is_ecml) | 126 if (is_ecml) |
| 140 pattern = GetEcmlPattern(kEcmlCardExpireYear); | 127 pattern = GetEcmlPattern(kEcmlCardExpireYear); |
| 141 else | 128 else |
| 142 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE); | 129 pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EXPIRATION_DATE_RE); |
| 143 | 130 |
| 144 if (!ParseText(scanner, pattern, | 131 if (!ParseField(scanner, pattern, |
| 145 &credit_card_field->expiration_year_)) { | 132 &credit_card_field->expiration_year_)) { |
| 146 scanner->Rewind(); | 133 scanner->Rewind(); |
| 147 return NULL; | 134 return NULL; |
| 148 } | 135 } |
| 149 continue; | 136 continue; |
| 150 } | 137 } |
| 151 } | 138 } |
| 152 | 139 |
| 153 if (ParseText(scanner, GetEcmlPattern(kEcmlCardExpireDay))) | 140 if (ParseField(scanner, GetEcmlPattern(kEcmlCardExpireDay), NULL)) |
| 154 continue; | 141 continue; |
| 155 | 142 |
| 156 // Some pages (e.g. ExpediaBilling.html) have a "card description" | 143 // Some pages (e.g. ExpediaBilling.html) have a "card description" |
| 157 // field; we parse this field but ignore it. | 144 // field; we parse this field but ignore it. |
| 158 // We also ignore any other fields within a credit card block that | 145 // We also ignore any other fields within a credit card block that |
| 159 // start with "card", under the assumption that they are related to | 146 // start with "card", under the assumption that they are related to |
| 160 // the credit card section being processed but are uninteresting to us. | 147 // the credit card section being processed but are uninteresting to us. |
| 161 if (ParseText(scanner, | 148 if (ParseField(scanner, |
| 162 l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE))) | 149 l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_IGNORED_RE), |
| 150 NULL)) { |
| 163 continue; | 151 continue; |
| 152 } |
| 164 | 153 |
| 165 break; | 154 break; |
| 166 } | 155 } |
| 167 | 156 |
| 168 // Some pages have a billing address field after the cardholder name field. | 157 // Some pages have a billing address field after the cardholder name field. |
| 169 // For that case, allow only just the cardholder name field. The remaining | 158 // For that case, allow only just the cardholder name field. The remaining |
| 170 // CC fields will be picked up in a following CreditCardField. | 159 // CC fields will be picked up in a following CreditCardField. |
| 171 if (credit_card_field->cardholder_) | 160 if (credit_card_field->cardholder_) |
| 172 return credit_card_field.release(); | 161 return credit_card_field.release(); |
| 173 | 162 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 193 | 182 |
| 194 CreditCardField::CreditCardField() | 183 CreditCardField::CreditCardField() |
| 195 : cardholder_(NULL), | 184 : cardholder_(NULL), |
| 196 cardholder_last_(NULL), | 185 cardholder_last_(NULL), |
| 197 type_(NULL), | 186 type_(NULL), |
| 198 number_(NULL), | 187 number_(NULL), |
| 199 verification_(NULL), | 188 verification_(NULL), |
| 200 expiration_month_(NULL), | 189 expiration_month_(NULL), |
| 201 expiration_year_(NULL) { | 190 expiration_year_(NULL) { |
| 202 } | 191 } |
| 192 |
| 193 bool CreditCardField::ClassifyField(FieldTypeMap* map) const { |
| 194 bool ok = AddClassification(number_, CREDIT_CARD_NUMBER, map); |
| 195 |
| 196 // If the heuristics detected first and last name in separate fields, |
| 197 // then ignore both fields. Putting them into separate fields is probably |
| 198 // wrong, because the credit card can also contain a middle name or middle |
| 199 // initial. |
| 200 if (cardholder_last_ == NULL) |
| 201 ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map); |
| 202 |
| 203 ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map); |
| 204 ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map); |
| 205 ok = ok && AddClassification(expiration_year_, |
| 206 CREDIT_CARD_EXP_4_DIGIT_YEAR, |
| 207 map); |
| 208 return ok; |
| 209 } |
| OLD | NEW |