1 // Copyright 2013 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.
5 #include "chrome_frame/turndown_prompt/turndown_prompt.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/path_service.h"
15 #include "base/process/launch.h"
16 #include "base/win/scoped_bstr.h"
17 #include "base/win/scoped_comptr.h"
18 #include "base/win/win_util.h"
19 #include "chrome/installer/util/browser_distribution.h"
20 #include "chrome/installer/util/google_update_settings.h"
21 #include "chrome/installer/util/install_util.h"
22 #include "chrome/installer/util/installation_state.h"
23 #include "chrome/installer/util/util_constants.h"
24 #include "chrome_frame/infobars/infobar_manager.h"
25 #include "chrome_frame/policy_settings.h"
26 #include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h"
27 #include "chrome_frame/ready_mode/internal/url_launcher.h"
28 #include "chrome_frame/simple_resource_loader.h"
29 #include "chrome_frame/turndown_prompt/turndown_prompt_content.h"
30 #include "chrome_frame/utils.h"
31 #include "grit/chromium_strings.h"
32 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
36 void OnUninstallClicked(UrlLauncher* url_launcher);
38 // Manages the Turndown UI in response to browsing ChromeFrame-rendered
40 class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer {
42 BrowserObserver(IWebBrowser2* web_browser,
43 ReadyModeWebBrowserAdapter* adapter);
45 // ReadyModeWebBrowserAdapter::Observer implementation
46 virtual void OnNavigateTo(const string16& url);
47 virtual void OnRenderInChromeFrame(const string16& url);
48 virtual void OnRenderInHost(const string16& url);
51 // Shows the turndown prompt.
54 // Returns a self-managed pointer that is not guaranteed to survive handling
55 // of Windows events. For safety's sake, retrieve this pointer for each use
56 // and do not store it for use outside of scope.
57 InfobarManager* GetInfobarManager();
60 base::win::ScopedComPtr<IWebBrowser2> web_browser_;
61 ReadyModeWebBrowserAdapter* adapter_;
63 DISALLOW_COPY_AND_ASSIGN(BrowserObserver);
66 // Implements launching of a URL in an instance of IWebBrowser2.
67 class UrlLauncherImpl : public UrlLauncher {
69 explicit UrlLauncherImpl(IWebBrowser2* web_browser);
71 // UrlLauncher implementation
72 void LaunchUrl(const string16& url);
75 base::win::ScopedComPtr<IWebBrowser2> web_browser_;
78 UrlLauncherImpl::UrlLauncherImpl(IWebBrowser2* web_browser) {
80 web_browser_ = web_browser;
83 void UrlLauncherImpl::LaunchUrl(const string16& url) {
84 VARIANT flags = { VT_I4 };
85 V_I4(&flags) = navOpenInNewWindow;
86 base::win::ScopedBstr location(url.c_str());
88 HRESULT hr = web_browser_->Navigate(location, &flags, NULL, NULL, NULL);
89 DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. "
93 BrowserObserver::BrowserObserver(IWebBrowser2* web_browser,
94 ReadyModeWebBrowserAdapter* adapter)
95 : web_browser_(web_browser),
99 void BrowserObserver::OnNavigateTo(const string16& url) {
100 if (!net::registry_controlled_domains::SameDomainOrHost(
103 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) {
104 rendered_url_ = GURL();
109 void BrowserObserver::OnRenderInChromeFrame(const string16& url) {
111 rendered_url_ = GURL(url);
114 void BrowserObserver::OnRenderInHost(const string16& url) {
116 rendered_url_ = GURL(url);
119 void BrowserObserver::ShowPrompt() {
120 // This pointer is self-managed and not guaranteed to survive handling of
121 // Windows events. For safety's sake, retrieve this pointer for each use and
122 // do not store it for use outside of scope.
123 InfobarManager* infobar_manager = GetInfobarManager();
125 if (infobar_manager) {
126 // Owned by infobar_content
127 scoped_ptr<UrlLauncher> url_launcher(new UrlLauncherImpl(web_browser_));
129 // Owned by infobar_manager
130 scoped_ptr<InfobarContent> infobar_content(new TurndownPromptContent(
131 url_launcher.release(),
132 base::Bind(&OnUninstallClicked,
133 base::Owned(new UrlLauncherImpl(web_browser_)))));
135 infobar_manager->Show(infobar_content.release(), TOP_INFOBAR);
139 void BrowserObserver::Hide() {
140 InfobarManager* infobar_manager = GetInfobarManager();
142 infobar_manager->HideAll();
145 InfobarManager* BrowserObserver::GetInfobarManager() {
146 HRESULT hr = NOERROR;
148 base::win::ScopedComPtr<IOleWindow> ole_window;
149 hr = DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive());
150 if (FAILED(hr) || ole_window == NULL) {
151 DLOG(ERROR) << "Failed to query SID_SShellBrowser from IWebBrowser2. "
156 HWND web_browser_hwnd = NULL;
157 hr = ole_window->GetWindow(&web_browser_hwnd);
158 if (FAILED(hr) || web_browser_hwnd == NULL) {
159 DLOG(ERROR) << "Failed to query HWND from IOleWindow. "
164 return InfobarManager::Get(web_browser_hwnd);
167 // Returns true if the module into which this code is linked is installed at
169 bool IsCurrentModuleSystemLevel() {
170 base::FilePath dll_path;
171 if (PathService::Get(base::DIR_MODULE, &dll_path))
172 return !InstallUtil::IsPerUserInstall(dll_path.value().c_str());
176 // Attempts to create a ReadyModeWebBrowserAdapter instance.
177 bool CreateWebBrowserAdapter(ReadyModeWebBrowserAdapter** adapter) {
180 CComObject<ReadyModeWebBrowserAdapter>* com_object;
182 CComObject<ReadyModeWebBrowserAdapter>::CreateInstance(&com_object);
185 DLOG(ERROR) << "Failed to create instance of ReadyModeWebBrowserAdapter. "
190 com_object->AddRef();
191 *adapter = com_object;
195 // Attempts to install Turndown prompts in the provided web browser.
196 bool InstallPrompts(IWebBrowser2* web_browser) {
197 base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> adapter;
199 if (!CreateWebBrowserAdapter(adapter.Receive()))
202 // Pass ownership of our delegate to the BrowserObserver
203 scoped_ptr<ReadyModeWebBrowserAdapter::Observer> browser_observer(
204 new BrowserObserver(web_browser, adapter));
206 // Owns the BrowserObserver
207 return adapter->Initialize(web_browser, browser_observer.release());
210 // Launches the Chrome Frame uninstaller in response to user action. This
211 // implementation should not be used to uninstall MSI-based versions of GCF,
212 // since those must be removed by way of Windows Installer machinery.
213 void LaunchChromeFrameUninstaller() {
214 BrowserDistribution* dist =
215 BrowserDistribution::GetSpecificDistribution(
216 BrowserDistribution::CHROME_FRAME);
217 const bool system_level = IsCurrentModuleSystemLevel();
218 installer::ProductState product_state;
219 if (!product_state.Initialize(system_level, dist)) {
220 DLOG(ERROR) << "Chrome frame isn't installed at "
221 << (system_level ? "system" : "user") << " level.";
225 CommandLine uninstall_command(product_state.uninstall_command());
226 if (uninstall_command.GetProgram().empty()) {
227 DLOG(ERROR) << "No uninstall command found in registry.";
231 // Force Uninstall silences the prompt to reboot to complete uninstall.
232 uninstall_command.AppendSwitch(installer::switches::kForceUninstall);
233 VLOG(1) << "Uninstalling Chrome Frame with command: "
234 << uninstall_command.GetCommandLineString();
235 base::LaunchProcess(uninstall_command, base::LaunchOptions(), NULL);
238 void LaunchLearnMoreURL(UrlLauncher* url_launcher) {
239 url_launcher->LaunchUrl(SimpleResourceLoader::Get(
240 IDS_CHROME_FRAME_TURNDOWN_LEARN_MORE_URL));
243 void OnUninstallClicked(UrlLauncher* url_launcher) {
244 LaunchChromeFrameUninstaller();
245 LaunchLearnMoreURL(url_launcher);
250 namespace turndown_prompt {
252 bool IsPromptSuppressed() {
253 // See if this is an MSI install of GCF or if updates have been disabled.
254 BrowserDistribution* dist =
255 BrowserDistribution::GetSpecificDistribution(
256 BrowserDistribution::CHROME_FRAME);
258 const bool system_level = IsCurrentModuleSystemLevel();
259 bool multi_install = false;
261 installer::ProductState product_state;
262 if (product_state.Initialize(system_level, dist)) {
263 if (product_state.is_msi())
265 multi_install = product_state.is_multi_install();
270 BrowserDistribution::GetSpecificDistribution(
271 BrowserDistribution::CHROME_BINARIES);
273 if (GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), NULL) ==
274 GoogleUpdateSettings::UPDATES_DISABLED) {
278 // See if the prompt is explicitly suppressed via GP.
279 return PolicySettings::GetInstance()->suppress_turndown_prompt();
282 void Configure(IWebBrowser2* web_browser) {
283 if (!IsPromptSuppressed())
284 InstallPrompts(web_browser);
287 } // namespace turndown_prompt