1 // Copyright (c) 2011 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/search_engines/util.h" 6 7 #include <set> 8 #include <vector> 9 10 #include "base/logging.h" 11 #include "chrome/browser/search_engines/template_url.h" 12 #include "chrome/browser/search_engines/template_url_model.h" 13 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" 14 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "content/browser/browser_thread.h" 17 18 string16 GetDefaultSearchEngineName(Profile* profile) { 19 if (!profile) { 20 NOTREACHED(); 21 return string16(); 22 } 23 const TemplateURL* const default_provider = 24 profile->GetTemplateURLModel()->GetDefaultSearchProvider(); 25 if (!default_provider) { 26 // TODO(cpu): bug 1187517. It is possible to have no default provider. 27 // returning an empty string is a stopgap measure for the crash 28 // http://code.google.com/p/chromium/issues/detail?id=2573 29 return string16(); 30 } 31 return default_provider->short_name(); 32 } 33 34 // Removes (and deletes) TemplateURLs from |urls| that have duplicate 35 // prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a 36 // bug it was possible get dups. This step is only called when the version 37 // number changes. Only pass in a non-NULL value for |service| if the removed 38 // items should be removed from the DB. 39 static void RemoveDuplicatePrepopulateIDs( 40 std::vector<TemplateURL*>* template_urls, 41 WebDataService* service) { 42 DCHECK(template_urls); 43 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI)); 44 45 std::set<int> ids; 46 for (std::vector<TemplateURL*>::iterator i = template_urls->begin(); 47 i != template_urls->end(); ) { 48 int prepopulate_id = (*i)->prepopulate_id(); 49 if (prepopulate_id) { 50 if (ids.find(prepopulate_id) != ids.end()) { 51 if (service) 52 service->RemoveKeyword(**i); 53 delete *i; 54 i = template_urls->erase(i); 55 } else { 56 ids.insert(prepopulate_id); 57 ++i; 58 } 59 } else { 60 ++i; 61 } 62 } 63 } 64 65 // Loads engines from prepopulate data and merges them in with the existing 66 // engines. This is invoked when the version of the prepopulate data changes. 67 void MergeEnginesFromPrepopulateData( 68 PrefService* prefs, 69 WebDataService* service, 70 std::vector<TemplateURL*>* template_urls, 71 const TemplateURL** default_search_provider) { 72 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI)); 73 DCHECK(template_urls); 74 DCHECK(default_search_provider); 75 76 // Build a map from prepopulate id to TemplateURL of existing urls. 77 typedef std::map<int, TemplateURL*> IDMap; 78 IDMap id_to_turl; 79 for (std::vector<TemplateURL*>::iterator i(template_urls->begin()); 80 i != template_urls->end(); ++i) { 81 int prepopulate_id = (*i)->prepopulate_id(); 82 if (prepopulate_id > 0) 83 id_to_turl[prepopulate_id] = *i; 84 } 85 86 std::vector<TemplateURL*> prepopulated_urls; 87 size_t default_search_index; 88 TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs, 89 &prepopulated_urls, 90 &default_search_index); 91 92 std::set<int> updated_ids; 93 for (size_t i = 0; i < prepopulated_urls.size(); ++i) { 94 // We take ownership of |prepopulated_urls[i]|. 95 scoped_ptr<TemplateURL> prepopulated_url(prepopulated_urls[i]); 96 const int prepopulated_id = prepopulated_url->prepopulate_id(); 97 if (!prepopulated_id || updated_ids.count(prepopulated_id)) { 98 // Prepopulate engines need a unique id. 99 NOTREACHED(); 100 continue; 101 } 102 103 TemplateURL* existing_url = NULL; 104 IDMap::iterator existing_url_iter(id_to_turl.find(prepopulated_id)); 105 if (existing_url_iter != id_to_turl.end()) { 106 existing_url = existing_url_iter->second; 107 if (!existing_url->safe_for_autoreplace()) { 108 // User edited the entry, preserve the keyword and description. 109 prepopulated_url->set_safe_for_autoreplace(false); 110 prepopulated_url->set_keyword(existing_url->keyword()); 111 prepopulated_url->set_autogenerate_keyword( 112 existing_url->autogenerate_keyword()); 113 prepopulated_url->set_short_name(existing_url->short_name()); 114 } 115 prepopulated_url->set_id(existing_url->id()); 116 117 *existing_url = *prepopulated_url; 118 if (service) { 119 service->UpdateKeyword(*existing_url); 120 } 121 id_to_turl.erase(existing_url_iter); 122 } else { 123 existing_url = prepopulated_url.get(); 124 template_urls->push_back(prepopulated_url.release()); 125 } 126 DCHECK(existing_url); 127 if (i == default_search_index && !*default_search_provider) 128 *default_search_provider = existing_url; 129 130 updated_ids.insert(prepopulated_id); 131 } 132 133 // Remove any prepopulated engines which are no longer in the master list, as 134 // long as the user hasn't modified them or made them the default engine. 135 for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) { 136 const TemplateURL* template_url = i->second; 137 if ((template_url->safe_for_autoreplace()) && 138 (template_url != *default_search_provider)) { 139 std::vector<TemplateURL*>::iterator i = find(template_urls->begin(), 140 template_urls->end(), 141 template_url); 142 DCHECK(i != template_urls->end()); 143 template_urls->erase(i); 144 if (service) 145 service->RemoveKeyword(*template_url); 146 delete template_url; 147 } 148 } 149 } 150 151 void GetSearchProvidersUsingKeywordResult( 152 const WDTypedResult& result, 153 WebDataService* service, 154 PrefService* prefs, 155 std::vector<TemplateURL*>* template_urls, 156 const TemplateURL** default_search_provider, 157 int* new_resource_keyword_version) { 158 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI)); 159 DCHECK(template_urls); 160 DCHECK(template_urls->empty()); 161 DCHECK(default_search_provider); 162 DCHECK(*default_search_provider == NULL); 163 DCHECK(result.GetType() == KEYWORDS_RESULT); 164 DCHECK(new_resource_keyword_version); 165 166 *new_resource_keyword_version = 0; 167 WDKeywordsResult keyword_result = reinterpret_cast< 168 const WDResult<WDKeywordsResult>*>(&result)->GetValue(); 169 170 template_urls->swap(keyword_result.keywords); 171 172 const int resource_keyword_version = 173 TemplateURLPrepopulateData::GetDataVersion(prefs); 174 if (keyword_result.builtin_keyword_version != resource_keyword_version) { 175 // There should never be duplicate TemplateURLs. We had a bug such that 176 // duplicate TemplateURLs existed for one locale. As such we invoke 177 // RemoveDuplicatePrepopulateIDs to nuke the duplicates. 178 RemoveDuplicatePrepopulateIDs(template_urls, service); 179 } 180 181 if (keyword_result.default_search_provider_id) { 182 // See if we can find the default search provider. 183 for (std::vector<TemplateURL*>::iterator i = template_urls->begin(); 184 i != template_urls->end(); ++i) { 185 if ((*i)->id() == keyword_result.default_search_provider_id) { 186 *default_search_provider = *i; 187 break; 188 } 189 } 190 } 191 192 if (keyword_result.builtin_keyword_version != resource_keyword_version) { 193 MergeEnginesFromPrepopulateData(prefs, service, template_urls, 194 default_search_provider); 195 *new_resource_keyword_version = resource_keyword_version; 196 } 197 } 198 199