1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncapi.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <algorithm>
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <bitset>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <iomanip>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <list>
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <queue>
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base64.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/command_line.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/observer_list.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sha1.h"
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/string_number_conversions.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/time.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/values.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/all_status.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/change_reorder_buffer.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/model_safe_worker.h"
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/engine/nudge_source.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/net/server_connection_manager.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_thread.h"
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/engine/http_post_provider_factory.h"
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/js_arg_list.h"
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/js_backend.h"
4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/js_event_router.h"
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/notifier/sync_notifier.h"
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/notifier/sync_notifier_observer.h"
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/sync/protocol/app_specifics.pb.h"
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/protocol/proto_value_conversions.h"
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/service_constants.h"
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/protocol/session_specifics.pb.h"
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/sync.pb.h"
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/sync/sessions/sync_session.h"
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/sessions/sync_session_context.h"
5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/sync/syncable/autofill_migration.h"
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/syncable/directory_change_listener.h"
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h"
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/syncable/model_type_payload_map.h"
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/sync/syncable/model_type.h"
62dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/sync/syncable/nigori_util.h"
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable.h"
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/util/crypto_helpers.h"
65dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/common/chrome_switches.h"
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/deprecated/event_sys.h"
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/gaia/gaia_authenticator.h"
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/network_change_notifier.h"
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing base::TimeDelta;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::AllStatus;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::Cryptographer;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::KeyParams;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::ModelSafeRoutingInfo;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::ModelSafeWorker;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::ModelSafeWorkerRegistrar;
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickusing browser_sync::ServerConnectionEvent;
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing browser_sync::ServerConnectionEvent2;
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing browser_sync::ServerConnectionEventListener;
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing browser_sync::SyncEngineEvent;
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickusing browser_sync::SyncEngineEventListener;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::Syncer;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::SyncerThread;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::kNigoriTag;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing browser_sync::sessions::SyncSessionContext;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::list;
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::hex;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::string;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::vector;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Directory;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::DirectoryManager;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Entry;
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing syncable::ModelTypeBitSet;
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing syncable::OriginalEntries;
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing syncable::WriterTag;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SPECIFICS;
98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochusing sync_pb::AutofillProfileSpecifics;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef GoogleServiceAuthError AuthError;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kThreadExitTimeoutMsec = 60000;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kSSLPort = 443;
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const int kSyncerThreadDelayMsec = 250;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#if defined(OS_CHROMEOS)
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#endif  // OS_CHROMEOS
109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We manage the lifetime of sync_api::SyncManager::SyncInternal ourselves.
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDISABLE_RUNNABLE_METHOD_REFCOUNT(sync_api::SyncManager::SyncInternal);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace sync_api {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char kDefaultNameForNewNodes[] = " ";
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The list of names which are reserved for use by the server.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char* kForbiddenServerNames[] = { "", ".", ".." };
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Static helper functions.
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper function to look up the int64 metahandle of an object given the ID
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// string.
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int64 IdToMetahandle(syncable::BaseTransaction* trans,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            const syncable::Id& id) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Entry entry(trans, syncable::GET_BY_ID, id);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry.good())
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return kInvalidId;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entry.Get(syncable::META_HANDLE);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Checks whether |name| is a server-illegal name followed by zero or more space
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// characters.  The three server-illegal names are the empty string, dot, and
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dot-dot.  Very long names (>255 bytes in UTF-8 Normalization Form C) are
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// also illegal, but are not considered here.
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool IsNameServerIllegalAfterTrimming(const std::string& name) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t untrimmed_count = name.find_last_not_of(' ') + 1;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < arraysize(kForbiddenServerNames); ++i) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (name.compare(0, untrimmed_count, kForbiddenServerNames[i]) == 0)
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool EndsWithSpace(const std::string& string) {
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !string.empty() && *string.rbegin() == ' ';
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// When taking a name from the syncapi, append a space if it matches the
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// pattern of a server-illegal name followed by zero or more spaces.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void SyncAPINameToServerName(const std::wstring& sync_api_name,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    std::string* out) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *out = WideToUTF8(sync_api_name);
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsNameServerIllegalAfterTrimming(*out))
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    out->append(" ");
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// In the reverse direction, if a server name matches the pattern of a
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// server-illegal name followed by one or more spaces, remove the trailing
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// space.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void ServerNameToSyncAPIName(const std::string& server_name,
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    std::wstring* out) {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int length_to_copy = server_name.length();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsNameServerIllegalAfterTrimming(server_name) &&
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EndsWithSpace(server_name))
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    --length_to_copy;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!UTF8ToWide(server_name.c_str(), length_to_copy, out)) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED() << "Could not convert server name from UTF8 to wide";
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickUserShare::UserShare() {}
176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
177731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickUserShare::~UserShare() {}
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BaseNode member definitions.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseNode::BaseNode() {}
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseNode::~BaseNode() {}
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string BaseNode::GenerateSyncableHash(
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ModelType model_type, const std::string& client_tag) {
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // blank PB with just the extension in it has termination symbol,
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // handy for delimiter
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics serialized_type;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::AddDefaultExtensionValue(model_type, &serialized_type);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string hash_input;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  serialized_type.AppendToString(&hash_input);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hash_input.append(client_tag);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string encode_output;
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return encode_output;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricksync_pb::PasswordSpecificsData* DecryptPasswordSpecifics(
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const sync_pb::EntitySpecifics& specifics, Cryptographer* crypto) {
2034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!specifics.HasExtension(sync_pb::password))
2044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return NULL;
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::PasswordSpecifics& password_specifics =
206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      specifics.GetExtension(sync_pb::password);
207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!password_specifics.has_encrypted())
208dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return NULL;
209dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EncryptedData& encrypted = password_specifics.encrypted();
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<sync_pb::PasswordSpecificsData> data(
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new sync_pb::PasswordSpecificsData);
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!crypto->Decrypt(encrypted, data.get()))
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return data.release();
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseNode::DecryptIfNecessary(Entry* entry) {
218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (GetIsFolder()) return true;  // Ignore the top-level datatype folder.
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const sync_pb::EntitySpecifics& specifics =
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry->Get(syncable::SPECIFICS);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (specifics.HasExtension(sync_pb::password)) {
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Passwords have their own legacy encryption structure.
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        specifics, GetTransaction()->GetCryptographer()));
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!data.get())
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    password_data_.swap(data);
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return true;
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // We assume any node with the encrypted field set has encrypted data.
232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!specifics.has_encrypted())
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return true;
234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EncryptedData& encrypted =
236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      specifics.encrypted();
237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string plaintext_data = GetTransaction()->GetCryptographer()->
238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      DecryptToString(encrypted);
239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (plaintext_data.length() == 0)
240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!unencrypted_data_.ParseFromString(plaintext_data)) {
242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "Failed to decrypt encrypted node of type " <<
243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      syncable::ModelTypeToString(entry->GetModelType()) << ".";
244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
249dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
250dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const syncable::Entry* entry) const {
251dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS);
252dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (specifics.has_encrypted()) {
253dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) !=
254dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           syncable::UNSPECIFIED);
255dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return unencrypted_data_;
256dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
257dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) ==
258dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           syncable::UNSPECIFIED);
259dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return specifics;
260dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
261dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetParentId() const {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        GetEntry()->Get(syncable::PARENT_ID));
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetId() const {
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetEntry()->Get(syncable::META_HANDLE);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenint64 BaseNode::GetModificationTime() const {
2733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return GetEntry()->Get(syncable::MTIME);
2743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
2753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseNode::GetIsFolder() const {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetEntry()->Get(syncable::IS_DIR);
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring BaseNode::GetTitle() const {
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring result;
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), &result);
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGURL BaseNode::GetURL() const {
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GURL(GetBookmarkSpecifics().url());
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetPredecessorId() const {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (id_string.IsRoot())
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return kInvalidId;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetSuccessorId() const {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (id_string.IsRoot())
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return kInvalidId;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetFirstChildId() const {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Directory* dir = GetTransaction()->GetLookup();
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id id_string =
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dir->GetFirstChildId(trans, GetEntry()->Get(syncable::ID));
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (id_string.IsRoot())
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return kInvalidId;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDictionaryValue* BaseNode::ToValue() const {
31572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DictionaryValue* node_info = new DictionaryValue();
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("id", base::Int64ToString(GetId()));
31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // TODO(akalin): Return time in a better format.
31872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("modificationTime",
31972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       base::Int64ToString(GetModificationTime()));
32072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("parentId", base::Int64ToString(GetParentId()));
32172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetBoolean("isFolder", GetIsFolder());
32272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // TODO(akalin): Add a std::string accessor for the title.
32372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("title", WideToUTF8(GetTitle()));
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  node_info->Set("type", ModelTypeToValue(GetModelType()));
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Specifics are already in the Entry value, so no need to duplicate
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // it here.
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("externalId",
32872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       base::Int64ToString(GetExternalId()));
32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("predecessorId",
33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       base::Int64ToString(GetPredecessorId()));
33172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("successorId",
33272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       base::Int64ToString(GetSuccessorId()));
33372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  node_info->SetString("firstChildId",
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                       base::Int64ToString(GetFirstChildId()));
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  node_info->Set("entry", GetEntry()->ToValue());
33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return node_info;
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!output)
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& favicon = GetBookmarkSpecifics().favicon();
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reinterpret_cast<const unsigned char*>(favicon.data() +
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             favicon.length()));
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 BaseNode::GetExternalId() const {
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::APPS, GetModelType());
354dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
355dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
356dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::app);
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::AUTOFILL, GetModelType());
361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
362dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::autofill);
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
366201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
367201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::autofill_profile);
371201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
372201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::bookmark);
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::NIGORI, GetModelType());
382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::nigori);
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::PASSWORDS, GetModelType());
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(password_data_.get());
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return *password_data_;
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const {
394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::PREFERENCES, GetModelType());
395dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
396dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::preference);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::THEMES, GetModelType());
402dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
404dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::theme);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
408dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
409dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
410dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
411dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::typed_url);
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
415dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
417dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
418dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::extension);
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
422dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::SESSIONS, GetModelType());
423dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const sync_pb::EntitySpecifics& unencrypted =
424dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetUnencryptedSpecifics(GetEntry());
425dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return unencrypted.GetExtension(sync_pb::session);
4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsyncable::ModelType BaseNode::GetModelType() const {
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetEntry()->GetModelType();
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// WriteNode member definitions
434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid WriteNode::EncryptIfNecessary(sync_pb::EntitySpecifics* unencrypted) {
435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelType type = syncable::GetModelTypeFromSpecifics(*unencrypted);
436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_NE(type, syncable::UNSPECIFIED);
437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_NE(type, syncable::PASSWORDS);  // Passwords use their own encryption.
438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_NE(type, syncable::NIGORI);     // Nigori is encrypted separately.
439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet encrypted_types =
441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetEncryptedDataTypes(GetTransaction()->GetWrappedTrans());
442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (encrypted_types.count(type) == 0) {
443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // This datatype does not require encryption.
444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
446dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (unencrypted->has_encrypted()) {
448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // This specifics is already encrypted, our work is done.
449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(WARNING) << "Attempted to encrypt an already encrypted entity"
450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      << " specifics of type " << syncable::ModelTypeToString(type)
451dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      << ". Dropping.";
452dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sync_pb::EntitySpecifics encrypted;
455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::AddDefaultExtensionValue(type, &encrypted);
456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(2) << "Encrypted specifics of type " << syncable::ModelTypeToString(type)
457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << " with content: " << unencrypted->SerializeAsString() << "\n";
458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!GetTransaction()->GetCryptographer()->Encrypt(
459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      *unencrypted,
460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      encrypted.mutable_encrypted())) {
461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "Could not encrypt data for node of type " <<
462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      syncable::ModelTypeToString(type);
463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NOTREACHED();
464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  unencrypted->CopyFrom(encrypted);
466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetIsFolder(bool folder) {
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_->Get(syncable::IS_DIR) == folder)
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;  // Skip redundant changes.
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(syncable::IS_DIR, folder);
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MarkForSyncing();
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetTitle(const std::wstring& title) {
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string server_legal_name;
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncAPINameToServerName(title, &server_legal_name);
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string old_name = entry_->Get(syncable::NON_UNIQUE_NAME);
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (server_legal_name == old_name)
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;  // Skip redundant changes.
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(syncable::NON_UNIQUE_NAME, server_legal_name);
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MarkForSyncing();
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetURL(const GURL& url) {
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_value.set_url(url.spec());
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetBookmarkSpecifics(new_value);
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WriteNode::SetAppSpecifics(
4963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const sync_pb::AppSpecifics& new_value) {
497dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::APPS, GetModelType());
4983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PutAppSpecificsAndMarkForSyncing(new_value);
4993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetAutofillSpecifics(
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::AutofillSpecifics& new_value) {
503dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::AUTOFILL, GetModelType());
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutAutofillSpecificsAndMarkForSyncing(new_value);
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutAutofillSpecificsAndMarkForSyncing(
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::AutofillSpecifics& new_value) {
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value);
511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid WriteNode::SetAutofillProfileSpecifics(
51621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const sync_pb::AutofillProfileSpecifics& new_value) {
51721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
51821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PutAutofillProfileSpecificsAndMarkForSyncing(new_value);
51921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
52021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
52121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing(
52221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const sync_pb::AutofillProfileSpecifics& new_value) {
52321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  sync_pb::EntitySpecifics entity_specifics;
52421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom(
52521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      new_value);
526dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
52721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PutSpecificsAndMarkForSyncing(entity_specifics);
52821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
52921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetBookmarkSpecifics(
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::BookmarkSpecifics& new_value) {
532dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutBookmarkSpecificsAndMarkForSyncing(new_value);
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutBookmarkSpecificsAndMarkForSyncing(
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::BookmarkSpecifics& new_value) {
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value);
540dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetNigoriSpecifics(
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::NigoriSpecifics& new_value) {
546dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::NIGORI, GetModelType());
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutNigoriSpecificsAndMarkForSyncing(new_value);
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutNigoriSpecificsAndMarkForSyncing(
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::NigoriSpecifics& new_value) {
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value);
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetPasswordSpecifics(
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::PasswordSpecificsData& data) {
559dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::PASSWORDS, GetModelType());
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Cryptographer* cryptographer = GetTransaction()->GetCryptographer();
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Idempotency check to prevent unnecessary syncing: if the plaintexts match
564ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // and the old ciphertext is encrypted with the most current key, there's
565ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // nothing to do here.  Because each encryption is seeded with a different
566ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // random value, checking for equivalence post-encryption doesn't suffice.
567ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const sync_pb::EncryptedData& old_ciphertext =
568ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::password).encrypted();
569ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext(
570ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer));
571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (old_plaintext.get() &&
572ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      old_plaintext->SerializeAsString() == data.SerializeAsString() &&
573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) {
574ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::PasswordSpecifics new_value;
578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) {
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
580731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutPasswordSpecificsAndMarkForSyncing(new_value);
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetPreferenceSpecifics(
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::PreferenceSpecifics& new_value) {
586dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::PREFERENCES, GetModelType());
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutPreferenceSpecificsAndMarkForSyncing(new_value);
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetThemeSpecifics(
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::ThemeSpecifics& new_value) {
592dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::THEMES, GetModelType());
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutThemeSpecificsAndMarkForSyncing(new_value);
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WriteNode::SetSessionSpecifics(
5973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const sync_pb::SessionSpecifics& new_value) {
598dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::SESSIONS, GetModelType());
5993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PutSessionSpecificsAndMarkForSyncing(new_value);
6003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
602dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid WriteNode::ResetFromSpecifics() {
603dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sync_pb::EntitySpecifics new_data;
604dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  new_data.CopyFrom(GetUnencryptedSpecifics(GetEntry()));
605dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&new_data);
606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  PutSpecificsAndMarkForSyncing(new_data);
607dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
6083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutPasswordSpecificsAndMarkForSyncing(
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::PasswordSpecifics& new_value) {
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutPreferenceSpecificsAndMarkForSyncing(
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::PreferenceSpecifics& new_value) {
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value);
620dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetTypedUrlSpecifics(
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& new_value) {
626dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutTypedUrlSpecificsAndMarkForSyncing(new_value);
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetExtensionSpecifics(
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::ExtensionSpecifics& new_value) {
632dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutExtensionSpecificsAndMarkForSyncing(new_value);
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WriteNode::PutAppSpecificsAndMarkForSyncing(
6373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const sync_pb::AppSpecifics& new_value) {
6383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  sync_pb::EntitySpecifics entity_specifics;
6393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value);
640dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
6413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PutSpecificsAndMarkForSyncing(entity_specifics);
6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutThemeSpecificsAndMarkForSyncing(
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::ThemeSpecifics& new_value) {
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value);
648dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutTypedUrlSpecificsAndMarkForSyncing(
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& new_value) {
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value);
656dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutExtensionSpecificsAndMarkForSyncing(
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::ExtensionSpecifics& new_value) {
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics entity_specifics;
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value);
664dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(entity_specifics);
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WriteNode::PutSessionSpecificsAndMarkForSyncing(
6693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const sync_pb::SessionSpecifics& new_value) {
6703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  sync_pb::EntitySpecifics entity_specifics;
6713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value);
672dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptIfNecessary(&entity_specifics);
6733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PutSpecificsAndMarkForSyncing(entity_specifics);
6743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutSpecificsAndMarkForSyncing(
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::EntitySpecifics& specifics) {
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Skip redundant changes.
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (specifics.SerializeAsString() ==
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry_->Get(SPECIFICS).SerializeAsString()) {
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(SPECIFICS, specifics);
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MarkForSyncing();
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetExternalId(int64 id) {
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (GetExternalId() != id)
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry_->Put(syncable::LOCAL_EXTERNAL_ID, id);
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWriteNode::WriteNode(WriteTransaction* transaction)
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : entry_(NULL), transaction_(transaction) {
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transaction);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWriteNode::~WriteNode() {
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete entry_;
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Find an existing node matching the ID |id|, and bind this WriteNode to it.
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true on success.
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::InitByIdLookup(int64 id) {
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(id, kInvalidId);
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      syncable::GET_BY_HANDLE, id);
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DecryptIfNecessary(entry_));
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Find a node by client tag, and bind this WriteNode to it.
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true if the write node was found, and was not deleted.
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Undeleting a deleted node is possible by ClientTag.
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::InitByClientTagLookup(syncable::ModelType model_type,
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      const std::string& tag) {
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tag.empty())
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string hash = GenerateSyncableHash(model_type, tag);
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      syncable::GET_BY_CLIENT_TAG, hash);
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DecryptIfNecessary(entry_));
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::InitByTagLookup(const std::string& tag) {
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tag.empty())
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      syncable::GET_BY_SERVER_TAG, tag);
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->good())
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_->Get(syncable::IS_DEL))
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::ModelType model_type = GetModelType();
740dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(syncable::NIGORI, model_type);
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutModelType(syncable::ModelType model_type) {
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set an empty specifics of the appropriate datatype.  The presence
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of the specific extension will identify the model type.
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(GetModelType() == model_type ||
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         GetModelType() == syncable::UNSPECIFIED);  // Immutable once set.
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::EntitySpecifics specifics;
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::AddDefaultExtensionValue(model_type, &specifics);
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutSpecificsAndMarkForSyncing(specifics);
753dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(model_type, GetModelType());
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Create a new node with default properties, and bind this WriteNode to it.
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true on success.
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::InitByCreation(syncable::ModelType model_type,
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               const BaseNode& parent,
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               const BaseNode* predecessor) {
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |predecessor| must be a child of |parent| or NULL.
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (predecessor && predecessor->GetParentId() != parent.GetId()) {
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false);
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start out with a dummy name.  We expect
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the caller to set a meaningful name after creation.
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string dummy(kDefaultNameForNewNodes);
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      syncable::CREATE, parent_id, dummy);
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->good())
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Entries are untitled folders by default.
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(syncable::IS_DIR, true);
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutModelType(model_type);
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutPredecessor(predecessor);
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Create a new node with default properties and a client defined unique tag,
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and bind this WriteNode to it.
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return true on success. If the tag exists in the database, then
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we will attempt to undelete the node.
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(chron): Code datatype into hash tag.
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(chron): Is model type ever lost?
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::InitUniqueByCreation(syncable::ModelType model_type,
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const BaseNode& parent,
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const std::string& tag) {
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string hash = GenerateSyncableHash(model_type, tag);
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start out with a dummy name.  We expect
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the caller to set a meaningful name after creation.
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string dummy(kDefaultNameForNewNodes);
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check if we have this locally and need to undelete it.
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<syncable::MutableEntry> existing_entry(
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 syncable::GET_BY_CLIENT_TAG, hash));
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (existing_entry->good()) {
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (existing_entry->Get(syncable::IS_DEL)) {
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Rules for undelete:
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // BASE_VERSION: Must keep the same.
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // ID: Essential to keep the same.
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // META_HANDLE: Must be the same, so we can't "split" the entry.
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // IS_DEL: Must be set to false, will cause reindexing.
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //         This one is weird because IS_DEL is true for "update only"
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //         items. It should be OK to undelete an update only.
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // MTIME/CTIME: Seems reasonable to just leave them alone.
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // IS_UNSYNCED: Must set this to true or face database insurrection.
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //              We do this below this block.
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //                      to SERVER_VERSION. We keep it the same here.
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // IS_DIR: We'll leave it the same.
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // SPECIFICS: Reset it.
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      existing_entry->Put(syncable::IS_DEL, false);
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Client tags are immutable and must be paired with the ID.
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If a server update comes down with an ID and client tag combo,
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // and it already exists, always overwrite it and store only one copy.
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We have to undelete entries because we can't disassociate IDs from
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // tags and updates.
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy);
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      existing_entry->Put(syncable::PARENT_ID, parent_id);
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry_ = existing_entry.release();
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        syncable::CREATE, parent_id, dummy);
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!entry_->good()) {
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash);
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't support directory and tag combinations.
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(syncable::IS_DIR, false);
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Will clear specifics data.
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutModelType(model_type);
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutPredecessor(NULL);
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WriteNode::SetPosition(const BaseNode& new_parent,
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            const BaseNode* predecessor) {
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |predecessor| must be a child of |new_parent| or NULL.
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false);
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID);
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Filter out redundant changes if both the parent and the predecessor match.
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_parent_id == entry_->Get(syncable::PARENT_ID)) {
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const syncable::Id& old = entry_->Get(syncable::PREV_ID);
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((!predecessor && old.IsRoot()) ||
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) {
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Atomically change the parent. This will fail if it would
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // introduce a cycle in the hierarchy.
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->Put(syncable::PARENT_ID, new_parent_id))
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PutPredecessor(predecessor);
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst syncable::Entry* WriteNode::GetEntry() const {
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entry_;
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BaseTransaction* WriteNode::GetTransaction() const {
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transaction_;
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::Remove() {
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->Put(syncable::IS_DEL, true);
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MarkForSyncing();
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::PutPredecessor(const BaseNode* predecessor) {
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::Id predecessor_id = predecessor ?
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      predecessor->GetEntry()->Get(syncable::ID) : syncable::Id();
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_->PutPredecessor(predecessor_id);
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Mark this entry as unsynced, to wake up the syncer.
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MarkForSyncing();
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::SetFaviconBytes(const vector<unsigned char>& bytes) {
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size());
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetBookmarkSpecifics(new_value);
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteNode::MarkForSyncing() {
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::MarkForSyncing(entry_);
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ReadNode member definitions
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochReadNode::ReadNode(const BaseTransaction* transaction)
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : entry_(NULL), transaction_(transaction) {
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(transaction);
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
937201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochReadNode::ReadNode() {
938201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  entry_ = NULL;
939201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  transaction_ = NULL;
940201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
941201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochReadNode::~ReadNode() {
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete entry_;
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ReadNode::InitByRootLookup() {
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::Entry(trans, syncable::GET_BY_ID, trans->root_id());
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->good())
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false) << "Could not lookup root node for reading.";
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ReadNode::InitByIdLookup(int64 id) {
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(id, kInvalidId);
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::Entry(trans, syncable::GET_BY_HANDLE, id);
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->good())
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_->Get(syncable::IS_DEL))
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::ModelType model_type = GetModelType();
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  model_type == syncable::TOP_LEVEL_FOLDER)
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "SyncAPI InitByIdLookup referencing unusual object.";
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DecryptIfNecessary(entry_);
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ReadNode::InitByClientTagLookup(syncable::ModelType model_type,
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const std::string& tag) {
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tag.empty())
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string hash = GenerateSyncableHash(model_type, tag);
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::Entry(transaction_->GetWrappedTrans(),
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               syncable::GET_BY_CLIENT_TAG, hash);
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DecryptIfNecessary(entry_));
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst syncable::Entry* ReadNode::GetEntry() const {
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return entry_;
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst BaseTransaction* ReadNode::GetTransaction() const {
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transaction_;
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ReadNode::InitByTagLookup(const std::string& tag) {
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!entry_) << "Init called twice";
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tag.empty())
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  entry_ = new syncable::Entry(trans, syncable::GET_BY_SERVER_TAG, tag);
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!entry_->good())
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_->Get(syncable::IS_DEL))
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::ModelType model_type = GetModelType();
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  model_type == syncable::TOP_LEVEL_FOLDER)
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "SyncAPI InitByTagLookup referencing unusually typed object.";
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return DecryptIfNecessary(entry_);
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ReadTransaction member definitions
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochReadTransaction::ReadTransaction(UserShare* share)
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseTransaction(share),
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transaction_(NULL),
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      close_transaction_(true) {
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction_ = new syncable::ReadTransaction(GetLookup(), __FILE__, __LINE__);
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochReadTransaction::ReadTransaction(UserShare* share,
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 syncable::BaseTransaction* trans)
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseTransaction(share),
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transaction_(trans),
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      close_transaction_(false) {}
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochReadTransaction::~ReadTransaction() {
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (close_transaction_) {
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete transaction_;
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsyncable::BaseTransaction* ReadTransaction::GetWrappedTrans() const {
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transaction_;
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// WriteTransaction member definitions
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWriteTransaction::WriteTransaction(UserShare* share)
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseTransaction(share),
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      transaction_(NULL) {
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction_ = new syncable::WriteTransaction(GetLookup(), syncable::SYNCAPI,
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                __FILE__, __LINE__);
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWriteTransaction::~WriteTransaction() {
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete transaction_;
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsyncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return transaction_;
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1051731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSyncManager::ChangeRecord::ChangeRecord()
1052731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : id(kInvalidId), action(ACTION_ADD) {}
1053731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1054731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSyncManager::ChangeRecord::~ChangeRecord() {}
1055731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
105672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDictionaryValue* SyncManager::ChangeRecord::ToValue(
105772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const BaseTransaction* trans) const {
105872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DictionaryValue* value = new DictionaryValue();
105972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string action_str;
106072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  switch (action) {
106172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ACTION_ADD:
106272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      action_str = "Add";
106372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
106472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ACTION_DELETE:
106572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      action_str = "Delete";
106672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
106772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    case ACTION_UPDATE:
106872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      action_str = "Update";
106972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
107072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    default:
107172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NOTREACHED();
107272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      action_str = "Unknown";
107372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
107472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
107572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  value->SetString("action", action_str);
107672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Value* node_value = NULL;
107772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (action == ACTION_DELETE) {
107872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DictionaryValue* node_dict = new DictionaryValue();
107972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    node_dict->SetString("id", base::Int64ToString(id));
108072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    node_dict->Set("specifics",
108172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                    browser_sync::EntitySpecificsToValue(specifics));
108272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (extra.get()) {
108372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      node_dict->Set("extra", extra->ToValue());
108472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
108572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    node_value = node_dict;
108672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
108772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ReadNode node(trans);
108872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (node.InitByIdLookup(id)) {
108972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      node_value = node.ToValue();
109072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
109172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
109272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!node_value) {
109372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    NOTREACHED();
109472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    node_value = Value::CreateNullValue();
109572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
109672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  value->Set("node", node_value);
109772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return value;
109872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
109972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseNode::ContainsString(const std::string& lowercase_query) const {
1101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(GetEntry());
1102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(lipalani) - figure out what to do if the node is encrypted.
1103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const sync_pb::EntitySpecifics& specifics = GetEntry()->Get(SPECIFICS);
1104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string temp;
1105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The protobuf serialized string contains the original strings. So
1106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // we will just serialize it and search it.
1107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  specifics.SerializeToString(&temp);
1108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Now convert to lower case.
1110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  StringToLowerASCII(&temp);
1111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return temp.find(lowercase_query) != std::string::npos;
1113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1115dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData() {}
1116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1117731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
1118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const sync_pb::PasswordSpecificsData& data)
1119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : unencrypted_(data) {
1120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1122731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
1123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
112472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDictionaryValue* SyncManager::ExtraPasswordChangeRecordData::ToValue() const {
112572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return browser_sync::PasswordSpecificsDataToValue(unencrypted_);
112672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
112772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
112872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst sync_pb::PasswordSpecificsData&
112972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SyncManager::ExtraPasswordChangeRecordData::unencrypted() const {
113072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return unencrypted_;
113172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
113272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace {
1134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct NotificationInfo {
1136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int total_count;
1137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string payload;
1138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NotificationInfo() : total_count(0) {}
1140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ~NotificationInfo() {}
1142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Returned pointer owned by the caller.
1144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DictionaryValue* ToValue() const {
1145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* value = new DictionaryValue();
1146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    value->SetInteger("totalCount", total_count);
1147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    value->SetString("payload", payload);
1148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return value;
1149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
1151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentypedef std::map<syncable::ModelType, NotificationInfo> NotificationInfoMap;
1153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// returned pointer is owned by the caller.
1155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDictionaryValue* NotificationInfoToValue(
1156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const NotificationInfoMap& notification_info) {
1157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DictionaryValue* value = new DictionaryValue();
1158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (NotificationInfoMap::const_iterator it = notification_info.begin();
1160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      it != notification_info.end(); ++it) {
1161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& model_type_str =
1162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        syncable::ModelTypeToString(it->first);
1163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    value->Set(model_type_str, it->second.ToValue());
1164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return value;
1167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace
1170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SyncManager's implementation: SyncManager::SyncInternal
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SyncManager::SyncInternal
1174dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    : public net::NetworkChangeNotifier::IPAddressObserver,
1175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      public sync_notifier::SyncNotifierObserver,
117672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      public browser_sync::JsBackend,
1177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      public SyncEngineEventListener,
1178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      public ServerConnectionEventListener,
1179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      public syncable::DirectoryChangeListener {
1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kDefaultNudgeDelayMilliseconds;
1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kPreferencesNudgeDelayMilliseconds;
1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit SyncInternal(SyncManager* sync_manager)
1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : core_message_loop_(NULL),
118572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        parent_router_(NULL),
1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        sync_manager_(sync_manager),
1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        registrar_(NULL),
1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        initialized_(false),
1189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
1190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  virtual ~SyncInternal() {
1194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(!core_message_loop_);
1195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool Init(const FilePath& database_location,
1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            const std::string& sync_server_and_path,
1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            int port,
1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            bool use_ssl,
1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            HttpPostProviderFactory* post_factory,
1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            const char* user_agent,
12053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            const SyncCredentials& credentials,
1206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            sync_notifier::SyncNotifier* sync_notifier,
12073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            const std::string& restored_key_for_bootstrapping,
12083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            bool setup_for_test_mode);
12093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
12103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Sign into sync with given credentials.
12113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We do not verify the tokens given. After this call, the tokens are set
12123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // and the sync DB is open. True if successful, false if something
12133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // went wrong.
12143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool SignIn(const SyncCredentials& credentials);
12153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
12163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Update tokens that we're using in Sync. Email must stay the same.
12173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void UpdateCredentials(const SyncCredentials& credentials);
1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Called when the user disables or enables a sync type.
1220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void UpdateEnabledTypes();
1221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tell the sync engine to start the syncing process.
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartSyncing();
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Whether or not the Nigori node is encrypted using an explicit passphrase.
12264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  bool IsUsingExplicitPassphrase();
12274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Set the datatypes we want to encrypt and encrypt any nodes as necessary.
1229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
1230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
12314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Try to set the current passphrase to |passphrase|, and record whether
12324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // it is an explicit passphrase or implicitly using gaia in the Nigori
12334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // node.
12344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  void SetPassphrase(const std::string& passphrase, bool is_explicit);
1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Call periodically from a database-safe thread to persist recent changes
1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to the syncapi model.
1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SaveChanges();
1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // DirectoryChangeListener implementation.
1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This listener is called upon completion of a syncable transaction, and
1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // builds the list of sync-engine initiated changes that will be forwarded to
1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the SyncManager's Observers.
1244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void HandleTransactionCompleteChangeEvent(
1245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const ModelTypeBitSet& models_with_changes);
1246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual ModelTypeBitSet HandleTransactionEndingChangeEvent(
1247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::BaseTransaction* trans);
1248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void HandleCalculateChangesChangeEventFromSyncApi(
1249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const OriginalEntries& originals,
1250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const WriterTag& writer,
1251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::BaseTransaction* trans);
1252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void HandleCalculateChangesChangeEventFromSyncer(
1253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const OriginalEntries& originals,
1254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const WriterTag& writer,
1255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::BaseTransaction* trans);
1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Listens for notifications from the ServerConnectionManager
1258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void HandleServerConnectionEvent(const ServerConnectionEvent& event);
1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Open the directory named with username_for_share
12613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool OpenDirectory();
1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // SyncNotifierObserver implementation.
1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnNotificationStateChange(
1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bool notifications_enabled);
1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnIncomingNotification(
1268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const syncable::ModelTypePayloadMap& type_payloads);
1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void StoreState(const std::string& cookie);
1271731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
127272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void AddObserver(SyncManager::Observer* observer);
127372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
127472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void RemoveObserver(SyncManager::Observer* observer);
127572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Accessors for the private members.
1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncAPIServerConnectionManager* connection_manager() {
1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return connection_manager_.get();
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SyncerThread* syncer_thread() { return syncer_thread_.get(); }
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UserShare* GetUserShare() { return &share_; }
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return the currently active (validated) username for use with syncable
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // types.
1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& username_for_share() const {
12873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return share_.name;
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
129072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Status GetStatus();
1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void RequestNudge(const tracked_objects::Location& nudge_location);
1293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void RequestNudgeWithDataTypes(const TimeDelta& delay,
1295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      browser_sync::NudgeSource source, const ModelTypeBitSet& types,
1296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const tracked_objects::Location& nudge_location);
1297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See SyncManager::Shutdown for information.
1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Shutdown();
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Whether we're initialized to the point of being able to accept changes
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (and hence allow transaction creation). See initialized_ for details.
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool initialized() const {
130472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(initialized_mutex_);
1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return initialized_;
1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // If this is a deletion for a password, sets the legacy
1309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets
1310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // |buffer|'s specifics field to contain the unencrypted data.
1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SetExtraChangeRecordData(int64 id,
1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                syncable::ModelType type,
1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                ChangeReorderBuffer* buffer,
13143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                Cryptographer* cryptographer,
1315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                const syncable::EntryKernel& original,
1316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                bool existed_before,
1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                bool exists_now);
1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Called only by our NetworkChangeNotifier.
1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnIPAddressChanged();
1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool InitialSyncEndedForAllEnabledTypes() {
1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!lookup.good()) {
1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ModelSafeRoutingInfo enabled_types;
1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_->GetModelSafeRoutingInfo(&enabled_types);
1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        i != enabled_types.end(); ++i) {
1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!lookup->initial_sync_ended_for_type(i->first))
1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  syncable::AutofillMigrationState GetAutofillMigrationState() {
134021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
134121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!lookup.good()) {
134221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
134321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return syncable::NOT_MIGRATED;
134421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
134521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
134621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return lookup->get_autofill_migration_state();
134721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
134821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
134921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void SetAutofillMigrationState(syncable::AutofillMigrationState state) {
135021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
135121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!lookup.good()) {
135221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
135321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return;
135421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
135521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
135621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return lookup->set_autofill_migration_state(state);
135721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
135821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
135921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void SetAutofillMigrationDebugInfo(
136021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
136121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      const syncable::AutofillMigrationDebugInfo& info) {
136221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
136321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!lookup.good()) {
136421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
136521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return;
136621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
136721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
136821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return lookup->set_autofill_migration_state_debug_info(
136921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        property_to_set, info);
137021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
137121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
137221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  syncable::AutofillMigrationDebugInfo
137321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      GetAutofillMigrationDebugInfo() {
137421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
137521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!lookup.good()) {
137621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
137721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      syncable::AutofillMigrationDebugInfo null_value = {0};
137821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return null_value;
137921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
138021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return lookup->get_autofill_migration_debug_info();
138121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
138221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1383731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // SyncEngineEventListener implementation.
1384731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
138572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // ServerConnectionEventListener implementation.
1387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event);
1388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
138972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // browser_sync::JsBackend implementation.
139072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual void SetParentJsEventRouter(browser_sync::JsEventRouter* router);
139172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual void RemoveParentJsEventRouter();
139272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual const browser_sync::JsEventRouter* GetParentJsEventRouter() const;
139372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  virtual void ProcessMessage(const std::string& name,
139472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                              const browser_sync::JsArgList& args,
139572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                              const browser_sync::JsEventHandler* sender);
139672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue* FindNodesContainingString(const std::string& query);
1398731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private:
1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Helper to call OnAuthError when no authentication credentials are
1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // available.
1402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RaiseAuthNeededEvent();
1403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Helper to set initialized_ to true and raise an event to clients to notify
1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that initialization is complete and it is safe to send us changes. If
1406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already initialized, this is a no-op.
1407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void MarkAndNotifyInitializationComplete();
1408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sends notifications to peers.
1410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void SendNotification();
1411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Determine if the parents or predecessors differ between the old and new
1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // versions of an entry stored in |a| and |b|.  Note that a node's index may
1414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the relative order is unchanged).  To handle such cases, we rely on the
1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // caller to treat a position update on any sibling as updating the positions
1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of all siblings.
1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool VisiblePositionsDiffer(const syncable::EntryKernel& a,
1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     const syncable::Entry& b) {
1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the datatype isn't one where the browser model cares about position,
1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // don't bother notifying that data model of position-only changes.
1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!b.ShouldMaintainPosition())
1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (a.ref(syncable::NEXT_ID) != b.Get(syncable::NEXT_ID))
1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID))
1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Determine if any of the fields made visible to clients of the Sync API
1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // differ between the versions of an entry stored in |a| and |b|. A return
1433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // value of false means that it should be OK to ignore this change.
1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a,
1435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                      const syncable::Entry& b,
1436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                      Cryptographer* cryptographer) {
1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ModelType model_type = b.GetModelType();
1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Suppress updates to items that aren't tracked by any browser model.
1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (model_type == syncable::UNSPECIFIED ||
1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        model_type == syncable::TOP_LEVEL_FOLDER) {
1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME))
1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR))
1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Check if data has changed (account for encryption).
1448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string a_str, b_str;
1449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (a.ref(SPECIFICS).has_encrypted()) {
1450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const sync_pb::EncryptedData& encrypted = a.ref(SPECIFICS).encrypted();
1451dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      a_str = cryptographer->DecryptToString(encrypted);
1452dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
1453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      a_str = a.ref(SPECIFICS).SerializeAsString();
1454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
1455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (b.Get(SPECIFICS).has_encrypted()) {
1456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const sync_pb::EncryptedData& encrypted = b.Get(SPECIFICS).encrypted();
1457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      b_str = cryptographer->DecryptToString(encrypted);
1458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
1459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      b_str = b.Get(SPECIFICS).SerializeAsString();
1460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
1461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (a_str != b_str) {
1462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (VisiblePositionsDiffer(a, b))
1465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool ChangeBuffersAreEmpty() {
1470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!change_buffers_[i].IsEmpty())
1472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void CheckServerReachable() {
14783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (connection_manager()) {
14793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      connection_manager()->CheckServerReachable();
14803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
14813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED() << "Should be valid connection manager!";
14823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
14833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
14843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1485731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void ReEncryptEverything(WriteTransaction* trans);
1486731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Initializes (bootstraps) the Cryptographer if NIGORI has finished
1488731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // initial sync so that it can immediately start encrypting / decrypting.
1489731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If the restored key is incompatible with the current version of the NIGORI
1490731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // node (which could happen if a restart occurred just after an update to
1491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // NIGORI was downloaded and the user must enter a new passphrase to decrypt)
1492731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // then we will raise OnPassphraseRequired and set pending keys for
1493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // decryption.  Otherwise, the cryptographer is made ready (is_ready()).
1494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
1495731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Called for every notification. This updates the notification statistics
1497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to be displayed in about:sync.
1498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void UpdateNotificationInfo(
1499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const syncable::ModelTypePayloadMap& type_payloads);
1500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
15014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // Helper for migration to new nigori proto to set
15024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // 'using_explicit_passphrase' in the NigoriSpecifics.
15034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // TODO(tim): Bug 62103.  Remove this after it has been pushed out to dev
15044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // channel users.
1505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void SetUsingExplicitPassphrasePrefForMigration(
1506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      WriteTransaction* const trans);
15074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1508513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Checks for server reachabilty and requests a nudge.
1509513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  void OnIPAddressChangedImpl();
1510513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
151172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Functions called by ProcessMessage().
151272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  browser_sync::JsArgList ProcessGetNodeByIdMessage(
151372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      const browser_sync::JsArgList& args);
151472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  browser_sync::JsArgList ProcessFindNodesContainingString(
1516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const browser_sync::JsArgList& args);
1517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We couple the DirectoryManager and username together in a UserShare member
1519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so we can return a handle to share_ to clients of the API for use when
1520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // constructing any transaction type.
1521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UserShare share_;
1522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop* core_message_loop_;
1524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ObserverList<SyncManager::Observer> observers_;
152672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
152772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  browser_sync::JsEventRouter* parent_router_;
1528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The ServerConnectionManager used to abstract communication between the
1530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // client (the Syncer) and the sync server.
1531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
1532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The thread that runs the Syncer. Needs to be explicitly Start()ed.
1534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<SyncerThread> syncer_thread_;
1535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The SyncNotifier which notifies us when updates need to be downloaded.
1537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier::SyncNotifier* sync_notifier_;
1538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // A multi-purpose status watch object that aggregates stats from various
1540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // sync components.
1541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AllStatus allstatus_;
1542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Each element of this array is a store of change records produced by
1544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // HandleChangeEvent during the CALCULATE_CHANGES step.  The changes are
1545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // segregated by model type, and are stored here to be processed and
1546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // forwarded to the observer slightly later, at the TRANSACTION_ENDING
15473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // step by HandleTransactionEndingChangeEvent. The list is cleared in the
15483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
1549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
1550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1551201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Event listener hookup for the ServerConnectionManager.
1552201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  scoped_ptr<EventListenerHookup> connection_manager_hookup_;
1553201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The sync dir_manager to which we belong.
1555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncManager* const sync_manager_;
1556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The entity that provides us with information about which types to sync.
1558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The instance is shared between the SyncManager and the Syncer.
1559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ModelSafeWorkerRegistrar* registrar_;
1560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set to true once Init has been called, and we know of an authenticated
1562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // valid) username either from a fresh authentication attempt (as in
1563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // first-use case) or from a previous attempt stored in our UserSettings
1564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (as in the steady-state), and the syncable::Directory has been opened,
1565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // meaning we are ready to accept changes.  Protected by initialized_mutex_
1566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // as it can get read/set by both the SyncerThread and the AuthWatcherThread.
1567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool initialized_;
156872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  mutable base::Lock initialized_mutex_;
1569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // True if the SyncManager should be running in test mode (no syncer thread
15713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // actually communicating with the server).
15723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool setup_for_test_mode_;
15733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
15743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
1575dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Map used to store the notification info to be displayed in about:sync page.
1577ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(lipalani) - prefill the map with enabled data types.
1578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NotificationInfoMap notification_info_map_;
1579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
1580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
1581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
1582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSyncManager::Observer::~Observer() {}
158472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1585c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncManager::SyncManager() {
1586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_ = new SyncInternal(this);
1587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SyncManager::Init(const FilePath& database_location,
1590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const char* sync_server_and_path,
1591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       int sync_server_port,
1592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       bool use_ssl,
1593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       HttpPostProviderFactory* post_factory,
1594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       ModelSafeWorkerRegistrar* registrar,
1595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const char* user_agent,
15963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       const SyncCredentials& credentials,
1597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       sync_notifier::SyncNotifier* sync_notifier,
15983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       const std::string& restored_key_for_bootstrapping,
15993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       bool setup_for_test_mode) {
1600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(post_factory);
1601731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "SyncManager starting Init...";
1602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string server_string(sync_server_and_path);
1603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return data_->Init(database_location,
1604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     server_string,
1605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     sync_server_port,
1606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     use_ssl,
1607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     post_factory,
1608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     registrar,
1609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     user_agent,
16103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     credentials,
1611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     sync_notifier,
16123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     restored_key_for_bootstrapping,
16133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                     setup_for_test_mode);
1614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
16173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  data_->UpdateCredentials(credentials);
16183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
16193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::UpdateEnabledTypes() {
1621ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_->UpdateEnabledTypes();
1622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1623dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
16243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
16253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SyncManager::InitialSyncEndedForAllEnabledTypes() {
16263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return data_->InitialSyncEndedForAllEnabledTypes();
1627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::StartSyncing() {
1630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_->StartSyncing();
1631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsensyncable::AutofillMigrationState
163421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    SyncManager::GetAutofillMigrationState() {
163521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return data_->GetAutofillMigrationState();
163621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
163721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
163821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SyncManager::SetAutofillMigrationState(
163921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::AutofillMigrationState state) {
164021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return data_->SetAutofillMigrationState(state);
164121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
164221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
164321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsensyncable::AutofillMigrationDebugInfo
164421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    SyncManager::GetAutofillMigrationDebugInfo() {
164521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return data_->GetAutofillMigrationDebugInfo();
164621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
164721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
164821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SyncManager::SetAutofillMigrationDebugInfo(
164921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
165021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const syncable::AutofillMigrationDebugInfo& info) {
165121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return data_->SetAutofillMigrationDebugInfo(property_to_set, info);
165221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
165321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
16544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid SyncManager::SetPassphrase(const std::string& passphrase,
16554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch     bool is_explicit) {
16564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  data_->SetPassphrase(passphrase, is_explicit);
16574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
16584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1659dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SyncManager::EncryptDataTypes(
1660dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const syncable::ModelTypeSet& encrypted_types) {
1661dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  data_->EncryptDataTypes(encrypted_types);
1662dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1663dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
16644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool SyncManager::IsUsingExplicitPassphrase() {
16654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return data_ && data_->IsUsingExplicitPassphrase();
1666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1668ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::RequestNudge(const tracked_objects::Location& location) {
1669ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_->RequestNudge(location);
16703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
16713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
16723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SyncManager::RequestClearServerData() {
16733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (data_->syncer_thread())
1674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    data_->syncer_thread()->ScheduleClearUserData();
1675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1677dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SyncManager::RequestConfig(const syncable::ModelTypeBitSet& types) {
1678dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!data_->syncer_thread())
1679dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1680ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  StartConfigurationMode(NULL);
1681ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_->syncer_thread()->ScheduleConfig(types);
1682ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1683ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::StartConfigurationMode(ModeChangeCallback* callback) {
1685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!data_->syncer_thread())
1686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
1687ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_->syncer_thread()->Start(
1688ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      browser_sync::SyncerThread::CONFIGURATION_MODE, callback);
1689dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1690dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst std::string& SyncManager::GetAuthenticatedUsername() {
1692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data_);
1693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return data_->username_for_share();
1694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SyncManager::SyncInternal::Init(
1697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const FilePath& database_location,
1698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& sync_server_and_path,
1699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int port,
1700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_ssl,
1701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HttpPostProviderFactory* post_factory,
1702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* user_agent,
17043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const SyncCredentials& credentials,
1705ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sync_notifier::SyncNotifier* sync_notifier,
17063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& restored_key_for_bootstrapping,
17073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool setup_for_test_mode) {
1708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1709731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Starting SyncInternal initialization.";
1710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  core_message_loop_ = MessageLoop::current();
1712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(core_message_loop_);
1713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_ = model_safe_worker_registrar;
17143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  setup_for_test_mode_ = setup_for_test_mode;
1715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_ = sync_notifier;
1717ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_->AddObserver(this);
1718ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  share_.dir_manager.reset(new DirectoryManager(database_location));
1720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  connection_manager_.reset(new SyncAPIServerConnectionManager(
17223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      sync_server_and_path, port, use_ssl, user_agent, post_factory));
1723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1724dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::NetworkChangeNotifier::AddIPAddressObserver(this);
1725ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1726ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  connection_manager()->AddListener(this);
1727ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(akalin): CheckServerReachable() can block, which may cause jank if we
1729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // try to shut down sync.  Fix this.
17303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  core_message_loop_->PostTask(FROM_HERE,
17313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
1732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Test mode does not use a syncer context or syncer thread.
173472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!setup_for_test_mode_) {
17353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Build a SyncSessionContext and store the worker in it.
1736731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Sync is bringing up SyncSessionContext.";
1737731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::vector<SyncEngineEventListener*> listeners;
1738731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    listeners.push_back(&allstatus_);
1739731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    listeners.push_back(this);
17403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SyncSessionContext* context = new SyncSessionContext(
1741731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        connection_manager_.get(),
1742731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        dir_manager(),
1743731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        model_safe_worker_registrar,
1744731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        listeners);
1745dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    context->set_account_name(credentials.email);
17463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // The SyncerThread takes ownership of |context|.
1747ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_thread_.reset(new SyncerThread(context, new Syncer()));
1748731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
1749731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1750731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool signed_in = SignIn(credentials);
1751731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1752ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (signed_in && syncer_thread()) {
1753ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_thread()->Start(
1754ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        browser_sync::SyncerThread::CONFIGURATION_MODE, NULL);
1755ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1756ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1757731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Do this once the directory is opened.
1758731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BootstrapEncryption(restored_key_for_bootstrapping);
1759ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MarkAndNotifyInitializationComplete();
1760731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return signed_in;
1761731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
1762731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1763731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid SyncManager::SyncInternal::BootstrapEncryption(
1764731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& restored_key_for_bootstrapping) {
1765731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1766731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!lookup.good()) {
1767731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    NOTREACHED();
1768731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
1769731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
17703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1771731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1772731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
1773731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1774dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sync_pb::NigoriSpecifics nigori;
1775dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  {
1776ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Cryptographer should only be accessed while holding a transaction.
1777dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ReadTransaction trans(GetUserShare());
1778ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Cryptographer* cryptographer = trans.GetCryptographer();
1779ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    cryptographer->Bootstrap(restored_key_for_bootstrapping);
1780ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1781dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ReadNode node(&trans);
1782dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!node.InitByTagLookup(kNigoriTag)) {
1783dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NOTREACHED();
1784dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
1785dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
17863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1787dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    nigori.CopyFrom(node.GetNigoriSpecifics());
1788dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!nigori.encrypted().blob().empty()) {
1789dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (cryptographer->CanDecrypt(nigori.encrypted())) {
1790dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        cryptographer->SetKeys(nigori.encrypted());
1791dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
1792dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        cryptographer->SetPendingKeys(nigori.encrypted());
1793dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1794dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          OnPassphraseRequired(true));
1795dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
1796731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
1797731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
1798dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1799dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Refresh list of encrypted datatypes.
1800dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet encrypted_types =
1801dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      syncable::GetEncryptedDataTypesFromNigori(nigori);
1802dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1803dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Ensure any datatypes that need encryption are encrypted.
1804dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  EncryptDataTypes(encrypted_types);
1805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::StartSyncing() {
1808ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Start the syncer thread. This won't actually
1809ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // result in any syncing until at least the
1810ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // DirectoryManager broadcasts the OPENED event,
1811ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // and a valid server connection is detected.
1812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (syncer_thread())  // NULL during certain unittests.
1813ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
1814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
1817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // There is only one real time we need this mutex.  If we get an auth
1818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // success, and before the initial sync ends we get an auth failure.  In this
1819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // case we'll be listening to both the AuthWatcher and Syncer, and it's a race
1820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // between their respective threads to call MarkAndNotify.  We need to make
1821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // sure the observer is notified once and only once.
1822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
182372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(initialized_mutex_);
1824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (initialized_)
1825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
1826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    initialized_ = true;
1827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notify that initialization is complete.
183072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
183172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                    OnInitializationComplete());
1832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1834ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::SendNotification() {
1835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!sync_notifier_) {
1837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "Not sending notification: sync_notifier_ is NULL";
1838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1840ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  allstatus_.IncrementNotificationsSent();
1841ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_->SendNotification();
1842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SyncManager::SyncInternal::OpenDirectory() {
18453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(!initialized()) << "Should only happen once";
18463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
18473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool share_opened = dir_manager()->Open(username_for_share());
18483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(share_opened);
18493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!share_opened) {
185072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
185172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      OnStopSyncingPermanently());
18523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
18533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG(ERROR) << "Could not open share for:" << username_for_share();
18543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Database has to be initialized for the guid to be available.
18583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
18593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!lookup.good()) {
18603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
18613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
18623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
18633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
18643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  connection_manager()->set_client_id(lookup->cache_guid());
18653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1866ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  lookup->SetChangeListener(this);
18673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
1868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
18713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
18723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(share_.name.empty());
18733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  share_.name = credentials.email;
1874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1875731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Signing in user: " << username_for_share();
1876731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!OpenDirectory())
1877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1879ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Retrieve and set the sync notifier state. This should be done
1880ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // only after OpenDirectory is called.
1881ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1882ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string state;
1883ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (lookup.good()) {
1884ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    state = lookup->GetAndClearNotificationState();
1885ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
1886ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    LOG(ERROR) << "Could not read notification state";
1887ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1888ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (VLOG_IS_ON(1)) {
1889ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::string encoded_state;
1890ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::Base64Encode(state, &encoded_state);
1891ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    VLOG(1) << "Read notification state: " << encoded_state;
189272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
1893ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_->SetState(state);
1894ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1895ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateCredentials(credentials);
1896ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateEnabledTypes();
1897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SyncManager::SyncInternal::UpdateCredentials(
19013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const SyncCredentials& credentials) {
19023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1903dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(credentials.email, share_.name);
1904ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!credentials.email.empty());
1905ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!credentials.sync_token.empty());
19063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  connection_manager()->set_auth_token(credentials.sync_token);
1907ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_->UpdateCredentials(
1908ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      credentials.email, credentials.sync_token);
1909ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!setup_for_test_mode_) {
1910ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CheckServerReachable();
1911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
1912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1914ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::UpdateEnabledTypes() {
1915ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1916ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ModelSafeRoutingInfo routes;
1917ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar_->GetModelSafeRoutingInfo(&routes);
1918ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncable::ModelTypeSet enabled_types;
1919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (ModelSafeRoutingInfo::const_iterator it = routes.begin();
1920ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       it != routes.end(); ++it) {
1921ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    enabled_types.insert(it->first);
1922731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
1923ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_notifier_->UpdateEnabledTypes(enabled_types);
1924731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
1925731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::RaiseAuthNeededEvent() {
192772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  FOR_EACH_OBSERVER(
192872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      SyncManager::Observer, observers_,
192972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
1930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1932ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::SetUsingExplicitPassphrasePrefForMigration(
1933ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    WriteTransaction* const trans) {
1934ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WriteNode node(trans);
19354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!node.InitByTagLookup(kNigoriTag)) {
19364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
19374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    NOTREACHED();
19384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return;
19394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
19404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
19414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  specifics.set_using_explicit_passphrase(true);
19424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  node.SetNigoriSpecifics(specifics);
19434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
19444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::SetPassphrase(
19464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const std::string& passphrase, bool is_explicit) {
1947ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // All accesses to the cryptographer are protected by a transaction.
1948ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WriteTransaction trans(GetUserShare());
1949ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Cryptographer* cryptographer = trans.GetCryptographer();
1950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  KeyParams params = {"localhost", "dummy", passphrase};
1951ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (cryptographer->has_pending_keys()) {
1953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!cryptographer->DecryptPendingKeys(params)) {
1954dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      VLOG(1) << "Passphrase failed to decrypt pending keys.";
195572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1956dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        OnPassphraseFailed());
1957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
1958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
19594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
19604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // TODO(tim): If this is the first time the user has entered a passphrase
19614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // since the protocol changed to store passphrase preferences in the cloud,
19624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // make sure we update this preference. See bug 62103.
19634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (is_explicit)
1964ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetUsingExplicitPassphrasePrefForMigration(&trans);
19654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1966dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Nudge the syncer so that encrypted datatype updates that were waiting for
1967dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // this passphrase get applied as soon as possible.
1968ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RequestNudge(FROM_HERE);
1969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1970dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    VLOG(1) << "No pending keys, adding provided passphrase.";
1971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WriteNode node(&trans);
1972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!node.InitByTagLookup(kNigoriTag)) {
1973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
1975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
1976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
19774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
19784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Prevent an implicit SetPassphrase request from changing an explicitly
19794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // set passphrase.
19804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
19814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return;
19824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cryptographer->AddKey(params);
1984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1985731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
1986731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // messing with the Nigori node, because we can't call SetPassphrase until
1987731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // download conditions are met vs Cryptographer init.  It seems like it's
1988731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // safe to defer this work.
1989dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1990dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    specifics.clear_encrypted();
1991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cryptographer->GetKeys(specifics.mutable_encrypted());
19924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    specifics.set_using_explicit_passphrase(is_explicit);
1993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    node.SetNigoriSpecifics(specifics);
1994731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ReEncryptEverything(&trans);
1995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
19963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
19973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string bootstrap_token;
19983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  cryptographer->GetBootstrapToken(&bootstrap_token);
199972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
200072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                    OnPassphraseAccepted(bootstrap_token));
2001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
20044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ReadTransaction trans(&share_);
20054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ReadNode node(&trans);
20064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!node.InitByTagLookup(kNigoriTag)) {
20074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
20084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    NOTREACHED();
20094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
20104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
20114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
20124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return node.GetNigoriSpecifics().using_explicit_passphrase();
20134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
20144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2015dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SyncManager::SyncInternal::EncryptDataTypes(
2016dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const syncable::ModelTypeSet& encrypted_types) {
2017dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(1) << "Attempting to encrypt datatypes "
2018dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          << syncable::ModelTypeSetToString(encrypted_types);
2019dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2020dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  WriteTransaction trans(GetUserShare());
2021dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  WriteNode node(&trans);
2022dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!node.InitByTagLookup(kNigoriTag)) {
2023dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not "
2024dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen               << "found.";
2025dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NOTREACHED();
2026731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
2027731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
2028731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
2029dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Update the Nigori node set of encrypted datatypes so other machines notice.
2030dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Note, we merge the current encrypted types with those requested. Once a
2031dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // datatypes is marked as needing encryption, it is never unmarked.
2032dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  sync_pb::NigoriSpecifics nigori;
2033dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  nigori.CopyFrom(node.GetNigoriSpecifics());
2034dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet current_encrypted_types =
2035dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      syncable::GetEncryptedDataTypesFromNigori(nigori);
2036dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet newly_encrypted_types;
2037dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(),
2038dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                 encrypted_types.begin(), encrypted_types.end(),
2039dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                 std::inserter(newly_encrypted_types,
2040dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               newly_encrypted_types.begin()));
2041dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::FillNigoriEncryptedTypes(newly_encrypted_types, &nigori);
2042dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  node.SetNigoriSpecifics(nigori);
2043dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2044dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(zea): only reencrypt this datatype? ReEncrypting everything is a
2045dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // safer approach, and should not impact anything that is already encrypted
2046dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // (redundant changes are ignored).
2047dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ReEncryptEverything(&trans);
2048dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return;
2049dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
2050dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2051ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace {
2052ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2053ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FindChildNodesContainingString(const std::string& lowercase_query,
2054ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ReadNode& parent_node,
2055ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sync_api::ReadTransaction* trans,
2056ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ListValue* result) {
2057ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int64 child_id = parent_node.GetFirstChildId();
2058ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (child_id != kInvalidId) {
2059ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ReadNode node(trans);
2060ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (node.InitByIdLookup(child_id)) {
2061ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (node.ContainsString(lowercase_query)) {
2062ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        result->Append(new StringValue(base::Int64ToString(child_id)));
2063ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
2064ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FindChildNodesContainingString(lowercase_query, node, trans, result);
2065ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      child_id = node.GetSuccessorId();
2066ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
2067ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(WARNING) << "Lookup of node failed. Id: " << child_id;
2068ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
2069ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
2070ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
2071ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2072ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace
2073ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2074ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Returned pointer owned by the caller.
2075ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenListValue* SyncManager::SyncInternal::FindNodesContainingString(
2076ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& query) {
2077ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Convert the query string to lower case to perform case insensitive
2078ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // searches.
2079ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string lowercase_query = query;
2080ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  StringToLowerASCII(&lowercase_query);
2081ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ReadTransaction trans(GetUserShare());
2082ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ReadNode root(&trans);
2083ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  root.InitByRootLookup();
2084ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2085ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue* result = new ListValue();
2086ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2087ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::Time start_time = base::Time::Now();
2088ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FindChildNodesContainingString(lowercase_query, root, &trans, result);
2089ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::Time end_time = base::Time::Now();
2090ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2091ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::TimeDelta delta = end_time - start_time;
2092ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  VLOG(1) << "Time taken in milliseconds to search " << delta.InMilliseconds();
2093ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2094ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return result;
2095ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2096ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2097dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
2098dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  syncable::ModelTypeSet encrypted_types =
2099dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      GetEncryptedDataTypes(trans->GetWrappedTrans());
2100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ModelSafeRoutingInfo routes;
2101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  registrar_->GetModelSafeRoutingInfo(&routes);
2102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string tag;
2103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (syncable::ModelTypeSet::iterator iter = encrypted_types.begin();
2104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       iter != encrypted_types.end(); ++iter) {
2105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (*iter == syncable::PASSWORDS || routes.count(*iter) == 0)
2106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
2107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ReadNode type_root(trans);
2108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    tag = syncable::ModelTypeToRootTag(*iter);
2109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!type_root.InitByTagLookup(tag)) {
2110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      NOTREACHED();
2111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return;
2112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
2113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Iterate through all children of this datatype.
2115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::queue<int64> to_visit;
2116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 child_id = type_root.GetFirstChildId();
2117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    to_visit.push(child_id);
2118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    while (!to_visit.empty()) {
2119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      child_id = to_visit.front();
2120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      to_visit.pop();
2121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (child_id == kInvalidId)
2122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        continue;
2123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      WriteNode child(trans);
2125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!child.InitByIdLookup(child_id)) {
2126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        NOTREACHED();
2127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
2128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
2129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (child.GetIsFolder()) {
2130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        to_visit.push(child.GetFirstChildId());
2131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
2132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // Rewrite the specifics of the node with encrypted data if necessary.
2133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        child.ResetFromSpecifics();
2134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
2135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      to_visit.push(child.GetSuccessorId());
2136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
2137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
2138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (routes.count(syncable::PASSWORDS) > 0) {
2140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Passwords are encrypted with their own legacy scheme.
2141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    encrypted_types.insert(syncable::PASSWORDS);
2142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ReadNode passwords_root(trans);
2143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string passwords_tag =
2144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        syncable::ModelTypeToRootTag(syncable::PASSWORDS);
2145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!passwords_root.InitByTagLookup(passwords_tag)) {
2146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      LOG(WARNING) << "No passwords to reencrypt.";
2147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
2148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
2149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int64 child_id = passwords_root.GetFirstChildId();
2151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    while (child_id != kInvalidId) {
2152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      WriteNode child(trans);
2153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!child.InitByIdLookup(child_id)) {
2154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        NOTREACHED();
2155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
2156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
2157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      child.SetPasswordSpecifics(child.GetPasswordSpecifics());
2158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      child_id = child.GetSuccessorId();
2159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
2160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
2161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
2162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                    OnEncryptionComplete(encrypted_types));
2164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
2165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
2166c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncManager::~SyncManager() {
2167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete data_;
2168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::AddObserver(Observer* observer) {
217172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  data_->AddObserver(observer);
217272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
217372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
217472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::RemoveObserver(Observer* observer) {
217572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  data_->RemoveObserver(observer);
2176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbrowser_sync::JsBackend* SyncManager::GetJsBackend() {
217972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return data_;
2180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::Shutdown() {
2183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_->Shutdown();
2184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::Shutdown() {
21873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  method_factory_.RevokeAll();
21883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (syncer_thread()) {
2190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_thread()->Stop();
2191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    syncer_thread_.reset();
2192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We NULL out sync_notifer_ so that any pending tasks do not
2195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // trigger further notifications.
2196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(akalin): NULL the other member variables defensively, too.
2197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (sync_notifier_) {
2198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sync_notifier_->RemoveObserver(this);
2199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |this| is about to be destroyed, so we have to ensure any messages
2202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that were posted to core_thread_ before or during syncer thread shutdown
2203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // are flushed out, else they refer to garbage memory.  SendNotification
2204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // is an example.
2205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(tim): Remove this monstrosity, perhaps with ObserverListTS once core
2206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // thread is removed. Bug 78190.
2207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
2208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(core_message_loop_);
2209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool old_state = core_message_loop_->NestableTasksAllowed();
2210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    core_message_loop_->SetNestableTasksAllowed(true);
2211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    core_message_loop_->RunAllPending();
2212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    core_message_loop_->SetNestableTasksAllowed(old_state);
2213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
2216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2217201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  connection_manager_hookup_.reset();
22183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dir_manager()) {
2220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dir_manager()->FinalSaveChangesForAll();
2221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dir_manager()->Close(username_for_share());
2222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reset the DirectoryManager and UserSettings so they relinquish sqlite
2225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // handles to backing files.
2226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  share_.dir_manager.reset();
2227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  core_message_loop_ = NULL;
2229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::OnIPAddressChanged() {
2232731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "IP address change detected";
2233513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#if defined (OS_CHROMEOS)
2234513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // TODO(tim): This is a hack to intentionally lose a race with flimflam at
2235513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // shutdown, so we don't cause shutdown to wait for our http request.
2236513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // http://crosbug.com/8429
2237513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MessageLoop::current()->PostDelayedTask(FROM_HERE,
2238513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      method_factory_.NewRunnableMethod(&SyncInternal::OnIPAddressChangedImpl),
2239513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      kChromeOSNetworkChangeReactionDelayHackMsec);
2240513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#else
2241513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  OnIPAddressChangedImpl();
2242513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#endif  // defined(OS_CHROMEOS)
2243513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
2244513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
2245513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SyncManager::SyncInternal::OnIPAddressChangedImpl() {
2246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(akalin): CheckServerReachable() can block, which may cause
2247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // jank if we try to shut down sync.  Fix this.
2248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  connection_manager()->CheckServerReachable();
2249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  RequestNudge(FROM_HERE);
2250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::OnServerConnectionEvent(
2253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ServerConnectionEvent2& event) {
2254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ServerConnectionEvent legacy;
2255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  legacy.what_happened = ServerConnectionEvent::STATUS_CHANGED;
2256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  legacy.connection_code = event.connection_code;
2257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  legacy.server_reachable = event.server_reachable;
2258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  HandleServerConnectionEvent(legacy);
22593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
22603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2261201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid SyncManager::SyncInternal::HandleServerConnectionEvent(
22623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const ServerConnectionEvent& event) {
22633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  allstatus_.HandleServerConnectionEvent(event);
22643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) {
22653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (event.connection_code ==
22663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
226772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
226872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        OnAuthError(AuthError::None()));
22693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
22703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
22713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
227272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FOR_EACH_OBSERVER(
227372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SyncManager::Observer, observers_,
227472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
22753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
22763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
22773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
22783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
2280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const syncable::ModelTypeBitSet& models_with_changes) {
2281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This notification happens immediately after the transaction mutex is
2282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // released. This allows work to be performed without blocking other threads
2283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // from acquiring a transaction.
2284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (observers_.size() <= 0)
2285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
2286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Call commit.
2288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
2289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (models_with_changes.test(i)) {
2290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        OnChangesComplete(syncable::ModelTypeFromInt(i)));
2292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
2293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
2294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenModelTypeBitSet SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
2297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::BaseTransaction* trans) {
2298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This notification happens immediately before a syncable WriteTransaction
2299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // falls out of scope. It happens while the channel mutex is still held,
2300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and while the transaction mutex is held, so it cannot be re-entrant.
230172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (observers_.size() <= 0 || ChangeBuffersAreEmpty())
2302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return ModelTypeBitSet();
2303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This will continue the WriteTransaction using a read only wrapper.
2305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is the last chance for read to occur in the WriteTransaction
2306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that's closing. This special ReadTransaction will not close the
2307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // underlying transaction.
2308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ReadTransaction read_trans(GetUserShare(), trans);
2309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncable::ModelTypeBitSet models_with_changes;
2311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
2312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (change_buffers_[i].IsEmpty())
2313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
2314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    vector<ChangeRecord> ordered_changes;
2316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    change_buffers_[i].GetAllChangesInTreeOrder(&read_trans, &ordered_changes);
2317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!ordered_changes.empty()) {
231872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FOR_EACH_OBSERVER(
231972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          SyncManager::Observer, observers_,
2320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          OnChangesApplied(syncable::ModelTypeFromInt(i), &read_trans,
232172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                           &ordered_changes[0], ordered_changes.size()));
2322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      models_with_changes.set(i, true);
2323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    change_buffers_[i].Clear();
2325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return models_with_changes;
2327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
2330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const OriginalEntries& originals,
2331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const WriterTag& writer,
2332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::BaseTransaction* trans) {
2333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We have been notified about a user action changing a sync model.
2334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(writer == syncable::SYNCAPI ||
2335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         writer == syncable::UNITTEST);
2336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
2337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "CALCULATE_CHANGES called with unapplied old changes.";
2338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool exists_unsynced_items = false;
2340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool only_preference_changes = true;
23414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  syncable::ModelTypeBitSet model_types;
2342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (syncable::OriginalEntries::const_iterator i = originals.begin();
2343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       i != originals.end() && !exists_unsynced_items;
2344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
2345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 id = i->ref(syncable::META_HANDLE);
2346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::Entry e(trans, syncable::GET_BY_HANDLE, id);
2347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(e.good());
2348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ModelType model_type = e.GetModelType();
2350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (e.Get(syncable::IS_UNSYNCED)) {
2352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (model_type == syncable::TOP_LEVEL_FOLDER ||
2353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          model_type == syncable::UNSPECIFIED) {
2354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
2355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
2356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
2357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Unsynced items will cause us to nudge the the syncer.
2358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      exists_unsynced_items = true;
2359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      model_types[model_type] = true;
2361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (model_type != syncable::PREFERENCES)
2362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        only_preference_changes = false;
2363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (exists_unsynced_items && syncer_thread()) {
2366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int nudge_delay = only_preference_changes ?
2367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kPreferencesNudgeDelayMilliseconds : kDefaultNudgeDelayMilliseconds;
2368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    core_message_loop_->PostTask(FROM_HERE,
2369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        NewRunnableMethod(this, &SyncInternal::RequestNudgeWithDataTypes,
2370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        TimeDelta::FromMilliseconds(nudge_delay),
2371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        browser_sync::NUDGE_SOURCE_LOCAL,
2372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        model_types,
2373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FROM_HERE));
2374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
2378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ModelType type, ChangeReorderBuffer* buffer,
23793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Cryptographer* cryptographer, const syncable::EntryKernel& original,
23803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool existed_before, bool exists_now) {
2381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // If this is a deletion and the datatype was encrypted, we need to decrypt it
2382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // and attach it to the buffer.
2383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!exists_now && existed_before) {
2384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
23853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (type == syncable::PASSWORDS) {
2386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Passwords must use their own legacy ExtraPasswordChangeRecordData.
23873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      scoped_ptr<sync_pb::PasswordSpecificsData> data(
2388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          DecryptPasswordSpecifics(original_specifics, cryptographer));
23893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!data.get()) {
23903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NOTREACHED();
23913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return;
23923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
23933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
2394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else if (original_specifics.has_encrypted()) {
2395dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // All other datatypes can just create a new unencrypted specifics and
2396dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // attach it.
2397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
2398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
2399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        NOTREACHED();
2400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
2401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
24023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    buffer->SetSpecificsForId(id, original_specifics);
2404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
2408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const OriginalEntries& originals,
2409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const WriterTag& writer,
2410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::BaseTransaction* trans) {
2411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We only expect one notification per sync step, so change_buffers_ should
2412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // contain no pending entries.
2413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(writer == syncable::SYNCER ||
2414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         writer == syncable::UNITTEST);
2415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
2416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "CALCULATE_CHANGES called with unapplied old changes.";
2417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Cryptographer* crypto = dir_manager()->GetCryptographer(trans);
2419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (syncable::OriginalEntries::const_iterator i = originals.begin();
2420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       i != originals.end(); ++i) {
2421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 id = i->ref(syncable::META_HANDLE);
2422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncable::Entry e(trans, syncable::GET_BY_HANDLE, id);
2423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool existed_before = !i->ref(syncable::IS_DEL);
2424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool exists_now = e.good() && !e.Get(syncable::IS_DEL);
2425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(e.good());
2426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Omit items that aren't associated with a model.
2428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::ModelType type = e.GetModelType();
2429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED)
2430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
2431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (exists_now && !existed_before)
2433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      change_buffers_[type].PushAddedItem(id);
2434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else if (!exists_now && existed_before)
2435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      change_buffers_[type].PushDeletedItem(id);
2436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    else if (exists_now && existed_before &&
2437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             VisiblePropertiesDiffer(*i, e, crypto)) {
2438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e));
2439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
2440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetExtraChangeRecordData(id, type, &change_buffers_[type], crypto, *i,
2442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             existed_before, exists_now);
2443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
244672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSyncManager::Status SyncManager::SyncInternal::GetStatus() {
244772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return allstatus_.status();
2448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::RequestNudge(
2451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& location) {
2452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (syncer_thread())
2453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     syncer_thread()->ScheduleNudge(
2454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
2455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ModelTypeBitSet(), location);
2456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::RequestNudgeWithDataTypes(
2459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const TimeDelta& delay,
2460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    browser_sync::NudgeSource source, const ModelTypeBitSet& types,
2461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const tracked_objects::Location& nudge_location) {
2462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (syncer_thread())
2463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     syncer_thread()->ScheduleNudge(delay, source, types, nudge_location);
2464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2466731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid SyncManager::SyncInternal::OnSyncEngineEvent(
2467731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const SyncEngineEvent& event) {
246872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (observers_.size() <= 0)
2469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Only send an event if this is due to a cycle ending and this cycle
2472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // concludes a canonical "sync" process; that is, based on what is known
2473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // locally we are "all happy" and up-to-date.  There may be new changes on
2474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the server, but we'll get them on a subsequent sync.
2475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
2476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Notifications are sent at the end of every sync cycle, regardless of
2477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // whether we should sync again.
2478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ModelSafeRoutingInfo enabled_types;
2480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_->GetModelSafeRoutingInfo(&enabled_types);
2481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    {
2482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Check to see if we need to notify the frontend that we have newly
2483dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // encrypted types or that we require a passphrase.
2484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sync_api::ReadTransaction trans(GetUserShare());
2485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sync_api::ReadNode node(&trans);
2486dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!node.InitByTagLookup(kNigoriTag)) {
2487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        DCHECK(!event.snapshot->is_share_usable);
2488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
2489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
2490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
2491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      syncable::ModelTypeSet encrypted_types =
2492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          syncable::GetEncryptedDataTypesFromNigori(nigori);
2493dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // If passwords are enabled, they're automatically considered encrypted.
2494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (enabled_types.count(syncable::PASSWORDS) > 0)
2495dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        encrypted_types.insert(syncable::PASSWORDS);
2496dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!encrypted_types.empty()) {
2497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        Cryptographer* cryptographer = trans.GetCryptographer();
2498dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) {
2499dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (!nigori.encrypted().blob().empty()) {
2500dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            DCHECK(!cryptographer->CanDecrypt(nigori.encrypted()));
2501dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            cryptographer->SetPendingKeys(nigori.encrypted());
2502dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          }
2503dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
25043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2505dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // If we've completed a sync cycle and the cryptographer isn't ready
2506dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // yet, prompt the user for a passphrase.
2507dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (cryptographer->has_pending_keys()) {
2508dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2509dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            OnPassphraseRequired(true));
2510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        } else if (!cryptographer->is_ready()) {
2511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            OnPassphraseRequired(false));
2513dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        } else {
2514dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2515dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                            OnEncryptionComplete(encrypted_types));
2516dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
2517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
2518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!initialized())
2521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
2522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!event.snapshot->has_more_to_sync) {
252472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
252572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        OnSyncCycleCompleted(event.snapshot));
2526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // This is here for tests, which are still using p2p notifications.
2529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // SendNotification does not do anything if we are using server based
2530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // notifications.
2531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // TODO(chron): Consider changing this back to track has_more_to_sync
2532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // only notify peers if a successful commit has occurred.
2533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool new_notification =
2534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (event.snapshot->syncer_status.num_successful_commits > 0);
2535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (new_notification) {
2536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      core_message_loop_->PostTask(
2537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          FROM_HERE,
2538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(
2539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              this,
2540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              &SyncManager::SyncInternal::SendNotification));
2541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
2542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2544731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
254572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
254672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      OnStopSyncingPermanently());
2547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2550731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
255172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
255272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      OnClearServerDataSucceeded());
2553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2556731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
255772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
255872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      OnClearServerDataFailed());
25593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
25603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2562731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
256372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
256472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      OnUpdatedToken(event.updated_token));
25653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
25663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
256972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::SyncInternal::SetParentJsEventRouter(
257072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    browser_sync::JsEventRouter* router) {
257172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(router);
257272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  parent_router_ = router;
257372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
257472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
257572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::SyncInternal::RemoveParentJsEventRouter() {
257672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  parent_router_ = NULL;
257772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
257872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
257972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst browser_sync::JsEventRouter*
258072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SyncManager::SyncInternal::GetParentJsEventRouter() const {
258172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return parent_router_;
258272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
258372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
258472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace {
258572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
258672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid LogNoRouter(const std::string& name,
258772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                 const browser_sync::JsArgList& args) {
258872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  VLOG(1) << "No parent router; not replying to message " << name
258972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          << " with args " << args.ToString();
259072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
259172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
259272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}  // namespace
259372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
259472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::SyncInternal::ProcessMessage(
259572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& name, const browser_sync::JsArgList& args,
259672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const browser_sync::JsEventHandler* sender) {
259772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(initialized_);
259872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (name == "getNotificationState") {
259972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!parent_router_) {
260072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LogNoRouter(name, args);
260172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
260272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
260372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    bool notifications_enabled = allstatus_.status().notifications_enabled;
260472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue return_args;
260572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return_args.Append(Value::CreateBooleanValue(notifications_enabled));
260672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    parent_router_->RouteJsEvent(
260772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        "onGetNotificationStateFinished",
260872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        browser_sync::JsArgList(return_args), sender);
2609ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (name == "getNotificationInfo") {
2610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!parent_router_) {
2611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LogNoRouter(name, args);
2612ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
2613ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
2614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ListValue return_args;
2616ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return_args.Append(NotificationInfoToValue(notification_info_map_));
2617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parent_router_->RouteJsEvent("onGetNotificationInfoFinished",
2618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        browser_sync::JsArgList(return_args), sender);
261972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else if (name == "getRootNode") {
262072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!parent_router_) {
262172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LogNoRouter(name, args);
262272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
262372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
262472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ReadTransaction trans(GetUserShare());
262572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ReadNode root(&trans);
262672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    root.InitByRootLookup();
262772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue return_args;
262872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return_args.Append(root.ToValue());
262972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    parent_router_->RouteJsEvent(
263072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        "onGetRootNodeFinished",
263172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        browser_sync::JsArgList(return_args), sender);
263272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else if (name == "getNodeById") {
263372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!parent_router_) {
263472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      LogNoRouter(name, args);
263572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
263672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
263772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    parent_router_->RouteJsEvent(
263872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        "onGetNodeByIdFinished", ProcessGetNodeByIdMessage(args), sender);
2639ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (name == "findNodesContainingString") {
2640ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!parent_router_) {
2641ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LogNoRouter(name, args);
2642ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
2643ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
2644ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parent_router_->RouteJsEvent(
2645ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        "onFindNodesContainingStringFinished",
2646ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ProcessFindNodesContainingString(args), sender);
264772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
264872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    VLOG(1) << "Dropping unknown message " << name
264972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              << " with args " << args.ToString();
265072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
265172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
265272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
265372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbrowser_sync::JsArgList SyncManager::SyncInternal::ProcessGetNodeByIdMessage(
265472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const browser_sync::JsArgList& args) {
265572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ListValue null_return_args_list;
265672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  null_return_args_list.Append(Value::CreateNullValue());
265772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  browser_sync::JsArgList null_return_args(null_return_args_list);
265872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string id_str;
265972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!args.Get().GetString(0, &id_str)) {
266072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null_return_args;
266172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
266272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int64 id;
266372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!base::StringToInt64(id_str, &id)) {
266472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null_return_args;
266572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
266672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (id == kInvalidId) {
266772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null_return_args;
266872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
266972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ReadTransaction trans(GetUserShare());
267072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ReadNode node(&trans);
267172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!node.InitByIdLookup(id)) {
267272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null_return_args;
267372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
267472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ListValue return_args;
267572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return_args.Append(node.ToValue());
267672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return browser_sync::JsArgList(return_args);
267772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
267872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2679ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbrowser_sync::JsArgList SyncManager::SyncInternal::
2680ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProcessFindNodesContainingString(
2681ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const browser_sync::JsArgList& args) {
2682ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string query;
2683ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue return_args;
2684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!args.Get().GetString(0, &query)) {
2685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return_args.Append(new ListValue());
2686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return browser_sync::JsArgList(return_args);
2687ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
2688ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2689ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue* result = FindNodesContainingString(query);
2690ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return_args.Append(result);
2691ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return browser_sync::JsArgList(return_args);
2692ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
2693ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::OnNotificationStateChange(
2695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool notifications_enabled) {
2696731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "P2P: Notifications enabled = "
2697731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          << (notifications_enabled ? "true" : "false");
2698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  allstatus_.SetNotificationsEnabled(notifications_enabled);
2699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (syncer_thread()) {
2700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    syncer_thread()->set_notifications_enabled(notifications_enabled);
2701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
270272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (parent_router_) {
270372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue args;
270472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    args.Append(Value::CreateBooleanValue(notifications_enabled));
270572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // TODO(akalin): Tidy up grammar in event names.
270672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    parent_router_->RouteJsEvent("onSyncNotificationStateChange",
270772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 browser_sync::JsArgList(args), NULL);
270872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
2709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2711ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::UpdateNotificationInfo(
2712ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const syncable::ModelTypePayloadMap& type_payloads) {
2713ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
2714ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       it != type_payloads.end(); ++it) {
2715ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NotificationInfo* info = &notification_info_map_[it->first];
2716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    info->total_count++;
2717ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    info->payload = it->second;
2718ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
2719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::OnIncomingNotification(
2722ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const syncable::ModelTypePayloadMap& type_payloads) {
2723ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!type_payloads.empty()) {
27244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (syncer_thread()) {
2725ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncer_thread()->ScheduleNudgeWithPayloads(
2726ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          TimeDelta::FromMilliseconds(kSyncerThreadDelayMsec),
2727ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          browser_sync::NUDGE_SOURCE_NOTIFICATION,
2728ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          type_payloads, FROM_HERE);
27294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
27304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    allstatus_.IncrementNotificationsReceived();
2731ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    UpdateNotificationInfo(type_payloads);
27324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  } else {
27334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    LOG(WARNING) << "Sync received notification without any type information.";
27344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
273572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
273672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (parent_router_) {
273772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue args;
273872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue* changed_types = new ListValue();
273972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    args.Append(changed_types);
2740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (syncable::ModelTypePayloadMap::const_iterator
2741ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             it = type_payloads.begin();
2742ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         it != type_payloads.end(); ++it) {
274372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      const std::string& model_type_str =
274472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          syncable::ModelTypeToString(it->first);
274572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      changed_types->Append(Value::CreateStringValue(model_type_str));
274672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
274772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    parent_router_->RouteJsEvent("onSyncIncomingNotification",
274872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 browser_sync::JsArgList(args), NULL);
274972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
2750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2752ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SyncManager::SyncInternal::StoreState(
2753ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& state) {
2754731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2755731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!lookup.good()) {
2756731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    LOG(ERROR) << "Could not write notification state";
2757731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // TODO(akalin): Propagate result callback all the way to this
2758731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // function and call it with "false" to signal failure.
2759731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
2760731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
2761731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (VLOG_IS_ON(1)) {
2762731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string encoded_state;
2763731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::Base64Encode(state, &encoded_state);
2764731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Writing notification state: " << encoded_state;
2765731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
2766731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  lookup->SetNotificationState(state);
2767731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  lookup->SaveChanges();
2768731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
2769731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
277072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::SyncInternal::AddObserver(
277172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SyncManager::Observer* observer) {
277272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  observers_.AddObserver(observer);
277372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
277472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
277572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::SyncInternal::RemoveObserver(
277672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    SyncManager::Observer* observer) {
277772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  observers_.RemoveObserver(observer);
277872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
277972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2780c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncManager::Status::Summary SyncManager::GetStatusSummary() const {
278172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return data_->GetStatus().summary;
2782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2784c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncManager::Status SyncManager::GetDetailedStatus() const {
278572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return data_->GetStatus();
2786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2788c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
2789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SaveChanges() {
2791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_->SaveChanges();
2792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SyncManager::SyncInternal::SaveChanges() {
2795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!lookup.good()) {
2797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false) << "ScopedDirLookup creation failed; Unable to SaveChanges";
2798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lookup->SaveChanges();
2801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////
2804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BaseTransaction member definitions
2805c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTransaction::BaseTransaction(UserShare* share)
2806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : lookup_(NULL) {
2807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(share && share->dir_manager.get());
2808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
28093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                          share->name);
2810ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  cryptographer_ = share->dir_manager->GetCryptographer(this);
2811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!(lookup_->good()))
2812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(false) << "ScopedDirLookup failed on valid DirManager.";
2813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2814c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTransaction::~BaseTransaction() {
2815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete lookup_;
2816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2818c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUserShare* SyncManager::GetUserShare() const {
2819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
2820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return data_->GetUserShare();
2821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
2822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SyncManager::HasUnsyncedItems() const {
28243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  sync_api::ReadTransaction trans(GetUserShare());
28253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
28263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
28273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
282872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::TriggerOnNotificationStateChangeForTest(
282972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    bool notifications_enabled) {
283072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  data_->OnNotificationStateChange(notifications_enabled);
283172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
283272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
283372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SyncManager::TriggerOnIncomingNotificationForTest(
283472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const syncable::ModelTypeBitSet& model_types) {
2835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncable::ModelTypePayloadMap model_types_with_payloads =
2836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      syncable::ModelTypePayloadMapFromBitSet(model_types,
2837ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          std::string());
2838ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
2839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_->OnIncomingNotification(model_types_with_payloads);
284072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
284172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace sync_api
2843