syncapi.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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/engine/syncapi.h"
6
7#include "build/build_config.h"
8
9#include <bitset>
10#include <iomanip>
11#include <list>
12#include <string>
13#include <vector>
14
15#include "base/basictypes.h"
16#include "base/base64.h"
17#include "base/lock.h"
18#include "base/logging.h"
19#include "base/message_loop.h"
20#include "base/platform_thread.h"
21#include "base/scoped_ptr.h"
22#include "base/sha1.h"
23#include "base/string_util.h"
24#include "base/task.h"
25#include "base/utf_string_conversions.h"
26#include "chrome/browser/browser_process.h"
27#include "chrome/browser/browser_thread.h"
28#include "chrome/browser/sync/sync_constants.h"
29#include "chrome/browser/sync/engine/all_status.h"
30#include "chrome/browser/sync/engine/change_reorder_buffer.h"
31#include "chrome/browser/sync/engine/model_safe_worker.h"
32#include "chrome/browser/sync/engine/net/server_connection_manager.h"
33#include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
34#include "chrome/browser/sync/engine/syncer.h"
35#include "chrome/browser/sync/engine/syncer_thread.h"
36#include "chrome/browser/sync/notifier/server_notifier_thread.h"
37#include "chrome/browser/sync/notifier/state_writer.h"
38#include "chrome/browser/sync/protocol/app_specifics.pb.h"
39#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
40#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
41#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
42#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
43#include "chrome/browser/sync/protocol/password_specifics.pb.h"
44#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
45#include "chrome/browser/sync/protocol/session_specifics.pb.h"
46#include "chrome/browser/sync/protocol/service_constants.h"
47#include "chrome/browser/sync/protocol/sync.pb.h"
48#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
49#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
50#include "chrome/browser/sync/sessions/sync_session_context.h"
51#include "chrome/browser/sync/syncable/directory_manager.h"
52#include "chrome/browser/sync/syncable/syncable.h"
53#include "chrome/browser/sync/util/crypto_helpers.h"
54#include "chrome/common/chrome_switches.h"
55#include "chrome/common/deprecated/event_sys.h"
56#include "chrome/common/net/gaia/gaia_authenticator.h"
57#include "jingle/notifier/listener/mediator_thread_impl.h"
58#include "jingle/notifier/listener/notification_constants.h"
59#include "jingle/notifier/listener/talk_mediator.h"
60#include "jingle/notifier/listener/talk_mediator_impl.h"
61#include "net/base/network_change_notifier.h"
62
63using browser_sync::AllStatus;
64using browser_sync::Cryptographer;
65using browser_sync::KeyParams;
66using browser_sync::ModelSafeRoutingInfo;
67using browser_sync::ModelSafeWorker;
68using browser_sync::ModelSafeWorkerRegistrar;
69using browser_sync::ServerConnectionEvent;
70using browser_sync::ServerConnectionEventListener;
71using browser_sync::SyncEngineEvent;
72using browser_sync::SyncEngineEventListener;
73using browser_sync::Syncer;
74using browser_sync::SyncerThread;
75using browser_sync::kNigoriTag;
76using browser_sync::sessions::SyncSessionContext;
77using notifier::TalkMediator;
78using notifier::TalkMediatorImpl;
79using std::list;
80using std::hex;
81using std::string;
82using std::vector;
83using syncable::Directory;
84using syncable::DirectoryManager;
85using syncable::Entry;
86using syncable::SPECIFICS;
87
88typedef GoogleServiceAuthError AuthError;
89
90static const int kThreadExitTimeoutMsec = 60000;
91static const int kSSLPort = 443;
92
93#if defined(OS_CHROMEOS)
94static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
95#endif  // OS_CHROMEOS
96
97// We manage the lifetime of sync_api::SyncManager::SyncInternal ourselves.
98DISABLE_RUNNABLE_METHOD_REFCOUNT(sync_api::SyncManager::SyncInternal);
99
100namespace sync_api {
101
102static const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
103    FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
104static const char kDefaultNameForNewNodes[] = " ";
105
106// The list of names which are reserved for use by the server.
107static const char* kForbiddenServerNames[] = { "", ".", ".." };
108
109//////////////////////////////////////////////////////////////////////////
110// Static helper functions.
111
112// Helper function to look up the int64 metahandle of an object given the ID
113// string.
114static int64 IdToMetahandle(syncable::BaseTransaction* trans,
115                            const syncable::Id& id) {
116  syncable::Entry entry(trans, syncable::GET_BY_ID, id);
117  if (!entry.good())
118    return kInvalidId;
119  return entry.Get(syncable::META_HANDLE);
120}
121
122// Checks whether |name| is a server-illegal name followed by zero or more space
123// characters.  The three server-illegal names are the empty string, dot, and
124// dot-dot.  Very long names (>255 bytes in UTF-8 Normalization Form C) are
125// also illegal, but are not considered here.
126static bool IsNameServerIllegalAfterTrimming(const std::string& name) {
127  size_t untrimmed_count = name.find_last_not_of(' ') + 1;
128  for (size_t i = 0; i < arraysize(kForbiddenServerNames); ++i) {
129    if (name.compare(0, untrimmed_count, kForbiddenServerNames[i]) == 0)
130      return true;
131  }
132  return false;
133}
134
135static bool EndsWithSpace(const std::string& string) {
136  return !string.empty() && *string.rbegin() == ' ';
137}
138
139// When taking a name from the syncapi, append a space if it matches the
140// pattern of a server-illegal name followed by zero or more spaces.
141static void SyncAPINameToServerName(const std::wstring& sync_api_name,
142                                    std::string* out) {
143  *out = WideToUTF8(sync_api_name);
144  if (IsNameServerIllegalAfterTrimming(*out))
145    out->append(" ");
146}
147
148// In the reverse direction, if a server name matches the pattern of a
149// server-illegal name followed by one or more spaces, remove the trailing
150// space.
151static void ServerNameToSyncAPIName(const std::string& server_name,
152                                    std::wstring* out) {
153  int length_to_copy = server_name.length();
154  if (IsNameServerIllegalAfterTrimming(server_name) &&
155      EndsWithSpace(server_name))
156    --length_to_copy;
157  if (!UTF8ToWide(server_name.c_str(), length_to_copy, out)) {
158    NOTREACHED() << "Could not convert server name from UTF8 to wide";
159  }
160}
161
162UserShare::UserShare() {}
163
164UserShare::~UserShare() {}
165
166////////////////////////////////////
167// BaseNode member definitions.
168
169BaseNode::BaseNode() {}
170
171BaseNode::~BaseNode() {}
172
173std::string BaseNode::GenerateSyncableHash(
174    syncable::ModelType model_type, const std::string& client_tag) {
175  // blank PB with just the extension in it has termination symbol,
176  // handy for delimiter
177  sync_pb::EntitySpecifics serialized_type;
178  syncable::AddDefaultExtensionValue(model_type, &serialized_type);
179  std::string hash_input;
180  serialized_type.AppendToString(&hash_input);
181  hash_input.append(client_tag);
182
183  std::string encode_output;
184  CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
185  return encode_output;
186}
187
188sync_pb::PasswordSpecificsData* DecryptPasswordSpecifics(
189    const sync_pb::EntitySpecifics& specifics, Cryptographer* crypto) {
190  if (!specifics.HasExtension(sync_pb::password))
191    return NULL;
192  const sync_pb::EncryptedData& encrypted =
193      specifics.GetExtension(sync_pb::password).encrypted();
194  scoped_ptr<sync_pb::PasswordSpecificsData> data(
195      new sync_pb::PasswordSpecificsData);
196  if (!crypto->Decrypt(encrypted, data.get()))
197    return NULL;
198  return data.release();
199}
200
201bool BaseNode::DecryptIfNecessary(Entry* entry) {
202  if (GetIsFolder()) return true;  // Ignore the top-level password folder.
203  const sync_pb::EntitySpecifics& specifics =
204      entry->Get(syncable::SPECIFICS);
205  if (specifics.HasExtension(sync_pb::password)) {
206    scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
207        specifics, GetTransaction()->GetCryptographer()));
208    if (!data.get())
209      return false;
210    password_data_.swap(data);
211  }
212  return true;
213}
214
215int64 BaseNode::GetParentId() const {
216  return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
217                        GetEntry()->Get(syncable::PARENT_ID));
218}
219
220int64 BaseNode::GetId() const {
221  return GetEntry()->Get(syncable::META_HANDLE);
222}
223
224bool BaseNode::GetIsFolder() const {
225  return GetEntry()->Get(syncable::IS_DIR);
226}
227
228std::wstring BaseNode::GetTitle() const {
229  std::wstring result;
230  ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), &result);
231  return result;
232}
233
234GURL BaseNode::GetURL() const {
235  return GURL(GetBookmarkSpecifics().url());
236}
237
238int64 BaseNode::GetPredecessorId() const {
239  syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
240  if (id_string.IsRoot())
241    return kInvalidId;
242  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
243}
244
245int64 BaseNode::GetSuccessorId() const {
246  syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
247  if (id_string.IsRoot())
248    return kInvalidId;
249  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
250}
251
252int64 BaseNode::GetFirstChildId() const {
253  syncable::Directory* dir = GetTransaction()->GetLookup();
254  syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
255  syncable::Id id_string =
256      dir->GetFirstChildId(trans, GetEntry()->Get(syncable::ID));
257  if (id_string.IsRoot())
258    return kInvalidId;
259  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
260}
261
262void BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
263  if (!output)
264    return;
265  const std::string& favicon = GetBookmarkSpecifics().favicon();
266  output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
267      reinterpret_cast<const unsigned char*>(favicon.data() +
268                                             favicon.length()));
269}
270
271int64 BaseNode::GetExternalId() const {
272  return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
273}
274
275const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
276  DCHECK(GetModelType() == syncable::APPS);
277  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::app);
278}
279
280const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
281  DCHECK(GetModelType() == syncable::AUTOFILL);
282  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill);
283}
284
285const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
286  DCHECK(GetModelType() == syncable::BOOKMARKS);
287  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::bookmark);
288}
289
290const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
291  DCHECK(GetModelType() == syncable::NIGORI);
292  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::nigori);
293}
294
295const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
296  DCHECK(GetModelType() == syncable::PASSWORDS);
297  DCHECK(password_data_.get());
298  return *password_data_;
299}
300
301const sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const {
302  DCHECK(GetModelType() == syncable::PREFERENCES);
303  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::preference);
304}
305
306const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
307  DCHECK(GetModelType() == syncable::THEMES);
308  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::theme);
309}
310
311const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
312  DCHECK(GetModelType() == syncable::TYPED_URLS);
313  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::typed_url);
314}
315
316const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
317  DCHECK(GetModelType() == syncable::EXTENSIONS);
318  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::extension);
319}
320
321const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
322  DCHECK(GetModelType() == syncable::SESSIONS);
323  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::session);
324}
325
326syncable::ModelType BaseNode::GetModelType() const {
327  return GetEntry()->GetModelType();
328}
329
330////////////////////////////////////
331// WriteNode member definitions
332void WriteNode::SetIsFolder(bool folder) {
333  if (entry_->Get(syncable::IS_DIR) == folder)
334    return;  // Skip redundant changes.
335
336  entry_->Put(syncable::IS_DIR, folder);
337  MarkForSyncing();
338}
339
340void WriteNode::SetTitle(const std::wstring& title) {
341  std::string server_legal_name;
342  SyncAPINameToServerName(title, &server_legal_name);
343
344  string old_name = entry_->Get(syncable::NON_UNIQUE_NAME);
345
346  if (server_legal_name == old_name)
347    return;  // Skip redundant changes.
348
349  entry_->Put(syncable::NON_UNIQUE_NAME, server_legal_name);
350  MarkForSyncing();
351}
352
353void WriteNode::SetURL(const GURL& url) {
354  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
355  new_value.set_url(url.spec());
356  SetBookmarkSpecifics(new_value);
357}
358
359void WriteNode::SetAppSpecifics(
360    const sync_pb::AppSpecifics& new_value) {
361  DCHECK(GetModelType() == syncable::APPS);
362  PutAppSpecificsAndMarkForSyncing(new_value);
363}
364
365void WriteNode::SetAutofillSpecifics(
366    const sync_pb::AutofillSpecifics& new_value) {
367  DCHECK(GetModelType() == syncable::AUTOFILL);
368  PutAutofillSpecificsAndMarkForSyncing(new_value);
369}
370
371void WriteNode::PutAutofillSpecificsAndMarkForSyncing(
372    const sync_pb::AutofillSpecifics& new_value) {
373  sync_pb::EntitySpecifics entity_specifics;
374  entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value);
375  PutSpecificsAndMarkForSyncing(entity_specifics);
376}
377
378void WriteNode::SetBookmarkSpecifics(
379    const sync_pb::BookmarkSpecifics& new_value) {
380  DCHECK(GetModelType() == syncable::BOOKMARKS);
381  PutBookmarkSpecificsAndMarkForSyncing(new_value);
382}
383
384void WriteNode::PutBookmarkSpecificsAndMarkForSyncing(
385    const sync_pb::BookmarkSpecifics& new_value) {
386  sync_pb::EntitySpecifics entity_specifics;
387  entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value);
388  PutSpecificsAndMarkForSyncing(entity_specifics);
389}
390
391void WriteNode::SetNigoriSpecifics(
392    const sync_pb::NigoriSpecifics& new_value) {
393  DCHECK(GetModelType() == syncable::NIGORI);
394  PutNigoriSpecificsAndMarkForSyncing(new_value);
395}
396
397void WriteNode::PutNigoriSpecificsAndMarkForSyncing(
398    const sync_pb::NigoriSpecifics& new_value) {
399  sync_pb::EntitySpecifics entity_specifics;
400  entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value);
401  PutSpecificsAndMarkForSyncing(entity_specifics);
402}
403
404void WriteNode::SetPasswordSpecifics(
405    const sync_pb::PasswordSpecificsData& data) {
406  DCHECK(GetModelType() == syncable::PASSWORDS);
407
408  sync_pb::PasswordSpecifics new_value;
409  if (!GetTransaction()->GetCryptographer()->Encrypt(
410      data,
411      new_value.mutable_encrypted())) {
412    NOTREACHED();
413  }
414
415  PutPasswordSpecificsAndMarkForSyncing(new_value);
416}
417
418void WriteNode::SetPreferenceSpecifics(
419    const sync_pb::PreferenceSpecifics& new_value) {
420  DCHECK(GetModelType() == syncable::PREFERENCES);
421  PutPreferenceSpecificsAndMarkForSyncing(new_value);
422}
423
424void WriteNode::SetThemeSpecifics(
425    const sync_pb::ThemeSpecifics& new_value) {
426  DCHECK(GetModelType() == syncable::THEMES);
427  PutThemeSpecificsAndMarkForSyncing(new_value);
428}
429
430void WriteNode::SetSessionSpecifics(
431    const sync_pb::SessionSpecifics& new_value) {
432  DCHECK(GetModelType() == syncable::SESSIONS);
433  PutSessionSpecificsAndMarkForSyncing(new_value);
434}
435
436
437void WriteNode::PutPasswordSpecificsAndMarkForSyncing(
438    const sync_pb::PasswordSpecifics& new_value) {
439  sync_pb::EntitySpecifics entity_specifics;
440  entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
441  PutSpecificsAndMarkForSyncing(entity_specifics);
442}
443
444void WriteNode::PutPreferenceSpecificsAndMarkForSyncing(
445    const sync_pb::PreferenceSpecifics& new_value) {
446  sync_pb::EntitySpecifics entity_specifics;
447  entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value);
448  PutSpecificsAndMarkForSyncing(entity_specifics);
449}
450
451void WriteNode::SetTypedUrlSpecifics(
452    const sync_pb::TypedUrlSpecifics& new_value) {
453  DCHECK(GetModelType() == syncable::TYPED_URLS);
454  PutTypedUrlSpecificsAndMarkForSyncing(new_value);
455}
456
457void WriteNode::SetExtensionSpecifics(
458    const sync_pb::ExtensionSpecifics& new_value) {
459  DCHECK(GetModelType() == syncable::EXTENSIONS);
460  PutExtensionSpecificsAndMarkForSyncing(new_value);
461}
462
463void WriteNode::PutAppSpecificsAndMarkForSyncing(
464    const sync_pb::AppSpecifics& new_value) {
465  sync_pb::EntitySpecifics entity_specifics;
466  entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value);
467  PutSpecificsAndMarkForSyncing(entity_specifics);
468}
469
470void WriteNode::PutThemeSpecificsAndMarkForSyncing(
471    const sync_pb::ThemeSpecifics& new_value) {
472  sync_pb::EntitySpecifics entity_specifics;
473  entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value);
474  PutSpecificsAndMarkForSyncing(entity_specifics);
475}
476
477void WriteNode::PutTypedUrlSpecificsAndMarkForSyncing(
478    const sync_pb::TypedUrlSpecifics& new_value) {
479  sync_pb::EntitySpecifics entity_specifics;
480  entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value);
481  PutSpecificsAndMarkForSyncing(entity_specifics);
482}
483
484void WriteNode::PutExtensionSpecificsAndMarkForSyncing(
485    const sync_pb::ExtensionSpecifics& new_value) {
486  sync_pb::EntitySpecifics entity_specifics;
487  entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value);
488  PutSpecificsAndMarkForSyncing(entity_specifics);
489}
490
491
492void WriteNode::PutSessionSpecificsAndMarkForSyncing(
493    const sync_pb::SessionSpecifics& new_value) {
494  sync_pb::EntitySpecifics entity_specifics;
495  entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value);
496  PutSpecificsAndMarkForSyncing(entity_specifics);
497}
498
499
500void WriteNode::PutSpecificsAndMarkForSyncing(
501    const sync_pb::EntitySpecifics& specifics) {
502  // Skip redundant changes.
503  if (specifics.SerializeAsString() ==
504      entry_->Get(SPECIFICS).SerializeAsString()) {
505    return;
506  }
507  entry_->Put(SPECIFICS, specifics);
508  MarkForSyncing();
509}
510
511void WriteNode::SetExternalId(int64 id) {
512  if (GetExternalId() != id)
513    entry_->Put(syncable::LOCAL_EXTERNAL_ID, id);
514}
515
516WriteNode::WriteNode(WriteTransaction* transaction)
517    : entry_(NULL), transaction_(transaction) {
518  DCHECK(transaction);
519}
520
521WriteNode::~WriteNode() {
522  delete entry_;
523}
524
525// Find an existing node matching the ID |id|, and bind this WriteNode to it.
526// Return true on success.
527bool WriteNode::InitByIdLookup(int64 id) {
528  DCHECK(!entry_) << "Init called twice";
529  DCHECK_NE(id, kInvalidId);
530  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
531                                      syncable::GET_BY_HANDLE, id);
532  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
533          DecryptIfNecessary(entry_));
534}
535
536// Find a node by client tag, and bind this WriteNode to it.
537// Return true if the write node was found, and was not deleted.
538// Undeleting a deleted node is possible by ClientTag.
539bool WriteNode::InitByClientTagLookup(syncable::ModelType model_type,
540                                      const std::string& tag) {
541  DCHECK(!entry_) << "Init called twice";
542  if (tag.empty())
543    return false;
544
545  const std::string hash = GenerateSyncableHash(model_type, tag);
546
547  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
548                                      syncable::GET_BY_CLIENT_TAG, hash);
549  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
550          DecryptIfNecessary(entry_));
551}
552
553bool WriteNode::InitByTagLookup(const std::string& tag) {
554  DCHECK(!entry_) << "Init called twice";
555  if (tag.empty())
556    return false;
557  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
558                                      syncable::GET_BY_SERVER_TAG, tag);
559  if (!entry_->good())
560    return false;
561  if (entry_->Get(syncable::IS_DEL))
562    return false;
563  syncable::ModelType model_type = GetModelType();
564  DCHECK(model_type == syncable::NIGORI);
565  return true;
566}
567
568void WriteNode::PutModelType(syncable::ModelType model_type) {
569  // Set an empty specifics of the appropriate datatype.  The presence
570  // of the specific extension will identify the model type.
571  DCHECK(GetModelType() == model_type ||
572         GetModelType() == syncable::UNSPECIFIED);  // Immutable once set.
573
574  sync_pb::EntitySpecifics specifics;
575  syncable::AddDefaultExtensionValue(model_type, &specifics);
576  PutSpecificsAndMarkForSyncing(specifics);
577  DCHECK(GetModelType() == model_type);
578}
579
580// Create a new node with default properties, and bind this WriteNode to it.
581// Return true on success.
582bool WriteNode::InitByCreation(syncable::ModelType model_type,
583                               const BaseNode& parent,
584                               const BaseNode* predecessor) {
585  DCHECK(!entry_) << "Init called twice";
586  // |predecessor| must be a child of |parent| or NULL.
587  if (predecessor && predecessor->GetParentId() != parent.GetId()) {
588    DCHECK(false);
589    return false;
590  }
591
592  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
593
594  // Start out with a dummy name.  We expect
595  // the caller to set a meaningful name after creation.
596  string dummy(kDefaultNameForNewNodes);
597
598  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
599                                      syncable::CREATE, parent_id, dummy);
600
601  if (!entry_->good())
602    return false;
603
604  // Entries are untitled folders by default.
605  entry_->Put(syncable::IS_DIR, true);
606
607  PutModelType(model_type);
608
609  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
610  PutPredecessor(predecessor);
611
612  return true;
613}
614
615// Create a new node with default properties and a client defined unique tag,
616// and bind this WriteNode to it.
617// Return true on success. If the tag exists in the database, then
618// we will attempt to undelete the node.
619// TODO(chron): Code datatype into hash tag.
620// TODO(chron): Is model type ever lost?
621bool WriteNode::InitUniqueByCreation(syncable::ModelType model_type,
622                                     const BaseNode& parent,
623                                     const std::string& tag) {
624  DCHECK(!entry_) << "Init called twice";
625
626  const std::string hash = GenerateSyncableHash(model_type, tag);
627
628  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
629
630  // Start out with a dummy name.  We expect
631  // the caller to set a meaningful name after creation.
632  string dummy(kDefaultNameForNewNodes);
633
634  // Check if we have this locally and need to undelete it.
635  scoped_ptr<syncable::MutableEntry> existing_entry(
636      new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
637                                 syncable::GET_BY_CLIENT_TAG, hash));
638
639  if (existing_entry->good()) {
640    if (existing_entry->Get(syncable::IS_DEL)) {
641      // Rules for undelete:
642      // BASE_VERSION: Must keep the same.
643      // ID: Essential to keep the same.
644      // META_HANDLE: Must be the same, so we can't "split" the entry.
645      // IS_DEL: Must be set to false, will cause reindexing.
646      //         This one is weird because IS_DEL is true for "update only"
647      //         items. It should be OK to undelete an update only.
648      // MTIME/CTIME: Seems reasonable to just leave them alone.
649      // IS_UNSYNCED: Must set this to true or face database insurrection.
650      //              We do this below this block.
651      // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION
652      //                      to SERVER_VERSION. We keep it the same here.
653      // IS_DIR: We'll leave it the same.
654      // SPECIFICS: Reset it.
655
656      existing_entry->Put(syncable::IS_DEL, false);
657
658      // Client tags are immutable and must be paired with the ID.
659      // If a server update comes down with an ID and client tag combo,
660      // and it already exists, always overwrite it and store only one copy.
661      // We have to undelete entries because we can't disassociate IDs from
662      // tags and updates.
663
664      existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy);
665      existing_entry->Put(syncable::PARENT_ID, parent_id);
666      entry_ = existing_entry.release();
667    } else {
668      return false;
669    }
670  } else {
671    entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
672                                        syncable::CREATE, parent_id, dummy);
673    if (!entry_->good()) {
674      return false;
675    }
676
677    // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
678    entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash);
679  }
680
681  // We don't support directory and tag combinations.
682  entry_->Put(syncable::IS_DIR, false);
683
684  // Will clear specifics data.
685  PutModelType(model_type);
686
687  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
688  PutPredecessor(NULL);
689
690  return true;
691}
692
693bool WriteNode::SetPosition(const BaseNode& new_parent,
694                            const BaseNode* predecessor) {
695  // |predecessor| must be a child of |new_parent| or NULL.
696  if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
697    DCHECK(false);
698    return false;
699  }
700
701  syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID);
702
703  // Filter out redundant changes if both the parent and the predecessor match.
704  if (new_parent_id == entry_->Get(syncable::PARENT_ID)) {
705    const syncable::Id& old = entry_->Get(syncable::PREV_ID);
706    if ((!predecessor && old.IsRoot()) ||
707        (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) {
708      return true;
709    }
710  }
711
712  // Atomically change the parent. This will fail if it would
713  // introduce a cycle in the hierarchy.
714  if (!entry_->Put(syncable::PARENT_ID, new_parent_id))
715    return false;
716
717  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
718  PutPredecessor(predecessor);
719
720  return true;
721}
722
723const syncable::Entry* WriteNode::GetEntry() const {
724  return entry_;
725}
726
727const BaseTransaction* WriteNode::GetTransaction() const {
728  return transaction_;
729}
730
731void WriteNode::Remove() {
732  entry_->Put(syncable::IS_DEL, true);
733  MarkForSyncing();
734}
735
736void WriteNode::PutPredecessor(const BaseNode* predecessor) {
737  syncable::Id predecessor_id = predecessor ?
738      predecessor->GetEntry()->Get(syncable::ID) : syncable::Id();
739  entry_->PutPredecessor(predecessor_id);
740  // Mark this entry as unsynced, to wake up the syncer.
741  MarkForSyncing();
742}
743
744void WriteNode::SetFaviconBytes(const vector<unsigned char>& bytes) {
745  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
746  new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size());
747  SetBookmarkSpecifics(new_value);
748}
749
750void WriteNode::MarkForSyncing() {
751  syncable::MarkForSyncing(entry_);
752}
753
754//////////////////////////////////////////////////////////////////////////
755// ReadNode member definitions
756ReadNode::ReadNode(const BaseTransaction* transaction)
757    : entry_(NULL), transaction_(transaction) {
758  DCHECK(transaction);
759}
760
761ReadNode::~ReadNode() {
762  delete entry_;
763}
764
765void ReadNode::InitByRootLookup() {
766  DCHECK(!entry_) << "Init called twice";
767  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
768  entry_ = new syncable::Entry(trans, syncable::GET_BY_ID, trans->root_id());
769  if (!entry_->good())
770    DCHECK(false) << "Could not lookup root node for reading.";
771}
772
773bool ReadNode::InitByIdLookup(int64 id) {
774  DCHECK(!entry_) << "Init called twice";
775  DCHECK_NE(id, kInvalidId);
776  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
777  entry_ = new syncable::Entry(trans, syncable::GET_BY_HANDLE, id);
778  if (!entry_->good())
779    return false;
780  if (entry_->Get(syncable::IS_DEL))
781    return false;
782  syncable::ModelType model_type = GetModelType();
783  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
784                  model_type == syncable::TOP_LEVEL_FOLDER)
785      << "SyncAPI InitByIdLookup referencing unusual object.";
786  return DecryptIfNecessary(entry_);
787}
788
789bool ReadNode::InitByClientTagLookup(syncable::ModelType model_type,
790                                     const std::string& tag) {
791  DCHECK(!entry_) << "Init called twice";
792  if (tag.empty())
793    return false;
794
795  const std::string hash = GenerateSyncableHash(model_type, tag);
796
797  entry_ = new syncable::Entry(transaction_->GetWrappedTrans(),
798                               syncable::GET_BY_CLIENT_TAG, hash);
799  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
800          DecryptIfNecessary(entry_));
801}
802
803const syncable::Entry* ReadNode::GetEntry() const {
804  return entry_;
805}
806
807const BaseTransaction* ReadNode::GetTransaction() const {
808  return transaction_;
809}
810
811bool ReadNode::InitByTagLookup(const std::string& tag) {
812  DCHECK(!entry_) << "Init called twice";
813  if (tag.empty())
814    return false;
815  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
816  entry_ = new syncable::Entry(trans, syncable::GET_BY_SERVER_TAG, tag);
817  if (!entry_->good())
818    return false;
819  if (entry_->Get(syncable::IS_DEL))
820    return false;
821  syncable::ModelType model_type = GetModelType();
822  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
823                  model_type == syncable::TOP_LEVEL_FOLDER)
824      << "SyncAPI InitByTagLookup referencing unusually typed object.";
825  return DecryptIfNecessary(entry_);
826}
827
828//////////////////////////////////////////////////////////////////////////
829// ReadTransaction member definitions
830ReadTransaction::ReadTransaction(UserShare* share)
831    : BaseTransaction(share),
832      transaction_(NULL),
833      close_transaction_(true) {
834  transaction_ = new syncable::ReadTransaction(GetLookup(), __FILE__, __LINE__);
835}
836
837ReadTransaction::ReadTransaction(UserShare* share,
838                                 syncable::BaseTransaction* trans)
839    : BaseTransaction(share),
840      transaction_(trans),
841      close_transaction_(false) {}
842
843ReadTransaction::~ReadTransaction() {
844  if (close_transaction_) {
845    delete transaction_;
846  }
847}
848
849syncable::BaseTransaction* ReadTransaction::GetWrappedTrans() const {
850  return transaction_;
851}
852
853//////////////////////////////////////////////////////////////////////////
854// WriteTransaction member definitions
855WriteTransaction::WriteTransaction(UserShare* share)
856    : BaseTransaction(share),
857      transaction_(NULL) {
858  transaction_ = new syncable::WriteTransaction(GetLookup(), syncable::SYNCAPI,
859                                                __FILE__, __LINE__);
860}
861
862WriteTransaction::~WriteTransaction() {
863  delete transaction_;
864}
865
866syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
867  return transaction_;
868}
869
870// A GaiaAuthenticator that uses HttpPostProviders instead of CURL.
871class BridgedGaiaAuthenticator : public gaia::GaiaAuthenticator {
872 public:
873  BridgedGaiaAuthenticator(const string& user_agent, const string& service_id,
874                           const string& gaia_url,
875                           HttpPostProviderFactory* factory)
876      : GaiaAuthenticator(user_agent, service_id, gaia_url),
877        gaia_source_(user_agent), post_factory_(factory) {
878  }
879
880  virtual ~BridgedGaiaAuthenticator() {
881  }
882
883  virtual bool Post(const GURL& url, const string& post_body,
884                    unsigned long* response_code, string* response_body) {
885    string connection_url = "https://";
886    connection_url += url.host();
887    connection_url += url.path();
888    HttpPostProviderInterface* http = post_factory_->Create();
889    http->SetUserAgent(gaia_source_.c_str());
890    // SSL is on 443 for Gaia Posts always.
891    http->SetURL(connection_url.c_str(), kSSLPort);
892    http->SetPostPayload("application/x-www-form-urlencoded",
893                         post_body.length(), post_body.c_str());
894
895    int os_error_code = 0;
896    int int_response_code = 0;
897    if (!http->MakeSynchronousPost(&os_error_code, &int_response_code)) {
898      VLOG(1) << "Http POST failed, error returns: " << os_error_code;
899      return false;
900    }
901    *response_code = static_cast<int>(int_response_code);
902    response_body->assign(http->GetResponseContent(),
903                          http->GetResponseContentLength());
904    post_factory_->Destroy(http);
905    return true;
906  }
907
908  virtual int GetBackoffDelaySeconds(int current_backoff_delay) {
909    return SyncerThread::GetRecommendedDelaySeconds(current_backoff_delay);
910  }
911 private:
912  const std::string gaia_source_;
913  scoped_ptr<HttpPostProviderFactory> post_factory_;
914  DISALLOW_COPY_AND_ASSIGN(BridgedGaiaAuthenticator);
915};
916
917SyncManager::ChangeRecord::ChangeRecord()
918    : id(kInvalidId), action(ACTION_ADD) {}
919
920SyncManager::ChangeRecord::~ChangeRecord() {}
921
922SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
923    const sync_pb::PasswordSpecificsData& data)
924    : unencrypted_(data) {
925}
926
927SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
928
929//////////////////////////////////////////////////////////////////////////
930// SyncManager's implementation: SyncManager::SyncInternal
931class SyncManager::SyncInternal
932    : public net::NetworkChangeNotifier::Observer,
933      public TalkMediator::Delegate,
934      public sync_notifier::StateWriter,
935      public browser_sync::ChannelEventHandler<syncable::DirectoryChangeEvent>,
936      public SyncEngineEventListener,
937      public ServerConnectionEventListener {
938  static const int kDefaultNudgeDelayMilliseconds;
939  static const int kPreferencesNudgeDelayMilliseconds;
940 public:
941  explicit SyncInternal(SyncManager* sync_manager)
942      : core_message_loop_(NULL),
943        observer_(NULL),
944        sync_manager_(sync_manager),
945        registrar_(NULL),
946        notification_pending_(false),
947        initialized_(false),
948        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
949    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
950  }
951
952  virtual ~SyncInternal() {
953    DCHECK(!core_message_loop_);
954    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
955  }
956
957  bool Init(const FilePath& database_location,
958            const std::string& sync_server_and_path,
959            int port,
960            bool use_ssl,
961            HttpPostProviderFactory* post_factory,
962            ModelSafeWorkerRegistrar* model_safe_worker_registrar,
963            const char* user_agent,
964            const SyncCredentials& credentials,
965            const notifier::NotifierOptions& notifier_options,
966            const std::string& restored_key_for_bootstrapping,
967            bool setup_for_test_mode);
968
969  // Sign into sync with given credentials.
970  // We do not verify the tokens given. After this call, the tokens are set
971  // and the sync DB is open. True if successful, false if something
972  // went wrong.
973  bool SignIn(const SyncCredentials& credentials);
974
975  // Update tokens that we're using in Sync. Email must stay the same.
976  void UpdateCredentials(const SyncCredentials& credentials);
977
978  // Tell the sync engine to start the syncing process.
979  void StartSyncing();
980
981  // Whether or not the Nigori node is encrypted using an explicit passphrase.
982  bool IsUsingExplicitPassphrase();
983
984  // Try to set the current passphrase to |passphrase|, and record whether
985  // it is an explicit passphrase or implicitly using gaia in the Nigori
986  // node.
987  void SetPassphrase(const std::string& passphrase, bool is_explicit);
988
989  // Call periodically from a database-safe thread to persist recent changes
990  // to the syncapi model.
991  void SaveChanges();
992
993  // This listener is called upon completion of a syncable transaction, and
994  // builds the list of sync-engine initiated changes that will be forwarded to
995  // the SyncManager's Observers.
996  virtual void HandleChannelEvent(const syncable::DirectoryChangeEvent& event);
997  void HandleTransactionCompleteChangeEvent(
998      const syncable::DirectoryChangeEvent& event);
999  void HandleTransactionEndingChangeEvent(
1000      const syncable::DirectoryChangeEvent& event);
1001  void HandleCalculateChangesChangeEventFromSyncApi(
1002      const syncable::DirectoryChangeEvent& event);
1003  void HandleCalculateChangesChangeEventFromSyncer(
1004      const syncable::DirectoryChangeEvent& event);
1005
1006  // Listens for notifications from the ServerConnectionManager
1007  virtual void OnServerConnectionEvent(const ServerConnectionEvent& event);
1008
1009  // Open the directory named with username_for_share
1010  bool OpenDirectory();
1011
1012  // Login to the talk mediator with the given credentials.
1013  void TalkMediatorLogin(
1014      const std::string& email, const std::string& token);
1015
1016  // TalkMediator::Delegate implementation.
1017  virtual void OnNotificationStateChange(
1018      bool notifications_enabled);
1019
1020  virtual void OnIncomingNotification(
1021      const IncomingNotificationData& notification_data);
1022
1023  virtual void OnOutgoingNotification();
1024
1025  // sync_notifier::StateWriter implementation.
1026  virtual void WriteState(const std::string& state);
1027
1028  // Accessors for the private members.
1029  DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
1030  SyncAPIServerConnectionManager* connection_manager() {
1031    return connection_manager_.get();
1032  }
1033  SyncerThread* syncer_thread() { return syncer_thread_.get(); }
1034  TalkMediator* talk_mediator() { return talk_mediator_.get(); }
1035  void set_observer(SyncManager::Observer* observer) { observer_ = observer; }
1036  UserShare* GetUserShare() { return &share_; }
1037
1038  // Return the currently active (validated) username for use with syncable
1039  // types.
1040  const std::string& username_for_share() const {
1041    return share_.name;
1042  }
1043
1044  // Note about SyncManager::Status implementation: Status is a trimmed
1045  // down AllStatus::Status, augmented with authentication failure information
1046  // gathered from the internal AuthWatcher. The sync UI itself hooks up to
1047  // various sources like the AuthWatcher individually, but with syncapi we try
1048  // to keep everything status-related in one place. This means we have to
1049  // privately manage state about authentication failures, and whenever the
1050  // status or status summary is requested we aggregate this state with
1051  // AllStatus::Status information.
1052  Status ComputeAggregatedStatus();
1053  Status::Summary ComputeAggregatedStatusSummary();
1054
1055  // See SyncManager::Shutdown for information.
1056  void Shutdown();
1057
1058  // Whether we're initialized to the point of being able to accept changes
1059  // (and hence allow transaction creation). See initialized_ for details.
1060  bool initialized() const {
1061    AutoLock lock(initialized_mutex_);
1062    return initialized_;
1063  }
1064
1065  void SetExtraChangeRecordData(int64 id,
1066                                syncable::ModelType type,
1067                                ChangeReorderBuffer* buffer,
1068                                Cryptographer* cryptographer,
1069                                const syncable::EntryKernel& original,
1070                                bool existed_before,
1071                                bool exists_now);
1072
1073  // Called only by our NetworkChangeNotifier.
1074  virtual void OnIPAddressChanged();
1075
1076  bool InitialSyncEndedForAllEnabledTypes() {
1077    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1078    if (!lookup.good()) {
1079      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1080      return false;
1081    }
1082
1083    ModelSafeRoutingInfo enabled_types;
1084    registrar_->GetModelSafeRoutingInfo(&enabled_types);
1085    for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
1086        i != enabled_types.end(); ++i) {
1087      if (!lookup->initial_sync_ended_for_type(i->first))
1088        return false;
1089    }
1090    return true;
1091  }
1092
1093  // SyncEngineEventListener implementation.
1094  virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
1095 private:
1096  // Helper to handle the details of initializing the TalkMediator.
1097  // Must be called only after OpenDirectory() is called.
1098  void InitializeTalkMediator();
1099
1100  // Helper to call OnAuthError when no authentication credentials are
1101  // available.
1102  void RaiseAuthNeededEvent();
1103
1104  // Helper to set initialized_ to true and raise an event to clients to notify
1105  // that initialization is complete and it is safe to send us changes. If
1106  // already initialized, this is a no-op.
1107  void MarkAndNotifyInitializationComplete();
1108
1109  // If there's a pending notification to be sent, either from the
1110  // new_pending_notification flag or a previous unsuccessfully sent
1111  // notification, tries to send a notification.
1112  void SendPendingXMPPNotification(bool new_pending_notification);
1113
1114  // Determine if the parents or predecessors differ between the old and new
1115  // versions of an entry stored in |a| and |b|.  Note that a node's index may
1116  // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
1117  // the relative order is unchanged).  To handle such cases, we rely on the
1118  // caller to treat a position update on any sibling as updating the positions
1119  // of all siblings.
1120  static bool VisiblePositionsDiffer(const syncable::EntryKernel& a,
1121                                     const syncable::Entry& b) {
1122    // If the datatype isn't one where the browser model cares about position,
1123    // don't bother notifying that data model of position-only changes.
1124    if (!b.ShouldMaintainPosition())
1125      return false;
1126    if (a.ref(syncable::NEXT_ID) != b.Get(syncable::NEXT_ID))
1127      return true;
1128    if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID))
1129      return true;
1130    return false;
1131  }
1132
1133  // Determine if any of the fields made visible to clients of the Sync API
1134  // differ between the versions of an entry stored in |a| and |b|. A return
1135  // value of false means that it should be OK to ignore this change.
1136  static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a,
1137                                      const syncable::Entry& b) {
1138    syncable::ModelType model_type = b.GetModelType();
1139    // Suppress updates to items that aren't tracked by any browser model.
1140    if (model_type == syncable::UNSPECIFIED ||
1141        model_type == syncable::TOP_LEVEL_FOLDER) {
1142      return false;
1143    }
1144    if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME))
1145      return true;
1146    if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR))
1147      return true;
1148    if (a.ref(SPECIFICS).SerializeAsString() !=
1149        b.Get(SPECIFICS).SerializeAsString()) {
1150      return true;
1151    }
1152    if (VisiblePositionsDiffer(a, b))
1153      return true;
1154    return false;
1155  }
1156
1157  bool ChangeBuffersAreEmpty() {
1158    for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1159      if (!change_buffers_[i].IsEmpty())
1160        return false;
1161    }
1162    return true;
1163  }
1164
1165  void CheckServerReachable() {
1166    if (connection_manager()) {
1167      connection_manager()->CheckServerReachable();
1168    } else {
1169      NOTREACHED() << "Should be valid connection manager!";
1170    }
1171  }
1172
1173  void ReEncryptEverything(WriteTransaction* trans);
1174
1175  // Initializes (bootstraps) the Cryptographer if NIGORI has finished
1176  // initial sync so that it can immediately start encrypting / decrypting.
1177  // If the restored key is incompatible with the current version of the NIGORI
1178  // node (which could happen if a restart occurred just after an update to
1179  // NIGORI was downloaded and the user must enter a new passphrase to decrypt)
1180  // then we will raise OnPassphraseRequired and set pending keys for
1181  // decryption.  Otherwise, the cryptographer is made ready (is_ready()).
1182  void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
1183
1184  // Helper for migration to new nigori proto to set
1185  // 'using_explicit_passphrase' in the NigoriSpecifics.
1186  // TODO(tim): Bug 62103.  Remove this after it has been pushed out to dev
1187  // channel users.
1188  void SetUsingExplicitPassphrasePrefForMigration();
1189
1190  // Checks for server reachabilty and requests a nudge.
1191  void OnIPAddressChangedImpl();
1192
1193  // We couple the DirectoryManager and username together in a UserShare member
1194  // so we can return a handle to share_ to clients of the API for use when
1195  // constructing any transaction type.
1196  UserShare share_;
1197
1198  MessageLoop* core_message_loop_;
1199
1200  // Observer registered via SetObserver/RemoveObserver.
1201  // WARNING: This can be NULL!
1202  SyncManager::Observer* observer_;
1203
1204  // The ServerConnectionManager used to abstract communication between the
1205  // client (the Syncer) and the sync server.
1206  scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
1207
1208  // The thread that runs the Syncer. Needs to be explicitly Start()ed.
1209  scoped_refptr<SyncerThread> syncer_thread_;
1210
1211  // Notification (xmpp) handler.
1212  scoped_ptr<TalkMediator> talk_mediator_;
1213
1214  // A multi-purpose status watch object that aggregates stats from various
1215  // sync components.
1216  AllStatus allstatus_;
1217
1218  // Each element of this array is a store of change records produced by
1219  // HandleChangeEvent during the CALCULATE_CHANGES step.  The changes are
1220  // segregated by model type, and are stored here to be processed and
1221  // forwarded to the observer slightly later, at the TRANSACTION_ENDING
1222  // step by HandleTransactionEndingChangeEvent. The list is cleared in the
1223  // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
1224  ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
1225
1226  // Bit vector keeping track of which models need to have their
1227  // OnChangesComplete observer set.
1228  //
1229  // Set by HandleTransactionEndingChangeEvent, cleared in
1230  // HandleTransactionCompleteChangeEvent.
1231  std::bitset<syncable::MODEL_TYPE_COUNT> model_has_change_;
1232
1233  // The event listener hookup that is registered for HandleChangeEvent.
1234  scoped_ptr<browser_sync::ChannelHookup<syncable::DirectoryChangeEvent> >
1235      dir_change_hookup_;
1236
1237  // The sync dir_manager to which we belong.
1238  SyncManager* const sync_manager_;
1239
1240  // The entity that provides us with information about which types to sync.
1241  // The instance is shared between the SyncManager and the Syncer.
1242  ModelSafeWorkerRegistrar* registrar_;
1243
1244  // True if the next SyncCycle should notify peers of an update.
1245  bool notification_pending_;
1246
1247  // Set to true once Init has been called, and we know of an authenticated
1248  // valid) username either from a fresh authentication attempt (as in
1249  // first-use case) or from a previous attempt stored in our UserSettings
1250  // (as in the steady-state), and the syncable::Directory has been opened,
1251  // meaning we are ready to accept changes.  Protected by initialized_mutex_
1252  // as it can get read/set by both the SyncerThread and the AuthWatcherThread.
1253  bool initialized_;
1254  mutable Lock initialized_mutex_;
1255
1256  notifier::NotifierOptions notifier_options_;
1257
1258  // True if the SyncManager should be running in test mode (no syncer thread
1259  // actually communicating with the server).
1260  bool setup_for_test_mode_;
1261
1262  ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
1263};
1264const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
1265const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
1266
1267SyncManager::SyncManager() {
1268  data_ = new SyncInternal(this);
1269}
1270
1271bool SyncManager::Init(const FilePath& database_location,
1272                       const char* sync_server_and_path,
1273                       int sync_server_port,
1274                       bool use_ssl,
1275                       HttpPostProviderFactory* post_factory,
1276                       ModelSafeWorkerRegistrar* registrar,
1277                       const char* user_agent,
1278                       const SyncCredentials& credentials,
1279                       const notifier::NotifierOptions& notifier_options,
1280                       const std::string& restored_key_for_bootstrapping,
1281                       bool setup_for_test_mode) {
1282  DCHECK(post_factory);
1283  VLOG(1) << "SyncManager starting Init...";
1284  string server_string(sync_server_and_path);
1285  return data_->Init(database_location,
1286                     server_string,
1287                     sync_server_port,
1288                     use_ssl,
1289                     post_factory,
1290                     registrar,
1291                     user_agent,
1292                     credentials,
1293                     notifier_options,
1294                     restored_key_for_bootstrapping,
1295                     setup_for_test_mode);
1296}
1297
1298void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
1299  data_->UpdateCredentials(credentials);
1300}
1301
1302
1303bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
1304  return data_->InitialSyncEndedForAllEnabledTypes();
1305}
1306
1307void SyncManager::StartSyncing() {
1308  data_->StartSyncing();
1309}
1310
1311void SyncManager::SetPassphrase(const std::string& passphrase,
1312     bool is_explicit) {
1313  data_->SetPassphrase(passphrase, is_explicit);
1314}
1315
1316bool SyncManager::IsUsingExplicitPassphrase() {
1317  return data_ && data_->IsUsingExplicitPassphrase();
1318}
1319
1320bool SyncManager::RequestPause() {
1321  if (data_->syncer_thread())
1322    return data_->syncer_thread()->RequestPause();
1323  return false;
1324}
1325
1326bool SyncManager::RequestResume() {
1327  if (data_->syncer_thread())
1328    return data_->syncer_thread()->RequestResume();
1329  return false;
1330}
1331
1332void SyncManager::RequestNudge() {
1333  if (data_->syncer_thread())
1334    data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
1335}
1336
1337void SyncManager::RequestClearServerData() {
1338  if (data_->syncer_thread())
1339    data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kClearPrivateData);
1340}
1341
1342const std::string& SyncManager::GetAuthenticatedUsername() {
1343  DCHECK(data_);
1344  return data_->username_for_share();
1345}
1346
1347bool SyncManager::SyncInternal::Init(
1348    const FilePath& database_location,
1349    const std::string& sync_server_and_path,
1350    int port,
1351    bool use_ssl,
1352    HttpPostProviderFactory* post_factory,
1353    ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1354    const char* user_agent,
1355    const SyncCredentials& credentials,
1356    const notifier::NotifierOptions& notifier_options,
1357    const std::string& restored_key_for_bootstrapping,
1358    bool setup_for_test_mode) {
1359
1360  VLOG(1) << "Starting SyncInternal initialization.";
1361
1362  core_message_loop_ = MessageLoop::current();
1363  DCHECK(core_message_loop_);
1364  notifier_options_ = notifier_options;
1365  registrar_ = model_safe_worker_registrar;
1366  setup_for_test_mode_ = setup_for_test_mode;
1367
1368  share_.dir_manager.reset(new DirectoryManager(database_location));
1369
1370  connection_manager_.reset(new SyncAPIServerConnectionManager(
1371      sync_server_and_path, port, use_ssl, user_agent, post_factory));
1372
1373  connection_manager_->AddListener(this);
1374
1375  net::NetworkChangeNotifier::AddObserver(this);
1376  // TODO(akalin): CheckServerReachable() can block, which may cause jank if we
1377  // try to shut down sync.  Fix this.
1378  core_message_loop_->PostTask(FROM_HERE,
1379      method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
1380
1381  // Test mode does not use a syncer context or syncer thread.
1382  if (!setup_for_test_mode) {
1383    // Build a SyncSessionContext and store the worker in it.
1384    VLOG(1) << "Sync is bringing up SyncSessionContext.";
1385    std::vector<SyncEngineEventListener*> listeners;
1386    listeners.push_back(&allstatus_);
1387    listeners.push_back(this);
1388    SyncSessionContext* context = new SyncSessionContext(
1389        connection_manager_.get(),
1390        dir_manager(),
1391        model_safe_worker_registrar,
1392        listeners);
1393
1394    // The SyncerThread takes ownership of |context|.
1395    syncer_thread_ = new SyncerThread(context);
1396  }
1397
1398  bool signed_in = SignIn(credentials);
1399
1400  // Do this once the directory is opened.
1401  BootstrapEncryption(restored_key_for_bootstrapping);
1402  return signed_in;
1403}
1404
1405void SyncManager::SyncInternal::BootstrapEncryption(
1406    const std::string& restored_key_for_bootstrapping) {
1407  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1408  if (!lookup.good()) {
1409    NOTREACHED();
1410    return;
1411  }
1412
1413  if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1414    return;
1415
1416  Cryptographer* cryptographer = share_.dir_manager->cryptographer();
1417  cryptographer->Bootstrap(restored_key_for_bootstrapping);
1418
1419  ReadTransaction trans(GetUserShare());
1420  ReadNode node(&trans);
1421  if (!node.InitByTagLookup(kNigoriTag)) {
1422    NOTREACHED();
1423    return;
1424  }
1425
1426  const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
1427  if (!nigori.encrypted().blob().empty()) {
1428    if (cryptographer->CanDecrypt(nigori.encrypted())) {
1429      cryptographer->SetKeys(nigori.encrypted());
1430    } else {
1431      cryptographer->SetPendingKeys(nigori.encrypted());
1432      observer_->OnPassphraseRequired();
1433    }
1434  }
1435}
1436
1437void SyncManager::SyncInternal::StartSyncing() {
1438  if (syncer_thread())  // NULL during certain unittests.
1439    syncer_thread()->Start();  // Start the syncer thread. This won't actually
1440                               // result in any syncing until at least the
1441                               // DirectoryManager broadcasts the OPENED event,
1442                               // and a valid server connection is detected.
1443}
1444
1445void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
1446  // There is only one real time we need this mutex.  If we get an auth
1447  // success, and before the initial sync ends we get an auth failure.  In this
1448  // case we'll be listening to both the AuthWatcher and Syncer, and it's a race
1449  // between their respective threads to call MarkAndNotify.  We need to make
1450  // sure the observer is notified once and only once.
1451  {
1452    AutoLock lock(initialized_mutex_);
1453    if (initialized_)
1454      return;
1455    initialized_ = true;
1456  }
1457
1458  // Notify that initialization is complete.
1459  if (observer_)
1460    observer_->OnInitializationComplete();
1461}
1462
1463void SyncManager::SyncInternal::SendPendingXMPPNotification(
1464    bool new_pending_notification) {
1465  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1466  DCHECK_NE(notifier_options_.notification_method,
1467            notifier::NOTIFICATION_SERVER);
1468  notification_pending_ = notification_pending_ || new_pending_notification;
1469  if (!notification_pending_) {
1470    VLOG(1) << "Not sending notification: no pending notification";
1471    return;
1472  }
1473  if (!talk_mediator_.get()) {
1474    VLOG(1) << "Not sending notification: shutting down (talk_mediator_ is "
1475               "NULL)";
1476    return;
1477  }
1478  VLOG(1) << "Sending XMPP notification...";
1479  OutgoingNotificationData notification_data;
1480  notification_data.service_id = browser_sync::kSyncServiceId;
1481  notification_data.service_url = browser_sync::kSyncServiceUrl;
1482  notification_data.send_content = true;
1483  notification_data.priority = browser_sync::kSyncPriority;
1484  notification_data.write_to_cache_only = true;
1485  notification_data.service_specific_data =
1486      browser_sync::kSyncServiceSpecificData;
1487  notification_data.require_subscription = true;
1488  bool success = talk_mediator_->SendNotification(notification_data);
1489  if (success) {
1490    notification_pending_ = false;
1491    VLOG(1) << "Sent XMPP notification";
1492  } else {
1493    VLOG(1) << "Could not send XMPP notification";
1494  }
1495}
1496
1497bool SyncManager::SyncInternal::OpenDirectory() {
1498  DCHECK(!initialized()) << "Should only happen once";
1499
1500  bool share_opened = dir_manager()->Open(username_for_share());
1501  DCHECK(share_opened);
1502  if (!share_opened) {
1503    if (observer_)
1504      observer_->OnStopSyncingPermanently();
1505
1506    LOG(ERROR) << "Could not open share for:" << username_for_share();
1507    return false;
1508  }
1509
1510  // Database has to be initialized for the guid to be available.
1511  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1512  if (!lookup.good()) {
1513    NOTREACHED();
1514    return false;
1515  }
1516
1517  connection_manager()->set_client_id(lookup->cache_guid());
1518
1519  if (syncer_thread())
1520    syncer_thread()->CreateSyncer(username_for_share());
1521
1522  MarkAndNotifyInitializationComplete();
1523  dir_change_hookup_.reset(lookup->AddChangeObserver(this));
1524  return true;
1525}
1526
1527bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
1528  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1529  DCHECK(share_.name.empty());
1530  share_.name = credentials.email;
1531
1532  VLOG(1) << "Signing in user: " << username_for_share();
1533  if (!OpenDirectory())
1534    return false;
1535
1536  UpdateCredentials(credentials);
1537  return true;
1538}
1539
1540void SyncManager::SyncInternal::UpdateCredentials(
1541    const SyncCredentials& credentials) {
1542  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1543  DCHECK(share_.name == credentials.email);
1544  connection_manager()->set_auth_token(credentials.sync_token);
1545  TalkMediatorLogin(credentials.email, credentials.sync_token);
1546  CheckServerReachable();
1547  sync_manager_->RequestNudge();
1548}
1549
1550void SyncManager::SyncInternal::InitializeTalkMediator() {
1551  if (notifier_options_.notification_method ==
1552      notifier::NOTIFICATION_SERVER) {
1553    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1554    std::string state;
1555    if (lookup.good())
1556      state = lookup->GetAndClearNotificationState();
1557    else
1558      LOG(ERROR) << "Could not read notification state";
1559    if (VLOG_IS_ON(1)) {
1560      std::string encoded_state;
1561      base::Base64Encode(state, &encoded_state);
1562      VLOG(1) << "Read notification state: " << encoded_state;
1563    }
1564    sync_notifier::ServerNotifierThread* server_notifier_thread =
1565        new sync_notifier::ServerNotifierThread(
1566            notifier_options_, state, this);
1567    talk_mediator_.reset(
1568        new TalkMediatorImpl(server_notifier_thread,
1569                             notifier_options_.invalidate_xmpp_login,
1570                             notifier_options_.allow_insecure_connection));
1571  } else {
1572    notifier::MediatorThread* mediator_thread =
1573        new notifier::MediatorThreadImpl(notifier_options_);
1574    talk_mediator_.reset(
1575        new TalkMediatorImpl(mediator_thread,
1576                             notifier_options_.invalidate_xmpp_login,
1577                             notifier_options_.allow_insecure_connection));
1578    talk_mediator_->AddSubscribedServiceUrl(browser_sync::kSyncServiceUrl);
1579  }
1580  talk_mediator_->SetDelegate(this);
1581}
1582
1583void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
1584  if (observer_) {
1585    observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
1586  }
1587}
1588
1589void SyncManager::SyncInternal::SetUsingExplicitPassphrasePrefForMigration() {
1590  WriteTransaction trans(&share_);
1591  WriteNode node(&trans);
1592  if (!node.InitByTagLookup(kNigoriTag)) {
1593    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1594    NOTREACHED();
1595    return;
1596  }
1597  sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1598  specifics.set_using_explicit_passphrase(true);
1599  node.SetNigoriSpecifics(specifics);
1600}
1601
1602void SyncManager::SyncInternal::SetPassphrase(
1603    const std::string& passphrase, bool is_explicit) {
1604  Cryptographer* cryptographer = dir_manager()->cryptographer();
1605  KeyParams params = {"localhost", "dummy", passphrase};
1606  if (cryptographer->has_pending_keys()) {
1607    if (!cryptographer->DecryptPendingKeys(params)) {
1608      observer_->OnPassphraseRequired();
1609      return;
1610    }
1611
1612    // TODO(tim): If this is the first time the user has entered a passphrase
1613    // since the protocol changed to store passphrase preferences in the cloud,
1614    // make sure we update this preference. See bug 62103.
1615    if (is_explicit)
1616      SetUsingExplicitPassphrasePrefForMigration();
1617
1618    // Nudge the syncer so that passwords updates that were waiting for this
1619    // passphrase get applied as soon as possible.
1620    sync_manager_->RequestNudge();
1621  } else {
1622    WriteTransaction trans(GetUserShare());
1623    WriteNode node(&trans);
1624    if (!node.InitByTagLookup(kNigoriTag)) {
1625      // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1626      NOTREACHED();
1627      return;
1628    }
1629
1630    // Prevent an implicit SetPassphrase request from changing an explicitly
1631    // set passphrase.
1632    if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
1633      return;
1634
1635    cryptographer->AddKey(params);
1636
1637    // TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
1638    // messing with the Nigori node, because we can't call SetPassphrase until
1639    // download conditions are met vs Cryptographer init.  It seems like it's
1640    // safe to defer this work.
1641    sync_pb::NigoriSpecifics specifics;
1642    cryptographer->GetKeys(specifics.mutable_encrypted());
1643    specifics.set_using_explicit_passphrase(is_explicit);
1644    node.SetNigoriSpecifics(specifics);
1645    ReEncryptEverything(&trans);
1646  }
1647
1648  std::string bootstrap_token;
1649  cryptographer->GetBootstrapToken(&bootstrap_token);
1650  observer_->OnPassphraseAccepted(bootstrap_token);
1651}
1652
1653bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
1654  ReadTransaction trans(&share_);
1655  ReadNode node(&trans);
1656  if (!node.InitByTagLookup(kNigoriTag)) {
1657    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1658    NOTREACHED();
1659    return false;
1660  }
1661
1662  return node.GetNigoriSpecifics().using_explicit_passphrase();
1663}
1664
1665void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
1666  // TODO(tim): bug 59242.  We shouldn't lookup by data type and instead use
1667  // a protocol flag or existence of an EncryptedData message, but for now,
1668  // encryption is on if-and-only-if the type is passwords, and we haven't
1669  // ironed out the protocol for generic encryption.
1670  static const char* passwords_tag = "google_chrome_passwords";
1671  ReadNode passwords_root(trans);
1672  if (!passwords_root.InitByTagLookup(passwords_tag)) {
1673    LOG(WARNING) << "No passwords to reencrypt.";
1674    return;
1675  }
1676
1677  int64 child_id = passwords_root.GetFirstChildId();
1678  while (child_id != kInvalidId) {
1679    WriteNode child(trans);
1680    if (!child.InitByIdLookup(child_id)) {
1681      NOTREACHED();
1682      return;
1683    }
1684    child.SetPasswordSpecifics(child.GetPasswordSpecifics());
1685    child_id = child.GetSuccessorId();
1686  }
1687}
1688
1689SyncManager::~SyncManager() {
1690  delete data_;
1691}
1692
1693void SyncManager::SetObserver(Observer* observer) {
1694  data_->set_observer(observer);
1695}
1696
1697void SyncManager::RemoveObserver() {
1698  data_->set_observer(NULL);
1699}
1700
1701void SyncManager::Shutdown() {
1702  data_->Shutdown();
1703}
1704
1705void SyncManager::SyncInternal::Shutdown() {
1706  method_factory_.RevokeAll();
1707
1708  // We NULL out talk_mediator_ so that any tasks pumped below do not
1709  // trigger further XMPP actions.
1710  //
1711  // TODO(akalin): NULL the other member variables defensively, too.
1712  scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release());
1713
1714  if (syncer_thread()) {
1715    if (!syncer_thread()->Stop(kThreadExitTimeoutMsec)) {
1716      LOG(FATAL) << "Unable to stop the syncer, it won't be happy...";
1717    }
1718    syncer_thread_ = NULL;
1719  }
1720
1721  // Shutdown the xmpp buzz connection.
1722  if (talk_mediator.get()) {
1723    VLOG(1) << "P2P: Mediator logout started.";
1724    talk_mediator->Logout();
1725    VLOG(1) << "P2P: Mediator logout completed.";
1726    talk_mediator.reset();
1727    VLOG(1) << "P2P: Mediator destroyed.";
1728  }
1729
1730  // Pump any messages the auth watcher, syncer thread, or talk
1731  // mediator posted before they shut down. (See OnSyncEngineEvent(),
1732  // and HandleTalkMediatorEvent() for the
1733  // events that may be posted.)
1734  {
1735    CHECK(core_message_loop_);
1736    bool old_state = core_message_loop_->NestableTasksAllowed();
1737    core_message_loop_->SetNestableTasksAllowed(true);
1738    core_message_loop_->RunAllPending();
1739    core_message_loop_->SetNestableTasksAllowed(old_state);
1740  }
1741
1742  net::NetworkChangeNotifier::RemoveObserver(this);
1743
1744  connection_manager_->RemoveListener(this);
1745
1746  if (dir_manager()) {
1747    dir_manager()->FinalSaveChangesForAll();
1748    dir_manager()->Close(username_for_share());
1749  }
1750
1751  // Reset the DirectoryManager and UserSettings so they relinquish sqlite
1752  // handles to backing files.
1753  share_.dir_manager.reset();
1754
1755  // We don't want to process any more events.
1756  dir_change_hookup_.reset();
1757
1758  core_message_loop_ = NULL;
1759}
1760
1761void SyncManager::SyncInternal::OnIPAddressChanged() {
1762  VLOG(1) << "IP address change detected";
1763#if defined (OS_CHROMEOS)
1764  // TODO(tim): This is a hack to intentionally lose a race with flimflam at
1765  // shutdown, so we don't cause shutdown to wait for our http request.
1766  // http://crosbug.com/8429
1767  MessageLoop::current()->PostDelayedTask(FROM_HERE,
1768      method_factory_.NewRunnableMethod(&SyncInternal::OnIPAddressChangedImpl),
1769      kChromeOSNetworkChangeReactionDelayHackMsec);
1770#else
1771  OnIPAddressChangedImpl();
1772#endif  // defined(OS_CHROMEOS)
1773}
1774
1775void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
1776  // TODO(akalin): CheckServerReachable() can block, which may cause
1777  // jank if we try to shut down sync.  Fix this.
1778  connection_manager()->CheckServerReachable();
1779  sync_manager_->RequestNudge();
1780}
1781
1782// Listen to model changes, filter out ones initiated by the sync API, and
1783// saves the rest (hopefully just backend Syncer changes resulting from
1784// ApplyUpdates) to data_->changelist.
1785void SyncManager::SyncInternal::HandleChannelEvent(
1786    const syncable::DirectoryChangeEvent& event) {
1787  if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE) {
1788    // Safe to perform slow I/O operations now, go ahead and commit.
1789    HandleTransactionCompleteChangeEvent(event);
1790    return;
1791  } else if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_ENDING) {
1792    HandleTransactionEndingChangeEvent(event);
1793    return;
1794  } else if (event.todo == syncable::DirectoryChangeEvent::CALCULATE_CHANGES) {
1795    if (event.writer == syncable::SYNCAPI) {
1796      HandleCalculateChangesChangeEventFromSyncApi(event);
1797      return;
1798    }
1799    HandleCalculateChangesChangeEventFromSyncer(event);
1800    return;
1801  } else if (event.todo == syncable::DirectoryChangeEvent::SHUTDOWN) {
1802    dir_change_hookup_.reset();
1803  }
1804}
1805
1806void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
1807    const syncable::DirectoryChangeEvent& event) {
1808  // This notification happens immediately after the channel mutex is released
1809  // This allows work to be performed without holding the WriteTransaction lock
1810  // but before the transaction is finished.
1811  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE);
1812  if (!observer_)
1813    return;
1814
1815  // Call commit
1816  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1817    if (model_has_change_.test(i)) {
1818      observer_->OnChangesComplete(syncable::ModelTypeFromInt(i));
1819      model_has_change_.reset(i);
1820    }
1821  }
1822}
1823
1824void SyncManager::SyncInternal::OnServerConnectionEvent(
1825    const ServerConnectionEvent& event) {
1826  allstatus_.HandleServerConnectionEvent(event);
1827  if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) {
1828    if (event.connection_code ==
1829        browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
1830      if (observer_) {
1831        observer_->OnAuthError(AuthError::None());
1832      }
1833    }
1834
1835    if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
1836      if (observer_) {
1837        observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
1838      }
1839    }
1840  } else {
1841    DCHECK_EQ(ServerConnectionEvent::SHUTDOWN, event.what_happened);
1842    connection_manager_->RemoveListener(this);
1843  }
1844}
1845
1846void SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
1847    const syncable::DirectoryChangeEvent& event) {
1848  // This notification happens immediately before a syncable WriteTransaction
1849  // falls out of scope. It happens while the channel mutex is still held,
1850  // and while the transaction mutex is held, so it cannot be re-entrant.
1851  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::TRANSACTION_ENDING);
1852  if (!observer_ || ChangeBuffersAreEmpty())
1853    return;
1854
1855  // This will continue the WriteTransaction using a read only wrapper.
1856  // This is the last chance for read to occur in the WriteTransaction
1857  // that's closing. This special ReadTransaction will not close the
1858  // underlying transaction.
1859  ReadTransaction trans(GetUserShare(), event.trans);
1860
1861  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1862    if (change_buffers_[i].IsEmpty())
1863      continue;
1864
1865    vector<ChangeRecord> ordered_changes;
1866    change_buffers_[i].GetAllChangesInTreeOrder(&trans, &ordered_changes);
1867    if (!ordered_changes.empty()) {
1868      observer_->OnChangesApplied(syncable::ModelTypeFromInt(i), &trans,
1869                                  &ordered_changes[0], ordered_changes.size());
1870      model_has_change_.set(i, true);
1871    }
1872    change_buffers_[i].Clear();
1873  }
1874}
1875
1876void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
1877    const syncable::DirectoryChangeEvent& event) {
1878  // We have been notified about a user action changing the bookmark model.
1879  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES);
1880  DCHECK(event.writer == syncable::SYNCAPI ||
1881         event.writer == syncable::UNITTEST);
1882  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1883      "CALCULATE_CHANGES called with unapplied old changes.";
1884
1885  bool exists_unsynced_items = false;
1886  bool only_preference_changes = true;
1887  syncable::ModelTypeBitSet model_types;
1888  for (syncable::OriginalEntries::const_iterator i = event.originals->begin();
1889       i != event.originals->end() && !exists_unsynced_items;
1890       ++i) {
1891    int64 id = i->ref(syncable::META_HANDLE);
1892    syncable::Entry e(event.trans, syncable::GET_BY_HANDLE, id);
1893    DCHECK(e.good());
1894
1895    syncable::ModelType model_type = e.GetModelType();
1896
1897    if (e.Get(syncable::IS_UNSYNCED)) {
1898      if (model_type == syncable::TOP_LEVEL_FOLDER ||
1899          model_type == syncable::UNSPECIFIED) {
1900        NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
1901        continue;
1902      }
1903      // Unsynced items will cause us to nudge the the syncer.
1904      exists_unsynced_items = true;
1905
1906      model_types[model_type] = true;
1907      if (model_type != syncable::PREFERENCES)
1908        only_preference_changes = false;
1909    }
1910  }
1911  if (exists_unsynced_items && syncer_thread()) {
1912    int nudge_delay = only_preference_changes ?
1913        kPreferencesNudgeDelayMilliseconds : kDefaultNudgeDelayMilliseconds;
1914    syncer_thread()->NudgeSyncerWithDataTypes(
1915        nudge_delay,
1916        SyncerThread::kLocal,
1917        model_types);
1918  }
1919}
1920
1921void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
1922    syncable::ModelType type, ChangeReorderBuffer* buffer,
1923    Cryptographer* cryptographer, const syncable::EntryKernel& original,
1924    bool existed_before, bool exists_now) {
1925  // If this is a deletion, attach the entity specifics as extra data
1926  // so that the delete can be processed.
1927  if (!exists_now && existed_before) {
1928    buffer->SetSpecificsForId(id, original.ref(SPECIFICS));
1929    if (type == syncable::PASSWORDS) {
1930      // Need to dig a bit deeper as passwords are encrypted.
1931      scoped_ptr<sync_pb::PasswordSpecificsData> data(
1932          DecryptPasswordSpecifics(original.ref(SPECIFICS), cryptographer));
1933      if (!data.get()) {
1934        NOTREACHED();
1935        return;
1936      }
1937      buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
1938    }
1939  }
1940}
1941
1942void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
1943    const syncable::DirectoryChangeEvent& event) {
1944  // We only expect one notification per sync step, so change_buffers_ should
1945  // contain no pending entries.
1946  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES);
1947  DCHECK(event.writer == syncable::SYNCER ||
1948         event.writer == syncable::UNITTEST);
1949  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1950      "CALCULATE_CHANGES called with unapplied old changes.";
1951
1952  for (syncable::OriginalEntries::const_iterator i = event.originals->begin();
1953       i != event.originals->end(); ++i) {
1954    int64 id = i->ref(syncable::META_HANDLE);
1955    syncable::Entry e(event.trans, syncable::GET_BY_HANDLE, id);
1956    bool existed_before = !i->ref(syncable::IS_DEL);
1957    bool exists_now = e.good() && !e.Get(syncable::IS_DEL);
1958    DCHECK(e.good());
1959
1960    // Omit items that aren't associated with a model.
1961    syncable::ModelType type = e.GetModelType();
1962    if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED)
1963      continue;
1964
1965    if (exists_now && !existed_before)
1966      change_buffers_[type].PushAddedItem(id);
1967    else if (!exists_now && existed_before)
1968      change_buffers_[type].PushDeletedItem(id);
1969    else if (exists_now && existed_before && VisiblePropertiesDiffer(*i, e))
1970      change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e));
1971
1972    SetExtraChangeRecordData(id, type, &change_buffers_[type],
1973                             dir_manager()->cryptographer(), *i,
1974                             existed_before, exists_now);
1975  }
1976}
1977
1978SyncManager::Status::Summary
1979SyncManager::SyncInternal::ComputeAggregatedStatusSummary() {
1980  switch (allstatus_.status().icon) {
1981    case AllStatus::OFFLINE:
1982      return Status::OFFLINE;
1983    case AllStatus::OFFLINE_UNSYNCED:
1984      return Status::OFFLINE_UNSYNCED;
1985    case AllStatus::SYNCING:
1986      return Status::SYNCING;
1987    case AllStatus::READY:
1988      return Status::READY;
1989    case AllStatus::CONFLICT:
1990      return Status::CONFLICT;
1991    case AllStatus::OFFLINE_UNUSABLE:
1992      return Status::OFFLINE_UNUSABLE;
1993    default:
1994      return Status::INVALID;
1995  }
1996}
1997
1998SyncManager::Status SyncManager::SyncInternal::ComputeAggregatedStatus() {
1999  Status return_status =
2000      { ComputeAggregatedStatusSummary(),
2001        allstatus_.status().authenticated,
2002        allstatus_.status().server_up,
2003        allstatus_.status().server_reachable,
2004        allstatus_.status().server_broken,
2005        allstatus_.status().notifications_enabled,
2006        allstatus_.status().notifications_received,
2007        allstatus_.status().notifications_sent,
2008        allstatus_.status().unsynced_count,
2009        allstatus_.status().conflicting_count,
2010        allstatus_.status().syncing,
2011        allstatus_.status().initial_sync_ended,
2012        allstatus_.status().syncer_stuck,
2013        allstatus_.status().updates_available,
2014        allstatus_.status().updates_received,
2015        allstatus_.status().disk_full,
2016        false,   // TODO(ncarter): invalid store?
2017        allstatus_.status().max_consecutive_errors};
2018  return return_status;
2019}
2020
2021void SyncManager::SyncInternal::OnSyncEngineEvent(
2022    const SyncEngineEvent& event) {
2023  if (!observer_)
2024    return;
2025
2026  // Only send an event if this is due to a cycle ending and this cycle
2027  // concludes a canonical "sync" process; that is, based on what is known
2028  // locally we are "all happy" and up-to-date.  There may be new changes on
2029  // the server, but we'll get them on a subsequent sync.
2030  //
2031  // Notifications are sent at the end of every sync cycle, regardless of
2032  // whether we should sync again.
2033  if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2034    ModelSafeRoutingInfo enabled_types;
2035    registrar_->GetModelSafeRoutingInfo(&enabled_types);
2036    if (enabled_types.count(syncable::PASSWORDS) > 0) {
2037      Cryptographer* cryptographer =
2038          GetUserShare()->dir_manager->cryptographer();
2039      if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) {
2040        sync_api::ReadTransaction trans(GetUserShare());
2041        sync_api::ReadNode node(&trans);
2042        if (!node.InitByTagLookup(kNigoriTag)) {
2043          DCHECK(!event.snapshot->is_share_usable);
2044          return;
2045        }
2046        const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
2047        if (!nigori.encrypted().blob().empty()) {
2048          DCHECK(!cryptographer->CanDecrypt(nigori.encrypted()));
2049          cryptographer->SetPendingKeys(nigori.encrypted());
2050        }
2051      }
2052
2053      // If we've completed a sync cycle and the cryptographer isn't ready yet,
2054      // prompt the user for a passphrase.
2055      if (!cryptographer->is_ready() || cryptographer->has_pending_keys()) {
2056        observer_->OnPassphraseRequired();
2057      }
2058    }
2059
2060    if (!initialized())
2061      return;
2062
2063    if (!event.snapshot->has_more_to_sync) {
2064      observer_->OnSyncCycleCompleted(event.snapshot);
2065    }
2066
2067    if (notifier_options_.notification_method !=
2068        notifier::NOTIFICATION_SERVER) {
2069      // TODO(chron): Consider changing this back to track has_more_to_sync
2070      // only notify peers if a successful commit has occurred.
2071      bool new_pending_notification =
2072          (event.snapshot->syncer_status.num_successful_commits > 0);
2073      core_message_loop_->PostTask(
2074          FROM_HERE,
2075          NewRunnableMethod(
2076              this,
2077              &SyncManager::SyncInternal::SendPendingXMPPNotification,
2078              new_pending_notification));
2079    }
2080  }
2081
2082  if (event.what_happened == SyncEngineEvent::SYNCER_THREAD_PAUSED) {
2083    observer_->OnPaused();
2084    return;
2085  }
2086
2087  if (event.what_happened == SyncEngineEvent::SYNCER_THREAD_RESUMED) {
2088    observer_->OnResumed();
2089    return;
2090  }
2091
2092  if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
2093    observer_->OnStopSyncingPermanently();
2094    return;
2095  }
2096
2097  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
2098    observer_->OnClearServerDataSucceeded();
2099    return;
2100  }
2101
2102  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
2103    observer_->OnClearServerDataFailed();
2104    return;
2105  }
2106
2107  if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
2108    observer_->OnUpdatedToken(event.updated_token);
2109    return;
2110  }
2111}
2112
2113void SyncManager::SyncInternal::OnNotificationStateChange(
2114    bool notifications_enabled) {
2115  VLOG(1) << "P2P: Notifications enabled = "
2116          << (notifications_enabled ? "true" : "false");
2117  allstatus_.SetNotificationsEnabled(notifications_enabled);
2118  if (syncer_thread()) {
2119    syncer_thread()->SetNotificationsEnabled(notifications_enabled);
2120  }
2121  if ((notifier_options_.notification_method !=
2122       notifier::NOTIFICATION_SERVER) && notifications_enabled) {
2123    // Nudge the syncer thread when notifications are enabled, in case there is
2124    // any data that has not yet been synced. If we are listening to
2125    // server-issued notifications, we are already guaranteed to receive a
2126    // notification on a successful connection.
2127    if (syncer_thread()) {
2128      syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
2129    }
2130
2131    // Send a notification as soon as subscriptions are on
2132    // (see http://code.google.com/p/chromium/issues/detail?id=38563 ).
2133    core_message_loop_->PostTask(
2134        FROM_HERE,
2135        NewRunnableMethod(
2136            this,
2137            &SyncManager::SyncInternal::SendPendingXMPPNotification,
2138            true));
2139  }
2140}
2141
2142void SyncManager::SyncInternal::TalkMediatorLogin(
2143    const std::string& email, const std::string& token) {
2144  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
2145  DCHECK(!email.empty());
2146  DCHECK(!token.empty());
2147  InitializeTalkMediator();
2148  talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
2149  talk_mediator_->Login();
2150}
2151
2152void SyncManager::SyncInternal::OnIncomingNotification(
2153    const IncomingNotificationData& notification_data) {
2154  syncable::ModelTypeBitSet model_types;
2155
2156  // Check if the service url is a sync URL.  An empty service URL is
2157  // treated as a legacy sync notification.  If we're listening to
2158  // server-issued notifications, no need to check the service_url.
2159  if (notifier_options_.notification_method ==
2160      notifier::NOTIFICATION_SERVER) {
2161    VLOG(1) << "Sync received server notification: " <<
2162        notification_data.service_specific_data;
2163
2164    if (!syncable::ModelTypeBitSetFromString(
2165            notification_data.service_specific_data,
2166            &model_types)) {
2167      LOG(DFATAL) << "Could not extract model types from server data.";
2168      model_types.set();
2169    }
2170  } else if (notification_data.service_url.empty() ||
2171             (notification_data.service_url ==
2172              browser_sync::kSyncLegacyServiceUrl) ||
2173             (notification_data.service_url ==
2174              browser_sync::kSyncServiceUrl)) {
2175    VLOG(1) << "Sync received P2P notification.";
2176
2177    // Catch for sync integration tests (uses p2p). Just set all datatypes.
2178    model_types.set();
2179  } else {
2180    LOG(WARNING) << "Notification fron unexpected source: "
2181                 << notification_data.service_url;
2182  }
2183
2184  if (model_types.any()) {
2185    if (syncer_thread()) {
2186     // Introduce a delay to help coalesce initial notifications.
2187     syncer_thread()->NudgeSyncerWithDataTypes(
2188         250,
2189         SyncerThread::kNotification,
2190         model_types);
2191    }
2192    allstatus_.IncrementNotificationsReceived();
2193  } else {
2194    LOG(WARNING) << "Sync received notification without any type information.";
2195  }
2196}
2197
2198void SyncManager::SyncInternal::OnOutgoingNotification() {
2199  DCHECK_NE(notifier_options_.notification_method,
2200            notifier::NOTIFICATION_SERVER);
2201  allstatus_.IncrementNotificationsSent();
2202}
2203
2204void SyncManager::SyncInternal::WriteState(const std::string& state) {
2205  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2206  if (!lookup.good()) {
2207    LOG(ERROR) << "Could not write notification state";
2208    // TODO(akalin): Propagate result callback all the way to this
2209    // function and call it with "false" to signal failure.
2210    return;
2211  }
2212  if (VLOG_IS_ON(1)) {
2213    std::string encoded_state;
2214    base::Base64Encode(state, &encoded_state);
2215    VLOG(1) << "Writing notification state: " << encoded_state;
2216  }
2217  lookup->SetNotificationState(state);
2218  lookup->SaveChanges();
2219}
2220
2221SyncManager::Status::Summary SyncManager::GetStatusSummary() const {
2222  return data_->ComputeAggregatedStatusSummary();
2223}
2224
2225SyncManager::Status SyncManager::GetDetailedStatus() const {
2226  return data_->ComputeAggregatedStatus();
2227}
2228
2229SyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
2230
2231void SyncManager::SaveChanges() {
2232  data_->SaveChanges();
2233}
2234
2235void SyncManager::SyncInternal::SaveChanges() {
2236  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2237  if (!lookup.good()) {
2238    DCHECK(false) << "ScopedDirLookup creation failed; Unable to SaveChanges";
2239    return;
2240  }
2241  lookup->SaveChanges();
2242}
2243
2244//////////////////////////////////////////////////////////////////////////
2245// BaseTransaction member definitions
2246BaseTransaction::BaseTransaction(UserShare* share)
2247    : lookup_(NULL) {
2248  DCHECK(share && share->dir_manager.get());
2249  lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
2250                                          share->name);
2251  cryptographer_ = share->dir_manager->cryptographer();
2252  if (!(lookup_->good()))
2253    DCHECK(false) << "ScopedDirLookup failed on valid DirManager.";
2254}
2255BaseTransaction::~BaseTransaction() {
2256  delete lookup_;
2257}
2258
2259UserShare* SyncManager::GetUserShare() const {
2260  DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
2261  return data_->GetUserShare();
2262}
2263
2264bool SyncManager::HasUnsyncedItems() const {
2265  sync_api::ReadTransaction trans(GetUserShare());
2266  return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2267}
2268
2269}  // namespace sync_api
2270