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 |