- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / turndown_prompt / turndown_prompt.cc
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.
4
5 #include "chrome_frame/turndown_prompt/turndown_prompt.h"
6
7 #include <atlbase.h>
8 #include <shlguid.h>
9
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"
33
34 namespace {
35
36 void OnUninstallClicked(UrlLauncher* url_launcher);
37
38 // Manages the Turndown UI in response to browsing ChromeFrame-rendered
39 // pages.
40 class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer {
41  public:
42   BrowserObserver(IWebBrowser2* web_browser,
43                   ReadyModeWebBrowserAdapter* adapter);
44
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);
49
50  private:
51   // Shows the turndown prompt.
52   void ShowPrompt();
53   void Hide();
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();
58
59   GURL rendered_url_;
60   base::win::ScopedComPtr<IWebBrowser2> web_browser_;
61   ReadyModeWebBrowserAdapter* adapter_;
62
63   DISALLOW_COPY_AND_ASSIGN(BrowserObserver);
64 };
65
66 // Implements launching of a URL in an instance of IWebBrowser2.
67 class UrlLauncherImpl : public UrlLauncher {
68  public:
69   explicit UrlLauncherImpl(IWebBrowser2* web_browser);
70
71   // UrlLauncher implementation
72   void LaunchUrl(const string16& url);
73
74  private:
75   base::win::ScopedComPtr<IWebBrowser2> web_browser_;
76 };
77
78 UrlLauncherImpl::UrlLauncherImpl(IWebBrowser2* web_browser) {
79   DCHECK(web_browser);
80   web_browser_ = web_browser;
81 }
82
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());
87
88   HRESULT hr = web_browser_->Navigate(location, &flags, NULL, NULL, NULL);
89   DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. "
90                              << "Error: " << hr;
91 }
92
93 BrowserObserver::BrowserObserver(IWebBrowser2* web_browser,
94                                  ReadyModeWebBrowserAdapter* adapter)
95     : web_browser_(web_browser),
96       adapter_(adapter) {
97 }
98
99 void BrowserObserver::OnNavigateTo(const string16& url) {
100   if (!net::registry_controlled_domains::SameDomainOrHost(
101           GURL(url),
102           rendered_url_,
103           net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) {
104     rendered_url_ = GURL();
105     Hide();
106   }
107 }
108
109 void BrowserObserver::OnRenderInChromeFrame(const string16& url) {
110   ShowPrompt();
111   rendered_url_ = GURL(url);
112 }
113
114 void BrowserObserver::OnRenderInHost(const string16& url) {
115   Hide();
116   rendered_url_ = GURL(url);
117 }
118
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();
124
125   if (infobar_manager) {
126     // Owned by infobar_content
127     scoped_ptr<UrlLauncher> url_launcher(new UrlLauncherImpl(web_browser_));
128
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_)))));
134
135     infobar_manager->Show(infobar_content.release(), TOP_INFOBAR);
136   }
137 }
138
139 void BrowserObserver::Hide() {
140   InfobarManager* infobar_manager = GetInfobarManager();
141   if (infobar_manager)
142     infobar_manager->HideAll();
143 }
144
145 InfobarManager* BrowserObserver::GetInfobarManager() {
146   HRESULT hr = NOERROR;
147
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. "
152                 << "Error: " << hr;
153     return NULL;
154   }
155
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. "
160                 << "Error: " << hr;
161     return NULL;
162   }
163
164   return InfobarManager::Get(web_browser_hwnd);
165 }
166
167 // Returns true if the module into which this code is linked is installed at
168 // system-level.
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());
173   return false;
174 }
175
176 // Attempts to create a ReadyModeWebBrowserAdapter instance.
177 bool CreateWebBrowserAdapter(ReadyModeWebBrowserAdapter** adapter) {
178   *adapter = NULL;
179
180   CComObject<ReadyModeWebBrowserAdapter>* com_object;
181   HRESULT hr =
182       CComObject<ReadyModeWebBrowserAdapter>::CreateInstance(&com_object);
183
184   if (FAILED(hr)) {
185     DLOG(ERROR) << "Failed to create instance of ReadyModeWebBrowserAdapter. "
186                 << "Error: " << hr;
187     return false;
188   }
189
190   com_object->AddRef();
191   *adapter = com_object;
192   return true;
193 }
194
195 // Attempts to install Turndown prompts in the provided web browser.
196 bool InstallPrompts(IWebBrowser2* web_browser) {
197   base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> adapter;
198
199   if (!CreateWebBrowserAdapter(adapter.Receive()))
200     return false;
201
202   // Pass ownership of our delegate to the BrowserObserver
203   scoped_ptr<ReadyModeWebBrowserAdapter::Observer> browser_observer(
204       new BrowserObserver(web_browser, adapter));
205
206   // Owns the BrowserObserver
207   return adapter->Initialize(web_browser, browser_observer.release());
208 }
209
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.";
222     return;
223   }
224
225   CommandLine uninstall_command(product_state.uninstall_command());
226   if (uninstall_command.GetProgram().empty()) {
227     DLOG(ERROR) << "No uninstall command found in registry.";
228     return;
229   }
230
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);
236 }
237
238 void LaunchLearnMoreURL(UrlLauncher* url_launcher) {
239   url_launcher->LaunchUrl(SimpleResourceLoader::Get(
240       IDS_CHROME_FRAME_TURNDOWN_LEARN_MORE_URL));
241 }
242
243 void OnUninstallClicked(UrlLauncher* url_launcher) {
244   LaunchChromeFrameUninstaller();
245   LaunchLearnMoreURL(url_launcher);
246 }
247
248 }  // namespace
249
250 namespace turndown_prompt {
251
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);
257
258   const bool system_level = IsCurrentModuleSystemLevel();
259   bool multi_install = false;
260
261   installer::ProductState product_state;
262   if (product_state.Initialize(system_level, dist)) {
263     if (product_state.is_msi())
264       return true;
265     multi_install = product_state.is_multi_install();
266   }
267
268   if (multi_install) {
269     dist =
270         BrowserDistribution::GetSpecificDistribution(
271             BrowserDistribution::CHROME_BINARIES);
272   }
273   if (GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), NULL) ==
274       GoogleUpdateSettings::UPDATES_DISABLED) {
275     return true;
276   }
277
278   // See if the prompt is explicitly suppressed via GP.
279   return PolicySettings::GetInstance()->suppress_turndown_prompt();
280 }
281
282 void Configure(IWebBrowser2* web_browser) {
283   if (!IsPromptSuppressed())
284     InstallPrompts(web_browser);
285 }
286
287 }  // namespace turndown_prompt