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/webdata/autofill_profile_syncable_service.h" | |
6 | |
7 #include "base/guid.h" | |
8 #include "base/location.h" | |
9 #include "base/logging.h" | |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "components/autofill/core/browser/autofill_country.h" | |
12 #include "components/autofill/core/browser/autofill_profile.h" | |
13 #include "components/autofill/core/browser/form_group.h" | |
14 #include "components/autofill/core/browser/webdata/autofill_table.h" | |
15 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" | |
16 #include "components/webdata/common/web_database.h" | |
17 #include "content/public/browser/browser_thread.h" | |
18 #include "sync/api/sync_error.h" | |
19 #include "sync/api/sync_error_factory.h" | |
20 #include "sync/protocol/sync.pb.h" | |
21 | |
22 using base::ASCIIToUTF16; | |
23 using base::UTF8ToUTF16; | |
24 using base::UTF16ToUTF8; | |
25 using content::BrowserThread; | |
26 | |
27 namespace autofill { | |
28 | |
29 namespace { | |
30 | |
31 std::string LimitData(const std::string& data) { | |
32 std::string sanitized_value(data); | |
33 if (sanitized_value.length() > AutofillTable::kMaxDataLength) | |
34 sanitized_value.resize(AutofillTable::kMaxDataLength); | |
35 return sanitized_value; | |
36 } | |
37 | |
38 void* UserDataKey() { | |
39 // Use the address of a static that COMDAT folding won't ever fold | |
40 // with something else. | |
41 static int user_data_key = 0; | |
42 return reinterpret_cast<void*>(&user_data_key); | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 const char kAutofillProfileTag[] = "google_chrome_autofill_profiles"; | |
48 | |
49 AutofillProfileSyncableService::AutofillProfileSyncableService( | |
50 AutofillWebDataBackend* webdata_backend, | |
51 const std::string& app_locale) | |
52 : webdata_backend_(webdata_backend), | |
53 app_locale_(app_locale), | |
54 scoped_observer_(this) { | |
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
56 DCHECK(webdata_backend_); | |
57 | |
58 scoped_observer_.Add(webdata_backend_); | |
59 } | |
60 | |
61 AutofillProfileSyncableService::~AutofillProfileSyncableService() { | |
62 DCHECK(CalledOnValidThread()); | |
63 } | |
64 | |
65 // static | |
66 void AutofillProfileSyncableService::CreateForWebDataServiceAndBackend( | |
67 AutofillWebDataService* web_data_service, | |
68 AutofillWebDataBackend* webdata_backend, | |
69 const std::string& app_locale) { | |
70 web_data_service->GetDBUserData()->SetUserData( | |
71 UserDataKey(), | |
72 new AutofillProfileSyncableService(webdata_backend, app_locale)); | |
73 } | |
74 | |
75 // static | |
76 AutofillProfileSyncableService* | |
77 AutofillProfileSyncableService::FromWebDataService( | |
78 AutofillWebDataService* web_data_service) { | |
79 return static_cast<AutofillProfileSyncableService*>( | |
80 web_data_service->GetDBUserData()->GetUserData(UserDataKey())); | |
81 } | |
82 | |
83 AutofillProfileSyncableService::AutofillProfileSyncableService() | |
84 : webdata_backend_(NULL), | |
85 scoped_observer_(this) { | |
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
87 } | |
88 | |
89 syncer::SyncMergeResult | |
90 AutofillProfileSyncableService::MergeDataAndStartSyncing( | |
91 syncer::ModelType type, | |
92 const syncer::SyncDataList& initial_sync_data, | |
93 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | |
94 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) { | |
95 DCHECK(CalledOnValidThread()); | |
96 DCHECK(!sync_processor_.get()); | |
97 DCHECK(sync_processor.get()); | |
98 DCHECK(sync_error_factory.get()); | |
99 DVLOG(1) << "Associating Autofill: MergeDataAndStartSyncing"; | |
100 | |
101 syncer::SyncMergeResult merge_result(type); | |
102 sync_error_factory_ = sync_error_factory.Pass(); | |
103 if (!LoadAutofillData(&profiles_.get())) { | |
104 merge_result.set_error(sync_error_factory_->CreateAndUploadError( | |
105 FROM_HERE, "Could not get the autofill data from WebDatabase.")); | |
106 return merge_result; | |
107 } | |
108 | |
109 if (DLOG_IS_ON(INFO)) { | |
110 DVLOG(2) << "[AUTOFILL MIGRATION]" | |
111 << "Printing profiles from web db"; | |
112 | |
113 for (ScopedVector<AutofillProfile>::const_iterator ix = | |
114 profiles_.begin(); ix != profiles_.end(); ++ix) { | |
115 AutofillProfile* p = *ix; | |
116 DVLOG(2) << "[AUTOFILL MIGRATION] " | |
117 << UTF16ToUTF8(p->GetRawInfo(NAME_FIRST)) | |
118 << UTF16ToUTF8(p->GetRawInfo(NAME_LAST)) | |
119 << p->guid(); | |
120 } | |
121 } | |
122 | |
123 sync_processor_ = sync_processor.Pass(); | |
124 | |
125 GUIDToProfileMap remaining_profiles; | |
126 CreateGUIDToProfileMap(profiles_.get(), &remaining_profiles); | |
127 | |
128 DataBundle bundle; | |
129 // Go through and check for all the profiles that sync already knows about. | |
130 for (syncer::SyncDataList::const_iterator sync_iter = | |
131 initial_sync_data.begin(); | |
132 sync_iter != initial_sync_data.end(); | |
133 ++sync_iter) { | |
134 GUIDToProfileMap::iterator it = | |
135 CreateOrUpdateProfile(*sync_iter, &remaining_profiles, &bundle); | |
136 // |it| points to created/updated profile. Add it to the |profiles_map_| and | |
137 // then remove it from |remaining_profiles|. After this loop is completed | |
138 // |remaining_profiles| will have only those profiles that are not in the | |
139 // sync. | |
140 profiles_map_[it->first] = it->second; | |
141 remaining_profiles.erase(it); | |
142 } | |
143 | |
144 // Check for similar unmatched profiles - they are created independently on | |
145 // two systems, so merge them. | |
146 for (GUIDToProfileMap::iterator it = bundle.candidates_to_merge.begin(); | |
147 it != bundle.candidates_to_merge.end(); ++it) { | |
148 GUIDToProfileMap::iterator profile_to_merge = | |
149 remaining_profiles.find(it->first); | |
150 if (profile_to_merge != remaining_profiles.end()) { | |
151 bundle.profiles_to_delete.push_back(profile_to_merge->second->guid()); | |
152 if (MergeProfile(*(profile_to_merge->second), it->second, app_locale_)) | |
153 bundle.profiles_to_sync_back.push_back(it->second); | |
154 DVLOG(2) << "[AUTOFILL SYNC]" | |
155 << "Found similar profile in sync db but with a different guid: " | |
156 << UTF16ToUTF8(it->second->GetRawInfo(NAME_FIRST)) | |
157 << UTF16ToUTF8(it->second->GetRawInfo(NAME_LAST)) | |
158 << "New guid " << it->second->guid() | |
159 << ". Profile to be deleted " | |
160 << profile_to_merge->second->guid(); | |
161 remaining_profiles.erase(profile_to_merge); | |
162 } | |
163 } | |
164 | |
165 if (!SaveChangesToWebData(bundle)) { | |
166 merge_result.set_error(sync_error_factory_->CreateAndUploadError( | |
167 FROM_HERE, | |
168 "Failed to update webdata.")); | |
169 return merge_result; | |
170 } | |
171 | |
172 syncer::SyncChangeList new_changes; | |
173 for (GUIDToProfileMap::iterator i = remaining_profiles.begin(); | |
174 i != remaining_profiles.end(); ++i) { | |
175 new_changes.push_back( | |
176 syncer::SyncChange(FROM_HERE, | |
177 syncer::SyncChange::ACTION_ADD, | |
178 CreateData(*(i->second)))); | |
179 profiles_map_[i->first] = i->second; | |
180 } | |
181 | |
182 for (size_t i = 0; i < bundle.profiles_to_sync_back.size(); ++i) { | |
183 new_changes.push_back( | |
184 syncer::SyncChange(FROM_HERE, | |
185 syncer::SyncChange::ACTION_UPDATE, | |
186 CreateData(*(bundle.profiles_to_sync_back[i])))); | |
187 } | |
188 | |
189 if (!new_changes.empty()) { | |
190 merge_result.set_error( | |
191 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); | |
192 } | |
193 | |
194 if (webdata_backend_) | |
195 webdata_backend_->NotifyOfMultipleAutofillChanges(); | |
196 | |
197 return merge_result; | |
198 } | |
199 | |
200 void AutofillProfileSyncableService::StopSyncing(syncer::ModelType type) { | |
201 DCHECK(CalledOnValidThread()); | |
202 DCHECK_EQ(type, syncer::AUTOFILL_PROFILE); | |
203 | |
204 sync_processor_.reset(); | |
205 sync_error_factory_.reset(); | |
206 profiles_.clear(); | |
207 profiles_map_.clear(); | |
208 } | |
209 | |
210 syncer::SyncDataList AutofillProfileSyncableService::GetAllSyncData( | |
211 syncer::ModelType type) const { | |
212 DCHECK(CalledOnValidThread()); | |
213 DCHECK(sync_processor_.get()); | |
214 DCHECK_EQ(type, syncer::AUTOFILL_PROFILE); | |
215 | |
216 syncer::SyncDataList current_data; | |
217 | |
218 for (GUIDToProfileMap::const_iterator i = profiles_map_.begin(); | |
219 i != profiles_map_.end(); ++i) { | |
220 current_data.push_back(CreateData(*(i->second))); | |
221 } | |
222 return current_data; | |
223 } | |
224 | |
225 syncer::SyncError AutofillProfileSyncableService::ProcessSyncChanges( | |
226 const tracked_objects::Location& from_here, | |
227 const syncer::SyncChangeList& change_list) { | |
228 DCHECK(CalledOnValidThread()); | |
229 if (!sync_processor_.get()) { | |
230 syncer::SyncError error(FROM_HERE, | |
231 syncer::SyncError::DATATYPE_ERROR, | |
232 "Models not yet associated.", | |
233 syncer::AUTOFILL_PROFILE); | |
234 return error; | |
235 } | |
236 | |
237 DataBundle bundle; | |
238 | |
239 for (syncer::SyncChangeList::const_iterator i = change_list.begin(); | |
240 i != change_list.end(); ++i) { | |
241 DCHECK(i->IsValid()); | |
242 switch (i->change_type()) { | |
243 case syncer::SyncChange::ACTION_ADD: | |
244 case syncer::SyncChange::ACTION_UPDATE: | |
245 CreateOrUpdateProfile(i->sync_data(), &profiles_map_, &bundle); | |
246 break; | |
247 case syncer::SyncChange::ACTION_DELETE: { | |
248 std::string guid = i->sync_data().GetSpecifics(). | |
249 autofill_profile().guid(); | |
250 bundle.profiles_to_delete.push_back(guid); | |
251 profiles_map_.erase(guid); | |
252 } break; | |
253 default: | |
254 NOTREACHED() << "Unexpected sync change state."; | |
255 return sync_error_factory_->CreateAndUploadError( | |
256 FROM_HERE, | |
257 "ProcessSyncChanges failed on ChangeType " + | |
258 syncer::SyncChange::ChangeTypeToString(i->change_type())); | |
259 } | |
260 } | |
261 | |
262 if (!SaveChangesToWebData(bundle)) { | |
263 return sync_error_factory_->CreateAndUploadError( | |
264 FROM_HERE, | |
265 "Failed to update webdata."); | |
266 } | |
267 | |
268 if (webdata_backend_) | |
269 webdata_backend_->NotifyOfMultipleAutofillChanges(); | |
270 | |
271 return syncer::SyncError(); | |
272 } | |
273 | |
274 void AutofillProfileSyncableService::AutofillProfileChanged( | |
275 const AutofillProfileChange& change) { | |
276 // Check if sync is on. If we receive notification prior to the sync being set | |
277 // up we are going to process all when MergeData..() is called. If we receive | |
278 // notification after the sync exited, it will be sinced next time Chrome | |
279 // starts. | |
280 if (sync_processor_.get()) { | |
281 ActOnChange(change); | |
282 } else if (!flare_.is_null()) { | |
283 flare_.Run(syncer::AUTOFILL_PROFILE); | |
284 flare_.Reset(); | |
285 } | |
286 } | |
287 | |
288 bool AutofillProfileSyncableService::LoadAutofillData( | |
289 std::vector<AutofillProfile*>* profiles) { | |
290 return GetAutofillTable()->GetAutofillProfiles(profiles); | |
291 } | |
292 | |
293 bool AutofillProfileSyncableService::SaveChangesToWebData( | |
294 const DataBundle& bundle) { | |
295 DCHECK(CalledOnValidThread()); | |
296 | |
297 AutofillTable* autofill_table = GetAutofillTable(); | |
298 | |
299 bool success = true; | |
300 for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) { | |
301 if (!autofill_table->RemoveAutofillProfile(bundle.profiles_to_delete[i])) | |
302 success = false; | |
303 } | |
304 | |
305 for (size_t i = 0; i < bundle.profiles_to_add.size(); i++) { | |
306 if (!autofill_table->AddAutofillProfile(*bundle.profiles_to_add[i])) | |
307 success = false; | |
308 } | |
309 | |
310 for (size_t i = 0; i < bundle.profiles_to_update.size(); i++) { | |
311 if (!autofill_table->UpdateAutofillProfile(*bundle.profiles_to_update[i])) | |
312 success = false; | |
313 } | |
314 return success; | |
315 } | |
316 | |
317 // static | |
318 bool AutofillProfileSyncableService::OverwriteProfileWithServerData( | |
319 const sync_pb::AutofillProfileSpecifics& specifics, | |
320 AutofillProfile* profile, | |
321 const std::string& app_locale) { | |
322 bool diff = false; | |
323 if (profile->origin() != specifics.origin()) { | |
324 bool was_verified = profile->IsVerified(); | |
325 profile->set_origin(specifics.origin()); | |
326 diff = true; | |
327 | |
328 // Verified profiles should never be overwritten by unverified ones. | |
329 DCHECK(!was_verified || profile->IsVerified()); | |
330 } | |
331 | |
332 // Update all multivalued fields: names, emails, and phones. | |
333 diff = UpdateMultivaluedField(NAME_FIRST, | |
334 specifics.name_first(), profile) || diff; | |
335 diff = UpdateMultivaluedField(NAME_MIDDLE, | |
336 specifics.name_middle(), profile) || diff; | |
337 diff = UpdateMultivaluedField(NAME_LAST, | |
338 specifics.name_last(), profile) || diff; | |
339 diff = UpdateMultivaluedField(EMAIL_ADDRESS, | |
340 specifics.email_address(), profile) || diff; | |
341 diff = UpdateMultivaluedField(PHONE_HOME_WHOLE_NUMBER, | |
342 specifics.phone_home_whole_number(), | |
343 profile) || diff; | |
344 | |
345 // Update all simple single-valued address fields. | |
346 diff = UpdateField(COMPANY_NAME, specifics.company_name(), profile) || diff; | |
347 diff = UpdateField(ADDRESS_HOME_CITY, | |
348 specifics.address_home_city(), profile) || diff; | |
349 diff = UpdateField(ADDRESS_HOME_STATE, | |
350 specifics.address_home_state(), profile) || diff; | |
351 diff = UpdateField(ADDRESS_HOME_ZIP, | |
352 specifics.address_home_zip(), profile) || diff; | |
353 diff = UpdateField(ADDRESS_HOME_SORTING_CODE, | |
354 specifics.address_home_sorting_code(), profile) || diff; | |
355 diff = UpdateField(ADDRESS_HOME_DEPENDENT_LOCALITY, | |
356 specifics.address_home_dependent_locality(), | |
357 profile) || diff; | |
358 | |
359 // Update the country field, which can contain either a country code (if set | |
360 // by a newer version of Chrome), or a country name (if set by an older | |
361 // version of Chrome). | |
362 base::string16 country_name_or_code = | |
363 ASCIIToUTF16(specifics.address_home_country()); | |
364 std::string country_code = | |
365 AutofillCountry::GetCountryCode(country_name_or_code, app_locale); | |
366 diff = UpdateField(ADDRESS_HOME_COUNTRY, country_code, profile) || diff; | |
367 | |
368 // Update the street address. In newer versions of Chrome (M34+), this data | |
369 // is stored in the |address_home_street_address| field. In older versions, | |
370 // this data is stored separated out by address line. | |
371 if (specifics.has_address_home_street_address()) { | |
372 diff = UpdateField(ADDRESS_HOME_STREET_ADDRESS, | |
373 specifics.address_home_street_address(), | |
374 profile) || diff; | |
375 } else { | |
376 diff = UpdateField(ADDRESS_HOME_LINE1, | |
377 specifics.address_home_line1(), profile) || diff; | |
378 diff = UpdateField(ADDRESS_HOME_LINE2, | |
379 specifics.address_home_line2(), profile) || diff; | |
380 } | |
381 return diff; | |
382 } | |
383 | |
384 // static | |
385 void AutofillProfileSyncableService::WriteAutofillProfile( | |
386 const AutofillProfile& profile, | |
387 sync_pb::EntitySpecifics* profile_specifics) { | |
388 sync_pb::AutofillProfileSpecifics* specifics = | |
389 profile_specifics->mutable_autofill_profile(); | |
390 | |
391 DCHECK(base::IsValidGUID(profile.guid())); | |
392 | |
393 // Reset all multi-valued fields in the protobuf. | |
394 specifics->clear_name_first(); | |
395 specifics->clear_name_middle(); | |
396 specifics->clear_name_last(); | |
397 specifics->clear_email_address(); | |
398 specifics->clear_phone_home_whole_number(); | |
399 | |
400 specifics->set_guid(profile.guid()); | |
401 specifics->set_origin(profile.origin()); | |
402 | |
403 std::vector<base::string16> values; | |
404 profile.GetRawMultiInfo(NAME_FIRST, &values); | |
405 for (size_t i = 0; i < values.size(); ++i) { | |
406 specifics->add_name_first(LimitData(UTF16ToUTF8(values[i]))); | |
407 } | |
408 | |
409 profile.GetRawMultiInfo(NAME_MIDDLE, &values); | |
410 for (size_t i = 0; i < values.size(); ++i) { | |
411 specifics->add_name_middle(LimitData(UTF16ToUTF8(values[i]))); | |
412 } | |
413 | |
414 profile.GetRawMultiInfo(NAME_LAST, &values); | |
415 for (size_t i = 0; i < values.size(); ++i) { | |
416 specifics->add_name_last(LimitData(UTF16ToUTF8(values[i]))); | |
417 } | |
418 | |
419 specifics->set_address_home_line1( | |
420 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)))); | |
421 specifics->set_address_home_line2( | |
422 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)))); | |
423 specifics->set_address_home_city( | |
424 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)))); | |
425 specifics->set_address_home_state( | |
426 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)))); | |
427 specifics->set_address_home_zip( | |
428 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)))); | |
429 specifics->set_address_home_country( | |
430 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)))); | |
431 specifics->set_address_home_street_address( | |
432 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS)))); | |
433 specifics->set_address_home_sorting_code( | |
434 LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)))); | |
435 specifics->set_address_home_dependent_locality( | |
436 LimitData( | |
437 UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)))); | |
438 | |
439 profile.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
440 for (size_t i = 0; i < values.size(); ++i) { | |
441 specifics->add_email_address(LimitData(UTF16ToUTF8(values[i]))); | |
442 } | |
443 | |
444 specifics->set_company_name( | |
445 LimitData(UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)))); | |
446 | |
447 profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values); | |
448 for (size_t i = 0; i < values.size(); ++i) { | |
449 specifics->add_phone_home_whole_number(LimitData(UTF16ToUTF8(values[i]))); | |
450 } | |
451 } | |
452 | |
453 void AutofillProfileSyncableService::CreateGUIDToProfileMap( | |
454 const std::vector<AutofillProfile*>& profiles, | |
455 GUIDToProfileMap* profile_map) { | |
456 DCHECK(profile_map); | |
457 profile_map->clear(); | |
458 for (size_t i = 0; i < profiles.size(); ++i) | |
459 (*profile_map)[profiles[i]->guid()] = profiles[i]; | |
460 } | |
461 | |
462 AutofillProfileSyncableService::GUIDToProfileMap::iterator | |
463 AutofillProfileSyncableService::CreateOrUpdateProfile( | |
464 const syncer::SyncData& data, | |
465 GUIDToProfileMap* profile_map, | |
466 DataBundle* bundle) { | |
467 DCHECK(profile_map); | |
468 DCHECK(bundle); | |
469 | |
470 DCHECK_EQ(syncer::AUTOFILL_PROFILE, data.GetDataType()); | |
471 | |
472 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); | |
473 const sync_pb::AutofillProfileSpecifics& autofill_specifics( | |
474 specifics.autofill_profile()); | |
475 | |
476 GUIDToProfileMap::iterator existing_profile = profile_map->find( | |
477 autofill_specifics.guid()); | |
478 if (existing_profile != profile_map->end()) { | |
479 // The synced profile already exists locally. It might need to be updated. | |
480 if (OverwriteProfileWithServerData( | |
481 autofill_specifics, existing_profile->second, app_locale_)) { | |
482 bundle->profiles_to_update.push_back(existing_profile->second); | |
483 } | |
484 return existing_profile; | |
485 } | |
486 | |
487 | |
488 // New profile synced. | |
489 AutofillProfile* new_profile = new AutofillProfile( | |
490 autofill_specifics.guid(), autofill_specifics.origin()); | |
491 OverwriteProfileWithServerData(autofill_specifics, new_profile, app_locale_); | |
492 | |
493 // Check if profile appears under a different guid. | |
494 // Unverified profiles should never overwrite verified ones. | |
495 for (GUIDToProfileMap::iterator it = profile_map->begin(); | |
496 it != profile_map->end(); ++it) { | |
497 AutofillProfile* local_profile = it->second; | |
498 if (local_profile->Compare(*new_profile) == 0) { | |
499 // Ensure that a verified profile can never revert back to an unverified | |
500 // one. | |
501 if (local_profile->IsVerified() && !new_profile->IsVerified()) { | |
502 new_profile->set_origin(local_profile->origin()); | |
503 bundle->profiles_to_sync_back.push_back(new_profile); | |
504 } | |
505 | |
506 bundle->profiles_to_delete.push_back(local_profile->guid()); | |
507 DVLOG(2) << "[AUTOFILL SYNC]" | |
508 << "Found in sync db but with a different guid: " | |
509 << UTF16ToUTF8(local_profile->GetRawInfo(NAME_FIRST)) | |
510 << UTF16ToUTF8(local_profile->GetRawInfo(NAME_LAST)) | |
511 << "New guid " << new_profile->guid() | |
512 << ". Profile to be deleted " << local_profile->guid(); | |
513 profile_map->erase(it); | |
514 break; | |
515 } else if (!local_profile->IsVerified() && | |
516 !new_profile->IsVerified() && | |
517 !local_profile->PrimaryValue().empty() && | |
518 local_profile->PrimaryValue() == new_profile->PrimaryValue()) { | |
519 // Add it to candidates for merge - if there is no profile with this | |
520 // guid we will merge them. | |
521 bundle->candidates_to_merge.insert( | |
522 std::make_pair(local_profile->guid(), new_profile)); | |
523 } | |
524 } | |
525 profiles_.push_back(new_profile); | |
526 bundle->profiles_to_add.push_back(new_profile); | |
527 return profile_map->insert(std::make_pair(new_profile->guid(), | |
528 new_profile)).first; | |
529 } | |
530 | |
531 void AutofillProfileSyncableService::ActOnChange( | |
532 const AutofillProfileChange& change) { | |
533 DCHECK((change.type() == AutofillProfileChange::REMOVE && | |
534 !change.profile()) || | |
535 (change.type() != AutofillProfileChange::REMOVE && change.profile())); | |
536 DCHECK(sync_processor_.get()); | |
537 syncer::SyncChangeList new_changes; | |
538 DataBundle bundle; | |
539 switch (change.type()) { | |
540 case AutofillProfileChange::ADD: | |
541 new_changes.push_back( | |
542 syncer::SyncChange(FROM_HERE, | |
543 syncer::SyncChange::ACTION_ADD, | |
544 CreateData(*(change.profile())))); | |
545 DCHECK(profiles_map_.find(change.profile()->guid()) == | |
546 profiles_map_.end()); | |
547 profiles_.push_back(new AutofillProfile(*(change.profile()))); | |
548 profiles_map_[change.profile()->guid()] = profiles_.get().back(); | |
549 break; | |
550 case AutofillProfileChange::UPDATE: { | |
551 GUIDToProfileMap::iterator it = profiles_map_.find( | |
552 change.profile()->guid()); | |
553 DCHECK(it != profiles_map_.end()); | |
554 *(it->second) = *(change.profile()); | |
555 new_changes.push_back( | |
556 syncer::SyncChange(FROM_HERE, | |
557 syncer::SyncChange::ACTION_UPDATE, | |
558 CreateData(*(change.profile())))); | |
559 break; | |
560 } | |
561 case AutofillProfileChange::REMOVE: { | |
562 AutofillProfile empty_profile(change.key(), std::string()); | |
563 new_changes.push_back( | |
564 syncer::SyncChange(FROM_HERE, | |
565 syncer::SyncChange::ACTION_DELETE, | |
566 CreateData(empty_profile))); | |
567 profiles_map_.erase(change.key()); | |
568 break; | |
569 } | |
570 default: | |
571 NOTREACHED(); | |
572 } | |
573 syncer::SyncError error = | |
574 sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); | |
575 if (error.IsSet()) { | |
576 // TODO(isherman): Investigating http://crbug.com/121592 | |
577 VLOG(1) << "[AUTOFILL SYNC] " | |
578 << "Failed processing change:\n" | |
579 << " Error: " << error.message() << "\n" | |
580 << " Guid: " << change.key(); | |
581 } | |
582 } | |
583 | |
584 syncer::SyncData AutofillProfileSyncableService::CreateData( | |
585 const AutofillProfile& profile) { | |
586 sync_pb::EntitySpecifics specifics; | |
587 WriteAutofillProfile(profile, &specifics); | |
588 return | |
589 syncer::SyncData::CreateLocalData( | |
590 profile.guid(), profile.guid(), specifics); | |
591 } | |
592 | |
593 bool AutofillProfileSyncableService::UpdateField( | |
594 ServerFieldType field_type, | |
595 const std::string& new_value, | |
596 AutofillProfile* autofill_profile) { | |
597 if (UTF16ToUTF8(autofill_profile->GetRawInfo(field_type)) == new_value) | |
598 return false; | |
599 autofill_profile->SetRawInfo(field_type, UTF8ToUTF16(new_value)); | |
600 return true; | |
601 } | |
602 | |
603 bool AutofillProfileSyncableService::UpdateMultivaluedField( | |
604 ServerFieldType field_type, | |
605 const ::google::protobuf::RepeatedPtrField<std::string>& new_values, | |
606 AutofillProfile* autofill_profile) { | |
607 std::vector<base::string16> values; | |
608 autofill_profile->GetRawMultiInfo(field_type, &values); | |
609 bool changed = false; | |
610 if (static_cast<size_t>(new_values.size()) != values.size()) { | |
611 values.clear(); | |
612 values.resize(static_cast<size_t>(new_values.size())); | |
613 changed = true; | |
614 } | |
615 for (size_t i = 0; i < values.size(); ++i) { | |
616 base::string16 synced_value( | |
617 UTF8ToUTF16(new_values.Get(static_cast<int>(i)))); | |
618 if (values[i] != synced_value) { | |
619 values[i] = synced_value; | |
620 changed = true; | |
621 } | |
622 } | |
623 if (changed) | |
624 autofill_profile->SetRawMultiInfo(field_type, values); | |
625 return changed; | |
626 } | |
627 | |
628 bool AutofillProfileSyncableService::MergeProfile( | |
629 const AutofillProfile& merge_from, | |
630 AutofillProfile* merge_into, | |
631 const std::string& app_locale) { | |
632 merge_into->OverwriteWithOrAddTo(merge_from, app_locale); | |
633 return (merge_into->Compare(merge_from) != 0 || | |
634 merge_into->origin() != merge_from.origin()); | |
635 } | |
636 | |
637 AutofillTable* AutofillProfileSyncableService::GetAutofillTable() const { | |
638 return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase()); | |
639 } | |
640 | |
641 void AutofillProfileSyncableService::InjectStartSyncFlare( | |
642 const syncer::SyncableService::StartSyncFlare& flare) { | |
643 flare_ = flare; | |
644 } | |
645 | |
646 AutofillProfileSyncableService::DataBundle::DataBundle() {} | |
647 | |
648 AutofillProfileSyncableService::DataBundle::~DataBundle() {} | |
649 | |
650 } // namespace autofill | |
OLD | NEW |