Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3508)

Unified Diff: chrome/browser/importer/safari_importer.mm

Issue 159668: First cut at Safari Import - Home Page & History Only. (Closed)
Patch Set: Fix Stuart's comments. Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/importer/safari_importer.h ('k') | chrome/browser/importer/safari_importer_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/importer/safari_importer.mm
diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm
new file mode 100644
index 0000000000000000000000000000000000000000..b97bef4b87cef1a075497a113dba63cc615c2859
--- /dev/null
+++ b/chrome/browser/importer/safari_importer.mm
@@ -0,0 +1,222 @@
+// Copyright (c) 2009 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 <vector>
+
+#include "base/message_loop.h"
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "base/time.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
+#include "net/base/data_url.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 FilePath& library_dir)
+ : writer_(NULL), library_dir_(library_dir) {
+}
+
+SafariImporter::~SafariImporter() {
+}
+
+void SafariImporter::StartImport(ProfileInfo profile_info,
+ uint16 items, ProfileWriter* writer,
+ MessageLoop* delegate_loop,
+ ImporterHost* host) {
+ writer_ = writer;
+ 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();
+}
+
+void SafariImporter::ImportBookmarks() {
+ NOTIMPLEMENTED();
+}
+
+void SafariImporter::ImportSearchEngines() {
+ NOTIMPLEMENTED();
+}
+
+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 bluring
+ // the field before we pick it up, but the details of that are beyond the
+ // scope of this comment.
+}
+
+void SafariImporter::ImportHistory() {
+ std::vector<history::URLRow> rows;
+ ParseHistoryItems(&rows);
+
+ if (!rows.empty() && !cancelled()) {
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddHistoryPage, rows));
+ }
+}
+
+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(reinterpret_cast<CFStringRef>(history_time)) +
+ kCFAbsoluteTimeIntervalSince1970;
+}
+
+void SafariImporter::ParseHistoryItems(
+ std::vector<history::URLRow>* 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];
+
+ NSArray* safari_history_items = [history_dict valueForKey:@"WebHistoryDates"];
+
+ for (NSDictionary* history_item in safari_history_items) {
+ using base::SysNSStringToUTF8;
+ using base::SysNSStringToWide;
+ NSString* url_ns = [history_item valueForKey:@""];
+ if (!url_ns)
+ continue;
+
+ GURL url(SysNSStringToUTF8(url_ns));
+
+ if (!CanImportSafariURL(url))
+ continue;
+
+ history::URLRow row(url);
+ NSString* title_ns = [history_item valueForKey:@"title"];
+
+ // Sometimes items don't have a title, in which case we just substitue
+ // the url.
+ if (!title_ns)
+ title_ns = url_ns;
+
+ row.set_title(SysNSStringToWide(title_ns));
+ int visit_count = [[history_item valueForKey:@"visitCount"]
+ intValue];
+ row.set_visit_count(visit_count);
+ // Include imported URLs in autocompletion - don't hide them.
+ row.set_hidden(0);
+ // Item was never typed before in the omnibox.
+ row.set_typed_count(0);
+
+ NSString* last_visit_str = [history_item valueForKey:@"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.set_last_visit(base::Time::FromDoubleT(seconds_since_unix_epoch));
+
+ history_items->push_back(row);
+ }
+}
+
+void SafariImporter::ImportHomepage() {
+ const NSString* homepage_ns =
+ reinterpret_cast<const NSString*>(
+ CFPreferencesCopyAppValue(CFSTR("HomePage"),
+ CFSTR("com.apple.Safari")));
stuartmorgan 2009/07/31 19:57:01 This needs releasing; Copy gives you an owned refe
+ if (!homepage_ns)
+ return;
+
+ string16 hompeage_str = base::SysNSStringToUTF16(homepage_ns);
+ GURL homepage(hompeage_str);
+ if (homepage.is_valid()) {
+ main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
+ &ProfileWriter::AddHomepage, homepage));
+ }
+}
+
+// TODO(jeremy): This is temporary, just copied from the FF import code in case
+// we need it, clean this up when writing favicon import code.
+// static
+void SafariImporter::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(chrome::kDataScheme))
+ 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);
+}
+
« no previous file with comments | « chrome/browser/importer/safari_importer.h ('k') | chrome/browser/importer/safari_importer_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698