Index: chrome/browser/sync/glue/autofill_change_processor2.cc |
diff --git a/chrome/browser/sync/glue/autofill_change_processor2.cc b/chrome/browser/sync/glue/autofill_change_processor2.cc |
new file mode 100755 |
index 0000000000000000000000000000000000000000..405e7039c13502bec6a9665ce5122239b3b4ecb0 |
--- /dev/null |
+++ b/chrome/browser/sync/glue/autofill_change_processor2.cc |
@@ -0,0 +1,583 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/sync/glue/autofill_change_processor2.h" |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "base/string_util.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/profile.h" |
+#include "chrome/browser/autofill/personal_data_manager.h" |
+#include "chrome/browser/sync/glue/autofill_model_associator.h" |
+#include "chrome/browser/sync/glue/autofill_model_associator2.h" |
+#include "chrome/browser/sync/profile_sync_service.h" |
+#include "chrome/browser/webdata/autofill_change.h" |
+#include "chrome/browser/webdata/web_data_service.h" |
+#include "chrome/browser/webdata/web_database.h" |
+#include "chrome/common/notification_service.h" |
+ |
+namespace browser_sync { |
+ |
+class AutofillModelAssociator2; |
+struct AutofillChangeProcessor2::AutofillChangeRecord { |
+ sync_api::SyncManager::ChangeRecord::Action action_; |
+ int64 id_; |
+ sync_pb::AutofillSpecifics autofill_; |
+ AutofillChangeRecord(sync_api::SyncManager::ChangeRecord::Action action, |
+ int64 id, const sync_pb::AutofillSpecifics& autofill) |
+ : action_(action), |
+ id_(id), |
+ autofill_(autofill) { } |
+}; |
+ |
+AutofillChangeProcessor2::AutofillChangeProcessor2( |
+ AutofillModelAssociator2* model_associator, |
+ WebDatabase* web_database, |
+ PersonalDataManager* personal_data, |
+ UnrecoverableErrorHandler* error_handler) |
+ : ChangeProcessor(error_handler), |
+ model_associator_(model_associator), |
+ web_database_(web_database), |
+ personal_data_(personal_data), |
+ observing_(false) { |
+ DCHECK(model_associator); |
+ DCHECK(web_database); |
+ DCHECK(error_handler); |
+ DCHECK(personal_data); |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ StartObserving(); |
+} |
+ |
+AutofillChangeProcessor2::~AutofillChangeProcessor2() {} |
+ |
+void AutofillChangeProcessor2::Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ // Ensure this notification came from our web database. |
+ WebDataService* wds = Source<WebDataService>(source).ptr(); |
+ if (!wds || wds->GetDatabase() != web_database_) |
+ return; |
+ |
+ DCHECK(running()); |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ if (!observing_) |
+ return; |
+ |
+ sync_api::WriteTransaction trans(share_handle()); |
+ sync_api::ReadNode autofill_root(&trans); |
+ if (!autofill_root.InitByTagLookup(kAutofillTag)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Server did not create the top-level autofill node. " |
+ "We might be running against an out-of-date server."); |
+ return; |
+ } |
+ |
+ switch (type.value) { |
+ case NotificationType::AUTOFILL_ENTRIES_CHANGED: { |
+ AutofillChangeList* changes = Details<AutofillChangeList>(details).ptr(); |
+ ObserveAutofillEntriesChanged(changes, &trans, autofill_root); |
+ break; |
+ } |
+ case NotificationType::AUTOFILL_PROFILE_CHANGED: { |
+ AutofillProfileChange* change = |
+ Details<AutofillProfileChange>(details).ptr(); |
+ ObserveAutofillProfileChanged(change, &trans, autofill_root); |
+ break; |
+ } |
+ default: |
+ NOTREACHED() << "Invalid NotificationType."; |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::ChangeProfileLabelIfAlreadyTaken( |
+ sync_api::BaseTransaction* trans, |
+ const string16& pre_update_label, |
+ AutoFillProfile* profile, |
+ std::string* tag) { |
+ DCHECK_EQ(AutofillModelAssociator2::ProfileLabelToTag(profile->Label()), |
+ *tag); |
+ sync_api::ReadNode read_node(trans); |
+ if (!pre_update_label.empty() && pre_update_label == profile->Label()) |
+ return; |
+ if (read_node.InitByClientTagLookup(syncable::AUTOFILL, *tag)) { |
+ // Handle the edge case of duplicate labels. |
+ string16 new_label(AutofillModelAssociator2::MakeUniqueLabel( |
+ profile->Label(), pre_update_label, trans)); |
+ if (new_label.empty()) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "No unique label; can't move aside"); |
+ return; |
+ } |
+ OverrideProfileLabel(new_label, profile, tag); |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::OverrideProfileLabel( |
+ const string16& new_label, |
+ AutoFillProfile* profile_to_update, |
+ std::string* tag_to_update) { |
+ tag_to_update->assign(AutofillModelAssociator2::ProfileLabelToTag(new_label)); |
+ |
+ profile_to_update->set_label(new_label); |
+ if (!web_database_->UpdateAutoFillProfile(*profile_to_update)) { |
+ std::string err = "Failed to overwrite label for node "; |
+ err += UTF16ToUTF8(new_label); |
+ error_handler()->OnUnrecoverableError(FROM_HERE, err); |
+ return; |
+ } |
+ |
+ // Notify the PersonalDataManager that it's out of date. |
+ PostOptimisticRefreshTask(); |
+} |
+ |
+void AutofillChangeProcessor2::PostOptimisticRefreshTask() { |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ new AutofillModelAssociator2::DoOptimisticRefreshTask( |
+ personal_data_)); |
+} |
+ |
+void AutofillChangeProcessor2::AddAutofillProfileSyncNode( |
+ sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill, |
+ const std::string& tag, const AutoFillProfile* profile) { |
+ sync_api::WriteNode sync_node(trans); |
+ if (!sync_node.InitUniqueByCreation(syncable::AUTOFILL, autofill, tag)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Failed to create autofill sync node."); |
+ return; |
+ } |
+ sync_node.SetTitle(UTF8ToWide(tag)); |
+ |
+ WriteAutofillProfile(*profile, &sync_node); |
+ model_associator_->Associate(&tag, sync_node.GetId()); |
+} |
+ |
+void AutofillChangeProcessor2::ObserveAutofillProfileChanged( |
+ AutofillProfileChange* change, sync_api::WriteTransaction* trans, |
+ const sync_api::ReadNode& autofill_root) { |
+ std::string tag(AutofillModelAssociator2::ProfileLabelToTag(change->key())); |
+ switch (change->type()) { |
+ case AutofillProfileChange::ADD: { |
+ scoped_ptr<AutoFillProfile> clone( |
+ static_cast<AutoFillProfile*>(change->profile()->Clone())); |
+ DCHECK_EQ(clone->Label(), change->key()); |
+ ChangeProfileLabelIfAlreadyTaken(trans, string16(), clone.get(), &tag); |
+ AddAutofillProfileSyncNode(trans, autofill_root, tag, clone.get()); |
+ break; |
+ } |
+ case AutofillProfileChange::UPDATE: { |
+ scoped_ptr<AutoFillProfile> clone( |
+ static_cast<AutoFillProfile*>(change->profile()->Clone())); |
+ std::string pre_update_tag = AutofillModelAssociator2::ProfileLabelToTag( |
+ change->pre_update_label()); |
+ DCHECK_EQ(clone->Label(), change->key()); |
+ sync_api::WriteNode sync_node(trans); |
+ ChangeProfileLabelIfAlreadyTaken(trans, change->pre_update_label(), |
+ clone.get(), &tag); |
+ if (pre_update_tag != tag) { |
+ // If the label changes, replace the node instead of updating it. |
+ RemoveSyncNode(pre_update_tag, trans); |
+ AddAutofillProfileSyncNode(trans, autofill_root, tag, clone.get()); |
+ return; |
+ } |
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag); |
+ if (sync_api::kInvalidId == sync_id) { |
+ std::string err = "Unexpected notification for: " + tag; |
+ error_handler()->OnUnrecoverableError(FROM_HERE, err); |
+ return; |
+ } else { |
+ if (!sync_node.InitByIdLookup(sync_id)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Autofill node lookup failed."); |
+ return; |
+ } |
+ WriteAutofillProfile(*clone.get(), &sync_node); |
+ } |
+ break; |
+ } |
+ case AutofillProfileChange::REMOVE: { |
+ RemoveSyncNode(tag, trans); |
+ break; |
+ } |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::ObserveAutofillEntriesChanged( |
+ AutofillChangeList* changes, sync_api::WriteTransaction* trans, |
+ const sync_api::ReadNode& autofill_root) { |
+ for (AutofillChangeList::iterator change = changes->begin(); |
+ change != changes->end(); ++change) { |
+ switch (change->type()) { |
+ case AutofillChange::ADD: |
+ { |
+ sync_api::WriteNode sync_node(trans); |
+ std::string tag = |
+ AutofillModelAssociator2::KeyToTag(change->key().name(), |
+ change->key().value()); |
+ if (!sync_node.InitUniqueByCreation(syncable::AUTOFILL, |
+ autofill_root, tag)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Failed to create autofill sync node."); |
+ return; |
+ } |
+ |
+ std::vector<base::Time> timestamps; |
+ if (!web_database_->GetAutofillTimestamps( |
+ change->key().name(), |
+ change->key().value(), |
+ ×tamps)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Failed to get timestamps."); |
+ return; |
+ } |
+ |
+ sync_node.SetTitle(UTF8ToWide(tag)); |
+ |
+ WriteAutofillEntry(AutofillEntry(change->key(), timestamps), |
+ &sync_node); |
+ model_associator_->Associate(&tag, sync_node.GetId()); |
+ } |
+ break; |
+ |
+ case AutofillChange::UPDATE: |
+ { |
+ sync_api::WriteNode sync_node(trans); |
+ std::string tag = AutofillModelAssociator2::KeyToTag( |
+ change->key().name(), change->key().value()); |
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag); |
+ if (sync_api::kInvalidId == sync_id) { |
+ std::string err = "Unexpected notification for: " + |
+ UTF16ToUTF8(change->key().name()); |
+ error_handler()->OnUnrecoverableError(FROM_HERE, err); |
+ return; |
+ } else { |
+ if (!sync_node.InitByIdLookup(sync_id)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Autofill node lookup failed."); |
+ return; |
+ } |
+ } |
+ |
+ std::vector<base::Time> timestamps; |
+ if (!web_database_->GetAutofillTimestamps( |
+ change->key().name(), |
+ change->key().value(), |
+ ×tamps)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Failed to get timestamps."); |
+ return; |
+ } |
+ |
+ WriteAutofillEntry(AutofillEntry(change->key(), timestamps), |
+ &sync_node); |
+ } |
+ break; |
+ case AutofillChange::REMOVE: { |
+ std::string tag = AutofillModelAssociator2::KeyToTag( |
+ change->key().name(), change->key().value()); |
+ RemoveSyncNode(tag, trans); |
+ } |
+ break; |
+ } |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::RemoveSyncNode(const std::string& tag, |
+ sync_api::WriteTransaction* trans) { |
+ sync_api::WriteNode sync_node(trans); |
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag); |
+ if (sync_api::kInvalidId == sync_id) { |
+ std::string err = "Unexpected notification for: " + tag; |
+ error_handler()->OnUnrecoverableError(FROM_HERE, err); |
+ return; |
+ } else { |
+ if (!sync_node.InitByIdLookup(sync_id)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Autofill node lookup failed."); |
+ return; |
+ } |
+ model_associator_->Disassociate(sync_node.GetId()); |
+ sync_node.Remove(); |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::ApplyChangesFromSyncModel( |
+ const sync_api::BaseTransaction* trans, |
+ const sync_api::SyncManager::ChangeRecord* changes, |
+ int change_count) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ if (!running()) |
+ return; |
+ StopObserving(); |
+ |
+ sync_api::ReadNode autofill_root(trans); |
+ if (!autofill_root.InitByTagLookup(kAutofillTag)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Autofill root node lookup failed."); |
+ return; |
+ } |
+ |
+ for (int i = 0; i < change_count; ++i) { |
+ sync_api::SyncManager::ChangeRecord::Action action(changes[i].action); |
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) { |
+ DCHECK(changes[i].specifics.HasExtension(sync_pb::autofill)) |
+ << "Autofill specifics data not present on delete!"; |
+ const sync_pb::AutofillSpecifics& autofill = |
+ changes[i].specifics.GetExtension(sync_pb::autofill); |
+ if (autofill.has_value() || autofill.has_profile()) { |
+ autofill_changes_.push_back(AutofillChangeRecord(changes[i].action, |
+ changes[i].id, |
+ autofill)); |
+ } else { |
+ NOTREACHED() << "Autofill specifics has no data!"; |
+ } |
+ continue; |
+ } |
+ |
+ // Handle an update or add. |
+ sync_api::ReadNode sync_node(trans); |
+ if (!sync_node.InitByIdLookup(changes[i].id)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Autofill node lookup failed."); |
+ return; |
+ } |
+ |
+ // Check that the changed node is a child of the autofills folder. |
+ DCHECK(autofill_root.GetId() == sync_node.GetParentId()); |
+ DCHECK(syncable::AUTOFILL == sync_node.GetModelType()); |
+ |
+ const sync_pb::AutofillSpecifics& autofill( |
+ sync_node.GetAutofillSpecifics()); |
+ int64 sync_id = sync_node.GetId(); |
+ if (autofill.has_value() || autofill.has_profile()) { |
+ autofill_changes_.push_back(AutofillChangeRecord(changes[i].action, |
+ sync_id, autofill)); |
+ } else { |
+ NOTREACHED() << "Autofill specifics has no data!"; |
+ } |
+ } |
+ |
+ StartObserving(); |
+} |
+ |
+void AutofillChangeProcessor2::CommitChangesFromSyncModel() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ if (!running()) |
+ return; |
+ StopObserving(); |
+ |
+ std::vector<AutofillEntry> new_entries; |
+ for (unsigned int i = 0; i < autofill_changes_.size(); i++) { |
+ // Handle deletions. |
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == |
+ autofill_changes_[i].action_) { |
+ if (autofill_changes_[i].autofill_.has_value()) { |
+ ApplySyncAutofillEntryDelete(autofill_changes_[i].autofill_); |
+ } else if (autofill_changes_[i].autofill_.has_profile()) { |
+ ApplySyncAutofillProfileDelete(autofill_changes_[i].autofill_.profile(), |
+ autofill_changes_[i].id_); |
+ } else { |
+ NOTREACHED() << "Autofill's CommitChanges received change with no" |
+ " data!"; |
+ } |
+ continue; |
+ } |
+ |
+ // Handle update/adds. |
+ if (autofill_changes_[i].autofill_.has_value()) { |
+ ApplySyncAutofillEntryChange(autofill_changes_[i].action_, |
+ autofill_changes_[i].autofill_, &new_entries, |
+ autofill_changes_[i].id_); |
+ } else if (autofill_changes_[i].autofill_.has_profile()) { |
+ ApplySyncAutofillProfileChange(autofill_changes_[i].action_, |
+ autofill_changes_[i].autofill_.profile(), |
+ autofill_changes_[i].id_); |
+ } else { |
+ NOTREACHED() << "Autofill's CommitChanges received change with no data!"; |
+ } |
+ } |
+ autofill_changes_.clear(); |
+ |
+ // Make changes |
+ if (!web_database_->UpdateAutofillEntries(new_entries)) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Could not update autofill entries."); |
+ return; |
+ } |
+ |
+ PostOptimisticRefreshTask(); |
+ |
+ StartObserving(); |
+} |
+ |
+void AutofillChangeProcessor2::ApplySyncAutofillEntryDelete( |
+ const sync_pb::AutofillSpecifics& autofill) { |
+ if (!web_database_->RemoveFormElement( |
+ UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value()))) { |
+ error_handler()->OnUnrecoverableError(FROM_HERE, |
+ "Could not remove autofill node."); |
+ return; |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::ApplySyncAutofillEntryChange( |
+ sync_api::SyncManager::ChangeRecord::Action action, |
+ const sync_pb::AutofillSpecifics& autofill, |
+ std::vector<AutofillEntry>* new_entries, |
+ int64 sync_id) { |
+ DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action); |
+ |
+ std::vector<base::Time> timestamps; |
+ size_t timestamps_size = autofill.usage_timestamp_size(); |
+ for (size_t c = 0; c < timestamps_size; ++c) { |
+ timestamps.push_back( |
+ base::Time::FromInternalValue(autofill.usage_timestamp(c))); |
+ } |
+ AutofillKey k(UTF8ToUTF16(autofill.name()), UTF8ToUTF16(autofill.value())); |
+ AutofillEntry new_entry(k, timestamps); |
+ |
+ new_entries->push_back(new_entry); |
+ std::string tag(AutofillModelAssociator2::KeyToTag(k.name(), k.value())); |
+ if (action == sync_api::SyncManager::ChangeRecord::ACTION_ADD) |
+ model_associator_->Associate(&tag, sync_id); |
+} |
+ |
+void AutofillChangeProcessor2::ApplySyncAutofillProfileChange( |
+ sync_api::SyncManager::ChangeRecord::Action action, |
+ const sync_pb::AutofillProfileSpecifics& profile, |
+ int64 sync_id) { |
+ DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action); |
+ |
+ std::string tag(AutofillModelAssociator2::ProfileLabelToTag( |
+ UTF8ToUTF16(profile.label()))); |
+ switch (action) { |
+ case sync_api::SyncManager::ChangeRecord::ACTION_ADD: { |
+ PersonalDataManager* pdm = model_associator_->sync_service()-> |
+ profile()->GetPersonalDataManager(); |
+ scoped_ptr<AutoFillProfile> p( |
+ pdm->CreateNewEmptyAutoFillProfileForDBThread( |
+ UTF8ToUTF16(profile.label()))); |
+ AutofillModelAssociator2::OverwriteProfileWithServerData(p.get(), |
+ profile); |
+ |
+ model_associator_->Associate(&tag, sync_id); |
+ if (!web_database_->AddAutoFillProfile(*p.get())) { |
+ NOTREACHED() << "Couldn't add autofill profile: " << profile.label(); |
+ return; |
+ } |
+ break; |
+ } |
+ case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { |
+ AutoFillProfile* p = NULL; |
+ string16 label = UTF8ToUTF16(profile.label()); |
+ if (!web_database_->GetAutoFillProfileForLabel(label, &p)) { |
+ NOTREACHED() << "Couldn't retrieve autofill profile: " << label; |
+ return; |
+ } |
+ AutofillModelAssociator2::OverwriteProfileWithServerData(p, profile); |
+ if (!web_database_->UpdateAutoFillProfile(*p)) { |
+ NOTREACHED() << "Couldn't update autofill profile: " << label; |
+ return; |
+ } |
+ delete p; |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void AutofillChangeProcessor2::ApplySyncAutofillProfileDelete( |
+ const sync_pb::AutofillProfileSpecifics& profile, |
+ int64 sync_id) { |
+ string16 label(UTF8ToUTF16(profile.label())); |
+ AutoFillProfile* ptr = NULL; |
+ bool get_success = web_database_->GetAutoFillProfileForLabel(label, &ptr); |
+ scoped_ptr<AutoFillProfile> p(ptr); |
+ if (!get_success) { |
+ NOTREACHED() << "Couldn't retrieve autofill profile: " << label; |
+ return; |
+ } |
+ if (!web_database_->RemoveAutoFillProfile(p->unique_id())) { |
+ NOTREACHED() << "Couldn't remove autofill profile: " << label; |
+ return; |
+ } |
+ model_associator_->Disassociate(sync_id); |
+} |
+ |
+void AutofillChangeProcessor2::StartImpl(Profile* profile) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ observing_ = true; |
+} |
+ |
+void AutofillChangeProcessor2::StopImpl() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ observing_ = false; |
+} |
+ |
+ |
+void AutofillChangeProcessor2::StartObserving() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ notification_registrar_.Add(this, NotificationType::AUTOFILL_ENTRIES_CHANGED, |
+ NotificationService::AllSources()); |
+ notification_registrar_.Add(this, NotificationType::AUTOFILL_PROFILE_CHANGED, |
+ NotificationService::AllSources()); |
+} |
+ |
+void AutofillChangeProcessor2::StopObserving() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
+ notification_registrar_.RemoveAll(); |
+} |
+ |
+// static |
+void AutofillChangeProcessor2::WriteAutofillEntry( |
+ const AutofillEntry& entry, |
+ sync_api::WriteNode* node) { |
+ sync_pb::AutofillSpecifics autofill; |
+ autofill.set_name(UTF16ToUTF8(entry.key().name())); |
+ autofill.set_value(UTF16ToUTF8(entry.key().value())); |
+ const std::vector<base::Time>& ts(entry.timestamps()); |
+ for (std::vector<base::Time>::const_iterator timestamp = ts.begin(); |
+ timestamp != ts.end(); ++timestamp) { |
+ autofill.add_usage_timestamp(timestamp->ToInternalValue()); |
+ } |
+ node->SetAutofillSpecifics(autofill); |
+} |
+ |
+// static |
+void AutofillChangeProcessor2::WriteAutofillProfile( |
+ const AutoFillProfile& profile, sync_api::WriteNode* node) { |
+ sync_pb::AutofillSpecifics autofill; |
+ sync_pb::AutofillProfileSpecifics* s(autofill.mutable_profile()); |
+ s->set_label(UTF16ToUTF8(profile.Label())); |
+ s->set_name_first(UTF16ToUTF8( |
+ profile.GetFieldText(AutoFillType(NAME_FIRST)))); |
+ s->set_name_middle(UTF16ToUTF8( |
+ profile.GetFieldText(AutoFillType(NAME_MIDDLE)))); |
+ s->set_name_last(UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))); |
+ s->set_address_home_line1( |
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))); |
+ s->set_address_home_line2( |
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))); |
+ s->set_address_home_city(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(ADDRESS_HOME_CITY)))); |
+ s->set_address_home_state(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(ADDRESS_HOME_STATE)))); |
+ s->set_address_home_country(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(ADDRESS_HOME_COUNTRY)))); |
+ s->set_address_home_zip(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(ADDRESS_HOME_ZIP)))); |
+ s->set_email_address(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(EMAIL_ADDRESS)))); |
+ s->set_company_name(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(COMPANY_NAME)))); |
+ s->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(PHONE_FAX_WHOLE_NUMBER)))); |
+ s->set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText( |
+ AutoFillType(PHONE_HOME_WHOLE_NUMBER)))); |
+ node->SetAutofillSpecifics(autofill); |
+} |
+ |
+} // namespace browser_sync |