| Index: chrome/browser/importer/safari_importer.mm
|
| diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm
|
| deleted file mode 100644
|
| index 4a5de0dba616fceaab1159d65de88af3612ba0d4..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/importer/safari_importer.mm
|
| +++ /dev/null
|
| @@ -1,399 +0,0 @@
|
| -// 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 <Cocoa/Cocoa.h>
|
| -
|
| -#include "chrome/browser/importer/safari_importer.h"
|
| -
|
| -#include <map>
|
| -#include <vector>
|
| -
|
| -#include "base/file_util.h"
|
| -#include "base/mac/mac_util.h"
|
| -#include "base/strings/string16.h"
|
| -#include "base/strings/sys_string_conversions.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "base/time/time.h"
|
| -#include "chrome/browser/importer/importer_bridge.h"
|
| -#include "chrome/browser/importer/reencode_favicon.h"
|
| -#include "chrome/common/importer/imported_bookmark_entry.h"
|
| -#include "chrome/common/importer/imported_favicon_usage.h"
|
| -#include "chrome/common/url_constants.h"
|
| -#include "grit/generated_resources.h"
|
| -#include "net/base/data_url.h"
|
| -#include "sql/statement.h"
|
| -#include "url/gurl.h"
|
| -
|
| -namespace {
|
| -
|
| -// A function like this is used by other importers in order to filter out
|
| -// URLS we don't want to import.
|
| -// For now it's pretty basic, but I've split it out so it's easy to slot
|
| -// in necessary logic for filtering URLS, should we need it.
|
| -bool CanImportSafariURL(const GURL& url) {
|
| - // The URL is not valid.
|
| - if (!url.is_valid())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -SafariImporter::SafariImporter(const base::FilePath& library_dir)
|
| - : library_dir_(library_dir) {
|
| -}
|
| -
|
| -SafariImporter::~SafariImporter() {
|
| -}
|
| -
|
| -// static
|
| -bool SafariImporter::CanImport(const base::FilePath& library_dir,
|
| - uint16* services_supported) {
|
| - DCHECK(services_supported);
|
| - *services_supported = importer::NONE;
|
| -
|
| - // Import features are toggled by the following:
|
| - // bookmarks import: existence of ~/Library/Safari/Bookmarks.plist file.
|
| - // history import: existence of ~/Library/Safari/History.plist file.
|
| - base::FilePath safari_dir = library_dir.Append("Safari");
|
| - base::FilePath bookmarks_path = safari_dir.Append("Bookmarks.plist");
|
| - base::FilePath history_path = safari_dir.Append("History.plist");
|
| -
|
| - if (base::PathExists(bookmarks_path))
|
| - *services_supported |= importer::FAVORITES;
|
| - if (base::PathExists(history_path))
|
| - *services_supported |= importer::HISTORY;
|
| -
|
| - return *services_supported != importer::NONE;
|
| -}
|
| -
|
| -void SafariImporter::StartImport(const importer::SourceProfile& source_profile,
|
| - uint16 items,
|
| - 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 ((items & importer::HISTORY) && !cancelled()) {
|
| - bridge_->NotifyItemStarted(importer::HISTORY);
|
| - ImportHistory();
|
| - bridge_->NotifyItemEnded(importer::HISTORY);
|
| - }
|
| - if ((items & importer::FAVORITES) && !cancelled()) {
|
| - bridge_->NotifyItemStarted(importer::FAVORITES);
|
| - ImportBookmarks();
|
| - bridge_->NotifyItemEnded(importer::FAVORITES);
|
| - }
|
| - if ((items & importer::PASSWORDS) && !cancelled()) {
|
| - bridge_->NotifyItemStarted(importer::PASSWORDS);
|
| - ImportPasswords();
|
| - bridge_->NotifyItemEnded(importer::PASSWORDS);
|
| - }
|
| - bridge_->NotifyEnded();
|
| -}
|
| -
|
| -void SafariImporter::ImportBookmarks() {
|
| - string16 toolbar_name =
|
| - bridge_->GetLocalizedString(IDS_BOOKMARK_BAR_FOLDER_NAME);
|
| - std::vector<ImportedBookmarkEntry> bookmarks;
|
| - ParseBookmarks(toolbar_name, &bookmarks);
|
| -
|
| - // Write bookmarks into profile.
|
| - if (!bookmarks.empty() && !cancelled()) {
|
| - const string16& first_folder_name =
|
| - bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_SAFARI);
|
| - bridge_->AddBookmarks(bookmarks, first_folder_name);
|
| - }
|
| -
|
| - // Import favicons.
|
| - sql::Connection db;
|
| - if (!OpenDatabase(&db))
|
| - return;
|
| -
|
| - FaviconMap favicon_map;
|
| - ImportFaviconURLs(&db, &favicon_map);
|
| - // Write favicons into profile.
|
| - if (!favicon_map.empty() && !cancelled()) {
|
| - std::vector<ImportedFaviconUsage> favicons;
|
| - LoadFaviconData(&db, favicon_map, &favicons);
|
| - bridge_->SetFavicons(favicons);
|
| - }
|
| -}
|
| -
|
| -bool SafariImporter::OpenDatabase(sql::Connection* db) {
|
| - // Construct ~/Library/Safari/WebIcons.db path.
|
| - NSString* library_dir = [NSString
|
| - stringWithUTF8String:library_dir_.value().c_str()];
|
| - NSString* safari_dir = [library_dir
|
| - stringByAppendingPathComponent:@"Safari"];
|
| - NSString* favicons_db_path = [safari_dir
|
| - stringByAppendingPathComponent:@"WebpageIcons.db"];
|
| -
|
| - const char* db_path = [favicons_db_path fileSystemRepresentation];
|
| - return db->Open(base::FilePath(db_path));
|
| -}
|
| -
|
| -void SafariImporter::ImportFaviconURLs(sql::Connection* db,
|
| - FaviconMap* favicon_map) {
|
| - const char* query = "SELECT iconID, url FROM PageURL;";
|
| - sql::Statement s(db->GetUniqueStatement(query));
|
| -
|
| - while (s.Step() && !cancelled()) {
|
| - int64 icon_id = s.ColumnInt64(0);
|
| - GURL url = GURL(s.ColumnString(1));
|
| - (*favicon_map)[icon_id].insert(url);
|
| - }
|
| -}
|
| -
|
| -void SafariImporter::LoadFaviconData(
|
| - sql::Connection* db,
|
| - const FaviconMap& favicon_map,
|
| - std::vector<ImportedFaviconUsage>* favicons) {
|
| - const char* query = "SELECT i.url, d.data "
|
| - "FROM IconInfo i JOIN IconData d "
|
| - "ON i.iconID = d.iconID "
|
| - "WHERE i.iconID = ?;";
|
| - sql::Statement s(db->GetUniqueStatement(query));
|
| -
|
| - for (FaviconMap::const_iterator i = favicon_map.begin();
|
| - i != favicon_map.end(); ++i) {
|
| - s.Reset(true);
|
| - s.BindInt64(0, i->first);
|
| - if (s.Step()) {
|
| - ImportedFaviconUsage usage;
|
| -
|
| - usage.favicon_url = GURL(s.ColumnString(0));
|
| - if (!usage.favicon_url.is_valid())
|
| - continue; // Don't bother importing favicons with invalid URLs.
|
| -
|
| - std::vector<unsigned char> data;
|
| - s.ColumnBlobAsVector(1, &data);
|
| - if (data.empty())
|
| - continue; // Data definitely invalid.
|
| -
|
| - if (!ReencodeFavicon(&data[0], data.size(), &usage.png_data))
|
| - continue; // Unable to decode.
|
| -
|
| - usage.urls = i->second;
|
| - favicons->push_back(usage);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SafariImporter::RecursiveReadBookmarksFolder(
|
| - NSDictionary* bookmark_folder,
|
| - const std::vector<string16>& parent_path_elements,
|
| - bool is_in_toolbar,
|
| - const string16& toolbar_name,
|
| - std::vector<ImportedBookmarkEntry>* out_bookmarks) {
|
| - DCHECK(bookmark_folder);
|
| -
|
| - NSString* type = [bookmark_folder objectForKey:@"WebBookmarkType"];
|
| - NSString* title = [bookmark_folder objectForKey:@"Title"];
|
| -
|
| - // Are we the dictionary that contains all other bookmarks?
|
| - // We need to know this so we don't add it to the path.
|
| - bool is_top_level_bookmarks_container = [bookmark_folder
|
| - objectForKey:@"WebBookmarkFileVersion"] != nil;
|
| -
|
| - // We're expecting a list of bookmarks here, if that isn't what we got, fail.
|
| - if (!is_top_level_bookmarks_container) {
|
| - // Top level containers sometimes don't have title attributes.
|
| - if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) {
|
| - NOTREACHED() << "Type=("
|
| - << (type ? base::SysNSStringToUTF8(type) : "Null type")
|
| - << ") Title=("
|
| - << (title ? base::SysNSStringToUTF8(title) : "Null title")
|
| - << ")";
|
| - return;
|
| - }
|
| - }
|
| -
|
| - NSArray* elements = [bookmark_folder objectForKey:@"Children"];
|
| - if (!elements && (!parent_path_elements.empty() || !is_in_toolbar)) {
|
| - // This is an empty folder, so add it explicitly; but don't add the toolbar
|
| - // folder if it is empty. Note that all non-empty folders are added
|
| - // implicitly when their children are added.
|
| - ImportedBookmarkEntry entry;
|
| - // Safari doesn't specify a creation time for the folder.
|
| - entry.creation_time = base::Time::Now();
|
| - entry.title = base::SysNSStringToUTF16(title);
|
| - entry.path = parent_path_elements;
|
| - entry.in_toolbar = is_in_toolbar;
|
| - entry.is_folder = true;
|
| -
|
| - out_bookmarks->push_back(entry);
|
| - return;
|
| - }
|
| -
|
| - std::vector<string16> path_elements(parent_path_elements);
|
| - // Create a folder for the toolbar, but not for the bookmarks menu.
|
| - if (path_elements.empty() && [title isEqualToString:@"BookmarksBar"]) {
|
| - is_in_toolbar = true;
|
| - path_elements.push_back(toolbar_name);
|
| - } else if (!is_top_level_bookmarks_container &&
|
| - !(path_elements.empty() &&
|
| - [title isEqualToString:@"BookmarksMenu"])) {
|
| - if (title)
|
| - path_elements.push_back(base::SysNSStringToUTF16(title));
|
| - }
|
| -
|
| - // Iterate over individual bookmarks.
|
| - for (NSDictionary* bookmark in elements) {
|
| - NSString* type = [bookmark objectForKey:@"WebBookmarkType"];
|
| - if (!type)
|
| - continue;
|
| -
|
| - // If this is a folder, recurse.
|
| - if ([type isEqualToString:@"WebBookmarkTypeList"]) {
|
| - RecursiveReadBookmarksFolder(bookmark,
|
| - path_elements,
|
| - is_in_toolbar,
|
| - toolbar_name,
|
| - out_bookmarks);
|
| - }
|
| -
|
| - // If we didn't see a bookmark folder, then we're expecting a bookmark
|
| - // item. If that's not what we got then ignore it.
|
| - if (![type isEqualToString:@"WebBookmarkTypeLeaf"])
|
| - continue;
|
| -
|
| - NSString* url = [bookmark objectForKey:@"URLString"];
|
| - NSString* title = [[bookmark objectForKey:@"URIDictionary"]
|
| - objectForKey:@"title"];
|
| -
|
| - if (!url || !title)
|
| - continue;
|
| -
|
| - // Output Bookmark.
|
| - ImportedBookmarkEntry entry;
|
| - // Safari doesn't specify a creation time for the bookmark.
|
| - entry.creation_time = base::Time::Now();
|
| - entry.title = base::SysNSStringToUTF16(title);
|
| - entry.url = GURL(base::SysNSStringToUTF8(url));
|
| - entry.path = path_elements;
|
| - entry.in_toolbar = is_in_toolbar;
|
| -
|
| - out_bookmarks->push_back(entry);
|
| - }
|
| -}
|
| -
|
| -void SafariImporter::ParseBookmarks(
|
| - const string16& toolbar_name,
|
| - std::vector<ImportedBookmarkEntry>* bookmarks) {
|
| - DCHECK(bookmarks);
|
| -
|
| - // Construct ~/Library/Safari/Bookmarks.plist path
|
| - NSString* library_dir = [NSString
|
| - stringWithUTF8String:library_dir_.value().c_str()];
|
| - NSString* safari_dir = [library_dir
|
| - stringByAppendingPathComponent:@"Safari"];
|
| - NSString* bookmarks_plist = [safari_dir
|
| - stringByAppendingPathComponent:@"Bookmarks.plist"];
|
| -
|
| - // Load the plist file.
|
| - NSDictionary* bookmarks_dict = [NSDictionary
|
| - dictionaryWithContentsOfFile:bookmarks_plist];
|
| - if (!bookmarks_dict)
|
| - return;
|
| -
|
| - // Recursively read in bookmarks.
|
| - std::vector<string16> parent_path_elements;
|
| - RecursiveReadBookmarksFolder(bookmarks_dict, parent_path_elements, false,
|
| - toolbar_name, bookmarks);
|
| -}
|
| -
|
| -void SafariImporter::ImportPasswords() {
|
| - // Safari stores it's passwords in the Keychain, same as us so we don't need
|
| - // to import them.
|
| - // Note: that we don't automatically pick them up, there is some logic around
|
| - // the user needing to explicitly input his username in a page and blurring
|
| - // the field before we pick it up, but the details of that are beyond the
|
| - // scope of this comment.
|
| -}
|
| -
|
| -void SafariImporter::ImportHistory() {
|
| - std::vector<ImporterURLRow> rows;
|
| - ParseHistoryItems(&rows);
|
| -
|
| - if (!rows.empty() && !cancelled()) {
|
| - bridge_->SetHistoryItems(rows, importer::VISIT_SOURCE_SAFARI_IMPORTED);
|
| - }
|
| -}
|
| -
|
| -double SafariImporter::HistoryTimeToEpochTime(NSString* history_time) {
|
| - DCHECK(history_time);
|
| - // Add Difference between Unix epoch and CFAbsoluteTime epoch in seconds.
|
| - // Unix epoch is 1970-01-01 00:00:00.0 UTC,
|
| - // CF epoch is 2001-01-01 00:00:00.0 UTC.
|
| - return CFStringGetDoubleValue(base::mac::NSToCFCast(history_time)) +
|
| - kCFAbsoluteTimeIntervalSince1970;
|
| -}
|
| -
|
| -void SafariImporter::ParseHistoryItems(
|
| - std::vector<ImporterURLRow>* history_items) {
|
| - DCHECK(history_items);
|
| -
|
| - // Construct ~/Library/Safari/History.plist path
|
| - NSString* library_dir = [NSString
|
| - stringWithUTF8String:library_dir_.value().c_str()];
|
| - NSString* safari_dir = [library_dir
|
| - stringByAppendingPathComponent:@"Safari"];
|
| - NSString* history_plist = [safari_dir
|
| - stringByAppendingPathComponent:@"History.plist"];
|
| -
|
| - // Load the plist file.
|
| - NSDictionary* history_dict = [NSDictionary
|
| - dictionaryWithContentsOfFile:history_plist];
|
| - if (!history_dict)
|
| - return;
|
| -
|
| - NSArray* safari_history_items = [history_dict
|
| - objectForKey:@"WebHistoryDates"];
|
| -
|
| - for (NSDictionary* history_item in safari_history_items) {
|
| - NSString* url_ns = [history_item objectForKey:@""];
|
| - if (!url_ns)
|
| - continue;
|
| -
|
| - GURL url(base::SysNSStringToUTF8(url_ns));
|
| -
|
| - if (!CanImportSafariURL(url))
|
| - continue;
|
| -
|
| - ImporterURLRow row(url);
|
| - NSString* title_ns = [history_item objectForKey:@"title"];
|
| -
|
| - // Sometimes items don't have a title, in which case we just substitue
|
| - // the url.
|
| - if (!title_ns)
|
| - title_ns = url_ns;
|
| -
|
| - row.title = base::SysNSStringToUTF16(title_ns);
|
| - int visit_count = [[history_item objectForKey:@"visitCount"]
|
| - intValue];
|
| - row.visit_count = visit_count;
|
| - // Include imported URLs in autocompletion - don't hide them.
|
| - row.hidden = 0;
|
| - // Item was never typed before in the omnibox.
|
| - row.typed_count = 0;
|
| -
|
| - NSString* last_visit_str = [history_item objectForKey:@"lastVisitedDate"];
|
| - // The last visit time should always be in the history item, but if not
|
| - /// just continue without this item.
|
| - DCHECK(last_visit_str);
|
| - if (!last_visit_str)
|
| - continue;
|
| -
|
| - // Convert Safari's last visit time to Unix Epoch time.
|
| - double seconds_since_unix_epoch = HistoryTimeToEpochTime(last_visit_str);
|
| - row.last_visit = base::Time::FromDoubleT(seconds_since_unix_epoch);
|
| -
|
| - history_items->push_back(row);
|
| - }
|
| -}
|
|
|