• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetDefaultSearchEngineName(Profile * profile)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.
RemoveDuplicatePrepopulateIDs(std::vector<TemplateURL * > * template_urls,WebDataService * service)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.
MergeEnginesFromPrepopulateData(PrefService * prefs,WebDataService * service,std::vector<TemplateURL * > * template_urls,const TemplateURL ** default_search_provider)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 
GetSearchProvidersUsingKeywordResult(const WDTypedResult & result,WebDataService * service,PrefService * prefs,std::vector<TemplateURL * > * template_urls,const TemplateURL ** default_search_provider,int * new_resource_keyword_version)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