| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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/sync/glue/autofill_profile_change_processor.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/string_util.h" | |
| 11 #include "base/tracked.h" | |
| 12 #include "base/utf_string_conversions.h" | |
| 13 #include "chrome/browser/autofill/autofill_profile.h" | |
| 14 #include "chrome/browser/autofill/personal_data_manager.h" | |
| 15 #include "chrome/browser/sync/glue/autofill_profile_model_associator.h" | |
| 16 #include "chrome/browser/sync/glue/change_processor.h" | |
| 17 #include "chrome/browser/sync/glue/do_optimistic_refresh_task.h" | |
| 18 #include "chrome/browser/sync/internal_api/read_node.h" | |
| 19 #include "chrome/browser/sync/internal_api/sync_manager.h" | |
| 20 #include "chrome/browser/sync/internal_api/write_node.h" | |
| 21 #include "chrome/browser/sync/internal_api/write_transaction.h" | |
| 22 #include "chrome/browser/sync/unrecoverable_error_handler.h" | |
| 23 #include "chrome/browser/webdata/autofill_change.h" | |
| 24 #include "chrome/browser/webdata/autofill_table.h" | |
| 25 #include "chrome/browser/webdata/web_database.h" | |
| 26 #include "chrome/common/chrome_notification_types.h" | |
| 27 #include "chrome/common/guid.h" | |
| 28 #include "content/common/notification_registrar.h" | |
| 29 #include "content/common/notification_service.h" | |
| 30 | |
| 31 namespace browser_sync { | |
| 32 | |
| 33 AutofillProfileChangeProcessor::AutofillProfileChangeProcessor( | |
| 34 AutofillProfileModelAssociator *model_associator, | |
| 35 WebDatabase* web_database, | |
| 36 PersonalDataManager* personal_data_manager, | |
| 37 UnrecoverableErrorHandler* error_handler) | |
| 38 : ChangeProcessor(error_handler), | |
| 39 model_associator_(model_associator), | |
| 40 observing_(false), | |
| 41 web_database_(web_database), | |
| 42 personal_data_(personal_data_manager) { | |
| 43 DCHECK(model_associator); | |
| 44 DCHECK(web_database); | |
| 45 DCHECK(error_handler); | |
| 46 DCHECK(personal_data_manager); | |
| 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
| 48 | |
| 49 StartObserving(); | |
| 50 } | |
| 51 | |
| 52 AutofillProfileChangeProcessor::~AutofillProfileChangeProcessor() {} | |
| 53 | |
| 54 void AutofillProfileChangeProcessor::ApplyChangesFromSyncModel( | |
| 55 const sync_api::BaseTransaction *write_trans, | |
| 56 const sync_api::SyncManager::ChangeRecord* changes, | |
| 57 int change_count) { | |
| 58 | |
| 59 ScopedStopObserving<AutofillProfileChangeProcessor> observer(this); | |
| 60 | |
| 61 sync_api::ReadNode autofill_profile_root(write_trans); | |
| 62 if (!autofill_profile_root.InitByTagLookup(kAutofillProfileTag)) { | |
| 63 error_handler()->OnUnrecoverableError(FROM_HERE, | |
| 64 "Autofill Profile root node lookup failed"); | |
| 65 return; | |
| 66 } | |
| 67 | |
| 68 for (int i = 0; i < change_count; ++i) { | |
| 69 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == | |
| 70 changes[i].action) { | |
| 71 DCHECK(changes[i].specifics.HasExtension( | |
| 72 sync_pb::autofill_profile)); | |
| 73 | |
| 74 const sync_pb::AutofillProfileSpecifics& specifics = | |
| 75 changes[i].specifics.GetExtension(sync_pb::autofill_profile); | |
| 76 | |
| 77 autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action, | |
| 78 changes[i].id, | |
| 79 specifics)); | |
| 80 continue; | |
| 81 } | |
| 82 | |
| 83 // If it is not a delete. | |
| 84 sync_api::ReadNode sync_node(write_trans); | |
| 85 if (!sync_node.InitByIdLookup(changes[i].id)) { | |
| 86 LOG(ERROR) << "Could not find the id in sync db " << changes[i].id; | |
| 87 continue; | |
| 88 } | |
| 89 | |
| 90 const sync_pb::AutofillProfileSpecifics& autofill( | |
| 91 sync_node.GetAutofillProfileSpecifics()); | |
| 92 | |
| 93 autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action, | |
| 94 changes[i].id, | |
| 95 autofill)); | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 void AutofillProfileChangeProcessor::Observe(int type, | |
| 100 const NotificationSource& source, | |
| 101 const NotificationDetails& details) { | |
| 102 DCHECK_EQ(type, chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED); | |
| 103 WebDataService* wds = Source<WebDataService>(source).ptr(); | |
| 104 | |
| 105 if (!wds || wds->GetDatabase() != web_database_) | |
| 106 return; | |
| 107 | |
| 108 sync_api::WriteTransaction trans(FROM_HERE, share_handle()); | |
| 109 sync_api::ReadNode autofill_root(&trans); | |
| 110 if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) { | |
| 111 error_handler()->OnUnrecoverableError(FROM_HERE, | |
| 112 "Server did not create a tolp level node"); | |
| 113 return; | |
| 114 } | |
| 115 | |
| 116 AutofillProfileChange* change = Details<AutofillProfileChange>(details).ptr(); | |
| 117 | |
| 118 ActOnChange(change, &trans, autofill_root); | |
| 119 } | |
| 120 | |
| 121 void AutofillProfileChangeProcessor::ActOnChange( | |
| 122 AutofillProfileChange* change, | |
| 123 sync_api::WriteTransaction* trans, | |
| 124 sync_api::ReadNode& autofill_root) { | |
| 125 DCHECK(change->type() == AutofillProfileChange::REMOVE || change->profile()); | |
| 126 switch (change->type()) { | |
| 127 case AutofillProfileChange::ADD: { | |
| 128 AddAutofillProfileSyncNode(trans, autofill_root, *(change->profile())); | |
| 129 break; | |
| 130 } | |
| 131 case AutofillProfileChange::UPDATE: { | |
| 132 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); | |
| 133 if (sync_api::kInvalidId == sync_id) { | |
| 134 LOG(ERROR) << "Sync id is not found for " << change->key(); | |
| 135 break; | |
| 136 } | |
| 137 sync_api::WriteNode node(trans); | |
| 138 if (!node.InitByIdLookup(sync_id)) { | |
| 139 LOG(ERROR) << "Could not find sync node for id " << sync_id; | |
| 140 break; | |
| 141 } | |
| 142 | |
| 143 WriteAutofillProfile(*(change->profile()), &node); | |
| 144 break; | |
| 145 } | |
| 146 case AutofillProfileChange::REMOVE: { | |
| 147 int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key()); | |
| 148 if (sync_api::kInvalidId == sync_id) { | |
| 149 LOG(ERROR) << "Sync id is not found for " << change->key(); | |
| 150 break; | |
| 151 } | |
| 152 sync_api::WriteNode node(trans); | |
| 153 if (!node.InitByIdLookup(sync_id)) { | |
| 154 LOG(ERROR) << "Could not find sync node for id " << sync_id; | |
| 155 break; | |
| 156 } | |
| 157 node.Remove(); | |
| 158 model_associator_->Disassociate(sync_id); | |
| 159 break; | |
| 160 } | |
| 161 default: | |
| 162 NOTREACHED(); | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 void AutofillProfileChangeProcessor::CommitChangesFromSyncModel() { | |
| 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
| 168 | |
| 169 if (!running()) | |
| 170 return; | |
| 171 | |
| 172 ScopedStopObserving<AutofillProfileChangeProcessor> observer(this); | |
| 173 | |
| 174 for (unsigned int i = 0;i < autofill_changes_.size(); ++i) { | |
| 175 if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == | |
| 176 autofill_changes_[i].action_) { | |
| 177 if (!web_database_->GetAutofillTable()->RemoveAutofillProfile( | |
| 178 autofill_changes_[i].profile_specifics_.guid())) { | |
| 179 LOG(ERROR) << "could not delete the profile " << | |
| 180 autofill_changes_[i].profile_specifics_.guid(); | |
| 181 continue; | |
| 182 } | |
| 183 continue; | |
| 184 } | |
| 185 | |
| 186 // Now for updates and adds. | |
| 187 ApplyAutofillProfileChange(autofill_changes_[i].action_, | |
| 188 autofill_changes_[i].profile_specifics_, | |
| 189 autofill_changes_[i].id_); | |
| 190 } | |
| 191 | |
| 192 autofill_changes_.clear(); | |
| 193 | |
| 194 PostOptimisticRefreshTask(); | |
| 195 } | |
| 196 | |
| 197 void AutofillProfileChangeProcessor::PostOptimisticRefreshTask() { | |
| 198 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 199 new DoOptimisticRefreshForAutofill( | |
| 200 personal_data_)); | |
| 201 } | |
| 202 | |
| 203 void AutofillProfileChangeProcessor::ApplyAutofillProfileChange( | |
| 204 sync_api::SyncManager::ChangeRecord::Action action, | |
| 205 const sync_pb::AutofillProfileSpecifics& profile_specifics, | |
| 206 int64 sync_id) { | |
| 207 | |
| 208 DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action); | |
| 209 switch (action) { | |
| 210 case sync_api::SyncManager::ChangeRecord::ACTION_ADD: { | |
| 211 if (guid::IsValidGUID(profile_specifics.guid()) == false) { | |
| 212 NOTREACHED() << "Guid from the server is invalid " << | |
| 213 profile_specifics.guid(); | |
| 214 return; | |
| 215 } | |
| 216 AutofillProfile p(profile_specifics.guid()); | |
| 217 AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p, | |
| 218 profile_specifics); | |
| 219 if (!web_database_->GetAutofillTable()->AddAutofillProfile(p)) { | |
| 220 LOG(ERROR) << "could not add autofill profile for guid " << p.guid(); | |
| 221 break; | |
| 222 } | |
| 223 | |
| 224 // Now that the node has been succesfully created we can associate it. | |
| 225 std::string guid = p.guid(); | |
| 226 model_associator_->Associate(&guid, sync_id); | |
| 227 break; | |
| 228 } | |
| 229 case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: { | |
| 230 AutofillProfile *p; | |
| 231 if (!web_database_->GetAutofillTable()->GetAutofillProfile( | |
| 232 profile_specifics.guid(), &p)) { | |
| 233 LOG(ERROR) << "Could not find the autofill profile to update for " << | |
| 234 profile_specifics.guid(); | |
| 235 break; | |
| 236 } | |
| 237 scoped_ptr<AutofillProfile> autofill_pointer(p); | |
| 238 AutofillProfileModelAssociator::OverwriteProfileWithServerData( | |
| 239 autofill_pointer.get(), | |
| 240 profile_specifics); | |
| 241 | |
| 242 if (!web_database_->GetAutofillTable()->UpdateAutofillProfile( | |
| 243 *(autofill_pointer.get()))) { | |
| 244 LOG(ERROR) << "Could not update autofill profile for " << | |
| 245 profile_specifics.guid(); | |
| 246 break; | |
| 247 } | |
| 248 break; | |
| 249 } | |
| 250 default: { | |
| 251 NOTREACHED(); | |
| 252 break; | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 void AutofillProfileChangeProcessor::RemoveSyncNode(const std::string& guid, | |
| 258 sync_api::WriteTransaction* trans) { | |
| 259 sync_api::WriteNode node(trans); | |
| 260 int64 sync_id = model_associator_->GetSyncIdFromChromeId(guid); | |
| 261 if (sync_api::kInvalidId == sync_id) { | |
| 262 LOG(ERROR) << "Could not find the node in associator " << guid; | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 if (!node.InitByIdLookup(sync_id)) { | |
| 267 LOG(ERROR) << "Could not find the sync node for " << guid; | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 model_associator_->Disassociate(sync_id); | |
| 272 node.Remove(); | |
| 273 } | |
| 274 | |
| 275 void AutofillProfileChangeProcessor::AddAutofillProfileSyncNode( | |
| 276 sync_api::WriteTransaction* trans, | |
| 277 sync_api::BaseNode& autofill_profile_root, | |
| 278 const AutofillProfile& profile) { | |
| 279 | |
| 280 std::string guid = profile.guid(); | |
| 281 | |
| 282 if (guid::IsValidGUID(guid) == false) { | |
| 283 DCHECK(false) << "Guid set on the profile is invalid " << guid; | |
| 284 return; | |
| 285 } | |
| 286 | |
| 287 sync_api::WriteNode node(trans); | |
| 288 if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE, | |
| 289 autofill_profile_root, | |
| 290 profile.guid())) { | |
| 291 LOG(ERROR) << "could not create a sync node "; | |
| 292 return; | |
| 293 } | |
| 294 | |
| 295 node.SetTitle(UTF8ToWide(profile.guid())); | |
| 296 | |
| 297 WriteAutofillProfile(profile, &node); | |
| 298 | |
| 299 model_associator_->Associate(&guid, node.GetId()); | |
| 300 } | |
| 301 | |
| 302 void AutofillProfileChangeProcessor::StartObserving() { | |
| 303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
| 304 notification_registrar_.Add(this, | |
| 305 chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED, | |
| 306 NotificationService::AllSources()); | |
| 307 } | |
| 308 | |
| 309 void AutofillProfileChangeProcessor::StopObserving() { | |
| 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
| 311 notification_registrar_.RemoveAll(); | |
| 312 } | |
| 313 | |
| 314 void AutofillProfileChangeProcessor::WriteAutofillProfile( | |
| 315 const AutofillProfile& profile, | |
| 316 sync_api::WriteNode* node) { | |
| 317 sync_pb::AutofillProfileSpecifics specifics; | |
| 318 | |
| 319 // This would get compiled out in official builds. The caller is expected to | |
| 320 // pass in a valid profile object with valid guid.(i.e., the caller might | |
| 321 // have to a DCHECK and log before calling. Having to check in 2 places is | |
| 322 // not optimal.) | |
| 323 DCHECK(guid::IsValidGUID(profile.guid())); | |
| 324 | |
| 325 specifics.set_guid(profile.guid()); | |
| 326 specifics.set_name_first(UTF16ToUTF8(profile.GetInfo(NAME_FIRST))); | |
| 327 specifics.set_name_middle(UTF16ToUTF8(profile.GetInfo(NAME_MIDDLE))); | |
| 328 specifics.set_name_last(UTF16ToUTF8(profile.GetInfo(NAME_LAST))); | |
| 329 specifics.set_address_home_line1( | |
| 330 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1))); | |
| 331 specifics.set_address_home_line2( | |
| 332 UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2))); | |
| 333 specifics.set_address_home_city(UTF16ToUTF8(profile.GetInfo( | |
| 334 ADDRESS_HOME_CITY))); | |
| 335 specifics.set_address_home_state(UTF16ToUTF8(profile.GetInfo( | |
| 336 ADDRESS_HOME_STATE))); | |
| 337 specifics.set_address_home_country(UTF16ToUTF8(profile.GetInfo( | |
| 338 ADDRESS_HOME_COUNTRY))); | |
| 339 specifics.set_address_home_zip(UTF16ToUTF8(profile.GetInfo( | |
| 340 ADDRESS_HOME_ZIP))); | |
| 341 specifics.set_email_address(UTF16ToUTF8(profile.GetInfo(EMAIL_ADDRESS))); | |
| 342 specifics.set_company_name(UTF16ToUTF8(profile.GetInfo(COMPANY_NAME))); | |
| 343 specifics.set_phone_fax_whole_number(UTF16ToUTF8(profile.GetInfo( | |
| 344 PHONE_FAX_WHOLE_NUMBER))); | |
| 345 specifics.set_phone_home_whole_number(UTF16ToUTF8(profile.GetInfo( | |
| 346 PHONE_HOME_WHOLE_NUMBER))); | |
| 347 node->SetAutofillProfileSpecifics(specifics); | |
| 348 } | |
| 349 | |
| 350 } // namespace browser_sync | |
| OLD | NEW |