// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/autofill/form_field.h"
#include <stddef.h>
#include <string>
#include <utility>
#include "base/logging.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/address_field.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/credit_card_field.h"
#include "chrome/browser/autofill/field_types.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/name_field.h"
#include "chrome/browser/autofill/phone_field.h"
#include "grit/autofill_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "unicode/regex.h"
// Field names from the ECML specification; see RFC 3106. We've
// made these names lowercase since we convert labels and field names to
// lowercase before searching.
// shipping name/address fields
const char kEcmlShipToTitle[] = "ecom_shipto_postal_name_prefix";
const char kEcmlShipToFirstName[] = "ecom_shipto_postal_name_first";
const char kEcmlShipToMiddleName[] = "ecom_shipto_postal_name_middle";
const char kEcmlShipToLastName[] = "ecom_shipto_postal_name_last";
const char kEcmlShipToNameSuffix[] = "ecom_shipto_postal_name_suffix";
const char kEcmlShipToCompanyName[] = "ecom_shipto_postal_company";
const char kEcmlShipToAddress1[] = "ecom_shipto_postal_street_line1";
const char kEcmlShipToAddress2[] = "ecom_shipto_postal_street_line2";
const char kEcmlShipToAddress3[] = "ecom_shipto_postal_street_line3";
const char kEcmlShipToCity[] = "ecom_shipto_postal_city";
const char kEcmlShipToStateProv[] = "ecom_shipto_postal_stateprov";
const char kEcmlShipToPostalCode[] = "ecom_shipto_postal_postalcode";
const char kEcmlShipToCountry[] = "ecom_shipto_postal_countrycode";
const char kEcmlShipToPhone[] = "ecom_shipto_telecom_phone_number";
const char kEcmlShipToEmail[] = "ecom_shipto_online_email";
// billing name/address fields
const char kEcmlBillToTitle[] = "ecom_billto_postal_name_prefix";
const char kEcmlBillToFirstName[] = "ecom_billto_postal_name_first";
const char kEcmlBillToMiddleName[] = "ecom_billto_postal_name_middle";
const char kEcmlBillToLastName[] = "ecom_billto_postal_name_last";
const char kEcmlBillToNameSuffix[] = "ecom_billto_postal_name_suffix";
const char kEcmlBillToCompanyName[] = "ecom_billto_postal_company";
const char kEcmlBillToAddress1[] = "ecom_billto_postal_street_line1";
const char kEcmlBillToAddress2[] = "ecom_billto_postal_street_line2";
const char kEcmlBillToAddress3[] = "ecom_billto_postal_street_line3";
const char kEcmlBillToCity[] = "ecom_billto_postal_city";
const char kEcmlBillToStateProv[] = "ecom_billto_postal_stateprov";
const char kEcmlBillToPostalCode[] = "ecom_billto_postal_postalcode";
const char kEcmlBillToCountry[] = "ecom_billto_postal_countrycode";
const char kEcmlBillToPhone[] = "ecom_billto_telecom_phone_number";
const char kEcmlBillToEmail[] = "ecom_billto_online_email";
// credit card fields
const char kEcmlCardHolder[] = "ecom_payment_card_name";
const char kEcmlCardType[] = "ecom_payment_card_type";
const char kEcmlCardNumber[] = "ecom_payment_card_number";
const char kEcmlCardVerification[] = "ecom_payment_card_verification";
const char kEcmlCardExpireDay[] = "ecom_payment_card_expdate_day";
const char kEcmlCardExpireMonth[] = "ecom_payment_card_expdate_month";
const char kEcmlCardExpireYear[] = "ecom_payment_card_expdate_year";
namespace autofill {
bool MatchString(const string16& input, const string16& pattern) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString icu_pattern(pattern.data(), pattern.length());
icu::UnicodeString icu_input(input.data(), input.length());
icu::RegexMatcher matcher(icu_pattern, icu_input,
UREGEX_CASE_INSENSITIVE, status);
DCHECK(U_SUCCESS(status));
UBool match = matcher.find(0, status);
DCHECK(U_SUCCESS(status));
return !!match;
}
} // namespace autofill
class EmailField : public FormField {
public:
virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const {
bool ok = Add(field_type_map, field_, AutofillType(EMAIL_ADDRESS));
DCHECK(ok);
return true;
}
static EmailField* Parse(std::vector<AutofillField*>::const_iterator* iter,
bool is_ecml) {
string16 pattern;
if (is_ecml) {
pattern = GetEcmlPattern(kEcmlShipToEmail, kEcmlBillToEmail, '|');
} else {
pattern = l10n_util::GetStringUTF16(IDS_AUTOFILL_EMAIL_RE);
}
AutofillField* field;
if (ParseText(iter, pattern, &field))
return new EmailField(field);
return NULL;
}
private:
explicit EmailField(AutofillField *field) : field_(field) {}
AutofillField* field_;
};
FormFieldType FormField::GetFormFieldType() const {
return kOtherFieldType;
}
// static
bool FormField::Match(AutofillField* field,
const string16& pattern,
bool match_label_only) {
if (match_label_only) {
if (autofill::MatchString(field->label, pattern)) {
return true;
}
} else {
// For now, we apply the same pattern to the field's label and the field's
// name. Matching the name is a bit of a long shot for many patterns, but
// it generally doesn't hurt to try.
if (autofill::MatchString(field->label, pattern) ||
autofill::MatchString(field->name, pattern)) {
return true;
}
}
return false;
}
// static
FormField* FormField::ParseFormField(
std::vector<AutofillField*>::const_iterator* iter,
bool is_ecml) {
FormField *field;
field = EmailField::Parse(iter, is_ecml);
if (field != NULL)
return field;
// Parses both phone and fax.
field = PhoneField::Parse(iter, is_ecml);
if (field != NULL)
return field;
field = AddressField::Parse(iter, is_ecml);
if (field != NULL)
return field;
field = CreditCardField::Parse(iter, is_ecml);
if (field != NULL)
return field;
// We search for a NameField last since it matches the word "name", which is
// relatively general.
return NameField::Parse(iter, is_ecml);
}
// static
bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
const string16& pattern) {
AutofillField* field;
return ParseText(iter, pattern, &field);
}
// static
bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
const string16& pattern,
AutofillField** dest) {
return ParseText(iter, pattern, dest, false);
}
// static
bool FormField::ParseEmptyText(
std::vector<AutofillField*>::const_iterator* iter,
AutofillField** dest) {
return ParseLabelText(iter, ASCIIToUTF16("^$"), dest);
}
// static
bool FormField::ParseLabelText(
std::vector<AutofillField*>::const_iterator* iter,
const string16& pattern,
AutofillField** dest) {
return ParseText(iter, pattern, dest, true);
}
// static
bool FormField::ParseText(std::vector<AutofillField*>::const_iterator* iter,
const string16& pattern,
AutofillField** dest,
bool match_label_only) {
AutofillField* field = **iter;
if (!field)
return false;
if (Match(field, pattern, match_label_only)) {
if (dest)
*dest = field;
(*iter)++;
return true;
}
return false;
}
// static
bool FormField::ParseLabelAndName(
std::vector<AutofillField*>::const_iterator* iter,
const string16& pattern,
AutofillField** dest) {
AutofillField* field = **iter;
if (!field)
return false;
if (autofill::MatchString(field->label, pattern) &&
autofill::MatchString(field->name, pattern)) {
if (dest)
*dest = field;
(*iter)++;
return true;
}
return false;
}
// static
bool FormField::ParseEmpty(std::vector<AutofillField*>::const_iterator* iter) {
// TODO(jhawkins): Handle select fields.
return ParseLabelAndName(iter, ASCIIToUTF16("^$"), NULL);
}
// static
bool FormField::Add(FieldTypeMap* field_type_map, AutofillField* field,
const AutofillType& type) {
// Several fields are optional.
if (field)
field_type_map->insert(make_pair(field->unique_name(), type.field_type()));
return true;
}
string16 FormField::GetEcmlPattern(const char* ecml_name) {
return ASCIIToUTF16(std::string("^") + ecml_name);
}
string16 FormField::GetEcmlPattern(const char* ecml_name1,
const char* ecml_name2,
char pattern_operator) {
return ASCIIToUTF16(StringPrintf("^%s%c^%s",
ecml_name1, pattern_operator, ecml_name2));
}
FormFieldSet::FormFieldSet(FormStructure* fields) {
std::vector<AddressField*> addresses;
// First, find if there is one form field with an ECML name. If there is,
// then we will match an element only if it is in the standard.
bool is_ecml = CheckECML(fields);
// Parse fields.
std::vector<AutofillField*>::const_iterator field = fields->begin();
while (field != fields->end() && *field != NULL) {
FormField* form_field = FormField::ParseFormField(&field, is_ecml);
if (!form_field) {
field++;
continue;
}
push_back(form_field);
if (form_field->GetFormFieldType() == kAddressType) {
AddressField* address = static_cast<AddressField*>(form_field);
if (address->IsFullAddress())
addresses.push_back(address);
}
}
// Now determine an address type for each address. Note, if this is an ECML
// form, then we already got this info from the field names.
if (!is_ecml && !addresses.empty()) {
if (addresses.size() == 1) {
addresses[0]->SetType(addresses[0]->FindType());
} else {
AddressType type0 = addresses[0]->FindType();
AddressType type1 = addresses[1]->FindType();
// When there are two addresses on a page, they almost always appear in
// the order (billing, shipping).
bool reversed = (type0 == kShippingAddress && type1 == kBillingAddress);
addresses[0]->SetType(reversed ? kShippingAddress : kBillingAddress);
addresses[1]->SetType(reversed ? kBillingAddress : kShippingAddress);
}
}
}
bool FormFieldSet::CheckECML(FormStructure* fields) {
size_t num_fields = fields->field_count();
struct EcmlField {
const char* name_;
const int length_;
} form_fields[] = {
#define ECML_STRING_ENTRY(x) { x, arraysize(x) - 1 },
ECML_STRING_ENTRY(kEcmlShipToTitle)
ECML_STRING_ENTRY(kEcmlShipToFirstName)
ECML_STRING_ENTRY(kEcmlShipToMiddleName)
ECML_STRING_ENTRY(kEcmlShipToLastName)
ECML_STRING_ENTRY(kEcmlShipToNameSuffix)
ECML_STRING_ENTRY(kEcmlShipToCompanyName)
ECML_STRING_ENTRY(kEcmlShipToAddress1)
ECML_STRING_ENTRY(kEcmlShipToAddress2)
ECML_STRING_ENTRY(kEcmlShipToAddress3)
ECML_STRING_ENTRY(kEcmlShipToCity)
ECML_STRING_ENTRY(kEcmlShipToStateProv)
ECML_STRING_ENTRY(kEcmlShipToPostalCode)
ECML_STRING_ENTRY(kEcmlShipToCountry)
ECML_STRING_ENTRY(kEcmlShipToPhone)
ECML_STRING_ENTRY(kEcmlShipToPhone)
ECML_STRING_ENTRY(kEcmlShipToEmail)
ECML_STRING_ENTRY(kEcmlBillToTitle)
ECML_STRING_ENTRY(kEcmlBillToFirstName)
ECML_STRING_ENTRY(kEcmlBillToMiddleName)
ECML_STRING_ENTRY(kEcmlBillToLastName)
ECML_STRING_ENTRY(kEcmlBillToNameSuffix)
ECML_STRING_ENTRY(kEcmlBillToCompanyName)
ECML_STRING_ENTRY(kEcmlBillToAddress1)
ECML_STRING_ENTRY(kEcmlBillToAddress2)
ECML_STRING_ENTRY(kEcmlBillToAddress3)
ECML_STRING_ENTRY(kEcmlBillToCity)
ECML_STRING_ENTRY(kEcmlBillToStateProv)
ECML_STRING_ENTRY(kEcmlBillToPostalCode)
ECML_STRING_ENTRY(kEcmlBillToCountry)
ECML_STRING_ENTRY(kEcmlBillToPhone)
ECML_STRING_ENTRY(kEcmlBillToPhone)
ECML_STRING_ENTRY(kEcmlBillToEmail)
ECML_STRING_ENTRY(kEcmlCardHolder)
ECML_STRING_ENTRY(kEcmlCardType)
ECML_STRING_ENTRY(kEcmlCardNumber)
ECML_STRING_ENTRY(kEcmlCardVerification)
ECML_STRING_ENTRY(kEcmlCardExpireMonth)
ECML_STRING_ENTRY(kEcmlCardExpireYear)
#undef ECML_STRING_ENTRY
};
const string16 ecom(ASCIIToUTF16("ecom"));
for (size_t index = 0; index < num_fields; ++index) {
const string16& utf16_name = fields->field(index)->name;
if (StartsWith(utf16_name, ecom, true)) {
std::string name(UTF16ToASCII(utf16_name));
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(form_fields); ++i) {
if (base::strncasecmp(name.c_str(), form_fields[i].name_,
form_fields[i].length_) == 0) {
return true;
}
}
}
}
return false;
}