OLD | NEW |
---|---|
(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 | |
OLD | NEW |