1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/new_tab_page_sync_handler.h"
6
7 #include <vector>
8
9 #include "base/callback.h"
10 #include "base/string_split.h"
11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/net/chrome_url_request_context.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "content/browser/renderer_host/render_view_host.h"
17 #include "grit/generated_resources.h"
18 #include "net/base/cookie_monster.h"
19 #include "net/url_request/url_request_context.h"
20 #include "ui/base/l10n/l10n_util.h"
21
22 // Default URL for the sync web interface.
23 //
24 // TODO(idana): when we figure out how we are going to allow third parties to
25 // plug in their own sync engine, we should allow this value to be
26 // configurable.
27 static const char kSyncDefaultViewOnlineUrl[] = "http://docs.google.com";
28
29 // TODO(idana): the following code was originally copied from
30 // toolbar_importer.h/cc and it needs to be moved to a common Google Accounts
31 // utility.
32
33 // A simple pair of fields that identify a set of Google cookies, used to
34 // filter from a larger set.
35 struct GoogleCookieFilter {
36 // The generalized, fully qualified URL of pages where
37 // cookies with id |cookie_id| are obtained / accessed.
38 const char* url;
39 // The id of the cookie this filter is selecting,
40 // with name/value delimiter (i.e '=').
41 const char* cookie_id;
42 };
43
44 // Filters to select Google GAIA cookies.
45 static const GoogleCookieFilter kGAIACookieFilters[] = {
46 { "http://.google.com/", "SID=" }, // Gmail.
47 // Add filters here for other interesting cookies that should result in
48 // showing the promotions (e.g ASIDAS for dasher accounts).
49 };
50
IsGoogleGAIACookieInstalled()51 bool IsGoogleGAIACookieInstalled() {
52 for (size_t i = 0; i < arraysize(kGAIACookieFilters); ++i) {
53 // Since we are running on the UI thread don't call GetURLRequestContext().
54 net::CookieStore* store =
55 Profile::GetDefaultRequestContext()->DONTUSEME_GetCookieStore();
56 GURL url(kGAIACookieFilters[i].url);
57 net::CookieOptions options;
58 options.set_include_httponly(); // The SID cookie might be httponly.
59 std::string cookies = store->GetCookiesWithOptions(url, options);
60 std::vector<std::string> cookie_list;
61 base::SplitString(cookies, ';', &cookie_list);
62 for (std::vector<std::string>::iterator current = cookie_list.begin();
63 current != cookie_list.end();
64 ++current) {
65 size_t position =
66 current->find(kGAIACookieFilters[i].cookie_id);
67 if (0 == position)
68 return true;
69 }
70 }
71 return false;
72 }
73
NewTabPageSyncHandler()74 NewTabPageSyncHandler::NewTabPageSyncHandler() : sync_service_(NULL),
75 waiting_for_initial_page_load_(true) {
76 }
77
~NewTabPageSyncHandler()78 NewTabPageSyncHandler::~NewTabPageSyncHandler() {
79 if (sync_service_)
80 sync_service_->RemoveObserver(this);
81 }
82
83 // static
84 NewTabPageSyncHandler::MessageType
FromSyncStatusMessageType(sync_ui_util::MessageType type)85 NewTabPageSyncHandler::FromSyncStatusMessageType(
86 sync_ui_util::MessageType type) {
87 switch (type) {
88 case sync_ui_util::SYNC_ERROR:
89 return SYNC_ERROR;
90 case sync_ui_util::SYNC_PROMO:
91 return SYNC_PROMO;
92 case sync_ui_util::PRE_SYNCED:
93 case sync_ui_util::SYNCED:
94 default:
95 return HIDE;
96 }
97 }
98
Attach(WebUI * web_ui)99 WebUIMessageHandler* NewTabPageSyncHandler::Attach(WebUI* web_ui) {
100 sync_service_ = web_ui->GetProfile()->GetProfileSyncService();
101 DCHECK(sync_service_); // This shouldn't get called by an incognito NTP.
102 DCHECK(!sync_service_->IsManaged()); // And neither if sync is managed.
103 sync_service_->AddObserver(this);
104 return WebUIMessageHandler::Attach(web_ui);
105 }
106
RegisterMessages()107 void NewTabPageSyncHandler::RegisterMessages() {
108 web_ui_->RegisterMessageCallback("GetSyncMessage",
109 NewCallback(this, &NewTabPageSyncHandler::HandleGetSyncMessage));
110 web_ui_->RegisterMessageCallback("SyncLinkClicked",
111 NewCallback(this, &NewTabPageSyncHandler::HandleSyncLinkClicked));
112 }
113
HandleGetSyncMessage(const ListValue * args)114 void NewTabPageSyncHandler::HandleGetSyncMessage(const ListValue* args) {
115 waiting_for_initial_page_load_ = false;
116 BuildAndSendSyncStatus();
117 }
118
HideSyncStatusSection()119 void NewTabPageSyncHandler::HideSyncStatusSection() {
120 SendSyncMessageToPage(HIDE, std::string(), std::string());
121 }
122
BuildAndSendSyncStatus()123 void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
124 DCHECK(!waiting_for_initial_page_load_);
125
126 // Hide the sync status section if sync is managed or disabled entirely.
127 if (!sync_service_ || sync_service_->IsManaged()) {
128 HideSyncStatusSection();
129 return;
130 }
131
132 // Don't show sync status if setup is not complete.
133 if (!sync_service_->HasSyncSetupCompleted()) {
134 return;
135 }
136
137 // Once sync has been enabled, the supported "sync statuses" for the NNTP
138 // from the user's perspective are:
139 //
140 // "Sync error", when we can't authenticate or establish a connection with
141 // the sync server (appropriate information appended to
142 // message).
143 string16 status_msg;
144 string16 link_text;
145 sync_ui_util::MessageType type =
146 sync_ui_util::GetStatusLabelsForNewTabPage(sync_service_,
147 &status_msg,
148 &link_text);
149 SendSyncMessageToPage(FromSyncStatusMessageType(type),
150 UTF16ToUTF8(status_msg), UTF16ToUTF8(link_text));
151 }
152
HandleSyncLinkClicked(const ListValue * args)153 void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
154 DCHECK(!waiting_for_initial_page_load_);
155 DCHECK(sync_service_);
156 if (!sync_service_->IsSyncEnabled())
157 return;
158 if (sync_service_->HasSyncSetupCompleted()) {
159 sync_service_->ShowErrorUI(NULL);
160 DictionaryValue value;
161 value.SetString("syncEnabledMessage",
162 l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO,
163 sync_service_->GetAuthenticatedUsername()));
164 web_ui_->CallJavascriptFunction("syncAlreadyEnabled", value);
165 } else {
166 // User clicked the 'Start now' link to begin syncing.
167 ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP);
168 sync_service_->ShowLoginDialog(NULL);
169 }
170 }
171
OnStateChanged()172 void NewTabPageSyncHandler::OnStateChanged() {
173 // Don't do anything if the page has not yet loaded.
174 if (waiting_for_initial_page_load_)
175 return;
176 BuildAndSendSyncStatus();
177 }
178
SendSyncMessageToPage(MessageType type,std::string msg,std::string linktext)179 void NewTabPageSyncHandler::SendSyncMessageToPage(
180 MessageType type, std::string msg,
181 std::string linktext) {
182 DictionaryValue value;
183 std::string user;
184 std::string title;
185 std::string linkurl;
186
187 // If there is nothing to show, we should hide the sync section altogether.
188 if (type == HIDE || (msg.empty() && linktext.empty())) {
189 value.SetBoolean("syncsectionisvisible", false);
190 } else {
191 if (type == SYNC_ERROR)
192 title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
193 else if (type == SYNC_PROMO)
194 title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE);
195 else
196 NOTREACHED();
197
198 value.SetBoolean("syncsectionisvisible", true);
199 value.SetString("msg", msg);
200 value.SetString("title", title);
201 if (linktext.empty()) {
202 value.SetBoolean("linkisvisible", false);
203 } else {
204 value.SetBoolean("linkisvisible", true);
205 value.SetString("linktext", linktext);
206
207 // The only time we set the URL is when the user is synced and we need to
208 // show a link to a web interface (e.g. http://docs.google.com). When we
209 // set that URL, HandleSyncLinkClicked won't be called when the user
210 // clicks on the link.
211 if (linkurl.empty()) {
212 value.SetBoolean("linkurlisset", false);
213 } else {
214 value.SetBoolean("linkurlisset", true);
215 value.SetString("linkurl", linkurl);
216 }
217 }
218 }
219 web_ui_->CallJavascriptFunction("syncMessageChanged", value);
220 }
221