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