// Copyright (c) 2010 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/personal_data_manager.h" #include #include #include "base/logging.h" #include "base/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_manager.h" #include "chrome/browser/autofill/autofill_field.h" #include "chrome/browser/autofill/form_structure.h" #include "chrome/browser/autofill/phone_number.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/profile.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/browser/pref_service.h" #include "chrome/common/pref_names.h" namespace { // The minimum number of fields that must contain user data and have known types // before autofill will attempt to import the data into a profile. const int kMinImportSize = 5; const char kUnlabeled[] = "Unlabeled"; } // namespace PersonalDataManager::~PersonalDataManager() { CancelPendingQuery(&pending_profiles_query_); CancelPendingQuery(&pending_creditcards_query_); } void PersonalDataManager::OnWebDataServiceRequestDone( WebDataService::Handle h, const WDTypedResult* result) { // Error from the web database. if (!result) return; DCHECK(pending_profiles_query_ || pending_creditcards_query_); DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT || result->GetType() == AUTOFILL_CREDITCARDS_RESULT); switch (result->GetType()) { case AUTOFILL_PROFILES_RESULT: ReceiveLoadedProfiles(h, result); break; case AUTOFILL_CREDITCARDS_RESULT: ReceiveLoadedCreditCards(h, result); break; default: NOTREACHED(); } // If both requests have responded, then all personal data is loaded. if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0) { is_data_loaded_ = true; // Copy is needed as observer can unsubscribe itself when notified. std::vector temporary_copy; temporary_copy.resize(observers_.size()); std::copy(observers_.begin(), observers_.end(), temporary_copy.begin()); for (std::vector::iterator iter = temporary_copy.begin(); iter != temporary_copy.end(); ++iter) { (*iter)->OnPersonalDataLoaded(); } } } ///////////////////////////////////////////////////////////////////////////// // PersonalDataManager, // views::ButtonListener implementations void PersonalDataManager::OnAutoFillDialogApply( std::vector* profiles, std::vector* credit_cards) { // |profiles| may be NULL // |credit_cards| may be NULL if (profiles) { CancelPendingQuery(&pending_profiles_query_); SetProfiles(profiles); } if (credit_cards) { CancelPendingQuery(&pending_creditcards_query_); SetCreditCards(credit_cards); } } void PersonalDataManager::SetObserver(PersonalDataManager::Observer* observer) { for (std::vector::iterator iter = observers_.begin(); iter != observers_.end(); ++iter) { if (*iter == observer) { // Already have this observer. return; } } observers_.push_back(observer); } void PersonalDataManager::RemoveObserver( PersonalDataManager::Observer* observer) { for (std::vector::iterator iter = observers_.begin(); iter != observers_.end(); ++iter) { if (*iter == observer) { observers_.erase(iter); return; } } } bool PersonalDataManager::ImportFormData( const std::vector& form_structures, AutoFillManager* autofill_manager) { InitializeIfNeeded(); AutoLock lock(unique_ids_lock_); // Parse the form and construct a profile based on the information that is // possible to import. int importable_fields = 0; int importable_credit_card_fields = 0; imported_profile_.reset(new AutoFillProfile(string16(), 0)); // TODO(jhawkins): Use a hash of the CC# instead of a list of unique IDs? imported_credit_card_.reset(new CreditCard(string16(), 0)); bool billing_address_info = false; std::vector::const_iterator iter; for (iter = form_structures.begin(); iter != form_structures.end(); ++iter) { const FormStructure* form = *iter; for (size_t i = 0; i < form->field_count(); ++i) { const AutoFillField* field = form->field(i); string16 value = CollapseWhitespace(field->value(), false); // If we don't know the type of the field, or the user hasn't entered any // information into the field, then skip it. if (!field->IsFieldFillable() || value.empty()) continue; AutoFillType field_type(field->type()); FieldTypeGroup group(field_type.group()); if (group == AutoFillType::CREDIT_CARD) { // If the user has a password set, we have no way of setting credit // card numbers. if (!HasPassword()) { imported_credit_card_->SetInfo(AutoFillType(field_type.field_type()), value); ++importable_credit_card_fields; } } else { // In the case of a phone number, if the whole phone number was entered // into a single field, then parse it and set the sub components. if (field_type.subgroup() == AutoFillType::PHONE_WHOLE_NUMBER) { string16 number; string16 city_code; string16 country_code; if (group == AutoFillType::PHONE_HOME) { PhoneNumber::ParsePhoneNumber( value, &number, &city_code, &country_code); imported_profile_->SetInfo( AutoFillType(PHONE_HOME_COUNTRY_CODE), country_code); imported_profile_->SetInfo( AutoFillType(PHONE_HOME_CITY_CODE), city_code); imported_profile_->SetInfo( AutoFillType(PHONE_HOME_NUMBER), number); } else if (group == AutoFillType::PHONE_FAX) { PhoneNumber::ParsePhoneNumber( value, &number, &city_code, &country_code); imported_profile_->SetInfo( AutoFillType(PHONE_FAX_COUNTRY_CODE), country_code); imported_profile_->SetInfo( AutoFillType(PHONE_FAX_CITY_CODE), city_code); imported_profile_->SetInfo( AutoFillType(PHONE_FAX_NUMBER), number); } continue; } imported_profile_->SetInfo(AutoFillType(field_type.field_type()), value); // If we found any billing address information, then set the profile to // use a separate billing address. if (group == AutoFillType::ADDRESS_BILLING) billing_address_info = true; ++importable_fields; } } } // If the user did not enter enough information on the page then don't bother // importing the data. if (importable_fields + importable_credit_card_fields < kMinImportSize) return false; if (importable_fields == 0) imported_profile_.reset(); if (importable_credit_card_fields == 0) imported_credit_card_.reset(); return true; } void PersonalDataManager::SaveImportedFormData() { if (profile_->IsOffTheRecord()) return; if (imported_profile_.get()) { imported_profile_->set_label(ASCIIToUTF16(kUnlabeled)); std::vector profiles; profiles.push_back(*imported_profile_); SetProfiles(&profiles); } if (imported_credit_card_.get()) { imported_credit_card_->set_label(ASCIIToUTF16(kUnlabeled)); std::vector credit_cards; credit_cards.push_back(*imported_credit_card_); SetCreditCards(&credit_cards); } } void PersonalDataManager::GetImportedFormData(AutoFillProfile** profile, CreditCard** credit_card) { DCHECK(profile); DCHECK(credit_card); if (imported_profile_.get()) { imported_profile_->set_label(ASCIIToUTF16(kUnlabeled)); } *profile = imported_profile_.get(); if (imported_credit_card_.get()) { imported_credit_card_->set_label(ASCIIToUTF16(kUnlabeled)); } *credit_card = imported_credit_card_.get(); } void PersonalDataManager::SetProfiles(std::vector* profiles) { if (profile_->IsOffTheRecord()) return; SetUniqueProfileLabels(profiles); WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!wds) return; AutoLock lock(unique_ids_lock_); // Remove the unique IDs of the new set of profiles from the unique ID set. for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (iter->unique_id() != 0) unique_profile_ids_.erase(iter->unique_id()); } // Any remaining IDs are not in the new profile list and should be removed // from the web database. for (std::set::iterator iter = unique_profile_ids_.begin(); iter != unique_profile_ids_.end(); ++iter) { wds->RemoveAutoFillProfile(*iter); } // Clear the unique IDs. The set of unique IDs is updated for each profile // added to |web_profiles_| below. unique_profile_ids_.clear(); // Update the web database with the existing profiles. We need to handle // these first so that |unique_profile_ids_| is reset with the IDs of the // existing profiles; otherwise, new profiles added before older profiles can // take their unique ID. for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (iter->unique_id() != 0) { unique_profile_ids_.insert(iter->unique_id()); wds->UpdateAutoFillProfile(*iter); } } // Add the new profiles to the web database. for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { // The profile was added by the AutoFill dialog, so we need to set the // unique ID. This also means we need to add this profile to the web // database. if (iter->unique_id() == 0) { iter->set_unique_id(CreateNextUniqueID(&unique_profile_ids_)); wds->AddAutoFillProfile(*iter); } } web_profiles_.reset(); for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { web_profiles_.push_back(new AutoFillProfile(*iter)); } // Read our writes to ensure consistency with the database. Refresh(); } void PersonalDataManager::SetCreditCards( std::vector* credit_cards) { if (profile_->IsOffTheRecord()) return; SetUniqueCreditCardLabels(credit_cards); WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!wds) return; AutoLock lock(unique_ids_lock_); // Remove the unique IDs of the new set of credit cards from the unique ID // set. for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { if (iter->unique_id() != 0) unique_creditcard_ids_.erase(iter->unique_id()); } // Any remaining IDs are not in the new credit card list and should be removed // from the web database. for (std::set::iterator iter = unique_creditcard_ids_.begin(); iter != unique_creditcard_ids_.end(); ++iter) { wds->RemoveCreditCard(*iter); } // Clear the unique IDs. The set of unique IDs is updated for each credit // card added to |credit_cards_| below. unique_creditcard_ids_.clear(); // Update the web database with the existing credit cards. We need to handle // these first so that |unique_creditcard_ids_| is reset with the IDs of the // existing credit cards; otherwise, new credit cards added before older // credit cards can take their unique ID. for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { if (iter->unique_id() != 0) { unique_creditcard_ids_.insert(iter->unique_id()); wds->UpdateCreditCard(*iter); } } // Add the new credit cards to the web database. for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { // The credit card was added by the AutoFill dialog, so we need to set the // unique ID. This also means we need to add this credit card to the web // database. if (iter->unique_id() == 0) { iter->set_unique_id(CreateNextUniqueID(&unique_creditcard_ids_)); wds->AddCreditCard(*iter); } } credit_cards_.reset(); for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { credit_cards_.push_back(new CreditCard(*iter)); } } void PersonalDataManager::GetPossibleFieldTypes(const string16& text, FieldTypeSet* possible_types) { InitializeIfNeeded(); string16 clean_info = StringToLowerASCII(CollapseWhitespace(text, false)); if (clean_info.empty()) { possible_types->insert(EMPTY_TYPE); return; } for (ScopedVector::iterator iter = web_profiles_.begin(); iter != web_profiles_.end(); ++iter) { const FormGroup* profile = *iter; if (!profile) { DLOG(ERROR) << "NULL information in profiles list"; continue; } profile->GetPossibleFieldTypes(clean_info, possible_types); } for (ScopedVector::iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { const FormGroup* credit_card = *iter; if (!credit_card) { DLOG(ERROR) << "NULL information in credit cards list"; continue; } credit_card->GetPossibleFieldTypes(clean_info, possible_types); } if (possible_types->size() == 0) possible_types->insert(UNKNOWN_TYPE); } bool PersonalDataManager::HasPassword() { InitializeIfNeeded(); return !password_hash_.empty(); } const std::vector& PersonalDataManager::profiles() { // |profile_| is NULL in AutoFillManagerTest. if (!profile_) return web_profiles_.get(); bool auxiliary_profiles_enabled = profile_->GetPrefs()->GetBoolean( prefs::kAutoFillAuxiliaryProfilesEnabled); if (auxiliary_profiles_enabled) { profiles_.clear(); // Populates |auxiliary_profiles_|. LoadAuxiliaryProfiles(); profiles_.insert(profiles_.end(), web_profiles_.begin(), web_profiles_.end()); profiles_.insert(profiles_.end(), auxiliary_profiles_.begin(), auxiliary_profiles_.end()); return profiles_; } else { return web_profiles_.get(); } } const std::vector& PersonalDataManager::web_profiles() { return web_profiles_.get(); } int PersonalDataManager::DefaultProfile() const { if (web_profiles_.empty()) return -1; // If no default is explicitly set we default to first element. string16 default_label = WideToUTF16Hack(profile_->GetPrefs()->GetString( prefs::kAutoFillDefaultProfile)); if (default_label.empty()) return 0; std::vector::const_iterator iter; size_t i = 0; for (iter = web_profiles_->begin(); iter != web_profiles_->end(); ++iter, ++i) { if (default_label == (*iter)->Label()) break; } DCHECK(i < web_profiles_->size()); if (i < web_profiles_->size()) return i; else return 0; } int PersonalDataManager::DefaultCreditCard() const { if (credit_cards_.empty()) return -1; // If no default is explicitly set we default to first element. string16 default_label = WideToUTF16Hack(profile_->GetPrefs()->GetString( prefs::kAutoFillDefaultCreditCard)); if (default_label.empty()) return 0; std::vector::const_iterator iter; size_t i = 0; for (iter = credit_cards_->begin(); iter != credit_cards_->end(); ++iter, ++i) { if (default_label == (*iter)->Label()) break; } DCHECK(i < credit_cards_->size()); if (i < credit_cards_->size()) return i; else return 0; } AutoFillProfile* PersonalDataManager::CreateNewEmptyAutoFillProfileForDBThread( const string16& label) { // See comment in header for thread details. DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); AutoLock lock(unique_ids_lock_); AutoFillProfile* p = new AutoFillProfile(label, CreateNextUniqueID(&unique_profile_ids_)); return p; } void PersonalDataManager::Refresh() { LoadProfiles(); LoadCreditCards(); } PersonalDataManager::PersonalDataManager() : profile_(NULL), is_initialized_(false), is_data_loaded_(false), pending_profiles_query_(0), pending_creditcards_query_(0) { } void PersonalDataManager::Init(Profile* profile) { profile_ = profile; LoadProfiles(); LoadCreditCards(); } void PersonalDataManager::InitializeIfNeeded() { if (is_initialized_) return; is_initialized_ = true; // TODO(jhawkins): Load data. } int PersonalDataManager::CreateNextUniqueID(std::set* unique_ids) { // Profile IDs MUST start at 1 to allow 0 as an error value when reading // the ID from the WebDB (see LoadData()). unique_ids_lock_.AssertAcquired(); int id = 1; while (unique_ids->count(id) != 0) ++id; unique_ids->insert(id); return id; } void PersonalDataManager::LoadProfiles() { WebDataService* web_data_service = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!web_data_service) { NOTREACHED(); return; } CancelPendingQuery(&pending_profiles_query_); pending_profiles_query_ = web_data_service->GetAutoFillProfiles(this); } // Win and Linux implementations do nothing. Mac implementation fills in the // contents of |auxiliary_profiles_|. #if !defined(OS_MACOSX) void PersonalDataManager::LoadAuxiliaryProfiles() { } #endif void PersonalDataManager::LoadCreditCards() { WebDataService* web_data_service = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!web_data_service) { NOTREACHED(); return; } CancelPendingQuery(&pending_creditcards_query_); pending_creditcards_query_ = web_data_service->GetCreditCards(this); } void PersonalDataManager::ReceiveLoadedProfiles(WebDataService::Handle h, const WDTypedResult* result) { DCHECK_EQ(pending_profiles_query_, h); pending_profiles_query_ = 0; AutoLock lock(unique_ids_lock_); unique_profile_ids_.clear(); web_profiles_.reset(); const WDResult >* r = static_cast >*>(result); std::vector profiles = r->GetValue(); for (std::vector::iterator iter = profiles.begin(); iter != profiles.end(); ++iter) { unique_profile_ids_.insert((*iter)->unique_id()); web_profiles_.push_back(*iter); } } void PersonalDataManager::ReceiveLoadedCreditCards( WebDataService::Handle h, const WDTypedResult* result) { DCHECK_EQ(pending_creditcards_query_, h); pending_creditcards_query_ = 0; AutoLock lock(unique_ids_lock_); unique_creditcard_ids_.clear(); credit_cards_.reset(); const WDResult >* r = static_cast >*>(result); std::vector credit_cards = r->GetValue(); for (std::vector::iterator iter = credit_cards.begin(); iter != credit_cards.end(); ++iter) { unique_creditcard_ids_.insert((*iter)->unique_id()); credit_cards_.push_back(*iter); } } void PersonalDataManager::CancelPendingQuery(WebDataService::Handle* handle) { if (*handle) { WebDataService* web_data_service = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); if (!web_data_service) { NOTREACHED(); return; } web_data_service->CancelRequest(*handle); } *handle = 0; } void PersonalDataManager::SetUniqueProfileLabels( std::vector* profiles) { std::map > label_map; for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { label_map[iter->Label()].push_back(&(*iter)); } for (std::map >::iterator iter = label_map.begin(); iter != label_map.end(); ++iter) { // Start at the second element because the first label should not be // renamed. The appended label number starts at 2, because the first label // has an implicit index of 1. for (size_t i = 1; i < iter->second.size(); ++i) { string16 newlabel = iter->second[i]->Label() + UintToString16(static_cast(i + 1)); iter->second[i]->set_label(newlabel); } } } void PersonalDataManager::SetUniqueCreditCardLabels( std::vector* credit_cards) { std::map > label_map; for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { label_map[iter->Label()].push_back(&(*iter)); } for (std::map >::iterator iter = label_map.begin(); iter != label_map.end(); ++iter) { // Start at the second element because the first label should not be // renamed. The appended label number starts at 2, because the first label // has an implicit index of 1. for (size_t i = 1; i < iter->second.size(); ++i) { string16 newlabel = iter->second[i]->Label() + UintToString16(static_cast(i + 1)); iter->second[i]->set_label(newlabel); } } }