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

Side by Side 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, 4 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 <Cocoa/Cocoa.h>
6
7 #include "chrome/browser/importer/safari_importer.h"
8
9 #include <vector>
10
11 #include "base/message_loop.h"
12 #include "base/string16.h"
13 #include "base/sys_string_conversions.h"
14 #include "base/time.h"
15 #include "chrome/common/url_constants.h"
16 #include "googleurl/src/gurl.h"
17 #include "grit/generated_resources.h"
18 #include "net/base/data_url.h"
19
20 namespace {
21
22 // A function like this is used by other importers in order to filter out
23 // URLS we don't want to import.
24 // For now it's pretty basic, but I've split it out so it's easy to slot
25 // in necessary logic for filtering URLS, should we need it.
26 bool CanImportSafariURL(const GURL& url) {
27 // The URL is not valid.
28 if (!url.is_valid())
29 return false;
30
31 return true;
32 }
33
34 } // namespace
35
36 SafariImporter::SafariImporter(const FilePath& library_dir)
37 : writer_(NULL), library_dir_(library_dir) {
38 }
39
40 SafariImporter::~SafariImporter() {
41 }
42
43 void SafariImporter::StartImport(ProfileInfo profile_info,
44 uint16 items, ProfileWriter* writer,
45 MessageLoop* delegate_loop,
46 ImporterHost* host) {
47 writer_ = writer;
48 importer_host_ = host;
49
50 // The order here is important!
51 NotifyStarted();
52 if ((items & HOME_PAGE) && !cancelled())
53 ImportHomepage(); // Doesn't have a UI item.
54 if ((items & FAVORITES) && !cancelled()) {
55 NotifyItemStarted(FAVORITES);
56 ImportBookmarks();
57 NotifyItemEnded(FAVORITES);
58 }
59 if ((items & SEARCH_ENGINES) && !cancelled()) {
60 NotifyItemStarted(SEARCH_ENGINES);
61 ImportSearchEngines();
62 NotifyItemEnded(SEARCH_ENGINES);
63 }
64 if ((items & PASSWORDS) && !cancelled()) {
65 NotifyItemStarted(PASSWORDS);
66 ImportPasswords();
67 NotifyItemEnded(PASSWORDS);
68 }
69 if ((items & HISTORY) && !cancelled()) {
70 NotifyItemStarted(HISTORY);
71 ImportHistory();
72 NotifyItemEnded(HISTORY);
73 }
74 NotifyEnded();
75 }
76
77 void SafariImporter::ImportBookmarks() {
78 NOTIMPLEMENTED();
79 }
80
81 void SafariImporter::ImportSearchEngines() {
82 NOTIMPLEMENTED();
83 }
84
85 void SafariImporter::ImportPasswords() {
86 // Safari stores it's passwords in the Keychain, same as us so we don't need
87 // to import them.
88 // Note: that we don't automatically pick them up, there is some logic around
89 // the user needing to explicitly input his username in a page and bluring
90 // the field before we pick it up, but the details of that are beyond the
91 // scope of this comment.
92 }
93
94 void SafariImporter::ImportHistory() {
95 std::vector<history::URLRow> rows;
96 ParseHistoryItems(&rows);
97
98 if (!rows.empty() && !cancelled()) {
99 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
100 &ProfileWriter::AddHistoryPage, rows));
101 }
102 }
103
104 double SafariImporter::HistoryTimeToEpochTime(NSString* history_time) {
105 DCHECK(history_time);
106 // Add Difference between Unix epoch and CFAbsoluteTime epoch in seconds.
107 // Unix epoch is 1970-01-01 00:00:00.0 UTC,
108 // CF epoch is 2001-01-01 00:00:00.0 UTC.
109 return CFStringGetDoubleValue(reinterpret_cast<CFStringRef>(history_time)) +
110 kCFAbsoluteTimeIntervalSince1970;
111 }
112
113 void SafariImporter::ParseHistoryItems(
114 std::vector<history::URLRow>* history_items) {
115 DCHECK(history_items);
116
117 // Construct ~/Library/Safari/History.plist path
118 NSString* library_dir = [NSString
119 stringWithUTF8String:library_dir_.value().c_str()];
120 NSString* safari_dir = [library_dir
121 stringByAppendingPathComponent:@"Safari"];
122 NSString* history_plist = [safari_dir
123 stringByAppendingPathComponent:@"History.plist"];
124
125 // Load the plist file.
126 NSDictionary* history_dict = [NSDictionary
127 dictionaryWithContentsOfFile:history_plist];
128
129 NSArray* safari_history_items = [history_dict valueForKey:@"WebHistoryDates"];
130
131 for (NSDictionary* history_item in safari_history_items) {
132 using base::SysNSStringToUTF8;
133 using base::SysNSStringToWide;
134 NSString* url_ns = [history_item valueForKey:@""];
135 if (!url_ns)
136 continue;
137
138 GURL url(SysNSStringToUTF8(url_ns));
139
140 if (!CanImportSafariURL(url))
141 continue;
142
143 history::URLRow row(url);
144 NSString* title_ns = [history_item valueForKey:@"title"];
145
146 // Sometimes items don't have a title, in which case we just substitue
147 // the url.
148 if (!title_ns)
149 title_ns = url_ns;
150
151 row.set_title(SysNSStringToWide(title_ns));
152 int visit_count = [[history_item valueForKey:@"visitCount"]
153 intValue];
154 row.set_visit_count(visit_count);
155 // Include imported URLs in autocompletion - don't hide them.
156 row.set_hidden(0);
157 // Item was never typed before in the omnibox.
158 row.set_typed_count(0);
159
160 NSString* last_visit_str = [history_item valueForKey:@"lastVisitedDate"];
161 // The last visit time should always be in the history item, but if not
162 /// just continue without this item.
163 DCHECK(last_visit_str);
164 if (!last_visit_str)
165 continue;
166
167 // Convert Safari's last visit time to Unix Epoch time.
168 double seconds_since_unix_epoch = HistoryTimeToEpochTime(last_visit_str);
169 row.set_last_visit(base::Time::FromDoubleT(seconds_since_unix_epoch));
170
171 history_items->push_back(row);
172 }
173 }
174
175 void SafariImporter::ImportHomepage() {
176 const NSString* homepage_ns =
177 reinterpret_cast<const NSString*>(
178 CFPreferencesCopyAppValue(CFSTR("HomePage"),
179 CFSTR("com.apple.Safari")));
stuartmorgan 2009/07/31 19:57:01 This needs releasing; Copy gives you an owned refe
180 if (!homepage_ns)
181 return;
182
183 string16 hompeage_str = base::SysNSStringToUTF16(homepage_ns);
184 GURL homepage(hompeage_str);
185 if (homepage.is_valid()) {
186 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
187 &ProfileWriter::AddHomepage, homepage));
188 }
189 }
190
191 // TODO(jeremy): This is temporary, just copied from the FF import code in case
192 // we need it, clean this up when writing favicon import code.
193 // static
194 void SafariImporter::DataURLToFaviconUsage(
195 const GURL& link_url,
196 const GURL& favicon_data,
197 std::vector<history::ImportedFavIconUsage>* favicons) {
198 if (!link_url.is_valid() || !favicon_data.is_valid() ||
199 !favicon_data.SchemeIs(chrome::kDataScheme))
200 return;
201
202 // Parse the data URL.
203 std::string mime_type, char_set, data;
204 if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
205 data.empty())
206 return;
207
208 history::ImportedFavIconUsage usage;
209 if (!ReencodeFavicon(reinterpret_cast<const unsigned char*>(&data[0]),
210 data.size(), &usage.png_data))
211 return; // Unable to decode.
212
213 // We need to make up a URL for the favicon. We use a version of the page's
214 // URL so that we can be sure it will not collide.
215 usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
216
217 // We only have one URL per favicon for Firefox 2 bookmarks.
218 usage.urls.insert(link_url);
219
220 favicons->push_back(usage);
221 }
222
OLDNEW
« 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