| OLD | NEW |
| (Empty) |
| 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 base::string16& url); | |
| 47 virtual void OnRenderInChromeFrame(const base::string16& url); | |
| 48 virtual void OnRenderInHost(const base::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 base::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 base::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 base::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 base::string16& url) { | |
| 110 ShowPrompt(); | |
| 111 rendered_url_ = GURL(url); | |
| 112 } | |
| 113 | |
| 114 void BrowserObserver::OnRenderInHost(const base::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 | |
| OLD | NEW |