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