1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/importer/external_process_importer_host.h" 6 7 #include "base/bind.h" 8 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/bookmarks/bookmark_model.h" 10 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 11 #include "chrome/browser/importer/external_process_importer_client.h" 12 #include "chrome/browser/importer/firefox_profile_lock.h" 13 #include "chrome/browser/importer/importer_lock_dialog.h" 14 #include "chrome/browser/importer/importer_progress_observer.h" 15 #include "chrome/browser/importer/in_process_importer_bridge.h" 16 #include "chrome/browser/search_engines/template_url_service.h" 17 #include "chrome/browser/search_engines/template_url_service_factory.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/notification_source.h" 20 21 using content::BrowserThread; 22 23 ExternalProcessImporterHost::ExternalProcessImporterHost() 24 : weak_ptr_factory_(this), 25 headless_(false), 26 parent_window_(NULL), 27 observer_(NULL), 28 profile_(NULL), 29 waiting_for_bookmarkbar_model_(false), 30 installed_bookmark_observer_(false), 31 is_source_readable_(true), 32 client_(NULL), 33 items_(0), 34 cancelled_(false), 35 import_process_launched_(false) { 36 } 37 38 void ExternalProcessImporterHost::Cancel() { 39 cancelled_ = true; 40 if (import_process_launched_) 41 client_->Cancel(); 42 NotifyImportEnded(); // Tells the observer that we're done, and deletes us. 43 } 44 45 void ExternalProcessImporterHost::StartImportSettings( 46 const importer::SourceProfile& source_profile, 47 Profile* target_profile, 48 uint16 items, 49 ProfileWriter* writer) { 50 // We really only support importing from one host at a time. 51 DCHECK(!profile_); 52 DCHECK(target_profile); 53 54 profile_ = target_profile; 55 writer_ = writer; 56 source_profile_ = source_profile; 57 items_ = items; 58 59 if (!CheckForFirefoxLock(source_profile)) { 60 Cancel(); 61 return; 62 } 63 64 CheckForLoadedModels(items); 65 66 LaunchImportIfReady(); 67 } 68 69 void ExternalProcessImporterHost::NotifyImportStarted() { 70 if (observer_) 71 observer_->ImportStarted(); 72 } 73 74 void ExternalProcessImporterHost::NotifyImportItemStarted( 75 importer::ImportItem item) { 76 if (observer_) 77 observer_->ImportItemStarted(item); 78 } 79 80 void ExternalProcessImporterHost::NotifyImportItemEnded( 81 importer::ImportItem item) { 82 if (observer_) 83 observer_->ImportItemEnded(item); 84 } 85 86 void ExternalProcessImporterHost::NotifyImportEnded() { 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 88 firefox_lock_.reset(); 89 if (observer_) 90 observer_->ImportEnded(); 91 delete this; 92 } 93 94 ExternalProcessImporterHost::~ExternalProcessImporterHost() { 95 if (installed_bookmark_observer_) { 96 DCHECK(profile_); 97 BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); 98 } 99 } 100 101 void ExternalProcessImporterHost::LaunchImportIfReady() { 102 if (waiting_for_bookmarkbar_model_ || !registrar_.IsEmpty() || 103 !is_source_readable_ || cancelled_) 104 return; 105 106 // This is the in-process half of the bridge, which catches data from the IPC 107 // pipe and feeds it to the ProfileWriter. The external process half of the 108 // bridge lives in the external process (see ProfileImportThread). 109 // The ExternalProcessImporterClient created in the next line owns the bridge, 110 // and will delete it. 111 InProcessImporterBridge* bridge = 112 new InProcessImporterBridge(writer_.get(), 113 weak_ptr_factory_.GetWeakPtr()); 114 client_ = new ExternalProcessImporterClient(this, source_profile_, items_, 115 bridge); 116 import_process_launched_ = true; 117 client_->Start(); 118 } 119 120 void ExternalProcessImporterHost::Loaded(BookmarkModel* model, 121 bool ids_reassigned) { 122 DCHECK(model->loaded()); 123 model->RemoveObserver(this); 124 waiting_for_bookmarkbar_model_ = false; 125 installed_bookmark_observer_ = false; 126 127 LaunchImportIfReady(); 128 } 129 130 void ExternalProcessImporterHost::BookmarkModelBeingDeleted( 131 BookmarkModel* model) { 132 installed_bookmark_observer_ = false; 133 } 134 135 void ExternalProcessImporterHost::BookmarkModelChanged() { 136 } 137 138 void ExternalProcessImporterHost::Observe(int type, 139 const content::NotificationSource& source, 140 const content::NotificationDetails& details) { 141 DCHECK_EQ(type, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED); 142 registrar_.RemoveAll(); 143 LaunchImportIfReady(); 144 } 145 146 void ExternalProcessImporterHost::ShowWarningDialog() { 147 DCHECK(!headless_); 148 importer::ShowImportLockDialog( 149 parent_window_, 150 base::Bind(&ExternalProcessImporterHost::OnImportLockDialogEnd, 151 weak_ptr_factory_.GetWeakPtr())); 152 } 153 154 void ExternalProcessImporterHost::OnImportLockDialogEnd(bool is_continue) { 155 if (is_continue) { 156 // User chose to continue, then we check the lock again to make 157 // sure that Firefox has been closed. Try to import the settings 158 // if successful. Otherwise, show a warning dialog. 159 firefox_lock_->Lock(); 160 if (firefox_lock_->HasAcquired()) { 161 is_source_readable_ = true; 162 LaunchImportIfReady(); 163 } else { 164 ShowWarningDialog(); 165 } 166 } else { 167 NotifyImportEnded(); 168 } 169 } 170 171 bool ExternalProcessImporterHost::CheckForFirefoxLock( 172 const importer::SourceProfile& source_profile) { 173 if (source_profile.importer_type != importer::TYPE_FIREFOX) 174 return true; 175 176 DCHECK(!firefox_lock_.get()); 177 firefox_lock_.reset(new FirefoxProfileLock(source_profile.source_path)); 178 if (firefox_lock_->HasAcquired()) 179 return true; 180 181 // If fail to acquire the lock, we set the source unreadable and 182 // show a warning dialog, unless running without UI (in which case the import 183 // must be aborted). 184 is_source_readable_ = false; 185 if (headless_) 186 return false; 187 188 ShowWarningDialog(); 189 return true; 190 } 191 192 void ExternalProcessImporterHost::CheckForLoadedModels(uint16 items) { 193 // A target profile must be loaded by StartImportSettings(). 194 DCHECK(profile_); 195 196 // BookmarkModel should be loaded before adding IE favorites. So we observe 197 // the BookmarkModel if needed, and start the task after it has been loaded. 198 if ((items & importer::FAVORITES) && !writer_->BookmarkModelIsLoaded()) { 199 BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); 200 waiting_for_bookmarkbar_model_ = true; 201 installed_bookmark_observer_ = true; 202 } 203 204 // Observes the TemplateURLService if needed to import search engines from the 205 // other browser. We also check to see if we're importing bookmarks because 206 // we can import bookmark keywords from Firefox as search engines. 207 if ((items & importer::SEARCH_ENGINES) || (items & importer::FAVORITES)) { 208 if (!writer_->TemplateURLServiceIsLoaded()) { 209 TemplateURLService* model = 210 TemplateURLServiceFactory::GetForProfile(profile_); 211 registrar_.Add(this, chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED, 212 content::Source<TemplateURLService>(model)); 213 model->Load(); 214 } 215 } 216 } 217