OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <Cocoa/Cocoa.h> | 5 #include <Cocoa/Cocoa.h> |
6 | 6 |
7 #include "chrome/browser/importer/safari_importer.h" | 7 #include "chrome/browser/importer/safari_importer.h" |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 #include <vector> | 10 #include <vector> |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 } | 90 } |
91 if ((items & importer::PASSWORDS) && !cancelled()) { | 91 if ((items & importer::PASSWORDS) && !cancelled()) { |
92 bridge_->NotifyItemStarted(importer::PASSWORDS); | 92 bridge_->NotifyItemStarted(importer::PASSWORDS); |
93 ImportPasswords(); | 93 ImportPasswords(); |
94 bridge_->NotifyItemEnded(importer::PASSWORDS); | 94 bridge_->NotifyItemEnded(importer::PASSWORDS); |
95 } | 95 } |
96 bridge_->NotifyEnded(); | 96 bridge_->NotifyEnded(); |
97 } | 97 } |
98 | 98 |
99 void SafariImporter::ImportBookmarks() { | 99 void SafariImporter::ImportBookmarks() { |
| 100 string16 toolbar_name = |
| 101 bridge_->GetLocalizedString(IDS_BOOMARK_BAR_FOLDER_NAME); |
100 std::vector<ProfileWriter::BookmarkEntry> bookmarks; | 102 std::vector<ProfileWriter::BookmarkEntry> bookmarks; |
101 ParseBookmarks(&bookmarks); | 103 ParseBookmarks(toolbar_name, &bookmarks); |
102 | 104 |
103 // Write bookmarks into profile. | 105 // Write bookmarks into profile. |
104 if (!bookmarks.empty() && !cancelled()) { | 106 if (!bookmarks.empty() && !cancelled()) { |
105 const string16& first_folder_name = | 107 const string16& first_folder_name = |
106 bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_SAFARI); | 108 bridge_->GetLocalizedString(IDS_BOOKMARK_GROUP_FROM_SAFARI); |
107 int options = 0; | 109 bridge_->AddBookmarks(bookmarks, first_folder_name); |
108 if (import_to_bookmark_bar()) | |
109 options = ProfileWriter::IMPORT_TO_BOOKMARK_BAR; | |
110 bridge_->AddBookmarks(bookmarks, first_folder_name, options); | |
111 } | 110 } |
112 | 111 |
113 // Import favicons. | 112 // Import favicons. |
114 sql::Connection db; | 113 sql::Connection db; |
115 if (!OpenDatabase(&db)) | 114 if (!OpenDatabase(&db)) |
116 return; | 115 return; |
117 | 116 |
118 FaviconMap favicon_map; | 117 FaviconMap favicon_map; |
119 ImportFaviconURLs(&db, &favicon_map); | 118 ImportFaviconURLs(&db, &favicon_map); |
120 // Write favicons into profile. | 119 // Write favicons into profile. |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 usage.urls = i->second; | 185 usage.urls = i->second; |
187 favicons->push_back(usage); | 186 favicons->push_back(usage); |
188 } | 187 } |
189 } | 188 } |
190 } | 189 } |
191 | 190 |
192 void SafariImporter::RecursiveReadBookmarksFolder( | 191 void SafariImporter::RecursiveReadBookmarksFolder( |
193 NSDictionary* bookmark_folder, | 192 NSDictionary* bookmark_folder, |
194 const std::vector<string16>& parent_path_elements, | 193 const std::vector<string16>& parent_path_elements, |
195 bool is_in_toolbar, | 194 bool is_in_toolbar, |
| 195 const string16& toolbar_name, |
196 std::vector<ProfileWriter::BookmarkEntry>* out_bookmarks) { | 196 std::vector<ProfileWriter::BookmarkEntry>* out_bookmarks) { |
197 DCHECK(bookmark_folder); | 197 DCHECK(bookmark_folder); |
198 | 198 |
199 NSString* type = [bookmark_folder objectForKey:@"WebBookmarkType"]; | 199 NSString* type = [bookmark_folder objectForKey:@"WebBookmarkType"]; |
200 NSString* title = [bookmark_folder objectForKey:@"Title"]; | 200 NSString* title = [bookmark_folder objectForKey:@"Title"]; |
201 | 201 |
202 // Are we the dictionary that contains all other bookmarks? | 202 // Are we the dictionary that contains all other bookmarks? |
203 // We need to know this so we don't add it to the path. | 203 // We need to know this so we don't add it to the path. |
204 bool is_top_level_bookmarks_container = [bookmark_folder | 204 bool is_top_level_bookmarks_container = [bookmark_folder |
205 objectForKey:@"WebBookmarkFileVersion"] != nil; | 205 objectForKey:@"WebBookmarkFileVersion"] != nil; |
206 | 206 |
207 // We're expecting a list of bookmarks here, if that isn't what we got, fail. | 207 // We're expecting a list of bookmarks here, if that isn't what we got, fail. |
208 if (!is_top_level_bookmarks_container) { | 208 if (!is_top_level_bookmarks_container) { |
209 // Top level containers sometimes don't have title attributes. | 209 // Top level containers sometimes don't have title attributes. |
210 if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) { | 210 if (![type isEqualToString:@"WebBookmarkTypeList"] || !title) { |
211 DCHECK(false) << "Type =(" | 211 NOTREACHED() << "Type=(" |
212 << (type ? base::SysNSStringToUTF8(type) : "Null Type") | 212 << (type ? base::SysNSStringToUTF8(type) : "Null type") |
213 << ") Title=(" << (title ? base::SysNSStringToUTF8(title) : "Null title") | 213 << ") Title=(" |
214 << ")"; | 214 << (title ? base::SysNSStringToUTF8(title) : "Null title") |
| 215 << ")"; |
215 return; | 216 return; |
216 } | 217 } |
217 } | 218 } |
218 | 219 |
| 220 NSArray* elements = [bookmark_folder objectForKey:@"Children"]; |
| 221 if (!elements && (!parent_path_elements.empty() || !is_in_toolbar)) { |
| 222 // This is an empty folder, so add it explicitly; but don't add the toolbar |
| 223 // folder if it is empty. Note that all non-empty folders are added |
| 224 // implicitly when their children are added. |
| 225 ProfileWriter::BookmarkEntry entry; |
| 226 // Safari doesn't specify a creation time for the folder. |
| 227 entry.creation_time = base::Time::Now(); |
| 228 entry.title = base::SysNSStringToUTF16(title); |
| 229 entry.path = parent_path_elements; |
| 230 entry.in_toolbar = is_in_toolbar; |
| 231 entry.is_folder = true; |
| 232 |
| 233 out_bookmarks->push_back(entry); |
| 234 return; |
| 235 } |
| 236 |
219 std::vector<string16> path_elements(parent_path_elements); | 237 std::vector<string16> path_elements(parent_path_elements); |
220 // Is this the toolbar folder? | 238 // Create a folder for the toolbar, but not for the bookmarks menu. |
221 if ([title isEqualToString:@"BookmarksBar"]) { | 239 if (path_elements.empty() && [title isEqualToString:@"BookmarksBar"]) { |
222 // Be defensive, the toolbar items shouldn't have a prepended path. | |
223 path_elements.clear(); | |
224 is_in_toolbar = true; | 240 is_in_toolbar = true; |
225 } else if ([title isEqualToString:@"BookmarksMenu"]) { | 241 path_elements.push_back(toolbar_name); |
226 // top level container for normal bookmarks. | 242 } else if (!is_top_level_bookmarks_container && |
227 path_elements.clear(); | 243 !(path_elements.empty() && |
228 } else if (!is_top_level_bookmarks_container) { | 244 [title isEqualToString:@"BookmarksMenu"])) { |
229 if (title) | 245 if (title) |
230 path_elements.push_back(base::SysNSStringToUTF16(title)); | 246 path_elements.push_back(base::SysNSStringToUTF16(title)); |
231 } | 247 } |
232 | 248 |
233 NSArray* elements = [bookmark_folder objectForKey:@"Children"]; | |
234 // TODO(jeremy) Does Chrome support importing empty folders? | |
235 if (!elements) | |
236 return; | |
237 | |
238 // Iterate over individual bookmarks. | 249 // Iterate over individual bookmarks. |
239 for (NSDictionary* bookmark in elements) { | 250 for (NSDictionary* bookmark in elements) { |
240 NSString* type = [bookmark objectForKey:@"WebBookmarkType"]; | 251 NSString* type = [bookmark objectForKey:@"WebBookmarkType"]; |
241 if (!type) | 252 if (!type) |
242 continue; | 253 continue; |
243 | 254 |
244 // If this is a folder, recurse. | 255 // If this is a folder, recurse. |
245 if ([type isEqualToString:@"WebBookmarkTypeList"]) { | 256 if ([type isEqualToString:@"WebBookmarkTypeList"]) { |
246 RecursiveReadBookmarksFolder(bookmark, | 257 RecursiveReadBookmarksFolder(bookmark, |
247 path_elements, | 258 path_elements, |
248 is_in_toolbar, | 259 is_in_toolbar, |
| 260 toolbar_name, |
249 out_bookmarks); | 261 out_bookmarks); |
250 } | 262 } |
251 | 263 |
252 // If we didn't see a bookmark folder, then we're expecting a bookmark | 264 // If we didn't see a bookmark folder, then we're expecting a bookmark |
253 // item, if that's not what we got then ignore it. | 265 // item. If that's not what we got then ignore it. |
254 if (![type isEqualToString:@"WebBookmarkTypeLeaf"]) | 266 if (![type isEqualToString:@"WebBookmarkTypeLeaf"]) |
255 continue; | 267 continue; |
256 | 268 |
257 NSString* url = [bookmark objectForKey:@"URLString"]; | 269 NSString* url = [bookmark objectForKey:@"URLString"]; |
258 NSString* title = [[bookmark objectForKey:@"URIDictionary"] | 270 NSString* title = [[bookmark objectForKey:@"URIDictionary"] |
259 objectForKey:@"title"]; | 271 objectForKey:@"title"]; |
260 | 272 |
261 if (!url || !title) | 273 if (!url || !title) |
262 continue; | 274 continue; |
263 | 275 |
264 // Output Bookmark. | 276 // Output Bookmark. |
265 ProfileWriter::BookmarkEntry entry; | 277 ProfileWriter::BookmarkEntry entry; |
266 // Safari doesn't specify a creation time for the bookmark. | 278 // Safari doesn't specify a creation time for the bookmark. |
267 entry.creation_time = base::Time::Now(); | 279 entry.creation_time = base::Time::Now(); |
268 entry.title = base::SysNSStringToUTF16(title); | 280 entry.title = base::SysNSStringToUTF16(title); |
269 entry.url = GURL(base::SysNSStringToUTF8(url)); | 281 entry.url = GURL(base::SysNSStringToUTF8(url)); |
270 entry.path = path_elements; | 282 entry.path = path_elements; |
271 entry.in_toolbar = is_in_toolbar; | 283 entry.in_toolbar = is_in_toolbar; |
272 | 284 |
273 out_bookmarks->push_back(entry); | 285 out_bookmarks->push_back(entry); |
274 } | 286 } |
275 } | 287 } |
276 | 288 |
277 void SafariImporter::ParseBookmarks( | 289 void SafariImporter::ParseBookmarks( |
| 290 const string16& toolbar_name, |
278 std::vector<ProfileWriter::BookmarkEntry>* bookmarks) { | 291 std::vector<ProfileWriter::BookmarkEntry>* bookmarks) { |
279 DCHECK(bookmarks); | 292 DCHECK(bookmarks); |
280 | 293 |
281 // Construct ~/Library/Safari/Bookmarks.plist path | 294 // Construct ~/Library/Safari/Bookmarks.plist path |
282 NSString* library_dir = [NSString | 295 NSString* library_dir = [NSString |
283 stringWithUTF8String:library_dir_.value().c_str()]; | 296 stringWithUTF8String:library_dir_.value().c_str()]; |
284 NSString* safari_dir = [library_dir | 297 NSString* safari_dir = [library_dir |
285 stringByAppendingPathComponent:@"Safari"]; | 298 stringByAppendingPathComponent:@"Safari"]; |
286 NSString* bookmarks_plist = [safari_dir | 299 NSString* bookmarks_plist = [safari_dir |
287 stringByAppendingPathComponent:@"Bookmarks.plist"]; | 300 stringByAppendingPathComponent:@"Bookmarks.plist"]; |
288 | 301 |
289 // Load the plist file. | 302 // Load the plist file. |
290 NSDictionary* bookmarks_dict = [NSDictionary | 303 NSDictionary* bookmarks_dict = [NSDictionary |
291 dictionaryWithContentsOfFile:bookmarks_plist]; | 304 dictionaryWithContentsOfFile:bookmarks_plist]; |
292 if (!bookmarks_dict) | 305 if (!bookmarks_dict) |
293 return; | 306 return; |
294 | 307 |
295 // Recursively read in bookmarks. | 308 // Recursively read in bookmarks. |
296 std::vector<string16> parent_path_elements; | 309 std::vector<string16> parent_path_elements; |
297 RecursiveReadBookmarksFolder(bookmarks_dict, parent_path_elements, false, | 310 RecursiveReadBookmarksFolder(bookmarks_dict, parent_path_elements, false, |
298 bookmarks); | 311 toolbar_name, bookmarks); |
299 } | 312 } |
300 | 313 |
301 void SafariImporter::ImportPasswords() { | 314 void SafariImporter::ImportPasswords() { |
302 // Safari stores it's passwords in the Keychain, same as us so we don't need | 315 // Safari stores it's passwords in the Keychain, same as us so we don't need |
303 // to import them. | 316 // to import them. |
304 // Note: that we don't automatically pick them up, there is some logic around | 317 // Note: that we don't automatically pick them up, there is some logic around |
305 // the user needing to explicitly input his username in a page and blurring | 318 // the user needing to explicitly input his username in a page and blurring |
306 // the field before we pick it up, but the details of that are beyond the | 319 // the field before we pick it up, but the details of that are beyond the |
307 // scope of this comment. | 320 // scope of this comment. |
308 } | 321 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 if (!last_visit_str) | 393 if (!last_visit_str) |
381 continue; | 394 continue; |
382 | 395 |
383 // Convert Safari's last visit time to Unix Epoch time. | 396 // Convert Safari's last visit time to Unix Epoch time. |
384 double seconds_since_unix_epoch = HistoryTimeToEpochTime(last_visit_str); | 397 double seconds_since_unix_epoch = HistoryTimeToEpochTime(last_visit_str); |
385 row.set_last_visit(base::Time::FromDoubleT(seconds_since_unix_epoch)); | 398 row.set_last_visit(base::Time::FromDoubleT(seconds_since_unix_epoch)); |
386 | 399 |
387 history_items->push_back(row); | 400 history_items->push_back(row); |
388 } | 401 } |
389 } | 402 } |
OLD | NEW |