| Index: chrome/browser/firefox2_importer.cc
|
| ===================================================================
|
| --- chrome/browser/firefox2_importer.cc (revision 2150)
|
| +++ chrome/browser/firefox2_importer.cc (working copy)
|
| @@ -1,515 +0,0 @@
|
| -// Copyright (c) 2006-2008 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/firefox2_importer.h"
|
| -
|
| -#include "base/file_util.h"
|
| -#include "base/path_service.h"
|
| -#include "base/registry.h"
|
| -#include "base/string_util.h"
|
| -#include "base/values.h"
|
| -#include "chrome/browser/firefox_importer_utils.h"
|
| -#include "chrome/browser/mork_reader.h"
|
| -#include "chrome/browser/template_url.h"
|
| -#include "chrome/browser/template_url_parser.h"
|
| -#include "chrome/common/l10n_util.h"
|
| -#include "chrome/common/time_format.h"
|
| -#include "generated_resources.h"
|
| -#include "net/base/data_url.h"
|
| -
|
| -// Firefox2Importer.
|
| -
|
| -Firefox2Importer::Firefox2Importer() {
|
| -}
|
| -
|
| -Firefox2Importer::~Firefox2Importer() {
|
| -}
|
| -
|
| -void Firefox2Importer::StartImport(ProfileInfo profile_info,
|
| - uint16 items, ProfileWriter* writer,
|
| - ImporterHost* host) {
|
| - writer_ = writer;
|
| - source_path_ = profile_info.source_path;
|
| - app_path_ = profile_info.app_path;
|
| - importer_host_ = host;
|
| -
|
| - // The order here is important!
|
| - NotifyStarted();
|
| - if ((items & HOME_PAGE) && !cancelled())
|
| - ImportHomepage(); // Doesn't have a UI item.
|
| - if ((items & FAVORITES) && !cancelled()) {
|
| - NotifyItemStarted(FAVORITES);
|
| - ImportBookmarks();
|
| - NotifyItemEnded(FAVORITES);
|
| - }
|
| - if ((items & SEARCH_ENGINES) && !cancelled()) {
|
| - NotifyItemStarted(SEARCH_ENGINES);
|
| - ImportSearchEngines();
|
| - NotifyItemEnded(SEARCH_ENGINES);
|
| - }
|
| - if ((items & PASSWORDS) && !cancelled()) {
|
| - NotifyItemStarted(PASSWORDS);
|
| - ImportPasswords();
|
| - NotifyItemEnded(PASSWORDS);
|
| - }
|
| - if ((items & HISTORY) && !cancelled()) {
|
| - NotifyItemStarted(HISTORY);
|
| - ImportHistory();
|
| - NotifyItemEnded(HISTORY);
|
| - }
|
| - NotifyEnded();
|
| -}
|
| -
|
| -// static
|
| -void Firefox2Importer::LoadDefaultBookmarks(const std::wstring& app_path,
|
| - std::set<GURL> *urls) {
|
| - // Firefox keeps its default bookmarks in a bookmarks.html file that
|
| - // lives at: <Firefox install dir>\defaults\profile\bookmarks.html
|
| - std::wstring file = app_path;
|
| - file_util::AppendToPath(&file, L"defaults\\profile\\bookmarks.html");
|
| -
|
| - urls->clear();
|
| -
|
| - // Read the whole file.
|
| - std::string content;
|
| - file_util::ReadFileToString(file, &content);
|
| - std::vector<std::string> lines;
|
| - SplitString(content, '\n', &lines);
|
| -
|
| - std::string charset;
|
| - for (size_t i = 0; i < lines.size(); ++i) {
|
| - std::string line;
|
| - TrimString(lines[i], " ", &line);
|
| -
|
| - // Get the encoding of the bookmark file.
|
| - if (ParseCharsetFromLine(line, &charset))
|
| - continue;
|
| -
|
| - // Get the bookmark.
|
| - std::wstring title;
|
| - GURL url, favicon;
|
| - std::wstring shortcut;
|
| - Time add_date;
|
| - std::wstring post_data;
|
| - if (ParseBookmarkFromLine(line, charset, &title, &url,
|
| - &favicon, &shortcut, &add_date,
|
| - &post_data))
|
| - urls->insert(url);
|
| - }
|
| -}
|
| -
|
| -// static
|
| -TemplateURL* Firefox2Importer::CreateTemplateURL(const std::wstring& title,
|
| - const std::wstring& keyword,
|
| - const GURL& url) {
|
| - // Skip if the keyword or url is invalid.
|
| - if (keyword.empty() && url.is_valid())
|
| - return NULL;
|
| -
|
| - TemplateURL* t_url = new TemplateURL();
|
| - // We set short name by using the title if it exists.
|
| - // Otherwise, we use the shortcut.
|
| - t_url->set_short_name(!title.empty() ? title : keyword);
|
| - t_url->set_keyword(keyword);
|
| - t_url->SetURL(TemplateURLRef::DisplayURLToURLRef(UTF8ToWide(url.spec())),
|
| - 0, 0);
|
| - return t_url;
|
| -}
|
| -
|
| -void Firefox2Importer::ImportBookmarks() {
|
| - // Read the whole file.
|
| - std::wstring file = source_path_;
|
| - file_util::AppendToPath(&file, L"bookmarks.html");
|
| - std::string content;
|
| - file_util::ReadFileToString(file, &content);
|
| - std::vector<std::string> lines;
|
| - SplitString(content, '\n', &lines);
|
| -
|
| - // Load the default bookmarks.
|
| - std::set<GURL> default_urls;
|
| - LoadDefaultBookmarks(app_path_, &default_urls);
|
| -
|
| - // Parse the bookmarks.html file.
|
| - std::vector<ProfileWriter::BookmarkEntry> bookmarks, toolbar_bookmarks;
|
| - std::vector<TemplateURL*> template_urls;
|
| - std::vector<history::ImportedFavIconUsage> favicons;
|
| - std::wstring last_folder
|
| - = l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX);
|
| - bool last_folder_on_toolbar = false;
|
| - std::vector<std::wstring> path;
|
| - size_t toolbar_folder = 0;
|
| - std::string charset;
|
| - for (size_t i = 0; i < lines.size() && !cancelled(); ++i) {
|
| - std::string line;
|
| - TrimString(lines[i], " ", &line);
|
| -
|
| - // Get the encoding of the bookmark file.
|
| - if (ParseCharsetFromLine(line, &charset))
|
| - continue;
|
| -
|
| - // Get the folder name.
|
| - if (ParseFolderNameFromLine(line, charset, &last_folder,
|
| - &last_folder_on_toolbar))
|
| - continue;
|
| -
|
| - // Get the bookmark entry.
|
| - std::wstring title, shortcut;
|
| - GURL url, favicon;
|
| - Time add_date;
|
| - std::wstring post_data;
|
| - // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based
|
| - // keywords yet.
|
| - if (ParseBookmarkFromLine(line, charset, &title,
|
| - &url, &favicon, &shortcut, &add_date,
|
| - &post_data) &&
|
| - post_data.empty() &&
|
| - CanImportURL(GURL(url)) &&
|
| - default_urls.find(url) == default_urls.end()) {
|
| - if (toolbar_folder > path.size() && path.size() > 0) {
|
| - NOTREACHED(); // error in parsing.
|
| - break;
|
| - }
|
| -
|
| - ProfileWriter::BookmarkEntry entry;
|
| - entry.creation_time = add_date;
|
| - entry.url = url;
|
| - entry.title = title;
|
| -
|
| - if (first_run() && toolbar_folder) {
|
| - // Flatten the items in toolbar.
|
| - entry.in_toolbar = true;
|
| - entry.path.assign(path.begin() + toolbar_folder, path.end());
|
| - toolbar_bookmarks.push_back(entry);
|
| - } else {
|
| - // Insert the item into the "Imported from Firefox" folder after
|
| - // the first run.
|
| - entry.path.assign(path.begin(), path.end());
|
| - if (first_run())
|
| - entry.path.erase(entry.path.begin());
|
| - bookmarks.push_back(entry);
|
| - }
|
| -
|
| - // Save the favicon. DataURLToFaviconUsage will handle the case where
|
| - // there is no favicon.
|
| - DataURLToFaviconUsage(url, favicon, &favicons);
|
| -
|
| - // If there is a SHORTCUT attribute for this bookmark, we
|
| - // add it as our keywords.
|
| - TemplateURL* t_url = CreateTemplateURL(title, shortcut, url);
|
| - if (t_url)
|
| - template_urls.push_back(t_url);
|
| -
|
| - continue;
|
| - }
|
| -
|
| - // Bookmarks in sub-folder are encapsulated with <DL> tag.
|
| - if (StartsWithASCII(line, "<DL>", true)) {
|
| - path.push_back(last_folder);
|
| - last_folder.clear();
|
| - if (last_folder_on_toolbar && !toolbar_folder)
|
| - toolbar_folder = path.size();
|
| - } else if (StartsWithASCII(line, "</DL>", true)) {
|
| - if (path.empty())
|
| - break; // Mismatch <DL>.
|
| - path.pop_back();
|
| - if (toolbar_folder > path.size())
|
| - toolbar_folder = 0;
|
| - }
|
| - }
|
| -
|
| - // Write data into profile.
|
| - bookmarks.insert(bookmarks.begin(), toolbar_bookmarks.begin(),
|
| - toolbar_bookmarks.end());
|
| - if (!bookmarks.empty() && !cancelled()) {
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddBookmarkEntry, bookmarks));
|
| - }
|
| - if (!template_urls.empty() && !cancelled()) {
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddKeywords, template_urls, -1, false));
|
| - } else {
|
| - STLDeleteContainerPointers(template_urls.begin(), template_urls.end());
|
| - }
|
| - if (!favicons.empty()) {
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddFavicons, favicons));
|
| - }
|
| -}
|
| -
|
| -void Firefox2Importer::ImportPasswords() {
|
| - // Initializes NSS3.
|
| - NSSDecryptor decryptor;
|
| - if (!decryptor.Init(source_path_, source_path_) &&
|
| - !decryptor.Init(app_path_, source_path_))
|
| - return;
|
| -
|
| - // Firefox 2 uses signons2.txt to store the pssswords. If it doesn't
|
| - // exist, we try to find its older version.
|
| - std::wstring file = source_path_;
|
| - file_util::AppendToPath(&file, L"signons2.txt");
|
| - if (!file_util::PathExists(file)) {
|
| - file = source_path_;
|
| - file_util::AppendToPath(&file, L"signons.txt");
|
| - }
|
| -
|
| - std::string content;
|
| - file_util::ReadFileToString(file, &content);
|
| - std::vector<PasswordForm> forms;
|
| - decryptor.ParseSignons(content, &forms);
|
| -
|
| - if (!cancelled()) {
|
| - for (size_t i = 0; i < forms.size(); ++i) {
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddPasswordForm, forms[i]));
|
| - }
|
| - }
|
| -}
|
| -
|
| -void Firefox2Importer::ImportHistory() {
|
| - std::wstring file = source_path_;
|
| - file_util::AppendToPath(&file, L"history.dat");
|
| - ImportHistoryFromFirefox2(file, main_loop_, writer_);
|
| -}
|
| -
|
| -void Firefox2Importer::ImportSearchEngines() {
|
| - std::vector<std::wstring> files;
|
| - GetSearchEnginesXMLFiles(&files);
|
| -
|
| - std::vector<TemplateURL*> search_engines;
|
| - ParseSearchEnginesFromXMLFiles(files, &search_engines);
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddKeywords, search_engines,
|
| - GetFirefoxDefaultSearchEngineIndex(search_engines, source_path_),
|
| - true));
|
| -}
|
| -
|
| -void Firefox2Importer::ImportHomepage() {
|
| - GURL homepage = GetHomepage(source_path_);
|
| - if (homepage.is_valid() && !IsDefaultHomepage(homepage, app_path_)) {
|
| - main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
|
| - &ProfileWriter::AddHomepage, homepage));
|
| - }
|
| -}
|
| -
|
| -void Firefox2Importer::GetSearchEnginesXMLFiles(
|
| - std::vector<std::wstring>* files) {
|
| - // Search engines are contained in XML files in a searchplugins directory that
|
| - // can be found in 2 locations:
|
| - // - Firefox install dir (default search engines)
|
| - // - the profile dir (user added search engines)
|
| - std::wstring dir(app_path_);
|
| - file_util::AppendToPath(&dir, L"searchplugins");
|
| - FindXMLFilesInDir(dir, files);
|
| -
|
| - std::wstring profile_dir = source_path_;
|
| - file_util::AppendToPath(&profile_dir, L"searchplugins");
|
| - FindXMLFilesInDir(profile_dir, files);
|
| -}
|
| -
|
| -// static
|
| -bool Firefox2Importer::ParseCharsetFromLine(const std::string& line,
|
| - std::string* charset) {
|
| - const char kCharset[] = "charset=";
|
| - if (StartsWithASCII(line, "<META", true) &&
|
| - line.find("CONTENT=\"") != std::string::npos) {
|
| - size_t begin = line.find(kCharset);
|
| - if (begin == std::string::npos)
|
| - return false;
|
| - begin += std::string(kCharset).size();
|
| - size_t end = line.find_first_of('\"', begin);
|
| - *charset = line.substr(begin, end - begin);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// static
|
| -bool Firefox2Importer::ParseFolderNameFromLine(const std::string& line,
|
| - const std::string& charset,
|
| - std::wstring* folder_name,
|
| - bool* is_toolbar_folder) {
|
| - const char kFolderOpen[] = "<DT><H3";
|
| - const char kFolderClose[] = "</H3>";
|
| - const char kToolbarFolderAttribute[] = "PERSONAL_TOOLBAR_FOLDER";
|
| -
|
| - if (!StartsWithASCII(line, kFolderOpen, true))
|
| - return false;
|
| -
|
| - size_t end = line.find(kFolderClose);
|
| - size_t tag_end = line.rfind('>', end) + 1;
|
| - // If no end tag or start tag is broken, we skip to find the folder name.
|
| - if (end == std::string::npos || tag_end < arraysize(kFolderOpen))
|
| - return false;
|
| -
|
| - CodepageToWide(line.substr(tag_end, end - tag_end), charset.c_str(),
|
| - OnStringUtilConversionError::SKIP, folder_name);
|
| - HTMLUnescape(folder_name);
|
| -
|
| - std::string attribute_list = line.substr(arraysize(kFolderOpen),
|
| - tag_end - arraysize(kFolderOpen) - 1);
|
| - std::string value;
|
| - if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
|
| - LowerCaseEqualsASCII(value, "true"))
|
| - *is_toolbar_folder = true;
|
| - else
|
| - *is_toolbar_folder = false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -bool Firefox2Importer::ParseBookmarkFromLine(const std::string& line,
|
| - const std::string& charset,
|
| - std::wstring* title,
|
| - GURL* url,
|
| - GURL* favicon,
|
| - std::wstring* shortcut,
|
| - Time* add_date,
|
| - std::wstring* post_data) {
|
| - const char kItemOpen[] = "<DT><A";
|
| - const char kItemClose[] = "</A>";
|
| - const char kFeedURLAttribute[] = "FEEDURL";
|
| - const char kHrefAttribute[] = "HREF";
|
| - const char kIconAttribute[] = "ICON";
|
| - const char kShortcutURLAttribute[] = "SHORTCUTURL";
|
| - const char kAddDateAttribute[] = "ADD_DATE";
|
| - const char kPostDataAttribute[] = "POST_DATA";
|
| -
|
| - title->clear();
|
| - *url = GURL();
|
| - *favicon = GURL();
|
| - shortcut->clear();
|
| - post_data->clear();
|
| - *add_date = Time();
|
| -
|
| - if (!StartsWithASCII(line, kItemOpen, true))
|
| - return false;
|
| -
|
| - size_t end = line.find(kItemClose);
|
| - size_t tag_end = line.rfind('>', end) + 1;
|
| - if (end == std::string::npos || tag_end < arraysize(kItemOpen))
|
| - return false; // No end tag or start tag is broken.
|
| -
|
| - std::string attribute_list = line.substr(arraysize(kItemOpen),
|
| - tag_end - arraysize(kItemOpen) - 1);
|
| -
|
| - // We don't import Live Bookmark folders, which is Firefox's RSS reading
|
| - // feature, since the user never necessarily bookmarked them and we don't
|
| - // have this feature to update their contents.
|
| - std::string value;
|
| - if (GetAttribute(attribute_list, kFeedURLAttribute, &value))
|
| - return false;
|
| -
|
| - // Title
|
| - CodepageToWide(line.substr(tag_end, end - tag_end), charset.c_str(),
|
| - OnStringUtilConversionError::SKIP, title);
|
| - HTMLUnescape(title);
|
| -
|
| - // URL
|
| - if (GetAttribute(attribute_list, kHrefAttribute, &value)) {
|
| - ReplaceSubstringsAfterOffset(&value, 0, "%22", "\"");
|
| - *url = GURL(value);
|
| - }
|
| -
|
| - // Favicon
|
| - if (GetAttribute(attribute_list, kIconAttribute, &value))
|
| - *favicon = GURL(value);
|
| -
|
| - // Keyword
|
| - if (GetAttribute(attribute_list, kShortcutURLAttribute, &value)) {
|
| - CodepageToWide(value, charset.c_str(), OnStringUtilConversionError::SKIP,
|
| - shortcut);
|
| - HTMLUnescape(shortcut);
|
| - }
|
| -
|
| - // Add date
|
| - if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
|
| - int64 time = StringToInt64(value);
|
| - // Upper bound it at 32 bits.
|
| - if (0 < time && time < (1LL << 32))
|
| - *add_date = Time::FromTimeT(time);
|
| - }
|
| -
|
| - // Post data.
|
| - if (GetAttribute(attribute_list, kPostDataAttribute, &value)) {
|
| - CodepageToWide(value, charset.c_str(),
|
| - OnStringUtilConversionError::SKIP, post_data);
|
| - HTMLUnescape(post_data);
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -bool Firefox2Importer::GetAttribute(const std::string& attribute_list,
|
| - const std::string& attribute,
|
| - std::string* value) {
|
| - const char kQuote[] = "\"";
|
| -
|
| - size_t begin = attribute_list.find(attribute + "=" + kQuote);
|
| - if (begin == std::string::npos)
|
| - return false; // Can't find the attribute.
|
| -
|
| - begin = attribute_list.find(kQuote, begin) + 1;
|
| - size_t end = attribute_list.find(kQuote, begin);
|
| - if (end == std::string::npos)
|
| - return false; // The value is not quoted.
|
| -
|
| - *value = attribute_list.substr(begin, end - begin);
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -void Firefox2Importer::HTMLUnescape(std::wstring *text) {
|
| - ReplaceSubstringsAfterOffset(text, 0, L"<", L"<");
|
| - ReplaceSubstringsAfterOffset(text, 0, L">", L">");
|
| - ReplaceSubstringsAfterOffset(text, 0, L"&", L"&");
|
| - ReplaceSubstringsAfterOffset(text, 0, L""", L"\"");
|
| - ReplaceSubstringsAfterOffset(text, 0, L"'", L"\'");
|
| -}
|
| -
|
| -// static
|
| -void Firefox2Importer::FindXMLFilesInDir(
|
| - const std::wstring& dir,
|
| - std::vector<std::wstring>* xml_files) {
|
| - file_util::FileEnumerator file_enum(dir, false,
|
| - file_util::FileEnumerator::FILES,
|
| - L"*.xml");
|
| - std::wstring file(file_enum.Next());
|
| - while (!file.empty()) {
|
| - xml_files->push_back(file);
|
| - file = file_enum.Next();
|
| - }
|
| -}
|
| -
|
| -// static
|
| -void Firefox2Importer::DataURLToFaviconUsage(
|
| - const GURL& link_url,
|
| - const GURL& favicon_data,
|
| - std::vector<history::ImportedFavIconUsage>* favicons) {
|
| - if (!link_url.is_valid() || !favicon_data.is_valid() ||
|
| - !favicon_data.SchemeIs("data"))
|
| - return;
|
| -
|
| - // Parse the data URL.
|
| - std::string mime_type, char_set, data;
|
| - if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
|
| - data.empty())
|
| - return;
|
| -
|
| - history::ImportedFavIconUsage usage;
|
| - if (!ReencodeFavicon(reinterpret_cast<const unsigned char*>(&data[0]),
|
| - data.size(), &usage.png_data))
|
| - return; // Unable to decode.
|
| -
|
| - // We need to make up a URL for the favicon. We use a version of the page's
|
| - // URL so that we can be sure it will not collide.
|
| - usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
|
| -
|
| - // We only have one URL per favicon for Firefox 2 bookmarks.
|
| - usage.urls.insert(link_url);
|
| -
|
| - favicons->push_back(usage);
|
| -}
|
| -
|
|
|