1 // Copyright (c) 2012 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/importer/in_process_importer_bridge.h" 6 7 #include "base/bind.h" 8 #include "base/debug/dump_without_crashing.h" 9 #include "base/files/file_util.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "chrome/browser/importer/external_process_importer_host.h" 13 #include "chrome/browser/search_engines/ui_thread_search_terms_data.h" 14 #include "chrome/common/importer/imported_bookmark_entry.h" 15 #include "chrome/common/importer/imported_favicon_usage.h" 16 #include "chrome/common/importer/importer_autofill_form_data_entry.h" 17 #include "components/autofill/core/browser/webdata/autofill_entry.h" 18 #include "components/autofill/core/common/password_form.h" 19 #include "components/search_engines/template_url.h" 20 #include "components/search_engines/template_url_parser.h" 21 #include "components/search_engines/template_url_prepopulate_data.h" 22 #include "content/public/browser/browser_thread.h" 23 #include "ui/base/l10n/l10n_util.h" 24 25 #if defined(OS_WIN) 26 #include "components/os_crypt/ie7_password_win.h" 27 #endif 28 29 #include <iterator> 30 31 namespace { 32 33 history::URLRows ConvertImporterURLRowsToHistoryURLRows( 34 const std::vector<ImporterURLRow>& rows) { 35 history::URLRows converted; 36 converted.reserve(rows.size()); 37 for (std::vector<ImporterURLRow>::const_iterator it = rows.begin(); 38 it != rows.end(); ++it) { 39 history::URLRow row(it->url); 40 row.set_title(it->title); 41 row.set_visit_count(it->visit_count); 42 row.set_typed_count(it->typed_count); 43 row.set_last_visit(it->last_visit); 44 row.set_hidden(it->hidden); 45 converted.push_back(row); 46 } 47 return converted; 48 } 49 50 history::VisitSource ConvertImporterVisitSourceToHistoryVisitSource( 51 importer::VisitSource visit_source) { 52 switch (visit_source) { 53 case importer::VISIT_SOURCE_BROWSED: 54 return history::SOURCE_BROWSED; 55 case importer::VISIT_SOURCE_FIREFOX_IMPORTED: 56 return history::SOURCE_FIREFOX_IMPORTED; 57 case importer::VISIT_SOURCE_IE_IMPORTED: 58 return history::SOURCE_IE_IMPORTED; 59 case importer::VISIT_SOURCE_SAFARI_IMPORTED: 60 return history::SOURCE_SAFARI_IMPORTED; 61 } 62 NOTREACHED(); 63 return history::SOURCE_SYNCED; 64 } 65 66 // http://crbug.com/404012. Let's see where the empty fields come from. 67 void CheckForEmptyUsernameAndPassword(const autofill::PasswordForm& form) { 68 if (form.username_value.empty() && 69 form.password_value.empty() && 70 !form.blacklisted_by_user) { 71 base::debug::DumpWithoutCrashing(); 72 } 73 } 74 75 } // namespace 76 77 using content::BrowserThread; 78 79 namespace { 80 81 // FirefoxURLParameterFilter is used to remove parameter mentioning Firefox from 82 // the search URL when importing search engines. 83 class FirefoxURLParameterFilter : public TemplateURLParser::ParameterFilter { 84 public: 85 FirefoxURLParameterFilter() {} 86 virtual ~FirefoxURLParameterFilter() {} 87 88 // TemplateURLParser::ParameterFilter method. 89 virtual bool KeepParameter(const std::string& key, 90 const std::string& value) OVERRIDE { 91 std::string low_value = base::StringToLowerASCII(value); 92 if (low_value.find("mozilla") != std::string::npos || 93 low_value.find("firefox") != std::string::npos || 94 low_value.find("moz:") != std::string::npos) { 95 return false; 96 } 97 return true; 98 } 99 100 private: 101 DISALLOW_COPY_AND_ASSIGN(FirefoxURLParameterFilter); 102 }; 103 104 // Creates a TemplateURL with the |keyword| and |url|. |title| may be empty. 105 // This function transfers ownership of the created TemplateURL to the caller. 106 TemplateURL* CreateTemplateURL(const base::string16& title, 107 const base::string16& keyword, 108 const GURL& url) { 109 // Skip if the url is invalid. 110 if (!url.is_valid()) 111 return NULL; 112 113 TemplateURLData data; 114 if (keyword.empty()) 115 data.SetKeyword(TemplateURL::GenerateKeyword(url)); 116 else 117 data.SetKeyword(keyword); 118 // We set short name by using the title if it exists. 119 // Otherwise, we use the shortcut. 120 data.short_name = title.empty() ? keyword : title; 121 data.SetURL( 122 TemplateURLRef::DisplayURLToURLRef(base::UTF8ToUTF16(url.spec()))); 123 return new TemplateURL(data); 124 } 125 126 // Parses the OpenSearch XML files in |xml_files| and populates |search_engines| 127 // with the resulting TemplateURLs. 128 void ParseSearchEnginesFromFirefoxXMLData( 129 const std::vector<std::string>& xml_data, 130 std::vector<TemplateURL*>* search_engines) { 131 DCHECK(search_engines); 132 133 typedef std::map<std::string, TemplateURL*> SearchEnginesMap; 134 SearchEnginesMap search_engine_for_url; 135 FirefoxURLParameterFilter param_filter; 136 // The first XML file represents the default search engine in Firefox 3, so we 137 // need to keep it on top of the list. 138 SearchEnginesMap::const_iterator default_turl = search_engine_for_url.end(); 139 for (std::vector<std::string>::const_iterator xml_iter = 140 xml_data.begin(); xml_iter != xml_data.end(); ++xml_iter) { 141 TemplateURL* template_url = TemplateURLParser::Parse( 142 UIThreadSearchTermsData(NULL), true, 143 xml_iter->data(), xml_iter->length(), ¶m_filter); 144 if (template_url) { 145 SearchEnginesMap::iterator iter = 146 search_engine_for_url.find(template_url->url()); 147 if (iter == search_engine_for_url.end()) { 148 iter = search_engine_for_url.insert( 149 std::make_pair(template_url->url(), template_url)).first; 150 } else { 151 // We have already found a search engine with the same URL. We give 152 // priority to the latest one found, as GetSearchEnginesXMLFiles() 153 // returns a vector with first Firefox default search engines and then 154 // the user's ones. We want to give priority to the user ones. 155 delete iter->second; 156 iter->second = template_url; 157 } 158 if (default_turl == search_engine_for_url.end()) 159 default_turl = iter; 160 } 161 } 162 163 // Put the results in the |search_engines| vector. 164 for (SearchEnginesMap::iterator t_iter = search_engine_for_url.begin(); 165 t_iter != search_engine_for_url.end(); ++t_iter) { 166 if (t_iter == default_turl) 167 search_engines->insert(search_engines->begin(), default_turl->second); 168 else 169 search_engines->push_back(t_iter->second); 170 } 171 } 172 173 } // namespace 174 175 InProcessImporterBridge::InProcessImporterBridge( 176 ProfileWriter* writer, 177 base::WeakPtr<ExternalProcessImporterHost> host) : writer_(writer), 178 host_(host) { 179 } 180 181 void InProcessImporterBridge::AddBookmarks( 182 const std::vector<ImportedBookmarkEntry>& bookmarks, 183 const base::string16& first_folder_name) { 184 BrowserThread::PostTask( 185 BrowserThread::UI, FROM_HERE, 186 base::Bind(&ProfileWriter::AddBookmarks, writer_, bookmarks, 187 first_folder_name)); 188 } 189 190 void InProcessImporterBridge::AddHomePage(const GURL& home_page) { 191 BrowserThread::PostTask( 192 BrowserThread::UI, FROM_HERE, 193 base::Bind(&ProfileWriter::AddHomepage, writer_, home_page)); 194 } 195 196 #if defined(OS_WIN) 197 void InProcessImporterBridge::AddIE7PasswordInfo( 198 const importer::ImporterIE7PasswordInfo& password_info) { 199 IE7PasswordInfo ie7_password_info; 200 ie7_password_info.url_hash = password_info.url_hash; 201 ie7_password_info.encrypted_data = password_info.encrypted_data; 202 ie7_password_info.date_created = password_info.date_created; 203 204 BrowserThread::PostTask( 205 BrowserThread::UI, FROM_HERE, 206 base::Bind(&ProfileWriter::AddIE7PasswordInfo, writer_, 207 ie7_password_info)); 208 } 209 #endif // OS_WIN 210 211 void InProcessImporterBridge::SetFavicons( 212 const std::vector<ImportedFaviconUsage>& favicons) { 213 BrowserThread::PostTask( 214 BrowserThread::UI, FROM_HERE, 215 base::Bind(&ProfileWriter::AddFavicons, writer_, favicons)); 216 } 217 218 void InProcessImporterBridge::SetHistoryItems( 219 const std::vector<ImporterURLRow>& rows, 220 importer::VisitSource visit_source) { 221 history::URLRows converted_rows = 222 ConvertImporterURLRowsToHistoryURLRows(rows); 223 history::VisitSource converted_visit_source = 224 ConvertImporterVisitSourceToHistoryVisitSource(visit_source); 225 BrowserThread::PostTask(BrowserThread::UI, 226 FROM_HERE, 227 base::Bind(&ProfileWriter::AddHistoryPage, 228 writer_, 229 converted_rows, 230 converted_visit_source)); 231 } 232 233 void InProcessImporterBridge::SetKeywords( 234 const std::vector<importer::URLKeywordInfo>& url_keywords, 235 bool unique_on_host_and_path) { 236 ScopedVector<TemplateURL> owned_template_urls; 237 for (size_t i = 0; i < url_keywords.size(); ++i) { 238 owned_template_urls.push_back( 239 CreateTemplateURL(url_keywords[i].display_name, 240 url_keywords[i].keyword, 241 url_keywords[i].url)); 242 } 243 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 244 base::Bind(&ProfileWriter::AddKeywords, writer_, 245 base::Passed(&owned_template_urls), unique_on_host_and_path)); 246 } 247 248 void InProcessImporterBridge::SetFirefoxSearchEnginesXMLData( 249 const std::vector<std::string>& search_engine_data) { 250 std::vector<TemplateURL*> search_engines; 251 ParseSearchEnginesFromFirefoxXMLData(search_engine_data, &search_engines); 252 253 ScopedVector<TemplateURL> owned_template_urls; 254 std::copy(search_engines.begin(), search_engines.end(), 255 std::back_inserter(owned_template_urls)); 256 257 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 258 base::Bind(&ProfileWriter::AddKeywords, writer_, 259 base::Passed(&owned_template_urls), true)); 260 } 261 262 void InProcessImporterBridge::SetPasswordForm( 263 const autofill::PasswordForm& form) { 264 CheckForEmptyUsernameAndPassword(form); 265 BrowserThread::PostTask( 266 BrowserThread::UI, FROM_HERE, 267 base::Bind(&ProfileWriter::AddPasswordForm, writer_, form)); 268 } 269 270 void InProcessImporterBridge::SetAutofillFormData( 271 const std::vector<ImporterAutofillFormDataEntry>& entries) { 272 std::vector<autofill::AutofillEntry> autofill_entries; 273 for (size_t i = 0; i < entries.size(); ++i) { 274 autofill_entries.push_back(autofill::AutofillEntry( 275 autofill::AutofillKey(entries[i].name, entries[i].value), 276 entries[i].first_used, 277 entries[i].last_used)); 278 } 279 280 BrowserThread::PostTask(BrowserThread::UI, 281 FROM_HERE, 282 base::Bind(&ProfileWriter::AddAutofillFormDataEntries, 283 writer_, 284 autofill_entries)); 285 } 286 287 void InProcessImporterBridge::NotifyStarted() { 288 BrowserThread::PostTask( 289 BrowserThread::UI, FROM_HERE, 290 base::Bind(&ExternalProcessImporterHost::NotifyImportStarted, host_)); 291 } 292 293 void InProcessImporterBridge::NotifyItemStarted(importer::ImportItem item) { 294 BrowserThread::PostTask( 295 BrowserThread::UI, FROM_HERE, 296 base::Bind(&ExternalProcessImporterHost::NotifyImportItemStarted, 297 host_, item)); 298 } 299 300 void InProcessImporterBridge::NotifyItemEnded(importer::ImportItem item) { 301 BrowserThread::PostTask( 302 BrowserThread::UI, FROM_HERE, 303 base::Bind(&ExternalProcessImporterHost::NotifyImportItemEnded, 304 host_, item)); 305 } 306 307 void InProcessImporterBridge::NotifyEnded() { 308 BrowserThread::PostTask( 309 BrowserThread::UI, FROM_HERE, 310 base::Bind(&ExternalProcessImporterHost::NotifyImportEnded, host_)); 311 } 312 313 base::string16 InProcessImporterBridge::GetLocalizedString(int message_id) { 314 return l10n_util::GetStringUTF16(message_id); 315 } 316 317 InProcessImporterBridge::~InProcessImporterBridge() {} 318