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_model_associator.h"
6
7#include "base/utf_string_conversions.h"
8#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
9#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
10#include "chrome/browser/sync/profile_sync_service.h"
11#include "chrome/browser/webdata/web_database.h"
12#include "chrome/common/guid.h"
13
14using sync_api::ReadNode;
15namespace browser_sync {
16
17const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
18
19AutofillProfileModelAssociator::AutofillProfileModelAssociator(
20    ProfileSyncService* sync_service,
21    WebDatabase* web_database,
22    PersonalDataManager* personal_data)
23    : sync_service_(sync_service),
24      web_database_(web_database),
25      personal_data_(personal_data),
26      autofill_node_id_(sync_api::kInvalidId),
27      abort_association_pending_(false),
28      number_of_profiles_created_(0) {
29  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
30  DCHECK(sync_service_);
31  DCHECK(web_database_);
32  DCHECK(personal_data_);
33}
34
35AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
36  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
37}
38
39AutofillProfileModelAssociator::AutofillProfileModelAssociator()
40    : sync_service_(NULL),
41      web_database_(NULL),
42      personal_data_(NULL),
43      autofill_node_id_(0),
44      abort_association_pending_(false),
45      number_of_profiles_created_(0) {
46}
47
48bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutofillProfiles(
49    sync_api::WriteTransaction* write_trans,
50    const sync_api::ReadNode& autofill_root,
51    const std::vector<AutofillProfile*>& all_profiles_from_db,
52    std::set<std::string>* current_profiles,
53    std::vector<AutofillProfile*>* updated_profiles,
54    std::vector<AutofillProfile*>* new_profiles,
55    std::vector<std::string>* profiles_to_delete) {
56
57  if (VLOG_IS_ON(2)) {
58    VLOG(2) << "[AUTOFILL MIGRATION]"
59            << "Printing profiles from web db";
60
61    for (std::vector<AutofillProfile*>::const_iterator ix =
62        all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
63      AutofillProfile* p = *ix;
64      VLOG(2) << "[AUTOFILL MIGRATION]  "
65              << p->GetInfo(NAME_FIRST)
66              << p->GetInfo(NAME_LAST)
67              << p->guid();
68    }
69  }
70
71  VLOG(1) << "[AUTOFILL MIGRATION]"
72          << "Looking for the above data in sync db..";
73
74  // Alias the all_profiles_from_db so we fit in 80 characters
75  const std::vector<AutofillProfile*>& profiles(all_profiles_from_db);
76  for (std::vector<AutofillProfile*>::const_iterator ix = profiles.begin();
77      ix != profiles.end();
78      ++ix) {
79    std::string guid((*ix)->guid());
80    if (guid::IsValidGUID(guid) == false) {
81      DCHECK(false) << "Guid in the web db is invalid " << guid;
82      continue;
83    }
84
85    ReadNode node(write_trans);
86    if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid) &&
87        // The following check is to ensure the given sync node is not already
88        // associated with another profile. That could happen if the user has
89        // the same profile duplicated.
90        current_profiles->find(guid) == current_profiles->end()) {
91      VLOG(2) << "[AUTOFILL MIGRATION]"
92              << " Found in sync db: "
93              << (*ix)->GetInfo(NAME_FIRST)
94              << (*ix)->GetInfo(NAME_LAST)
95              << (*ix)->guid()
96              << " so associating with node id " << node.GetId();
97      const sync_pb::AutofillProfileSpecifics& autofill(
98          node.GetAutofillProfileSpecifics());
99      if (OverwriteProfileWithServerData(*ix, autofill)) {
100        updated_profiles->push_back(*ix);
101      }
102      Associate(&guid, node.GetId());
103      current_profiles->insert(guid);
104    } else {
105      MakeNewAutofillProfileSyncNodeIfNeeded(write_trans,
106          autofill_root,
107          (**ix),
108          new_profiles,
109          current_profiles,
110          profiles_to_delete);
111    }
112  }
113  return true;
114}
115
116bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode(
117    const std::string& tag,
118    int64* sync_id) {
119  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
120  sync_api::ReadNode sync_node(&trans);
121  if (!sync_node.InitByTagLookup(tag.c_str()))
122    return false;
123  *sync_id = sync_node.GetId();
124  return true;
125}
126
127bool AutofillProfileModelAssociator::LoadAutofillData(
128    std::vector<AutofillProfile*>* profiles) {
129  if (IsAbortPending())
130    return false;
131
132  if (!web_database_->GetAutofillTable()->GetAutofillProfiles(profiles))
133    return false;
134
135  return true;
136}
137
138bool AutofillProfileModelAssociator::AssociateModels() {
139  VLOG(1) << "Associating Autofill Models";
140  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
141  {
142    base::AutoLock lock(abort_association_pending_lock_);
143    abort_association_pending_ = false;
144  }
145
146  ScopedVector<AutofillProfile> profiles;
147
148  if (!LoadAutofillData(&profiles.get())) {
149    LOG(ERROR) << "Could not get the autofill data from WebDatabase.";
150    return false;
151  }
152
153  VLOG(1) << "[AUTOFILL MIGRATION]"
154          << " Now associating to the new autofill profile model associator"
155          << " root node";
156  DataBundle bundle;
157  {
158    // The write transaction lock is held inside this block.
159    // We do all the web db operations outside this block.
160    sync_api::WriteTransaction trans(sync_service_->GetUserShare());
161
162    sync_api::ReadNode autofill_root(&trans);
163    if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
164      LOG(ERROR) << "Server did not create the top-level autofill node. We "
165                 << "might be running against an out-of-date server.";
166      return false;
167    }
168
169    if (!TraverseAndAssociateChromeAutofillProfiles(&trans, autofill_root,
170            profiles.get(), &bundle.current_profiles,
171            &bundle.updated_profiles,
172            &bundle.new_profiles,
173            &bundle.profiles_to_delete) ||
174        !TraverseAndAssociateAllSyncNodes(&trans, autofill_root, &bundle)) {
175      return false;
176    }
177  }
178
179  if (!SaveChangesToWebData(bundle)) {
180    LOG(ERROR) << "Failed to update autofill entries.";
181    return false;
182  }
183
184  if (sync_service_->GetAutofillMigrationState() !=
185     syncable::MIGRATED) {
186    syncable::AutofillMigrationDebugInfo debug_info;
187    debug_info.autofill_profile_added_during_migration =
188        number_of_profiles_created_;
189    sync_service_->SetAutofillMigrationDebugInfo(
190        syncable::AutofillMigrationDebugInfo::PROFILES_ADDED,
191        debug_info);
192    sync_service_->SetAutofillMigrationState(
193        syncable::MIGRATED);
194  }
195
196  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
197      new DoOptimisticRefreshForAutofill(personal_data_));
198  return true;
199}
200
201bool AutofillProfileModelAssociator::DisassociateModels() {
202  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
203  id_map_.clear();
204  id_map_inverse_.clear();
205  return true;
206}
207
208// Helper to compare the local value and cloud value of a field, merge into
209// the local value if they differ, and return whether the merge happened.
210bool AutofillProfileModelAssociator::MergeField(FormGroup* f,
211    AutofillFieldType t,
212    const std::string& specifics_field) {
213  if (UTF16ToUTF8(f->GetInfo(t)) == specifics_field)
214    return false;
215  f->SetInfo(t, UTF8ToUTF16(specifics_field));
216  return true;
217}
218bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
219    bool *has_nodes) {
220  CHECK_NE(has_nodes, reinterpret_cast<bool*>(NULL));
221  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
222
223  sync_api::ReadNode node(&trans);
224
225  if (!node.InitByTagLookup(kAutofillProfileTag)) {
226    LOG(ERROR) << "Sever did not create a top level node"
227               << "Out of data server or autofill type not enabled";
228    return false;
229  }
230
231  *has_nodes = sync_api::kInvalidId != node.GetFirstChildId();
232  return true;
233}
234// static
235bool AutofillProfileModelAssociator::OverwriteProfileWithServerData(
236    AutofillProfile* merge_into,
237    const sync_pb::AutofillProfileSpecifics& specifics) {
238  bool diff = false;
239  AutofillProfile* p = merge_into;
240  const sync_pb::AutofillProfileSpecifics& s(specifics);
241  diff = MergeField(p, NAME_FIRST, s.name_first()) || diff;
242  diff = MergeField(p, NAME_LAST, s.name_last()) || diff;
243  diff = MergeField(p, NAME_MIDDLE, s.name_middle()) || diff;
244  diff = MergeField(p, ADDRESS_HOME_LINE1, s.address_home_line1()) || diff;
245  diff = MergeField(p, ADDRESS_HOME_LINE2, s.address_home_line2()) || diff;
246  diff = MergeField(p, ADDRESS_HOME_CITY, s.address_home_city()) || diff;
247  diff = MergeField(p, ADDRESS_HOME_STATE, s.address_home_state()) || diff;
248  diff = MergeField(p, ADDRESS_HOME_COUNTRY, s.address_home_country()) || diff;
249  diff = MergeField(p, ADDRESS_HOME_ZIP, s.address_home_zip()) || diff;
250  diff = MergeField(p, EMAIL_ADDRESS, s.email_address()) || diff;
251  diff = MergeField(p, COMPANY_NAME, s.company_name()) || diff;
252  diff = MergeField(p, PHONE_FAX_WHOLE_NUMBER, s.phone_fax_whole_number())
253      || diff;
254  diff = MergeField(p, PHONE_HOME_WHOLE_NUMBER, s.phone_home_whole_number())
255      || diff;
256  return diff;
257}
258
259
260int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile(
261    sync_api::WriteTransaction* trans,
262    const sync_api::BaseNode& autofill_root,
263    const AutofillProfile& profile_from_db,
264    std::set<std::string>* current_profiles) {
265  int64 sync_child_id = autofill_root.GetFirstChildId();
266  while (sync_child_id != sync_api::kInvalidId) {
267    ReadNode read_node(trans);
268    AutofillProfile p;
269    if (!read_node.InitByIdLookup(sync_child_id)) {
270      LOG(ERROR) << "unable to find the id given by getfirst child " <<
271        sync_child_id;
272      return sync_api::kInvalidId;
273    }
274    const sync_pb::AutofillProfileSpecifics& autofill_specifics(
275        read_node.GetAutofillProfileSpecifics());
276
277    // This find should be fast as the set uses tree.
278    if (current_profiles->find(autofill_specifics.guid())
279        == current_profiles->end()) {
280      OverwriteProfileWithServerData(&p, autofill_specifics);
281      if (p.Compare(profile_from_db) == 0) {
282        return sync_child_id;
283      }
284    }
285    sync_child_id = read_node.GetSuccessorId();
286  }
287
288  return sync_api::kInvalidId;
289}
290bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded(
291    sync_api::WriteTransaction* trans,
292    const sync_api::BaseNode& autofill_root,
293    const AutofillProfile& profile,
294    std::vector<AutofillProfile*>* new_profiles,
295    std::set<std::string>* current_profiles,
296    std::vector<std::string>* profiles_to_delete) {
297
298  int64 sync_node_id = FindSyncNodeWithProfile(trans,
299      autofill_root,
300      profile,
301      current_profiles);
302  if (sync_node_id != sync_api::kInvalidId) {
303    // In case of duplicates throw away the local profile and apply the
304    // server profile.(The only difference between the 2 profiles are the guids)
305    profiles_to_delete->push_back(profile.guid());
306    sync_api::ReadNode read_node(trans);
307    if (!read_node.InitByIdLookup(sync_node_id)) {
308      LOG(ERROR);
309      return false;
310    }
311    const sync_pb::AutofillProfileSpecifics& autofill_specifics(
312        read_node.GetAutofillProfileSpecifics());
313    if (guid::IsValidGUID(autofill_specifics.guid()) == false) {
314      NOTREACHED() << "Guid in the web db is invalid " <<
315          autofill_specifics.guid();
316      return false;
317    }
318    AutofillProfile* p = new AutofillProfile(autofill_specifics.guid());
319    OverwriteProfileWithServerData(p, autofill_specifics);
320    new_profiles->push_back(p);
321    std::string guid = autofill_specifics.guid();
322    Associate(&guid, sync_node_id);
323    current_profiles->insert(autofill_specifics.guid());
324    VLOG(2) << "[AUTOFILL MIGRATION]"
325            << "Found in sync db but with a different guid: "
326            << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
327            << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
328            << "New guid " << autofill_specifics.guid() << " sync node id "
329            << sync_node_id << " so associating. Profile to be deleted "
330            << profile.guid();
331  } else {
332    sync_api::WriteNode node(trans);
333
334    // The profile.guid() is expected to be a valid guid. The caller is expected
335    // to pass in a valid profile object with a valid guid. Having to check in
336    // 2 places(the caller and here) is not optimal.
337    if (!node.InitUniqueByCreation(
338             syncable::AUTOFILL_PROFILE, autofill_root, profile.guid())) {
339      LOG(ERROR) << "Failed to create autofill sync node.";
340      return false;
341    }
342    node.SetTitle(UTF8ToWide(profile.guid()));
343    VLOG(2) << "[AUTOFILL MIGRATION]"
344            << "NOT Found in sync db  "
345            << UTF16ToUTF8(profile.GetInfo(NAME_FIRST))
346            << UTF16ToUTF8(profile.GetInfo(NAME_LAST))
347            << profile.guid()
348            << " so creating a new sync node. Sync node id "
349            << node.GetId();
350    AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node);
351    current_profiles->insert(profile.guid());
352    std::string guid = profile.guid();
353    Associate(&guid, node.GetId());
354    number_of_profiles_created_++;
355  }
356  return true;
357}
358
359bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
360    sync_api::WriteTransaction* write_trans,
361    const sync_api::ReadNode& autofill_root,
362    DataBundle* bundle) {
363  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
364  VLOG(1) << "[AUTOFILL MIGRATION] "
365          << " Iterating over sync nodes of autofill profile root node";
366
367  int64 sync_child_id = autofill_root.GetFirstChildId();
368  while (sync_child_id != sync_api::kInvalidId) {
369    ReadNode sync_child(write_trans);
370    if (!sync_child.InitByIdLookup(sync_child_id)) {
371      LOG(ERROR) << "Failed to fetch child node.";
372      return false;
373    }
374    const sync_pb::AutofillProfileSpecifics& autofill(
375        sync_child.GetAutofillProfileSpecifics());
376
377    AddNativeProfileIfNeeded(autofill, bundle, sync_child);
378
379    sync_child_id = sync_child.GetSuccessorId();
380  }
381  return true;
382}
383
384void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
385    const sync_pb::AutofillProfileSpecifics& profile,
386    DataBundle* bundle,
387    const sync_api::ReadNode& node) {
388  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
389
390  VLOG(2) << "[AUTOFILL MIGRATION] "
391          << "Trying to lookup "
392          << profile.name_first()
393          << " "
394          << profile.name_last()
395          << "sync node id " << node.GetId()
396          << " Guid " << profile.guid()
397          << " in the web db";
398
399  if (guid::IsValidGUID(profile.guid()) == false) {
400    DCHECK(false) << "Guid in the sync db is invalid " << profile.guid();
401    return;
402  }
403
404  if (bundle->current_profiles.find(profile.guid()) ==
405      bundle->current_profiles.end()) {
406    std::string guid(profile.guid());
407    Associate(&guid, node.GetId());
408    AutofillProfile* p = new AutofillProfile(profile.guid());
409    OverwriteProfileWithServerData(p, profile);
410    bundle->new_profiles.push_back(p);
411    VLOG(2) << "[AUTOFILL MIGRATION] "
412            << " Did not find one so creating it on web db";
413  } else {
414    VLOG(2) << "[AUTOFILL MIGRATION] "
415            << " Found it on web db. Moving on ";
416  }
417}
418
419bool AutofillProfileModelAssociator::SaveChangesToWebData(
420    const DataBundle& bundle) {
421  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
422
423  if (IsAbortPending())
424    return false;
425
426  for (size_t i = 0; i < bundle.new_profiles.size(); i++) {
427    if (IsAbortPending())
428      return false;
429    if (!web_database_->GetAutofillTable()->AddAutofillProfile(
430        *bundle.new_profiles[i]))
431      return false;
432  }
433
434  for (size_t i = 0; i < bundle.updated_profiles.size(); i++) {
435    if (IsAbortPending())
436      return false;
437    if (!web_database_->GetAutofillTable()->UpdateAutofillProfile(
438        *bundle.updated_profiles[i]))
439      return false;
440  }
441
442  for (size_t i = 0; i< bundle.profiles_to_delete.size(); ++i) {
443    if (IsAbortPending())
444      return false;
445    if (!web_database_->GetAutofillTable()->RemoveAutofillProfile(
446        bundle.profiles_to_delete[i]))
447      return false;
448  }
449  return true;
450}
451
452bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId(
453    const std::string& node_id,
454    sync_api::BaseNode* sync_node) {
455  return false;
456}
457
458void AutofillProfileModelAssociator::Associate(
459    const std::string* autofill,
460    int64 sync_id) {
461  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
462  DCHECK_NE(sync_api::kInvalidId, sync_id);
463  DCHECK(id_map_.find(*autofill) == id_map_.end());
464  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
465  id_map_[*autofill] = sync_id;
466  id_map_inverse_[sync_id] = *autofill;
467}
468
469void AutofillProfileModelAssociator::Disassociate(int64 sync_id) {
470  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
471  SyncIdToAutofillMap::iterator iter = id_map_inverse_.find(sync_id);
472  if (iter == id_map_inverse_.end())
473    return;
474  CHECK(id_map_.erase(iter->second));
475  id_map_inverse_.erase(iter);
476}
477
478int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId(
479    const std::string& autofill) {
480  AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
481  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
482}
483
484void AutofillProfileModelAssociator::AbortAssociation() {
485  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
486  base::AutoLock lock(abort_association_pending_lock_);
487  abort_association_pending_ = true;
488}
489
490const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId(
491    int64 sync_id) {
492  SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id);
493  return iter == id_map_inverse_.end() ? NULL : &(iter->second);
494}
495
496bool AutofillProfileModelAssociator::IsAbortPending() {
497  base::AutoLock lock(abort_association_pending_lock_);
498  return abort_association_pending_;
499}
500
501AutofillProfileModelAssociator::DataBundle::DataBundle() {}
502
503AutofillProfileModelAssociator::DataBundle::~DataBundle() {
504  STLDeleteElements(&new_profiles);
505}
506
507bool AutofillProfileModelAssociator::CryptoReadyIfNecessary() {
508  // We only access the cryptographer while holding a transaction.
509  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
510  syncable::ModelTypeSet encrypted_types;
511  sync_service_->GetEncryptedDataTypes(&encrypted_types);
512  return encrypted_types.count(syncable::AUTOFILL_PROFILE) == 0 ||
513         sync_service_->IsCryptographerReady(&trans);
514}
515
516}  // namespace browser_sync
517
518