Chromium Code Reviews| 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 |