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

Side by Side Diff: chrome/browser/ie_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/ie_importer.h ('k') | chrome/browser/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/ie_importer.h"
6
7 #include <intshcut.h>
8 #include <pstore.h>
9 #include <shlobj.h>
10 #include <urlhist.h>
11 #include <algorithm>
12
13 #include "base/file_util.h"
14 #include "base/registry.h"
15 #include "base/string_util.h"
16 #include "base/time.h"
17 #include "base/win_util.h"
18 #include "chrome/browser/bookmarks/bookmark_model.h"
19 #include "chrome/browser/ie7_password.h"
20 #include "chrome/browser/template_url_model.h"
21 #include "chrome/common/l10n_util.h"
22 #include "chrome/common/time_format.h"
23 #include "chrome/common/win_util.h"
24 #include "googleurl/src/gurl.h"
25
26 #include "generated_resources.h"
27
28 namespace {
29
30 // Gets the creation time of the given file or directory.
31 static Time GetFileCreationTime(const std::wstring& file) {
32 Time creation_time;
33 ScopedHandle file_handle(
34 CreateFile(file.c_str(), GENERIC_READ,
35 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
36 NULL, OPEN_EXISTING,
37 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL));
38 FILETIME creation_filetime;
39 if (GetFileTime(file_handle, &creation_filetime, NULL, NULL))
40 creation_time = Time::FromFileTime(creation_filetime);
41 return creation_time;
42 }
43
44 } // namespace
45
46 // static
47 // {E161255A-37C3-11D2-BCAA-00C04fD929DB}
48 const GUID IEImporter::kPStoreAutocompleteGUID = {0xe161255a, 0x37c3, 0x11d2,
49 {0xbc, 0xaa, 0x00, 0xc0, 0x4f, 0xd9, 0x29, 0xdb}};
50 // {A79029D6-753E-4e27-B807-3D46AB1545DF}
51 const GUID IEImporter::kUnittestGUID = { 0xa79029d6, 0x753e, 0x4e27,
52 {0xb8, 0x7, 0x3d, 0x46, 0xab, 0x15, 0x45, 0xdf}};
53
54 void IEImporter::StartImport(ProfileInfo profile_info,
55 uint16 items,
56 ProfileWriter* writer,
57 ImporterHost* host) {
58 writer_ = writer;
59 source_path_ = profile_info.source_path;
60 importer_host_ = host;
61
62 NotifyStarted();
63
64 // Some IE settings (such as Protected Storage) is obtained via COM APIs.
65 win_util::ScopedCOMInitializer com_initializer;
66
67 if ((items & HOME_PAGE) && !cancelled())
68 ImportHomepage(); // Doesn't have a UI item.
69 // The order here is important!
70 if ((items & FAVORITES) && !cancelled()) {
71 NotifyItemStarted(FAVORITES);
72 ImportFavorites();
73 NotifyItemEnded(FAVORITES);
74 }
75 if ((items & SEARCH_ENGINES) && !cancelled()) {
76 NotifyItemStarted(SEARCH_ENGINES);
77 ImportSearchEngines();
78 NotifyItemEnded(SEARCH_ENGINES);
79 }
80 if ((items & PASSWORDS) && !cancelled()) {
81 NotifyItemStarted(PASSWORDS);
82 // Always import IE6 passwords.
83 ImportPasswordsIE6();
84
85 if (CurrentIEVersion() >= 7)
86 ImportPasswordsIE7();
87 NotifyItemEnded(PASSWORDS);
88 }
89 if ((items & HISTORY) && !cancelled()) {
90 NotifyItemStarted(HISTORY);
91 ImportHistory();
92 NotifyItemEnded(HISTORY);
93 }
94 NotifyEnded();
95 }
96
97 void IEImporter::ImportFavorites() {
98 std::wstring path;
99
100 FavoritesInfo info;
101 if (!GetFavoritesInfo(&info))
102 return;
103
104 BookmarkVector bookmarks;
105 ParseFavoritesFolder(info, &bookmarks);
106
107 if (!bookmarks.empty() && !cancelled()) {
108 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
109 &ProfileWriter::AddBookmarkEntry, bookmarks));
110 }
111 }
112
113 void IEImporter::ImportPasswordsIE6() {
114 GUID AutocompleteGUID = kPStoreAutocompleteGUID;
115 if (!source_path_.empty()) {
116 // We supply a fake GUID for testting.
117 AutocompleteGUID = kUnittestGUID;
118 }
119
120 // The PStoreCreateInstance function retrieves an interface pointer
121 // to a storage provider. But this function has no associated import
122 // library or header file, we must call it using the LoadLibrary()
123 // and GetProcAddress() functions.
124 typedef HRESULT (WINAPI *PStoreCreateFunc)(IPStore**, DWORD, DWORD, DWORD);
125 HMODULE pstorec_dll = LoadLibrary(L"pstorec.dll");
126 PStoreCreateFunc PStoreCreateInstance =
127 (PStoreCreateFunc)GetProcAddress(pstorec_dll, "PStoreCreateInstance");
128
129 CComPtr<IPStore> pstore;
130 HRESULT result = PStoreCreateInstance(&pstore, 0, 0, 0);
131 if (result != S_OK) {
132 FreeLibrary(pstorec_dll);
133 return;
134 }
135
136 std::vector<AutoCompleteInfo> ac_list;
137
138 // Enumerates AutoComplete items in the protected database.
139 CComPtr<IEnumPStoreItems> item;
140 result = pstore->EnumItems(0, &AutocompleteGUID,
141 &AutocompleteGUID, 0, &item);
142 if (result != PST_E_OK) {
143 pstore.Release();
144 FreeLibrary(pstorec_dll);
145 return;
146 }
147
148 wchar_t* item_name;
149 while (!cancelled() && SUCCEEDED(item->Next(1, &item_name, 0))) {
150 DWORD length = 0;
151 unsigned char* buffer = NULL;
152 result = pstore->ReadItem(0, &AutocompleteGUID, &AutocompleteGUID,
153 item_name, &length, &buffer, NULL, 0);
154 if (SUCCEEDED(result)) {
155 AutoCompleteInfo ac;
156 ac.key = item_name;
157 std::wstring data;
158 data.insert(0, reinterpret_cast<wchar_t*>(buffer),
159 length / sizeof(wchar_t));
160
161 // The key name is always ended with ":StringData".
162 const wchar_t kDataSuffix[] = L":StringData";
163 size_t i = ac.key.rfind(kDataSuffix);
164 if (i != std::wstring::npos && ac.key.substr(i) == kDataSuffix) {
165 ac.key.erase(i);
166 ac.is_url = (ac.key.find(L"://") != std::wstring::npos);
167 ac_list.push_back(ac);
168 SplitString(data, L'\0', &ac_list[ac_list.size() - 1].data);
169 }
170 CoTaskMemFree(buffer);
171 }
172 CoTaskMemFree(item_name);
173 }
174 // Releases them before unload the dll.
175 item.Release();
176 pstore.Release();
177 FreeLibrary(pstorec_dll);
178
179 size_t i;
180 for (i = 0; i < ac_list.size(); i++) {
181 if (!ac_list[i].is_url || ac_list[i].data.size() < 2)
182 continue;
183
184 GURL url(ac_list[i].key.c_str());
185 if (!(LowerCaseEqualsASCII(url.scheme(), "http") ||
186 LowerCaseEqualsASCII(url.scheme(), "https"))) {
187 continue;
188 }
189
190 PasswordForm form;
191 GURL::Replacements rp;
192 rp.ClearUsername();
193 rp.ClearPassword();
194 rp.ClearQuery();
195 rp.ClearRef();
196 form.origin = url.ReplaceComponents(rp);
197 form.username_value = ac_list[i].data[0];
198 form.password_value = ac_list[i].data[1];
199 form.signon_realm = url.GetOrigin().spec();
200
201 // This is not precise, because a scheme of https does not imply a valid
202 // certificate was presented; however we assign it this way so that if we
203 // import a password from IE whose scheme is https, we give it the benefit
204 // of the doubt and DONT auto-fill it unless the form appears under
205 // valid SSL conditions.
206 form.ssl_valid = url.SchemeIsSecure();
207
208 // Goes through the list to find out the username field
209 // of the web page.
210 size_t list_it, item_it;
211 for (list_it = 0; list_it < ac_list.size(); ++list_it) {
212 if (ac_list[list_it].is_url)
213 continue;
214
215 for (item_it = 0; item_it < ac_list[list_it].data.size(); ++item_it)
216 if (ac_list[list_it].data[item_it] == form.username_value) {
217 form.username_element = ac_list[list_it].key;
218 break;
219 }
220 }
221
222 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
223 &ProfileWriter::AddPasswordForm, form));
224 }
225 }
226
227 void IEImporter::ImportPasswordsIE7() {
228 if (!source_path_.empty()) {
229 // We have been called from the unit tests. Don't import real passwords.
230 return;
231 }
232
233 const wchar_t kStorage2Path[] =
234 L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2";
235
236 RegKey key(HKEY_CURRENT_USER, kStorage2Path, KEY_READ);
237 RegistryValueIterator reg_iterator(HKEY_CURRENT_USER, kStorage2Path);
238 while (reg_iterator.Valid() && !cancelled()) {
239 // Get the size of the encrypted data.
240 DWORD value_len = 0;
241 if (key.ReadValue(reg_iterator.Name(), NULL, &value_len) && value_len) {
242 // Query the encrypted data.
243 std::vector<unsigned char> value;
244 value.resize(value_len);
245 if (key.ReadValue(reg_iterator.Name(), &value.front(), &value_len)) {
246 IE7PasswordInfo password_info;
247 password_info.url_hash = reg_iterator.Name();
248 password_info.encrypted_data = value;
249 password_info.date_created = Time::Now();
250 main_loop_->PostTask(FROM_HERE,
251 NewRunnableMethod(writer_,
252 &ProfileWriter::AddIE7PasswordInfo,
253 password_info));
254 }
255 }
256
257 ++reg_iterator;
258 }
259 }
260
261 // Reads history information from COM interface.
262 void IEImporter::ImportHistory() {
263 const std::string kSchemes[] = {"http", "https", "ftp", "file"};
264 int total_schemes = arraysize(kSchemes);
265
266 CComPtr<IUrlHistoryStg2> url_history_stg2;
267 HRESULT result;
268 result = url_history_stg2.CoCreateInstance(CLSID_CUrlHistory, NULL,
269 CLSCTX_INPROC_SERVER);
270 if (FAILED(result))
271 return;
272 CComPtr<IEnumSTATURL> enum_url;
273 if (SUCCEEDED(result = url_history_stg2->EnumUrls(&enum_url))) {
274 std::vector<history::URLRow> rows;
275 STATURL stat_url;
276 ULONG fetched;
277 while (!cancelled() &&
278 (result = enum_url->Next(1, &stat_url, &fetched)) == S_OK) {
279 std::wstring url_string;
280 std::wstring title_string;
281 if (stat_url.pwcsUrl) {
282 url_string = stat_url.pwcsUrl;
283 CoTaskMemFree(stat_url.pwcsUrl);
284 }
285 if (stat_url.pwcsTitle) {
286 title_string = stat_url.pwcsTitle;
287 CoTaskMemFree(stat_url.pwcsTitle);
288 }
289
290 GURL url(url_string);
291 // Skips the URLs that are invalid or have other schemes.
292 if (!url.is_valid() ||
293 (std::find(kSchemes, kSchemes + total_schemes, url.scheme()) ==
294 kSchemes + total_schemes))
295 continue;
296
297 history::URLRow row(url);
298 row.set_title(title_string);
299 row.set_last_visit(Time::FromFileTime(stat_url.ftLastVisited));
300 if (stat_url.dwFlags == STATURL_QUERYFLAG_TOPLEVEL) {
301 row.set_visit_count(1);
302 row.set_hidden(false);
303 } else {
304 row.set_hidden(true);
305 }
306
307 rows.push_back(row);
308 }
309
310 if (!rows.empty() && !cancelled()) {
311 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
312 &ProfileWriter::AddHistoryPage, rows));
313 }
314 }
315 }
316
317 void IEImporter::ImportSearchEngines() {
318 // On IE, search engines are stored in the registry, under:
319 // Software\Microsoft\Internet Explorer\SearchScopes
320 // Each key represents a search engine. The URL value contains the URL and
321 // the DisplayName the name.
322 // The default key's name is contained under DefaultScope.
323 const wchar_t kSearchScopePath[] =
324 L"Software\\Microsoft\\Internet Explorer\\SearchScopes";
325
326 RegKey key(HKEY_CURRENT_USER, kSearchScopePath, KEY_READ);
327 std::wstring default_search_engine_name;
328 const TemplateURL* default_search_engine = NULL;
329 std::map<std::wstring, TemplateURL*> search_engines_map;
330 key.ReadValue(L"DefaultScope", &default_search_engine_name);
331 RegistryKeyIterator key_iterator(HKEY_CURRENT_USER, kSearchScopePath);
332 while (key_iterator.Valid()) {
333 std::wstring sub_key_name = kSearchScopePath;
334 sub_key_name.append(L"\\").append(key_iterator.Name());
335 RegKey sub_key(HKEY_CURRENT_USER, sub_key_name.c_str(), KEY_READ);
336 std::wstring url;
337 if (!sub_key.ReadValue(L"URL", &url) || url.empty()) {
338 LOG(INFO) << "No URL for IE search engine at " << key_iterator.Name();
339 ++key_iterator;
340 continue;
341 }
342 // For the name, we try the default value first (as Live Search uses a
343 // non displayable name in DisplayName, and the readable name under the
344 // default value).
345 std::wstring name;
346 if (!sub_key.ReadValue(NULL, &name) || name.empty()) {
347 // Try the displayable name.
348 if (!sub_key.ReadValue(L"DisplayName", &name) || name.empty()) {
349 LOG(INFO) << "No name for IE search engine at " << key_iterator.Name();
350 ++key_iterator;
351 continue;
352 }
353 }
354
355 std::map<std::wstring, TemplateURL*>::iterator t_iter =
356 search_engines_map.find(url);
357 TemplateURL* template_url =
358 (t_iter != search_engines_map.end()) ? t_iter->second : NULL;
359 if (!template_url) {
360 // First time we see that URL.
361 template_url = new TemplateURL();
362 template_url->set_short_name(name);
363 template_url->SetURL(url, 0, 0);
364 // Give this a keyword to facilitate tab-to-search, if possible.
365 template_url->set_keyword(TemplateURLModel::GenerateKeyword(GURL(url),
366 false));
367 template_url->set_show_in_default_list(true);
368 search_engines_map[url] = template_url;
369 }
370 if (template_url && key_iterator.Name() == default_search_engine_name) {
371 DCHECK(!default_search_engine);
372 default_search_engine = template_url;
373 }
374 ++key_iterator;
375 }
376
377 // ProfileWriter::AddKeywords() requires a vector and we have a map.
378 std::map<std::wstring, TemplateURL*>::iterator t_iter;
379 std::vector<TemplateURL*> search_engines;
380 int default_search_engine_index = -1;
381 for (t_iter = search_engines_map.begin(); t_iter != search_engines_map.end();
382 ++t_iter) {
383 search_engines.push_back(t_iter->second);
384 if (default_search_engine == t_iter->second) {
385 default_search_engine_index =
386 static_cast<int>(search_engines.size()) - 1;
387 }
388 }
389 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
390 &ProfileWriter::AddKeywords, search_engines, default_search_engine_index,
391 true));
392 }
393
394 void IEImporter::ImportHomepage() {
395 const wchar_t kIESettingsMain[] =
396 L"Software\\Microsoft\\Internet Explorer\\Main";
397 const wchar_t kIEHomepage[] = L"Start Page";
398 const wchar_t kIEDefaultHomepage[] = L"Default_Page_URL";
399
400 RegKey key(HKEY_CURRENT_USER, kIESettingsMain, KEY_READ);
401 std::wstring homepage_url;
402 if (!key.ReadValue(kIEHomepage, &homepage_url) || homepage_url.empty())
403 return;
404
405 GURL homepage = GURL(homepage_url);
406 if (!homepage.is_valid())
407 return;
408
409 // Check to see if this is the default website and skip import.
410 RegKey keyDefault(HKEY_LOCAL_MACHINE, kIESettingsMain, KEY_READ);
411 std::wstring default_homepage_url;
412 if (keyDefault.ReadValue(kIEDefaultHomepage, &default_homepage_url) &&
413 !default_homepage_url.empty()) {
414 if (homepage.spec() == GURL(default_homepage_url).spec())
415 return;
416 }
417
418 main_loop_->PostTask(FROM_HERE, NewRunnableMethod(writer_,
419 &ProfileWriter::AddHomepage, homepage));
420 }
421
422 bool IEImporter::GetFavoritesInfo(IEImporter::FavoritesInfo *info) {
423 if (!source_path_.empty()) {
424 // Source path exists during testing.
425 info->path = source_path_;
426 file_util::AppendToPath(&info->path, L"Favorites");
427 info->links_folder = L"Links";
428 return true;
429 }
430
431 // IE stores the favorites in the Favorites under user profile's folder.
432 wchar_t buffer[MAX_PATH];
433 if (FAILED(SHGetFolderPath(NULL, CSIDL_FAVORITES, NULL,
434 SHGFP_TYPE_CURRENT, buffer)))
435 return false;
436 info->path = buffer;
437
438 // There is a Links folder under Favorites folder in Windows Vista, but it
439 // is not recording in Vista's registry. So in Vista, we assume the Links
440 // folder is under Favorites folder since it looks like there is not name
441 // different in every language version of Windows Vista.
442 if (win_util::GetWinVersion() != win_util::WINVERSION_VISTA) {
443 // The Link folder name is stored in the registry.
444 DWORD buffer_length = sizeof(buffer);
445 if (!ReadFromRegistry(HKEY_CURRENT_USER,
446 L"Software\\Microsoft\\Internet Explorer\\Toolbar",
447 L"LinksFolderName", buffer, &buffer_length))
448 return false;
449 info->links_folder = buffer;
450 } else {
451 info->links_folder = L"Links";
452 }
453
454 // Gets the creation time of the user's profile folder.
455 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL,
456 SHGFP_TYPE_CURRENT, buffer)))
457 return false;
458 info->profile_creation_time = GetFileCreationTime(buffer);
459
460 return true;
461 }
462
463 void IEImporter::ParseFavoritesFolder(const FavoritesInfo& info,
464 BookmarkVector* bookmarks) {
465 std::wstring ie_folder = l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_IE);
466 BookmarkVector toolbar_bookmarks;
467 std::wstring file;
468 std::vector<std::wstring> file_list;
469 file_util::FileEnumerator file_enumerator(info.path, true,
470 file_util::FileEnumerator::FILES);
471 while (!(file = file_enumerator.Next()).empty() && !cancelled())
472 file_list.push_back(file);
473
474 // Keep the bookmarks in alphabetical order.
475 std::sort(file_list.begin(), file_list.end());
476
477 for (std::vector<std::wstring>::iterator it = file_list.begin();
478 it != file_list.end(); ++it) {
479 std::wstring filename = file_util::GetFilenameFromPath(*it);
480 std::wstring extension = file_util::GetFileExtensionFromPath(filename);
481 if (!LowerCaseEqualsASCII(extension, "url"))
482 continue;
483
484 // We don't import default bookmarks from IE, e.g. "Customize links",
485 // "Free Hotmail". To detect these, we compare the creation time of the
486 // .url file with that of the profile folder. The file's creation time
487 // should be 2 minute later (to allow jitter).
488 Time creation = GetFileCreationTime(*it);
489 if (info.profile_creation_time != Time() &&
490 creation - info.profile_creation_time <= TimeDelta::FromMinutes(2))
491 continue;
492
493 // Skip the bookmark with invalid URL.
494 GURL url = GURL(ResolveInternetShortcut(*it));
495 if (!url.is_valid())
496 continue;
497
498 // Remove the dot and the file extension, and the directory path.
499 std::wstring relative_path = it->substr(info.path.size(),
500 it->size() - filename.size() - info.path.size());
501 TrimString(relative_path, L"\\", &relative_path);
502
503 ProfileWriter::BookmarkEntry entry;
504 entry.title = filename.substr(0, filename.size() - (extension.size() + 1));
505 entry.url = url;
506 entry.creation_time = creation;
507 if (!relative_path.empty())
508 SplitString(relative_path, file_util::kPathSeparator, &entry.path);
509
510 // Flatten the bookmarks in Link folder onto bookmark toolbar. Otherwise,
511 // put it into "Other bookmarks".
512 if (first_run() &&
513 (entry.path.size() > 0 && entry.path[0] == info.links_folder)) {
514 entry.in_toolbar = true;
515 entry.path.erase(entry.path.begin());
516 toolbar_bookmarks.push_back(entry);
517 } else {
518 // After the first run, we put the bookmarks in a "Imported From IE"
519 // folder, so that we don't mess up the "Other bookmarks".
520 if (!first_run())
521 entry.path.insert(entry.path.begin(), ie_folder);
522 bookmarks->push_back(entry);
523 }
524 }
525 bookmarks->insert(bookmarks->begin(), toolbar_bookmarks.begin(),
526 toolbar_bookmarks.end());
527 }
528
529 std::wstring IEImporter::ResolveInternetShortcut(const std::wstring& file) {
530 win_util::CoMemReleaser<wchar_t> url;
531 CComPtr<IUniformResourceLocator> url_locator;
532 HRESULT result = url_locator.CoCreateInstance(CLSID_InternetShortcut, NULL,
533 CLSCTX_INPROC_SERVER);
534 if (FAILED(result))
535 return std::wstring();
536
537 CComPtr<IPersistFile> persist_file;
538 result = url_locator.QueryInterface(&persist_file);
539 if (FAILED(result))
540 return std::wstring();
541
542 // Loads the Internet Shortcut from persistent storage.
543 result = persist_file->Load(file.c_str(), STGM_READ);
544 if (FAILED(result))
545 return std::wstring();
546
547 result = url_locator->GetURL(&url);
548 // GetURL can return S_FALSE (FAILED(S_FALSE) is false) when url == NULL.
549 if (FAILED(result) || (url == NULL))
550 return std::wstring();
551
552 return std::wstring(url);
553 }
554
555 int IEImporter::CurrentIEVersion() const {
556 static int version = -1;
557 if (version < 0) {
558 wchar_t buffer[128];
559 DWORD buffer_length = sizeof(buffer);
560 bool result = ReadFromRegistry(HKEY_LOCAL_MACHINE,
561 L"Software\\Microsoft\\Internet Explorer",
562 L"Version", buffer, &buffer_length);
563 version = (result ? _wtoi(buffer) : 0);
564 }
565 return version;
566 }
567
OLDNEW
« no previous file with comments | « chrome/browser/ie_importer.h ('k') | chrome/browser/importer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698