| // Copyright (c) 2012 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/importer/importer_host.h" |
| |
| #include "base/bind.h" |
| #include "base/message_loop.h" |
| #include "base/metrics/histogram.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/bookmarks/bookmark_model.h" |
| #include "chrome/browser/bookmarks/bookmark_model_factory.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/importer/firefox_profile_lock.h" |
| #include "chrome/browser/importer/importer.h" |
| #include "chrome/browser/importer/importer_lock_dialog.h" |
| #include "chrome/browser/importer/importer_progress_observer.h" |
| #include "chrome/browser/importer/importer_type.h" |
| #include "chrome/browser/importer/in_process_importer_bridge.h" |
| #include "chrome/browser/importer/toolbar_importer_utils.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search_engines/template_url.h" |
| #include "chrome/browser/search_engines/template_url_service.h" |
| #include "chrome/browser/search_engines/template_url_service_factory.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/simple_message_box.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_source.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| using content::BrowserThread; |
| |
| ImporterHost::ImporterHost() |
| : weak_ptr_factory_(this), |
| profile_(NULL), |
| waiting_for_bookmarkbar_model_(false), |
| installed_bookmark_observer_(false), |
| is_source_readable_(true), |
| headless_(false), |
| parent_window_(NULL), |
| browser_(NULL), |
| observer_(NULL) { |
| BrowserList::AddObserver(this); |
| } |
| |
| void ImporterHost::ShowWarningDialog() { |
| if (headless_) { |
| OnImportLockDialogEnd(false); |
| return; |
| } |
| |
| importer::ShowImportLockDialog( |
| parent_window_, |
| base::Bind(&ImporterHost::OnImportLockDialogEnd, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void ImporterHost::OnImportLockDialogEnd(bool is_continue) { |
| if (is_continue) { |
| // User chose to continue, then we check the lock again to make |
| // sure that Firefox has been closed. Try to import the settings |
| // if successful. Otherwise, show a warning dialog. |
| firefox_lock_->Lock(); |
| if (firefox_lock_->HasAcquired()) { |
| is_source_readable_ = true; |
| InvokeTaskIfDone(); |
| } else { |
| ShowWarningDialog(); |
| } |
| } else { |
| // User chose to skip the import process. We should reset the |task_| and |
| // notify the ImporterHost to finish. |
| task_.Reset(); |
| importer_ = NULL; |
| NotifyImportEnded(); |
| } |
| } |
| |
| void ImporterHost::SetObserver(importer::ImporterProgressObserver* observer) { |
| observer_ = observer; |
| } |
| |
| void ImporterHost::NotifyImportStarted() { |
| if (observer_) |
| observer_->ImportStarted(); |
| } |
| |
| void ImporterHost::NotifyImportItemStarted(importer::ImportItem item) { |
| if (observer_) |
| observer_->ImportItemStarted(item); |
| } |
| |
| void ImporterHost::NotifyImportItemEnded(importer::ImportItem item) { |
| if (observer_) |
| observer_->ImportItemEnded(item); |
| } |
| |
| void ImporterHost::NotifyImportEnded() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| firefox_lock_.reset(); // Release the Firefox profile lock. |
| if (observer_) |
| observer_->ImportEnded(); |
| delete this; |
| } |
| |
| void ImporterHost::StartImportSettings( |
| const importer::SourceProfile& source_profile, |
| Profile* target_profile, |
| uint16 items, |
| ProfileWriter* writer) { |
| // We really only support importing from one host at a time. |
| DCHECK(!profile_); |
| DCHECK(target_profile); |
| |
| profile_ = target_profile; |
| PrefService* user_prefs = profile_->GetPrefs(); |
| |
| // Make sure only items that were not disabled by policy are imported. |
| if (!user_prefs->GetBoolean(prefs::kImportHistory)) |
| items &= ~importer::HISTORY; |
| if (!user_prefs->GetBoolean(prefs::kImportSearchEngine)) |
| items &= ~importer::SEARCH_ENGINES; |
| if (!user_prefs->GetBoolean(prefs::kImportBookmarks)) |
| items &= ~importer::FAVORITES; |
| if (!user_prefs->GetBoolean(prefs::kImportSavedPasswords)) |
| items &= ~importer::PASSWORDS; |
| |
| // Preserves the observer and creates a task, since we do async import so that |
| // it doesn't block the UI. When the import is complete, observer will be |
| // notified. |
| writer_ = writer; |
| importer_ = importer::CreateImporterByType(source_profile.importer_type); |
| // If we fail to create the Importer, exit, as we cannot do anything. |
| if (!importer_) { |
| NotifyImportEnded(); |
| return; |
| } |
| |
| scoped_refptr<InProcessImporterBridge> bridge( |
| new InProcessImporterBridge(writer_.get(), |
| weak_ptr_factory_.GetWeakPtr())); |
| task_ = base::Bind( |
| &Importer::StartImport, importer_, source_profile, items, bridge); |
| |
| CheckForFirefoxLock(source_profile, items); |
| |
| #if defined(OS_WIN) |
| // For google toolbar import, we need the user to log in and store their GAIA |
| // credentials. |
| if (source_profile.importer_type == importer::TYPE_GOOGLE_TOOLBAR5) { |
| toolbar_importer_utils::IsGoogleGAIACookieInstalled( |
| base::Bind(&ImporterHost::OnGoogleGAIACookieChecked, |
| weak_ptr_factory_.GetWeakPtr()), |
| profile_); |
| is_source_readable_ = false; |
| } |
| #endif |
| |
| CheckForLoadedModels(items); |
| InvokeTaskIfDone(); |
| } |
| |
| void ImporterHost::OnGoogleGAIACookieChecked(bool result) { |
| #if defined(OS_WIN) |
| if (!result) { |
| chrome::ShowMessageBox( |
| NULL, |
| l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), |
| l10n_util::GetStringUTF16(IDS_IMPORTER_GOOGLE_LOGIN_TEXT), |
| chrome::MESSAGE_BOX_TYPE_INFORMATION); |
| |
| GURL url("https://accounts.google.com/ServiceLogin"); |
| if (browser_) |
| chrome::AddSelectedTabWithURL(browser_, url, |
| content::PAGE_TRANSITION_TYPED); |
| |
| MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| &ImporterHost::OnImportLockDialogEnd, |
| weak_ptr_factory_.GetWeakPtr(), false)); |
| } else { |
| is_source_readable_ = true; |
| InvokeTaskIfDone(); |
| } |
| #endif |
| } |
| |
| ImporterHost::~ImporterHost() { |
| BrowserList::RemoveObserver(this); |
| |
| if (installed_bookmark_observer_) { |
| DCHECK(profile_); |
| BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); |
| } |
| } |
| |
| void ImporterHost::CheckForFirefoxLock( |
| const importer::SourceProfile& source_profile, |
| uint16 items) { |
| if (source_profile.importer_type == importer::TYPE_FIREFOX2 || |
| source_profile.importer_type == importer::TYPE_FIREFOX3) { |
| DCHECK(!firefox_lock_.get()); |
| firefox_lock_.reset(new FirefoxProfileLock(source_profile.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; |
| ShowWarningDialog(); |
| } |
| } |
| } |
| |
| void ImporterHost::CheckForLoadedModels(uint16 items) { |
| // A target profile must be loaded by StartImportSettings(). |
| DCHECK(profile_); |
| |
| // 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()) { |
| BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); |
| waiting_for_bookmarkbar_model_ = true; |
| installed_bookmark_observer_ = true; |
| } |
| |
| // Observes the TemplateURLService 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_->TemplateURLServiceIsLoaded()) { |
| TemplateURLService* model = |
| TemplateURLServiceFactory::GetForProfile(profile_); |
| registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED, |
| content::Source<TemplateURLService>(model)); |
| model->Load(); |
| } |
| } |
| } |
| |
| void ImporterHost::InvokeTaskIfDone() { |
| if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() || |
| !is_source_readable_) |
| return; |
| BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, task_); |
| } |
| |
| void ImporterHost::Loaded(BookmarkModel* model, bool ids_reassigned) { |
| DCHECK(model->loaded()); |
| model->RemoveObserver(this); |
| waiting_for_bookmarkbar_model_ = false; |
| installed_bookmark_observer_ = false; |
| |
| InvokeTaskIfDone(); |
| } |
| |
| void ImporterHost::BookmarkModelBeingDeleted(BookmarkModel* model) { |
| installed_bookmark_observer_ = false; |
| } |
| |
| void ImporterHost::BookmarkModelChanged() { |
| } |
| |
| void ImporterHost::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(type == chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED); |
| registrar_.RemoveAll(); |
| InvokeTaskIfDone(); |
| } |
| |
| void ImporterHost::OnBrowserRemoved(Browser* browser) { |
| if (browser_ == browser) |
| browser_ = NULL; |
| } |