diff options
Diffstat (limited to 'chrome/browser/automation/automation_provider.cc')
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 4133 |
1 files changed, 4133 insertions, 0 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc new file mode 100644 index 0000000..6c66931 --- /dev/null +++ b/chrome/browser/automation/automation_provider.cc @@ -0,0 +1,4133 @@ +// 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/automation/automation_provider.h" + +#include <set> + +#include "app/l10n_util.h" +#include "app/message_box_flags.h" +#include "base/callback.h" +#include "base/file_path.h" +#include "base/file_version_info.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/json/string_escape.h" +#include "base/keyboard_codes.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/stl_util-inl.h" +#include "base/string_util.h" +#include "base/task.h" +#include "base/thread.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "base/waitable_event.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/app_modal_dialog.h" +#include "chrome/browser/app_modal_dialog_queue.h" +#include "chrome/browser/autofill/autofill_manager.h" +#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h" +#include "chrome/browser/automation/automation_browser_tracker.h" +#include "chrome/browser/automation/automation_extension_tracker.h" +#include "chrome/browser/automation/automation_provider_json.h" +#include "chrome/browser/automation/automation_provider_list.h" +#include "chrome/browser/automation/automation_provider_observers.h" +#include "chrome/browser/automation/automation_resource_message_filter.h" +#include "chrome/browser/automation/automation_tab_tracker.h" +#include "chrome/browser/automation/automation_window_tracker.h" +#include "chrome/browser/automation/extension_port_container.h" +#include "chrome/browser/autocomplete/autocomplete_edit.h" +#include "chrome/browser/blocked_popup_container.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_storage.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/browsing_data_remover.h" +#include "chrome/browser/character_encoding.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/dom_operation_notification_details.h" +#include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/download/download_item.h" +#include "chrome/browser/download/download_shelf.h" +#include "chrome/browser/download/save_package.h" +#include "chrome/browser/extensions/crx_installer.h" +#include "chrome/browser/extensions/extension_browser_event_router.h" +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/extensions/extension_install_ui.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "chrome/browser/extensions/extension_tabs_module.h" +#include "chrome/browser/extensions/extension_toolbar_model.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/user_script_master.h" +#include "chrome/browser/find_bar.h" +#include "chrome/browser/find_bar_controller.h" +#include "chrome/browser/find_notification_details.h" +#include "chrome/browser/host_content_settings_map.h" +#include "chrome/browser/importer/importer.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/io_thread.h" +#include "chrome/browser/location_bar.h" +#include "chrome/browser/login_prompt.h" +#include "chrome/browser/net/url_request_mock_util.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/pref_service.h" +#include "chrome/browser/printing/print_job.h" +#include "chrome/browser/profile_manager.h" +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/ssl/ssl_manager.h" +#include "chrome/browser/ssl/ssl_blocking_page.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/browser/translate/translate_infobar_delegate.h" +#include "chrome/common/automation_constants.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version_info.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/json_value_serializer.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/automation/automation_messages.h" +#include "chrome/test/automation/tab_proxy.h" +#include "net/proxy/proxy_service.h" +#include "net/proxy/proxy_config_service_fixed.h" +#include "net/url_request/url_request_context.h" +#include "chrome/browser/automation/ui_controls.h" +#include "views/event.h" +#include "webkit/glue/password_form.h" +#include "webkit/glue/plugins/plugin_list.h" + +#if defined(OS_WIN) +#include "chrome/browser/external_tab_container_win.h" +#endif // defined(OS_WIN) + +using base::Time; + +class AutomationInterstitialPage : public InterstitialPage { + public: + AutomationInterstitialPage(TabContents* tab, + const GURL& url, + const std::string& contents) + : InterstitialPage(tab, true, url), + contents_(contents) { + } + + virtual std::string GetHTMLContents() { return contents_; } + + private: + std::string contents_; + + DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage); +}; + +class ClickTask : public Task { + public: + explicit ClickTask(int flags) : flags_(flags) {} + virtual ~ClickTask() {} + + virtual void Run() { + ui_controls::MouseButton button = ui_controls::LEFT; + if ((flags_ & views::Event::EF_LEFT_BUTTON_DOWN) == + views::Event::EF_LEFT_BUTTON_DOWN) { + button = ui_controls::LEFT; + } else if ((flags_ & views::Event::EF_RIGHT_BUTTON_DOWN) == + views::Event::EF_RIGHT_BUTTON_DOWN) { + button = ui_controls::RIGHT; + } else if ((flags_ & views::Event::EF_MIDDLE_BUTTON_DOWN) == + views::Event::EF_MIDDLE_BUTTON_DOWN) { + button = ui_controls::MIDDLE; + } else { + NOTREACHED(); + } + + ui_controls::SendMouseClick(button); + } + + private: + int flags_; + + DISALLOW_COPY_AND_ASSIGN(ClickTask); +}; + +AutomationProvider::AutomationProvider(Profile* profile) + : redirect_query_(0), + profile_(profile), + reply_message_(NULL), + popup_menu_waiter_(NULL) { + browser_tracker_.reset(new AutomationBrowserTracker(this)); + extension_tracker_.reset(new AutomationExtensionTracker(this)); + tab_tracker_.reset(new AutomationTabTracker(this)); + window_tracker_.reset(new AutomationWindowTracker(this)); + autocomplete_edit_tracker_.reset( + new AutomationAutocompleteEditTracker(this)); + new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this)); + dom_operation_observer_.reset(new DomOperationNotificationObserver(this)); + metric_event_duration_observer_.reset(new MetricEventDurationObserver()); + extension_test_result_observer_.reset( + new ExtensionTestResultNotificationObserver(this)); + g_browser_process->AddRefModule(); +} + +AutomationProvider::~AutomationProvider() { + STLDeleteContainerPairSecondPointers(port_containers_.begin(), + port_containers_.end()); + port_containers_.clear(); + + // Make sure that any outstanding NotificationObservers also get destroyed. + ObserverList<NotificationObserver>::Iterator it(notification_observer_list_); + NotificationObserver* observer; + while ((observer = it.GetNext()) != NULL) + delete observer; + + if (channel_.get()) { + channel_->Close(); + } + g_browser_process->ReleaseModule(); +} + +void AutomationProvider::ConnectToChannel(const std::string& channel_id) { + automation_resource_message_filter_ = new AutomationResourceMessageFilter; + channel_.reset( + new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, + automation_resource_message_filter_, + g_browser_process->io_thread()->message_loop(), + true, g_browser_process->shutdown_event())); + scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo()); + std::string version_string; + if (version_info != NULL) { + version_string = WideToASCII(version_info->file_version()); + } + + // Send a hello message with our current automation protocol version. + channel_->Send(new AutomationMsg_Hello(0, version_string.c_str())); +} + +void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) { + if (expected_tabs == 0) { + Send(new AutomationMsg_InitialLoadsComplete(0)); + } else { + initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this)); + } +} + +NotificationObserver* AutomationProvider::AddNavigationStatusListener( + NavigationController* tab, IPC::Message* reply_message, + int number_of_navigations, bool include_current_navigation) { + NotificationObserver* observer = + new NavigationNotificationObserver(tab, this, reply_message, + number_of_navigations, + include_current_navigation); + + notification_observer_list_.AddObserver(observer); + return observer; +} + +void AutomationProvider::RemoveNavigationStatusListener( + NotificationObserver* obs) { + notification_observer_list_.RemoveObserver(obs); +} + +NotificationObserver* AutomationProvider::AddTabStripObserver( + Browser* parent, + IPC::Message* reply_message) { + NotificationObserver* observer = + new TabAppendedNotificationObserver(parent, this, reply_message); + notification_observer_list_.AddObserver(observer); + + return observer; +} + +void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) { + notification_observer_list_.RemoveObserver(obs); +} + +void AutomationProvider::AddLoginHandler(NavigationController* tab, + LoginHandler* handler) { + login_handler_map_[tab] = handler; +} + +void AutomationProvider::RemoveLoginHandler(NavigationController* tab) { + DCHECK(login_handler_map_[tab]); + login_handler_map_.erase(tab); +} + +void AutomationProvider::AddPortContainer(ExtensionPortContainer* port) { + int port_id = port->port_id(); + DCHECK_NE(-1, port_id); + DCHECK(port_containers_.find(port_id) == port_containers_.end()); + + port_containers_[port_id] = port; +} + +void AutomationProvider::RemovePortContainer(ExtensionPortContainer* port) { + int port_id = port->port_id(); + DCHECK_NE(-1, port_id); + + PortContainerMap::iterator it = port_containers_.find(port_id); + DCHECK(it != port_containers_.end()); + + if (it != port_containers_.end()) { + delete it->second; + port_containers_.erase(it); + } +} + +ExtensionPortContainer* AutomationProvider::GetPortContainer( + int port_id) const { + PortContainerMap::const_iterator it = port_containers_.find(port_id); + if (it == port_containers_.end()) + return NULL; + + return it->second; +} + +int AutomationProvider::GetIndexForNavigationController( + const NavigationController* controller, const Browser* parent) const { + DCHECK(parent); + return parent->GetIndexOfController(controller); +} + +int AutomationProvider::AddExtension(Extension* extension) { + DCHECK(extension); + return extension_tracker_->Add(extension); +} + +Extension* AutomationProvider::GetExtension(int extension_handle) { + return extension_tracker_->GetResource(extension_handle); +} + +Extension* AutomationProvider::GetEnabledExtension(int extension_handle) { + Extension* extension = extension_tracker_->GetResource(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service && + service->GetExtensionById(extension->id(), false)) + return extension; + return NULL; +} + +Extension* AutomationProvider::GetDisabledExtension(int extension_handle) { + Extension* extension = extension_tracker_->GetResource(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service && + service->GetExtensionById(extension->id(), true) && + !service->GetExtensionById(extension->id(), false)) + return extension; + return NULL; +} + +void AutomationProvider::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser) + IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync, + CloseBrowserAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab) + IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab) + IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies) + IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie) + IPC_MESSAGE_HANDLER(AutomationMsg_DeleteCookie, DeleteCookie) + IPC_MESSAGE_HANDLER(AutomationMsg_ShowCollectedCookiesDialog, + ShowCollectedCookiesDialog) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_NavigateToURL, NavigateToURL) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_NavigateToURLBlockUntilNavigationsComplete, + NavigateToURLBlockUntilNavigationsComplete) + IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncWithDisposition, + NavigationAsyncWithDisposition) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoBack, GoBack) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoForward, GoForward) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth) + IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom, + GetRedirectsFrom) + IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount) + IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount, + GetNormalBrowserWindowCount) + IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow) + IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale) + IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow, + GetLastActiveBrowserWindow) + IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow) + IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow, + FindNormalBrowserWindow) + IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive) + IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow) + IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowMaximized, IsWindowMaximized) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync, + ExecuteBrowserCommandAsync) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand, + ExecuteBrowserCommand) + IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds) + IPC_MESSAGE_HANDLER(AutomationMsg_GetWindowBounds, GetWindowBounds) + IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds) + IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisible, SetWindowVisible) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowClick, WindowSimulateClick) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowMouseMove, WindowSimulateMouseMove) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPress, WindowSimulateKeyPress) +#if !defined(OS_MACOSX) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag, + WindowSimulateDrag) +#endif // !defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount) + IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType) + IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND) +#endif // defined(OS_WIN) + IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID) + IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle) + IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex) + IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL) + IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility) + IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreen, IsFullscreen) + IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreenBubbleVisible, + GetFullscreenBubbleVisibility) + IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused) + IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAccelerator, ApplyAccelerator) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation, + ExecuteJavascript) + IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount, + GetConstrainedWindowCount) + IPC_MESSAGE_HANDLER(AutomationMsg_FindInPage, HandleFindInPageRequest) + IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewID, GetFocusedViewID) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement, + HandleInspectElementRequest) + IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory) + IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig); + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindow, + OpenNewBrowserWindow) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType, + OpenNewBrowserWindowOfType) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser) + IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowser, + GetAutocompleteEditForBrowser) + IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindow, GetBrowserForWindow) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ShowInterstitialPage, + ShowInterstitialPage) + IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPage, + HideInterstitialPage) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabToBeRestored, + WaitForTabToBeRestored) + IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState, GetSecurityState) + IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType, GetPageType) + IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration, + GetMetricEventDuration) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ActionOnSSLBlockingPage, + ActionOnSSLBlockingPage) + IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront) + IPC_MESSAGE_HANDLER(AutomationMsg_IsMenuCommandEnabled, + IsMenuCommandEnabled) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_PrintNow, PrintNow) + IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_SavePage, SavePage) + IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetText, + GetAutocompleteEditText) + IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetText, + SetAutocompleteEditText) + IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgress, + AutocompleteEditIsQueryInProgress) + IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatches, + AutocompleteEditGetMatches) + IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPage, + HandleOpenFindInPageRequest) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest) + IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility, + GetFindWindowVisibility) + IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocation, + HandleFindWindowLocationRequest) + IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibility, + GetBookmarkBarVisibility) + IPC_MESSAGE_HANDLER(AutomationMsg_GetBookmarksAsJSON, + GetBookmarksAsJSON) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad, + WaitForBookmarkModelToLoad) + IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkGroup, + AddBookmarkGroup) + IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkURL, + AddBookmarkURL) + IPC_MESSAGE_HANDLER(AutomationMsg_ReparentBookmark, + ReparentBookmark) + IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkTitle, + SetBookmarkTitle) + IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkURL, + SetBookmarkURL) + IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBookmark, + RemoveBookmark) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest, + SendJSONRequest) + IPC_MESSAGE_HANDLER(AutomationMsg_GetInfoBarCount, GetInfoBarCount) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ClickInfoBarAccept, + ClickInfoBarAccept) + IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTime, + GetLastNavigationTime) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForNavigation, + WaitForNavigation) + IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreference, SetIntPreference) + IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialog, + GetShowingAppModalDialog) + IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButton, + ClickAppModalDialogButton) + IPC_MESSAGE_HANDLER(AutomationMsg_SetStringPreference, SetStringPreference) + IPC_MESSAGE_HANDLER(AutomationMsg_GetBooleanPreference, + GetBooleanPreference) + IPC_MESSAGE_HANDLER(AutomationMsg_SetBooleanPreference, + SetBooleanPreference) + IPC_MESSAGE_HANDLER(AutomationMsg_GetPageCurrentEncoding, + GetPageCurrentEncoding) + IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding) + IPC_MESSAGE_HANDLER(AutomationMsg_SavePackageShouldPromptUser, + SavePackageShouldPromptUser) + IPC_MESSAGE_HANDLER(AutomationMsg_WindowTitle, GetWindowTitle) + IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility) + IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount) + IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll) + IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut) + IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy) + IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste) + IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_WaitForBrowserWindowCountToBecome, + WaitForBrowserWindowCountToBecome) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_WaitForAppModalDialogToBeShown, + WaitForAppModalDialogToBeShown) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_GoBackBlockUntilNavigationsComplete, + GoBackBlockUntilNavigationsComplete) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_GoForwardBlockUntilNavigationsComplete, + GoForwardBlockUntilNavigationsComplete) + IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension, + InstallExtension) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoadExpandedExtension, + LoadExpandedExtension) + IPC_MESSAGE_HANDLER(AutomationMsg_GetEnabledExtensions, + GetEnabledExtensions) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForExtensionTestResult, + WaitForExtensionTestResult) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_InstallExtensionAndGetHandle, + InstallExtensionAndGetHandle) + IPC_MESSAGE_HANDLER(AutomationMsg_UninstallExtension, + UninstallExtension) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EnableExtension, + EnableExtension) + IPC_MESSAGE_HANDLER(AutomationMsg_DisableExtension, + DisableExtension) + IPC_MESSAGE_HANDLER_DELAY_REPLY( + AutomationMsg_ExecuteExtensionActionInActiveTabAsync, + ExecuteExtensionActionInActiveTabAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_MoveExtensionBrowserAction, + MoveExtensionBrowserAction) + IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty, + GetExtensionProperty) + IPC_MESSAGE_HANDLER(AutomationMsg_ShutdownSessionService, + ShutdownSessionService) + IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync) + IPC_MESSAGE_HANDLER(AutomationMsg_SetContentSetting, SetContentSetting) + IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData) + IPC_MESSAGE_HANDLER(AutomationMsg_ResetToDefaultTheme, ResetToDefaultTheme) +#if defined(TOOLKIT_VIEWS) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForFocusedViewIDToChange, + WaitForFocusedViewIDToChange) + IPC_MESSAGE_HANDLER(AutomationMsg_StartTrackingPopupMenus, + StartTrackingPopupMenus) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForPopupMenuToOpen, + WaitForPopupMenuToOpen) +#endif // defined(TOOLKIT_VIEWS) +#if defined(OS_WIN) + // These are for use with external tabs. + IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab) + IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator, + ProcessUnhandledAccelerator) + IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus) + IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition) + IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome, + OnForwardContextMenuCommandToChrome) + IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab, + NavigateInExternalTab) + IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex, + NavigateExternalTabAtIndex) + IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab) + IPC_MESSAGE_HANDLER(AutomationMsg_SetEnableExtensionAutomation, + SetEnableExtensionAutomation) + IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost, + OnMessageFromExternalHost) + IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved) + IPC_MESSAGE_HANDLER(AutomationMsg_RunUnloadHandlers, OnRunUnloadHandlers) +#endif // defined(OS_WIN) +#if defined(OS_CHROMEOS) + IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoginWithUserAndPass, + LoginWithUserAndPass) +#endif // defined(OS_CHROMEOS) + IPC_END_MESSAGE_MAP() +} + +void AutomationProvider::ActivateTab(int handle, int at_index, int* status) { + *status = -1; + if (browser_tracker_->ContainsHandle(handle) && at_index > -1) { + Browser* browser = browser_tracker_->GetResource(handle); + if (at_index >= 0 && at_index < browser->tab_count()) { + browser->SelectTabContentsAt(at_index, true); + *status = 0; + } + } +} + +void AutomationProvider::AppendTab(int handle, const GURL& url, + IPC::Message* reply_message) { + int append_tab_response = -1; // -1 is the error code + NotificationObserver* observer = NULL; + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + observer = AddTabStripObserver(browser, reply_message); + TabContents* tab_contents = browser->AddTabWithURL( + url, GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED, + NULL, std::string()); + if (tab_contents) { + append_tab_response = + GetIndexForNavigationController(&tab_contents->controller(), browser); + } + } + + if (append_tab_response < 0) { + // The append tab failed. Remove the TabStripObserver + if (observer) { + RemoveTabStripObserver(observer); + delete observer; + } + + AutomationMsg_AppendTab::WriteReplyParams(reply_message, + append_tab_response); + Send(reply_message); + } +} + +void AutomationProvider::NavigateToURL(int handle, const GURL& url, + IPC::Message* reply_message) { + NavigateToURLBlockUntilNavigationsComplete(handle, url, 1, reply_message); +} + +void AutomationProvider::NavigateToURLBlockUntilNavigationsComplete( + int handle, const GURL& url, int number_of_navigations, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + + // Simulate what a user would do. Activate the tab and then navigate. + // We could allow navigating in a background tab in future. + Browser* browser = FindAndActivateTab(tab); + + if (browser) { + AddNavigationStatusListener(tab, reply_message, number_of_navigations, + false); + + // TODO(darin): avoid conversion to GURL + browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED); + return; + } + } + + AutomationMsg_NavigateToURL::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::NavigationAsync(int handle, + const GURL& url, + bool* status) { + NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status); +} + +void AutomationProvider::NavigationAsyncWithDisposition( + int handle, + const GURL& url, + WindowOpenDisposition disposition, + bool* status) { + *status = false; + + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + + // Simulate what a user would do. Activate the tab and then navigate. + // We could allow navigating in a background tab in future. + Browser* browser = FindAndActivateTab(tab); + + if (browser) { + // Don't add any listener unless a callback mechanism is desired. + // TODO(vibhor): Do this if such a requirement arises in future. + browser->OpenURL(url, GURL(), disposition, PageTransition::TYPED); + *status = true; + } + } +} + +void AutomationProvider::GoBack(int handle, IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = FindAndActivateTab(tab); + if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) { + AddNavigationStatusListener(tab, reply_message, 1, false); + browser->GoBack(CURRENT_TAB); + return; + } + } + + AutomationMsg_GoBack::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::GoForward(int handle, IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = FindAndActivateTab(tab); + if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) { + AddNavigationStatusListener(tab, reply_message, 1, false); + browser->GoForward(CURRENT_TAB); + return; + } + } + + AutomationMsg_GoForward::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::Reload(int handle, IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = FindAndActivateTab(tab); + if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) { + AddNavigationStatusListener(tab, reply_message, 1, false); + browser->Reload(CURRENT_TAB); + return; + } + } + + AutomationMsg_Reload::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::SetAuth(int tab_handle, + const std::wstring& username, + const std::wstring& password, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + LoginHandlerMap::iterator iter = login_handler_map_.find(tab); + + if (iter != login_handler_map_.end()) { + // If auth is needed again after this, assume login has failed. This is + // not strictly correct, because a navigation can require both proxy and + // server auth, but it should be OK for now. + LoginHandler* handler = iter->second; + AddNavigationStatusListener(tab, reply_message, 1, false); + handler->SetAuth(username, password); + return; + } + } + + AutomationMsg_SetAuth::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); + Send(reply_message); +} + +void AutomationProvider::CancelAuth(int tab_handle, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + LoginHandlerMap::iterator iter = login_handler_map_.find(tab); + + if (iter != login_handler_map_.end()) { + // If auth is needed again after this, something is screwy. + LoginHandler* handler = iter->second; + AddNavigationStatusListener(tab, reply_message, 1, false); + handler->CancelAuth(); + return; + } + } + + AutomationMsg_CancelAuth::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); + Send(reply_message); +} + +void AutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) { + *needs_auth = false; + + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + LoginHandlerMap::iterator iter = login_handler_map_.find(tab); + + if (iter != login_handler_map_.end()) { + // The LoginHandler will be in our map IFF the tab needs auth. + *needs_auth = true; + } + } +} + +void AutomationProvider::GetRedirectsFrom(int tab_handle, + const GURL& source_url, + IPC::Message* reply_message) { + DCHECK(!redirect_query_) << "Can only handle one redirect query at once."; + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + HistoryService* history_service = + tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS); + + DCHECK(history_service) << "Tab " << tab_handle << "'s profile " << + "has no history service"; + if (history_service) { + DCHECK(reply_message_ == NULL); + reply_message_ = reply_message; + // Schedule a history query for redirects. The response will be sent + // asynchronously from the callback the history system uses to notify us + // that it's done: OnRedirectQueryComplete. + redirect_query_ = history_service->QueryRedirectsFrom( + source_url, &consumer_, + NewCallback(this, &AutomationProvider::OnRedirectQueryComplete)); + return; // Response will be sent when query completes. + } + } + + // Send failure response. + std::vector<GURL> empty; + AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty); + Send(reply_message); +} + +void AutomationProvider::GetActiveTabIndex(int handle, int* active_tab_index) { + *active_tab_index = -1; // -1 is the error code + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + *active_tab_index = browser->selected_index(); + } +} + +void AutomationProvider::GetBrowserLocale(string16* locale) { + DCHECK(g_browser_process); + *locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale()); +} + +void AutomationProvider::GetBrowserWindowCount(int* window_count) { + *window_count = static_cast<int>(BrowserList::size()); +} + +void AutomationProvider::GetNormalBrowserWindowCount(int* window_count) { + *window_count = static_cast<int>( + BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL)); +} + +void AutomationProvider::GetShowingAppModalDialog(bool* showing_dialog, + int* dialog_button) { + AppModalDialog* dialog_delegate = + Singleton<AppModalDialogQueue>()->active_dialog(); + *showing_dialog = (dialog_delegate != NULL); + if (*showing_dialog) + *dialog_button = dialog_delegate->GetDialogButtons(); + else + *dialog_button = MessageBoxFlags::DIALOGBUTTON_NONE; +} + +void AutomationProvider::ClickAppModalDialogButton(int button, bool* success) { + *success = false; + + AppModalDialog* dialog_delegate = + Singleton<AppModalDialogQueue>()->active_dialog(); + if (dialog_delegate && + (dialog_delegate->GetDialogButtons() & button) == button) { + if ((button & MessageBoxFlags::DIALOGBUTTON_OK) == + MessageBoxFlags::DIALOGBUTTON_OK) { + dialog_delegate->AcceptWindow(); + *success = true; + } + if ((button & MessageBoxFlags::DIALOGBUTTON_CANCEL) == + MessageBoxFlags::DIALOGBUTTON_CANCEL) { + DCHECK(!*success) << "invalid param, OK and CANCEL specified"; + dialog_delegate->CancelWindow(); + *success = true; + } + } +} + +void AutomationProvider::ShutdownSessionService(int handle, bool* result) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->profile()->ShutdownSessionService(); + *result = true; + } else { + *result = false; + } +} + +void AutomationProvider::GetBrowserWindow(int index, int* handle) { + *handle = 0; + if (index >= 0) { + BrowserList::const_iterator iter = BrowserList::begin(); + for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index) {} + if (iter != BrowserList::end()) { + *handle = browser_tracker_->Add(*iter); + } + } +} + +void AutomationProvider::FindNormalBrowserWindow(int* handle) { + *handle = 0; + Browser* browser = BrowserList::FindBrowserWithType(profile_, + Browser::TYPE_NORMAL, + false); + if (browser) + *handle = browser_tracker_->Add(browser); +} + +void AutomationProvider::GetLastActiveBrowserWindow(int* handle) { + *handle = 0; + Browser* browser = BrowserList::GetLastActive(); + if (browser) + *handle = browser_tracker_->Add(browser); +} + +#if defined(OS_POSIX) +// TODO(estade): use this implementation for all platforms? +void AutomationProvider::GetActiveWindow(int* handle) { + gfx::NativeWindow window = + BrowserList::GetLastActive()->window()->GetNativeHandle(); + *handle = window_tracker_->Add(window); +} +#endif + +void AutomationProvider::ExecuteBrowserCommandAsync(int handle, int command, + bool* success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser->command_updater()->SupportsCommand(command) && + browser->command_updater()->IsCommandEnabled(command)) { + browser->ExecuteCommand(command); + *success = true; + } + } +} + +void AutomationProvider::ExecuteBrowserCommand( + int handle, int command, IPC::Message* reply_message) { + // List of commands which just finish synchronously and don't require + // setting up an observer. + static const int kSynchronousCommands[] = { + IDC_HOME, + IDC_SELECT_NEXT_TAB, + IDC_SELECT_PREVIOUS_TAB, + IDC_SHOW_BOOKMARK_MANAGER, + }; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser->command_updater()->SupportsCommand(command) && + browser->command_updater()->IsCommandEnabled(command)) { + // First check if we can handle the command without using an observer. + for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) { + if (command == kSynchronousCommands[i]) { + browser->ExecuteCommand(command); + AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, + true); + Send(reply_message); + return; + } + } + + // Use an observer if we have one, otherwise fail. + if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver( + this, browser, command, reply_message)) { + browser->ExecuteCommand(command); + return; + } + } + } + AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false); + Send(reply_message); +} + +// This task just adds another task to the event queue. This is useful if +// you want to ensure that any tasks added to the event queue after this one +// have already been processed by the time |task| is run. +class InvokeTaskLaterTask : public Task { + public: + explicit InvokeTaskLaterTask(Task* task) : task_(task) {} + virtual ~InvokeTaskLaterTask() {} + + virtual void Run() { + MessageLoop::current()->PostTask(FROM_HERE, task_); + } + + private: + Task* task_; + + DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask); +}; + +void AutomationProvider::WindowSimulateClick(const IPC::Message& message, + int handle, + const gfx::Point& click, + int flags) { + if (window_tracker_->ContainsHandle(handle)) { + ui_controls::SendMouseMoveNotifyWhenDone(click.x(), click.y(), + new ClickTask(flags)); + } +} + +void AutomationProvider::WindowSimulateMouseMove(const IPC::Message& message, + int handle, + const gfx::Point& location) { + if (window_tracker_->ContainsHandle(handle)) + ui_controls::SendMouseMove(location.x(), location.y()); +} + +void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message, + int handle, + int key, + int flags) { + if (!window_tracker_->ContainsHandle(handle)) + return; + + gfx::NativeWindow window = window_tracker_->GetResource(handle); + // The key event is sent to whatever window is active. + ui_controls::SendKeyPress(window, static_cast<base::KeyboardCode>(key), + ((flags & views::Event::EF_CONTROL_DOWN) == + views::Event::EF_CONTROL_DOWN), + ((flags & views::Event::EF_SHIFT_DOWN) == + views::Event::EF_SHIFT_DOWN), + ((flags & views::Event::EF_ALT_DOWN) == + views::Event::EF_ALT_DOWN), + ((flags & views::Event::EF_COMMAND_DOWN) == + views::Event::EF_COMMAND_DOWN)); +} + +void AutomationProvider::IsWindowActive(int handle, bool* success, + bool* is_active) { + if (window_tracker_->ContainsHandle(handle)) { + *is_active = + platform_util::IsWindowActive(window_tracker_->GetResource(handle)); + *success = true; + } else { + *success = false; + *is_active = false; + } +} + +void AutomationProvider::GetTabCount(int handle, int* tab_count) { + *tab_count = -1; // -1 is the error code + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + *tab_count = browser->tab_count(); + } +} + +void AutomationProvider::GetType(int handle, int* type_as_int) { + *type_as_int = -1; // -1 is the error code + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + *type_as_int = static_cast<int>(browser->type()); + } +} + +void AutomationProvider::GetTab(int win_handle, int tab_index, + int* tab_handle) { + *tab_handle = 0; + if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) { + Browser* browser = browser_tracker_->GetResource(win_handle); + if (tab_index < browser->tab_count()) { + TabContents* tab_contents = + browser->GetTabContentsAt(tab_index); + *tab_handle = tab_tracker_->Add(&tab_contents->controller()); + } + } +} + +void AutomationProvider::GetTabTitle(int handle, int* title_string_size, + std::wstring* title) { + *title_string_size = -1; // -1 is the error code + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + NavigationEntry* entry = tab->GetActiveEntry(); + if (entry != NULL) { + *title = UTF16ToWideHack(entry->title()); + } else { + *title = std::wstring(); + } + *title_string_size = static_cast<int>(title->size()); + } +} + +void AutomationProvider::GetTabIndex(int handle, int* tabstrip_index) { + *tabstrip_index = -1; // -1 is the error code + + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = Browser::GetBrowserForController(tab, NULL); + *tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab); + } +} + +void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) { + if (window_tracker_->ContainsHandle(handle)) { + window_tracker_->Remove(window_tracker_->GetResource(handle)); + } +} + +void AutomationProvider::OnChannelError() { + LOG(INFO) << "AutomationProxy went away, shutting down app."; + AutomationProviderList::GetInstance()->RemoveProvider(this); +} + +// TODO(brettw) change this to accept GURLs when history supports it +void AutomationProvider::OnRedirectQueryComplete( + HistoryService::Handle request_handle, + GURL from_url, + bool success, + history::RedirectList* redirects) { + DCHECK(request_handle == redirect_query_); + DCHECK(reply_message_ != NULL); + + std::vector<GURL> redirects_gurl; + reply_message_->WriteBool(success); + if (success) { + for (size_t i = 0; i < redirects->size(); i++) + redirects_gurl.push_back(redirects->at(i)); + } + + IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl); + + Send(reply_message_); + redirect_query_ = 0; + reply_message_ = NULL; +} + +bool AutomationProvider::Send(IPC::Message* msg) { + DCHECK(channel_.get()); + return channel_->Send(msg); +} + +Browser* AutomationProvider::FindAndActivateTab( + NavigationController* controller) { + int tab_index; + Browser* browser = Browser::GetBrowserForController(controller, &tab_index); + if (browser) + browser->SelectTabContentsAt(tab_index, true); + + return browser; +} + +namespace { + +class GetCookiesTask : public Task { + public: + GetCookiesTask(const GURL& url, + URLRequestContextGetter* context_getter, + base::WaitableEvent* event, + std::string* cookies) + : url_(url), + context_getter_(context_getter), + event_(event), + cookies_(cookies) {} + + virtual void Run() { + *cookies_ = context_getter_->GetCookieStore()->GetCookies(url_); + event_->Signal(); + } + + private: + const GURL& url_; + URLRequestContextGetter* const context_getter_; + base::WaitableEvent* const event_; + std::string* const cookies_; + + DISALLOW_COPY_AND_ASSIGN(GetCookiesTask); +}; + +std::string GetCookiesForURL( + const GURL& url, + URLRequestContextGetter* context_getter) { + std::string cookies; + base::WaitableEvent event(true /* manual reset */, + false /* not initially signaled */); + CHECK(ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + new GetCookiesTask(url, context_getter, &event, &cookies))); + event.Wait(); + return cookies; +} + +class SetCookieTask : public Task { + public: + SetCookieTask(const GURL& url, + const std::string& value, + URLRequestContextGetter* context_getter, + base::WaitableEvent* event, + bool* rv) + : url_(url), + value_(value), + context_getter_(context_getter), + event_(event), + rv_(rv) {} + + virtual void Run() { + *rv_ = context_getter_->GetCookieStore()->SetCookie(url_, value_); + event_->Signal(); + } + + private: + const GURL& url_; + const std::string& value_; + URLRequestContextGetter* const context_getter_; + base::WaitableEvent* const event_; + bool* const rv_; + + DISALLOW_COPY_AND_ASSIGN(SetCookieTask); +}; + +bool SetCookieForURL( + const GURL& url, + const std::string& value, + URLRequestContextGetter* context_getter) { + base::WaitableEvent event(true /* manual reset */, + false /* not initially signaled */); + bool rv = false; + CHECK(ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + new SetCookieTask(url, value, context_getter, &event, &rv))); + event.Wait(); + return rv; +} + +class DeleteCookieTask : public Task { + public: + DeleteCookieTask(const GURL& url, + const std::string& name, + const scoped_refptr<URLRequestContextGetter>& context_getter) + : url_(url), + name_(name), + context_getter_(context_getter) {} + + virtual void Run() { + net::CookieStore* cookie_store = context_getter_->GetCookieStore(); + cookie_store->DeleteCookie(url_, name_); + } + + private: + const GURL url_; + const std::string name_; + const scoped_refptr<URLRequestContextGetter> context_getter_; + + DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask); +}; + +} // namespace + +void AutomationProvider::GetCookies(const GURL& url, int handle, + int* value_size, + std::string* value) { + *value_size = -1; + if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + + // Since we are running on the UI thread don't call GetURLRequestContext(). + scoped_refptr<URLRequestContextGetter> request_context = + tab->tab_contents()->request_context(); + if (!request_context.get()) + request_context = tab->profile()->GetRequestContext(); + + *value = GetCookiesForURL(url, request_context.get()); + *value_size = static_cast<int>(value->size()); + } +} + +void AutomationProvider::SetCookie(const GURL& url, + const std::string value, + int handle, + int* response_value) { + *response_value = -1; + + if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + + scoped_refptr<URLRequestContextGetter> request_context = + tab->tab_contents()->request_context(); + if (!request_context.get()) + request_context = tab->profile()->GetRequestContext(); + + if (SetCookieForURL(url, value, request_context.get())) + *response_value = 1; + } +} + +void AutomationProvider::DeleteCookie(const GURL& url, + const std::string& cookie_name, + int handle, bool* success) { + *success = false; + if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + new DeleteCookieTask(url, cookie_name, + tab->profile()->GetRequestContext())); + *success = true; + } +} + +void AutomationProvider::ShowCollectedCookiesDialog( + int handle, bool* success) { + *success = false; + if (tab_tracker_->ContainsHandle(handle)) { + TabContents* tab_contents = + tab_tracker_->GetResource(handle)->tab_contents(); + tab_contents->delegate()->ShowCollectedCookiesDialog(tab_contents); + *success = true; + } +} + +void AutomationProvider::GetTabURL(int handle, bool* success, GURL* url) { + *success = false; + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + // Return what the user would see in the location bar. + *url = tab->GetActiveEntry()->virtual_url(); + *success = true; + } +} + +void AutomationProvider::GetTabProcessID(int handle, int* process_id) { + *process_id = -1; + + if (tab_tracker_->ContainsHandle(handle)) { + *process_id = 0; + TabContents* tab_contents = + tab_tracker_->GetResource(handle)->tab_contents(); + RenderProcessHost* rph = tab_contents->GetRenderProcessHost(); + if (rph) + *process_id = base::GetProcId(rph->GetHandle()); + } +} + +void AutomationProvider::ApplyAccelerator(int handle, int id) { + NOTREACHED() << "This function has been deprecated. " + << "Please use ExecuteBrowserCommandAsync instead."; +} + +void AutomationProvider::ExecuteJavascript(int handle, + const std::wstring& frame_xpath, + const std::wstring& script, + IPC::Message* reply_message) { + bool succeeded = false; + TabContents* tab_contents = GetTabContentsForHandle(handle, NULL); + if (tab_contents) { + // Set the routing id of this message with the controller. + // This routing id needs to be remembered for the reverse + // communication while sending back the response of + // this javascript execution. + std::wstring set_automation_id; + SStringPrintf(&set_automation_id, + L"window.domAutomationController.setAutomationId(%d);", + reply_message->routing_id()); + + DCHECK(reply_message_ == NULL); + reply_message_ = reply_message; + + tab_contents->render_view_host()->ExecuteJavascriptInWebFrame( + frame_xpath, set_automation_id); + tab_contents->render_view_host()->ExecuteJavascriptInWebFrame( + frame_xpath, script); + succeeded = true; + } + + if (!succeeded) { + AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string()); + Send(reply_message); + } +} + +void AutomationProvider::GetShelfVisibility(int handle, bool* visible) { + *visible = false; + + if (browser_tracker_->ContainsHandle(handle)) { +#if defined(OS_CHROMEOS) + // Chromium OS shows FileBrowse ui rather than download shelf. So we + // enumerate all browsers and look for a chrome://filebrowse... pop up. + for (BrowserList::const_iterator it = BrowserList::begin(); + it != BrowserList::end(); ++it) { + if ((*it)->type() == Browser::TYPE_POPUP) { + const GURL& url = + (*it)->GetTabContentsAt((*it)->selected_index())->GetURL(); + + if (url.SchemeIs(chrome::kChromeUIScheme) && + url.host() == chrome::kChromeUIFileBrowseHost) { + *visible = true; + break; + } + } + } +#else + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + *visible = browser->window()->IsDownloadShelfVisible(); + } +#endif + } +} + +void AutomationProvider::SetShelfVisibility(int handle, bool visible) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + if (visible) + browser->window()->GetDownloadShelf()->Show(); + else + browser->window()->GetDownloadShelf()->Close(); + } + } +} + +void AutomationProvider::IsFullscreen(int handle, bool* visible) { + *visible = false; + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) + *visible = browser->window()->IsFullscreen(); + } +} + +void AutomationProvider::GetFullscreenBubbleVisibility(int handle, + bool* visible) { + *visible = false; + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) + *visible = browser->window()->IsFullscreenBubbleVisible(); + } +} + +void AutomationProvider::GetConstrainedWindowCount(int handle, int* count) { + *count = -1; // -1 is the error code + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + TabContents* tab_contents = nav_controller->tab_contents(); + if (tab_contents) { + *count = static_cast<int>(tab_contents->child_windows_.size()); + } + } +} + +void AutomationProvider::HandleFindInPageRequest( + int handle, const std::wstring& find_request, + int forward, int match_case, int* active_ordinal, int* matches_found) { + NOTREACHED() << "This function has been deprecated." + << "Please use HandleFindRequest instead."; + *matches_found = -1; + return; +} + +void AutomationProvider::HandleFindRequest( + int handle, + const AutomationMsg_Find_Params& params, + IPC::Message* reply_message) { + if (!tab_tracker_->ContainsHandle(handle)) { + AutomationMsg_FindInPage::WriteReplyParams(reply_message, -1, -1); + Send(reply_message); + return; + } + + NavigationController* nav = tab_tracker_->GetResource(handle); + TabContents* tab_contents = nav->tab_contents(); + + find_in_page_observer_.reset(new + FindInPageNotificationObserver(this, tab_contents, reply_message)); + + tab_contents->set_current_find_request_id( + FindInPageNotificationObserver::kFindInPageRequestId); + tab_contents->render_view_host()->StartFinding( + FindInPageNotificationObserver::kFindInPageRequestId, + params.search_string, params.forward, params.match_case, + params.find_next); +} + +void AutomationProvider::HandleOpenFindInPageRequest( + const IPC::Message& message, int handle) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->FindInPage(false, false); + } +} + +void AutomationProvider::GetFindWindowVisibility(int handle, bool* visible) { + *visible = false; + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + FindBarTesting* find_bar = + browser->GetFindBarController()->find_bar()->GetFindBarTesting(); + find_bar->GetFindBarWindowInfo(NULL, visible); + } +} + +void AutomationProvider::HandleFindWindowLocationRequest(int handle, int* x, + int* y) { + gfx::Point position(0, 0); + bool visible = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + FindBarTesting* find_bar = + browser->GetFindBarController()->find_bar()->GetFindBarTesting(); + find_bar->GetFindBarWindowInfo(&position, &visible); + } + + *x = position.x(); + *y = position.y(); +} + +// Bookmark bar visibility is based on the pref (e.g. is it in the toolbar). +// Presence in the NTP is NOT considered visible by this call. +void AutomationProvider::GetBookmarkBarVisibility(int handle, + bool* visible, + bool* animating) { + *visible = false; + *animating = false; + + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { +#if 0 // defined(TOOLKIT_VIEWS) && defined(OS_LINUX) + // TODO(jrg): Was removed in rev43789 for perf. Need to investigate. + + // IsBookmarkBarVisible() line looks correct but is not + // consistent across platforms. Specifically, on Mac/Linux, it + // returns false if the bar is hidden in a pref (even if visible + // on the NTP). On ChromeOS, it returned true if on NTP + // independent of the pref. Making the code more consistent + // caused a perf bot regression on Windows (which shares views). + // See http://crbug.com/40225 + *visible = browser->profile()->GetPrefs()->GetBoolean( + prefs::kShowBookmarkBar); +#else + *visible = browser->window()->IsBookmarkBarVisible(); +#endif + *animating = browser->window()->IsBookmarkBarAnimating(); + } + } +} + +void AutomationProvider::GetBookmarksAsJSON(int handle, + std::string* bookmarks_as_json, + bool *success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + if (!browser->profile()->GetBookmarkModel()->IsLoaded()) { + return; + } + scoped_refptr<BookmarkStorage> storage = new BookmarkStorage( + browser->profile(), + browser->profile()->GetBookmarkModel()); + *success = storage->SerializeData(bookmarks_as_json); + } + } +} + +void AutomationProvider::WaitForBookmarkModelToLoad( + int handle, + IPC::Message* reply_message) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (model->IsLoaded()) { + AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams( + reply_message, true); + Send(reply_message); + } else { + // The observer will delete itself when done. + new AutomationProviderBookmarkModelObserver(this, reply_message, + model); + } + } +} + +void AutomationProvider::AddBookmarkGroup(int handle, + int64 parent_id, int index, + std::wstring title, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* parent = model->GetNodeByID(parent_id); + DCHECK(parent); + if (parent) { + const BookmarkNode* child = model->AddGroup(parent, index, + WideToUTF16(title)); + DCHECK(child); + if (child) + *success = true; + } + } + } + *success = false; +} + +void AutomationProvider::AddBookmarkURL(int handle, + int64 parent_id, int index, + std::wstring title, const GURL& url, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* parent = model->GetNodeByID(parent_id); + DCHECK(parent); + if (parent) { + const BookmarkNode* child = model->AddURL(parent, index, + WideToUTF16(title), url); + DCHECK(child); + if (child) + *success = true; + } + } + } + *success = false; +} + +void AutomationProvider::ReparentBookmark(int handle, + int64 id, int64 new_parent_id, + int index, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* node = model->GetNodeByID(id); + DCHECK(node); + const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id); + DCHECK(new_parent); + if (node && new_parent) { + model->Move(node, new_parent, index); + *success = true; + } + } + } + *success = false; +} + +void AutomationProvider::SetBookmarkTitle(int handle, + int64 id, std::wstring title, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* node = model->GetNodeByID(id); + DCHECK(node); + if (node) { + model->SetTitle(node, WideToUTF16(title)); + *success = true; + } + } + } + *success = false; +} + +void AutomationProvider::SetBookmarkURL(int handle, + int64 id, const GURL& url, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* node = model->GetNodeByID(id); + DCHECK(node); + if (node) { + model->SetURL(node, url); + *success = true; + } + } + } + *success = false; +} + +void AutomationProvider::RemoveBookmark(int handle, + int64 id, + bool* success) { + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + if (browser) { + BookmarkModel* model = browser->profile()->GetBookmarkModel(); + if (!model->IsLoaded()) { + *success = false; + return; + } + const BookmarkNode* node = model->GetNodeByID(id); + DCHECK(node); + if (node) { + const BookmarkNode* parent = node->GetParent(); + DCHECK(parent); + model->Remove(parent, parent->IndexOfChild(node)); + *success = true; + } + } + } + *success = false; +} + +// Sample json input: { "command": "SetWindowDimensions", +// "x": 20, # optional +// "y": 20, # optional +// "width": 800, # optional +// "height": 600 } # optional +void AutomationProvider::SetWindowDimensions(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + gfx::Rect rect = browser->window()->GetRestoredBounds(); + int x, y, width, height; + if (args->GetInteger(L"x", &x)) + rect.set_x(x); + if (args->GetInteger(L"y", &y)) + rect.set_y(y); + if (args->GetInteger(L"width", &width)) + rect.set_width(width); + if (args->GetInteger(L"height", &height)) + rect.set_height(height); + browser->window()->SetBounds(rect); + AutomationJSONReply(this, reply_message).SendSuccess(NULL); +} + +ListValue* AutomationProvider::GetInfobarsInfo(TabContents* tc) { + // Each infobar may have different properties depending on the type. + ListValue* infobars = new ListValue; + for (int infobar_index = 0; + infobar_index < tc->infobar_delegate_count(); + ++infobar_index) { + DictionaryValue* infobar_item = new DictionaryValue; + InfoBarDelegate* infobar = tc->GetInfoBarDelegateAt(infobar_index); + if (infobar->AsConfirmInfoBarDelegate()) { + // Also covers ThemeInstalledInfoBarDelegate and + // CrashedExtensionInfoBarDelegate. + infobar_item->SetString(L"type", "confirm_infobar"); + ConfirmInfoBarDelegate* confirm_infobar = + infobar->AsConfirmInfoBarDelegate(); + infobar_item->SetString(L"text", confirm_infobar->GetMessageText()); + infobar_item->SetString(L"link_text", confirm_infobar->GetLinkText()); + ListValue* buttons_list = new ListValue; + int buttons = confirm_infobar->GetButtons(); + if (ConfirmInfoBarDelegate::BUTTON_OK & buttons) { + StringValue* button_label = new StringValue( + confirm_infobar->GetButtonLabel( + ConfirmInfoBarDelegate::BUTTON_OK)); + buttons_list->Append(button_label); + } + if (ConfirmInfoBarDelegate::BUTTON_CANCEL & buttons) { + StringValue* button_label = new StringValue( + confirm_infobar->GetButtonLabel( + ConfirmInfoBarDelegate::BUTTON_CANCEL)); + buttons_list->Append(button_label); + } + infobar_item->Set(L"buttons", buttons_list); + } else if (infobar->AsAlertInfoBarDelegate()) { + infobar_item->SetString(L"type", "alert_infobar"); + AlertInfoBarDelegate* alert_infobar = + infobar->AsAlertInfoBarDelegate(); + infobar_item->SetString(L"text", alert_infobar->GetMessageText()); + } else if (infobar->AsLinkInfoBarDelegate()) { + infobar_item->SetString(L"type", "link_infobar"); + LinkInfoBarDelegate* link_infobar = infobar->AsLinkInfoBarDelegate(); + infobar_item->SetString(L"link_text", link_infobar->GetLinkText()); + } else if (infobar->AsTranslateInfoBarDelegate()) { + infobar_item->SetString(L"type", "translate_infobar"); + TranslateInfoBarDelegate* translate_infobar = + infobar->AsTranslateInfoBarDelegate(); + infobar_item->SetString(L"original_lang_code", + translate_infobar->GetOriginalLanguageCode()); + infobar_item->SetString(L"target_lang_code", + translate_infobar->GetTargetLanguageCode()); + } else if (infobar->AsExtensionInfoBarDelegate()) { + infobar_item->SetString(L"type", "extension_infobar"); + } else { + infobar_item->SetString(L"type", "unknown_infobar"); + } + infobars->Append(infobar_item); + } + return infobars; +} + +// Sample json input: { "command": "WaitForInfobarCount", +// "count": COUNT, +// "tab_index": INDEX } +// Sample output: {} +void AutomationProvider::WaitForInfobarCount(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + int tab_index; + int count; + if (!args->GetInteger(L"count", &count) || count < 0 || + !args->GetInteger(L"tab_index", &tab_index) || tab_index < 0) { + AutomationJSONReply(this, reply_message).SendError( + "Missing or invalid args: 'count', 'tab_index'."); + return; + } + + TabContents* tab_contents = browser->GetTabContentsAt(tab_index); + // Observer deletes itself. + new WaitForInfobarCountObserver(this, reply_message, tab_contents, count); +} + +namespace { + +// Task to get info about BrowserChildProcessHost. Must run on IO thread to +// honor the semantics of BrowserChildProcessHost. +// Used by AutomationProvider::GetBrowserInfo(). +class GetChildProcessHostInfoTask : public Task { + public: + GetChildProcessHostInfoTask(base::WaitableEvent* event, + ListValue* child_processes) + : event_(event), + child_processes_(child_processes) {} + + virtual void Run() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) { + // Only add processes which are already started, + // since we need their handle. + if ((*iter)->handle() == base::kNullProcessHandle) { + continue; + } + ChildProcessInfo* info = *iter; + DictionaryValue* item = new DictionaryValue; + item->SetString(L"name", info->name()); + item->SetString(L"type", + ChildProcessInfo::GetTypeNameInEnglish(info->type())); + item->SetInteger(L"pid", base::GetProcId(info->handle())); + child_processes_->Append(item); + } + event_->Signal(); + } + + private: + base::WaitableEvent* const event_; // weak + ListValue* child_processes_; + + DISALLOW_COPY_AND_ASSIGN(GetChildProcessHostInfoTask); +}; + +} // namespace + +// Sample json input: { "command": "GetBrowserInfo" } +// Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for +// sample json output. +void AutomationProvider::GetBrowserInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + DictionaryValue* properties = new DictionaryValue; + properties->SetString(L"ChromeVersion", chrome::kChromeVersion); + properties->SetString(L"BrowserProcessExecutableName", + chrome::kBrowserProcessExecutableName); + properties->SetString(L"HelperProcessExecutableName", + chrome::kHelperProcessExecutableName); + properties->SetString(L"BrowserProcessExecutablePath", + chrome::kBrowserProcessExecutablePath); + properties->SetString(L"HelperProcessExecutablePath", + chrome::kHelperProcessExecutablePath); + properties->SetString(L"command_line_string", + CommandLine::ForCurrentProcess()->command_line_string()); + + std::string branding; +#if defined(GOOGLE_CHROME_BUILD) + branding = "Google Chrome"; +#elif defined(CHROMIUM_BUILD) + branding = "Chromium"; +#else + branding = "Unknown Branding"; +#endif + properties->SetString(L"branding", branding); + + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->Set(L"properties", properties); + + return_value->SetInteger(L"browser_pid", base::GetCurrentProcId()); + // Add info about all windows in a list of dictionaries, one dictionary + // item per window. + ListValue* windows = new ListValue; + int windex = 0; + for (BrowserList::const_iterator it = BrowserList::begin(); + it != BrowserList::end(); + ++it, ++windex) { + DictionaryValue* browser_item = new DictionaryValue; + browser = *it; + browser_item->SetInteger(L"index", windex); + // Window properties + gfx::Rect rect = browser->window()->GetRestoredBounds(); + browser_item->SetInteger(L"x", rect.x()); + browser_item->SetInteger(L"y", rect.y()); + browser_item->SetInteger(L"width", rect.width()); + browser_item->SetInteger(L"height", rect.height()); + browser_item->SetBoolean(L"fullscreen", + browser->window()->IsFullscreen()); + browser_item->SetInteger(L"selected_tab", browser->selected_index()); + browser_item->SetBoolean(L"incognito", + browser->profile()->IsOffTheRecord()); + // For each window, add info about all tabs in a list of dictionaries, + // one dictionary item per tab. + ListValue* tabs = new ListValue; + for (int i = 0; i < browser->tab_count(); ++i) { + TabContents* tc = browser->GetTabContentsAt(i); + DictionaryValue* tab = new DictionaryValue; + tab->SetInteger(L"index", i); + tab->SetString(L"url", tc->GetURL().spec()); + tab->SetInteger(L"renderer_pid", + base::GetProcId(tc->GetRenderProcessHost()->GetHandle())); + tab->Set(L"infobars", GetInfobarsInfo(tc)); + tabs->Append(tab); + } + browser_item->Set(L"tabs", tabs); + + windows->Append(browser_item); + } + return_value->Set(L"windows", windows); + + return_value->SetString(L"child_process_path", + ChildProcessHost::GetChildPath(true).value()); + // Child processes are the processes for plugins and other workers. + // Add all child processes in a list of dictionaries, one dictionary item + // per child process. + ListValue* child_processes = new ListValue; + base::WaitableEvent event(true /* manual reset */, + false /* not initially signaled */); + CHECK(ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + new GetChildProcessHostInfoTask(&event, child_processes))); + event.Wait(); + return_value->Set(L"child_processes", child_processes); + + // Add all extension processes in a list of dictionaries, one dictionary + // item per extension process. + ListValue* extension_processes = new ListValue; + ProfileManager* profile_manager = g_browser_process->profile_manager(); + for (ProfileManager::const_iterator it = profile_manager->begin(); + it != profile_manager->end(); ++it) { + ExtensionProcessManager* process_manager = + (*it)->GetExtensionProcessManager(); + ExtensionProcessManager::const_iterator jt; + for (jt = process_manager->begin(); jt != process_manager->end(); ++jt) { + ExtensionHost* ex_host = *jt; + // Don't add dead extension processes. + if (!ex_host->IsRenderViewLive()) + continue; + DictionaryValue* item = new DictionaryValue; + item->SetString(L"name", ex_host->extension()->name()); + item->SetInteger( + L"pid", + base::GetProcId(ex_host->render_process_host()->GetHandle())); + extension_processes->Append(item); + } + } + return_value->Set(L"extension_processes", extension_processes); + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +// Sample json input: { "command": "GetHistoryInfo", +// "search_text": "some text" } +// Refer chrome/test/pyautolib/history_info.py for sample json output. +void AutomationProvider::GetHistoryInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + consumer_.CancelAllRequests(); + + string16 search_text; + args->GetString("search_text", &search_text); + + // Fetch history. + HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + history::QueryOptions options; + // The observer owns itself. It deletes itself after it fetches history. + AutomationProviderHistoryObserver* history_observer = + new AutomationProviderHistoryObserver(this, reply_message); + hs->QueryHistory( + search_text, + options, + &consumer_, + NewCallback(history_observer, + &AutomationProviderHistoryObserver::HistoryQueryComplete)); +} + +// Sample json input: { "command": "AddHistoryItem", +// "item": { "URL": "http://www.google.com", +// "title": "Google", # optional +// "time": 12345 # optional (time_t) +// } } +// Refer chrome/test/pyautolib/pyauto.py for details on input. +void AutomationProvider::AddHistoryItem(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + DictionaryValue* item = NULL; + args->GetDictionary(L"item", &item); + string16 url_text; + string16 title; + base::Time time = base::Time::Now(); + AutomationJSONReply reply(this, reply_message); + + if (!item->GetString("url", &url_text)) { + reply.SendError("bad args (no URL in dict?)"); + return; + } + GURL gurl(url_text); + item->GetString("title", &title); // Don't care if it fails. + int it; + double dt; + if (item->GetInteger(L"time", &it)) + time = base::Time::FromTimeT(it); + else if (item->GetReal(L"time", &dt)) + time = base::Time::FromDoubleT(dt); + + // Ideas for "dummy" values (e.g. id_scope) came from + // chrome/browser/autocomplete/history_contents_provider_unittest.cc + HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + const void* id_scope = reinterpret_cast<void*>(1); + hs->AddPage(gurl, time, + id_scope, + 0, + GURL(), + PageTransition::LINK, + history::RedirectList(), + false); + if (title.length()) + hs->SetPageTitle(gurl, title); + reply.SendSuccess(NULL); +} + +// Sample json input: { "command": "GetDownloadsInfo" } +// Refer chrome/test/pyautolib/download_info.py for sample json output. +void AutomationProvider::GetDownloadsInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + AutomationProviderDownloadManagerObserver observer; + std::vector<DownloadItem*> downloads; + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + AutomationJSONReply reply(this, reply_message); + + if (!profile_->HasCreatedDownloadManager()) { + reply.SendError("no download manager"); + return; + } + // Use DownloadManager's GetDownloads() method and not GetCurrentDownloads() + // since that would be transient; a download might enter and empty out + // the current download queue too soon to be noticed. + profile_->GetDownloadManager()->GetDownloads(&observer, L""); + downloads = observer.Downloads(); + + std::map<DownloadItem::DownloadState, std::string> state_to_string; + state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS"); + state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED"); + state_to_string[DownloadItem::REMOVING] = std::string("REMOVING"); + state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE"); + + std::map<DownloadItem::SafetyState, std::string> safety_state_to_string; + safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE"); + safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS"); + safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] = + std::string("DANGEROUS_BUT_VALIDATED"); + + ListValue* list_of_downloads = new ListValue; + for (std::vector<DownloadItem*>::iterator it = downloads.begin(); + it != downloads.end(); + it++) { // Fill info about each download item. + DictionaryValue* dl_item_value = new DictionaryValue; + dl_item_value->SetInteger(L"id", static_cast<int>((*it)->id())); + dl_item_value->SetString(L"url", (*it)->url().spec()); + dl_item_value->SetString(L"referrer_url", (*it)->referrer_url().spec()); + dl_item_value->SetString(L"file_name", (*it)->file_name().value()); + dl_item_value->SetString(L"full_path", (*it)->full_path().value()); + dl_item_value->SetBoolean(L"is_paused", (*it)->is_paused()); + dl_item_value->SetBoolean(L"open_when_complete", + (*it)->open_when_complete()); + dl_item_value->SetBoolean(L"is_extension_install", + (*it)->is_extension_install()); + dl_item_value->SetBoolean(L"is_temporary", (*it)->is_temporary()); + dl_item_value->SetBoolean(L"is_otr", (*it)->is_otr()); // off-the-record + dl_item_value->SetString(L"state", state_to_string[(*it)->state()]); + dl_item_value->SetString(L"safety_state", + safety_state_to_string[(*it)->safety_state()]); + dl_item_value->SetInteger(L"PercentComplete", (*it)->PercentComplete()); + list_of_downloads->Append(dl_item_value); + } + return_value->Set(L"downloads", list_of_downloads); + + reply.SendSuccess(return_value.get()); + // All value objects allocated above are owned by |return_value| + // and get freed by it. +} + +void AutomationProvider::WaitForDownloadsToComplete( + Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + AutomationProviderDownloadManagerObserver observer; + std::vector<DownloadItem*> downloads; + AutomationJSONReply reply(this, reply_message); + + // Look for a quick return. + if (!profile_->HasCreatedDownloadManager()) { + reply.SendSuccess(NULL); // No download manager. + return; + } + profile_->GetDownloadManager()->GetCurrentDownloads(&observer, FilePath()); + downloads = observer.Downloads(); + if (downloads.size() == 0) { + reply.SendSuccess(NULL); + return; + } + + // The observer owns itself. When the last observed item pings, it + // deletes itself. + AutomationProviderDownloadItemObserver* item_observer = + new AutomationProviderDownloadItemObserver( + this, reply_message, downloads.size()); + for (std::vector<DownloadItem*>::iterator i = downloads.begin(); + i != downloads.end(); + i++) { + (*i)->AddObserver(item_observer); + } +} + +// Sample json input: { "command": "GetPrefsInfo" } +// Refer chrome/test/pyautolib/prefs_info.py for sample json output. +void AutomationProvider::GetPrefsInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + const PrefService::PreferenceSet& prefs = + profile_->GetPrefs()->preference_set(); + DictionaryValue* items = new DictionaryValue; + for (PrefService::PreferenceSet::const_iterator it = prefs.begin(); + it != prefs.end(); ++it) { + items->Set((*it)->name(), (*it)->GetValue()->DeepCopy()); + } + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->Set(L"prefs", items); // return_value owns items. + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +// Sample json input: { "command": "SetPrefs", "path": path, "value": value } +void AutomationProvider::SetPrefs(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::wstring path; + Value* val; + AutomationJSONReply reply(this, reply_message); + if (args->GetString(L"path", &path) && args->Get(L"value", &val)) { + PrefService* pref_service = profile_->GetPrefs(); + const PrefService::Preference* pref = + pref_service->FindPreference(path.c_str()); + if (!pref) { // Not a registered pref. + reply.SendError("pref not registered."); + return; + } else if (pref->IsManaged()) { // Do not attempt to change a managed pref. + reply.SendError("pref is managed. cannot be changed."); + return; + } else { // Set the pref. + pref_service->Set(path.c_str(), *val); + } + } else { + reply.SendError("no pref path or value given."); + return; + } + + reply.SendSuccess(NULL); +} + +// Sample json input: { "command": "GetOmniboxInfo" } +// Refer chrome/test/pyautolib/omnibox_info.py for sample json output. +void AutomationProvider::GetOmniboxInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + + LocationBar* loc_bar = browser->window()->GetLocationBar(); + AutocompleteEditView* edit_view = loc_bar->location_entry(); + AutocompleteEditModel* model = edit_view->model(); + + // Fill up matches. + ListValue* matches = new ListValue; + const AutocompleteResult& result = model->result(); + for (AutocompleteResult::const_iterator i = result.begin(); + i != result.end(); ++i) { + const AutocompleteMatch& match = *i; + DictionaryValue* item = new DictionaryValue; // owned by return_value + item->SetString(L"type", AutocompleteMatch::TypeToString(match.type)); + item->SetBoolean(L"starred", match.starred); + item->SetString(L"destination_url", match.destination_url.spec()); + item->SetString(L"contents", match.contents); + item->SetString(L"description", match.description); + matches->Append(item); + } + return_value->Set(L"matches", matches); + + // Fill up other properties. + DictionaryValue* properties = new DictionaryValue; // owned by return_value + properties->SetBoolean(L"has_focus", model->has_focus()); + properties->SetBoolean(L"query_in_progress", model->query_in_progress()); + properties->SetString(L"keyword", model->keyword()); + properties->SetString(L"text", edit_view->GetText()); + return_value->Set(L"properties", properties); + + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +// Sample json input: { "command": "SetOmniboxText", +// "text": "goog" } +void AutomationProvider::SetOmniboxText(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::wstring text; + AutomationJSONReply reply(this, reply_message); + if (!args->GetString(L"text", &text)) { + reply.SendError("text missing"); + return; + } + browser->FocusLocationBar(); + LocationBar* loc_bar = browser->window()->GetLocationBar(); + AutocompleteEditView* edit_view = loc_bar->location_entry(); + edit_view->model()->OnSetFocus(false); + edit_view->SetUserText(text); + reply.SendSuccess(NULL); +} + +// Sample json input: { "command": "OmniboxMovePopupSelection", +// "count": 1 } +// Negative count implies up, positive implies down. Count values will be +// capped by the size of the popup list. +void AutomationProvider::OmniboxMovePopupSelection( + Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + int count; + AutomationJSONReply reply(this, reply_message); + if (!args->GetInteger(L"count", &count)) { + reply.SendError("count missing"); + return; + } + LocationBar* loc_bar = browser->window()->GetLocationBar(); + AutocompleteEditModel* model = loc_bar->location_entry()->model(); + model->OnUpOrDownKeyPressed(count); + reply.SendSuccess(NULL); +} + +// Sample json input: { "command": "OmniboxAcceptInput" } +void AutomationProvider::OmniboxAcceptInput(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + NavigationController& controller = + browser->GetSelectedTabContents()->controller(); + // Setup observer to wait until the selected item loads. + NotificationObserver* observer = + new OmniboxAcceptNotificationObserver(&controller, this, reply_message); + notification_observer_list_.AddObserver(observer); + + browser->window()->GetLocationBar()->AcceptInput(); +} + +// Sample json input: { "command": "GetInitialLoadTimes" } +// Refer to InitialLoadObserver::GetTimingInformation() for sample output. +void AutomationProvider::GetInitialLoadTimes( + Browser*, + DictionaryValue*, + IPC::Message* reply_message) { + scoped_ptr<DictionaryValue> return_value( + initial_load_observer_->GetTimingInformation()); + + std::string json_return; + base::JSONWriter::Write(return_value.get(), false, &json_return); + AutomationMsg_SendJSONRequest::WriteReplyParams( + reply_message, json_return, true); + Send(reply_message); +} + +// Sample json input: { "command": "GetPluginsInfo" } +// Refer chrome/test/pyautolib/plugins_info.py for sample json output. +void AutomationProvider::GetPluginsInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::vector<WebPluginInfo> plugins; + NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins); + ListValue* items = new ListValue; + for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin(); + it != plugins.end(); + ++it) { + DictionaryValue* item = new DictionaryValue; + item->SetStringFromUTF16(L"name", it->name); + item->SetString(L"path", it->path.value()); + item->SetStringFromUTF16(L"version", it->version); + item->SetStringFromUTF16(L"desc", it->desc); + item->SetBoolean(L"enabled", it->enabled); + // Add info about mime types. + ListValue* mime_types = new ListValue(); + for (std::vector<WebPluginMimeType>::const_iterator type_it = + it->mime_types.begin(); + type_it != it->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); + } + item->Set(L"mimeTypes", mime_types); + items->Append(item); + } + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->Set(L"plugins", items); // return_value owns items. + + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +// Sample json input: +// { "command": "EnablePlugin", +// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" } +void AutomationProvider::EnablePlugin(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + FilePath::StringType path; + AutomationJSONReply reply(this, reply_message); + if (!args->GetString(L"path", &path)) { + reply.SendError("path not specified."); + return; + } else if (!NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(path))) { + reply.SendError(StringPrintf("Could not enable plugin for path %s.", + path.c_str())); + return; + } + reply.SendSuccess(NULL); +} + +// Sample json input: +// { "command": "DisablePlugin", +// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" } +void AutomationProvider::DisablePlugin(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + FilePath::StringType path; + AutomationJSONReply reply(this, reply_message); + if (!args->GetString(L"path", &path)) { + reply.SendError("path not specified."); + return; + } else if (!NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(path))) { + reply.SendError(StringPrintf("Could not disable plugin for path %s.", + path.c_str())); + return; + } + reply.SendSuccess(NULL); +} + +// Sample json input: +// { "command": "SaveTabContents", +// "tab_index": 0, +// "filename": <a full pathname> } +// Sample json output: +// {} +void AutomationProvider::SaveTabContents(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + int tab_index = 0; + FilePath::StringType filename; + FilePath::StringType parent_directory; + TabContents* tab_contents = NULL; + + if (!args->GetInteger(L"tab_index", &tab_index) || + !args->GetString(L"filename", &filename)) { + AutomationJSONReply(this, reply_message).SendError( + "tab_index or filename param missing"); + return; + } else { + tab_contents = browser->GetTabContentsAt(tab_index); + if (!tab_contents) { + AutomationJSONReply(this, reply_message).SendError( + "no tab at tab_index"); + return; + } + } + // We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't + // used. Nevertheless, SavePackage requires it be valid. Sigh. + parent_directory = FilePath(filename).DirName().value(); + if (!tab_contents->SavePage(FilePath(filename), FilePath(parent_directory), + SavePackage::SAVE_AS_ONLY_HTML)) { + AutomationJSONReply(this, reply_message).SendError( + "Could not initiate SavePage"); + return; + } + // The observer will delete itself when done. + new SavePackageNotificationObserver(tab_contents->save_package(), + this, reply_message); +} + +// Refer to ImportSettings() in chrome/test/pyautolib/pyauto.py for sample +// json input. +// Sample json output: "{}" +void AutomationProvider::ImportSettings(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + // Map from the json string passed over to the import item masks. + std::map<std::string, ImportItem> string_to_import_item; + string_to_import_item["HISTORY"] = importer::HISTORY; + string_to_import_item["FAVORITES"] = importer::FAVORITES; + string_to_import_item["COOKIES"] = importer::COOKIES; + string_to_import_item["PASSWORDS"] = importer::PASSWORDS; + string_to_import_item["SEARCH_ENGINES"] = importer::SEARCH_ENGINES; + string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE; + string_to_import_item["ALL"] = importer::ALL; + + std::wstring browser_name; + int import_items = 0; + ListValue* import_items_list = NULL; + bool first_run; + + if (!args->GetString(L"import_from", &browser_name) || + !args->GetBoolean(L"first_run", &first_run) || + !args->GetList(L"import_items", &import_items_list)) { + AutomationJSONReply(this, reply_message).SendError( + "Incorrect type for one or more of the arguments."); + return; + } + + int num_items = import_items_list->GetSize(); + for (int i = 0; i < num_items; i++) { + std::string item; + import_items_list->GetString(i, &item); + // If the provided string is not part of the map, error out. + if (!ContainsKey(string_to_import_item, item)) { + AutomationJSONReply(this, reply_message).SendError( + "Invalid item string found in import_items."); + return; + } + import_items |= string_to_import_item[item]; + } + + ImporterHost* importer_host = new ImporterHost(); + // Get the correct ProfileInfo based on the browser they user provided. + importer::ProfileInfo profile_info; + int num_browsers = importer_host->GetAvailableProfileCount(); + int i = 0; + for ( ; i < num_browsers; i++) { + std::wstring name = importer_host->GetSourceProfileNameAt(i); + if (name == browser_name) { + profile_info = importer_host->GetSourceProfileInfoAt(i); + break; + } + } + // If we made it to the end of the loop, then the input was bad. + if (i == num_browsers) { + AutomationJSONReply(this, reply_message).SendError( + "Invalid browser name string found."); + return; + } + + Profile* profile = browser->profile(); + + importer_host->SetObserver( + new AutomationProviderImportSettingsObserver(this, reply_message)); + importer_host->StartImportSettings(profile_info, profile, import_items, + new ProfileWriter(profile), first_run); +} + +// See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json +// input. +// Sample json output: { "password_added": true } +void AutomationProvider::AddSavedPassword(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + string16 username; + string16 password; + base::Time time = base::Time::Now(); + AutomationJSONReply reply(this, reply_message); + + if (!args->GetStringAsUTF16(L"password", &password) || + !args->GetStringAsUTF16(L"username", &username)) { + reply.SendError("Username and password must be strings."); + return; + } + + // If the time is specified, change time to the specified time. + int it; + double dt; + if (args->GetInteger(L"time", &it)) + time = base::Time::FromTimeT(it); + else if (args->GetReal(L"time", &dt)) + time = base::Time::FromDoubleT(dt); + + webkit_glue::PasswordForm new_password; + new_password.username_value = username; + new_password.password_value = password; + new_password.date_created = time; + + Profile* profile = browser->profile(); + // Use IMPLICIT_ACCESS since new passwords aren't added off the record. + PasswordStore* password_store = + profile->GetPasswordStore(Profile::IMPLICIT_ACCESS); + + // Set the return based on whether setting the password succeeded. + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + + // It will be null if it's accessed in an incognito window. + if (password_store != NULL) { + password_store->AddLogin(new_password); + return_value->SetBoolean(L"password_added", true); + } else { + return_value->SetBoolean(L"password_added", false); + } + + reply.SendSuccess(return_value.get()); +} + +// Sample json input: { "command": "GetSavedPasswords" } +// Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample +// json output. +void AutomationProvider::GetSavedPasswords(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + Profile* profile = browser->profile(); + // Use EXPLICIT_ACCESS since saved passwords can be retreived off the record. + PasswordStore* password_store = + profile->GetPasswordStore(Profile::EXPLICIT_ACCESS); + password_store->GetAutofillableLogins( + new AutomationProviderGetPasswordsObserver(this, reply_message)); + // Observer deletes itself after returning. +} + +// Refer to ClearBrowsingData() in chrome/test/pyautolib/pyauto.py for sample +// json input. +// Sample json output: {} +void AutomationProvider::ClearBrowsingData(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::map<std::string, BrowsingDataRemover::TimePeriod> string_to_time_period; + string_to_time_period["LAST_HOUR"] = BrowsingDataRemover::LAST_HOUR; + string_to_time_period["LAST_DAY"] = BrowsingDataRemover::LAST_DAY; + string_to_time_period["LAST_WEEK"] = BrowsingDataRemover::LAST_WEEK; + string_to_time_period["FOUR_WEEKS"] = BrowsingDataRemover::FOUR_WEEKS; + string_to_time_period["EVERYTHING"] = BrowsingDataRemover::EVERYTHING; + + std::map<std::string, int> string_to_mask_value; + string_to_mask_value["HISTORY"] = BrowsingDataRemover::REMOVE_HISTORY; + string_to_mask_value["DOWNLOADS"] = BrowsingDataRemover::REMOVE_DOWNLOADS; + string_to_mask_value["COOKIES"] = BrowsingDataRemover::REMOVE_COOKIES; + string_to_mask_value["PASSWORDS"] = BrowsingDataRemover::REMOVE_PASSWORDS; + string_to_mask_value["FORM_DATA"] = BrowsingDataRemover::REMOVE_FORM_DATA; + string_to_mask_value["CACHE"] = BrowsingDataRemover::REMOVE_CACHE; + + std::string time_period; + ListValue* to_remove; + if (!args->GetString(L"time_period", &time_period) || + !args->GetList(L"to_remove", &to_remove)) { + AutomationJSONReply(this, reply_message).SendError( + "time_period must be a string and to_remove a list."); + return; + } + + int remove_mask = 0; + int num_removals = to_remove->GetSize(); + for (int i = 0; i < num_removals; i++) { + std::string removal; + to_remove->GetString(i, &removal); + // If the provided string is not part of the map, then error out. + if (!ContainsKey(string_to_mask_value, removal)) { + AutomationJSONReply(this, reply_message).SendError( + "Invalid browsing data string found in to_remove."); + return; + } + remove_mask |= string_to_mask_value[removal]; + } + + if (!ContainsKey(string_to_time_period, time_period)) { + AutomationJSONReply(this, reply_message).SendError( + "Invalid string for time_period."); + return; + } + + BrowsingDataRemover* remover = new BrowsingDataRemover( + profile(), string_to_time_period[time_period], base::Time()); + + remover->AddObserver( + new AutomationProviderBrowsingDataObserver(this, reply_message)); + remover->Remove(remove_mask); + // BrowsingDataRemover deletes itself using DeleteTask. + // The observer also deletes itself after sending the reply. +} + +// Sample json input: { "command": "GetThemeInfo" } +// Refer GetThemeInfo() in chrome/test/pyautolib/pyauto.py for sample output. +void AutomationProvider::GetThemeInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + Extension* theme = browser->profile()->GetTheme(); + if (theme) { + return_value->SetString(L"name", theme->name()); + return_value->Set(L"images", theme->GetThemeImages()->DeepCopy()); + return_value->Set(L"colors", theme->GetThemeColors()->DeepCopy()); + return_value->Set(L"tints", theme->GetThemeTints()->DeepCopy()); + } + AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); +} + +// Sample json input: +// { "command": "GetAutoFillProfile" } +// Refer to GetAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample +// json output. +void AutomationProvider::GetAutoFillProfile(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + // Get the AutoFillProfiles currently in the database. + int tab_index = 0; + args->GetInteger(L"tab_index", &tab_index); + TabContents* tab_contents = browser->GetTabContentsAt(tab_index); + AutomationJSONReply reply(this, reply_message); + + if (tab_contents) { + PersonalDataManager* pdm = tab_contents->profile()->GetOriginalProfile() + ->GetPersonalDataManager(); + if (pdm) { + std::vector<AutoFillProfile*> autofill_profiles = pdm->profiles(); + std::vector<CreditCard*> credit_cards = pdm->credit_cards(); + + ListValue* profiles = GetListFromAutoFillProfiles(autofill_profiles); + ListValue* cards = GetListFromCreditCards(credit_cards); + + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + + return_value->Set(L"profiles", profiles); + return_value->Set(L"credit_cards", cards); + reply.SendSuccess(return_value.get()); + } else { + reply.SendError("No PersonalDataManager."); + return; + } + } else { + reply.SendError("No tab at that index."); + return; + } +} + +// Refer to FillAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample +// json input. +// Sample json output: {} +void AutomationProvider::FillAutoFillProfile(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + AutomationJSONReply reply(this, reply_message); + ListValue* profiles = NULL; + ListValue* cards = NULL; + args->GetList(L"profiles", &profiles); + args->GetList(L"credit_cards", &cards); + std::string error_mesg; + + std::vector<AutoFillProfile> autofill_profiles; + std::vector<CreditCard> credit_cards; + // Create an AutoFillProfile for each of the dictionary profiles. + if (profiles) { + autofill_profiles = GetAutoFillProfilesFromList(*profiles, &error_mesg); + } + // Create a CreditCard for each of the dictionary values. + if (cards) { + credit_cards = GetCreditCardsFromList(*cards, &error_mesg); + } + if (!error_mesg.empty()) { + reply.SendError(error_mesg); + return; + } + + // Save the AutoFillProfiles. + int tab_index = 0; + args->GetInteger(L"tab_index", &tab_index); + TabContents* tab_contents = browser->GetTabContentsAt(tab_index); + + if (tab_contents) { + PersonalDataManager* pdm = tab_contents->profile() + ->GetPersonalDataManager(); + if (pdm) { + pdm->OnAutoFillDialogApply(profiles? &autofill_profiles : NULL, + cards? &credit_cards : NULL); + } else { + reply.SendError("No PersonalDataManager."); + return; + } + } else { + reply.SendError("No tab at that index."); + return; + } + reply.SendSuccess(NULL); +} + +/* static */ +ListValue* AutomationProvider::GetListFromAutoFillProfiles( + std::vector<AutoFillProfile*> autofill_profiles) { + ListValue* profiles = new ListValue; + + std::map<AutoFillFieldType, std::wstring> autofill_type_to_string + = GetAutoFillFieldToStringMap(); + + // For each AutoFillProfile, transform it to a dictionary object to return. + for (std::vector<AutoFillProfile*>::iterator it = autofill_profiles.begin(); + it != autofill_profiles.end(); ++it) { + AutoFillProfile* profile = *it; + DictionaryValue* profile_info = new DictionaryValue; + profile_info->SetStringFromUTF16(L"label", profile->Label()); + // For each of the types, if it has a value, add it to the dictionary. + for (std::map<AutoFillFieldType, std::wstring>::iterator + type_it = autofill_type_to_string.begin(); + type_it != autofill_type_to_string.end(); ++type_it) { + string16 value = profile->GetFieldText(AutoFillType(type_it->first)); + if (value.length()) { // If there was something stored for that value. + profile_info->SetStringFromUTF16(type_it->second, value); + } + } + profiles->Append(profile_info); + } + return profiles; +} + +/* static */ +ListValue* AutomationProvider::GetListFromCreditCards( + std::vector<CreditCard*> credit_cards) { + ListValue* cards = new ListValue; + + std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string = + GetCreditCardFieldToStringMap(); + + // For each AutoFillProfile, transform it to a dictionary object to return. + for (std::vector<CreditCard*>::iterator it = credit_cards.begin(); + it != credit_cards.end(); ++it) { + CreditCard* card = *it; + DictionaryValue* card_info = new DictionaryValue; + card_info->SetStringFromUTF16(L"label", card->Label()); + // For each of the types, if it has a value, add it to the dictionary. + for (std::map<AutoFillFieldType, std::wstring>::iterator type_it = + credit_card_type_to_string.begin(); + type_it != credit_card_type_to_string.end(); ++type_it) { + string16 value = card->GetFieldText(AutoFillType(type_it->first)); + // If there was something stored for that value. + if (value.length()) { + card_info->SetStringFromUTF16(type_it->second, value); + } + } + cards->Append(card_info); + } + return cards; +} + +/* static */ +std::vector<AutoFillProfile> AutomationProvider::GetAutoFillProfilesFromList( + const ListValue& profiles, std::string* error_message) { + std::vector<AutoFillProfile> autofill_profiles; + DictionaryValue* profile_info = NULL; + string16 profile_label; + string16 current_value; + + std::map<AutoFillFieldType, std::wstring> autofill_type_to_string = + GetAutoFillFieldToStringMap(); + + int num_profiles = profiles.GetSize(); + for (int i = 0; i < num_profiles; i++) { + profiles.GetDictionary(i, &profile_info); + profile_info->GetString("label", &profile_label); + // Choose an id of 0 so that a unique id will be created. + AutoFillProfile profile(profile_label, 0); + // Loop through the possible profile types and add those provided. + for (std::map<AutoFillFieldType, std::wstring>::iterator type_it = + autofill_type_to_string.begin(); + type_it != autofill_type_to_string.end(); ++type_it) { + if (profile_info->HasKey(type_it->second)) { + if (profile_info->GetStringAsUTF16(type_it->second, ¤t_value)) { + profile.SetInfo(AutoFillType(type_it->first), current_value); + } else { + *error_message= "All values must be strings"; + break; + } + } + } + autofill_profiles.push_back(profile); + } + return autofill_profiles; +} + +/* static */ +std::vector<CreditCard> AutomationProvider::GetCreditCardsFromList( + const ListValue& cards, std::string* error_message) { + std::vector<CreditCard> credit_cards; + DictionaryValue* card_info = NULL; + string16 card_label; + string16 current_value; + + std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string = + GetCreditCardFieldToStringMap(); + + int num_credit_cards = cards.GetSize(); + for (int i = 0; i < num_credit_cards; i++) { + cards.GetDictionary(i, &card_info); + card_info->GetString("label", &card_label); + CreditCard card(card_label, 0); + // Loop through the possible credit card fields and add those provided. + for (std::map<AutoFillFieldType, std::wstring>::iterator type_it = + credit_card_type_to_string.begin(); + type_it != credit_card_type_to_string.end(); ++type_it) { + if (card_info->HasKey(type_it->second)) { + if (card_info->GetStringAsUTF16(type_it->second, ¤t_value)) { + card.SetInfo(AutoFillType(type_it->first), current_value); + } else { + *error_message= "All values must be strings"; + break; + } + } + } + credit_cards.push_back(card); + } + return credit_cards; +} + +/* static */ +std::map<AutoFillFieldType, std::wstring> + AutomationProvider::GetAutoFillFieldToStringMap() { + std::map<AutoFillFieldType, std::wstring> autofill_type_to_string; + autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST"; + autofill_type_to_string[NAME_MIDDLE] = L"NAME_MIDDLE"; + autofill_type_to_string[NAME_LAST] = L"NAME_LAST"; + autofill_type_to_string[COMPANY_NAME] = L"COMPANY_NAME"; + autofill_type_to_string[EMAIL_ADDRESS] = L"EMAIL_ADDRESS"; + autofill_type_to_string[ADDRESS_HOME_LINE1] = L"ADDRESS_HOME_LINE1"; + autofill_type_to_string[ADDRESS_HOME_LINE2] = L"ADDRESS_HOME_LINE2"; + autofill_type_to_string[ADDRESS_HOME_CITY] = L"ADDRESS_HOME_CITY"; + autofill_type_to_string[ADDRESS_HOME_STATE] = L"ADDRESS_HOME_STATE"; + autofill_type_to_string[ADDRESS_HOME_ZIP] = L"ADDRESS_HOME_ZIP"; + autofill_type_to_string[ADDRESS_HOME_COUNTRY] = L"ADDRESS_HOME_COUNTRY"; + autofill_type_to_string[PHONE_HOME_NUMBER] = L"PHONE_HOME_NUMBER"; + autofill_type_to_string[PHONE_FAX_NUMBER] = L"PHONE_FAX_NUMBER"; + autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST"; + return autofill_type_to_string; +} + +/* static */ +std::map<AutoFillFieldType, std::wstring> + AutomationProvider::GetCreditCardFieldToStringMap() { + std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string; + credit_card_type_to_string[CREDIT_CARD_NAME] = L"CREDIT_CARD_NAME"; + credit_card_type_to_string[CREDIT_CARD_NUMBER] = L"CREDIT_CARD_NUMBER"; + credit_card_type_to_string[CREDIT_CARD_TYPE] = L"CREDIT_CARD_TYPE"; + credit_card_type_to_string[CREDIT_CARD_EXP_MONTH] = L"CREDIT_CARD_EXP_MONTH"; + credit_card_type_to_string[CREDIT_CARD_EXP_4_DIGIT_YEAR] = + L"CREDIT_CARD_EXP_4_DIGIT_YEAR"; + return credit_card_type_to_string; +} + +void AutomationProvider::SendJSONRequest(int handle, + std::string json_request, + IPC::Message* reply_message) { + Browser* browser = NULL; + scoped_ptr<Value> values; + + // Basic error checking. + if (browser_tracker_->ContainsHandle(handle)) { + browser = browser_tracker_->GetResource(handle); + } + if (!browser) { + AutomationJSONReply(this, reply_message).SendError("no browser object"); + return; + } + base::JSONReader reader; + std::string error; + values.reset(reader.ReadAndReturnError(json_request, true, NULL, &error)); + if (!error.empty()) { + AutomationJSONReply(this, reply_message).SendError(error); + return; + } + + // Make sure input is a dict with a string command. + std::string command; + DictionaryValue* dict_value = NULL; + if (values->GetType() != Value::TYPE_DICTIONARY) { + AutomationJSONReply(this, reply_message).SendError("not a dict"); + return; + } + // Ownership remains with "values" variable. + dict_value = static_cast<DictionaryValue*>(values.get()); + if (!dict_value->GetStringASCII(std::string("command"), &command)) { + AutomationJSONReply(this, reply_message).SendError( + "no command key in dict or not a string command"); + return; + } + + // Map json commands to their handlers. + std::map<std::string, JsonHandler> handler_map; + handler_map["DisablePlugin"] = &AutomationProvider::DisablePlugin; + handler_map["EnablePlugin"] = &AutomationProvider::EnablePlugin; + handler_map["GetPluginsInfo"] = &AutomationProvider::GetPluginsInfo; + + handler_map["GetBrowserInfo"] = &AutomationProvider::GetBrowserInfo; + + handler_map["WaitForInfobarCount"] = &AutomationProvider::WaitForInfobarCount; + + handler_map["GetHistoryInfo"] = &AutomationProvider::GetHistoryInfo; + handler_map["AddHistoryItem"] = &AutomationProvider::AddHistoryItem; + + handler_map["GetOmniboxInfo"] = &AutomationProvider::GetOmniboxInfo; + handler_map["SetOmniboxText"] = &AutomationProvider::SetOmniboxText; + handler_map["OmniboxAcceptInput"] = &AutomationProvider::OmniboxAcceptInput; + handler_map["OmniboxMovePopupSelection"] = + &AutomationProvider::OmniboxMovePopupSelection; + + handler_map["GetPrefsInfo"] = &AutomationProvider::GetPrefsInfo; + handler_map["SetPrefs"] = &AutomationProvider::SetPrefs; + + handler_map["SetWindowDimensions"] = &AutomationProvider::SetWindowDimensions; + + handler_map["GetDownloadsInfo"] = &AutomationProvider::GetDownloadsInfo; + handler_map["WaitForAllDownloadsToComplete"] = + &AutomationProvider::WaitForDownloadsToComplete; + + handler_map["GetInitialLoadTimes"] = &AutomationProvider::GetInitialLoadTimes; + + handler_map["SaveTabContents"] = &AutomationProvider::SaveTabContents; + + handler_map["ImportSettings"] = &AutomationProvider::ImportSettings; + + handler_map["AddSavedPassword"] = &AutomationProvider::AddSavedPassword; + handler_map["GetSavedPasswords"] = &AutomationProvider::GetSavedPasswords; + + handler_map["ClearBrowsingData"] = &AutomationProvider::ClearBrowsingData; + + // SetTheme() implemented using InstallExtension(). + handler_map["GetThemeInfo"] = &AutomationProvider::GetThemeInfo; + + handler_map["GetAutoFillProfile"] = &AutomationProvider::GetAutoFillProfile; + handler_map["FillAutoFillProfile"] = &AutomationProvider::FillAutoFillProfile; + + if (handler_map.find(std::string(command)) != handler_map.end()) { + (this->*handler_map[command])(browser, dict_value, reply_message); + } else { + std::string error_string = "Unknown command. Options: "; + for (std::map<std::string, JsonHandler>::const_iterator it = + handler_map.begin(); it != handler_map.end(); ++it) { + error_string += it->first + ", "; + } + AutomationJSONReply(this, reply_message).SendError(error_string); + } +} + +void AutomationProvider::HandleInspectElementRequest( + int handle, int x, int y, IPC::Message* reply_message) { + TabContents* tab_contents = GetTabContentsForHandle(handle, NULL); + if (tab_contents) { + DCHECK(reply_message_ == NULL); + reply_message_ = reply_message; + + DevToolsManager::GetInstance()->InspectElement( + tab_contents->render_view_host(), x, y); + } else { + AutomationMsg_InspectElement::WriteReplyParams(reply_message, -1); + Send(reply_message); + } +} + +void AutomationProvider::ReceivedInspectElementResponse(int num_resources) { + if (reply_message_) { + AutomationMsg_InspectElement::WriteReplyParams(reply_message_, + num_resources); + Send(reply_message_); + reply_message_ = NULL; + } +} + +class SetProxyConfigTask : public Task { + public: + SetProxyConfigTask(URLRequestContextGetter* request_context_getter, + const std::string& new_proxy_config) + : request_context_getter_(request_context_getter), + proxy_config_(new_proxy_config) {} + virtual void Run() { + // First, deserialize the JSON string. If this fails, log and bail. + JSONStringValueSerializer deserializer(proxy_config_); + std::string error_msg; + scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg)); + if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) { + DLOG(WARNING) << "Received bad JSON string for ProxyConfig: " + << error_msg; + return; + } + + scoped_ptr<DictionaryValue> dict( + static_cast<DictionaryValue*>(root.release())); + // Now put together a proxy configuration from the deserialized string. + net::ProxyConfig pc; + PopulateProxyConfig(*dict.get(), &pc); + + net::ProxyService* proxy_service = + request_context_getter_->GetURLRequestContext()->proxy_service(); + DCHECK(proxy_service); + scoped_ptr<net::ProxyConfigService> proxy_config_service( + new net::ProxyConfigServiceFixed(pc)); + proxy_service->ResetConfigService(proxy_config_service.release()); + } + + void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) { + DCHECK(pc); + bool no_proxy = false; + if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) { + // Make no changes to the ProxyConfig. + return; + } + bool auto_config; + if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) { + pc->set_auto_detect(true); + } + std::string pac_url; + if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) { + pc->set_pac_url(GURL(pac_url)); + } + std::string proxy_bypass_list; + if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { + pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list); + } + std::string proxy_server; + if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) { + pc->proxy_rules().ParseFromString(proxy_server); + } + } + + private: + scoped_refptr<URLRequestContextGetter> request_context_getter_; + std::string proxy_config_; +}; + + +void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) { + URLRequestContextGetter* context_getter = Profile::GetDefaultRequestContext(); + if (!context_getter) { + FilePath user_data_dir; + PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + ProfileManager* profile_manager = g_browser_process->profile_manager(); + DCHECK(profile_manager); + Profile* profile = profile_manager->GetDefaultProfile(user_data_dir); + DCHECK(profile); + context_getter = profile->GetRequestContext(); + } + DCHECK(context_getter); + + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + new SetProxyConfigTask(context_getter, new_proxy_config)); +} + +void AutomationProvider::GetDownloadDirectory( + int handle, FilePath* download_directory) { + DLOG(INFO) << "Handling download directory request"; + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + DownloadManager* dlm = tab->profile()->GetDownloadManager(); + DCHECK(dlm); + *download_directory = dlm->download_path(); + } +} + +void AutomationProvider::OpenNewBrowserWindow(bool show, + IPC::Message* reply_message) { + OpenNewBrowserWindowOfType(static_cast<int>(Browser::TYPE_NORMAL), show, + reply_message); +} + +void AutomationProvider::OpenNewBrowserWindowOfType( + int type, bool show, IPC::Message* reply_message) { + new BrowserOpenedNotificationObserver(this, reply_message); + // We may have no current browser windows open so don't rely on + // asking an existing browser to execute the IDC_NEWWINDOW command + Browser* browser = new Browser(static_cast<Browser::Type>(type), profile_); + browser->CreateBrowserWindow(); + browser->AddBlankTab(true); + if (show) + browser->window()->Show(); +} + +void AutomationProvider::GetWindowForBrowser(int browser_handle, + bool* success, + int* handle) { + *success = false; + *handle = 0; + + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + gfx::NativeWindow win = browser->window()->GetNativeHandle(); + // Add() returns the existing handle for the resource if any. + *handle = window_tracker_->Add(win); + *success = true; + } +} + +void AutomationProvider::GetAutocompleteEditForBrowser( + int browser_handle, + bool* success, + int* autocomplete_edit_handle) { + *success = false; + *autocomplete_edit_handle = 0; + + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + LocationBar* loc_bar = browser->window()->GetLocationBar(); + AutocompleteEditView* edit_view = loc_bar->location_entry(); + // Add() returns the existing handle for the resource if any. + *autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view); + *success = true; + } +} + +void AutomationProvider::ShowInterstitialPage(int tab_handle, + const std::string& html_text, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* controller = tab_tracker_->GetResource(tab_handle); + TabContents* tab_contents = controller->tab_contents(); + + AddNavigationStatusListener(controller, reply_message, 1, false); + AutomationInterstitialPage* interstitial = + new AutomationInterstitialPage(tab_contents, + GURL("about:interstitial"), + html_text); + interstitial->Show(); + return; + } + + AutomationMsg_ShowInterstitialPage::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::HideInterstitialPage(int tab_handle, + bool* success) { + *success = false; + TabContents* tab_contents = GetTabContentsForHandle(tab_handle, NULL); + if (tab_contents && tab_contents->interstitial_page()) { + tab_contents->interstitial_page()->DontProceed(); + *success = true; + } +} + +void AutomationProvider::CloseTab(int tab_handle, + bool wait_until_closed, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* controller = tab_tracker_->GetResource(tab_handle); + int index; + Browser* browser = Browser::GetBrowserForController(controller, &index); + DCHECK(browser); + new TabClosedNotificationObserver(this, wait_until_closed, reply_message); + browser->CloseContents(controller->tab_contents()); + return; + } + + AutomationMsg_CloseTab::WriteReplyParams(reply_message, false); + Send(reply_message); +} + +void AutomationProvider::CloseBrowser(int browser_handle, + IPC::Message* reply_message) { + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + new BrowserClosedNotificationObserver(browser, this, + reply_message); + browser->window()->Close(); + } else { + NOTREACHED(); + } +} + +void AutomationProvider::CloseBrowserAsync(int browser_handle) { + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + browser->window()->Close(); + } else { + NOTREACHED(); + } +} + +void AutomationProvider::WaitForTabToBeRestored(int tab_handle, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + restore_tracker_.reset( + new NavigationControllerRestoredObserver(this, tab, reply_message)); + } +} + +void AutomationProvider::GetSecurityState(int handle, bool* success, + SecurityStyle* security_style, + int* ssl_cert_status, + int* insecure_content_status) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + NavigationEntry* entry = tab->GetActiveEntry(); + *success = true; + *security_style = entry->ssl().security_style(); + *ssl_cert_status = entry->ssl().cert_status(); + *insecure_content_status = entry->ssl().content_status(); + } else { + *success = false; + *security_style = SECURITY_STYLE_UNKNOWN; + *ssl_cert_status = 0; + *insecure_content_status = 0; + } +} + +void AutomationProvider::GetPageType(int handle, bool* success, + NavigationEntry::PageType* page_type) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + NavigationEntry* entry = tab->GetActiveEntry(); + *page_type = entry->page_type(); + *success = true; + // In order to return the proper result when an interstitial is shown and + // no navigation entry were created for it we need to ask the TabContents. + if (*page_type == NavigationEntry::NORMAL_PAGE && + tab->tab_contents()->showing_interstitial_page()) + *page_type = NavigationEntry::INTERSTITIAL_PAGE; + } else { + *success = false; + *page_type = NavigationEntry::NORMAL_PAGE; + } +} + +void AutomationProvider::GetMetricEventDuration(const std::string& event_name, + int* duration_ms) { + *duration_ms = metric_event_duration_observer_->GetEventDurationMs( + event_name); +} + +void AutomationProvider::ActionOnSSLBlockingPage(int handle, bool proceed, + IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + NavigationEntry* entry = tab->GetActiveEntry(); + if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) { + TabContents* tab_contents = tab->tab_contents(); + InterstitialPage* ssl_blocking_page = + InterstitialPage::GetInterstitialPage(tab_contents); + if (ssl_blocking_page) { + if (proceed) { + AddNavigationStatusListener(tab, reply_message, 1, false); + ssl_blocking_page->Proceed(); + return; + } + ssl_blocking_page->DontProceed(); + AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS); + Send(reply_message); + return; + } + } + } + // We failed. + AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::BringBrowserToFront(int browser_handle, + bool* success) { + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + browser->window()->Activate(); + *success = true; + } else { + *success = false; + } +} + +void AutomationProvider::IsMenuCommandEnabled(int browser_handle, + int message_num, + bool* menu_item_enabled) { + if (browser_tracker_->ContainsHandle(browser_handle)) { + Browser* browser = browser_tracker_->GetResource(browser_handle); + *menu_item_enabled = + browser->command_updater()->IsCommandEnabled(message_num); + } else { + *menu_item_enabled = false; + } +} + +void AutomationProvider::PrintNow(int tab_handle, + IPC::Message* reply_message) { + NavigationController* tab = NULL; + TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab); + if (tab_contents) { + FindAndActivateTab(tab); + notification_observer_list_.AddObserver( + new DocumentPrintedNotificationObserver(this, reply_message)); + if (tab_contents->PrintNow()) + return; + } + AutomationMsg_PrintNow::WriteReplyParams(reply_message, false); + Send(reply_message); +} + +void AutomationProvider::SavePage(int tab_handle, + const FilePath& file_name, + const FilePath& dir_path, + int type, + bool* success) { + if (!tab_tracker_->ContainsHandle(tab_handle)) { + *success = false; + return; + } + + NavigationController* nav = tab_tracker_->GetResource(tab_handle); + Browser* browser = FindAndActivateTab(nav); + DCHECK(browser); + if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) { + *success = false; + return; + } + + SavePackage::SavePackageType save_type = + static_cast<SavePackage::SavePackageType>(type); + DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML && + save_type <= SavePackage::SAVE_AS_COMPLETE_HTML); + nav->tab_contents()->SavePage(file_name, dir_path, save_type); + + *success = true; +} + +void AutomationProvider::GetAutocompleteEditText(int autocomplete_edit_handle, + bool* success, + std::wstring* text) { + *success = false; + if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) { + *text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)-> + GetText(); + *success = true; + } +} + +void AutomationProvider::SetAutocompleteEditText(int autocomplete_edit_handle, + const std::wstring& text, + bool* success) { + *success = false; + if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) { + autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)-> + SetUserText(text); + *success = true; + } +} + +void AutomationProvider::AutocompleteEditGetMatches( + int autocomplete_edit_handle, + bool* success, + std::vector<AutocompleteMatchData>* matches) { + *success = false; + if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) { + const AutocompleteResult& result = autocomplete_edit_tracker_-> + GetResource(autocomplete_edit_handle)->model()->result(); + for (AutocompleteResult::const_iterator i = result.begin(); + i != result.end(); ++i) + matches->push_back(AutocompleteMatchData(*i)); + *success = true; + } +} + +void AutomationProvider::AutocompleteEditIsQueryInProgress( + int autocomplete_edit_handle, + bool* success, + bool* query_in_progress) { + *success = false; + *query_in_progress = false; + if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) { + *query_in_progress = autocomplete_edit_tracker_-> + GetResource(autocomplete_edit_handle)->model()->query_in_progress(); + *success = true; + } +} + +#if !defined(OS_MACOSX) + +#endif // !defined(OS_MACOSX) + +TabContents* AutomationProvider::GetTabContentsForHandle( + int handle, NavigationController** tab) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + if (tab) + *tab = nav_controller; + return nav_controller->tab_contents(); + } + return NULL; +} + +TestingAutomationProvider::TestingAutomationProvider(Profile* profile) + : AutomationProvider(profile) { + BrowserList::AddObserver(this); + registrar_.Add(this, NotificationType::SESSION_END, + NotificationService::AllSources()); +} + +TestingAutomationProvider::~TestingAutomationProvider() { + BrowserList::RemoveObserver(this); +} + +void TestingAutomationProvider::OnChannelError() { + BrowserList::CloseAllBrowsersAndExit(); + AutomationProvider::OnChannelError(); +} + +void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) { +} + +void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) { + // For backwards compatibility with the testing automation interface, we + // want the automation provider (and hence the process) to go away when the + // last browser goes away. + if (BrowserList::size() == 1 && !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kKeepAliveForTest)) { + // If you change this, update Observer for NotificationType::SESSION_END + // below. + MessageLoop::current()->PostTask(FROM_HERE, + NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider)); + } +} + +void TestingAutomationProvider::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::SESSION_END); + // OnBrowserRemoving does a ReleaseLater. When session end is received we exit + // before the task runs resulting in this object not being deleted. This + // Release balance out the Release scheduled by OnBrowserRemoving. + Release(); +} + +void TestingAutomationProvider::OnRemoveProvider() { + AutomationProviderList::GetInstance()->RemoveProvider(this); +} + +void AutomationProvider::GetInfoBarCount(int handle, int* count) { + *count = -1; // -1 means error. + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + if (nav_controller) + *count = nav_controller->tab_contents()->infobar_delegate_count(); + } +} + +void AutomationProvider::ClickInfoBarAccept(int handle, + int info_bar_index, + bool wait_for_navigation, + IPC::Message* reply_message) { + bool success = false; + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + if (nav_controller) { + int count = nav_controller->tab_contents()->infobar_delegate_count(); + if (info_bar_index >= 0 && info_bar_index < count) { + if (wait_for_navigation) { + AddNavigationStatusListener(nav_controller, reply_message, 1, false); + } + InfoBarDelegate* delegate = + nav_controller->tab_contents()->GetInfoBarDelegateAt( + info_bar_index); + if (delegate->AsConfirmInfoBarDelegate()) + delegate->AsConfirmInfoBarDelegate()->Accept(); + success = true; + } + } + } + + // This "!wait_for_navigation || !success condition" logic looks suspicious. + // It will send a failure message when success is true but + // |wait_for_navigation| is false. + // TODO(phajdan.jr): investgate whether the reply param (currently + // AUTOMATION_MSG_NAVIGATION_ERROR) should depend on success. + if (!wait_for_navigation || !success) + AutomationMsg_ClickInfoBarAccept::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); +} + +void AutomationProvider::GetLastNavigationTime(int handle, + int64* last_navigation_time) { + Time time = tab_tracker_->GetLastNavigationTime(handle); + *last_navigation_time = time.ToInternalValue(); +} + +void AutomationProvider::WaitForNavigation(int handle, + int64 last_navigation_time, + IPC::Message* reply_message) { + NavigationController* controller = tab_tracker_->GetResource(handle); + Time time = tab_tracker_->GetLastNavigationTime(handle); + + if (time.ToInternalValue() > last_navigation_time || !controller) { + AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message, + controller == NULL ? AUTOMATION_MSG_NAVIGATION_ERROR : + AUTOMATION_MSG_NAVIGATION_SUCCESS); + Send(reply_message); + return; + } + + AddNavigationStatusListener(controller, reply_message, 1, true); +} + +void AutomationProvider::SetIntPreference(int handle, + const std::wstring& name, + int value, + bool* success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->profile()->GetPrefs()->SetInteger(name.c_str(), value); + *success = true; + } +} + +void AutomationProvider::SetStringPreference(int handle, + const std::wstring& name, + const std::string& value, + bool* success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->profile()->GetPrefs()->SetString(name.c_str(), value); + *success = true; + } +} + +void AutomationProvider::GetBooleanPreference(int handle, + const std::wstring& name, + bool* success, + bool* value) { + *success = false; + *value = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + *value = browser->profile()->GetPrefs()->GetBoolean(name.c_str()); + *success = true; + } +} + +void AutomationProvider::SetBooleanPreference(int handle, + const std::wstring& name, + bool value, + bool* success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + browser->profile()->GetPrefs()->SetBoolean(name.c_str(), value); + *success = true; + } +} + +// Gets the current used encoding name of the page in the specified tab. +void AutomationProvider::GetPageCurrentEncoding( + int tab_handle, std::string* current_encoding) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* nav = tab_tracker_->GetResource(tab_handle); + Browser* browser = FindAndActivateTab(nav); + DCHECK(browser); + + if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) + *current_encoding = nav->tab_contents()->encoding(); + } +} + +// Gets the current used encoding name of the page in the specified tab. +void AutomationProvider::OverrideEncoding(int tab_handle, + const std::string& encoding_name, + bool* success) { + *success = false; + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* nav = tab_tracker_->GetResource(tab_handle); + if (!nav) + return; + Browser* browser = FindAndActivateTab(nav); + + // If the browser has UI, simulate what a user would do. + // Activate the tab and then click the encoding menu. + if (browser && + browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) { + int selected_encoding_id = + CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name); + if (selected_encoding_id) { + browser->OverrideEncoding(selected_encoding_id); + *success = true; + } + } else { + // There is no UI, Chrome probably runs as Chrome-Frame mode. + // Try to get TabContents and call its override_encoding method. + TabContents* contents = nav->tab_contents(); + if (!contents) + return; + const std::string selected_encoding = + CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name); + if (selected_encoding.empty()) + return; + contents->SetOverrideEncoding(selected_encoding); + } + } +} + +void AutomationProvider::SavePackageShouldPromptUser(bool should_prompt) { + SavePackage::SetShouldPromptUser(should_prompt); +} + +void AutomationProvider::GetBlockedPopupCount(int handle, int* count) { + *count = -1; // -1 is the error code + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* nav_controller = tab_tracker_->GetResource(handle); + TabContents* tab_contents = nav_controller->tab_contents(); + if (tab_contents) { + BlockedPopupContainer* container = + tab_contents->blocked_popup_container(); + if (container) { + *count = static_cast<int>(container->GetBlockedPopupCount()); + } else { + // If we don't have a container, we don't have any blocked popups to + // contain! + *count = 0; + } + } + } +} + +void AutomationProvider::SelectAll(int tab_handle) { + RenderViewHost* view = GetViewForTab(tab_handle); + if (!view) { + NOTREACHED(); + return; + } + + view->SelectAll(); +} + +void AutomationProvider::Cut(int tab_handle) { + RenderViewHost* view = GetViewForTab(tab_handle); + if (!view) { + NOTREACHED(); + return; + } + + view->Cut(); +} + +void AutomationProvider::Copy(int tab_handle) { + RenderViewHost* view = GetViewForTab(tab_handle); + if (!view) { + NOTREACHED(); + return; + } + + view->Copy(); +} + +void AutomationProvider::Paste(int tab_handle) { + RenderViewHost* view = GetViewForTab(tab_handle); + if (!view) { + NOTREACHED(); + return; + } + + view->Paste(); +} + +void AutomationProvider::ReloadAsync(int tab_handle) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + if (!tab) { + NOTREACHED(); + return; + } + + const bool check_for_repost = true; + tab->Reload(check_for_repost); + } +} + +void AutomationProvider::StopAsync(int tab_handle) { + RenderViewHost* view = GetViewForTab(tab_handle); + if (!view) { + // We tolerate StopAsync being called even before a view has been created. + // So just log a warning instead of a NOTREACHED(). + DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle; + return; + } + + view->Stop(); +} + +void AutomationProvider::OnSetPageFontSize(int tab_handle, + int font_size) { + AutomationPageFontSize automation_font_size = + static_cast<AutomationPageFontSize>(font_size); + + if (automation_font_size < SMALLEST_FONT || + automation_font_size > LARGEST_FONT) { + DLOG(ERROR) << "Invalid font size specified : " + << font_size; + return; + } + + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + DCHECK(tab != NULL); + if (tab && tab->tab_contents()) { + DCHECK(tab->tab_contents()->profile() != NULL); + tab->tab_contents()->profile()->GetPrefs()->SetInteger( + prefs::kWebKitDefaultFontSize, font_size); + } + } +} + +void AutomationProvider::RemoveBrowsingData(int remove_mask) { + BrowsingDataRemover* remover; + remover = new BrowsingDataRemover(profile(), + BrowsingDataRemover::EVERYTHING, // All time periods. + base::Time()); + remover->Remove(remove_mask); + // BrowsingDataRemover deletes itself. +} + +void AutomationProvider::WaitForBrowserWindowCountToBecome( + int target_count, IPC::Message* reply_message) { + if (static_cast<int>(BrowserList::size()) == target_count) { + AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams( + reply_message, true); + Send(reply_message); + return; + } + + // Set up an observer (it will delete itself). + new BrowserCountChangeNotificationObserver(target_count, this, reply_message); +} + +void AutomationProvider::WaitForAppModalDialogToBeShown( + IPC::Message* reply_message) { + if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) { + AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams( + reply_message, true); + Send(reply_message); + return; + } + + // Set up an observer (it will delete itself). + new AppModalDialogShownObserver(this, reply_message); +} + +void AutomationProvider::GoBackBlockUntilNavigationsComplete( + int handle, int number_of_navigations, IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = FindAndActivateTab(tab); + if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) { + AddNavigationStatusListener(tab, reply_message, number_of_navigations, + false); + browser->GoBack(CURRENT_TAB); + return; + } + } + + AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +void AutomationProvider::GoForwardBlockUntilNavigationsComplete( + int handle, int number_of_navigations, IPC::Message* reply_message) { + if (tab_tracker_->ContainsHandle(handle)) { + NavigationController* tab = tab_tracker_->GetResource(handle); + Browser* browser = FindAndActivateTab(tab); + if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) { + AddNavigationStatusListener(tab, reply_message, number_of_navigations, + false); + browser->GoForward(CURRENT_TAB); + return; + } + } + + AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams( + reply_message, AUTOMATION_MSG_NAVIGATION_ERROR); + Send(reply_message); +} + +RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) { + if (tab_tracker_->ContainsHandle(tab_handle)) { + NavigationController* tab = tab_tracker_->GetResource(tab_handle); + if (!tab) { + NOTREACHED(); + return NULL; + } + + TabContents* tab_contents = tab->tab_contents(); + if (!tab_contents) { + NOTREACHED(); + return NULL; + } + + RenderViewHost* view_host = tab_contents->render_view_host(); + return view_host; + } + + return NULL; +} + +void AutomationProvider::GetBrowserForWindow(int window_handle, + bool* success, + int* browser_handle) { + *success = false; + *browser_handle = 0; + + gfx::NativeWindow window = window_tracker_->GetResource(window_handle); + if (!window) + return; + + BrowserList::const_iterator iter = BrowserList::begin(); + for (;iter != BrowserList::end(); ++iter) { + gfx::NativeWindow this_window = (*iter)->window()->GetNativeHandle(); + if (window == this_window) { + // Add() returns the existing handle for the resource if any. + *browser_handle = browser_tracker_->Add(*iter); + *success = true; + return; + } + } +} + +void AutomationProvider::InstallExtension(const FilePath& crx_path, + IPC::Message* reply_message) { + ExtensionsService* service = profile_->GetExtensionsService(); + if (service) { + // The observer will delete itself when done. + new ExtensionInstallNotificationObserver(this, + AutomationMsg_InstallExtension::ID, + reply_message); + + const FilePath& install_dir = service->install_directory(); + scoped_refptr<CrxInstaller> installer( + new CrxInstaller(install_dir, + service, + NULL)); // silent install, no UI + installer->set_allow_privilege_increase(true); + installer->InstallCrx(crx_path); + } else { + AutomationMsg_InstallExtension::WriteReplyParams( + reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); + Send(reply_message); + } +} + +void AutomationProvider::LoadExpandedExtension( + const FilePath& extension_dir, + IPC::Message* reply_message) { + if (profile_->GetExtensionsService()) { + // The observer will delete itself when done. + new ExtensionInstallNotificationObserver( + this, + AutomationMsg_LoadExpandedExtension::ID, + reply_message); + + profile_->GetExtensionsService()->LoadExtension(extension_dir); + } else { + AutomationMsg_LoadExpandedExtension::WriteReplyParams( + reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); + Send(reply_message); + } +} + +void AutomationProvider::GetEnabledExtensions( + std::vector<FilePath>* result) { + ExtensionsService* service = profile_->GetExtensionsService(); + DCHECK(service); + if (service->extensions_enabled()) { + const ExtensionList* extensions = service->extensions(); + DCHECK(extensions); + for (size_t i = 0; i < extensions->size(); ++i) { + Extension* extension = (*extensions)[i]; + DCHECK(extension); + if (extension->location() == Extension::INTERNAL || + extension->location() == Extension::LOAD) { + result->push_back(extension->path()); + } + } + } +} + +void AutomationProvider::WaitForExtensionTestResult( + IPC::Message* reply_message) { + DCHECK(reply_message_ == NULL); + reply_message_ = reply_message; + // Call MaybeSendResult, because the result might have come in before + // we were waiting on it. + extension_test_result_observer_->MaybeSendResult(); +} + +void AutomationProvider::InstallExtensionAndGetHandle( + const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) { + ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); + if (service && manager) { + // The observer will delete itself when done. + new ExtensionReadyNotificationObserver( + manager, + this, + AutomationMsg_InstallExtensionAndGetHandle::ID, + reply_message); + + ExtensionInstallUI* client = + (with_ui ? new ExtensionInstallUI(profile_) : NULL); + scoped_refptr<CrxInstaller> installer( + new CrxInstaller(service->install_directory(), + service, + client)); + installer->set_allow_privilege_increase(true); + installer->InstallCrx(crx_path); + } else { + AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams( + reply_message, 0); + Send(reply_message); + } +} + +void AutomationProvider::UninstallExtension(int extension_handle, + bool* success) { + *success = false; + Extension* extension = GetExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service) { + ExtensionUnloadNotificationObserver observer; + service->UninstallExtension(extension->id(), false); + // The extension unload notification should have been sent synchronously + // with the uninstall. Just to be safe, check that it was received. + *success = observer.did_receive_unload_notification(); + } +} + +void AutomationProvider::EnableExtension(int extension_handle, + IPC::Message* reply_message) { + Extension* extension = GetDisabledExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionProcessManager* manager = profile_->GetExtensionProcessManager(); + // Only enable if this extension is disabled. + if (extension && service && manager) { + // The observer will delete itself when done. + new ExtensionReadyNotificationObserver( + manager, + this, + AutomationMsg_EnableExtension::ID, + reply_message); + service->EnableExtension(extension->id()); + } else { + AutomationMsg_EnableExtension::WriteReplyParams(reply_message, false); + Send(reply_message); + } +} + +void AutomationProvider::DisableExtension(int extension_handle, + bool* success) { + *success = false; + Extension* extension = GetEnabledExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service) { + ExtensionUnloadNotificationObserver observer; + service->DisableExtension(extension->id()); + // The extension unload notification should have been sent synchronously + // with the disable. Just to be safe, check that it was received. + *success = observer.did_receive_unload_notification(); + } +} + +void AutomationProvider::ExecuteExtensionActionInActiveTabAsync( + int extension_handle, int browser_handle, + IPC::Message* reply_message) { + bool success = false; + Extension* extension = GetEnabledExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + ExtensionMessageService* message_service = + profile_->GetExtensionMessageService(); + Browser* browser = browser_tracker_->GetResource(browser_handle); + if (extension && service && message_service && browser) { + int tab_id = ExtensionTabUtil::GetTabId(browser->GetSelectedTabContents()); + if (extension->page_action()) { + ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted( + browser->profile(), extension->id(), "action", tab_id, "", 1); + success = true; + } else if (extension->browser_action()) { + ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( + browser->profile(), extension->id(), browser); + success = true; + } + } + AutomationMsg_ExecuteExtensionActionInActiveTabAsync::WriteReplyParams( + reply_message, success); + Send(reply_message); +} + +void AutomationProvider::MoveExtensionBrowserAction( + int extension_handle, int index, bool* success) { + *success = false; + Extension* extension = GetEnabledExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service) { + ExtensionToolbarModel* toolbar = service->toolbar_model(); + if (toolbar) { + if (index >= 0 && index < static_cast<int>(toolbar->size())) { + toolbar->MoveBrowserAction(extension, index); + *success = true; + } else { + DLOG(WARNING) << "Attempted to move browser action to invalid index."; + } + } + } +} + +void AutomationProvider::GetExtensionProperty( + int extension_handle, + AutomationMsg_ExtensionProperty type, + bool* success, + std::string* value) { + *success = false; + Extension* extension = GetExtension(extension_handle); + ExtensionsService* service = profile_->GetExtensionsService(); + if (extension && service) { + ExtensionToolbarModel* toolbar = service->toolbar_model(); + int found_index = -1; + int index = 0; + switch (type) { + case AUTOMATION_MSG_EXTENSION_ID: + *value = extension->id(); + *success = true; + break; + case AUTOMATION_MSG_EXTENSION_NAME: + *value = extension->name(); + *success = true; + break; + case AUTOMATION_MSG_EXTENSION_VERSION: + *value = extension->VersionString(); + *success = true; + break; + case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX: + if (toolbar) { + for (ExtensionList::const_iterator iter = toolbar->begin(); + iter != toolbar->end(); iter++) { + // Skip this extension if we are in incognito mode + // and it is not incognito-enabled. + if (profile_->IsOffTheRecord() && + !service->IsIncognitoEnabled(*iter)) + continue; + if (*iter == extension) { + found_index = index; + break; + } + index++; + } + *value = IntToString(found_index); + *success = true; + } + break; + default: + LOG(WARNING) << "Trying to get undefined extension property"; + break; + } + } +} + +void AutomationProvider::SaveAsAsync(int tab_handle) { + NavigationController* tab = NULL; + TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab); + if (tab_contents) + tab_contents->OnSavePage(); +} + +void AutomationProvider::SetContentSetting( + int handle, + const std::string& host, + ContentSettingsType content_type, + ContentSetting setting, + bool* success) { + *success = false; + if (browser_tracker_->ContainsHandle(handle)) { + Browser* browser = browser_tracker_->GetResource(handle); + HostContentSettingsMap* map = + browser->profile()->GetHostContentSettingsMap(); + if (host.empty()) { + map->SetDefaultContentSetting(content_type, setting); + } else { + map->SetContentSetting(HostContentSettingsMap::Pattern(host), + content_type, setting); + } + *success = true; + } +} + +#if !defined(TOOLKIT_VIEWS) +void AutomationProvider::GetFocusedViewID(int handle, int* view_id) { + NOTIMPLEMENTED(); +}; + +void AutomationProvider::WaitForFocusedViewIDToChange( + int handle, int previous_view_id, IPC::Message* reply_message) { + NOTIMPLEMENTED(); +} + +void AutomationProvider::StartTrackingPopupMenus( + int browser_handle, bool* success) { + NOTIMPLEMENTED(); +} + +void AutomationProvider::WaitForPopupMenuToOpen(IPC::Message* reply_message) { + NOTIMPLEMENTED(); +} +#endif // !defined(TOOLKIT_VIEWS) + +void AutomationProvider::ResetToDefaultTheme() { + profile_->ClearTheme(); +} |