| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/browser/autofill/personal_data_manager.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <functional> | |
| 9 #include <iterator> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/prefs/pref_service.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "chrome/browser/api/webdata/autofill_web_data_service.h" | |
| 16 #include "chrome/browser/autofill/autofill-inl.h" | |
| 17 #include "chrome/browser/autofill/autofill_country.h" | |
| 18 #include "chrome/browser/autofill/autofill_field.h" | |
| 19 #include "chrome/browser/autofill/autofill_metrics.h" | |
| 20 #include "chrome/browser/autofill/form_group.h" | |
| 21 #include "chrome/browser/autofill/form_structure.h" | |
| 22 #include "chrome/browser/autofill/personal_data_manager_observer.h" | |
| 23 #include "chrome/browser/autofill/phone_number.h" | |
| 24 #include "chrome/browser/autofill/phone_number_i18n.h" | |
| 25 #include "chrome/browser/autofill/validation.h" | |
| 26 #include "chrome/common/chrome_notification_types.h" | |
| 27 #include "components/autofill/common/autofill_pref_names.h" | |
| 28 #include "components/user_prefs/user_prefs.h" | |
| 29 #include "content/public/browser/browser_context.h" | |
| 30 #include "content/public/browser/notification_source.h" | |
| 31 | |
| 32 using content::BrowserContext; | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 const string16::value_type kCreditCardPrefix[] = {'*', 0}; | |
| 37 | |
| 38 template<typename T> | |
| 39 class FormGroupMatchesByGUIDFunctor { | |
| 40 public: | |
| 41 explicit FormGroupMatchesByGUIDFunctor(const std::string& guid) | |
| 42 : guid_(guid) { | |
| 43 } | |
| 44 | |
| 45 bool operator()(const T& form_group) { | |
| 46 return form_group.guid() == guid_; | |
| 47 } | |
| 48 | |
| 49 bool operator()(const T* form_group) { | |
| 50 return form_group->guid() == guid_; | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 std::string guid_; | |
| 55 }; | |
| 56 | |
| 57 template<typename T, typename C> | |
| 58 bool FindByGUID(const C& container, const std::string& guid) { | |
| 59 return std::find_if( | |
| 60 container.begin(), | |
| 61 container.end(), | |
| 62 FormGroupMatchesByGUIDFunctor<T>(guid)) != container.end(); | |
| 63 } | |
| 64 | |
| 65 template<typename T> | |
| 66 class DereferenceFunctor { | |
| 67 public: | |
| 68 template<typename T_Iterator> | |
| 69 const T& operator()(const T_Iterator& iterator) { | |
| 70 return *iterator; | |
| 71 } | |
| 72 }; | |
| 73 | |
| 74 template<typename T> | |
| 75 T* address_of(T& v) { | |
| 76 return &v; | |
| 77 } | |
| 78 | |
| 79 // Returns true if minimum requirements for import of a given |profile| have | |
| 80 // been met. An address submitted via a form must have at least these fields | |
| 81 // filled. No verification of validity of the contents is preformed. This is | |
| 82 // and existence check only. | |
| 83 bool IsMinimumAddress(const AutofillProfile& profile) { | |
| 84 return !profile.GetRawInfo(ADDRESS_HOME_LINE1).empty() && | |
| 85 !profile.GetRawInfo(ADDRESS_HOME_CITY).empty() && | |
| 86 !profile.GetRawInfo(ADDRESS_HOME_STATE).empty() && | |
| 87 !profile.GetRawInfo(ADDRESS_HOME_ZIP).empty(); | |
| 88 } | |
| 89 | |
| 90 // Return true if the |field_type| and |value| are valid within the context | |
| 91 // of importing a form. | |
| 92 bool IsValidFieldTypeAndValue(const std::set<AutofillFieldType>& types_seen, | |
| 93 AutofillFieldType field_type, | |
| 94 const string16& value) { | |
| 95 // Abandon the import if two fields of the same type are encountered. | |
| 96 // This indicates ambiguous data or miscategorization of types. | |
| 97 // Make an exception for PHONE_HOME_NUMBER however as both prefix and | |
| 98 // suffix are stored against this type. | |
| 99 if (types_seen.count(field_type) && field_type != PHONE_HOME_NUMBER) | |
| 100 return false; | |
| 101 | |
| 102 // Abandon the import if an email address value shows up in a field that is | |
| 103 // not an email address. | |
| 104 if (field_type != EMAIL_ADDRESS && autofill::IsValidEmailAddress(value)) | |
| 105 return false; | |
| 106 | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 } // namespace | |
| 111 | |
| 112 PersonalDataManager::PersonalDataManager() | |
| 113 : browser_context_(NULL), | |
| 114 is_data_loaded_(false), | |
| 115 pending_profiles_query_(0), | |
| 116 pending_creditcards_query_(0), | |
| 117 metric_logger_(new AutofillMetrics), | |
| 118 has_logged_profile_count_(false) {} | |
| 119 | |
| 120 void PersonalDataManager::Init(BrowserContext* browser_context) { | |
| 121 browser_context_ = browser_context; | |
| 122 metric_logger_->LogIsAutofillEnabledAtStartup(IsAutofillEnabled()); | |
| 123 | |
| 124 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 125 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 126 | |
| 127 // WebDataService may not be available in tests. | |
| 128 if (!autofill_data.get()) | |
| 129 return; | |
| 130 | |
| 131 LoadProfiles(); | |
| 132 LoadCreditCards(); | |
| 133 | |
| 134 notification_registrar_.Add( | |
| 135 this, | |
| 136 chrome::NOTIFICATION_AUTOFILL_MULTIPLE_CHANGED, | |
| 137 autofill_data->GetNotificationSource()); | |
| 138 } | |
| 139 | |
| 140 PersonalDataManager::~PersonalDataManager() { | |
| 141 CancelPendingQuery(&pending_profiles_query_); | |
| 142 CancelPendingQuery(&pending_creditcards_query_); | |
| 143 } | |
| 144 | |
| 145 void PersonalDataManager::OnWebDataServiceRequestDone( | |
| 146 WebDataServiceBase::Handle h, | |
| 147 const WDTypedResult* result) { | |
| 148 DCHECK(pending_profiles_query_ || pending_creditcards_query_); | |
| 149 | |
| 150 if (!result) { | |
| 151 // Error from the web database. | |
| 152 if (h == pending_creditcards_query_) | |
| 153 pending_creditcards_query_ = 0; | |
| 154 else if (h == pending_profiles_query_) | |
| 155 pending_profiles_query_ = 0; | |
| 156 return; | |
| 157 } | |
| 158 | |
| 159 DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT || | |
| 160 result->GetType() == AUTOFILL_CREDITCARDS_RESULT); | |
| 161 | |
| 162 switch (result->GetType()) { | |
| 163 case AUTOFILL_PROFILES_RESULT: | |
| 164 ReceiveLoadedProfiles(h, result); | |
| 165 break; | |
| 166 case AUTOFILL_CREDITCARDS_RESULT: | |
| 167 ReceiveLoadedCreditCards(h, result); | |
| 168 break; | |
| 169 default: | |
| 170 NOTREACHED(); | |
| 171 } | |
| 172 | |
| 173 // If both requests have responded, then all personal data is loaded. | |
| 174 if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0) { | |
| 175 is_data_loaded_ = true; | |
| 176 std::vector<AutofillProfile*> profile_pointers(web_profiles_.size()); | |
| 177 std::copy(web_profiles_.begin(), web_profiles_.end(), | |
| 178 profile_pointers.begin()); | |
| 179 AutofillProfile::AdjustInferredLabels(&profile_pointers); | |
| 180 FOR_EACH_OBSERVER(PersonalDataManagerObserver, observers_, | |
| 181 OnPersonalDataChanged()); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void PersonalDataManager::AddObserver(PersonalDataManagerObserver* observer) { | |
| 186 observers_.AddObserver(observer); | |
| 187 } | |
| 188 | |
| 189 void PersonalDataManager::RemoveObserver( | |
| 190 PersonalDataManagerObserver* observer) { | |
| 191 observers_.RemoveObserver(observer); | |
| 192 } | |
| 193 | |
| 194 void PersonalDataManager::Observe(int type, | |
| 195 const content::NotificationSource& source, | |
| 196 const content::NotificationDetails& details) { | |
| 197 DCHECK_EQ(type, chrome::NOTIFICATION_AUTOFILL_MULTIPLE_CHANGED); | |
| 198 | |
| 199 if (DCHECK_IS_ON()) { | |
| 200 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 201 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 202 | |
| 203 DCHECK(autofill_data.get() && | |
| 204 autofill_data->GetNotificationSource() == source); | |
| 205 } | |
| 206 | |
| 207 Refresh(); | |
| 208 } | |
| 209 | |
| 210 bool PersonalDataManager::ImportFormData( | |
| 211 const FormStructure& form, | |
| 212 const CreditCard** imported_credit_card) { | |
| 213 scoped_ptr<AutofillProfile> imported_profile(new AutofillProfile); | |
| 214 scoped_ptr<CreditCard> local_imported_credit_card(new CreditCard); | |
| 215 | |
| 216 // Parse the form and construct a profile based on the information that is | |
| 217 // possible to import. | |
| 218 int importable_credit_card_fields = 0; | |
| 219 | |
| 220 // Detect and discard forms with multiple fields of the same type. | |
| 221 std::set<AutofillFieldType> types_seen; | |
| 222 | |
| 223 // We only set complete phone, so aggregate phone parts in these vars and set | |
| 224 // complete at the end. | |
| 225 PhoneNumber::PhoneCombineHelper home; | |
| 226 | |
| 227 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 228 for (size_t i = 0; i < form.field_count(); ++i) { | |
| 229 const AutofillField* field = form.field(i); | |
| 230 string16 value = CollapseWhitespace(field->value, false); | |
| 231 | |
| 232 // If we don't know the type of the field, or the user hasn't entered any | |
| 233 // information into the field, then skip it. | |
| 234 if (!field->IsFieldFillable() || value.empty()) | |
| 235 continue; | |
| 236 | |
| 237 AutofillFieldType field_type = field->type(); | |
| 238 FieldTypeGroup group(AutofillType(field_type).group()); | |
| 239 | |
| 240 // If the |field_type| and |value| don't pass basic validity checks then | |
| 241 // abandon the import. | |
| 242 if (!IsValidFieldTypeAndValue(types_seen, field_type, value)) { | |
| 243 imported_profile.reset(); | |
| 244 local_imported_credit_card.reset(); | |
| 245 break; | |
| 246 } | |
| 247 | |
| 248 types_seen.insert(field_type); | |
| 249 | |
| 250 if (group == AutofillType::CREDIT_CARD) { | |
| 251 if (LowerCaseEqualsASCII(field->form_control_type, "month")) { | |
| 252 DCHECK_EQ(CREDIT_CARD_EXP_MONTH, field_type); | |
| 253 local_imported_credit_card->SetInfoForMonthInputType(value); | |
| 254 } else { | |
| 255 local_imported_credit_card->SetInfo(field_type, value, app_locale); | |
| 256 } | |
| 257 ++importable_credit_card_fields; | |
| 258 } else { | |
| 259 // We need to store phone data in the variables, before building the whole | |
| 260 // number at the end. The rest of the fields are set "as is". | |
| 261 // If the fields are not the phone fields in question home.SetInfo() is | |
| 262 // going to return false. | |
| 263 if (!home.SetInfo(field_type, value)) | |
| 264 imported_profile->SetInfo(field_type, value, app_locale); | |
| 265 | |
| 266 // Reject profiles with invalid country information. | |
| 267 if (field_type == ADDRESS_HOME_COUNTRY && | |
| 268 !value.empty() && imported_profile->CountryCode().empty()) { | |
| 269 imported_profile.reset(); | |
| 270 break; | |
| 271 } | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 // Construct the phone number. Reject the profile if the number is invalid. | |
| 276 if (imported_profile.get() && !home.IsEmpty()) { | |
| 277 string16 constructed_number; | |
| 278 if (!home.ParseNumber(*imported_profile, app_locale, &constructed_number) || | |
| 279 !imported_profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number, | |
| 280 app_locale)) { | |
| 281 imported_profile.reset(); | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 // Reject the profile if minimum address and validation requirements are not | |
| 286 // met. | |
| 287 if (imported_profile.get() && !IsValidLearnableProfile(*imported_profile)) | |
| 288 imported_profile.reset(); | |
| 289 | |
| 290 // Reject the credit card if we did not detect enough filled credit card | |
| 291 // fields or if the credit card number does not seem to be valid. | |
| 292 if (local_imported_credit_card.get() && | |
| 293 !local_imported_credit_card->IsComplete()) { | |
| 294 local_imported_credit_card.reset(); | |
| 295 } | |
| 296 | |
| 297 // Don't import if we already have this info. | |
| 298 // Don't present an infobar if we have already saved this card number. | |
| 299 bool merged_credit_card = false; | |
| 300 if (local_imported_credit_card.get()) { | |
| 301 for (std::vector<CreditCard*>::const_iterator iter = credit_cards_.begin(); | |
| 302 iter != credit_cards_.end(); | |
| 303 ++iter) { | |
| 304 if ((*iter)->UpdateFromImportedCard(*local_imported_credit_card.get(), | |
| 305 app_locale)) { | |
| 306 merged_credit_card = true; | |
| 307 UpdateCreditCard(**iter); | |
| 308 local_imported_credit_card.reset(); | |
| 309 break; | |
| 310 } | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 if (imported_profile.get()) { | |
| 315 // We always save imported profiles. | |
| 316 SaveImportedProfile(*imported_profile); | |
| 317 } | |
| 318 *imported_credit_card = local_imported_credit_card.release(); | |
| 319 | |
| 320 if (imported_profile.get() || *imported_credit_card || merged_credit_card) { | |
| 321 return true; | |
| 322 } else { | |
| 323 FOR_EACH_OBSERVER(PersonalDataManagerObserver, observers_, | |
| 324 OnInsufficientFormData()); | |
| 325 return false; | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 void PersonalDataManager::AddProfile(const AutofillProfile& profile) { | |
| 330 if (browser_context_->IsOffTheRecord()) | |
| 331 return; | |
| 332 | |
| 333 if (profile.IsEmpty()) | |
| 334 return; | |
| 335 | |
| 336 // Don't add an existing profile. | |
| 337 if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid())) | |
| 338 return; | |
| 339 | |
| 340 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 341 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 342 if (!autofill_data.get()) | |
| 343 return; | |
| 344 | |
| 345 // Don't add a duplicate. | |
| 346 if (FindByContents(web_profiles_, profile)) | |
| 347 return; | |
| 348 | |
| 349 // Add the new profile to the web database. | |
| 350 autofill_data->AddAutofillProfile(profile); | |
| 351 | |
| 352 // Refresh our local cache and send notifications to observers. | |
| 353 Refresh(); | |
| 354 } | |
| 355 | |
| 356 void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) { | |
| 357 if (browser_context_->IsOffTheRecord()) | |
| 358 return; | |
| 359 | |
| 360 if (!FindByGUID<AutofillProfile>(web_profiles_, profile.guid())) | |
| 361 return; | |
| 362 | |
| 363 if (profile.IsEmpty()) { | |
| 364 RemoveByGUID(profile.guid()); | |
| 365 return; | |
| 366 } | |
| 367 | |
| 368 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 369 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 370 if (!autofill_data.get()) | |
| 371 return; | |
| 372 | |
| 373 // Make the update. | |
| 374 autofill_data->UpdateAutofillProfile(profile); | |
| 375 | |
| 376 // Refresh our local cache and send notifications to observers. | |
| 377 Refresh(); | |
| 378 } | |
| 379 | |
| 380 AutofillProfile* PersonalDataManager::GetProfileByGUID( | |
| 381 const std::string& guid) { | |
| 382 const std::vector<AutofillProfile*>& profiles = GetProfiles(); | |
| 383 for (std::vector<AutofillProfile*>::const_iterator iter = profiles.begin(); | |
| 384 iter != profiles.end(); ++iter) { | |
| 385 if ((*iter)->guid() == guid) | |
| 386 return *iter; | |
| 387 } | |
| 388 return NULL; | |
| 389 } | |
| 390 | |
| 391 void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) { | |
| 392 if (browser_context_->IsOffTheRecord()) | |
| 393 return; | |
| 394 | |
| 395 if (credit_card.IsEmpty()) | |
| 396 return; | |
| 397 | |
| 398 if (FindByGUID<CreditCard>(credit_cards_, credit_card.guid())) | |
| 399 return; | |
| 400 | |
| 401 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 402 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 403 if (!autofill_data.get()) | |
| 404 return; | |
| 405 | |
| 406 // Don't add a duplicate. | |
| 407 if (FindByContents(credit_cards_, credit_card)) | |
| 408 return; | |
| 409 | |
| 410 // Add the new credit card to the web database. | |
| 411 autofill_data->AddCreditCard(credit_card); | |
| 412 | |
| 413 // Refresh our local cache and send notifications to observers. | |
| 414 Refresh(); | |
| 415 } | |
| 416 | |
| 417 void PersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) { | |
| 418 if (browser_context_->IsOffTheRecord()) | |
| 419 return; | |
| 420 | |
| 421 if (!FindByGUID<CreditCard>(credit_cards_, credit_card.guid())) | |
| 422 return; | |
| 423 | |
| 424 if (credit_card.IsEmpty()) { | |
| 425 RemoveByGUID(credit_card.guid()); | |
| 426 return; | |
| 427 } | |
| 428 | |
| 429 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 430 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 431 if (!autofill_data.get()) | |
| 432 return; | |
| 433 | |
| 434 // Make the update. | |
| 435 autofill_data->UpdateCreditCard(credit_card); | |
| 436 | |
| 437 // Refresh our local cache and send notifications to observers. | |
| 438 Refresh(); | |
| 439 } | |
| 440 | |
| 441 void PersonalDataManager::RemoveByGUID(const std::string& guid) { | |
| 442 if (browser_context_->IsOffTheRecord()) | |
| 443 return; | |
| 444 | |
| 445 bool is_credit_card = FindByGUID<CreditCard>(credit_cards_, guid); | |
| 446 bool is_profile = !is_credit_card && | |
| 447 FindByGUID<AutofillProfile>(web_profiles_, guid); | |
| 448 if (!is_credit_card && !is_profile) | |
| 449 return; | |
| 450 | |
| 451 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 452 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 453 if (!autofill_data.get()) | |
| 454 return; | |
| 455 | |
| 456 if (is_credit_card) | |
| 457 autofill_data->RemoveCreditCard(guid); | |
| 458 else | |
| 459 autofill_data->RemoveAutofillProfile(guid); | |
| 460 | |
| 461 // Refresh our local cache and send notifications to observers. | |
| 462 Refresh(); | |
| 463 } | |
| 464 | |
| 465 CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) { | |
| 466 for (std::vector<CreditCard*>::iterator iter = credit_cards_.begin(); | |
| 467 iter != credit_cards_.end(); ++iter) { | |
| 468 if ((*iter)->guid() == guid) | |
| 469 return *iter; | |
| 470 } | |
| 471 return NULL; | |
| 472 } | |
| 473 | |
| 474 void PersonalDataManager::GetNonEmptyTypes( | |
| 475 FieldTypeSet* non_empty_types) { | |
| 476 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 477 const std::vector<AutofillProfile*>& profiles = GetProfiles(); | |
| 478 for (std::vector<AutofillProfile*>::const_iterator iter = profiles.begin(); | |
| 479 iter != profiles.end(); ++iter) { | |
| 480 (*iter)->GetNonEmptyTypes(app_locale, non_empty_types); | |
| 481 } | |
| 482 | |
| 483 for (ScopedVector<CreditCard>::const_iterator iter = credit_cards_.begin(); | |
| 484 iter != credit_cards_.end(); ++iter) { | |
| 485 (*iter)->GetNonEmptyTypes(app_locale, non_empty_types); | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 bool PersonalDataManager::IsDataLoaded() const { | |
| 490 return is_data_loaded_; | |
| 491 } | |
| 492 | |
| 493 const std::vector<AutofillProfile*>& PersonalDataManager::GetProfiles() { | |
| 494 if (!components::UserPrefs::Get(browser_context_)->GetBoolean( | |
| 495 prefs::kAutofillAuxiliaryProfilesEnabled)) { | |
| 496 return web_profiles(); | |
| 497 } | |
| 498 | |
| 499 profiles_.clear(); | |
| 500 | |
| 501 // Populates |auxiliary_profiles_|. | |
| 502 LoadAuxiliaryProfiles(); | |
| 503 | |
| 504 profiles_.insert(profiles_.end(), web_profiles_.begin(), web_profiles_.end()); | |
| 505 profiles_.insert(profiles_.end(), | |
| 506 auxiliary_profiles_.begin(), auxiliary_profiles_.end()); | |
| 507 return profiles_; | |
| 508 } | |
| 509 | |
| 510 const std::vector<AutofillProfile*>& PersonalDataManager::web_profiles() const { | |
| 511 return web_profiles_.get(); | |
| 512 } | |
| 513 | |
| 514 const std::vector<CreditCard*>& PersonalDataManager::credit_cards() const { | |
| 515 return credit_cards_.get(); | |
| 516 } | |
| 517 | |
| 518 void PersonalDataManager::Refresh() { | |
| 519 LoadProfiles(); | |
| 520 LoadCreditCards(); | |
| 521 } | |
| 522 | |
| 523 void PersonalDataManager::GetProfileSuggestions( | |
| 524 AutofillFieldType type, | |
| 525 const string16& field_contents, | |
| 526 bool field_is_autofilled, | |
| 527 std::vector<AutofillFieldType> other_field_types, | |
| 528 std::vector<string16>* values, | |
| 529 std::vector<string16>* labels, | |
| 530 std::vector<string16>* icons, | |
| 531 std::vector<GUIDPair>* guid_pairs) { | |
| 532 values->clear(); | |
| 533 labels->clear(); | |
| 534 icons->clear(); | |
| 535 guid_pairs->clear(); | |
| 536 | |
| 537 const std::vector<AutofillProfile*>& profiles = GetProfiles(); | |
| 538 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 539 std::vector<AutofillProfile*> matched_profiles; | |
| 540 for (std::vector<AutofillProfile*>::const_iterator iter = profiles.begin(); | |
| 541 iter != profiles.end(); ++iter) { | |
| 542 AutofillProfile* profile = *iter; | |
| 543 | |
| 544 // The value of the stored data for this field type in the |profile|. | |
| 545 std::vector<string16> multi_values; | |
| 546 profile->GetMultiInfo(type, app_locale, &multi_values); | |
| 547 | |
| 548 for (size_t i = 0; i < multi_values.size(); ++i) { | |
| 549 if (!field_is_autofilled) { | |
| 550 // Suggest data that starts with what the user has typed. | |
| 551 if (!multi_values[i].empty() && | |
| 552 StartsWith(multi_values[i], field_contents, false)) { | |
| 553 matched_profiles.push_back(profile); | |
| 554 values->push_back(multi_values[i]); | |
| 555 guid_pairs->push_back(GUIDPair(profile->guid(), i)); | |
| 556 } | |
| 557 } else { | |
| 558 if (multi_values[i].empty()) | |
| 559 continue; | |
| 560 | |
| 561 string16 profile_value_lower_case( | |
| 562 StringToLowerASCII(multi_values[i])); | |
| 563 string16 field_value_lower_case(StringToLowerASCII(field_contents)); | |
| 564 // Phone numbers could be split in US forms, so field value could be | |
| 565 // either prefix or suffix of the phone. | |
| 566 bool matched_phones = false; | |
| 567 if (type == PHONE_HOME_NUMBER && !field_value_lower_case.empty() && | |
| 568 (profile_value_lower_case.find(field_value_lower_case) != | |
| 569 string16::npos)) { | |
| 570 matched_phones = true; | |
| 571 } | |
| 572 | |
| 573 // Suggest variants of the profile that's already been filled in. | |
| 574 if (matched_phones || | |
| 575 profile_value_lower_case == field_value_lower_case) { | |
| 576 for (size_t j = 0; j < multi_values.size(); ++j) { | |
| 577 if (!multi_values[j].empty()) { | |
| 578 values->push_back(multi_values[j]); | |
| 579 guid_pairs->push_back(GUIDPair(profile->guid(), j)); | |
| 580 } | |
| 581 } | |
| 582 | |
| 583 // We've added all the values for this profile so move on to the | |
| 584 // next. | |
| 585 break; | |
| 586 } | |
| 587 } | |
| 588 } | |
| 589 } | |
| 590 | |
| 591 if (!field_is_autofilled) { | |
| 592 AutofillProfile::CreateInferredLabels( | |
| 593 &matched_profiles, &other_field_types, | |
| 594 type, 1, labels); | |
| 595 } else { | |
| 596 // No sub-labels for previously filled fields. | |
| 597 labels->resize(values->size()); | |
| 598 } | |
| 599 | |
| 600 // No icons for profile suggestions. | |
| 601 icons->resize(values->size()); | |
| 602 } | |
| 603 | |
| 604 void PersonalDataManager::GetCreditCardSuggestions( | |
| 605 AutofillFieldType type, | |
| 606 const string16& field_contents, | |
| 607 std::vector<string16>* values, | |
| 608 std::vector<string16>* labels, | |
| 609 std::vector<string16>* icons, | |
| 610 std::vector<GUIDPair>* guid_pairs) { | |
| 611 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 612 for (std::vector<CreditCard*>::const_iterator iter = credit_cards().begin(); | |
| 613 iter != credit_cards().end(); ++iter) { | |
| 614 CreditCard* credit_card = *iter; | |
| 615 | |
| 616 // The value of the stored data for this field type in the |credit_card|. | |
| 617 string16 creditcard_field_value = credit_card->GetInfo(type, app_locale); | |
| 618 if (!creditcard_field_value.empty() && | |
| 619 StartsWith(creditcard_field_value, field_contents, false)) { | |
| 620 if (type == CREDIT_CARD_NUMBER) | |
| 621 creditcard_field_value = credit_card->ObfuscatedNumber(); | |
| 622 | |
| 623 string16 label; | |
| 624 if (credit_card->number().empty()) { | |
| 625 // If there is no CC number, return name to show something. | |
| 626 label = credit_card->GetInfo(CREDIT_CARD_NAME, app_locale); | |
| 627 } else { | |
| 628 label = kCreditCardPrefix; | |
| 629 label.append(credit_card->LastFourDigits()); | |
| 630 } | |
| 631 | |
| 632 values->push_back(creditcard_field_value); | |
| 633 labels->push_back(label); | |
| 634 icons->push_back(UTF8ToUTF16(credit_card->type())); | |
| 635 guid_pairs->push_back(GUIDPair(credit_card->guid(), 0)); | |
| 636 } | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 bool PersonalDataManager::IsAutofillEnabled() const { | |
| 641 return components::UserPrefs::Get(browser_context_)->GetBoolean( | |
| 642 prefs::kAutofillEnabled); | |
| 643 } | |
| 644 | |
| 645 // static | |
| 646 bool PersonalDataManager::IsValidLearnableProfile( | |
| 647 const AutofillProfile& profile) { | |
| 648 if (!IsMinimumAddress(profile)) | |
| 649 return false; | |
| 650 | |
| 651 string16 email = profile.GetRawInfo(EMAIL_ADDRESS); | |
| 652 if (!email.empty() && !autofill::IsValidEmailAddress(email)) | |
| 653 return false; | |
| 654 | |
| 655 // Reject profiles with invalid US state information. | |
| 656 string16 state = profile.GetRawInfo(ADDRESS_HOME_STATE); | |
| 657 if (profile.CountryCode() == "US" && | |
| 658 !state.empty() && !FormGroup::IsValidState(state)) { | |
| 659 return false; | |
| 660 } | |
| 661 | |
| 662 // Reject profiles with invalid US zip information. | |
| 663 string16 zip = profile.GetRawInfo(ADDRESS_HOME_ZIP); | |
| 664 if (profile.CountryCode() == "US" && !zip.empty() && | |
| 665 !autofill::IsValidZip(zip)) | |
| 666 return false; | |
| 667 | |
| 668 return true; | |
| 669 } | |
| 670 | |
| 671 // static | |
| 672 bool PersonalDataManager::MergeProfile( | |
| 673 const AutofillProfile& profile, | |
| 674 const std::vector<AutofillProfile*>& existing_profiles, | |
| 675 std::vector<AutofillProfile>* merged_profiles) { | |
| 676 merged_profiles->clear(); | |
| 677 | |
| 678 // Set to true if |profile| is merged into |existing_profiles|. | |
| 679 bool merged = false; | |
| 680 | |
| 681 // If we have already saved this address, merge in any missing values. | |
| 682 // Only merge with the first match. | |
| 683 for (std::vector<AutofillProfile*>::const_iterator iter = | |
| 684 existing_profiles.begin(); | |
| 685 iter != existing_profiles.end(); ++iter) { | |
| 686 if (!merged) { | |
| 687 if (!profile.PrimaryValue().empty() && | |
| 688 StringToLowerASCII((*iter)->PrimaryValue()) == | |
| 689 StringToLowerASCII(profile.PrimaryValue())) { | |
| 690 merged = true; | |
| 691 (*iter)->OverwriteWithOrAddTo(profile); | |
| 692 } | |
| 693 } | |
| 694 merged_profiles->push_back(**iter); | |
| 695 } | |
| 696 | |
| 697 // If the new profile was not merged with an existing one, add it to the list. | |
| 698 if (!merged) | |
| 699 merged_profiles->push_back(profile); | |
| 700 | |
| 701 return merged; | |
| 702 } | |
| 703 | |
| 704 void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) { | |
| 705 if (browser_context_->IsOffTheRecord()) | |
| 706 return; | |
| 707 | |
| 708 // Remove empty profiles from input. | |
| 709 profiles->erase( | |
| 710 std::remove_if(profiles->begin(), profiles->end(), | |
| 711 std::mem_fun_ref(&AutofillProfile::IsEmpty)), | |
| 712 profiles->end()); | |
| 713 | |
| 714 // Ensure that profile labels are up to date. Currently, sync relies on | |
| 715 // labels to identify a profile. | |
| 716 // TODO(dhollowa): We need to deprecate labels and update the way sync | |
| 717 // identifies profiles. | |
| 718 std::vector<AutofillProfile*> profile_pointers(profiles->size()); | |
| 719 std::transform(profiles->begin(), profiles->end(), profile_pointers.begin(), | |
| 720 address_of<AutofillProfile>); | |
| 721 AutofillProfile::AdjustInferredLabels(&profile_pointers); | |
| 722 | |
| 723 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 724 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 725 if (!autofill_data.get()) | |
| 726 return; | |
| 727 | |
| 728 // Any profiles that are not in the new profile list should be removed from | |
| 729 // the web database. | |
| 730 for (std::vector<AutofillProfile*>::const_iterator iter = | |
| 731 web_profiles_.begin(); | |
| 732 iter != web_profiles_.end(); ++iter) { | |
| 733 if (!FindByGUID<AutofillProfile>(*profiles, (*iter)->guid())) | |
| 734 autofill_data->RemoveAutofillProfile((*iter)->guid()); | |
| 735 } | |
| 736 | |
| 737 // Update the web database with the existing profiles. | |
| 738 for (std::vector<AutofillProfile>::iterator iter = profiles->begin(); | |
| 739 iter != profiles->end(); ++iter) { | |
| 740 if (FindByGUID<AutofillProfile>(web_profiles_, iter->guid())) | |
| 741 autofill_data->UpdateAutofillProfile(*iter); | |
| 742 } | |
| 743 | |
| 744 // Add the new profiles to the web database. Don't add a duplicate. | |
| 745 for (std::vector<AutofillProfile>::iterator iter = profiles->begin(); | |
| 746 iter != profiles->end(); ++iter) { | |
| 747 if (!FindByGUID<AutofillProfile>(web_profiles_, iter->guid()) && | |
| 748 !FindByContents(web_profiles_, *iter)) | |
| 749 autofill_data->AddAutofillProfile(*iter); | |
| 750 } | |
| 751 | |
| 752 // Copy in the new profiles. | |
| 753 web_profiles_.clear(); | |
| 754 for (std::vector<AutofillProfile>::iterator iter = profiles->begin(); | |
| 755 iter != profiles->end(); ++iter) { | |
| 756 web_profiles_.push_back(new AutofillProfile(*iter)); | |
| 757 } | |
| 758 | |
| 759 // Refresh our local cache and send notifications to observers. | |
| 760 Refresh(); | |
| 761 } | |
| 762 | |
| 763 void PersonalDataManager::SetCreditCards( | |
| 764 std::vector<CreditCard>* credit_cards) { | |
| 765 if (browser_context_->IsOffTheRecord()) | |
| 766 return; | |
| 767 | |
| 768 // Remove empty credit cards from input. | |
| 769 credit_cards->erase( | |
| 770 std::remove_if( | |
| 771 credit_cards->begin(), credit_cards->end(), | |
| 772 std::mem_fun_ref(&CreditCard::IsEmpty)), | |
| 773 credit_cards->end()); | |
| 774 | |
| 775 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 776 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 777 if (!autofill_data.get()) | |
| 778 return; | |
| 779 | |
| 780 // Any credit cards that are not in the new credit card list should be | |
| 781 // removed. | |
| 782 for (std::vector<CreditCard*>::const_iterator iter = credit_cards_.begin(); | |
| 783 iter != credit_cards_.end(); ++iter) { | |
| 784 if (!FindByGUID<CreditCard>(*credit_cards, (*iter)->guid())) | |
| 785 autofill_data->RemoveCreditCard((*iter)->guid()); | |
| 786 } | |
| 787 | |
| 788 // Update the web database with the existing credit cards. | |
| 789 for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); | |
| 790 iter != credit_cards->end(); ++iter) { | |
| 791 if (FindByGUID<CreditCard>(credit_cards_, iter->guid())) | |
| 792 autofill_data->UpdateCreditCard(*iter); | |
| 793 } | |
| 794 | |
| 795 // Add the new credit cards to the web database. Don't add a duplicate. | |
| 796 for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); | |
| 797 iter != credit_cards->end(); ++iter) { | |
| 798 if (!FindByGUID<CreditCard>(credit_cards_, iter->guid()) && | |
| 799 !FindByContents(credit_cards_, *iter)) | |
| 800 autofill_data->AddCreditCard(*iter); | |
| 801 } | |
| 802 | |
| 803 // Copy in the new credit cards. | |
| 804 credit_cards_.clear(); | |
| 805 for (std::vector<CreditCard>::iterator iter = credit_cards->begin(); | |
| 806 iter != credit_cards->end(); ++iter) { | |
| 807 credit_cards_.push_back(new CreditCard(*iter)); | |
| 808 } | |
| 809 | |
| 810 // Refresh our local cache and send notifications to observers. | |
| 811 Refresh(); | |
| 812 } | |
| 813 | |
| 814 void PersonalDataManager::LoadProfiles() { | |
| 815 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 816 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 817 if (!autofill_data.get()) { | |
| 818 NOTREACHED(); | |
| 819 return; | |
| 820 } | |
| 821 | |
| 822 CancelPendingQuery(&pending_profiles_query_); | |
| 823 | |
| 824 pending_profiles_query_ = autofill_data->GetAutofillProfiles(this); | |
| 825 } | |
| 826 | |
| 827 // Win and Linux implementations do nothing. Mac implementation fills in the | |
| 828 // contents of |auxiliary_profiles_|. | |
| 829 #if !defined(OS_MACOSX) | |
| 830 void PersonalDataManager::LoadAuxiliaryProfiles() { | |
| 831 } | |
| 832 #endif | |
| 833 | |
| 834 void PersonalDataManager::LoadCreditCards() { | |
| 835 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 836 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 837 if (!autofill_data.get()) { | |
| 838 NOTREACHED(); | |
| 839 return; | |
| 840 } | |
| 841 | |
| 842 CancelPendingQuery(&pending_creditcards_query_); | |
| 843 | |
| 844 pending_creditcards_query_ = autofill_data->GetCreditCards(this); | |
| 845 } | |
| 846 | |
| 847 void PersonalDataManager::ReceiveLoadedProfiles(WebDataServiceBase::Handle h, | |
| 848 const WDTypedResult* result) { | |
| 849 DCHECK_EQ(pending_profiles_query_, h); | |
| 850 | |
| 851 pending_profiles_query_ = 0; | |
| 852 web_profiles_.clear(); | |
| 853 | |
| 854 const WDResult<std::vector<AutofillProfile*> >* r = | |
| 855 static_cast<const WDResult<std::vector<AutofillProfile*> >*>(result); | |
| 856 | |
| 857 std::vector<AutofillProfile*> profiles = r->GetValue(); | |
| 858 for (std::vector<AutofillProfile*>::iterator iter = profiles.begin(); | |
| 859 iter != profiles.end(); ++iter) { | |
| 860 web_profiles_.push_back(*iter); | |
| 861 } | |
| 862 | |
| 863 LogProfileCount(); | |
| 864 } | |
| 865 | |
| 866 void PersonalDataManager::ReceiveLoadedCreditCards( | |
| 867 WebDataServiceBase::Handle h, const WDTypedResult* result) { | |
| 868 DCHECK_EQ(pending_creditcards_query_, h); | |
| 869 | |
| 870 pending_creditcards_query_ = 0; | |
| 871 credit_cards_.clear(); | |
| 872 | |
| 873 const WDResult<std::vector<CreditCard*> >* r = | |
| 874 static_cast<const WDResult<std::vector<CreditCard*> >*>(result); | |
| 875 | |
| 876 std::vector<CreditCard*> credit_cards = r->GetValue(); | |
| 877 for (std::vector<CreditCard*>::iterator iter = credit_cards.begin(); | |
| 878 iter != credit_cards.end(); ++iter) { | |
| 879 credit_cards_.push_back(*iter); | |
| 880 } | |
| 881 } | |
| 882 | |
| 883 void PersonalDataManager::CancelPendingQuery( | |
| 884 WebDataServiceBase::Handle* handle) { | |
| 885 if (*handle) { | |
| 886 scoped_ptr<AutofillWebDataService> autofill_data( | |
| 887 AutofillWebDataService::FromBrowserContext(browser_context_)); | |
| 888 if (!autofill_data.get()) { | |
| 889 NOTREACHED(); | |
| 890 return; | |
| 891 } | |
| 892 autofill_data->CancelRequest(*handle); | |
| 893 } | |
| 894 *handle = 0; | |
| 895 } | |
| 896 | |
| 897 void PersonalDataManager::SaveImportedProfile( | |
| 898 const AutofillProfile& imported_profile) { | |
| 899 if (browser_context_->IsOffTheRecord()) { | |
| 900 // The |IsOffTheRecord| check should happen earlier in the import process, | |
| 901 // upon form submission. | |
| 902 NOTREACHED(); | |
| 903 return; | |
| 904 } | |
| 905 | |
| 906 // Don't save a web profile if the data in the profile is a subset of an | |
| 907 // auxiliary profile. | |
| 908 for (std::vector<AutofillProfile*>::const_iterator iter = | |
| 909 auxiliary_profiles_.begin(); | |
| 910 iter != auxiliary_profiles_.end(); ++iter) { | |
| 911 if (imported_profile.IsSubsetOf(**iter)) | |
| 912 return; | |
| 913 } | |
| 914 | |
| 915 std::vector<AutofillProfile> profiles; | |
| 916 MergeProfile(imported_profile, web_profiles_.get(), &profiles); | |
| 917 SetProfiles(&profiles); | |
| 918 } | |
| 919 | |
| 920 | |
| 921 void PersonalDataManager::SaveImportedCreditCard( | |
| 922 const CreditCard& imported_card) { | |
| 923 DCHECK(!imported_card.number().empty()); | |
| 924 if (browser_context_->IsOffTheRecord()) { | |
| 925 // The |IsOffTheRecord| check should happen earlier in the import process, | |
| 926 // upon form submission. | |
| 927 NOTREACHED(); | |
| 928 return; | |
| 929 } | |
| 930 | |
| 931 // Set to true if |imported_card| is merged into the credit card list. | |
| 932 bool merged = false; | |
| 933 | |
| 934 const std::string app_locale = AutofillCountry::ApplicationLocale(); | |
| 935 std::vector<CreditCard> credit_cards; | |
| 936 for (std::vector<CreditCard*>::const_iterator card = credit_cards_.begin(); | |
| 937 card != credit_cards_.end(); | |
| 938 ++card) { | |
| 939 // If |imported_card| has not yet been merged, check whether it should be | |
| 940 // with the current |card|. | |
| 941 if (!merged && (*card)->UpdateFromImportedCard(imported_card, app_locale)) | |
| 942 merged = true; | |
| 943 | |
| 944 credit_cards.push_back(**card); | |
| 945 } | |
| 946 | |
| 947 if (!merged) | |
| 948 credit_cards.push_back(imported_card); | |
| 949 | |
| 950 SetCreditCards(&credit_cards); | |
| 951 } | |
| 952 | |
| 953 void PersonalDataManager::LogProfileCount() const { | |
| 954 if (!has_logged_profile_count_) { | |
| 955 metric_logger_->LogStoredProfileCount(web_profiles_.size()); | |
| 956 has_logged_profile_count_ = true; | |
| 957 } | |
| 958 } | |
| 959 | |
| 960 const AutofillMetrics* PersonalDataManager::metric_logger() const { | |
| 961 return metric_logger_.get(); | |
| 962 } | |
| 963 | |
| 964 void PersonalDataManager::set_metric_logger( | |
| 965 const AutofillMetrics* metric_logger) { | |
| 966 metric_logger_.reset(metric_logger); | |
| 967 } | |
| 968 | |
| 969 void PersonalDataManager::set_browser_context( | |
| 970 content::BrowserContext* context) { | |
| 971 browser_context_ = context; | |
| 972 } | |
| OLD | NEW |