blob: d14df5c5be8c04cb31d9247037f0407c5c523d97 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/dom_ui/plugins_ui.h"
#include <algorithm>
#include <string>
#include <vector>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/singleton.h"
#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "webkit/glue/plugins/plugin_list.h"
namespace {
///////////////////////////////////////////////////////////////////////////////
//
// PluginsHTMLSource
//
///////////////////////////////////////////////////////////////////////////////
class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
PluginsUIHTMLSource()
: DataSource(chrome::kChromeUIPluginsHost, MessageLoop::current()) {}
// Called when the network layer has requested a resource underneath
// the path we registered.
virtual void StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id);
virtual std::string GetMimeType(const std::string&) const {
return "text/html";
}
private:
~PluginsUIHTMLSource() {}
DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource);
};
void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
// Strings used in the JsTemplate file.
DictionaryValue localized_strings;
localized_strings.SetString(L"pluginsTitle",
l10n_util::GetString(IDS_PLUGINS_TITLE));
localized_strings.SetString(L"pluginsDetailsModeLink",
l10n_util::GetString(IDS_PLUGINS_DETAILS_MODE_LINK));
localized_strings.SetString(L"pluginsNoneInstalled",
l10n_util::GetString(IDS_PLUGINS_NONE_INSTALLED));
localized_strings.SetString(L"pluginDisabled",
l10n_util::GetString(IDS_PLUGINS_DISABLED_PLUGIN));
localized_strings.SetString(L"pluginVersion",
l10n_util::GetString(IDS_PLUGINS_VERSION));
localized_strings.SetString(L"pluginDescription",
l10n_util::GetString(IDS_PLUGINS_DESCRIPTION));
localized_strings.SetString(L"pluginPath",
l10n_util::GetString(IDS_PLUGINS_PATH));
localized_strings.SetString(L"pluginMimeTypes",
l10n_util::GetString(IDS_PLUGINS_MIME_TYPES));
localized_strings.SetString(L"pluginMimeTypesMimeType",
l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
localized_strings.SetString(L"pluginMimeTypesDescription",
l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
localized_strings.SetString(L"pluginMimeTypesFileExtensions",
l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
localized_strings.SetString(L"disable",
l10n_util::GetString(IDS_PLUGINS_DISABLE));
localized_strings.SetString(L"enable",
l10n_util::GetString(IDS_PLUGINS_ENABLE));
ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
static const base::StringPiece plugins_html(
ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PLUGINS_HTML));
std::string full_html(plugins_html.data(), plugins_html.size());
jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
html_bytes->data.resize(full_html.size());
std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
SendResponse(request_id, html_bytes);
}
////////////////////////////////////////////////////////////////////////////////
//
// PluginsDOMHandler
//
////////////////////////////////////////////////////////////////////////////////
// The handler for Javascript messages for the chrome://plugins/ page.
// TODO(viettrungluu): Make plugin list updates notify, and then observe
// changes; maybe replumb plugin list through plugin service?
// <http://crbug.com/39101>
class PluginsDOMHandler : public DOMMessageHandler {
public:
PluginsDOMHandler() {}
virtual ~PluginsDOMHandler() {}
// DOMMessageHandler implementation.
virtual void RegisterMessages();
// Callback for the "requestPluginsData" message.
void HandleRequestPluginsData(const Value* value);
// Callback for the "enablePlugin" message.
void HandleEnablePluginMessage(const Value* value);
// Callback for the "showTermsOfService" message. This really just opens a new
// window with about:terms. Flash can't link directly to about:terms due to
// the security model.
void HandleShowTermsOfServiceMessage(const Value* value);
private:
// Creates a dictionary containing all the information about the given plugin;
// this is put into the list to "return" for the "requestPluginsData" message.
DictionaryValue* CreatePluginDetailValue(const WebPluginInfo& plugin);
// Creates a dictionary containing the important parts of the information
// about the given plugin; this is put into a list and saved in prefs.
DictionaryValue* CreatePluginSummaryValue(const WebPluginInfo& plugin);
// Update the user preferences to reflect the current (user-selected) state of
// plugins.
void UpdatePreferences();
DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
};
void PluginsDOMHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("requestPluginsData",
NewCallback(this, &PluginsDOMHandler::HandleRequestPluginsData));
dom_ui_->RegisterMessageCallback("enablePlugin",
NewCallback(this, &PluginsDOMHandler::HandleEnablePluginMessage));
dom_ui_->RegisterMessageCallback("showTermsOfService",
NewCallback(this, &PluginsDOMHandler::HandleShowTermsOfServiceMessage));
}
void PluginsDOMHandler::HandleRequestPluginsData(const Value* value) {
DictionaryValue* results = new DictionaryValue();
// Add plugins to the results structure.
ListValue* plugins_list = new ListValue();
std::vector<WebPluginInfo> plugins;
NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
it != plugins.end();
++it) {
plugins_list->Append(CreatePluginDetailValue(*it));
}
results->Set(L"plugins", plugins_list);
dom_ui_->CallJavascriptFunction(L"returnPluginsData", *results);
}
void PluginsDOMHandler::HandleEnablePluginMessage(const Value* value) {
// Be robust in accepting badness since plug-ins display HTML (hence
// JavaScript).
if (!value->IsType(Value::TYPE_LIST))
return;
const ListValue* list = static_cast<const ListValue*>(value);
if (list->GetSize() != 2)
return;
FilePath::StringType plugin_path;
std::string enable_str;
if (!list->GetString(0, &plugin_path) ||
!list->GetString(1, &enable_str))
return;
if (enable_str == "true")
NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(plugin_path));
else
NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(plugin_path));
// TODO(viettrungluu): It's morally wrong to do this here (it should be done
// by the plugins service), and we might also want to ensure that the plugins
// list is always written to prefs even when the user hasn't disabled a
// plugin. This will require refactoring the plugin list and service.
// <http://crbug.com/39101>
UpdatePreferences();
}
void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const Value* value) {
// Show it in a new browser window....
Browser* browser = Browser::Create(dom_ui_->GetProfile());
browser->OpenURL(GURL(chrome::kAboutTermsURL),
GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
browser->window()->Show();
}
DictionaryValue* PluginsDOMHandler::CreatePluginDetailValue(
const WebPluginInfo& plugin) {
DictionaryValue* plugin_data = new DictionaryValue();
plugin_data->SetString(L"path", plugin.path.value());
plugin_data->SetStringFromUTF16(L"name", plugin.name);
plugin_data->SetStringFromUTF16(L"version", plugin.version);
plugin_data->SetStringFromUTF16(L"description", plugin.desc);
plugin_data->SetBoolean(L"enabled", plugin.enabled);
ListValue* mime_types = new ListValue();
for (std::vector<WebPluginMimeType>::const_iterator type_it =
plugin.mime_types.begin();
type_it != plugin.mime_types.end();
++type_it) {
DictionaryValue* mime_type = new DictionaryValue();
mime_type->SetString(L"mimeType", type_it->mime_type);
mime_type->SetStringFromUTF16(L"description", type_it->description);
ListValue* file_extensions = new ListValue();
for (std::vector<std::string>::const_iterator ext_it =
type_it->file_extensions.begin();
ext_it != type_it->file_extensions.end();
++ext_it) {
file_extensions->Append(new StringValue(*ext_it));
}
mime_type->Set(L"fileExtensions", file_extensions);
mime_types->Append(mime_type);
}
plugin_data->Set(L"mimeTypes", mime_types);
return plugin_data;
}
DictionaryValue* PluginsDOMHandler::CreatePluginSummaryValue(
const WebPluginInfo& plugin) {
DictionaryValue* plugin_data = new DictionaryValue();
plugin_data->SetString(L"path", plugin.path.value());
plugin_data->SetStringFromUTF16(L"name", plugin.name);
plugin_data->SetStringFromUTF16(L"version", plugin.version);
plugin_data->SetBoolean(L"enabled", plugin.enabled);
return plugin_data;
}
// TODO(viettrungluu): move this (and the registration of the prefs into the
// plugins service.
void PluginsDOMHandler::UpdatePreferences() {
PrefService* prefs = dom_ui_->GetProfile()->GetPrefs();
FilePath internal_dir;
if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
prefs->SetFilePath(prefs::kPluginsLastInternalDirectory, internal_dir);
ListValue* plugins_list = prefs->GetMutableList(prefs::kPluginsPluginsList);
plugins_list->Clear();
std::vector<WebPluginInfo> plugins;
NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
it != plugins.end();
++it) {
plugins_list->Append(CreatePluginSummaryValue(*it));
}
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
//
// PluginsUI
//
///////////////////////////////////////////////////////////////////////////////
PluginsUI::PluginsUI(TabContents* contents) : DOMUI(contents) {
AddMessageHandler((new PluginsDOMHandler())->Attach(this));
PluginsUIHTMLSource* html_source = new PluginsUIHTMLSource();
// Set up the chrome://plugins/ source.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
// static
RefCountedMemory* PluginsUI::GetFaviconResourceBytes() {
return ResourceBundle::GetSharedInstance().
LoadDataResourceBytes(IDR_PLUGIN);
}
// static
void PluginsUI::RegisterUserPrefs(PrefService* prefs) {
FilePath internal_dir;
PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
internal_dir);
prefs->RegisterListPref(prefs::kPluginsPluginsList);
prefs->RegisterBooleanPref(prefs::kPluginsEnabledInternalPDF, false);
}