Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

form_field.cc

// Copyright (c) 2009 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 "base/string_util.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/fax_field.h"
#include "chrome/browser/autofill/name_field.h"
#include "chrome/browser/autofill/phone_field.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRegularExpression.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.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 {

// The name of the hidden form control element.
const char* const kControlTypeHidden = "hidden";

}  // namespace

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 = ASCIIToUTF16("email|e-mail");
    }

    AutoFillField* field;
    if (ParseText(iter, pattern, &field))
      return new EmailField(field);

    return NULL;
  }

 private:
  explicit EmailField(AutoFillField *field) : field_(field) {}

  AutoFillField* field_;
};

// static
bool FormField::Match(AutoFillField* field,
                      const string16& pattern,
                      bool match_label_only) {
  if (match_label_only) {
    if (MatchLabel(field, 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 (MatchLabel(field, pattern) || MatchName(field, pattern)) {
      return true;
    }
  }

  return false;
}

// static
bool FormField::MatchName(AutoFillField* field, const string16& pattern) {
  // TODO(jhawkins): Remove StringToLowerASCII.  WebRegularExpression needs to
  // be fixed to take WebTextCaseInsensitive into account.
  WebKit::WebRegularExpression re(WebKit::WebString(pattern),
                                  WebKit::WebTextCaseInsensitive);
  bool match = re.match(
      WebKit::WebString(StringToLowerASCII(field->name()))) != -1;
  return match;
}

// static
bool FormField::MatchLabel(AutoFillField* field, const string16& pattern) {
  // TODO(jhawkins): Remove StringToLowerASCII.  WebRegularExpression needs to
  // be fixed to take WebTextCaseInsensitive into account.
  WebKit::WebRegularExpression re(WebKit::WebString(pattern),
                                  WebKit::WebTextCaseInsensitive);
  bool match = re.match(
      WebKit::WebString(StringToLowerASCII(field->label()))) != -1;
  return match;
}

// 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;
  field = PhoneField::Parse(iter, is_ecml);
  if (field != NULL)
    return field;
  field = FaxField::Parse(iter);
  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 ParseLabelAndName(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 (MatchLabel(field, pattern) && MatchName(field, 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) {
    // Don't parse hidden fields.
    if (LowerCaseEqualsASCII((*field)->form_control_type(),
                             kControlTypeHidden)) {
      field++;
      continue;
    }

    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;
}

Generated by  Doxygen 1.6.0   Back to index