diff options
27 files changed, 1892 insertions, 222 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 7120cb8..5380f75 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS @@ -4,6 +4,7 @@ include_rules = [ "+chrome/installer", "+chrome/personalization", "+chrome/plugin", # For Mac plugin interpose library. + "+chrome/profile_import", "+chrome/tools/profiles", # For history unit tests. "+chrome/views", "+grit", # For generated headers diff --git a/chrome/browser/cocoa/import_progress_dialog.h b/chrome/browser/cocoa/import_progress_dialog.h index 41e401d..72f2cc2 100644 --- a/chrome/browser/cocoa/import_progress_dialog.h +++ b/chrome/browser/cocoa/import_progress_dialog.h @@ -19,7 +19,6 @@ class ImporterObserverBridge; scoped_ptr<ImporterObserverBridge> import_host_observer_bridge_; ImporterHost* importer_host_; // (weak) ImportObserver* observer_; // (weak) - BOOL importing_; // Strings bound to static labels in the UI dialog. NSString* explanatory_text_; @@ -50,7 +49,6 @@ class ImporterObserverBridge; // Methods called by importer_host via ImporterObserverBridge. - (void)ImportItemStarted:(importer::ImportItem)item; - (void)ImportItemEnded:(importer::ImportItem)item; -- (void)ImportStarted; - (void)ImportEnded; @property(retain) NSString* explanatoryText; @@ -86,7 +84,7 @@ class ImporterObserverBridge : public ImporterHost::Observer { // Invoked when the import begins. virtual void ImportStarted() { - [owner_ ImportStarted]; + // Not needed for out of process import. } // Invoked when the source profile has been imported. diff --git a/chrome/browser/cocoa/import_progress_dialog.mm b/chrome/browser/cocoa/import_progress_dialog.mm index 765e4d1..b8966fd 100644 --- a/chrome/browser/cocoa/import_progress_dialog.mm +++ b/chrome/browser/cocoa/import_progress_dialog.mm @@ -112,7 +112,6 @@ NSString* keyForImportItem(importer::ImportItem item) { [super dealloc]; } - - (IBAction)showWindow:(id)sender { NSWindow* win = [self window]; [win center]; @@ -126,13 +125,12 @@ NSString* keyForImportItem(importer::ImportItem item) { } - (IBAction)cancel:(id)sender { - [self closeDialog]; - if (importing_) { - importer_host_->Cancel(); - } else { - [self release]; - } + // The ImporterHost will notify import_host_observer_bridge_ that import has + // ended, which will trigger the ImportEnded method, in which this object is + // released. + importer_host_->Cancel(); } + - (void)ImportItemStarted:(importer::ImportItem)item { [self setValue:progress_text_ forKey:keyForImportItem(item)]; } @@ -141,12 +139,7 @@ NSString* keyForImportItem(importer::ImportItem item) { [self setValue:done_text_ forKey:keyForImportItem(item)]; } -- (void)ImportStarted { - importing_ = YES; -} - - (void)ImportEnded { - importing_ = NO; importer_host_->SetObserver(NULL); if (observer_) observer_->ImportComplete(); @@ -184,7 +177,6 @@ void StartImportingWithUI(gfx::NativeWindow parent_window, new ProfileWriter(target_profile), first_run); - // Display the window while spinning a message loop. // For details on why we need a modal message loop see http://crbug.com/19169 NSWindow* progress_window = [progress_dialog_ window]; diff --git a/chrome/browser/first_run_mac.mm b/chrome/browser/first_run_mac.mm index b6bcbab..3a73403 100644 --- a/chrome/browser/first_run_mac.mm +++ b/chrome/browser/first_run_mac.mm @@ -64,7 +64,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir, } FirstRunController::FirstRunController() - : importer_host_(new ImporterHost) { + : importer_host_(new ExternalProcessImporterHost) { } void FirstRunController::FirstRunDone() { @@ -72,7 +72,6 @@ void FirstRunController::FirstRunDone() { // TODO(jeremy): Implement // FirstRun::SetShowFirstRunBubblePref(); // FirstRun::SetShowWelcomePagePref(); - delete this; } diff --git a/chrome/browser/gtk/import_progress_dialog_gtk.cc b/chrome/browser/gtk/import_progress_dialog_gtk.cc index 946e1d9..09e30da 100644 --- a/chrome/browser/gtk/import_progress_dialog_gtk.cc +++ b/chrome/browser/gtk/import_progress_dialog_gtk.cc @@ -62,7 +62,7 @@ void ImportProgressDialogGtk::StartImport(GtkWindow* parent, //////////////////////////////////////////////////////////////////////////////// // ImporterHost::Observer implementation: -void ImportProgressDialogGtk::ImportItemStarted(ImportItem item) { +void ImportProgressDialogGtk::ImportItemStarted(importer::ImportItem item) { DCHECK(items_ & item); switch (item) { case FAVORITES: @@ -86,7 +86,7 @@ void ImportProgressDialogGtk::ImportItemStarted(ImportItem item) { } } -void ImportProgressDialogGtk::ImportItemEnded(ImportItem item) { +void ImportProgressDialogGtk::ImportItemEnded(importer::ImportItem item) { DCHECK(items_ & item); switch (item) { case FAVORITES: diff --git a/chrome/browser/importer/firefox2_importer.cc b/chrome/browser/importer/firefox2_importer.cc index 655638c..211bfc9 100644 --- a/chrome/browser/importer/firefox2_importer.cc +++ b/chrome/browser/importer/firefox2_importer.cc @@ -7,7 +7,6 @@ #include <string> #include <vector> -#include "app/l10n_util.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/i18n/icu_string_conversions.h" @@ -19,6 +18,7 @@ #include "chrome/browser/history/history_types.h" #include "chrome/browser/importer/firefox_importer_utils.h" #include "chrome/browser/importer/importer_bridge.h" +#include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/importer/mork_reader.h" #include "chrome/browser/importer/nss_decryptor.h" #include "chrome/browser/search_engines/template_url.h" @@ -47,43 +47,44 @@ Firefox2Importer::Firefox2Importer() : parsing_bookmarks_html_file_(false) { Firefox2Importer::~Firefox2Importer() { } -void Firefox2Importer::StartImport(ProfileInfo profile_info, +void Firefox2Importer::StartImport(importer::ProfileInfo profile_info, uint16 items, ImporterBridge* bridge) { bridge_ = bridge; source_path_ = profile_info.source_path; app_path_ = profile_info.app_path; - parsing_bookmarks_html_file_ = (profile_info.browser_type == BOOKMARKS_HTML); + parsing_bookmarks_html_file_ = + (profile_info.browser_type == importer::BOOKMARKS_HTML); // The order here is important! bridge_->NotifyStarted(); - if ((items & HOME_PAGE) && !cancelled()) + if ((items & importer::HOME_PAGE) && !cancelled()) ImportHomepage(); // Doesn't have a UI item. // Note history should be imported before bookmarks because bookmark import // will also import favicons and we store favicon for a URL only if the URL // exist in history or bookmarks. - if ((items & HISTORY) && !cancelled()) { - bridge_->NotifyItemStarted(HISTORY); + if ((items & importer::HISTORY) && !cancelled()) { + bridge_->NotifyItemStarted(importer::HISTORY); ImportHistory(); - bridge_->NotifyItemEnded(HISTORY); + bridge_->NotifyItemEnded(importer::HISTORY); } - if ((items & FAVORITES) && !cancelled()) { - bridge_->NotifyItemStarted(FAVORITES); + if ((items & importer::FAVORITES) && !cancelled()) { + bridge_->NotifyItemStarted(importer::FAVORITES); ImportBookmarks(); - bridge_->NotifyItemEnded(FAVORITES); + bridge_->NotifyItemEnded(importer::FAVORITES); } - if ((items & SEARCH_ENGINES) && !cancelled()) { - bridge_->NotifyItemStarted(SEARCH_ENGINES); + if ((items & importer::SEARCH_ENGINES) && !cancelled()) { + bridge_->NotifyItemStarted(importer::SEARCH_ENGINES); ImportSearchEngines(); - bridge_->NotifyItemEnded(SEARCH_ENGINES); + bridge_->NotifyItemEnded(importer::SEARCH_ENGINES); } - if ((items & PASSWORDS) && !cancelled()) { - bridge_->NotifyItemStarted(PASSWORDS); + if ((items & importer::PASSWORDS) && !cancelled()) { + bridge_->NotifyItemStarted(importer::PASSWORDS); ImportPasswords(); - bridge_->NotifyItemEnded(PASSWORDS); + bridge_->NotifyItemEnded(importer::PASSWORDS); } bridge_->NotifyEnded(); } @@ -263,10 +264,9 @@ void Firefox2Importer::ImportBookmarks() { if (!parsing_bookmarks_html_file_) file = file.AppendASCII("bookmarks.html"); std::wstring first_folder_name; - if (parsing_bookmarks_html_file_) - first_folder_name = l10n_util::GetString(IDS_BOOKMARK_GROUP); - else - first_folder_name = l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); + first_folder_name = bridge_->GetLocalizedString( + parsing_bookmarks_html_file_ ? IDS_BOOKMARK_GROUP : + IDS_BOOKMARK_GROUP_FROM_FIREFOX); ImportBookmarksFile(file, default_urls, import_to_bookmark_bar(), first_folder_name, this, &bookmarks, &template_urls, diff --git a/chrome/browser/importer/firefox3_importer.cc b/chrome/browser/importer/firefox3_importer.cc index 6010f45..775e8ca 100644 --- a/chrome/browser/importer/firefox3_importer.cc +++ b/chrome/browser/importer/firefox3_importer.cc @@ -6,7 +6,6 @@ #include <set> -#include "app/l10n_util.h" #include "base/file_util.h" #include "base/message_loop.h" #include "base/scoped_ptr.h" @@ -16,6 +15,7 @@ #include "chrome/browser/importer/firefox2_importer.h" #include "chrome/browser/importer/firefox_importer_utils.h" #include "chrome/browser/importer/importer_bridge.h" +#include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/importer/nss_decryptor.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/common/time_format.h" @@ -33,7 +33,7 @@ using importer::ProfileInfo; using importer::SEARCH_ENGINES; using webkit_glue::PasswordForm; -void Firefox3Importer::StartImport(ProfileInfo profile_info, +void Firefox3Importer::StartImport(importer::ProfileInfo profile_info, uint16 items, ImporterBridge* bridge) { bridge_ = bridge; @@ -43,32 +43,32 @@ void Firefox3Importer::StartImport(ProfileInfo profile_info, // The order here is important! bridge_->NotifyStarted(); - if ((items & HOME_PAGE) && !cancelled()) + if ((items & importer::HOME_PAGE) && !cancelled()) ImportHomepage(); // Doesn't have a UI item. // Note history should be imported before bookmarks because bookmark import // will also import favicons and we store favicon for a URL only if the URL // exist in history or bookmarks. - if ((items & HISTORY) && !cancelled()) { - bridge_->NotifyItemStarted(HISTORY); + if ((items & importer::HISTORY) && !cancelled()) { + bridge_->NotifyItemStarted(importer::HISTORY); ImportHistory(); - bridge_->NotifyItemEnded(HISTORY); + bridge_->NotifyItemEnded(importer::HISTORY); } - if ((items & FAVORITES) && !cancelled()) { - bridge_->NotifyItemStarted(FAVORITES); + if ((items & importer::FAVORITES) && !cancelled()) { + bridge_->NotifyItemStarted(importer::FAVORITES); ImportBookmarks(); - bridge_->NotifyItemEnded(FAVORITES); + bridge_->NotifyItemEnded(importer::FAVORITES); } - if ((items & SEARCH_ENGINES) && !cancelled()) { - bridge_->NotifyItemStarted(SEARCH_ENGINES); + if ((items & importer::SEARCH_ENGINES) && !cancelled()) { + bridge_->NotifyItemStarted(importer::SEARCH_ENGINES); ImportSearchEngines(); - bridge_->NotifyItemEnded(SEARCH_ENGINES); + bridge_->NotifyItemEnded(importer::SEARCH_ENGINES); } - if ((items & PASSWORDS) && !cancelled()) { - bridge_->NotifyItemStarted(PASSWORDS); + if ((items & importer::PASSWORDS) && !cancelled()) { + bridge_->NotifyItemStarted(importer::PASSWORDS); ImportPasswords(); - bridge_->NotifyItemEnded(PASSWORDS); + bridge_->NotifyItemEnded(importer::PASSWORDS); } bridge_->NotifyEnded(); } @@ -177,7 +177,7 @@ void Firefox3Importer::ImportBookmarks() { } std::wstring firefox_folder = - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); + bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); for (size_t i = 0; i < list.size(); ++i) { BookmarkItem* item = list[i]; @@ -253,7 +253,7 @@ void Firefox3Importer::ImportBookmarks() { // Write into profile. if (!bookmarks.empty() && !cancelled()) { const std::wstring& first_folder_name = - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); + bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_FIREFOX); int options = 0; if (import_to_bookmark_bar()) options = ProfileWriter::IMPORT_TO_BOOKMARK_BAR; diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc index 3b660a1..aac856e 100644 --- a/chrome/browser/importer/importer.cc +++ b/chrome/browser/importer/importer.cc @@ -5,7 +5,6 @@ #include "chrome/browser/importer/importer.h" #include "app/l10n_util.h" -#include "base/string_util.h" #include "base/thread.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/browser_list.h" @@ -13,12 +12,10 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/importer/firefox_profile_lock.h" #include "chrome/browser/importer/importer_bridge.h" -#include "chrome/browser/pref_service.h" #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/notification_service.h" -#include "chrome/common/pref_names.h" #include "gfx/codec/png_codec.h" #include "gfx/favicon_size.h" #include "grit/generated_resources.h" @@ -171,7 +168,7 @@ void ImporterHost::StartImportSettings( // will be notified. writer_ = writer; importer_ = importer_list_.CreateImporterByType(profile_info.browser_type); - // If we fail to create Importer, exit as we can not do anything. + // If we fail to create Importer, exit as we cannot do anything. if (!importer_) { ImportEnded(); return; @@ -179,38 +176,13 @@ void ImporterHost::StartImportSettings( importer_->AddRef(); - bool import_to_bookmark_bar = first_run; - if (target_profile && target_profile->GetBookmarkModel()->IsLoaded()) { - std::vector<GURL> starred_urls; - target_profile->GetBookmarkModel()->GetBookmarks(&starred_urls); - import_to_bookmark_bar = (starred_urls.size() == 0); - } - importer_->set_import_to_bookmark_bar(import_to_bookmark_bar); + importer_->set_import_to_bookmark_bar(ShouldImportToBookmarkBar(first_run)); scoped_refptr<ImporterBridge> bridge( new InProcessImporterBridge(writer_.get(), this)); task_ = NewRunnableMethod(importer_, &Importer::StartImport, profile_info, items, bridge); - // We should lock the Firefox profile directory to prevent corruption. - if (profile_info.browser_type == importer::FIREFOX2 || - profile_info.browser_type == importer::FIREFOX3) { - firefox_lock_.reset(new FirefoxProfileLock(profile_info.source_path)); - if (!firefox_lock_->HasAcquired()) { - // If fail to acquire the lock, we set the source unreadable and - // show a warning dialog. - // However, if we're running without a UI (silently) and trying to - // import just the home page, then import anyway. The home page setting - // is stored in an unlocked text file, so it is the only preference safe - // to import even if Firefox is running. - if (items == importer::HOME_PAGE && first_run && this->headless_) { - AddRef(); - InvokeTaskIfDone(); - return; - } - is_source_readable_ = false; - ShowWarningDialog(); - } - } + CheckForFirefoxLock(profile_info, items, first_run); #if defined(OS_WIN) // For google toolbar import, we need the user to log in and store their GAIA @@ -238,26 +210,7 @@ void ImporterHost::StartImportSettings( } #endif - // BookmarkModel should be loaded before adding IE favorites. So we observe - // the BookmarkModel if needed, and start the task after it has been loaded. - if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { - target_profile->GetBookmarkModel()->AddObserver(this); - waiting_for_bookmarkbar_model_ = true; - installed_bookmark_observer_ = true; - } - - // Observes the TemplateURLModel if needed to import search engines from the - // other browser. We also check to see if we're importing bookmarks because - // we can import bookmark keywords from Firefox as search engines. - if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { - if (!writer_->TemplateURLModelIsLoaded()) { - TemplateURLModel* model = target_profile->GetTemplateURLModel(); - registrar_.Add(this, NotificationType::TEMPLATE_URL_MODEL_LOADED, - Source<TemplateURLModel>(model)); - model->Load(); - } - } - + CheckForLoadedModels(items); AddRef(); InvokeTaskIfDone(); } @@ -299,3 +252,335 @@ void ImporterHost::ImportEnded() { observer_->ImportEnded(); Release(); } + +bool ImporterHost::ShouldImportToBookmarkBar(bool first_run) { + bool import_to_bookmark_bar = first_run; + if (profile_ && profile_->GetBookmarkModel()->IsLoaded()) { + std::vector<GURL> starred_urls; + profile_->GetBookmarkModel()->GetBookmarks(&starred_urls); + import_to_bookmark_bar = (starred_urls.size() == 0); + } + return import_to_bookmark_bar; +} + +void ImporterHost::CheckForFirefoxLock( + const importer::ProfileInfo& profile_info, uint16 items, bool first_run) { + if (profile_info.browser_type == importer::FIREFOX2 || + profile_info.browser_type == importer::FIREFOX3) { + DCHECK(!firefox_lock_.get()); + firefox_lock_.reset(new FirefoxProfileLock(profile_info.source_path)); + if (!firefox_lock_->HasAcquired()) { + // If fail to acquire the lock, we set the source unreadable and + // show a warning dialog, unless running without UI. + is_source_readable_ = false; + if (!this->headless_) + ShowWarningDialog(); + } + } +} + +void ImporterHost::CheckForLoadedModels(uint16 items) { + // BookmarkModel should be loaded before adding IE favorites. So we observe + // the BookmarkModel if needed, and start the task after it has been loaded. + if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { + profile_->GetBookmarkModel()->AddObserver(this); + waiting_for_bookmarkbar_model_ = true; + installed_bookmark_observer_ = true; + } + + // Observes the TemplateURLModel if needed to import search engines from the + // other browser. We also check to see if we're importing bookmarks because + // we can import bookmark keywords from Firefox as search engines. + if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { + if (!writer_->TemplateURLModelIsLoaded()) { + TemplateURLModel* model = profile_->GetTemplateURLModel(); + registrar_.Add(this, NotificationType::TEMPLATE_URL_MODEL_LOADED, + Source<TemplateURLModel>(model)); + model->Load(); + } + } +} + +ExternalProcessImporterHost::ExternalProcessImporterHost() + : cancelled_(false), + import_process_launched_(false) { +} + +void ExternalProcessImporterHost::Loaded(BookmarkModel* model) { + DCHECK(model->IsLoaded()); + model->RemoveObserver(this); + waiting_for_bookmarkbar_model_ = false; + installed_bookmark_observer_ = false; + + std::vector<GURL> starred_urls; + model->GetBookmarks(&starred_urls); + // Because the import process is running externally, the decision whether + // to import to the bookmark bar must be stored here so that it can be + // passed to the importer when the import task is invoked. + import_to_bookmark_bar_ = (starred_urls.size() == 0); + InvokeTaskIfDone(); +} + +void ExternalProcessImporterHost::Cancel() { + cancelled_ = true; + if (import_process_launched_) + client_->Cancel(); + ImportEnded(); // Tells the observer that we're done, and releases us. +} + +void ExternalProcessImporterHost::StartImportSettings( + const importer::ProfileInfo& profile_info, + Profile* target_profile, + uint16 items, + ProfileWriter* writer, + bool first_run) { + DCHECK(!profile_); + profile_ = target_profile; + writer_ = writer; + profile_info_ = &profile_info; + items_ = items; + + import_to_bookmark_bar_ = ShouldImportToBookmarkBar(first_run); + CheckForFirefoxLock(profile_info, items, first_run); + CheckForLoadedModels(items); + + ImporterHost::AddRef(); // Balanced in ImporterHost::ImportEnded. + InvokeTaskIfDone(); +} + +void ExternalProcessImporterHost::InvokeTaskIfDone() { + if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() || + !is_source_readable_ || cancelled_) + return; + + // The in-process half of the bridge which catches data from the IPC pipe + // and feeds it to the ProfileWriter. The external process half of the + // bridge lives in the external process -- see ProfileImportThread. + // The ExternalProcessImporterClient created in the next line owns this + // bridge, and will delete it. + InProcessImporterBridge* bridge = + new InProcessImporterBridge(writer_.get(), this); + client_ = new ExternalProcessImporterClient(this, *profile_info_, items_, + bridge, import_to_bookmark_bar_); + import_process_launched_ = true; + client_->Start(); +} + +ExternalProcessImporterClient::ExternalProcessImporterClient( + ExternalProcessImporterHost* importer_host, + const importer::ProfileInfo& profile_info, + int items, + InProcessImporterBridge* bridge, + bool import_to_bookmark_bar) + : process_importer_host_(importer_host), + profile_info_(profile_info), + items_(items), + import_to_bookmark_bar_(import_to_bookmark_bar), + bridge_(bridge), + cancelled_(FALSE) { + bridge_->AddRef(); + process_importer_host_->ImportStarted(); +} + +ExternalProcessImporterClient::~ExternalProcessImporterClient() { + bridge_->Release(); +} + +void ExternalProcessImporterClient::Start() { + AddRef(); // balanced in Cleanup. + ChromeThread::ID thread_id; + CHECK(ChromeThread::GetCurrentThreadIdentifier(&thread_id)); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &ExternalProcessImporterClient::StartProcessOnIOThread, + g_browser_process->resource_dispatcher_host(), thread_id)); +} + +void ExternalProcessImporterClient::StartProcessOnIOThread( + ResourceDispatcherHost* rdh, + ChromeThread::ID thread_id) { + profile_import_process_host_ = + new ProfileImportProcessHost(rdh, this, thread_id); + profile_import_process_host_->StartProfileImportProcess(profile_info_, + items_, import_to_bookmark_bar_); +} + +void ExternalProcessImporterClient::Cancel() { + if (cancelled_) + return; + + cancelled_ = true; + if (profile_import_process_host_) { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &ExternalProcessImporterClient::CancelImportProcessOnIOThread)); + } + Release(); +} + +void ExternalProcessImporterClient::CancelImportProcessOnIOThread() { + profile_import_process_host_->CancelProfileImportProcess(); +} + +void ExternalProcessImporterClient::NotifyItemFinishedOnIOThread( + importer::ImportItem import_item) { + profile_import_process_host_->ReportImportItemFinished(import_item); +} + +void ExternalProcessImporterClient::OnProcessCrashed() { + if (cancelled_) + return; + + process_importer_host_->Cancel(); +} + +void ExternalProcessImporterClient::Cleanup() { + if (cancelled_) + return; + + if (process_importer_host_) + process_importer_host_->ImportEnded(); + Release(); +} + +void ExternalProcessImporterClient::OnImportStart() { + if (cancelled_) + return; + + bridge_->NotifyStarted(); +} + +void ExternalProcessImporterClient::OnImportFinished(bool succeeded, + std::string error_msg) { + if (cancelled_) + return; + + if (!succeeded) + LOG(WARNING) << "Import failed. Error: " << error_msg; + Cleanup(); +} + +void ExternalProcessImporterClient::OnImportItemStart(int item_data) { + if (cancelled_) + return; + + bridge_->NotifyItemStarted(static_cast<importer::ImportItem>(item_data)); +} + +void ExternalProcessImporterClient::OnImportItemFinished(int item_data) { + if (cancelled_) + return; + + importer::ImportItem import_item = + static_cast<importer::ImportItem>(item_data); + bridge_->NotifyItemEnded(import_item); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &ExternalProcessImporterClient::NotifyItemFinishedOnIOThread, + import_item)); +} + +void ExternalProcessImporterClient::OnHistoryImportStart( + size_t total_history_rows_count) { + if (cancelled_) + return; + + total_history_rows_count_ = total_history_rows_count; + history_rows_.reserve(total_history_rows_count); +} + +void ExternalProcessImporterClient::OnHistoryImportGroup( + const std::vector<history::URLRow> &history_rows_group) { + if (cancelled_) + return; + + history_rows_.insert(history_rows_.end(), history_rows_group.begin(), + history_rows_group.end()); + if (history_rows_.size() == total_history_rows_count_) + bridge_->SetHistoryItems(history_rows_); +} + +void ExternalProcessImporterClient::OnHomePageImportReady( + const GURL& home_page) { + if (cancelled_) + return; + + bridge_->AddHomePage(home_page); +} + +void ExternalProcessImporterClient::OnBookmarksImportStart( + const std::wstring first_folder_name, + int options, size_t total_bookmarks_count) { + if (cancelled_) + return; + + bookmarks_first_folder_name_ = first_folder_name; + bookmarks_options_ = options; + total_bookmarks_count_ = total_bookmarks_count; + bookmarks_.reserve(total_bookmarks_count); +} + +void ExternalProcessImporterClient::OnBookmarksImportGroup( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks_group) { + if (cancelled_) + return; + + // Collect sets of bookmarks from importer process until we have reached + // total_bookmarks_count_: + bookmarks_.insert(bookmarks_.end(), bookmarks_group.begin(), + bookmarks_group.end()); + if (bookmarks_.size() == total_bookmarks_count_) { + bridge_->AddBookmarkEntries(bookmarks_, bookmarks_first_folder_name_, + bookmarks_options_); + } +} + +void ExternalProcessImporterClient::OnFavIconsImportStart( + size_t total_fav_icons_count) { + if (cancelled_) + return; + + total_fav_icons_count_ = total_fav_icons_count; + fav_icons_.reserve(total_fav_icons_count); +} + +void ExternalProcessImporterClient::OnFavIconsImportGroup( + const std::vector<history::ImportedFavIconUsage>& fav_icons_group) { + if (cancelled_) + return; + + fav_icons_.insert(fav_icons_.end(), fav_icons_group.begin(), + fav_icons_group.end()); + if (fav_icons_.size() == total_fav_icons_count_) + bridge_->SetFavIcons(fav_icons_); +} + +void ExternalProcessImporterClient::OnPasswordFormImportReady( + const webkit_glue::PasswordForm& form) { + if (cancelled_) + return; + + bridge_->SetPasswordForm(form); +} + +void ExternalProcessImporterClient::OnKeywordsImportReady( + const std::vector<TemplateURL>& template_urls, + int default_keyword_index, bool unique_on_host_and_path) { + if (cancelled_) + return; + + std::vector<TemplateURL*> template_url_vec; + template_url_vec.reserve(template_urls.size()); + std::vector<TemplateURL>::const_iterator iter; + for (iter = template_urls.begin(); + iter != template_urls.end(); + ++iter) { + template_url_vec.push_back(new TemplateURL(*iter)); + } + bridge_->SetKeywords(template_url_vec, default_keyword_index, + unique_on_host_and_path); +} + diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h index d0ea428..a6c34ce 100644 --- a/chrome/browser/importer/importer.h +++ b/chrome/browser/importer/importer.h @@ -15,9 +15,11 @@ #include "base/scoped_ptr.h" #include "base/time.h" #include "chrome/browser/bookmarks/bookmark_model_observer.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/importer/importer_list.h" #include "chrome/browser/importer/profile_writer.h" +#include "chrome/browser/profile_import_process_host.h" #include "chrome/common/notification_registrar.h" #include "gfx/native_widget_types.h" #include "googleurl/src/gurl.h" @@ -25,7 +27,9 @@ using importer::ImportItem; using importer::ProfileInfo; +class ExternalProcessImporterClient; class ImporterBridge; +class InProcessImporterBridge; class Profile; class Task; class TemplateURL; @@ -88,16 +92,21 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>, // button. |is_continue| is true when user clicked the "Continue" button. void OnLockViewEnd(bool is_continue); - // Starts the process of importing the settings and data depending - // on what the user selected. - void StartImportSettings(const ProfileInfo& profile_info, - Profile* target_profile, - uint16 items, - ProfileWriter* writer, - bool first_run); - - // Cancel - void Cancel(); + // Starts the process of importing the settings and data depending on what + // the user selected. + // |profile_info| -- browser profile to import. + // |target_profile| -- profile to import into. + // |items| -- specifies which data to import (mask of ImportItems). + // |writer| -- called to actually write data back to the profile. + // |first_run| -- true if this method is being called during first run. + virtual void StartImportSettings(const importer::ProfileInfo& profile_info, + Profile* target_profile, + uint16 items, + ProfileWriter* writer, + bool first_run); + + // Cancel import. + virtual void Cancel(); // When in headless mode, the importer will not show the warning dialog and // the outcome is as if the user had canceled the import operation. @@ -119,11 +128,11 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>, public: virtual ~Observer() {} // Invoked when data for the specified item is about to be collected. - virtual void ImportItemStarted(ImportItem item) = 0; + virtual void ImportItemStarted(importer::ImportItem item) = 0; // Invoked when data for the specified item has been collected from the // source profile and is now ready for further processing. - virtual void ImportItemEnded(ImportItem item) = 0; + virtual void ImportItemEnded(importer::ImportItem item) = 0; // Invoked when the import begins. virtual void ImportStarted() = 0; @@ -137,16 +146,16 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>, // of the import process. The middle functions are notifications that the // harvesting of a particular source of data (specified by |item|) is under // way. - void ImportStarted(); - void ImportItemStarted(ImportItem item); - void ImportItemEnded(ImportItem item); - void ImportEnded(); + virtual void ImportStarted(); + virtual void ImportItemStarted(importer::ImportItem item); + virtual void ImportItemEnded(importer::ImportItem item); + virtual void ImportEnded(); int GetAvailableProfileCount() const { - return importer_list_.GetAvailableProfileCount(); + return importer_list_.GetAvailableProfileCount(); } - // Returns the name of the profile at the 'index' slot. The profiles are + // Returns the name of the profile at the 'index' slot. The profiles are // ordered such that the profile at index 0 is the likely default browser. std::wstring GetSourceProfileNameAt(int index) const { return importer_list_.GetSourceProfileNameAt(index); @@ -154,40 +163,54 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>, // Returns the ProfileInfo at the specified index. The ProfileInfo should be // passed to StartImportSettings(). - const ProfileInfo& GetSourceProfileInfoAt(int index) const { + const importer::ProfileInfo& GetSourceProfileInfoAt(int index) const { return importer_list_.GetSourceProfileInfoAt(index); } // Returns the ProfileInfo with the given browser type. - const ProfileInfo& GetSourceProfileInfoForBrowserType( + const importer::ProfileInfo& GetSourceProfileInfoForBrowserType( int browser_type) const { return importer_list_.GetSourceProfileInfoForBrowserType(browser_type); } - - private: + protected: friend class base::RefCountedThreadSafe<ImporterHost>; ~ImporterHost(); - // If we're not waiting on any model to finish loading, invokes the task_. - void InvokeTaskIfDone(); + // Returns true if importer should import to bookmark bar. + bool ShouldImportToBookmarkBar(bool first_run); - NotificationRegistrar registrar_; - ImporterList importer_list_; + // Make sure that Firefox isn't running, if import browser is Firefox. Show + // the user a dialog to notify that they need to close FF to continue. + // |profile_info| holds the browser type and source path. + // |items| is a mask of all ImportItems that are to be imported. + // |first_run| is true if this method is being called during first run. + void CheckForFirefoxLock(const importer::ProfileInfo& profile_info, + uint16 items, bool first_run); + + // Make sure BookmarkModel and TemplateURLModel are loaded before import + // process starts, if bookmarks and / or search engines are among the items + // which are to be imported. + void CheckForLoadedModels(uint16 items); // Profile we're importing from. Profile* profile_; Observer* observer_; - scoped_refptr<ProfileWriter> writer_; + // TODO(mirandac): task_ and importer_ should be private. Can't just put + // them there without changing the order of construct/destruct, so do this + // after main CL has been committed. // The task is the process of importing settings from other browsers. Task* task_; // The importer used in the task; Importer* importer_; + // Writes data from the importer back to the profile. + scoped_refptr<ProfileWriter> writer_; + // True if we're waiting for the model to finish loading. bool waiting_for_bookmarkbar_model_; @@ -200,15 +223,214 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>, // True if UI is not to be shown. bool headless_; + // Receives notification when the TemplateURLModel has loaded. + NotificationRegistrar registrar_; + // Parent Window to use when showing any modal dialog boxes. gfx::NativeWindow parent_window_; // Firefox profile lock. scoped_ptr<FirefoxProfileLock> firefox_lock_; + private: + // Launches the thread that starts the import task, unless bookmark or + // template model are not yet loaded. If load is not detected, this method + // will be called when the loading observer sees that model loading is + // complete. + virtual void InvokeTaskIfDone(); + + // Used to create an importer of the appropriate type. + ImporterList importer_list_; + DISALLOW_COPY_AND_ASSIGN(ImporterHost); }; +// This class manages the import process. It creates the in-process half of +// the importer bridge and the external process importer client. +class ExternalProcessImporterHost : public ImporterHost { + public: + ExternalProcessImporterHost(); + + // Called when the BookmarkModel has finished loading. Calls InvokeTaskIfDone + // to start importing. + virtual void Loaded(BookmarkModel* model); + + // Methods inherited from ImporterHost. + virtual void StartImportSettings(const importer::ProfileInfo& profile_info, + Profile* target_profile, + uint16 items, + ProfileWriter* writer, + bool first_run); + + virtual void Cancel(); + + protected: + // Launches the ExternalProcessImporterClient unless bookmark or template + // model are not yet loaded. If load is not detected, this method will be + // called when the loading observer sees that model loading is complete. + virtual void InvokeTaskIfDone(); + + private: + // Used to pass notifications from the browser side to the external process. + ExternalProcessImporterClient* client_; + + // Data for the external importer: ------------------------------------------ + // Information about a profile needed for importing. + const importer::ProfileInfo* profile_info_; + + // Mask of items to be imported (see importer::ImportItem). + uint16 items_; + + // Whether to import bookmarks to the bookmark bar. + bool import_to_bookmark_bar_; + + // True if the import process has been cancelled. + bool cancelled_; + + // True if the import process has been launched. This prevents race + // conditions on import cancel. + bool import_process_launched_; + + // End of external importer data -------------------------------------------- + + DISALLOW_COPY_AND_ASSIGN(ExternalProcessImporterHost); +}; + +// This class is the client for the ProfileImportProcessHost. It collects +// notifications from this process host and feeds data back to the importer +// host, who actually does the writing. +class ExternalProcessImporterClient + : public ProfileImportProcessHost::ImportProcessClient { + public: + ExternalProcessImporterClient(ExternalProcessImporterHost* importer_host, + const importer::ProfileInfo& profile_info, + int items, + InProcessImporterBridge* bridge, + bool import_to_bookmark_bar); + + ~ExternalProcessImporterClient(); + + // Launches the task to start the external process. + virtual void Start(); + + // Creates a new ProfileImportProcessHost, which launches the import process. + virtual void StartProcessOnIOThread(ResourceDispatcherHost* rdh, + ChromeThread::ID thread_id); + + // Called by the ExternalProcessImporterHost on import cancel. + virtual void Cancel(); + + // Cancel import process on IO thread. + void CancelImportProcessOnIOThread(); + + // Report item completely downloaded on IO thread. + void NotifyItemFinishedOnIOThread(importer::ImportItem import_item); + + // Cancel import on process crash. + virtual void OnProcessCrashed(); + + // Notifies the importerhost that import has finished, and calls Release(). + void Cleanup(); + + // ProfileImportProcessHost messages ---------------------------------------- + // The following methods are called by ProfileImportProcessHost when the + // corresponding message has been received from the import process. + virtual void OnImportStart(); + virtual void OnImportFinished(bool succeeded, std::string error_msg); + virtual void OnImportItemStart(int item_data); + virtual void OnImportItemFinished(int item_data); + + // Called on first message received when importing history; gives total + // number of rows to be imported. + virtual void OnHistoryImportStart(size_t total_history_rows_count); + + // Called when a group of URLRows has been received. + virtual void OnHistoryImportGroup( + const std::vector<history::URLRow> &history_rows_group); + + // Called when the home page has been received. + virtual void OnHomePageImportReady(const GURL& home_page); + + // First message received when importing bookmarks. + // |first_folder_name| can be NULL. + // |options| is described in ProfileWriter::BookmarkOptions. + // |total_bookmarks_count| is the total number of bookmarks to be imported. + virtual void OnBookmarksImportStart( + const std::wstring first_folder_name, + int options, size_t total_bookmarks_count); + + // Called when a group of bookmarks has been received. + virtual void OnBookmarksImportGroup( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks_group); + + // First message received when importing favicons. |total_fav_icons_size| + // gives the total number of fav icons to be imported. + virtual void OnFavIconsImportStart(size_t total_fav_icons_count); + + // Called when a group of favicons has been received. + virtual void OnFavIconsImportGroup( + const std::vector<history::ImportedFavIconUsage>& fav_icons_group); + + // Called when the passwordform has been received. + virtual void OnPasswordFormImportReady( + const webkit_glue::PasswordForm& form); + + // Called when search engines have been received. + virtual void OnKeywordsImportReady( + const std::vector<TemplateURL>& template_urls, + int default_keyword_index, bool unique_on_host_and_path); + + // End ProfileImportProcessHost messages ------------------------------------ + + private: + // These variables store data being collected from the importer until the + // entire group has been collected and is ready to be written to the profile. + std::vector<history::URLRow> history_rows_; + std::vector<ProfileWriter::BookmarkEntry> bookmarks_; + std::vector<history::ImportedFavIconUsage> fav_icons_; + + // Usually some variation on IDS_BOOKMARK_GROUP_...; the name of the folder + // under which imported bookmarks will be placed. + std::wstring bookmarks_first_folder_name_; + + // Determines how bookmarks should be added (ProfileWriter::BookmarkOptions). + int bookmarks_options_; + + // Total number of bookmarks to import. + size_t total_bookmarks_count_; + + // Total number of history items to import. + size_t total_history_rows_count_; + + // Total number of fav icons to import. + size_t total_fav_icons_count_; + + // Notifications received from the ProfileImportProcessHost are passed back + // to process_importer_host_, which calls the ProfileWriter to record the + // import data. When the import process is done, process_importer_host_ + // deletes itself. + ExternalProcessImporterHost* process_importer_host_; + + // Handles sending messages to the external process. Deletes itself when + // the external process dies (see ChildProcessHost::OnChildDied). + ProfileImportProcessHost* profile_import_process_host_; + + // Data to be passed from the importer host to the external importer. + const importer::ProfileInfo& profile_info_; + int items_; + bool import_to_bookmark_bar_; + + // Takes import data coming over IPC and delivers it to be written by the + // ProfileWriter. Released by ExternalProcessImporterClient in its + // destructor. + InProcessImporterBridge* bridge_; + + // True if import process has been cancelled. + bool cancelled_; + + DISALLOW_COPY_AND_ASSIGN(ExternalProcessImporterClient); +}; + // The base class of all importers. class Importer : public base::RefCountedThreadSafe<Importer> { public: @@ -218,7 +440,7 @@ class Importer : public base::RefCountedThreadSafe<Importer> { // Since we do async import, the importer should invoke // ImporterHost::Finished() to notify its host that import // stuff have been finished. - virtual void StartImport(ProfileInfo profile_info, + virtual void StartImport(importer::ProfileInfo profile_info, uint16 items, ImporterBridge* bridge) = 0; @@ -279,7 +501,7 @@ class ImportObserver { void StartImportingWithUI(gfx::NativeWindow parent_window, int16 items, ImporterHost* coordinator, - const ProfileInfo& source_profile, + const importer::ProfileInfo& source_profile, Profile* target_profile, ImportObserver* observer, bool first_run); diff --git a/chrome/browser/importer/importer_bridge.cc b/chrome/browser/importer/importer_bridge.cc index 782f12b..2a913d2 100644 --- a/chrome/browser/importer/importer_bridge.cc +++ b/chrome/browser/importer/importer_bridge.cc @@ -4,17 +4,23 @@ #include "chrome/browser/importer/importer_bridge.h" +#include "app/l10n_util.h" +#include "base/scoped_ptr.h" +#include "base/values.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/importer/importer.h" #if defined(OS_WIN) #include "chrome/browser/password_manager/ie7_password.h" #endif +#include "chrome/common/child_thread.h" +#include "chrome/browser/importer/importer_messages.h" +#include "chrome/profile_import/profile_import_thread.h" #include "webkit/glue/password_form.h" InProcessImporterBridge::InProcessImporterBridge(ProfileWriter* writer, ImporterHost* host) - : ImporterBridge(writer, host) { + : writer_(writer), host_(host) { } void InProcessImporterBridge::AddBookmarkEntries( @@ -29,7 +35,7 @@ void InProcessImporterBridge::AddBookmarkEntries( } void InProcessImporterBridge::AddHomePage(const GURL &home_page) { - ChromeThread::PostTask( + ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, NewRunnableMethod(writer_, &ProfileWriter::AddHomepage, home_page)); } @@ -99,3 +105,83 @@ void InProcessImporterBridge::NotifyEnded() { ChromeThread::UI, FROM_HERE, NewRunnableMethod(host_, &ImporterHost::ImportEnded)); } + +std::wstring InProcessImporterBridge::GetLocalizedString(int message_id) { + return l10n_util::GetString(message_id); +} + +ExternalProcessImporterBridge::ExternalProcessImporterBridge( + ProfileImportThread* profile_import_thread, + const DictionaryValue& localized_strings) + : profile_import_thread_(profile_import_thread), + localized_strings_(localized_strings) { +} + +void ExternalProcessImporterBridge::AddBookmarkEntries( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, + const std::wstring& first_folder_name, int options) { + profile_import_thread_->NotifyBookmarksImportReady(bookmarks, + first_folder_name, options); +} + +void ExternalProcessImporterBridge::AddHomePage(const GURL &home_page) { + // TODO(mirandac): remove home page import from code base. + // http://crbug.com/45678 :-) + NOTIMPLEMENTED(); +} + +#if defined(OS_WIN) +void ExternalProcessImporterBridge::AddIE7PasswordInfo( + const IE7PasswordInfo password_info) { + NOTIMPLEMENTED(); +} +#endif + +void ExternalProcessImporterBridge::SetFavIcons( + const std::vector<history::ImportedFavIconUsage>& fav_icons) { + profile_import_thread_->NotifyFavIconsImportReady(fav_icons); +} + +void ExternalProcessImporterBridge::SetHistoryItems( + const std::vector<history::URLRow> &rows) { + profile_import_thread_->NotifyHistoryImportReady(rows); +} + +void ExternalProcessImporterBridge::SetKeywords( + const std::vector<TemplateURL*>& template_urls, + int default_keyword_index, + bool unique_on_host_and_path) { + profile_import_thread_->NotifyKeywordsReady(template_urls, + default_keyword_index, unique_on_host_and_path); +} + +void ExternalProcessImporterBridge::SetPasswordForm( + const webkit_glue::PasswordForm& form) { + // TODO(mirandac): http://crbug.com/18775 + NOTIMPLEMENTED(); +} + +void ExternalProcessImporterBridge::NotifyItemStarted( + importer::ImportItem item) { + profile_import_thread_->NotifyItemStarted(item); +} + +void ExternalProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) { + profile_import_thread_->NotifyItemEnded(item); +} + +void ExternalProcessImporterBridge::NotifyStarted() { + profile_import_thread_->NotifyStarted(); +} + +void ExternalProcessImporterBridge::NotifyEnded() { + // The internal process detects import end when all items have been received. +} + +std::wstring ExternalProcessImporterBridge::GetLocalizedString( + int message_id) { + std::wstring message; + localized_strings_.GetString(IntToWString(message_id), &message); + return message; +} + diff --git a/chrome/browser/importer/importer_bridge.h b/chrome/browser/importer/importer_bridge.h index 14025e6..c6358da 100644 --- a/chrome/browser/importer/importer_bridge.h +++ b/chrome/browser/importer/importer_bridge.h @@ -10,20 +10,20 @@ #include <vector> #include "base/basictypes.h" +#include "base/ref_counted.h" #include "base/string16.h" - -#include "chrome/browser/importer/importer.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/importer/importer_data_types.h" // TODO: remove this, see friend declaration in ImporterBridge. #include "chrome/browser/importer/toolbar_importer.h" +class ProfileImportThread; +class DictionaryValue; +class ImporterHost; + class ImporterBridge : public base::RefCountedThreadSafe<ImporterBridge> { public: - ImporterBridge(ProfileWriter* writer, - ImporterHost* host) - : writer_(writer), - host_(host) { - } + ImporterBridge() { } virtual void AddBookmarkEntries( const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, @@ -57,6 +57,12 @@ class ImporterBridge : public base::RefCountedThreadSafe<ImporterBridge> { // Notifies the coordinator that the entire import operation has completed. virtual void NotifyEnded() = 0; + // For InProcessImporters this calls l10n_util. For ExternalProcessImporters + // this calls the set of strings we've ported over to the external process. + // It's good to avoid having to create a separate ResourceBundle for the + // external import process, since the importer only needs a few strings. + virtual std::wstring GetLocalizedString(int message_id) = 0; + protected: friend class base::RefCountedThreadSafe<ImporterBridge>; // TODO: In order to run Toolbar5Importer OOP we need to cut this @@ -66,9 +72,6 @@ class ImporterBridge : public base::RefCountedThreadSafe<ImporterBridge> { virtual ~ImporterBridge() {} - ProfileWriter* writer_; - ImporterHost* host_; - DISALLOW_COPY_AND_ASSIGN(ImporterBridge); }; @@ -77,7 +80,8 @@ class InProcessImporterBridge : public ImporterBridge { InProcessImporterBridge(ProfileWriter* writer, ImporterHost* host); - // Methods inherited from ImporterBridge. + // Methods inherited from ImporterBridge. On the internal side, these + // methods launch tasks to write the data to the profile with the |writer_|. virtual void AddBookmarkEntries( const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, const std::wstring& first_folder_name, @@ -89,7 +93,7 @@ class InProcessImporterBridge : public ImporterBridge { #endif virtual void SetFavIcons( - const std::vector<history::ImportedFavIconUsage>& fav_icons); + const std::vector<history::ImportedFavIconUsage>& fav_icons); virtual void SetHistoryItems(const std::vector<history::URLRow> &rows); virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls, int default_keyword_index, @@ -100,11 +104,64 @@ class InProcessImporterBridge : public ImporterBridge { virtual void NotifyItemEnded(importer::ImportItem item); virtual void NotifyStarted(); virtual void NotifyEnded(); + virtual std::wstring GetLocalizedString(int message_id); private: ~InProcessImporterBridge() {} + ProfileWriter* const writer_; // weak + ImporterHost* const host_; // weak + DISALLOW_COPY_AND_ASSIGN(InProcessImporterBridge); }; +// When the importer is run in an external process, the bridge is effectively +// split in half by the IPC infrastructure. The external bridge receives data +// and notifications from the importer, and sends it across IPC. The +// internal bridge gathers the data from the IPC host and writes it to the +// profile. +class ExternalProcessImporterBridge : public ImporterBridge { + public: + ExternalProcessImporterBridge(ProfileImportThread* profile_import_thread, + const DictionaryValue& localized_strings); + + // Methods inherited from ImporterBridge. On the external side, these + // methods gather data and give it to a ProfileImportThread to pass back + // to the browser process. + virtual void AddBookmarkEntries( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, + const std::wstring& first_folder_name, int options); + virtual void AddHomePage(const GURL &home_page); + +#if defined(OS_WIN) + virtual void AddIE7PasswordInfo(const IE7PasswordInfo password_info); +#endif + + virtual void SetFavIcons( + const std::vector<history::ImportedFavIconUsage>& fav_icons); + virtual void SetHistoryItems(const std::vector<history::URLRow> &rows); + virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls, + int default_keyword_index, + bool unique_on_host_and_path); + virtual void SetPasswordForm(const webkit_glue::PasswordForm& form); + + virtual void NotifyItemStarted(importer::ImportItem item); + virtual void NotifyItemEnded(importer::ImportItem item); + virtual void NotifyStarted(); + virtual void NotifyEnded(); + virtual std::wstring GetLocalizedString(int message_id); + + private: + ~ExternalProcessImporterBridge() {} + + // Call back to send data and messages across IPC. + ProfileImportThread* const profile_import_thread_; + + // Holds strings needed by the external importer because the resource + // bundle isn't available to the external process. + const DictionaryValue& localized_strings_; + + DISALLOW_COPY_AND_ASSIGN(ExternalProcessImporterBridge); +}; + #endif // CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_ diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc index 2fdd559..0919489 100644 --- a/chrome/browser/importer/importer_list.cc +++ b/chrome/browser/importer/importer_list.cc @@ -153,7 +153,7 @@ void ImporterList::DetectFirefoxProfiles() { if (firefox->app_path.empty()) firefox->app_path = app_path; firefox->services_supported = importer::HISTORY | importer::FAVORITES | - importer::COOKIES | importer::PASSWORDS | importer::SEARCH_ENGINES; + importer::PASSWORDS | importer::SEARCH_ENGINES; source_profiles_.push_back(firefox); } diff --git a/chrome/browser/importer/importer_messages.h b/chrome/browser/importer/importer_messages.h new file mode 100644 index 0000000..0ed8002 --- /dev/null +++ b/chrome/browser/importer/importer_messages.h @@ -0,0 +1,369 @@ +// 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. + +#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_ +#define CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/importer/profile_writer.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/common/common_param_traits.h" +#include "ipc/ipc_message_utils.h" + +namespace IPC { + +// Traits for importer::ProfileInfo struct to pack/unpack. +template <> +struct ParamTraits<importer::ProfileInfo> { + typedef importer::ProfileInfo param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.description); + WriteParam(m, static_cast<int>(p.browser_type)); + WriteParam(m, p.source_path); + WriteParam(m, p.app_path); + WriteParam(m, static_cast<int>(p.services_supported)); + } + static bool Read(const Message* m, void** iter, param_type* p) { + if (!ReadParam(m, iter, &p->description)) + return false; + + int browser_type = 0; + if (!ReadParam(m, iter, &browser_type)) + return false; + p->browser_type = static_cast<importer::ProfileType>(browser_type); + + if (!ReadParam(m, iter, &p->source_path) || + !ReadParam(m, iter, &p->app_path)) + return false; + + int services_supported = 0; + if (!ReadParam(m, iter, &services_supported)) + return false; + p->services_supported = static_cast<uint16>(services_supported); + + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.description, l); + l->append(L", "); + LogParam(static_cast<int>(p.browser_type), l); + l->append(L", "); + LogParam(p.source_path, l); + l->append(L", "); + LogParam(p.app_path, l); + l->append(L", "); + LogParam(static_cast<int>(p.services_supported), l); + l->append(L")"); + } +}; // ParamTraits<importer::ProfileInfo> + +// Traits for history::URLRow to pack/unpack. +template <> +struct ParamTraits<history::URLRow> { + typedef history::URLRow param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.id()); + WriteParam(m, p.url()); + WriteParam(m, p.title()); + WriteParam(m, p.visit_count()); + WriteParam(m, p.typed_count()); + WriteParam(m, p.last_visit()); + WriteParam(m, p.hidden()); + WriteParam(m, p.favicon_id()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + history::URLID id; + GURL url; + std::wstring title; + int visit_count, typed_count; + base::Time last_visit; + bool hidden; + history::FavIconID favicon_id; + if (!ReadParam(m, iter, &id) || + !ReadParam(m, iter, &url) || + !ReadParam(m, iter, &title) || + !ReadParam(m, iter, &visit_count) || + !ReadParam(m, iter, &typed_count) || + !ReadParam(m, iter, &last_visit) || + !ReadParam(m, iter, &hidden) || + !ReadParam(m, iter, &favicon_id)) + return false; + *p = history::URLRow(url, id); + p->set_title(title); + p->set_visit_count(visit_count); + p->set_typed_count(typed_count); + p->set_last_visit(last_visit); + p->set_hidden(hidden); + p->set_favicon_id(favicon_id); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.id(), l); + l->append(L", "); + LogParam(p.url(), l); + l->append(L", "); + LogParam(p.title(), l); + l->append(L", "); + LogParam(p.visit_count(), l); + l->append(L", "); + LogParam(p.typed_count(), l); + l->append(L", "); + LogParam(p.last_visit(), l); + l->append(L", "); + LogParam(p.hidden(), l); + l->append(L", "); + LogParam(p.favicon_id(), l); + l->append(L")"); + } +}; // ParamTraits<history::URLRow> + +// Traits for ProfileWriter::BookmarkEntry to pack/unpack. +template <> +struct ParamTraits<ProfileWriter::BookmarkEntry> { + typedef ProfileWriter::BookmarkEntry param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.in_toolbar); + WriteParam(m, p.url); + WriteParam(m, p.path); + WriteParam(m, p.title); + WriteParam(m, p.creation_time); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + (ReadParam(m, iter, &p->in_toolbar)) && + (ReadParam(m, iter, &p->url)) && + (ReadParam(m, iter, &p->path)) && + (ReadParam(m, iter, &p->title)) && + (ReadParam(m, iter, &p->creation_time)); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.in_toolbar, l); + l->append(L", "); + LogParam(p.url, l); + l->append(L", "); + LogParam(p.path, l); + l->append(L", "); + LogParam(p.title, l); + l->append(L", "); + LogParam(p.creation_time, l); + l->append(L")"); + } +}; // ParamTraits<ProfileWriter::BookmarkEntry> + +// Traits for history::ImportedFavIconUsage. +template <> +struct ParamTraits<history::ImportedFavIconUsage> { + typedef history::ImportedFavIconUsage param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.favicon_url); + WriteParam(m, p.png_data); + WriteParam(m, p.urls); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->favicon_url) && + ReadParam(m, iter, &p->png_data) && + ReadParam(m, iter, &p->urls); + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"("); + LogParam(p.favicon_url, l); + l->append(L", "); + LogParam(p.png_data, l); + l->append(L", "); + LogParam(p.urls, l); + l->append(L")"); + } +}; // ParamTraits<history::ImportedFavIconUsage + +// Traits for TemplateURLRef +template <> +struct ParamTraits<TemplateURLRef> { + typedef TemplateURLRef param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.url()); + WriteParam(m, p.index_offset()); + WriteParam(m, p.page_offset()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + std::wstring url; + int index_offset; + int page_offset; + if (!ReadParam(m, iter, &url) || + !ReadParam(m, iter, &index_offset) || + !ReadParam(m, iter, &page_offset)) + return false; + *p = TemplateURLRef(url, index_offset, page_offset); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<TemplateURLRef>"); + } +}; + +// Traits for TemplateURL::ImageRef +template <> +struct ParamTraits<TemplateURL::ImageRef> { + typedef TemplateURL::ImageRef param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.type); + WriteParam(m, p.width); + WriteParam(m, p.height); + WriteParam(m, p.url); + } + static bool Read(const Message* m, void** iter, param_type* p) { + std::wstring type; + int width; + int height; + GURL url; + if (!ReadParam(m, iter, &type) || + !ReadParam(m, iter, &width) || + !ReadParam(m, iter, &height) || + !ReadParam(m, iter, &url)) + return false; + *p = TemplateURL::ImageRef(type, width, height, url); // here in + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<TemplateURL::ImageRef>"); + } +}; + +// Traits for TemplateURL +template <> +struct ParamTraits<TemplateURL> { + typedef TemplateURL param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.short_name()); + WriteParam(m, p.description()); + if (p.suggestions_url()) { + WriteParam(m, true); + WriteParam(m, *p.suggestions_url()); + } else { + WriteParam(m, false); + } + WriteParam(m, *p.url()); + WriteParam(m, p.originating_url()); + WriteParam(m, p.keyword()); + WriteParam(m, p.autogenerate_keyword()); + WriteParam(m, p.show_in_default_list()); + WriteParam(m, p.safe_for_autoreplace()); + WriteParam(m, p.image_refs().size()); + + std::vector<TemplateURL::ImageRef>::const_iterator iter; + for (iter = p.image_refs().begin(); iter != p.image_refs().end(); ++iter) { + WriteParam(m, iter->type); + WriteParam(m, iter->width); + WriteParam(m, iter->height); + WriteParam(m, iter->url); + } + + WriteParam(m, p.languages()); + WriteParam(m, p.input_encodings()); + WriteParam(m, p.date_created()); + WriteParam(m, p.usage_count()); + WriteParam(m, p.prepopulate_id()); + } + static bool Read(const Message* m, void** iter, param_type* p) { + std::wstring short_name; + std::wstring description; + bool includes_suggestions_url; + TemplateURLRef suggestions_url; + TemplateURLRef url; + GURL originating_url; + std::wstring keyword; + bool autogenerate_keyword; + bool show_in_default_list; + bool safe_for_autoreplace; + std::vector<std::wstring> languages; + std::vector<std::string> input_encodings; + base::Time date_created; + int usage_count; + int prepopulate_id; + + if (!ReadParam(m, iter, &short_name) || + !ReadParam(m, iter, &description)) + return false; + + if (!ReadParam(m, iter, &includes_suggestions_url)) + return false; + if (includes_suggestions_url) { + if (!ReadParam(m, iter, &suggestions_url)) + return false; + } + + size_t image_refs_size = 0; + if (!ReadParam(m, iter, &url) || + !ReadParam(m, iter, &originating_url) || + !ReadParam(m, iter, &keyword) || + !ReadParam(m, iter, &autogenerate_keyword) || + !ReadParam(m, iter, &show_in_default_list) || + !ReadParam(m, iter, &safe_for_autoreplace) || + !ReadParam(m, iter, &image_refs_size)) + return false; + + *p = TemplateURL(); + for (size_t i = 0; i < image_refs_size; ++i) { + std::wstring type; + int width; + int height; + GURL url; + if (!ReadParam(m, iter, &type) || + !ReadParam(m, iter, &width) || + !ReadParam(m, iter, &height) || + !ReadParam(m, iter, &url)) + return false; + p->add_image_ref(TemplateURL::ImageRef(type, width, height, url)); + } + + if (!ReadParam(m, iter, &languages) || + !ReadParam(m, iter, &input_encodings) || + !ReadParam(m, iter, &date_created) || + !ReadParam(m, iter, &usage_count) || + !ReadParam(m, iter, &prepopulate_id)) + return false; + + p->set_short_name(short_name); + p->set_description(description); + p->SetSuggestionsURL(suggestions_url.url(), suggestions_url.index_offset(), + suggestions_url.page_offset()); + p->SetURL(url.url(), url.index_offset(), url.page_offset()); + p->set_originating_url(originating_url); + p->set_keyword(keyword); + p->set_autogenerate_keyword(autogenerate_keyword); + p->set_show_in_default_list(show_in_default_list); + p->set_safe_for_autoreplace(safe_for_autoreplace); + + std::vector<std::wstring>::const_iterator lang_iter; + for (lang_iter = languages.begin(); + lang_iter != languages.end(); + ++lang_iter) { + p->add_language(*lang_iter); + } + p->set_input_encodings(input_encodings); + p->set_date_created(date_created); + p->set_usage_count(usage_count); + p->set_prepopulate_id(prepopulate_id); + return true; + } + static void Log(const param_type& p, std::wstring* l) { + l->append(L"<TemplateURL>"); + } +}; + +} // namespace IPC + +#define MESSAGES_INTERNAL_FILE \ + "chrome/browser/importer/importer_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_ diff --git a/chrome/browser/importer/importer_messages_internal.h b/chrome/browser/importer/importer_messages_internal.h new file mode 100644 index 0000000..b247237 --- /dev/null +++ b/chrome/browser/importer/importer_messages_internal.h @@ -0,0 +1,80 @@ +// 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 <string> +#include <vector> + +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "ipc/ipc_message_macros.h" +#include "webkit/glue/password_form.h" + +//----------------------------------------------------------------------------- +// ProfileImportProcess messages +// These are messages sent from the browser to the profile import process. +IPC_BEGIN_MESSAGES(ProfileImportProcess) + IPC_MESSAGE_CONTROL4(ProfileImportProcessMsg_StartImport, + importer::ProfileInfo /* ProfileInfo struct */, + int /* bitmask of items to import */, + DictionaryValue /* localized strings */, + bool /* import to bookmark bar */) + + IPC_MESSAGE_CONTROL0(ProfileImportProcessMsg_CancelImport) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessMsg_ReportImportItemFinished, + int /* ImportItem */) +IPC_END_MESSAGES(ProfileImportProcess) + +//--------------------------------------------------------------------------- +// ProfileImportProcessHost messages +// These are messages sent from the profile import process to the browser. +IPC_BEGIN_MESSAGES(ProfileImportProcessHost) + // These messages send information about the status of the import and + // individual import tasks. + IPC_MESSAGE_CONTROL0(ProfileImportProcessHostMsg_Import_Started) + + IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_Import_Finished, + bool /* was import successful? */, + std::string /* error message, if any */) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Started, + int /* ImportItem */) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Finished, + int /* ImportItem */) + + // These messages send data from the external importer process back to + // the process host so it can be written to the profile. + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportStart, + int /* total number of history::URLRow items */) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportGroup, + std::vector<history::URLRow>) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHomePageImportReady, + GURL /* GURL of home page */) + + IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyBookmarksImportStart, + std::wstring /* first folder name */, + int /* options */, + int /* total number of bookmarks */) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup, + std::vector<ProfileWriter::BookmarkEntry>) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportStart, + int /* total number of FavIcons */) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportGroup, + std::vector<history::ImportedFavIconUsage> ) + + IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyPasswordFormReady, + webkit_glue::PasswordForm ) + + IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyKeywordsReady, + std::vector<TemplateURL>, + int, /* default keyword index */ + bool /* unique on host and path */) +IPC_END_MESSAGES(ProfileImportProcessHost) + diff --git a/chrome/browser/importer/importer_unittest.cc b/chrome/browser/importer/importer_unittest.cc index 3da8361..8a9f50c 100644 --- a/chrome/browser/importer/importer_unittest.cc +++ b/chrome/browser/importer/importer_unittest.cc @@ -205,8 +205,8 @@ class TestObserver : public ProfileWriter, password_count_ = 0; } - virtual void ImportItemStarted(ImportItem item) {} - virtual void ImportItemEnded(ImportItem item) {} + virtual void ImportItemStarted(importer::ImportItem item) {} + virtual void ImportItemEnded(importer::ImportItem item) {} virtual void ImportStarted() {} virtual void ImportEnded() { MessageLoop::current()->Quit(); @@ -554,8 +554,8 @@ class FirefoxObserver : public ProfileWriter, keyword_count_ = 0; } - virtual void ImportItemStarted(ImportItem item) {} - virtual void ImportItemEnded(ImportItem item) {} + virtual void ImportItemStarted(importer::ImportItem item) {} + virtual void ImportItemEnded(importer::ImportItem item) {} virtual void ImportStarted() {} virtual void ImportEnded() { MessageLoop::current()->Quit(); @@ -750,8 +750,8 @@ class Firefox3Observer : public ProfileWriter, import_search_engines_(import_search_engines) { } - virtual void ImportItemStarted(ImportItem item) {} - virtual void ImportItemEnded(ImportItem item) {} + virtual void ImportItemStarted(importer::ImportItem item) {} + virtual void ImportItemEnded(importer::ImportItem item) {} virtual void ImportStarted() {} virtual void ImportEnded() { MessageLoop::current()->Quit(); diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm index e503165..b124b84 100644 --- a/chrome/browser/importer/safari_importer.mm +++ b/chrome/browser/importer/safari_importer.mm @@ -9,7 +9,6 @@ #include <map> #include <vector> -#include "app/l10n_util.h" #include "base/file_util.h" #include "base/message_loop.h" #include "base/scoped_nsobject.h" @@ -18,6 +17,7 @@ #include "base/time.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/importer/importer_bridge.h" +#include "chrome/browser/importer/importer_data_types.h" #include "chrome/common/sqlite_utils.h" #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" @@ -57,7 +57,7 @@ SafariImporter::~SafariImporter() { bool SafariImporter::CanImport(const FilePath& library_dir, uint16 *services_supported) { DCHECK(services_supported); - *services_supported = NONE; + *services_supported = importer::NONE; // Import features are toggled by the following: // bookmarks import: existence of ~/Library/Safari/Bookmarks.plist file. @@ -68,37 +68,36 @@ bool SafariImporter::CanImport(const FilePath& library_dir, using file_util::PathExists; if (PathExists(bookmarks_path)) - *services_supported |= FAVORITES; + *services_supported |= importer::FAVORITES; if (PathExists(history_path)) - *services_supported |= HISTORY; + *services_supported |= importer::HISTORY; - return *services_supported != NONE; + return *services_supported != importer::NONE; } -void SafariImporter::StartImport(ProfileInfo profile_info, +void SafariImporter::StartImport(importer::ProfileInfo profile_info, uint16 services_supported, ImporterBridge* bridge) { bridge_ = bridge; - // The order here is important! bridge_->NotifyStarted(); // In keeping with import on other platforms (and for other browsers), we // don't import the home page (since it may lead to a useless homepage); see // crbug.com/25603. - if ((services_supported & HISTORY) && !cancelled()) { - bridge_->NotifyItemStarted(HISTORY); + if ((services_supported & importer::HISTORY) && !cancelled()) { + bridge_->NotifyItemStarted(importer::HISTORY); ImportHistory(); - bridge_->NotifyItemEnded(HISTORY); + bridge_->NotifyItemEnded(importer::HISTORY); } - if ((services_supported & FAVORITES) && !cancelled()) { - bridge_->NotifyItemStarted(FAVORITES); + if ((services_supported & importer::FAVORITES) && !cancelled()) { + bridge_->NotifyItemStarted(importer::FAVORITES); ImportBookmarks(); - bridge_->NotifyItemEnded(FAVORITES); + bridge_->NotifyItemEnded(importer::FAVORITES); } - if ((services_supported & PASSWORDS) && !cancelled()) { - bridge_->NotifyItemStarted(PASSWORDS); + if ((services_supported & importer::PASSWORDS) && !cancelled()) { + bridge_->NotifyItemStarted(importer::PASSWORDS); ImportPasswords(); - bridge_->NotifyItemEnded(PASSWORDS); + bridge_->NotifyItemEnded(importer::PASSWORDS); } bridge_->NotifyEnded(); } @@ -110,7 +109,7 @@ void SafariImporter::ImportBookmarks() { // Write bookmarks into profile. if (!bookmarks.empty() && !cancelled()) { const std::wstring& first_folder_name = - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_SAFARI); + bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_SAFARI); int options = 0; if (import_to_bookmark_bar()) options = ProfileWriter::IMPORT_TO_BOOKMARK_BAR; @@ -348,7 +347,8 @@ void SafariImporter::ParseHistoryItems( if (!history_dict) return; - NSArray* safari_history_items = [history_dict objectForKey:@"WebHistoryDates"]; + NSArray* safari_history_items = [history_dict + objectForKey:@"WebHistoryDates"]; for (NSDictionary* history_item in safari_history_items) { using base::SysNSStringToUTF8; diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc index 767d608..5b0a93c 100644 --- a/chrome/browser/importer/toolbar_importer.cc +++ b/chrome/browser/importer/toolbar_importer.cc @@ -6,12 +6,12 @@ #include <limits> -#include "app/l10n_util.h" #include "base/rand_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/first_run.h" #include "chrome/browser/importer/importer_bridge.h" +#include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/profile.h" #include "chrome/common/libxml_utils.h" #include "chrome/common/net/url_request_context_getter.h" @@ -82,7 +82,7 @@ const char Toolbar5Importer::kT5FrontEndUrlTemplate[] = // The constructor should set the initial state to NOT_USED. Toolbar5Importer::Toolbar5Importer() : state_(NOT_USED), - items_to_import_(NONE), + items_to_import_(importer::NONE), token_fetcher_(NULL), data_fetcher_(NULL) { } @@ -95,7 +95,7 @@ Toolbar5Importer::~Toolbar5Importer() { DCHECK(!data_fetcher_); } -void Toolbar5Importer::StartImport(ProfileInfo profile_info, +void Toolbar5Importer::StartImport(importer::ProfileInfo profile_info, uint16 items, ImporterBridge* bridge) { DCHECK(bridge); @@ -162,18 +162,18 @@ void Toolbar5Importer::OnURLFetchComplete( } void Toolbar5Importer::ContinueImport() { - DCHECK((items_to_import_ == FAVORITES) || - (items_to_import_ == NONE)) << + DCHECK((items_to_import_ == importer::FAVORITES) || + (items_to_import_ == importer::NONE)) << "The items requested are not supported"; // The order here is important. Each Begin... will clear the flag // of its item before its task finishes and re-enters this method. - if (NONE == items_to_import_) { + if (importer::NONE == items_to_import_) { EndImport(); return; } - if ((items_to_import_ & FAVORITES) && !cancelled()) { - items_to_import_ &= ~FAVORITES; + if ((items_to_import_ & importer::FAVORITES) && !cancelled()) { + items_to_import_ &= ~importer::FAVORITES; BeginImportBookmarks(); return; } @@ -207,12 +207,12 @@ void Toolbar5Importer::EndImport() { } void Toolbar5Importer::BeginImportBookmarks() { - bridge_->NotifyItemStarted(FAVORITES); + bridge_->NotifyItemStarted(importer::FAVORITES); GetAuthenticationFromServer(); } void Toolbar5Importer::EndImportBookmarks() { - bridge_->NotifyItemEnded(FAVORITES); + bridge_->NotifyItemEnded(importer::FAVORITES); ContinueImport(); } @@ -291,7 +291,9 @@ void Toolbar5Importer::GetBookmarksFromServerDataResponse( if (reader.Load(response) && !cancelled()) { // Construct Bookmarks std::vector<ProfileWriter::BookmarkEntry> bookmarks; - if (ParseBookmarksFromReader(&reader, &bookmarks)) + if (ParseBookmarksFromReader(&reader, &bookmarks, + WideToUTF16(bridge_->GetLocalizedString( + IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR)))) AddBookmarksToChrome(bookmarks); } EndImportBookmarks(); @@ -319,7 +321,8 @@ bool Toolbar5Importer::ParseAuthenticationTokenResponse( // Parsing bool Toolbar5Importer::ParseBookmarksFromReader( XmlReader* reader, - std::vector<ProfileWriter::BookmarkEntry>* bookmarks) { + std::vector<ProfileWriter::BookmarkEntry>* bookmarks, + const string16& bookmark_group_string) { DCHECK(reader); DCHECK(bookmarks); @@ -341,7 +344,8 @@ bool Toolbar5Importer::ParseBookmarksFromReader( kBookmarksXmlTag)) { ProfileWriter::BookmarkEntry bookmark_entry; std::vector<BookmarkFolderType> folders; - if (ExtractBookmarkInformation(reader, &bookmark_entry, &folders)) { + if (ExtractBookmarkInformation(reader, &bookmark_entry, &folders, + bookmark_group_string)) { // For each folder we create a new bookmark entry. Duplicates will // be detected when we attempt to create the bookmark in the profile. for (std::vector<BookmarkFolderType>::iterator folder = folders.begin(); @@ -402,7 +406,8 @@ bool Toolbar5Importer::LocateNextTagWithStopByName(XmlReader* reader, bool Toolbar5Importer::ExtractBookmarkInformation( XmlReader* reader, ProfileWriter::BookmarkEntry* bookmark_entry, - std::vector<BookmarkFolderType>* bookmark_folders) { + std::vector<BookmarkFolderType>* bookmark_folders, + const string16& bookmark_group_string) { DCHECK(reader); DCHECK(bookmark_entry); DCHECK(bookmark_folders); @@ -451,7 +456,8 @@ bool Toolbar5Importer::ExtractBookmarkInformation( return false; if (!ExtractTimeFromXmlReader(reader, bookmark_entry)) return false; - if (!ExtractFoldersFromXmlReader(reader, bookmark_folders)) + if (!ExtractFoldersFromXmlReader(reader, bookmark_folders, + bookmark_group_string)) return false; return true; @@ -523,7 +529,8 @@ bool Toolbar5Importer::ExtractTimeFromXmlReader( bool Toolbar5Importer::ExtractFoldersFromXmlReader( XmlReader* reader, - std::vector<BookmarkFolderType>* bookmark_folders) { + std::vector<BookmarkFolderType>* bookmark_folders, + const string16& bookmark_group_string) { DCHECK(reader); DCHECK(bookmark_folders); @@ -550,8 +557,7 @@ bool Toolbar5Importer::ExtractFoldersFromXmlReader( if (0 == label_vector.size()) { if (!FirstRun::IsChromeFirstRun()) { bookmark_folders->resize(1); - (*bookmark_folders)[0].push_back( - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR)); + (*bookmark_folders)[0].push_back(UTF16ToWide(bookmark_group_string)); } return true; } @@ -563,8 +569,7 @@ bool Toolbar5Importer::ExtractFoldersFromXmlReader( // If this is the first run then we place favorites with no labels // in the title bar. Else they are placed in the "Google Toolbar" folder. if (!FirstRun::IsChromeFirstRun() || !label_vector[index].empty()) { - (*bookmark_folders)[index].push_back( - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR)); + (*bookmark_folders)[index].push_back(UTF16ToWide(bookmark_group_string)); } // If the label and is in the form "xxx:yyy:zzz" this was created from an @@ -584,7 +589,7 @@ void Toolbar5Importer::AddBookmarksToChrome( const std::vector<ProfileWriter::BookmarkEntry>& bookmarks) { if (!bookmarks.empty() && !cancelled()) { const std::wstring& first_folder_name = - l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR); + bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_GOOGLE_TOOLBAR); int options = ProfileWriter::ADD_IF_UNIQUE | (import_to_bookmark_bar() ? ProfileWriter::IMPORT_TO_BOOKMARK_BAR : 0); bridge_->AddBookmarkEntries(bookmarks, first_folder_name, options); diff --git a/chrome/browser/importer/toolbar_importer.h b/chrome/browser/importer/toolbar_importer.h index 1f5bb48..0f31832 100644 --- a/chrome/browser/importer/toolbar_importer.h +++ b/chrome/browser/importer/toolbar_importer.h @@ -12,6 +12,7 @@ #include <vector> #include "base/gtest_prod_util.h" +#include "base/string16.h" #include "chrome/browser/importer/importer.h" #include "chrome/browser/importer/importer_data_types.h" #include "chrome/common/net/url_fetcher.h" @@ -121,7 +122,8 @@ class Toolbar5Importer : public URLFetcher::Delegate, public Importer { static bool ParseBookmarksFromReader( XmlReader* reader, - std::vector<ProfileWriter::BookmarkEntry>* bookmarks); + std::vector<ProfileWriter::BookmarkEntry>* bookmarks, + const string16& bookmark_group_string); static bool LocateNextOpenTag(XmlReader* reader); static bool LocateNextTagByName(XmlReader* reader, const std::string& tag); @@ -133,7 +135,8 @@ class Toolbar5Importer : public URLFetcher::Delegate, public Importer { static bool ExtractBookmarkInformation( XmlReader* reader, ProfileWriter::BookmarkEntry* bookmark_entry, - std::vector<BookmarkFolderType>* bookmark_folders); + std::vector<BookmarkFolderType>* bookmark_folders, + const string16& bookmark_group_string); static bool ExtractNamedValueFromXmlReader(XmlReader* reader, const std::string& name, std::string* buffer); @@ -145,7 +148,8 @@ class Toolbar5Importer : public URLFetcher::Delegate, public Importer { ProfileWriter::BookmarkEntry* entry); static bool ExtractFoldersFromXmlReader( XmlReader* reader, - std::vector<BookmarkFolderType>* bookmark_folders); + std::vector<BookmarkFolderType>* bookmark_folders, + const string16& bookmark_group_string); // Bookmark creation is done by the method below. void AddBookmarksToChrome( diff --git a/chrome/browser/importer/toolbar_importer_unittest.cc b/chrome/browser/importer/toolbar_importer_unittest.cc index 100e490..0bc6ab5 100644 --- a/chrome/browser/importer/toolbar_importer_unittest.cc +++ b/chrome/browser/importer/toolbar_importer_unittest.cc @@ -7,6 +7,7 @@ #include <string> #include <vector> +#include "base/string16.h" #include "chrome/browser/first_run.h" #include "chrome/browser/importer/importer.h" #include "chrome/browser/importer/toolbar_importer.h" @@ -25,6 +26,8 @@ static const wchar_t* kOtherTitle = L"MyOtherTitle"; static const char* kOtherUrl = "http://www.google.com/mail"; static const wchar_t* kOtherFolder = L"Mail"; +static const string16 kBookmarkGroupTitle = ASCIIToUTF16("BookmarkGroupTitle"); + // Since the following is very dense to read I enumerate the test cases here. // 1. Correct bookmark structure with one label. // 2. Correct bookmark structure with no labels. @@ -322,7 +325,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader1; EXPECT_TRUE(reader1.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader1, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader1, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(1U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -336,7 +340,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader2; EXPECT_TRUE(reader2.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader2, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader2, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(1U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -349,7 +354,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader3; EXPECT_TRUE(reader3.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader3, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader3, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(2U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -369,7 +375,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader4; EXPECT_TRUE(reader4.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader4, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader4, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(1U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -388,7 +395,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader5; EXPECT_TRUE(reader5.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader5, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader5, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(1U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -402,7 +410,8 @@ static const char* kBadBookmarkNoLabels = bookmarks.clear(); XmlReader reader6; EXPECT_TRUE(reader6.Load(bookmark_xml)); - EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader6, &bookmarks)); + EXPECT_TRUE(Toolbar5Importer::ParseBookmarksFromReader(&reader6, &bookmarks, + kBookmarkGroupTitle)); ASSERT_EQ(2U, bookmarks.size()); EXPECT_FALSE(bookmarks[0].in_toolbar); @@ -428,7 +437,7 @@ static const char* kBadBookmarkNoLabels = XmlReader reader8; EXPECT_TRUE(reader8.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader8, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); // Test case 9 tests when no <bookmark> section is present. bookmark_xml = kBadBookmarkNoBookmark; @@ -436,7 +445,7 @@ static const char* kBadBookmarkNoLabels = XmlReader reader9; EXPECT_TRUE(reader9.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader9, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); // Test case 10 tests when a bookmark has no <title> section. @@ -445,7 +454,7 @@ static const char* kBadBookmarkNoLabels = XmlReader reader10; EXPECT_TRUE(reader10.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader10, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); // Test case 11 tests when a bookmark has no <url> section. bookmark_xml = kBadBookmarkNoUrl; @@ -453,7 +462,7 @@ static const char* kBadBookmarkNoLabels = XmlReader reader11; EXPECT_TRUE(reader11.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader11, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); // Test case 12 tests when a bookmark has no <timestamp> section. bookmark_xml = kBadBookmarkNoTimestamp; @@ -461,7 +470,7 @@ static const char* kBadBookmarkNoLabels = XmlReader reader12; EXPECT_TRUE(reader12.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader12, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); // Test case 13 tests when a bookmark has no <labels> section. bookmark_xml = kBadBookmarkNoLabels; @@ -469,5 +478,5 @@ static const char* kBadBookmarkNoLabels = XmlReader reader13; EXPECT_TRUE(reader13.Load(bookmark_xml)); EXPECT_FALSE(Toolbar5Importer::ParseBookmarksFromReader(&reader13, - &bookmarks)); + &bookmarks, kBookmarkGroupTitle)); } diff --git a/chrome/browser/profile_import_process_host.cc b/chrome/browser/profile_import_process_host.cc new file mode 100644 index 0000000..ffe0395 --- /dev/null +++ b/chrome/browser/profile_import_process_host.cc @@ -0,0 +1,169 @@ +// 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/profile_import_process_host.h" + +#include "app/l10n_util.h" +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/importer/firefox_importer_utils.h" +#include "chrome/browser/importer/importer_messages.h" +#include "chrome/common/chrome_switches.h" +#include "grit/generated_resources.h" +#include "ipc/ipc_switches.h" + +ProfileImportProcessHost::ProfileImportProcessHost( + ResourceDispatcherHost* resource_dispatcher, + ImportProcessClient* import_process_client, + ChromeThread::ID thread_id) + : ChildProcessHost(PROFILE_IMPORT_PROCESS, resource_dispatcher), + import_process_client_(import_process_client), + thread_id_(thread_id) { +} + +bool ProfileImportProcessHost::StartProfileImportProcess( + const importer::ProfileInfo& profile_info, int items, + bool import_to_bookmark_bar) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!StartProcess()) + return false; + + // Dictionary of all localized strings that could be needed by the importer + // in the external process. + DictionaryValue localized_strings; + localized_strings.SetString( + IntToWString(IDS_BOOKMARK_GROUP_FROM_FIREFOX), + l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX)); + localized_strings.SetString( + IntToWString(IDS_BOOKMARK_GROUP_FROM_SAFARI), + l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_SAFARI)); + localized_strings.SetString( + IntToWString(IDS_IMPORT_FROM_FIREFOX), + l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX)); + localized_strings.SetString( + IntToWString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR), + l10n_util::GetString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR)); + localized_strings.SetString( + IntToWString(IDS_IMPORT_FROM_SAFARI), + l10n_util::GetString(IDS_IMPORT_FROM_SAFARI)); + + Send(new ProfileImportProcessMsg_StartImport( + profile_info, items, localized_strings, import_to_bookmark_bar)); + return true; +} + +bool ProfileImportProcessHost::CancelProfileImportProcess() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + Send(new ProfileImportProcessMsg_CancelImport()); + return true; +} + +bool ProfileImportProcessHost::ReportImportItemFinished( + importer::ImportItem item) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + Send(new ProfileImportProcessMsg_ReportImportItemFinished(item)); + return true; +} + +FilePath ProfileImportProcessHost::GetProfileImportProcessCmd() { + return GetChildPath(true); +} + +bool ProfileImportProcessHost::StartProcess() { + set_name(L"profile import process"); + + if (!CreateChannel()) + return false; + + FilePath exe_path = GetProfileImportProcessCmd(); + if (exe_path.empty()) { + NOTREACHED() << "Unable to get profile import process binary name."; + return false; + } + + CommandLine* cmd_line = new CommandLine(exe_path); + cmd_line->AppendSwitchWithValue(switches::kProcessType, + switches::kProfileImportProcess); + cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, + ASCIIToWide(channel_id())); + + SetCrashReporterCommandLine(cmd_line); + + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + if (browser_command_line.HasSwitch(switches::kChromeFrame)) + cmd_line->AppendSwitch(switches::kChromeFrame); + +#if defined(OS_MACOSX) + base::environment_vector env; + std::string dylib_path = GetFirefoxDylibPath().value(); + if (!dylib_path.empty()) + env.push_back(std::make_pair("DYLD_FALLBACK_LIBRARY_PATH", dylib_path)); + + Launch(false, env, cmd_line); +#elif defined(OS_WIN) + FilePath no_exposed_directory; + + Launch(no_exposed_directory, cmd_line); +#else + base::environment_vector env; + + Launch(false, env, cmd_line); +#endif + + return true; +} + +void ProfileImportProcessHost::OnMessageReceived(const IPC::Message& message) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + ChromeThread::PostTask( + thread_id_, FROM_HERE, + NewRunnableMethod(import_process_client_.get(), + &ImportProcessClient::OnMessageReceived, + message)); +} + +void ProfileImportProcessHost::OnProcessCrashed() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + ChromeThread::PostTask( + thread_id_, FROM_HERE, + NewRunnableMethod(import_process_client_.get(), + &ImportProcessClient::OnProcessCrashed)); +} + +void ProfileImportProcessHost::ImportProcessClient::OnMessageReceived( + const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(ProfileImportProcessHost, message) + // Notification messages about the state of the import process. + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Started, + ImportProcessClient::OnImportStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Finished, + ImportProcessClient::OnImportFinished) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Started, + ImportProcessClient::OnImportItemStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_ImportItem_Finished, + ImportProcessClient::OnImportItemFinished) + + // Data messages containing items to be written to the user profile. + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportStart, + ImportProcessClient::OnHistoryImportStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHistoryImportGroup, + ImportProcessClient::OnHistoryImportGroup) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyHomePageImportReady, + ImportProcessClient::OnHomePageImportReady) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportStart, + ImportProcessClient::OnBookmarksImportStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup, + ImportProcessClient::OnBookmarksImportGroup) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFavIconsImportStart, + ImportProcessClient::OnFavIconsImportStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyFavIconsImportGroup, + ImportProcessClient::OnFavIconsImportGroup) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyPasswordFormReady, + ImportProcessClient::OnPasswordFormImportReady) + IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyKeywordsReady, + ImportProcessClient::OnKeywordsImportReady) + IPC_END_MESSAGE_MAP_EX() +} diff --git a/chrome/browser/profile_import_process_host.h b/chrome/browser/profile_import_process_host.h new file mode 100644 index 0000000..1cb3819 --- /dev/null +++ b/chrome/browser/profile_import_process_host.h @@ -0,0 +1,142 @@ +// 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. + +#ifndef CHROME_BROWSER_PROFILE_IMPORT_PROCESS_HOST_H_ +#define CHROME_BROWSER_PROFILE_IMPORT_PROCESS_HOST_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "base/task.h" +#include "base/values.h" +#include "chrome/browser/child_process_host.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/importer/profile_writer.h" +#include "ipc/ipc_channel.h" +#include "webkit/glue/password_form.h" + +// Browser-side host to a profile import process. This class lives only on +// the IO thread. It passes messages back to the |thread_id_| thread through +// a client object. +class ProfileImportProcessHost : public ChildProcessHost { + public: + + // An interface that must be implemented by consumers of the profile import + // process in order to get results back from the process host. The + // ProfileImportProcessHost calls the client's functions on the thread passed + // to it when it's created. + class ImportProcessClient : + public base::RefCountedThreadSafe<ImportProcessClient> { + public: + ImportProcessClient() {} + + // These methods are used by the ProfileImportProcessHost to pass messages + // received from the external process back to the ImportProcessClient in + // ImporterHost. + virtual void OnProcessCrashed() {} + virtual void OnImportStart() {} + virtual void OnImportFinished(bool succeeded, std::string error_msg) {} + virtual void OnImportItemStart(int item) {} + virtual void OnImportItemFinished(int item) {} + virtual void OnImportItemFailed(std::string error_msg) {} + + // These methods pass back data to be written to the user's profile from + // the external process to the process host client. + virtual void OnHistoryImportStart(size_t total_history_rows_count) {} + virtual void OnHistoryImportGroup( + const std::vector<history::URLRow> &history_rows_group) {} + + virtual void OnHomePageImportReady( + const GURL& home_page) {} + + virtual void OnBookmarksImportStart( + const std::wstring first_folder_name, + int options, size_t total_bookmarks_count) {} + virtual void OnBookmarksImportGroup( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks) {} + + virtual void OnFavIconsImportStart(size_t total_fav_icons_count) {} + virtual void OnFavIconsImportGroup( + const std::vector<history::ImportedFavIconUsage>& fav_icons_group) {} + + virtual void OnPasswordFormImportReady( + const webkit_glue::PasswordForm& form) {} + + virtual void OnKeywordsImportReady( + const std::vector<TemplateURL>& template_urls, + int default_keyword_index, bool unique_on_host_and_path) {} + + virtual void OnMessageReceived(const IPC::Message& message); + + protected: + friend class base::RefCountedThreadSafe<ImportProcessClient>; + + virtual ~ImportProcessClient() {} + + private: + friend class ProfileImportProcessHost; + + DISALLOW_COPY_AND_ASSIGN(ImportProcessClient); + }; + + // |resource_dispatcher| is used in the base ChildProcessHost class to manage + // IPC requests. + // |import_process_client| implements callbacks which are triggered by + // incoming IPC messages. This client creates an interface between IPC + // messages received by the ProfileImportProcessHost and the internal + // importer_bridge. + // |thread_id| gives the thread where the client lives. The + // ProfileImportProcessHost spawns tasks on this thread for the client. + ProfileImportProcessHost(ResourceDispatcherHost* resource_dispatcher, + ImportProcessClient* import_process_client, + ChromeThread::ID thread_id); + + // |profile_info|, |items|, and |import_to_bookmark_bar| are all needed by + // the external importer process. + bool StartProfileImportProcess(const importer::ProfileInfo& profile_info, + int items, bool import_to_bookmark_bar); + + // Cancel the external import process. + bool CancelProfileImportProcess(); + + // Report that an item has been successfully imported. We need to make + // sure that all import messages have come across the wire before the + // external import process shuts itself down. + bool ReportImportItemFinished(importer::ImportItem item); + + protected: + // Allow these methods to be overridden for tests. + virtual FilePath GetProfileImportProcessCmd(); + + private: + // Launch the new process. + bool StartProcess(); + + // Called by the external importer process to send messages back to the + // ImportProcessClient. + void OnMessageReceived(const IPC::Message& message); + + // Overridden from ChildProcessHost: + virtual void OnProcessCrashed(); + virtual bool CanShutdown() { return true; } + virtual URLRequestContext* GetRequestContext( + uint32 request_id, + const ViewHostMsg_Resource_Request& request_data) { + return NULL; + } + + // Receives messages to be passed back to the importer host. + scoped_refptr<ImportProcessClient> import_process_client_; + + // The thread where the import_process_client_ lives. + ChromeThread::ID thread_id_; + + DISALLOW_COPY_AND_ASSIGN(ProfileImportProcessHost); +}; + +#endif // CHROME_BROWSER_PROFILE_IMPORT_PROCESS_HOST_H_ diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 8dd729c..0b81f6e 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -25,10 +25,10 @@ 'browser', 'debugger', 'chrome_gpu', + 'profile_import', 'renderer', 'syncapi', 'utility', - 'profile_import', 'worker', 'service', '../printing/printing.gyp:printing', diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 05cb5ae..2f163e8 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -18,6 +18,7 @@ 'domui_shared_resources', 'net_internals_resources', 'platform_locale_settings', + 'profile_import', 'browser/sync/protocol/sync_proto.gyp:sync_proto_cpp', 'syncapi', 'theme_resources', @@ -1565,6 +1566,8 @@ 'browser/importer/importer_data_types.h', 'browser/importer/importer_list.cc', 'browser/importer/importer_list.h', + 'browser/importer/importer_messages.h', + 'browser/importer/importer_messages_internal.h', 'browser/importer/mork_reader.cc', 'browser/importer/mork_reader.h', 'browser/importer/nss_decryptor.cc', @@ -1853,6 +1856,8 @@ 'browser/process_singleton_win.cc', 'browser/profile.cc', 'browser/profile.h', + 'browser/profile_import_process_host.cc', + 'browser/profile_import_process_host.h', 'browser/profile_manager.cc', 'browser/profile_manager.h', 'browser/renderer_host/async_resource_handler.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 7f142de..ab39a51 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -272,6 +272,7 @@ 'common', 'chrome_resources', 'chrome_strings', + 'profile_import', 'test_support_ui', '../base/base.gyp:base', '../net/net.gyp:net', @@ -496,6 +497,7 @@ 'common', 'common_net_test_support', 'debugger', + 'profile_import', 'renderer', 'service', 'test_support_unit', @@ -1260,6 +1262,7 @@ 'chrome_resources', 'chrome_strings', 'debugger', + 'profile_import', 'renderer', 'test_support_common', '../app/app.gyp:app_base', @@ -1871,6 +1874,7 @@ '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', '../third_party/libjingle/libjingle.gyp:libjingle', + 'profile_import', 'syncapi', 'test_support_unit', ], @@ -1937,6 +1941,7 @@ 'chrome_resources', 'common', 'debugger', + 'profile_import', 'renderer', 'chrome_strings', 'test_support_common', diff --git a/chrome/profile_import/DEPS b/chrome/profile_import/DEPS new file mode 100644 index 0000000..4c8adc9 --- /dev/null +++ b/chrome/profile_import/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+chrome/browser/history", + "+chrome/browser/importer", + "+chrome/browser/search_engines", + "+webkit/glue" +] diff --git a/chrome/profile_import/profile_import_thread.cc b/chrome/profile_import/profile_import_thread.cc index 6a0211f7..4a7ca13 100644 --- a/chrome/profile_import/profile_import_thread.cc +++ b/chrome/profile_import/profile_import_thread.cc @@ -1,19 +1,184 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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/profile_import/profile_import_thread.h" +#include <algorithm> + +#include "base/values.h" +#include "chrome/browser/importer/importer.h" +#include "chrome/browser/importer/importer_bridge.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/importer/importer_list.h" +#include "chrome/browser/importer/importer_messages.h" +#include "chrome/browser/search_engines/template_url.h" #include "chrome/common/child_process.h" -ProfileImportThread::ProfileImportThread() { - ChildProcess::current()->AddRefProcess(); +namespace { +// Rather than sending all import items over IPC at once we chunk them into +// separate requests. This avoids the case of a large import causing +// oversized IPC messages. +const int kNumBookmarksToSend = 100; +const int kNumHistoryRowsToSend = 100; +const int kNumFavIconsToSend = 100; } -ProfileImportThread::~ProfileImportThread() { +ProfileImportThread::ProfileImportThread() { + ChildProcess::current()->AddRefProcess(); // Balanced in Cleanup(). } void ProfileImportThread::OnControlMessageReceived(const IPC::Message& msg) { - ChildProcess::current()->ReleaseProcess(); + IPC_BEGIN_MESSAGE_MAP(ProfileImportThread, msg) + IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_StartImport, + OnImportStart) + IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_CancelImport, + OnImportCancel) + IPC_MESSAGE_HANDLER(ProfileImportProcessMsg_ReportImportItemFinished, + OnImportItemFinished) + IPC_END_MESSAGE_MAP() +} + +void ProfileImportThread::OnImportStart( + const ProfileInfo& profile_info, + int items, + const DictionaryValue& localized_strings, + bool import_to_bookmark_bar) { + bridge_ = new ExternalProcessImporterBridge(this, localized_strings); + bridge_->AddRef(); // Balanced in Cleanup(). + + ImporterList importer_list; + importer_ = importer_list.CreateImporterByType(profile_info.browser_type); + importer_->AddRef(); // Balanced in Cleanup(). + importer_->set_import_to_bookmark_bar(import_to_bookmark_bar); + items_to_import_ = items; + + if (!importer_) { + Send(new ProfileImportProcessHostMsg_Import_Finished(false, + "Importer could not be created.")); + return; + } + + // Create worker thread in which importer runs. + import_thread_.reset(new base::Thread("import_thread")); + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + if (!import_thread_->StartWithOptions(options)) { + NOTREACHED(); + Cleanup(); + } + import_thread_->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(importer_, &Importer::StartImport, + profile_info, items, bridge_)); +} + +void ProfileImportThread::OnImportCancel() { + Cleanup(); +} + +void ProfileImportThread::OnImportItemFinished(uint16 item) { + items_to_import_ ^= item; // Remove finished item from mask. + // If we've finished with all items, notify the browser process. + if (items_to_import_ == 0) + NotifyEnded(); +} + +void ProfileImportThread::NotifyItemStarted(ImportItem item) { + Send(new ProfileImportProcessHostMsg_ImportItem_Started(item)); +} + +void ProfileImportThread::NotifyItemEnded(ImportItem item) { + Send(new ProfileImportProcessHostMsg_ImportItem_Finished(item)); +} + +void ProfileImportThread::NotifyStarted() { + Send(new ProfileImportProcessHostMsg_Import_Started()); +} + +void ProfileImportThread::NotifyEnded() { + Send(new ProfileImportProcessHostMsg_Import_Finished(true, "")); + Cleanup(); +} + +void ProfileImportThread::NotifyHistoryImportReady( + const std::vector<history::URLRow> &rows) { + Send(new ProfileImportProcessHostMsg_NotifyHistoryImportStart(rows.size())); + + std::vector<history::URLRow>::const_iterator it; + for (it = rows.begin(); it < rows.end(); + it = it + kNumHistoryRowsToSend) { + std::vector<history::URLRow> row_group; + std::vector<history::URLRow>::const_iterator end_group = + it + kNumHistoryRowsToSend < rows.end() ? + it + kNumHistoryRowsToSend : rows.end(); + row_group.assign(it, end_group); + + Send(new ProfileImportProcessHostMsg_NotifyHistoryImportGroup(row_group)); + } +} + +void ProfileImportThread::NotifyHomePageImportReady( + const GURL& home_page) { NOTIMPLEMENTED(); } + +void ProfileImportThread::NotifyBookmarksImportReady( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, + const std::wstring& first_folder_name, int options) { + Send(new ProfileImportProcessHostMsg_NotifyBookmarksImportStart( + first_folder_name, options, bookmarks.size())); + + std::vector<ProfileWriter::BookmarkEntry>::const_iterator it; + for (it = bookmarks.begin(); it < bookmarks.end(); + it = it + kNumBookmarksToSend) { + std::vector<ProfileWriter::BookmarkEntry> bookmark_group; + std::vector<ProfileWriter::BookmarkEntry>::const_iterator end_group = + it + kNumBookmarksToSend < bookmarks.end() ? + it + kNumBookmarksToSend : bookmarks.end(); + bookmark_group.assign(it, end_group); + + Send(new ProfileImportProcessHostMsg_NotifyBookmarksImportGroup( + bookmark_group)); + } +} + +void ProfileImportThread::NotifyFavIconsImportReady( + const std::vector<history::ImportedFavIconUsage>& fav_icons) { + Send(new ProfileImportProcessHostMsg_NotifyFavIconsImportStart( + fav_icons.size())); + + std::vector<history::ImportedFavIconUsage>::const_iterator it; + for (it = fav_icons.begin(); it < fav_icons.end(); + it = it + kNumFavIconsToSend) { + std::vector<history::ImportedFavIconUsage> fav_icons_group; + std::vector<history::ImportedFavIconUsage>::const_iterator end_group = + std::min(it + kNumFavIconsToSend, fav_icons.end()); + fav_icons_group.assign(it, end_group); + + Send(new ProfileImportProcessHostMsg_NotifyFavIconsImportGroup( + fav_icons_group)); + } +} + +void ProfileImportThread::NotifyPasswordFormReady( + const webkit_glue::PasswordForm& form) { + Send(new ProfileImportProcessHostMsg_NotifyPasswordFormReady(form)); +} + +void ProfileImportThread::NotifyKeywordsReady( + const std::vector<TemplateURL*>& template_urls, + int default_keyword_index, bool unique_on_host_and_path) { + std::vector<TemplateURL> urls; + for (size_t i = 0; i < template_urls.size(); ++i) { + urls.push_back(*template_urls[i]); + } + Send(new ProfileImportProcessHostMsg_NotifyKeywordsReady(urls, + default_keyword_index, unique_on_host_and_path)); +} + +void ProfileImportThread::Cleanup() { + importer_->Cancel(); + importer_->Release(); + bridge_->Release(); + ChildProcess::current()->ReleaseProcess(); +} diff --git a/chrome/profile_import/profile_import_thread.h b/chrome/profile_import/profile_import_thread.h index ea2c4b8..67d79d1 100644 --- a/chrome/profile_import/profile_import_thread.h +++ b/chrome/profile_import/profile_import_thread.h @@ -1,28 +1,99 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. #ifndef CHROME_PROFILE_IMPORT_PROFILE_IMPORT_THREAD_H_ #define CHROME_PROFILE_IMPORT_PROFILE_IMPORT_THREAD_H_ +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/thread.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/importer/importer_data_types.h" +#include "chrome/browser/importer/profile_writer.h" #include "chrome/common/child_thread.h" +#include "webkit/glue/password_form.h" + +class DictionaryValue; +class ExternalProcessImporterBridge; +class Importer; +class InProcessImporterBridge; -// This class represents the background thread where the profile import task -// runs. +// This class represents the background thread which communicates with the +// importer work thread in the importer process. class ProfileImportThread : public ChildThread { public: ProfileImportThread(); - virtual ~ProfileImportThread(); + virtual ~ProfileImportThread() {} // Returns the one profile import thread. static ProfileImportThread* current() { return static_cast<ProfileImportThread*>(ChildThread::current()); } + // Bridging methods, called from importer_bridge tasks posted here. + void NotifyItemStarted(importer::ImportItem item); + void NotifyItemEnded(importer::ImportItem item); + void NotifyStarted(); + void NotifyEnded(); + + // Bridging methods that move data back across the process boundary. + void NotifyHistoryImportReady(const std::vector<history::URLRow> &rows); + void NotifyHomePageImportReady(const GURL& home_page); + void NotifyBookmarksImportReady( + const std::vector<ProfileWriter::BookmarkEntry>& bookmarks, + const std::wstring& first_folder_name, int options); + void NotifyFavIconsImportReady( + const std::vector<history::ImportedFavIconUsage>& fav_icons); + void NotifyPasswordFormReady(const webkit_glue::PasswordForm& form); + void NotifyKeywordsReady(const std::vector<TemplateURL*>& template_urls, + int default_keyword_index, bool unique_on_host_and_path); + private: // IPC messages virtual void OnControlMessageReceived(const IPC::Message& msg); + // Creates the importer and launches it in a new thread. Import is run on + // a separate thread so that this thread can receive messages from the + // main process (especially cancel requests) while the worker thread handles + // the actual import. + void OnImportStart( + const importer::ProfileInfo& profile_info, + int items, + const DictionaryValue& localized_strings, + bool import_to_bookmark_bar); + + // Calls cleanup to stop the import operation. + void OnImportCancel(); + + // Called from the main process to notify that an item has been received + // from the import process. + void OnImportItemFinished(uint16 item); + + // Release the process and ourselves. + void Cleanup(); + + // Thread that importer runs on, while ProfileImportThread handles messages + // from the browser process. + scoped_ptr<base::Thread> import_thread_; + + // Bridge object is passed to importer, so that it can send IPC calls + // directly back to the ProfileImportProcessHost. + ExternalProcessImporterBridge* bridge_; + + // importer::ProfileType enum from importer_list, stored in ProfileInfo + // struct in importer. + int browser_type_; + + // A mask of importer::ImportItems. + uint16 items_to_import_; + + // Importer of the appropriate type (Firefox, Safari, IE, etc.) + Importer* importer_; + DISALLOW_COPY_AND_ASSIGN(ProfileImportThread); }; |