| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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.h" | |
| 6 | |
| 7 #include <map> | |
| 8 | |
| 9 #include "base/file_util.h" | |
| 10 #include "base/gfx/image_operations.h" | |
| 11 #include "base/gfx/png_encoder.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "chrome/browser/bookmarks/bookmark_model.h" | |
| 14 #include "chrome/browser/browser_process.h" | |
| 15 #include "chrome/browser/firefox2_importer.h" | |
| 16 #include "chrome/browser/firefox3_importer.h" | |
| 17 #include "chrome/browser/firefox_importer_utils.h" | |
| 18 #include "chrome/browser/firefox_profile_lock.h" | |
| 19 #include "chrome/browser/ie_importer.h" | |
| 20 #include "chrome/browser/template_url_model.h" | |
| 21 #include "chrome/browser/shell_integration.h" | |
| 22 #include "chrome/browser/webdata/web_data_service.h" | |
| 23 #include "chrome/common/gfx/favicon_size.h" | |
| 24 #include "chrome/common/l10n_util.h" | |
| 25 #include "chrome/common/pref_names.h" | |
| 26 #include "chrome/common/pref_service.h" | |
| 27 #include "chrome/views/window.h" | |
| 28 #include "webkit/glue/image_decoder.h" | |
| 29 | |
| 30 #include "generated_resources.h" | |
| 31 | |
| 32 // ProfileWriter. | |
| 33 | |
| 34 bool ProfileWriter::BookmarkModelIsLoaded() const { | |
| 35 return profile_->GetBookmarkModel()->IsLoaded(); | |
| 36 } | |
| 37 | |
| 38 void ProfileWriter::AddBookmarkModelObserver(BookmarkModelObserver* observer) { | |
| 39 profile_->GetBookmarkModel()->AddObserver(observer); | |
| 40 } | |
| 41 | |
| 42 bool ProfileWriter::TemplateURLModelIsLoaded() const { | |
| 43 return profile_->GetTemplateURLModel()->loaded(); | |
| 44 } | |
| 45 | |
| 46 void ProfileWriter::AddTemplateURLModelObserver( | |
| 47 NotificationObserver* observer) { | |
| 48 TemplateURLModel* model = profile_->GetTemplateURLModel(); | |
| 49 NotificationService::current()->AddObserver( | |
| 50 observer, TEMPLATE_URL_MODEL_LOADED, | |
| 51 Source<TemplateURLModel>(model)); | |
| 52 model->Load(); | |
| 53 } | |
| 54 | |
| 55 void ProfileWriter::AddPasswordForm(const PasswordForm& form) { | |
| 56 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->AddLogin(form); | |
| 57 } | |
| 58 | |
| 59 void ProfileWriter::AddIE7PasswordInfo(const IE7PasswordInfo& info) { | |
| 60 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->AddIE7Login(info); | |
| 61 } | |
| 62 | |
| 63 void ProfileWriter::AddHistoryPage(const std::vector<history::URLRow>& page) { | |
| 64 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)-> | |
| 65 AddPagesWithDetails(page); | |
| 66 } | |
| 67 | |
| 68 void ProfileWriter::AddHomepage(const GURL& home_page) { | |
| 69 DCHECK(profile_); | |
| 70 | |
| 71 PrefService* prefs = profile_->GetPrefs(); | |
| 72 // NOTE: We set the kHomePage value, but keep the NewTab page as the homepage. | |
| 73 prefs->SetString(prefs::kHomePage, ASCIIToWide(home_page.spec())); | |
| 74 prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread()); | |
| 75 } | |
| 76 | |
| 77 void ProfileWriter::AddBookmarkEntry( | |
| 78 const std::vector<BookmarkEntry>& bookmark) { | |
| 79 BookmarkModel* model = profile_->GetBookmarkModel(); | |
| 80 DCHECK(model->IsLoaded()); | |
| 81 | |
| 82 bool show_bookmark_toolbar = false; | |
| 83 std::set<BookmarkNode*> groups_added_to; | |
| 84 for (std::vector<BookmarkEntry>::const_iterator it = bookmark.begin(); | |
| 85 it != bookmark.end(); ++it) { | |
| 86 // Don't insert this url if it exists in model or url is not valid. | |
| 87 if (model->GetNodeByURL(it->url) != NULL || !it->url.is_valid()) | |
| 88 continue; | |
| 89 | |
| 90 // Set up groups in BookmarkModel in such a way that path[i] is | |
| 91 // the subgroup of path[i-1]. Finally they construct a path in the | |
| 92 // model: | |
| 93 // path[0] \ path[1] \ ... \ path[size() - 1] | |
| 94 BookmarkNode* parent = | |
| 95 (it->in_toolbar ? model->GetBookmarkBarNode() : model->other_node()); | |
| 96 for (std::vector<std::wstring>::const_iterator i = it->path.begin(); | |
| 97 i != it->path.end(); ++i) { | |
| 98 BookmarkNode* child = NULL; | |
| 99 for (int index = 0; index < parent->GetChildCount(); ++index) { | |
| 100 BookmarkNode* node = parent->GetChild(index); | |
| 101 if ((node->GetType() == history::StarredEntry::BOOKMARK_BAR || | |
| 102 node->GetType() == history::StarredEntry::USER_GROUP) && | |
| 103 node->GetTitle() == *i) { | |
| 104 child = node; | |
| 105 break; | |
| 106 } | |
| 107 } | |
| 108 if (child == NULL) | |
| 109 child = model->AddGroup(parent, parent->GetChildCount(), *i); | |
| 110 parent = child; | |
| 111 } | |
| 112 groups_added_to.insert(parent); | |
| 113 model->AddURLWithCreationTime(parent, parent->GetChildCount(), | |
| 114 it->title, it->url, it->creation_time); | |
| 115 | |
| 116 // If some items are put into toolbar, it looks like the user was using | |
| 117 // it in their last browser. We turn on the bookmarks toolbar. | |
| 118 if (it->in_toolbar) | |
| 119 show_bookmark_toolbar = true; | |
| 120 } | |
| 121 | |
| 122 // Reset the date modified time of the groups we added to. We do this to | |
| 123 // make sure the 'recently added to' combobox in the bubble doesn't get random | |
| 124 // groups. | |
| 125 for (std::set<BookmarkNode*>::const_iterator i = groups_added_to.begin(); | |
| 126 i != groups_added_to.end(); ++i) { | |
| 127 model->ResetDateGroupModified(*i); | |
| 128 } | |
| 129 | |
| 130 if (show_bookmark_toolbar) | |
| 131 ShowBookmarkBar(); | |
| 132 } | |
| 133 | |
| 134 void ProfileWriter::AddFavicons( | |
| 135 const std::vector<history::ImportedFavIconUsage>& favicons) { | |
| 136 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)-> | |
| 137 SetImportedFavicons(favicons); | |
| 138 } | |
| 139 | |
| 140 typedef std::map<std::string, const TemplateURL*> HostPathMap; | |
| 141 | |
| 142 // Builds the key to use in HostPathMap for the specified TemplateURL. Returns | |
| 143 // an empty string if a host+path can't be generated for the TemplateURL. | |
| 144 // If an empty string is returned, it should not be added to HostPathMap. | |
| 145 static std::string BuildHostPathKey(const TemplateURL* t_url) { | |
| 146 if (t_url->url() && t_url->url()->SupportsReplacement()) { | |
| 147 GURL search_url(t_url->url()->ReplaceSearchTerms( | |
| 148 *t_url, L"random string", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, | |
| 149 std::wstring())); | |
| 150 if (search_url.is_valid()) | |
| 151 return search_url.host() + search_url.path(); | |
| 152 } | |
| 153 return std::string(); | |
| 154 } | |
| 155 | |
| 156 // Builds a set that contains an entry of the host+path for each TemplateURL in | |
| 157 // the TemplateURLModel that has a valid search url. | |
| 158 static void BuildHostPathMap(const TemplateURLModel& model, | |
| 159 HostPathMap* host_path_map) { | |
| 160 std::vector<const TemplateURL*> template_urls = model.GetTemplateURLs(); | |
| 161 for (size_t i = 0; i < template_urls.size(); ++i) { | |
| 162 const std::string host_path = BuildHostPathKey(template_urls[i]); | |
| 163 if (!host_path.empty()) { | |
| 164 const TemplateURL* existing_turl = (*host_path_map)[host_path]; | |
| 165 if (!existing_turl || | |
| 166 (template_urls[i]->show_in_default_list() && | |
| 167 !existing_turl->show_in_default_list())) { | |
| 168 // If there are multiple TemplateURLs with the same host+path, favor | |
| 169 // those shown in the default list. If there are multiple potential | |
| 170 // defaults, favor the first one, which should be the more commonly used | |
| 171 // one. | |
| 172 (*host_path_map)[host_path] = template_urls[i]; | |
| 173 } | |
| 174 } // else case, TemplateURL doesn't have a search url, doesn't support | |
| 175 // replacement, or doesn't have valid GURL. Ignore it. | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 void ProfileWriter::AddKeywords(const std::vector<TemplateURL*>& template_urls, | |
| 180 int default_keyword_index, | |
| 181 bool unique_on_host_and_path) { | |
| 182 TemplateURLModel* model = profile_->GetTemplateURLModel(); | |
| 183 HostPathMap host_path_map; | |
| 184 if (unique_on_host_and_path) | |
| 185 BuildHostPathMap(*model, &host_path_map); | |
| 186 | |
| 187 for (std::vector<TemplateURL*>::const_iterator i = template_urls.begin(); | |
| 188 i != template_urls.end(); ++i) { | |
| 189 TemplateURL* t_url = *i; | |
| 190 bool default_keyword = | |
| 191 default_keyword_index >= 0 && | |
| 192 (i - template_urls.begin() == default_keyword_index); | |
| 193 | |
| 194 // TemplateURLModel requires keywords to be unique. If there is already a | |
| 195 // TemplateURL with this keyword, don't import it again. | |
| 196 const TemplateURL* turl_with_keyword = | |
| 197 model->GetTemplateURLForKeyword(t_url->keyword()); | |
| 198 if (turl_with_keyword != NULL) { | |
| 199 if (default_keyword) | |
| 200 model->SetDefaultSearchProvider(turl_with_keyword); | |
| 201 delete t_url; | |
| 202 continue; | |
| 203 } | |
| 204 | |
| 205 // For search engines if there is already a keyword with the same | |
| 206 // host+path, we don't import it. This is done to avoid both duplicate | |
| 207 // search providers (such as two Googles, or two Yahoos) as well as making | |
| 208 // sure the search engines we provide aren't replaced by those from the | |
| 209 // imported browser. | |
| 210 if (unique_on_host_and_path && | |
| 211 host_path_map.find(BuildHostPathKey(t_url)) != host_path_map.end()) { | |
| 212 if (default_keyword) { | |
| 213 const TemplateURL* turl_with_host_path = | |
| 214 host_path_map[BuildHostPathKey(t_url)]; | |
| 215 if (turl_with_host_path) | |
| 216 model->SetDefaultSearchProvider(turl_with_host_path); | |
| 217 else | |
| 218 NOTREACHED(); // BuildHostPathMap should only insert non-null values. | |
| 219 } | |
| 220 delete t_url; | |
| 221 continue; | |
| 222 } | |
| 223 model->Add(t_url); | |
| 224 if (default_keyword) | |
| 225 model->SetDefaultSearchProvider(t_url); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 void ProfileWriter::ShowBookmarkBar() { | |
| 230 DCHECK(profile_); | |
| 231 | |
| 232 PrefService* prefs = profile_->GetPrefs(); | |
| 233 // Check whether the bookmark bar is shown in current pref. | |
| 234 if (!prefs->GetBoolean(prefs::kShowBookmarkBar)) { | |
| 235 // Set the pref and notify the notification service. | |
| 236 prefs->SetBoolean(prefs::kShowBookmarkBar, true); | |
| 237 prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread()); | |
| 238 Source<Profile> source(profile_); | |
| 239 NotificationService::current()->Notify( | |
| 240 NOTIFY_BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, source, | |
| 241 NotificationService::NoDetails()); | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 // Importer. | |
| 246 | |
| 247 // static | |
| 248 bool Importer::ReencodeFavicon(const unsigned char* src_data, size_t src_len, | |
| 249 std::vector<unsigned char>* png_data) { | |
| 250 // Decode the favicon using WebKit's image decoder. | |
| 251 webkit_glue::ImageDecoder decoder(gfx::Size(kFavIconSize, kFavIconSize)); | |
| 252 SkBitmap decoded = decoder.Decode(src_data, src_len); | |
| 253 if (decoded.empty()) | |
| 254 return false; // Unable to decode. | |
| 255 | |
| 256 if (decoded.width() != kFavIconSize || decoded.height() != kFavIconSize) { | |
| 257 // The bitmap is not the correct size, re-sample. | |
| 258 int new_width = decoded.width(); | |
| 259 int new_height = decoded.height(); | |
| 260 calc_favicon_target_size(&new_width, &new_height); | |
| 261 decoded = gfx::ImageOperations::Resize( | |
| 262 decoded, gfx::ImageOperations::RESIZE_LANCZOS3, | |
| 263 gfx::Size(new_width, new_height)); | |
| 264 } | |
| 265 | |
| 266 // Encode our bitmap as a PNG. | |
| 267 SkAutoLockPixels decoded_lock(decoded); | |
| 268 PNGEncoder::Encode(reinterpret_cast<unsigned char*>(decoded.getPixels()), | |
| 269 PNGEncoder::FORMAT_BGRA, decoded.width(), | |
| 270 decoded.height(), decoded.width() * 4, false, png_data); | |
| 271 return true; | |
| 272 } | |
| 273 | |
| 274 // ImporterHost. | |
| 275 | |
| 276 ImporterHost::ImporterHost() | |
| 277 : observer_(NULL), | |
| 278 task_(NULL), | |
| 279 importer_(NULL), | |
| 280 file_loop_(g_browser_process->file_thread()->message_loop()), | |
| 281 waiting_for_bookmarkbar_model_(false), | |
| 282 waiting_for_template_url_model_(false), | |
| 283 is_source_readable_(true) { | |
| 284 DetectSourceProfiles(); | |
| 285 } | |
| 286 | |
| 287 ImporterHost::ImporterHost(MessageLoop* file_loop) | |
| 288 : observer_(NULL), | |
| 289 task_(NULL), | |
| 290 importer_(NULL), | |
| 291 file_loop_(file_loop), | |
| 292 waiting_for_bookmarkbar_model_(false), | |
| 293 waiting_for_template_url_model_(false), | |
| 294 is_source_readable_(true) { | |
| 295 DetectSourceProfiles(); | |
| 296 } | |
| 297 | |
| 298 ImporterHost::~ImporterHost() { | |
| 299 STLDeleteContainerPointers(source_profiles_.begin(), source_profiles_.end()); | |
| 300 } | |
| 301 | |
| 302 void ImporterHost::Loaded(BookmarkModel* model) { | |
| 303 model->RemoveObserver(this); | |
| 304 waiting_for_bookmarkbar_model_ = false; | |
| 305 InvokeTaskIfDone(); | |
| 306 } | |
| 307 | |
| 308 void ImporterHost::Observe(NotificationType type, | |
| 309 const NotificationSource& source, | |
| 310 const NotificationDetails& details) { | |
| 311 DCHECK(type == TEMPLATE_URL_MODEL_LOADED); | |
| 312 TemplateURLModel* model = Source<TemplateURLModel>(source).ptr(); | |
| 313 NotificationService::current()->RemoveObserver( | |
| 314 this, TEMPLATE_URL_MODEL_LOADED, | |
| 315 Source<TemplateURLModel>(model)); | |
| 316 waiting_for_template_url_model_ = false; | |
| 317 InvokeTaskIfDone(); | |
| 318 } | |
| 319 | |
| 320 void ImporterHost::ShowWarningDialog() { | |
| 321 ChromeViews::Window::CreateChromeWindow(GetActiveWindow(), gfx::Rect(), | |
| 322 new ImporterLockView(this))->Show(); | |
| 323 } | |
| 324 | |
| 325 void ImporterHost::OnLockViewEnd(bool is_continue) { | |
| 326 if (is_continue) { | |
| 327 // User chose to continue, then we check the lock again to make | |
| 328 // sure that Firefox has been closed. Try to import the settings | |
| 329 // if successful. Otherwise, show a warning dialog. | |
| 330 firefox_lock_->Lock(); | |
| 331 if (firefox_lock_->HasAcquired()) { | |
| 332 is_source_readable_ = true; | |
| 333 InvokeTaskIfDone(); | |
| 334 } else { | |
| 335 ShowWarningDialog(); | |
| 336 } | |
| 337 } else { | |
| 338 // User chose to skip the import process. We should delete | |
| 339 // the task and notify the ImporterHost to finish. | |
| 340 delete task_; | |
| 341 task_ = NULL; | |
| 342 importer_ = NULL; | |
| 343 ImportEnded(); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 void ImporterHost::StartImportSettings(const ProfileInfo& profile_info, | |
| 348 uint16 items, | |
| 349 ProfileWriter* writer, | |
| 350 bool first_run) { | |
| 351 // Preserves the observer and creates a task, since we do async import | |
| 352 // so that it doesn't block the UI. When the import is complete, observer | |
| 353 // will be notified. | |
| 354 writer_ = writer; | |
| 355 importer_ = CreateImporterByType(profile_info.browser_type); | |
| 356 importer_->set_first_run(first_run); | |
| 357 task_ = NewRunnableMethod(importer_, &Importer::StartImport, | |
| 358 profile_info, items, writer_.get(), this); | |
| 359 | |
| 360 // We should lock the Firefox profile directory to prevent corruption. | |
| 361 if (profile_info.browser_type == FIREFOX2 || | |
| 362 profile_info.browser_type == FIREFOX3) { | |
| 363 firefox_lock_.reset(new FirefoxProfileLock(profile_info.source_path)); | |
| 364 if (!firefox_lock_->HasAcquired()) { | |
| 365 // If fail to acquire the lock, we set the source unreadable and | |
| 366 // show a warning dialog. | |
| 367 is_source_readable_ = false; | |
| 368 ShowWarningDialog(); | |
| 369 } | |
| 370 } | |
| 371 | |
| 372 // BookmarkModel should be loaded before adding IE favorites. So we observe | |
| 373 // the BookmarkModel if needed, and start the task after it has been loaded. | |
| 374 if ((items & FAVORITES) && !writer_->BookmarkModelIsLoaded()) { | |
| 375 writer_->AddBookmarkModelObserver(this); | |
| 376 waiting_for_bookmarkbar_model_ = true; | |
| 377 } | |
| 378 | |
| 379 // Observes the TemplateURLModel if needed to import search engines from the | |
| 380 // other browser. We also check to see if we're importing bookmarks because | |
| 381 // we can import bookmark keywords from Firefox as search engines. | |
| 382 if ((items & SEARCH_ENGINES) || (items & FAVORITES)) { | |
| 383 if (!writer_->TemplateURLModelIsLoaded()) { | |
| 384 writer_->AddTemplateURLModelObserver(this); | |
| 385 waiting_for_template_url_model_ = true; | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 AddRef(); | |
| 390 InvokeTaskIfDone(); | |
| 391 } | |
| 392 | |
| 393 void ImporterHost::Cancel() { | |
| 394 if (importer_) | |
| 395 importer_->Cancel(); | |
| 396 } | |
| 397 | |
| 398 void ImporterHost::SetObserver(Observer* observer) { | |
| 399 observer_ = observer; | |
| 400 } | |
| 401 | |
| 402 void ImporterHost::InvokeTaskIfDone() { | |
| 403 if (waiting_for_bookmarkbar_model_ || waiting_for_template_url_model_ || | |
| 404 !is_source_readable_) | |
| 405 return; | |
| 406 file_loop_->PostTask(FROM_HERE, task_); | |
| 407 } | |
| 408 | |
| 409 void ImporterHost::ImportItemStarted(ImportItem item) { | |
| 410 if (observer_) | |
| 411 observer_->ImportItemStarted(item); | |
| 412 } | |
| 413 | |
| 414 void ImporterHost::ImportItemEnded(ImportItem item) { | |
| 415 if (observer_) | |
| 416 observer_->ImportItemEnded(item); | |
| 417 } | |
| 418 | |
| 419 void ImporterHost::ImportStarted() { | |
| 420 if (observer_) | |
| 421 observer_->ImportStarted(); | |
| 422 } | |
| 423 | |
| 424 void ImporterHost::ImportEnded() { | |
| 425 firefox_lock_.reset(); // Release the Firefox profile lock. | |
| 426 if (observer_) | |
| 427 observer_->ImportEnded(); | |
| 428 Release(); | |
| 429 } | |
| 430 | |
| 431 Importer* ImporterHost::CreateImporterByType(ProfileType type) { | |
| 432 switch (type) { | |
| 433 case MS_IE: | |
| 434 return new IEImporter(); | |
| 435 case FIREFOX2: | |
| 436 return new Firefox2Importer(); | |
| 437 case FIREFOX3: | |
| 438 return new Firefox3Importer(); | |
| 439 } | |
| 440 NOTREACHED(); | |
| 441 return NULL; | |
| 442 } | |
| 443 | |
| 444 int ImporterHost::GetAvailableProfileCount() { | |
| 445 return static_cast<int>(source_profiles_.size()); | |
| 446 } | |
| 447 | |
| 448 std::wstring ImporterHost::GetSourceProfileNameAt(int index) const { | |
| 449 DCHECK(index < static_cast<int>(source_profiles_.size())); | |
| 450 return source_profiles_[index]->description; | |
| 451 } | |
| 452 | |
| 453 const ProfileInfo& ImporterHost::GetSourceProfileInfoAt(int index) const { | |
| 454 DCHECK(index < static_cast<int>(source_profiles_.size())); | |
| 455 return *source_profiles_[index]; | |
| 456 } | |
| 457 | |
| 458 void ImporterHost::DetectSourceProfiles() { | |
| 459 if (ShellIntegration::IsFirefoxDefaultBrowser()) { | |
| 460 DetectFirefoxProfiles(); | |
| 461 DetectIEProfiles(); | |
| 462 } else { | |
| 463 DetectIEProfiles(); | |
| 464 DetectFirefoxProfiles(); | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 void ImporterHost::DetectIEProfiles() { | |
| 469 // IE always exists and don't have multiple profiles. | |
| 470 ProfileInfo* ie = new ProfileInfo(); | |
| 471 ie->description = l10n_util::GetString(IDS_IMPORT_FROM_IE); | |
| 472 ie->browser_type = MS_IE; | |
| 473 ie->source_path.clear(); | |
| 474 ie->app_path.clear(); | |
| 475 source_profiles_.push_back(ie); | |
| 476 } | |
| 477 | |
| 478 void ImporterHost::DetectFirefoxProfiles() { | |
| 479 // Detects which version of Firefox is installed. | |
| 480 int version = GetCurrentFirefoxMajorVersion(); | |
| 481 ProfileType firefox_type; | |
| 482 if (version == 2) { | |
| 483 firefox_type = FIREFOX2; | |
| 484 } else if (version == 3) { | |
| 485 firefox_type = FIREFOX3; | |
| 486 } else { | |
| 487 // Ignores other versions of firefox. | |
| 488 return; | |
| 489 } | |
| 490 | |
| 491 std::wstring ini_file = GetProfilesINI(); | |
| 492 DictionaryValue root; | |
| 493 ParseProfileINI(ini_file, &root); | |
| 494 | |
| 495 std::wstring source_path; | |
| 496 for (int i = 0; ; ++i) { | |
| 497 std::wstring current_profile = L"Profile" + IntToWString(i); | |
| 498 if (!root.HasKey(current_profile)) { | |
| 499 // Profiles are continuously numbered. So we exit when we can't | |
| 500 // find the i-th one. | |
| 501 break; | |
| 502 } | |
| 503 std::wstring is_relative, path, profile_path; | |
| 504 if (root.GetString(current_profile + L".IsRelative", &is_relative) && | |
| 505 root.GetString(current_profile + L".Path", &path)) { | |
| 506 ReplaceSubstringsAfterOffset(&path, 0, L"/", L"\\"); | |
| 507 | |
| 508 // IsRelative=1 means the folder path would be relative to the | |
| 509 // path of profiles.ini. IsRelative=0 refers to a custom profile | |
| 510 // location. | |
| 511 if (is_relative == L"1") { | |
| 512 profile_path = file_util::GetDirectoryFromPath(ini_file); | |
| 513 file_util::AppendToPath(&profile_path, path); | |
| 514 } else { | |
| 515 profile_path = path; | |
| 516 } | |
| 517 | |
| 518 // We only import the default profile when multiple profiles exist, | |
| 519 // since the other profiles are used mostly by developers for testing. | |
| 520 // Otherwise, Profile0 will be imported. | |
| 521 std::wstring is_default; | |
| 522 if ((root.GetString(current_profile + L".Default", &is_default) && | |
| 523 is_default == L"1") || i == 0) { | |
| 524 source_path = profile_path; | |
| 525 // We break out of the loop when we have found the default profile. | |
| 526 if (is_default == L"1") | |
| 527 break; | |
| 528 } | |
| 529 } | |
| 530 } | |
| 531 | |
| 532 if (!source_path.empty()) { | |
| 533 ProfileInfo* firefox = new ProfileInfo(); | |
| 534 firefox->description = l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX); | |
| 535 firefox->browser_type = firefox_type; | |
| 536 firefox->source_path = source_path; | |
| 537 firefox->app_path = GetFirefoxInstallPath(); | |
| 538 source_profiles_.push_back(firefox); | |
| 539 } | |
| 540 } | |
| 541 | |
| OLD | NEW |