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

Side by Side Diff: chrome/browser/firefox2_importer.cc

Issue 3035: Move importer files into an importer subdirectory. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/firefox2_importer.h ('k') | chrome/browser/firefox3_importer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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 "chrome/browser/firefox2_importer.h"
6
7 #include "base/file_util.h"
8 #include "base/path_service.h"
9 #include "base/registry.h"
10 #include "base/string_util.h"
11 #include "base/values.h"
12 #include "chrome/browser/firefox_importer_utils.h"
13 #include "chrome/browser/mork_reader.h"
14 #include "chrome/browser/template_url.h"
15 #include "chrome/browser/template_url_parser.h"
16 #include "chrome/common/l10n_util.h"
17 #include "chrome/common/time_format.h"
18 #include "generated_resources.h"
19 #include "net/base/data_url.h"
20
21 // Firefox2Importer.
22
23 Firefox2Importer::Firefox2Importer() {
24 }
25
26 Firefox2Importer::~Firefox2Importer() {
27 }
28
29 void Firefox2Importer::StartImport(ProfileInfo profile_info,
30 uint16 items, ProfileWriter* writer,
31 ImporterHost* host) {
32 writer_ = writer;
33 source_path_ = profile_info.source_path;
34 app_path_ = profile_info.app_path;
35 importer_host_ = host;
36
37 // The order here is important!
38 NotifyStarted();
39 if ((items & HOME_PAGE) && !cancelled())
40 ImportHomepage(); // Doesn't have a UI item.
41 if ((items & FAVORITES) && !cancelled()) {
42 NotifyItemStarted(FAVORITES);
43 ImportBookmarks();
44 NotifyItemEnded(FAVORITES);
45 }
46 if ((items & SEARCH_ENGINES) && !cancelled()) {
47 NotifyItemStarted(SEARCH_ENGINES);
48 ImportSearchEngines();
49 NotifyItemEnded(SEARCH_ENGINES);
50 }
51 if ((items & PASSWORDS) && !cancelled()) {
52 NotifyItemStarted(PASSWORDS);
53 ImportPasswords();
54 NotifyItemEnded(PASSWORDS);
55 }
56 if ((items & HISTORY) && !cancelled()) {
57 NotifyItemStarted(HISTORY);
58 ImportHistory();
59 NotifyItemEnded(HISTORY);
60 }
61 NotifyEnded();
62 }
63
64 // static
65 void Firefox2Importer::LoadDefaultBookmarks(const std::wstring& app_path,
66 std::set<GURL> *urls) {
67 // Firefox keeps its default bookmarks in a bookmarks.html file that
68 // lives at: <Firefox install dir>\defaults\profile\bookmarks.html
69 std::wstring file = app_path;
70 file_util::AppendToPath(&file, L"defaults\\profile\\bookmarks.html");
71
72 urls->clear();
73
74 // Read the whole file.
75 std::string content;
76 file_util::ReadFileToString(file, &content);
77 std::vector<std::string> lines;
78 SplitString(content, '\n', &lines);
79
80 std::string charset;
81 for (size_t i = 0; i < lines.size(); ++i) {
82 std::string line;
83 TrimString(lines[i], " ", &line);
84
85 // Get the encoding of the bookmark file.
86 if (ParseCharsetFromLine(line, &charset))
87 continue;
88
89 // Get the bookmark.
90 std::wstring title;
91 GURL url, favicon;
92 std::wstring shortcut;
93 Time add_date;
94 std::wstring post_data;
95 if (ParseBookmarkFromLine(line, charset, &title, &url,
96 &favicon, &shortcut, &add_date,
97 &post_data))
98 urls->insert(url);
99 }
100 }
101
102 // static
103 TemplateURL* Firefox2Importer::CreateTemplateURL(const std::wstring& title,
104 const std::wstring& keyword,
105 const GURL& url) {
106 // Skip if the keyword or url is invalid.
107 if (keyword.empty() && url.is_valid())
108 return NULL;
109
110 TemplateURL* t_url = new TemplateURL();
111 // We set short name by using the title if it exists.
112 // Otherwise, we use the shortcut.
113 t_url->set_short_name(!title.empty() ? title : keyword);
114 t_url->set_keyword(keyword);
115 t_url->SetURL(TemplateURLRef::DisplayURLToURLRef(UTF8ToWide(url.spec())),
116 0, 0);
117 return t_url;
118 }
119
120 void Firefox2Importer::ImportBookmarks() {
121 // Read the whole file.
122 std::wstring file = source_path_;
123 file_util::AppendToPath(&file, L"bookmarks.html");
124 std::string content;
125 file_util::ReadFileToString(file, &content);
126 std::vector<std::string> lines;
127 SplitString(content, '\n', &lines);
128
129 // Load the default bookmarks.
130 std::set<GURL> default_urls;
131 LoadDefaultBookmarks(app_path_, &default_urls);
132
133 // Parse the bookmarks.html file.
134 std::vector<ProfileWriter::BookmarkEntry> bookmarks, toolbar_bookmarks;
135 std::vector<TemplateURL*> template_urls;
136 std::vector<history::ImportedFavIconUsage> favicons;
137 std::wstring last_folder
138 = l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX);
139 bool last_folder_on_toolbar = false;
140 std::vector<std::wstring> path;
141 size_t toolbar_folder = 0;
142 std::string charset;
143 for (size_t i = 0; i < lines.size() && !cancelled(); ++i) {
144 std::string line;
145 TrimString(lines[i], " ", &line);
146
147 // Get the encoding of the bookmark file.
148 if (ParseCharsetFromLine(line, &charset))
149 continue;
150
151 // Get the folder name.
152 if (ParseFolderNameFromLine(line, charset, &last_folder,
153 &last_folder_on_toolbar))
154 continue;
155
156 // Get the bookmark entry.
157 std::wstring title, shortcut;
158 GURL url, favicon;
159 Time add_date;
160 std::wstring post_data;
161 // TODO(jcampan): http://b/issue?id=1196285 we do not support POST based
162 // keywords yet.
163 if (ParseBookmarkFromLine(line, charset, &title,
164 &url, &favicon, &shortcut, &add_date,
165 &post_data) &&
166 post_data.empty() &&
167 CanImportURL(GURL(url)) &&
168 default_urls.find(url) == default_urls.end()) {
169 if (toolbar_folder > path.size() && path.size() > 0) {
170 NOTREACHED(); // error in parsing.
171 break;
172 }
173
174 ProfileWriter::BookmarkEntry entry;
175 entry.creation_time = add_date;
176 entry.url = url;
177 entry.title = title;
178
179 if (first_run() && toolbar_folder) {
180 // Flatten the items in toolbar.
181 entry.in_toolbar = true;
182 entry.path.assign(path.begin() + toolbar_folder, path.end());
183 toolbar_bookmarks.push_back(entry);
184 } else {
185 // Insert the item into the "Imported from Firefox" folder after
186 // the first run.
187 entry.path.assign(path.begin(), path.end());
188 if (first_run())
189 entry.path.erase(entry.path.begin());
190 bookmarks.push_back(entry);
191 }
192
193 // Save the favicon. DataURLToFaviconUsage will handle the case where
194 // there is no favicon.
195 DataURLToFaviconUsage(url, favicon, &favicons);
196
197 // If there is a SHORTCUT attribute for this bookmark, we
198 // add it as our keywords.
199 TemplateURL* t_url = CreateTemplateURL(title, shortcut, url);
200 if (t_url)
201 template_urls.push_back(t_url);
202
203 continue;
204 }
205
206 // Bookmarks in sub-folder are encapsulated with <DL> tag.
207 if (StartsWithASCII(line, "<DL>", true)) {
208 path.push_back(last_folder);
209 last_folder.clear();
210 if (last_folder_on_toolbar && !toolbar_folder)
211 toolbar_folder = path.size();
212 } else if (StartsWithASCII(line, "</DL>", true)) {
213 if (path.empty())
214 break; // Mismatch <DL>.
215 path.pop_back();
216 if (toolbar_folder > path.size())
217 toolbar_folder = 0;
218 }
219 }
220
221 // Write data into profile.
222 bookmarks.insert(bookmarks.begin(), toolbar_bookmarks.begin(),
223 toolbar_bookmarks.end());
224 if (!bookmarks.empty() && !cancelled()) {
225 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
226 &ProfileWriter::AddBookmarkEntry, bookmarks));
227 }
228 if (!template_urls.empty() && !cancelled()) {
229 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
230 &ProfileWriter::AddKeywords, template_urls, -1, false));
231 } else {
232 STLDeleteContainerPointers(template_urls.begin(), template_urls.end());
233 }
234 if (!favicons.empty()) {
235 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
236 &ProfileWriter::AddFavicons, favicons));
237 }
238 }
239
240 void Firefox2Importer::ImportPasswords() {
241 // Initializes NSS3.
242 NSSDecryptor decryptor;
243 if (!decryptor.Init(source_path_, source_path_) &&
244 !decryptor.Init(app_path_, source_path_))
245 return;
246
247 // Firefox 2 uses signons2.txt to store the pssswords. If it doesn't
248 // exist, we try to find its older version.
249 std::wstring file = source_path_;
250 file_util::AppendToPath(&file, L"signons2.txt");
251 if (!file_util::PathExists(file)) {
252 file = source_path_;
253 file_util::AppendToPath(&file, L"signons.txt");
254 }
255
256 std::string content;
257 file_util::ReadFileToString(file, &content);
258 std::vector<PasswordForm> forms;
259 decryptor.ParseSignons(content, &forms);
260
261 if (!cancelled()) {
262 for (size_t i = 0; i < forms.size(); ++i) {
263 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
264 &ProfileWriter::AddPasswordForm, forms[i]));
265 }
266 }
267 }
268
269 void Firefox2Importer::ImportHistory() {
270 std::wstring file = source_path_;
271 file_util::AppendToPath(&file, L"history.dat");
272 ImportHistoryFromFirefox2(file, main_loop_, writer_);
273 }
274
275 void Firefox2Importer::ImportSearchEngines() {
276 std::vector<std::wstring> files;
277 GetSearchEnginesXMLFiles(&files);
278
279 std::vector<TemplateURL*> search_engines;
280 ParseSearchEnginesFromXMLFiles(files, &search_engines);
281 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
282 &ProfileWriter::AddKeywords, search_engines,
283 GetFirefoxDefaultSearchEngineIndex(search_engines, source_path_),
284 true));
285 }
286
287 void Firefox2Importer::ImportHomepage() {
288 GURL homepage = GetHomepage(source_path_);
289 if (homepage.is_valid() && !IsDefaultHomepage(homepage, app_path_)) {
290 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
291 &ProfileWriter::AddHomepage, homepage));
292 }
293 }
294
295 void Firefox2Importer::GetSearchEnginesXMLFiles(
296 std::vector<std::wstring>* files) {
297 // Search engines are contained in XML files in a searchplugins directory that
298 // can be found in 2 locations:
299 // - Firefox install dir (default search engines)
300 // - the profile dir (user added search engines)
301 std::wstring dir(app_path_);
302 file_util::AppendToPath(&dir, L"searchplugins");
303 FindXMLFilesInDir(dir, files);
304
305 std::wstring profile_dir = source_path_;
306 file_util::AppendToPath(&profile_dir, L"searchplugins");
307 FindXMLFilesInDir(profile_dir, files);
308 }
309
310 // static
311 bool Firefox2Importer::ParseCharsetFromLine(const std::string& line,
312 std::string* charset) {
313 const char kCharset[] = "charset=";
314 if (StartsWithASCII(line, "<META", true) &&
315 line.find("CONTENT=\"") != std::string::npos) {
316 size_t begin = line.find(kCharset);
317 if (begin == std::string::npos)
318 return false;
319 begin += std::string(kCharset).size();
320 size_t end = line.find_first_of('\"', begin);
321 *charset = line.substr(begin, end - begin);
322 return true;
323 }
324 return false;
325 }
326
327 // static
328 bool Firefox2Importer::ParseFolderNameFromLine(const std::string& line,
329 const std::string& charset,
330 std::wstring* folder_name,
331 bool* is_toolbar_folder) {
332 const char kFolderOpen[] = "<DT><H3";
333 const char kFolderClose[] = "</H3>";
334 const char kToolbarFolderAttribute[] = "PERSONAL_TOOLBAR_FOLDER";
335
336 if (!StartsWithASCII(line, kFolderOpen, true))
337 return false;
338
339 size_t end = line.find(kFolderClose);
340 size_t tag_end = line.rfind('>', end) + 1;
341 // If no end tag or start tag is broken, we skip to find the folder name.
342 if (end == std::string::npos || tag_end < arraysize(kFolderOpen))
343 return false;
344
345 CodepageToWide(line.substr(tag_end, end - tag_end), charset.c_str(),
346 OnStringUtilConversionError::SKIP, folder_name);
347 HTMLUnescape(folder_name);
348
349 std::string attribute_list = line.substr(arraysize(kFolderOpen),
350 tag_end - arraysize(kFolderOpen) - 1);
351 std::string value;
352 if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
353 LowerCaseEqualsASCII(value, "true"))
354 *is_toolbar_folder = true;
355 else
356 *is_toolbar_folder = false;
357
358 return true;
359 }
360
361 // static
362 bool Firefox2Importer::ParseBookmarkFromLine(const std::string& line,
363 const std::string& charset,
364 std::wstring* title,
365 GURL* url,
366 GURL* favicon,
367 std::wstring* shortcut,
368 Time* add_date,
369 std::wstring* post_data) {
370 const char kItemOpen[] = "<DT><A";
371 const char kItemClose[] = "</A>";
372 const char kFeedURLAttribute[] = "FEEDURL";
373 const char kHrefAttribute[] = "HREF";
374 const char kIconAttribute[] = "ICON";
375 const char kShortcutURLAttribute[] = "SHORTCUTURL";
376 const char kAddDateAttribute[] = "ADD_DATE";
377 const char kPostDataAttribute[] = "POST_DATA";
378
379 title->clear();
380 *url = GURL();
381 *favicon = GURL();
382 shortcut->clear();
383 post_data->clear();
384 *add_date = Time();
385
386 if (!StartsWithASCII(line, kItemOpen, true))
387 return false;
388
389 size_t end = line.find(kItemClose);
390 size_t tag_end = line.rfind('>', end) + 1;
391 if (end == std::string::npos || tag_end < arraysize(kItemOpen))
392 return false; // No end tag or start tag is broken.
393
394 std::string attribute_list = line.substr(arraysize(kItemOpen),
395 tag_end - arraysize(kItemOpen) - 1);
396
397 // We don't import Live Bookmark folders, which is Firefox's RSS reading
398 // feature, since the user never necessarily bookmarked them and we don't
399 // have this feature to update their contents.
400 std::string value;
401 if (GetAttribute(attribute_list, kFeedURLAttribute, &value))
402 return false;
403
404 // Title
405 CodepageToWide(line.substr(tag_end, end - tag_end), charset.c_str(),
406 OnStringUtilConversionError::SKIP, title);
407 HTMLUnescape(title);
408
409 // URL
410 if (GetAttribute(attribute_list, kHrefAttribute, &value)) {
411 ReplaceSubstringsAfterOffset(&value, 0, "%22", "\"");
412 *url = GURL(value);
413 }
414
415 // Favicon
416 if (GetAttribute(attribute_list, kIconAttribute, &value))
417 *favicon = GURL(value);
418
419 // Keyword
420 if (GetAttribute(attribute_list, kShortcutURLAttribute, &value)) {
421 CodepageToWide(value, charset.c_str(), OnStringUtilConversionError::SKIP,
422 shortcut);
423 HTMLUnescape(shortcut);
424 }
425
426 // Add date
427 if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
428 int64 time = StringToInt64(value);
429 // Upper bound it at 32 bits.
430 if (0 < time && time < (1LL << 32))
431 *add_date = Time::FromTimeT(time);
432 }
433
434 // Post data.
435 if (GetAttribute(attribute_list, kPostDataAttribute, &value)) {
436 CodepageToWide(value, charset.c_str(),
437 OnStringUtilConversionError::SKIP, post_data);
438 HTMLUnescape(post_data);
439 }
440
441 return true;
442 }
443
444 // static
445 bool Firefox2Importer::GetAttribute(const std::string& attribute_list,
446 const std::string& attribute,
447 std::string* value) {
448 const char kQuote[] = "\"";
449
450 size_t begin = attribute_list.find(attribute + "=" + kQuote);
451 if (begin == std::string::npos)
452 return false; // Can't find the attribute.
453
454 begin = attribute_list.find(kQuote, begin) + 1;
455 size_t end = attribute_list.find(kQuote, begin);
456 if (end == std::string::npos)
457 return false; // The value is not quoted.
458
459 *value = attribute_list.substr(begin, end - begin);
460 return true;
461 }
462
463 // static
464 void Firefox2Importer::HTMLUnescape(std::wstring *text) {
465 ReplaceSubstringsAfterOffset(text, 0, L"&lt;", L"<");
466 ReplaceSubstringsAfterOffset(text, 0, L"&gt;", L">");
467 ReplaceSubstringsAfterOffset(text, 0, L"&amp;", L"&");
468 ReplaceSubstringsAfterOffset(text, 0, L"&quot;", L"\"");
469 ReplaceSubstringsAfterOffset(text, 0, L"&#39;", L"\'");
470 }
471
472 // static
473 void Firefox2Importer::FindXMLFilesInDir(
474 const std::wstring& dir,
475 std::vector<std::wstring>* xml_files) {
476 file_util::FileEnumerator file_enum(dir, false,
477 file_util::FileEnumerator::FILES,
478 L"*.xml");
479 std::wstring file(file_enum.Next());
480 while (!file.empty()) {
481 xml_files->push_back(file);
482 file = file_enum.Next();
483 }
484 }
485
486 // static
487 void Firefox2Importer::DataURLToFaviconUsage(
488 const GURL& link_url,
489 const GURL& favicon_data,
490 std::vector<history::ImportedFavIconUsage>* favicons) {
491 if (!link_url.is_valid() || !favicon_data.is_valid() ||
492 !favicon_data.SchemeIs("data"))
493 return;
494
495 // Parse the data URL.
496 std::string mime_type, char_set, data;
497 if (!net::DataURL::Parse(favicon_data, &mime_type, &char_set, &data) ||
498 data.empty())
499 return;
500
501 history::ImportedFavIconUsage usage;
502 if (!ReencodeFavicon(reinterpret_cast<const unsigned char*>(&data[0]),
503 data.size(), &usage.png_data))
504 return; // Unable to decode.
505
506 // We need to make up a URL for the favicon. We use a version of the page's
507 // URL so that we can be sure it will not collide.
508 usage.favicon_url = GURL(std::string("made-up-favicon:") + link_url.spec());
509
510 // We only have one URL per favicon for Firefox 2 bookmarks.
511 usage.urls.insert(link_url);
512
513 favicons->push_back(usage);
514 }
515
OLDNEW
« no previous file with comments | « chrome/browser/firefox2_importer.h ('k') | chrome/browser/firefox3_importer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698