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