1// Copyright (c) 2012 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/options/handler_options_handler.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/values.h"
14#include "chrome/browser/chrome_notification_types.h"
15#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/grit/generated_resources.h"
18#include "components/google/core/browser/google_util.h"
19#include "content/public/browser/web_ui.h"
20
21namespace options {
22
23namespace {
24
25const char kHandlersLearnMoreUrl[] =
26    "https://support.google.com/chrome/answer/1382847";
27
28}  // namespace
29
30HandlerOptionsHandler::HandlerOptionsHandler() {
31}
32
33HandlerOptionsHandler::~HandlerOptionsHandler() {
34}
35
36void HandlerOptionsHandler::GetLocalizedValues(
37    base::DictionaryValue* localized_strings) {
38  DCHECK(localized_strings);
39
40  static OptionsStringResource resources[] = {
41      { "handlers_tab_label", IDS_HANDLERS_TAB_LABEL },
42      { "handlers_allow", IDS_HANDLERS_ALLOW_RADIO },
43      { "handlers_block", IDS_HANDLERS_DONOTALLOW_RADIO },
44      { "handlers_type_column_header", IDS_HANDLERS_TYPE_COLUMN_HEADER },
45      { "handlers_site_column_header", IDS_HANDLERS_SITE_COLUMN_HEADER },
46      { "handlers_remove_link", IDS_HANDLERS_REMOVE_HANDLER_LINK },
47      { "handlers_none_handler", IDS_HANDLERS_NONE_HANDLER },
48      { "handlers_active_heading", IDS_HANDLERS_ACTIVE_HEADING },
49      { "handlers_ignored_heading", IDS_HANDLERS_IGNORED_HEADING },
50  };
51  RegisterTitle(localized_strings, "handlersPage",
52                IDS_HANDLER_OPTIONS_WINDOW_TITLE);
53  RegisterStrings(localized_strings, resources, arraysize(resources));
54
55  localized_strings->SetString("handlers_learn_more_url",
56                               kHandlersLearnMoreUrl);
57}
58
59void HandlerOptionsHandler::InitializeHandler() {
60  notification_registrar_.Add(
61      this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
62      content::Source<Profile>(Profile::FromWebUI(web_ui())));
63}
64
65void HandlerOptionsHandler::InitializePage() {
66  UpdateHandlerList();
67}
68
69void HandlerOptionsHandler::RegisterMessages() {
70  web_ui()->RegisterMessageCallback("clearDefault",
71      base::Bind(&HandlerOptionsHandler::ClearDefault,
72                 base::Unretained(this)));
73  web_ui()->RegisterMessageCallback("removeHandler",
74      base::Bind(&HandlerOptionsHandler::RemoveHandler,
75                 base::Unretained(this)));
76  web_ui()->RegisterMessageCallback("setHandlersEnabled",
77      base::Bind(&HandlerOptionsHandler::SetHandlersEnabled,
78                 base::Unretained(this)));
79  web_ui()->RegisterMessageCallback("setDefault",
80      base::Bind(&HandlerOptionsHandler::SetDefault,
81                 base::Unretained(this)));
82  web_ui()->RegisterMessageCallback("removeIgnoredHandler",
83      base::Bind(&HandlerOptionsHandler::RemoveIgnoredHandler,
84                 base::Unretained(this)));
85}
86
87ProtocolHandlerRegistry* HandlerOptionsHandler::GetProtocolHandlerRegistry() {
88  return ProtocolHandlerRegistryFactory::GetForBrowserContext(
89      Profile::FromWebUI(web_ui()));
90}
91
92static void GetHandlersAsListValue(
93    const ProtocolHandlerRegistry::ProtocolHandlerList& handlers,
94    base::ListValue* handler_list) {
95  ProtocolHandlerRegistry::ProtocolHandlerList::const_iterator handler;
96  for (handler = handlers.begin(); handler != handlers.end(); ++handler) {
97    base::ListValue* handlerValue = new base::ListValue();
98    handlerValue->Append(new base::StringValue(handler->protocol()));
99    handlerValue->Append(new base::StringValue(handler->url().spec()));
100    handlerValue->Append(new base::StringValue(handler->url().host()));
101    handler_list->Append(handlerValue);
102  }
103}
104
105void HandlerOptionsHandler::GetHandlersForProtocol(
106    const std::string& protocol,
107    base::DictionaryValue* handlers_value) {
108  ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry();
109  // The items which are to be written into |handlers_value| are also described
110  // in chrome/browser/resources/options/handler_options.js in @typedef
111  // for Handlers. Please update them whenever you add or remove any keys here.
112  handlers_value->SetString("protocol", protocol);
113  handlers_value->SetInteger("default_handler",
114      registry->GetHandlerIndex(protocol));
115  handlers_value->SetBoolean(
116      "is_default_handler_set_by_user",
117      registry->IsRegisteredByUser(registry->GetHandlerFor(protocol)));
118  handlers_value->SetBoolean("has_policy_recommendations",
119                             registry->HasPolicyRegisteredHandler(protocol));
120
121  base::ListValue* handlers_list = new base::ListValue();
122  GetHandlersAsListValue(registry->GetHandlersFor(protocol), handlers_list);
123  handlers_value->Set("handlers", handlers_list);
124}
125
126void HandlerOptionsHandler::GetIgnoredHandlers(base::ListValue* handlers) {
127  ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry();
128  ProtocolHandlerRegistry::ProtocolHandlerList ignored_handlers =
129      registry->GetIgnoredHandlers();
130  return GetHandlersAsListValue(ignored_handlers, handlers);
131}
132
133void HandlerOptionsHandler::UpdateHandlerList() {
134  ProtocolHandlerRegistry* registry = GetProtocolHandlerRegistry();
135  std::vector<std::string> protocols;
136  registry->GetRegisteredProtocols(&protocols);
137
138  base::ListValue handlers;
139  for (std::vector<std::string>::iterator protocol = protocols.begin();
140       protocol != protocols.end(); protocol++) {
141    base::DictionaryValue* handler_value = new base::DictionaryValue();
142    GetHandlersForProtocol(*protocol, handler_value);
143    handlers.Append(handler_value);
144  }
145
146  scoped_ptr<base::ListValue> ignored_handlers(new base::ListValue());
147  GetIgnoredHandlers(ignored_handlers.get());
148  web_ui()->CallJavascriptFunction("HandlerOptions.setHandlers", handlers);
149  web_ui()->CallJavascriptFunction("HandlerOptions.setIgnoredHandlers",
150                                   *ignored_handlers);
151}
152
153void HandlerOptionsHandler::RemoveHandler(const base::ListValue* args) {
154  const base::ListValue* list;
155  if (!args->GetList(0, &list)) {
156    NOTREACHED();
157    return;
158  }
159
160  ProtocolHandler handler(ParseHandlerFromArgs(list));
161  GetProtocolHandlerRegistry()->RemoveHandler(handler);
162
163  // No need to call UpdateHandlerList() - we should receive a notification
164  // that the ProtocolHandlerRegistry has changed and we will update the view
165  // then.
166}
167
168void HandlerOptionsHandler::RemoveIgnoredHandler(const base::ListValue* args) {
169  const base::ListValue* list;
170  if (!args->GetList(0, &list)) {
171    NOTREACHED();
172    return;
173  }
174
175  ProtocolHandler handler(ParseHandlerFromArgs(list));
176  GetProtocolHandlerRegistry()->RemoveIgnoredHandler(handler);
177}
178
179void HandlerOptionsHandler::SetHandlersEnabled(const base::ListValue* args) {
180  bool enabled = true;
181  CHECK(args->GetBoolean(0, &enabled));
182  if (enabled)
183    GetProtocolHandlerRegistry()->Enable();
184  else
185    GetProtocolHandlerRegistry()->Disable();
186}
187
188void HandlerOptionsHandler::ClearDefault(const base::ListValue* args) {
189  const base::Value* value;
190  CHECK(args->Get(0, &value));
191  std::string protocol_to_clear;
192  CHECK(value->GetAsString(&protocol_to_clear));
193  GetProtocolHandlerRegistry()->ClearDefault(protocol_to_clear);
194}
195
196void HandlerOptionsHandler::SetDefault(const base::ListValue* args) {
197  const base::ListValue* list;
198  CHECK(args->GetList(0, &list));
199  const ProtocolHandler& handler(ParseHandlerFromArgs(list));
200  CHECK(!handler.IsEmpty());
201  GetProtocolHandlerRegistry()->OnAcceptRegisterProtocolHandler(handler);
202}
203
204ProtocolHandler HandlerOptionsHandler::ParseHandlerFromArgs(
205    const base::ListValue* args) const {
206  base::string16 protocol;
207  base::string16 url;
208  bool ok = args->GetString(0, &protocol) && args->GetString(1, &url);
209  if (!ok)
210    return ProtocolHandler::EmptyProtocolHandler();
211  return ProtocolHandler::CreateProtocolHandler(base::UTF16ToUTF8(protocol),
212                                                GURL(base::UTF16ToUTF8(url)));
213}
214
215void HandlerOptionsHandler::Observe(
216    int type,
217    const content::NotificationSource& source,
218    const content::NotificationDetails& details) {
219  if (type == chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED)
220    UpdateHandlerList();
221  else
222    NOTREACHED();
223}
224
225}  // namespace options
226