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

Side by Side Diff: chrome/browser/search_engines/template_url_service.cc

Issue 10381016: Remove the "autogenerate keyword" bit on TemplateURL. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 7 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/search_engines/template_url_service.h" 5 #include "chrome/browser/search_engines/template_url_service.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/environment.h" 9 #include "base/environment.h"
10 #include "base/i18n/case_conversion.h" 10 #include "base/i18n/case_conversion.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // the rare case the term replaces the URL it's unlikely another keyword would 63 // the rare case the term replaces the URL it's unlikely another keyword would
64 // have the same url. 64 // have the same url.
65 const char kReplacementTerm[] = "blah.blah.blah.blah.blah"; 65 const char kReplacementTerm[] = "blah.blah.blah.blah.blah";
66 66
67 bool TemplateURLsHaveSamePrefs(const TemplateURL* url1, 67 bool TemplateURLsHaveSamePrefs(const TemplateURL* url1,
68 const TemplateURL* url2) { 68 const TemplateURL* url2) {
69 if (url1 == url2) 69 if (url1 == url2)
70 return true; 70 return true;
71 return (url1 != NULL) && (url2 != NULL) && 71 return (url1 != NULL) && (url2 != NULL) &&
72 (url1->short_name() == url2->short_name()) && 72 (url1->short_name() == url2->short_name()) &&
73 (url1->keyword() == url2->keyword()) && 73 ((url1->keyword() == url2->keyword()) ||
sky 2012/05/04 23:20:25 Is it worth moving this to a common place for both
Peter Kasting 2012/05/07 17:50:24 Yes, good idea.
74 (url1->IsGoogleSearchURLWithReplaceableKeyword() &&
75 url2->IsGoogleSearchURLWithReplaceableKeyword())) &&
74 (url1->url() == url2->url()) && 76 (url1->url() == url2->url()) &&
75 (url1->suggestions_url() == url2->suggestions_url()) && 77 (url1->suggestions_url() == url2->suggestions_url()) &&
76 (url1->instant_url() == url2->instant_url()) && 78 (url1->instant_url() == url2->instant_url()) &&
77 (url1->favicon_url() == url2->favicon_url()) && 79 (url1->favicon_url() == url2->favicon_url()) &&
78 (url1->safe_for_autoreplace() == url2->safe_for_autoreplace()) && 80 (url1->safe_for_autoreplace() == url2->safe_for_autoreplace()) &&
79 (url1->show_in_default_list() == url2->show_in_default_list()) && 81 (url1->show_in_default_list() == url2->show_in_default_list()) &&
80 (url1->input_encodings() == url2->input_encodings()); 82 (url1->input_encodings() == url2->input_encodings());
81 } 83 }
82 84
83 TemplateURL* FirstPotentialDefaultEngine( 85 TemplateURL* FirstPotentialDefaultEngine(
84 const TemplateURLService::TemplateURLVector& template_urls) { 86 const TemplateURLService::TemplateURLVector& template_urls) {
85 for (TemplateURLService::TemplateURLVector::const_iterator i( 87 for (TemplateURLService::TemplateURLVector::const_iterator i(
86 template_urls.begin()); i != template_urls.end(); ++i) { 88 template_urls.begin()); i != template_urls.end(); ++i) {
87 if (!(*i)->IsExtensionKeyword() && (*i)->SupportsReplacement()) 89 if (!(*i)->IsExtensionKeyword() && (*i)->SupportsReplacement())
88 return *i; 90 return *i;
89 } 91 }
90 return NULL; 92 return NULL;
91 } 93 }
92 94
95 // If |change_list| contains ACTION_UPDATEs followed by more ACTION_UPDATEs or
96 // ACTION_ADDs for the same GUID, remove all but the last one.
97 //
98 // This is necessary because when syncing we may first need to migrate the
99 // server-provided TemplateURL in some way, then resolve conflicts against a
100 // local URL, generating two different UPDATEs. If we send up both UPDATEs, and
101 // the server does not coalesce them before sending to other clients, then the
102 // first update could cause conflicts on the other clients, resulting in them
103 // sending back UPDATEs of their own to try to resolve things, thus causing mass
104 // confusion. Since the second UPDATE obviates the need for the first, removing
105 // the first locally is safe and avoids any potential for this problem.
106 //
107 // REVIEWERS: Should we instead do this uniquing at a lower level, or guarantee
108 // that the server will coalesce these so the client need not worry?
109 void PreventDuplicateGUIDUpdates(SyncChangeList* change_list) {
110 for (size_t i = change_list->size(); i > 1; ) {
111 --i; // Prevent underflow that could occur if we did this in the loop body.
112 const SyncChange& change_i = (*change_list)[i];
113 if ((change_i.change_type() != SyncChange::ACTION_ADD) &&
114 (change_i.change_type() != SyncChange::ACTION_UPDATE))
115 continue;
116 std::string guid(
117 change_i.sync_data().GetSpecifics().search_engine().sync_guid());
118 for (size_t j = 0; j < i; ) {
119 const SyncChange& change_j = (*change_list)[j];
120 if ((change_j.change_type() == SyncChange::ACTION_UPDATE) &&
121 (change_j.sync_data().GetSpecifics().search_engine().sync_guid() ==
122 guid)) {
123 change_list->erase(change_list->begin() + j);
124 --i;
125 } else {
126 ++j;
127 }
128 }
129 }
130 }
131
93 } // namespace 132 } // namespace
94 133
95 134
96 class TemplateURLService::LessWithPrefix { 135 class TemplateURLService::LessWithPrefix {
97 public: 136 public:
98 // We want to find the set of keywords that begin with a prefix. The STL 137 // We want to find the set of keywords that begin with a prefix. The STL
99 // algorithms will return the set of elements that are "equal to" the 138 // algorithms will return the set of elements that are "equal to" the
100 // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When 139 // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When
101 // cmp() is the typical std::less<>, this results in lexicographic equality; 140 // cmp() is the typical std::less<>, this results in lexicographic equality;
102 // we need to extend this to mark a prefix as "not less than" a keyword it 141 // we need to extend this to mark a prefix as "not less than" a keyword it
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 TemplateURLService::~TemplateURLService() { 192 TemplateURLService::~TemplateURLService() {
154 if (load_handle_) { 193 if (load_handle_) {
155 DCHECK(service_.get()); 194 DCHECK(service_.get());
156 service_->CancelRequest(load_handle_); 195 service_->CancelRequest(load_handle_);
157 } 196 }
158 197
159 STLDeleteElements(&template_urls_); 198 STLDeleteElements(&template_urls_);
160 } 199 }
161 200
162 // static 201 // static
163 string16 TemplateURLService::GenerateKeyword(const GURL& url, 202 string16 TemplateURLService::GenerateKeyword(const GURL& url) {
164 bool autodetected) { 203 DCHECK(url.is_valid());
165 // Don't autogenerate keywords for referrers that are the result of a form
166 // submission (TODO: right now we approximate this by checking for the URL
167 // having a query, but we should replace this with a call to WebCore to see if
168 // the originating page was actually a form submission), anything other than
169 // http, or referrers with a path.
170 //
171 // If we relax the path constraint, we need to be sure to sanitize the path
172 // elements and update AutocompletePopup to look for keywords using the path.
173 // See http://b/issue?id=863583.
174 if (!url.is_valid() ||
175 (autodetected && (url.has_query() || !url.SchemeIs(chrome::kHttpScheme) ||
176 ((url.path() != "") && (url.path() != "/")))))
177 return string16();
178
179 // Strip "www." off the front of the keyword; otherwise the keyword won't work 204 // Strip "www." off the front of the keyword; otherwise the keyword won't work
180 // properly. See http://code.google.com/p/chromium/issues/detail?id=6984 . 205 // properly. See http://code.google.com/p/chromium/issues/detail?id=6984 .
181 // Special case: if the host was exactly "www." (not sure this can happen but 206 // Special case: if the host was exactly "www." (not sure this can happen but
182 // perhaps with some weird intranet and custom DNS server?), ensure we at 207 // perhaps with some weird intranet and custom DNS server?), ensure we at
183 // least don't return the empty string. 208 // least don't return the empty string.
184 string16 keyword(net::StripWWW(UTF8ToUTF16(url.host()))); 209 string16 keyword(net::StripWWW(UTF8ToUTF16(url.host())));
185 return keyword.empty() ? ASCIIToUTF16("www") : keyword; 210 return keyword.empty() ? ASCIIToUTF16("www") : keyword;
186 } 211 }
187 212
188 // static 213 // static
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 DCHECK(t_url); 249 DCHECK(t_url);
225 UIThreadSearchTermsData search_terms_data; 250 UIThreadSearchTermsData search_terms_data;
226 return GenerateSearchURLUsingTermsData(t_url, search_terms_data); 251 return GenerateSearchURLUsingTermsData(t_url, search_terms_data);
227 } 252 }
228 253
229 // static 254 // static
230 GURL TemplateURLService::GenerateSearchURLUsingTermsData( 255 GURL TemplateURLService::GenerateSearchURLUsingTermsData(
231 const TemplateURL* t_url, 256 const TemplateURL* t_url,
232 const SearchTermsData& search_terms_data) { 257 const SearchTermsData& search_terms_data) {
233 DCHECK(t_url); 258 DCHECK(t_url);
259 DCHECK(!t_url->IsExtensionKeyword());
260
234 const TemplateURLRef& search_ref = t_url->url_ref(); 261 const TemplateURLRef& search_ref = t_url->url_ref();
235 // Extension keywords don't have host-based search URLs. 262 if (!search_ref.IsValidUsingTermsData(search_terms_data))
236 if (!search_ref.IsValidUsingTermsData(search_terms_data) ||
237 t_url->IsExtensionKeyword())
238 return GURL(); 263 return GURL();
239 264
240 if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data)) 265 if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data))
241 return GURL(t_url->url()); 266 return GURL(t_url->url());
242 267
243 return GURL(search_ref.ReplaceSearchTermsUsingTermsData( 268 return GURL(search_ref.ReplaceSearchTermsUsingTermsData(
244 ASCIIToUTF16(kReplacementTerm), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, 269 ASCIIToUTF16(kReplacementTerm), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
245 string16(), search_terms_data)); 270 string16(), search_terms_data));
246 } 271 }
247 272
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 const std::string& host) { 352 const std::string& host) {
328 TemplateURL* t_url = provider_map_->GetTemplateURLForHost(host); 353 TemplateURL* t_url = provider_map_->GetTemplateURLForHost(host);
329 if (t_url) 354 if (t_url)
330 return t_url; 355 return t_url;
331 return (initial_default_search_provider_.get() && 356 return (initial_default_search_provider_.get() &&
332 (GenerateSearchURL(initial_default_search_provider_.get()).host() == 357 (GenerateSearchURL(initial_default_search_provider_.get()).host() ==
333 host)) ? initial_default_search_provider_.get() : NULL; 358 host)) ? initial_default_search_provider_.get() : NULL;
334 } 359 }
335 360
336 void TemplateURLService::Add(TemplateURL* template_url) { 361 void TemplateURLService::Add(TemplateURL* template_url) {
337 AddNoNotify(template_url, true); 362 if (AddNoNotify(template_url, true))
338 NotifyObservers(); 363 NotifyObservers();
339 } 364 }
340 365
341 void TemplateURLService::AddAndSetProfile(TemplateURL* template_url, 366 void TemplateURLService::AddAndSetProfile(TemplateURL* template_url,
342 Profile* profile) { 367 Profile* profile) {
343 template_url->profile_ = profile; 368 template_url->profile_ = profile;
344 Add(template_url); 369 Add(template_url);
345 } 370 }
346 371
347 void TemplateURLService::AddWithOverrides(TemplateURL* template_url, 372 void TemplateURLService::AddWithOverrides(TemplateURL* template_url,
348 const string16& short_name, 373 const string16& short_name,
349 const string16& keyword, 374 const string16& keyword,
350 const std::string& url) { 375 const std::string& url) {
376 DCHECK(!keyword.empty());
351 DCHECK(!url.empty()); 377 DCHECK(!url.empty());
352 template_url->data_.short_name = short_name; 378 template_url->data_.short_name = short_name;
353 template_url->data_.SetKeyword(keyword); 379 template_url->data_.SetKeyword(keyword);
354 template_url->SetURL(url); 380 template_url->SetURL(url);
355 Add(template_url); 381 Add(template_url);
356 } 382 }
357 383
358 void TemplateURLService::Remove(TemplateURL* template_url) { 384 void TemplateURLService::Remove(TemplateURL* template_url) {
359 RemoveNoNotify(template_url); 385 RemoveNoNotify(template_url);
360 NotifyObservers(); 386 NotifyObservers();
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 } 473 }
448 474
449 void TemplateURLService::IncrementUsageCount(TemplateURL* url) { 475 void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
450 DCHECK(url && std::find(template_urls_.begin(), template_urls_.end(), url) != 476 DCHECK(url && std::find(template_urls_.begin(), template_urls_.end(), url) !=
451 template_urls_.end()); 477 template_urls_.end());
452 ++url->data_.usage_count; 478 ++url->data_.usage_count;
453 // Extension keywords are not persisted. 479 // Extension keywords are not persisted.
454 // TODO(mpcomplete): If we allow editing extension keywords, then those should 480 // TODO(mpcomplete): If we allow editing extension keywords, then those should
455 // be persisted to disk and synced. 481 // be persisted to disk and synced.
456 if (service_.get() && !url->IsExtensionKeyword()) 482 if (service_.get() && !url->IsExtensionKeyword())
457 service_.get()->UpdateKeyword(*url); 483 service_.get()->UpdateKeyword(url->data());
458 } 484 }
459 485
460 void TemplateURLService::ResetTemplateURL(TemplateURL* url, 486 void TemplateURLService::ResetTemplateURL(TemplateURL* url,
461 const string16& title, 487 const string16& title,
462 const string16& keyword, 488 const string16& keyword,
463 const std::string& search_url) { 489 const std::string& search_url) {
490 DCHECK(!keyword.empty());
464 DCHECK(!search_url.empty()); 491 DCHECK(!search_url.empty());
465 TemplateURLData data(url->data()); 492 TemplateURLData data(url->data());
466 data.short_name = title; 493 data.short_name = title;
467 data.SetKeyword(keyword); 494 data.SetKeyword(keyword);
468 if (search_url != data.url()) { 495 if (search_url != data.url()) {
469 data.SetURL(search_url); 496 data.SetURL(search_url);
470 // The urls have changed, reset the favicon url. 497 // The urls have changed, reset the favicon url.
471 data.favicon_url = GURL(); 498 data.favicon_url = GURL();
472 } 499 }
473 data.safe_for_autoreplace = false; 500 data.safe_for_autoreplace = false;
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // The value from the preferences was previously stored in the database. 631 // The value from the preferences was previously stored in the database.
605 // Reuse it. 632 // Reuse it.
606 } else { 633 } else {
607 // The value from the preferences takes over. 634 // The value from the preferences takes over.
608 default_search_provider = NULL; 635 default_search_provider = NULL;
609 if (default_from_prefs.get()) { 636 if (default_from_prefs.get()) {
610 TemplateURLData data(default_from_prefs->data()); 637 TemplateURLData data(default_from_prefs->data());
611 data.created_by_policy = true; 638 data.created_by_policy = true;
612 data.id = kInvalidTemplateURLID; 639 data.id = kInvalidTemplateURLID;
613 default_search_provider = new TemplateURL(profile_, data); 640 default_search_provider = new TemplateURL(profile_, data);
614 AddNoNotify(default_search_provider, true); 641 if (!AddNoNotify(default_search_provider, true))
642 default_search_provider = NULL;
615 } 643 }
616 } 644 }
617 // Note that this saves the default search provider to prefs. 645 // Note that this saves the default search provider to prefs.
618 if (!default_search_provider || 646 if (!default_search_provider ||
619 (!default_search_provider->IsExtensionKeyword() && 647 (!default_search_provider->IsExtensionKeyword() &&
620 default_search_provider->SupportsReplacement())) 648 default_search_provider->SupportsReplacement()))
621 SetDefaultSearchProviderNoNotify(default_search_provider); 649 SetDefaultSearchProviderNoNotify(default_search_provider);
622 } else { 650 } else {
623 // If we had a managed default, replace it with the synced default if 651 // If we had a managed default, replace it with the synced default if
624 // applicable, or the first provider of the list. 652 // applicable, or the first provider of the list.
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 DCHECK_EQ(syncable::SEARCH_ENGINES, iter->sync_data().GetDataType()); 830 DCHECK_EQ(syncable::SEARCH_ENGINES, iter->sync_data().GetDataType());
803 831
804 std::string guid = 832 std::string guid =
805 iter->sync_data().GetSpecifics().search_engine().sync_guid(); 833 iter->sync_data().GetSpecifics().search_engine().sync_guid();
806 TemplateURL* existing_turl = GetTemplateURLForGUID(guid); 834 TemplateURL* existing_turl = GetTemplateURLForGUID(guid);
807 scoped_ptr<TemplateURL> turl(CreateTemplateURLFromTemplateURLAndSyncData( 835 scoped_ptr<TemplateURL> turl(CreateTemplateURLFromTemplateURLAndSyncData(
808 profile_, existing_turl, iter->sync_data(), &new_changes)); 836 profile_, existing_turl, iter->sync_data(), &new_changes));
809 if (!turl.get()) 837 if (!turl.get())
810 continue; 838 continue;
811 839
840 // Explicitly don't check for conflicts against extension keywords; in this
841 // case the functions which modify the keyword map know how to handle the
842 // conflicts.
843 // TODO(mpcomplete): If we allow editing extension keywords, then those will
844 // need to undergo conflict resolution.
812 TemplateURL* existing_keyword_turl = 845 TemplateURL* existing_keyword_turl =
813 GetTemplateURLForKeyword(turl->keyword()); 846 FindNonExtensionTemplateURLForKeyword(turl->keyword());
814
815 if (iter->change_type() == SyncChange::ACTION_DELETE && existing_turl) { 847 if (iter->change_type() == SyncChange::ACTION_DELETE && existing_turl) {
816 bool delete_default = (existing_turl == GetDefaultSearchProvider()); 848 bool delete_default = (existing_turl == GetDefaultSearchProvider());
817 849
818 if (delete_default && is_default_search_managed_) { 850 if (delete_default && is_default_search_managed_) {
819 NOTREACHED() << "Tried to delete managed default search provider"; 851 NOTREACHED() << "Tried to delete managed default search provider";
820 } else { 852 } else {
821 if (delete_default) 853 if (delete_default)
822 default_search_provider_ = NULL; 854 default_search_provider_ = NULL;
823 855
824 Remove(existing_turl); 856 Remove(existing_turl);
825 857
826 if (delete_default) 858 if (delete_default)
827 SetDefaultSearchProvider(FindNewDefaultSearchProvider()); 859 SetDefaultSearchProvider(FindNewDefaultSearchProvider());
828 } 860 }
829 } else if (iter->change_type() == SyncChange::ACTION_ADD && 861 } else if (iter->change_type() == SyncChange::ACTION_ADD &&
830 !existing_turl) { 862 !existing_turl) {
831 std::string guid = turl->sync_guid(); 863 std::string guid = turl->sync_guid();
832 if (existing_keyword_turl) 864 if (existing_keyword_turl) {
833 ResolveSyncKeywordConflict(turl.get(), &new_changes); 865 ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
866 &new_changes);
867 }
834 // Force the local ID to kInvalidTemplateURLID so we can add it. 868 // Force the local ID to kInvalidTemplateURLID so we can add it.
835 TemplateURLData data(turl->data()); 869 TemplateURLData data(turl->data());
836 data.id = kInvalidTemplateURLID; 870 data.id = kInvalidTemplateURLID;
837 Add(new TemplateURL(profile_, data)); 871 Add(new TemplateURL(profile_, data));
838 872
839 // Possibly set the newly added |turl| as the default search provider. 873 // Possibly set the newly added |turl| as the default search provider.
840 SetDefaultSearchProviderIfNewlySynced(guid); 874 SetDefaultSearchProviderIfNewlySynced(guid);
841 } else if (iter->change_type() == SyncChange::ACTION_UPDATE && 875 } else if (iter->change_type() == SyncChange::ACTION_UPDATE &&
842 existing_turl) { 876 existing_turl) {
843 // Possibly resolve a keyword conflict if they have the same keywords but 877 // Possibly resolve a keyword conflict if they have the same keywords but
844 // are not the same entry. 878 // are not the same entry.
845 if (existing_keyword_turl && existing_keyword_turl != existing_turl) 879 if (existing_keyword_turl && existing_keyword_turl != existing_turl) {
846 ResolveSyncKeywordConflict(turl.get(), &new_changes); 880 ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
881 &new_changes);
882 }
847 UpdateNoNotify(existing_turl, *turl); 883 UpdateNoNotify(existing_turl, *turl);
848 NotifyObservers(); 884 NotifyObservers();
849 } else { 885 } else {
850 // Something really unexpected happened. Either we received an 886 // Something really unexpected happened. Either we received an
851 // ACTION_INVALID, or Sync is in a crazy state: 887 // ACTION_INVALID, or Sync is in a crazy state:
852 // . Trying to DELETE or UPDATE a non-existent search engine. 888 // . Trying to DELETE or UPDATE a non-existent search engine.
853 // . Trying to ADD a search engine that already exists. 889 // . Trying to ADD a search engine that already exists.
854 NOTREACHED() << "Unexpected sync change state."; 890 NOTREACHED() << "Unexpected sync change state.";
855 error = sync_error_factory_->CreateAndUploadError( 891 error = sync_error_factory_->CreateAndUploadError(
856 FROM_HERE, 892 FROM_HERE,
857 "ProcessSyncChanges failed on ChangeType " + 893 "ProcessSyncChanges failed on ChangeType " +
858 SyncChange::ChangeTypeToString(iter->change_type())); 894 SyncChange::ChangeTypeToString(iter->change_type()));
859 } 895 }
860 } 896 }
897 PreventDuplicateGUIDUpdates(&new_changes);
861 898
862 // If something went wrong, we want to prematurely exit to avoid pushing 899 // If something went wrong, we want to prematurely exit to avoid pushing
863 // inconsistent data to Sync. We return the last error we received. 900 // inconsistent data to Sync. We return the last error we received.
864 if (error.IsSet()) 901 if (error.IsSet())
865 return error; 902 return error;
866 903
867 error = sync_processor_->ProcessSyncChanges(from_here, new_changes); 904 error = sync_processor_->ProcessSyncChanges(from_here, new_changes);
868 905
869 return error; 906 return error;
870 } 907 }
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 // Merge duplicates and remove the processed local TURL from the map. 979 // Merge duplicates and remove the processed local TURL from the map.
943 std::string old_guid = dupe_turl->sync_guid(); 980 std::string old_guid = dupe_turl->sync_guid();
944 MergeSyncAndLocalURLDuplicates(sync_turl.release(), dupe_turl, 981 MergeSyncAndLocalURLDuplicates(sync_turl.release(), dupe_turl,
945 &new_changes); 982 &new_changes);
946 local_data_map.erase(old_guid); 983 local_data_map.erase(old_guid);
947 } else { 984 } else {
948 std::string guid = sync_turl->sync_guid(); 985 std::string guid = sync_turl->sync_guid();
949 // Keyword conflict is possible in this case. Resolve it first before 986 // Keyword conflict is possible in this case. Resolve it first before
950 // adding the new TemplateURL. Note that we don't remove the local TURL 987 // adding the new TemplateURL. Note that we don't remove the local TURL
951 // from local_data_map in this case as it may still need to be pushed to 988 // from local_data_map in this case as it may still need to be pushed to
952 // the cloud. 989 // the cloud. We also explicitly don't resolve conflicts against
953 ResolveSyncKeywordConflict(sync_turl.get(), &new_changes); 990 // extension keywords; see comments in ProcessSyncChanges().
991 TemplateURL* existing_keyword_turl =
992 FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
993 if (existing_keyword_turl) {
994 ResolveSyncKeywordConflict(sync_turl.get(), existing_keyword_turl,
995 &new_changes);
996 }
954 // Force the local ID to kInvalidTemplateURLID so we can add it. 997 // Force the local ID to kInvalidTemplateURLID so we can add it.
955 TemplateURLData data(sync_turl->data()); 998 TemplateURLData data(sync_turl->data());
956 data.id = kInvalidTemplateURLID; 999 data.id = kInvalidTemplateURLID;
957 Add(new TemplateURL(profile_, data)); 1000 Add(new TemplateURL(profile_, data));
958 1001
959 // Possibly set the newly added |turl| as the default search provider. 1002 // Possibly set the newly added |turl| as the default search provider.
960 SetDefaultSearchProviderIfNewlySynced(guid); 1003 SetDefaultSearchProviderIfNewlySynced(guid);
961 } 1004 }
962 } 1005 }
963 } 1006 }
964 1007
965 // The remaining SyncData in local_data_map should be everything that needs to 1008 // The remaining SyncData in local_data_map should be everything that needs to
966 // be pushed as ADDs to sync. 1009 // be pushed as ADDs to sync.
967 for (SyncDataMap::const_iterator iter = local_data_map.begin(); 1010 for (SyncDataMap::const_iterator iter = local_data_map.begin();
968 iter != local_data_map.end(); ++iter) { 1011 iter != local_data_map.end(); ++iter) {
969 new_changes.push_back(SyncChange(SyncChange::ACTION_ADD, iter->second)); 1012 new_changes.push_back(SyncChange(SyncChange::ACTION_ADD, iter->second));
970 } 1013 }
971 1014
1015 PreventDuplicateGUIDUpdates(&new_changes);
1016
972 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes); 1017 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
973 if (error.IsSet()) 1018 if (error.IsSet())
974 return error; 1019 return error;
975 1020
976 models_associated_ = true; 1021 models_associated_ = true;
977 return SyncError(); 1022 return SyncError();
978 } 1023 }
979 1024
980 void TemplateURLService::StopSyncing(syncable::ModelType type) { 1025 void TemplateURLService::StopSyncing(syncable::ModelType type) {
981 DCHECK_EQ(type, syncable::SEARCH_ENGINES); 1026 DCHECK_EQ(type, syncable::SEARCH_ENGINES);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 se_specifics->set_keyword(UTF16ToUTF8(turl.keyword())); 1069 se_specifics->set_keyword(UTF16ToUTF8(turl.keyword()));
1025 se_specifics->set_favicon_url(turl.favicon_url().spec()); 1070 se_specifics->set_favicon_url(turl.favicon_url().spec());
1026 se_specifics->set_url(turl.url()); 1071 se_specifics->set_url(turl.url());
1027 se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace()); 1072 se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace());
1028 se_specifics->set_originating_url(turl.originating_url().spec()); 1073 se_specifics->set_originating_url(turl.originating_url().spec());
1029 se_specifics->set_date_created(turl.date_created().ToInternalValue()); 1074 se_specifics->set_date_created(turl.date_created().ToInternalValue());
1030 se_specifics->set_input_encodings(JoinString(turl.input_encodings(), ';')); 1075 se_specifics->set_input_encodings(JoinString(turl.input_encodings(), ';'));
1031 se_specifics->set_show_in_default_list(turl.show_in_default_list()); 1076 se_specifics->set_show_in_default_list(turl.show_in_default_list());
1032 se_specifics->set_suggestions_url(turl.suggestions_url()); 1077 se_specifics->set_suggestions_url(turl.suggestions_url());
1033 se_specifics->set_prepopulate_id(turl.prepopulate_id()); 1078 se_specifics->set_prepopulate_id(turl.prepopulate_id());
1034 se_specifics->set_autogenerate_keyword(turl.autogenerate_keyword()); 1079 // REVIEWERS: Should I instead remove this line entirely?
1080 se_specifics->set_autogenerate_keyword(false);
1035 se_specifics->set_instant_url(turl.instant_url()); 1081 se_specifics->set_instant_url(turl.instant_url());
1036 se_specifics->set_last_modified(turl.last_modified().ToInternalValue()); 1082 se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
1037 se_specifics->set_sync_guid(turl.sync_guid()); 1083 se_specifics->set_sync_guid(turl.sync_guid());
1038 return SyncData::CreateLocalData(se_specifics->sync_guid(), 1084 return SyncData::CreateLocalData(se_specifics->sync_guid(),
1039 se_specifics->keyword(), 1085 se_specifics->keyword(),
1040 specifics); 1086 specifics);
1041 } 1087 }
1042 1088
1043 // static 1089 // static
1044 TemplateURL* TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData( 1090 TemplateURL* TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
1045 Profile* profile, 1091 Profile* profile,
1046 TemplateURL* existing_turl, 1092 TemplateURL* existing_turl,
1047 const SyncData& sync_data, 1093 const SyncData& sync_data,
1048 SyncChangeList* change_list) { 1094 SyncChangeList* change_list) {
1049 DCHECK(change_list); 1095 DCHECK(change_list);
1050 1096
1051 sync_pb::SearchEngineSpecifics specifics = 1097 sync_pb::SearchEngineSpecifics specifics =
1052 sync_data.GetSpecifics().search_engine(); 1098 sync_data.GetSpecifics().search_engine();
1053 1099
1054 // Past bugs might have caused either of these fields to be empty. Just 1100 // Past bugs might have caused either of these fields to be empty. Just
1055 // delete this data off the server. 1101 // delete this data off the server.
1056 if (specifics.url().empty() || specifics.sync_guid().empty()) { 1102 if (specifics.url().empty() || specifics.sync_guid().empty()) {
1057 change_list->push_back(SyncChange(SyncChange::ACTION_DELETE, sync_data)); 1103 change_list->push_back(SyncChange(SyncChange::ACTION_DELETE, sync_data));
1058 return NULL; 1104 return NULL;
1059 } 1105 }
1060 1106
1061 TemplateURLData data; 1107 TemplateURLData data;
1062 data.short_name = UTF8ToUTF16(specifics.short_name()); 1108 data.short_name = UTF8ToUTF16(specifics.short_name());
1063 data.originating_url = GURL(specifics.originating_url()); 1109 data.originating_url = GURL(specifics.originating_url());
1064 data.SetKeyword(UTF8ToUTF16(specifics.keyword())); 1110 string16 keyword(UTF8ToUTF16(specifics.keyword()));
1065 data.SetAutogenerateKeyword(specifics.autogenerate_keyword()); 1111 // REVIEWERS: Can we ever get to a state where this migration code can be
1112 // eliminated?
1113 bool reset_keyword =
1114 specifics.autogenerate_keyword() || specifics.keyword().empty();
1115 if (reset_keyword)
1116 keyword = ASCIIToUTF16("dummy"); // Will be replaced below.
1117 DCHECK(!keyword.empty());
1118 data.SetKeyword(keyword);
1066 data.SetURL(specifics.url()); 1119 data.SetURL(specifics.url());
1067 data.suggestions_url = specifics.suggestions_url(); 1120 data.suggestions_url = specifics.suggestions_url();
1068 data.instant_url = specifics.instant_url(); 1121 data.instant_url = specifics.instant_url();
1069 data.favicon_url = GURL(specifics.favicon_url()); 1122 data.favicon_url = GURL(specifics.favicon_url());
1070 data.show_in_default_list = specifics.show_in_default_list(); 1123 data.show_in_default_list = specifics.show_in_default_list();
1071 data.safe_for_autoreplace = specifics.safe_for_autoreplace(); 1124 data.safe_for_autoreplace = specifics.safe_for_autoreplace();
1072 base::SplitString(specifics.input_encodings(), ';', &data.input_encodings); 1125 base::SplitString(specifics.input_encodings(), ';', &data.input_encodings);
1073 data.date_created = base::Time::FromInternalValue(specifics.date_created()); 1126 data.date_created = base::Time::FromInternalValue(specifics.date_created());
1074 data.last_modified = base::Time::FromInternalValue(specifics.last_modified()); 1127 data.last_modified = base::Time::FromInternalValue(specifics.last_modified());
1075 data.prepopulate_id = specifics.prepopulate_id(); 1128 data.prepopulate_id = specifics.prepopulate_id();
1076 data.sync_guid = specifics.sync_guid(); 1129 data.sync_guid = specifics.sync_guid();
1077 if (existing_turl) { 1130 if (existing_turl) {
1078 data.id = existing_turl->id(); 1131 data.id = existing_turl->id();
1079 data.created_by_policy = existing_turl->created_by_policy(); 1132 data.created_by_policy = existing_turl->created_by_policy();
1080 data.usage_count = existing_turl->usage_count(); 1133 data.usage_count = existing_turl->usage_count();
1081 } 1134 }
1082 1135
1083 TemplateURL* turl = new TemplateURL(profile, data); 1136 TemplateURL* turl = new TemplateURL(profile, data);
1084 DCHECK(!turl->IsExtensionKeyword()); 1137 DCHECK(!turl->IsExtensionKeyword());
1138 if (reset_keyword) {
1139 turl->ResetKeywordIfNecessary(true);
1140 SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
1141 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
1142 }
1085 return turl; 1143 return turl;
1086 } 1144 }
1087 1145
1088 // static 1146 // static
1089 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap( 1147 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap(
1090 const SyncDataList& sync_data) { 1148 const SyncDataList& sync_data) {
1091 SyncDataMap data_map; 1149 SyncDataMap data_map;
1092 for (SyncDataList::const_iterator i(sync_data.begin()); i != sync_data.end(); 1150 for (SyncDataList::const_iterator i(sync_data.begin()); i != sync_data.end();
1093 ++i) 1151 ++i)
1094 data_map[i->GetSpecifics().search_engine().sync_guid()] = *i; 1152 data_map[i->GetSpecifics().search_engine().sync_guid()] = *i;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1160 if (initial_default_search_provider_.get() && 1218 if (initial_default_search_provider_.get() &&
1161 initial_default_search_provider_->url_ref().HasGoogleBaseURLs()) { 1219 initial_default_search_provider_->url_ref().HasGoogleBaseURLs()) {
1162 scoped_ptr<base::Environment> env(base::Environment::Create()); 1220 scoped_ptr<base::Environment> env(base::Environment::Create());
1163 if (!env->HasVar(env_vars::kHeadless) && 1221 if (!env->HasVar(env_vars::kHeadless) &&
1164 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) 1222 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame))
1165 GoogleURLTracker::RequestServerCheck(); 1223 GoogleURLTracker::RequestServerCheck();
1166 } 1224 }
1167 } 1225 }
1168 1226
1169 void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) { 1227 void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
1170 if (!template_url->keyword().empty()) 1228 const string16& keyword = template_url->keyword();
1171 keyword_to_template_map_.erase(template_url->keyword()); 1229 DCHECK_NE(0U, keyword_to_template_map_.count(keyword));
1230 if (keyword_to_template_map_[keyword] == template_url) {
1231 // We need to check whether the keyword can now be provided by another
1232 // TemplateURL. See the comments in AddToMaps() for more information on
1233 // extension keywords and how they can coexist with non-extension keywords.
1234 // In the case of more than one extension, we use the most recently
1235 // installed (which will be the most recently added, which will have the
1236 // highest ID).
1237 TemplateURL* best_fallback = NULL;
1238 for (TemplateURLVector::const_iterator i(template_urls_.begin());
1239 i != template_urls_.end(); ++i) {
1240 TemplateURL* turl = *i;
1241 // This next statement relies on the fact that there can only be one
1242 // non-extension TemplateURL with a given keyword.
1243 if ((turl != template_url) && (turl->keyword() == keyword) &&
1244 (!best_fallback || !best_fallback->IsExtensionKeyword() ||
1245 (turl->IsExtensionKeyword() && (turl->id() > best_fallback->id()))))
1246 best_fallback = turl;
1247 }
1248 if (best_fallback)
1249 keyword_to_template_map_[keyword] = best_fallback;
1250 else
1251 keyword_to_template_map_.erase(keyword);
1252 }
1172 1253
1173 // If the keyword we're removing is from an extension, we're now done, since 1254 // If the keyword we're removing is from an extension, we're now done, since
1174 // it won't be synced or stored in the provider map. 1255 // it won't be synced or stored in the provider map.
1175 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1256 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1176 // be synced. 1257 // be synced.
1177 if (template_url->IsExtensionKeyword()) 1258 if (template_url->IsExtensionKeyword())
1178 return; 1259 return;
1179 1260
1180 if (!template_url->sync_guid().empty()) 1261 if (!template_url->sync_guid().empty())
1181 guid_to_template_map_.erase(template_url->sync_guid()); 1262 guid_to_template_map_.erase(template_url->sync_guid());
1182 if (loaded_) 1263 if (loaded_)
1183 provider_map_->Remove(template_url); 1264 provider_map_->Remove(template_url);
1184 } 1265 }
1185 1266
1186 void TemplateURLService::RemoveFromKeywordMapByPointer( 1267 void TemplateURLService::RemoveFromKeywordMapByPointer(
1187 TemplateURL* template_url) { 1268 TemplateURL* template_url) {
1188 DCHECK(template_url); 1269 DCHECK(template_url);
1189 for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin(); 1270 for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
1190 i != keyword_to_template_map_.end(); ++i) { 1271 i != keyword_to_template_map_.end(); ++i) {
1191 if (i->second == template_url) { 1272 if (i->second == template_url) {
1192 keyword_to_template_map_.erase(i); 1273 keyword_to_template_map_.erase(i);
1193 // A given TemplateURL only occurs once in the map. As soon as we find the 1274 // A given TemplateURL only occurs once in the map. As soon as we find the
1194 // entry, stop. 1275 // entry, stop.
1195 break; 1276 break;
1196 } 1277 }
1197 } 1278 }
1198 } 1279 }
1199 1280
1200 void TemplateURLService::AddToMaps(TemplateURL* template_url) { 1281 void TemplateURLService::AddToMaps(TemplateURL* template_url) {
1201 if (!template_url->keyword().empty()) 1282 bool template_extension = template_url->IsExtensionKeyword();
1202 keyword_to_template_map_[template_url->keyword()] = template_url; 1283 const string16& keyword = template_url->keyword();
1284 KeywordToTemplateMap::const_iterator i =
1285 keyword_to_template_map_.find(keyword);
1286 if (i == keyword_to_template_map_.end()) {
1287 keyword_to_template_map_[keyword] = template_url;
1288 } else {
1289 const TemplateURL* existing_url = i->second;
1290 // We should only have overlapping keywords when at least one comes from
1291 // an extension. In that case, the ranking order is:
1292 // Manually-modified keywords > extension keywords > replaceable keywords
1293 // When there are multiple extensions, the last-added wins.
1294 bool existing_extension = existing_url->IsExtensionKeyword();
1295 DCHECK(existing_extension || template_extension);
1296 if (existing_extension ?
1297 !CanReplace(template_url) : CanReplace(existing_url))
1298 keyword_to_template_map_[keyword] = template_url;
1299 }
1203 1300
1204 // Extension keywords are not synced, so they don't go into the GUID map, 1301 // Extension keywords are not synced, so they don't go into the GUID map,
1205 // and do not use host-based search URLs, so they don't go into the provider 1302 // and do not use host-based search URLs, so they don't go into the provider
1206 // map, so at this point we're done. 1303 // map, so at this point we're done.
1207 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1304 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1208 // be persisted to disk and synced. 1305 // be persisted to disk and synced.
1209 if (template_url->IsExtensionKeyword()) 1306 if (template_extension)
1210 return; 1307 return;
1211 1308
1212 if (!template_url->sync_guid().empty()) 1309 if (!template_url->sync_guid().empty())
1213 guid_to_template_map_[template_url->sync_guid()] = template_url; 1310 guid_to_template_map_[template_url->sync_guid()] = template_url;
1214 if (loaded_) { 1311 if (loaded_) {
1215 UIThreadSearchTermsData search_terms_data; 1312 UIThreadSearchTermsData search_terms_data;
1216 provider_map_->Add(template_url, search_terms_data); 1313 provider_map_->Add(template_url, search_terms_data);
1217 } 1314 }
1218 } 1315 }
1219 1316
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1319 if (!prefs->GetBoolean(prefs::kDefaultSearchProviderEnabled)) { 1416 if (!prefs->GetBoolean(prefs::kDefaultSearchProviderEnabled)) {
1320 // The user doesn't want a default search provider. 1417 // The user doesn't want a default search provider.
1321 default_provider->reset(NULL); 1418 default_provider->reset(NULL);
1322 return true; 1419 return true;
1323 } 1420 }
1324 1421
1325 string16 name = 1422 string16 name =
1326 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderName)); 1423 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderName));
1327 string16 keyword = 1424 string16 keyword =
1328 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderKeyword)); 1425 UTF8ToUTF16(prefs->GetString(prefs::kDefaultSearchProviderKeyword));
1426 // Force keyword to be non-empty.
1427 // TODO(pkasting): This is only necessary as long as we're potentially loading
1428 // older prefs where empty keywords are theoretically possible. Eventually
1429 // this code can be replaced with a DCHECK(!keyword.empty());.
1430 bool update_keyword = keyword.empty();
1431 if (update_keyword)
1432 keyword = ASCIIToUTF16("dummy");
1329 std::string search_url = 1433 std::string search_url =
1330 prefs->GetString(prefs::kDefaultSearchProviderSearchURL); 1434 prefs->GetString(prefs::kDefaultSearchProviderSearchURL);
1331 // Force URL to be non-empty. We've never supported this case, but past bugs 1435 // Force URL to be non-empty. We've never supported this case, but past bugs
1332 // might have resulted in it slipping through; eventually this code can be 1436 // might have resulted in it slipping through; eventually this code can be
1333 // replaced with a DCHECK(!search_url.empty());. 1437 // replaced with a DCHECK(!search_url.empty());.
1334 if (search_url.empty()) 1438 if (search_url.empty())
1335 return false; 1439 return false;
1336 std::string suggest_url = 1440 std::string suggest_url =
1337 prefs->GetString(prefs::kDefaultSearchProviderSuggestURL); 1441 prefs->GetString(prefs::kDefaultSearchProviderSuggestURL);
1338 std::string instant_url = 1442 std::string instant_url =
(...skipping 20 matching lines...) Expand all
1359 base::StringToInt64(id_string, &value); 1463 base::StringToInt64(id_string, &value);
1360 data.id = value; 1464 data.id = value;
1361 } 1465 }
1362 if (!prepopulate_id.empty() && !*is_managed) { 1466 if (!prepopulate_id.empty() && !*is_managed) {
1363 int value; 1467 int value;
1364 base::StringToInt(prepopulate_id, &value); 1468 base::StringToInt(prepopulate_id, &value);
1365 data.prepopulate_id = value; 1469 data.prepopulate_id = value;
1366 } 1470 }
1367 default_provider->reset(new TemplateURL(profile_, data)); 1471 default_provider->reset(new TemplateURL(profile_, data));
1368 DCHECK(!(*default_provider)->IsExtensionKeyword()); 1472 DCHECK(!(*default_provider)->IsExtensionKeyword());
1473 if (update_keyword)
1474 (*default_provider)->ResetKeywordIfNecessary(true);
1369 return true; 1475 return true;
1370 } 1476 }
1371 1477
1372 bool TemplateURLService::CanReplaceKeywordForHost( 1478 bool TemplateURLService::CanReplaceKeywordForHost(
1373 const std::string& host, 1479 const std::string& host,
1374 TemplateURL** to_replace) { 1480 TemplateURL** to_replace) {
1375 DCHECK(!to_replace || !*to_replace); 1481 DCHECK(!to_replace || !*to_replace);
1376 const TemplateURLSet* urls = provider_map_->GetURLsForHost(host); 1482 const TemplateURLSet* urls = provider_map_->GetURLsForHost(host);
1377 if (!urls) 1483 if (!urls)
1378 return true; 1484 return true;
1379 for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) { 1485 for (TemplateURLSet::const_iterator i(urls->begin()); i != urls->end(); ++i) {
1380 if (CanReplace(*i)) { 1486 if (CanReplace(*i)) {
1381 if (to_replace) 1487 if (to_replace)
1382 *to_replace = *i; 1488 *to_replace = *i;
1383 return true; 1489 return true;
1384 } 1490 }
1385 } 1491 }
1386 return false; 1492 return false;
1387 } 1493 }
1388 1494
1389 bool TemplateURLService::CanReplace(const TemplateURL* t_url) { 1495 bool TemplateURLService::CanReplace(const TemplateURL* t_url) {
1390 return (t_url != default_search_provider_ && !t_url->show_in_default_list() && 1496 return (t_url != default_search_provider_ && !t_url->show_in_default_list() &&
1391 t_url->safe_for_autoreplace()); 1497 t_url->safe_for_autoreplace());
1392 } 1498 }
1393 1499
1500 TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
1501 const string16& keyword) {
1502 TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
1503 if (!keyword_turl || !keyword_turl->IsExtensionKeyword())
1504 return keyword_turl;
1505 // The extension keyword in the model may be hiding a replaceable
1506 // non-extension keyword. Look for it.
1507 for (TemplateURLVector::const_iterator i(template_urls_.begin());
1508 i != template_urls_.end(); ++i) {
1509 if (!(*i)->IsExtensionKeyword() && ((*i)->keyword() == keyword))
1510 return *i;
1511 }
1512 return NULL;
1513 }
1514
1394 void TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl, 1515 void TemplateURLService::UpdateNoNotify(TemplateURL* existing_turl,
1395 const TemplateURL& new_values) { 1516 const TemplateURL& new_values) {
1396 DCHECK(loaded_); 1517 DCHECK(loaded_);
1397 DCHECK(existing_turl); 1518 DCHECK(existing_turl);
1398 DCHECK(std::find(template_urls_.begin(), template_urls_.end(), 1519 DCHECK(std::find(template_urls_.begin(), template_urls_.end(),
1399 existing_turl) != template_urls_.end()); 1520 existing_turl) != template_urls_.end());
1400 1521
1401 // TODO(mpcomplete): If we allow editing extension keywords, then those should 1522 // TODO(mpcomplete): If we allow editing extension keywords, then those should
1402 // be persisted to disk and synced. In this case this DCHECK should be 1523 // be persisted to disk and synced. In this case this DCHECK should be
1403 // removed. 1524 // removed.
1404 DCHECK(!existing_turl->IsExtensionKeyword()); 1525 DCHECK(!existing_turl->IsExtensionKeyword());
1405 1526
1406 string16 old_keyword(existing_turl->keyword()); 1527 string16 old_keyword(existing_turl->keyword());
1407 if (!old_keyword.empty()) 1528 keyword_to_template_map_.erase(old_keyword);
1408 keyword_to_template_map_.erase(old_keyword);
1409 if (!existing_turl->sync_guid().empty()) 1529 if (!existing_turl->sync_guid().empty())
1410 guid_to_template_map_.erase(existing_turl->sync_guid()); 1530 guid_to_template_map_.erase(existing_turl->sync_guid());
1411 1531
1412 provider_map_->Remove(existing_turl); 1532 provider_map_->Remove(existing_turl);
1413 TemplateURLID previous_id = existing_turl->id(); 1533 TemplateURLID previous_id = existing_turl->id();
1414 *existing_turl = new_values; 1534 *existing_turl = new_values;
1415 existing_turl->data_.id = previous_id; 1535 existing_turl->data_.id = previous_id;
1416 UIThreadSearchTermsData search_terms_data; 1536 UIThreadSearchTermsData search_terms_data;
1417 provider_map_->Add(existing_turl, search_terms_data); 1537 provider_map_->Add(existing_turl, search_terms_data);
1418 1538
1419 const string16& keyword = existing_turl->keyword(); 1539 const string16& keyword = existing_turl->keyword();
1420 if (!keyword.empty()) 1540 KeywordToTemplateMap::const_iterator i =
1541 keyword_to_template_map_.find(keyword);
1542 if (i == keyword_to_template_map_.end()) {
1421 keyword_to_template_map_[keyword] = existing_turl; 1543 keyword_to_template_map_[keyword] = existing_turl;
1544 } else {
1545 // We can theoretically reach here in two cases:
1546 // * There is an existing extension keyword and sync brings in a rename of
1547 // a non-extension keyword to match. In this case we just need to pick
1548 // which keyword has priority to update the keyword map.
1549 // * Autogeneration of the keyword for a Google default search provider
1550 // at load time causes it to conflict with an existing keyword. In this
1551 // case we delete the existing keyword if it's replaceable, or else undo
1552 // the change in keyword for |existing_turl|.
1553 DCHECK(!existing_turl->IsExtensionKeyword());
1554 TemplateURL* existing_keyword_turl = i->second;
1555 if (existing_keyword_turl->IsExtensionKeyword()) {
1556 if (!CanReplace(existing_turl))
1557 keyword_to_template_map_[keyword] = existing_turl;
1558 } else {
1559 if (CanReplace(existing_keyword_turl)) {
1560 RemoveNoNotify(existing_keyword_turl);
1561 } else {
1562 existing_turl->data_.SetKeyword(old_keyword);
1563 keyword_to_template_map_[old_keyword] = existing_turl;
1564 }
1565 }
1566 }
1422 if (!existing_turl->sync_guid().empty()) 1567 if (!existing_turl->sync_guid().empty())
1423 guid_to_template_map_[existing_turl->sync_guid()] = existing_turl; 1568 guid_to_template_map_[existing_turl->sync_guid()] = existing_turl;
1424 1569
1425 if (service_.get()) 1570 if (service_.get())
1426 service_->UpdateKeyword(*existing_turl); 1571 service_->UpdateKeyword(existing_turl->data());
1427 1572
1428 // Inform sync of the update. 1573 // Inform sync of the update.
1429 ProcessTemplateURLChange(existing_turl, SyncChange::ACTION_UPDATE); 1574 ProcessTemplateURLChange(existing_turl, SyncChange::ACTION_UPDATE);
1430 1575
1431 if (default_search_provider_ == existing_turl) 1576 if (default_search_provider_ == existing_turl)
1432 SetDefaultSearchProviderNoNotify(existing_turl); 1577 SetDefaultSearchProviderNoNotify(existing_turl);
1433 } 1578 }
1434 1579
1435 PrefService* TemplateURLService::GetPrefs() { 1580 PrefService* TemplateURLService::GetPrefs() {
1436 return profile_ ? profile_->GetPrefs() : NULL; 1581 return profile_ ? profile_->GetPrefs() : NULL;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 bool something_changed = false; 1702 bool something_changed = false;
1558 for (TemplateURLVector::iterator i(template_urls_.begin()); 1703 for (TemplateURLVector::iterator i(template_urls_.begin());
1559 i != template_urls_.end(); ++i) { 1704 i != template_urls_.end(); ++i) {
1560 TemplateURL* t_url = *i; 1705 TemplateURL* t_url = *i;
1561 if (t_url->url_ref().HasGoogleBaseURLs() || 1706 if (t_url->url_ref().HasGoogleBaseURLs() ||
1562 t_url->suggestions_url_ref().HasGoogleBaseURLs()) { 1707 t_url->suggestions_url_ref().HasGoogleBaseURLs()) {
1563 something_changed = true; 1708 something_changed = true;
1564 string16 original_keyword(t_url->keyword()); 1709 string16 original_keyword(t_url->keyword());
1565 t_url->InvalidateCachedValues(); 1710 t_url->InvalidateCachedValues();
1566 const string16& new_keyword(t_url->keyword()); 1711 const string16& new_keyword(t_url->keyword());
1712 KeywordToTemplateMap::const_iterator i =
1713 keyword_to_template_map_.find(new_keyword);
1714 if ((i != keyword_to_template_map_.end()) && (i->second != t_url)) {
1715 // The new autogenerated keyword conflicts with another TemplateURL.
1716 // Overwrite it if it's replaceable; otherwise just reset |t_url|'s
1717 // keyword. (This will not prevent |t_url| from auto-updating the
1718 // keyword in the future if the conflicting TemplateURL disappears.)
1719 if (!CanReplace(i->second)) {
1720 t_url->data_.SetKeyword(original_keyword);
1721 continue;
1722 }
1723 RemoveNoNotify(i->second);
1724 }
1567 RemoveFromKeywordMapByPointer(t_url); 1725 RemoveFromKeywordMapByPointer(t_url);
1568 if (!new_keyword.empty()) 1726 keyword_to_template_map_[new_keyword] = t_url;
1569 keyword_to_template_map_[new_keyword] = t_url;
1570 } 1727 }
1571 } 1728 }
1572 1729
1573 if (something_changed && loaded_) { 1730 if (something_changed && loaded_) {
1574 UIThreadSearchTermsData search_terms_data; 1731 UIThreadSearchTermsData search_terms_data;
1575 provider_map_->UpdateGoogleBaseURLs(search_terms_data); 1732 provider_map_->UpdateGoogleBaseURLs(search_terms_data);
1576 NotifyObservers(); 1733 NotifyObservers();
1577 } 1734 }
1578 } 1735 }
1579 1736
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1624 TemplateURLData data(new_default_from_prefs->data()); 1781 TemplateURLData data(new_default_from_prefs->data());
1625 data.created_by_policy = true; 1782 data.created_by_policy = true;
1626 TemplateURL new_values(profile_, data); 1783 TemplateURL new_values(profile_, data);
1627 UpdateNoNotify(default_search_provider_, new_values); 1784 UpdateNoNotify(default_search_provider_, new_values);
1628 } else { 1785 } else {
1629 TemplateURL* new_template = NULL; 1786 TemplateURL* new_template = NULL;
1630 if (new_default_from_prefs.get()) { 1787 if (new_default_from_prefs.get()) {
1631 TemplateURLData data(new_default_from_prefs->data()); 1788 TemplateURLData data(new_default_from_prefs->data());
1632 data.created_by_policy = true; 1789 data.created_by_policy = true;
1633 new_template = new TemplateURL(profile_, data); 1790 new_template = new TemplateURL(profile_, data);
1634 AddNoNotify(new_template, true); 1791 if (!AddNoNotify(new_template, true))
1792 return;
1635 } 1793 }
1636 SetDefaultSearchProviderNoNotify(new_template); 1794 SetDefaultSearchProviderNoNotify(new_template);
1637 } 1795 }
1638 } else if (!is_default_search_managed_ && new_is_default_managed) { 1796 } else if (!is_default_search_managed_ && new_is_default_managed) {
1639 // The default used to be unmanaged and is now managed. Add the new 1797 // The default used to be unmanaged and is now managed. Add the new
1640 // managed default to the list of URLs and set it as default. 1798 // managed default to the list of URLs and set it as default.
1641 is_default_search_managed_ = new_is_default_managed; 1799 is_default_search_managed_ = new_is_default_managed;
1642 TemplateURL* new_template = NULL; 1800 TemplateURL* new_template = NULL;
1643 if (new_default_from_prefs.get()) { 1801 if (new_default_from_prefs.get()) {
1644 TemplateURLData data(new_default_from_prefs->data()); 1802 TemplateURLData data(new_default_from_prefs->data());
1645 data.created_by_policy = true; 1803 data.created_by_policy = true;
1646 new_template = new TemplateURL(profile_, data); 1804 new_template = new TemplateURL(profile_, data);
1647 AddNoNotify(new_template, true); 1805 if (!AddNoNotify(new_template, true))
1806 return;
1648 } 1807 }
1649 SetDefaultSearchProviderNoNotify(new_template); 1808 SetDefaultSearchProviderNoNotify(new_template);
1650 } else { 1809 } else {
1651 // The default was managed and is no longer. 1810 // The default was managed and is no longer.
1652 DCHECK(is_default_search_managed_ && !new_is_default_managed); 1811 DCHECK(is_default_search_managed_ && !new_is_default_managed);
1653 is_default_search_managed_ = new_is_default_managed; 1812 is_default_search_managed_ = new_is_default_managed;
1654 // If we had a default, delete the previous default if created by policy 1813 // If we had a default, delete the previous default if created by policy
1655 // and set a likely default. 1814 // and set a likely default.
1656 if ((default_search_provider_ != NULL) && 1815 if ((default_search_provider_ != NULL) &&
1657 default_search_provider_->created_by_policy()) { 1816 default_search_provider_->created_by_policy()) {
(...skipping 21 matching lines...) Expand all
1679 DCHECK(!url->IsExtensionKeyword()); 1838 DCHECK(!url->IsExtensionKeyword());
1680 } 1839 }
1681 1840
1682 default_search_provider_ = url; 1841 default_search_provider_ = url;
1683 1842
1684 if (url) { 1843 if (url) {
1685 // Don't mark the url as edited, otherwise we won't be able to rev the 1844 // Don't mark the url as edited, otherwise we won't be able to rev the
1686 // template urls we ship with. 1845 // template urls we ship with.
1687 url->data_.show_in_default_list = true; 1846 url->data_.show_in_default_list = true;
1688 if (service_.get()) 1847 if (service_.get())
1689 service_->UpdateKeyword(*url); 1848 service_->UpdateKeyword(url->data());
1690 1849
1691 if (url->url_ref().HasGoogleBaseURLs()) { 1850 if (url->url_ref().HasGoogleBaseURLs()) {
1692 GoogleURLTracker::RequestServerCheck(); 1851 GoogleURLTracker::RequestServerCheck();
1693 #if defined(ENABLE_RLZ) 1852 #if defined(ENABLE_RLZ)
1694 // Needs to be evaluated. See http://crbug.com/62328. 1853 // Needs to be evaluated. See http://crbug.com/62328.
1695 base::ThreadRestrictions::ScopedAllowIO allow_io; 1854 base::ThreadRestrictions::ScopedAllowIO allow_io;
1696 RLZTracker::RecordProductEvent(rlz_lib::CHROME, 1855 RLZTracker::RecordProductEvent(rlz_lib::CHROME,
1697 rlz_lib::CHROME_OMNIBOX, 1856 rlz_lib::CHROME_OMNIBOX,
1698 rlz_lib::SET_TO_GOOGLE); 1857 rlz_lib::SET_TO_GOOGLE);
1699 #endif 1858 #endif
(...skipping 13 matching lines...) Expand all
1713 } 1872 }
1714 1873
1715 if (service_.get()) 1874 if (service_.get())
1716 service_->SetDefaultSearchProvider(url); 1875 service_->SetDefaultSearchProvider(url);
1717 1876
1718 // Inform sync the change to the show_in_default_list flag. 1877 // Inform sync the change to the show_in_default_list flag.
1719 if (url) 1878 if (url)
1720 ProcessTemplateURLChange(url, SyncChange::ACTION_UPDATE); 1879 ProcessTemplateURLChange(url, SyncChange::ACTION_UPDATE);
1721 } 1880 }
1722 1881
1723 void TemplateURLService::AddNoNotify(TemplateURL* template_url, 1882 bool TemplateURLService::AddNoNotify(TemplateURL* template_url,
1724 bool newly_adding) { 1883 bool newly_adding) {
1725 DCHECK(template_url); 1884 DCHECK(template_url);
1726 1885
1727 if (newly_adding) { 1886 if (newly_adding) {
1728 DCHECK_EQ(kInvalidTemplateURLID, template_url->id()); 1887 DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
1729 DCHECK(std::find(template_urls_.begin(), template_urls_.end(), 1888 DCHECK(std::find(template_urls_.begin(), template_urls_.end(),
1730 template_url) == template_urls_.end()); 1889 template_url) == template_urls_.end());
1731 template_url->data_.id = ++next_id_; 1890 template_url->data_.id = ++next_id_;
1732 } 1891 }
1733 1892
1893 template_url->ResetKeywordIfNecessary(false);
1894 if (!template_url->IsExtensionKeyword()) {
1895 // Check whether |template_url|'s keyword conflicts with any already in the
1896 // model.
1897 TemplateURL* existing_keyword_turl =
1898 FindNonExtensionTemplateURLForKeyword(template_url->keyword());
1899 if (existing_keyword_turl != NULL) {
1900 DCHECK_NE(existing_keyword_turl, template_url);
1901 if (CanReplace(existing_keyword_turl)) {
1902 RemoveNoNotify(existing_keyword_turl);
1903 } else if (CanReplace(template_url)) {
1904 delete template_url;
1905 return false;
1906 } else {
1907 string16 new_keyword = UniquifyKeyword(*existing_keyword_turl);
1908 ResetTemplateURL(existing_keyword_turl,
1909 existing_keyword_turl->short_name(), new_keyword,
1910 existing_keyword_turl->url());
1911 }
1912 }
1913 }
1734 template_urls_.push_back(template_url); 1914 template_urls_.push_back(template_url);
1735 AddToMaps(template_url); 1915 AddToMaps(template_url);
1736 1916
1737 if (newly_adding) { 1917 if (newly_adding) {
1738 // Don't persist extension keywords to disk. They'll get re-added on each 1918 // Don't persist extension keywords to disk. They'll get re-added on each
1739 // launch as the extensions are loaded. 1919 // launch as the extensions are loaded.
1740 // TODO(mpcomplete): If we allow editing extension keywords, then those 1920 // TODO(mpcomplete): If we allow editing extension keywords, then those
1741 // should be persisted to disk and synced. 1921 // should be persisted to disk and synced.
1742 if (service_.get() && !template_url->IsExtensionKeyword()) 1922 if (service_.get() && !template_url->IsExtensionKeyword())
1743 service_->AddKeyword(*template_url); 1923 service_->AddKeyword(template_url->data());
1744 1924
1745 // Inform sync of the addition. Note that this will assign a GUID to 1925 // Inform sync of the addition. Note that this will assign a GUID to
1746 // template_url and add it to the guid_to_template_map_. 1926 // template_url and add it to the guid_to_template_map_.
1747 ProcessTemplateURLChange(template_url, SyncChange::ACTION_ADD); 1927 ProcessTemplateURLChange(template_url, SyncChange::ACTION_ADD);
1748 } 1928 }
1929
1930 return true;
1749 } 1931 }
1750 1932
1751 void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) { 1933 void TemplateURLService::RemoveNoNotify(TemplateURL* template_url) {
1752 TemplateURLVector::iterator i = 1934 TemplateURLVector::iterator i =
1753 std::find(template_urls_.begin(), template_urls_.end(), template_url); 1935 std::find(template_urls_.begin(), template_urls_.end(), template_url);
1754 if (i == template_urls_.end()) 1936 if (i == template_urls_.end())
1755 return; 1937 return;
1756 1938
1757 if (template_url == default_search_provider_) { 1939 if (template_url == default_search_provider_) {
1758 // Should never delete the default search provider. 1940 // Should never delete the default search provider.
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1856 } 2038 }
1857 2039
1858 string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl) { 2040 string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl) {
1859 // Already unique. 2041 // Already unique.
1860 if (!GetTemplateURLForKeyword(turl.keyword())) 2042 if (!GetTemplateURLForKeyword(turl.keyword()))
1861 return turl.keyword(); 2043 return turl.keyword();
1862 2044
1863 // First, try to return the generated keyword for the TemplateURL. 2045 // First, try to return the generated keyword for the TemplateURL.
1864 GURL gurl(turl.url()); 2046 GURL gurl(turl.url());
1865 if (gurl.is_valid()) { 2047 if (gurl.is_valid()) {
1866 string16 keyword_candidate = GenerateKeyword(gurl, true); 2048 string16 keyword_candidate = GenerateKeyword(gurl);
1867 if (!GetTemplateURLForKeyword(keyword_candidate) && 2049 if (!GetTemplateURLForKeyword(keyword_candidate))
1868 !keyword_candidate.empty())
1869 return keyword_candidate; 2050 return keyword_candidate;
1870 } 2051 }
1871 2052
1872 // We try to uniquify the keyword by appending a special character to the end. 2053 // We try to uniquify the keyword by appending a special character to the end.
1873 // This is a best-effort approach where we try to preserve the original 2054 // This is a best-effort approach where we try to preserve the original
1874 // keyword and let the user do what they will after our attempt. 2055 // keyword and let the user do what they will after our attempt.
1875 string16 keyword_candidate(turl.keyword()); 2056 string16 keyword_candidate(turl.keyword());
1876 do { 2057 do {
1877 keyword_candidate.append(ASCIIToUTF16("_")); 2058 keyword_candidate.append(ASCIIToUTF16("_"));
1878 } while (GetTemplateURLForKeyword(keyword_candidate)); 2059 } while (GetTemplateURLForKeyword(keyword_candidate));
1879 2060
1880 return keyword_candidate; 2061 return keyword_candidate;
1881 } 2062 }
1882 2063
1883 bool TemplateURLService::ResolveSyncKeywordConflict( 2064 void TemplateURLService::ResolveSyncKeywordConflict(
1884 TemplateURL* sync_turl, 2065 TemplateURL* sync_turl,
2066 TemplateURL* local_turl,
1885 SyncChangeList* change_list) { 2067 SyncChangeList* change_list) {
1886 DCHECK(sync_turl); 2068 DCHECK(sync_turl);
2069 DCHECK(local_turl);
2070 DCHECK(sync_turl->sync_guid() != local_turl->sync_guid());
2071 DCHECK(!local_turl->IsExtensionKeyword());
1887 DCHECK(change_list); 2072 DCHECK(change_list);
1888 2073
1889 TemplateURL* existing_turl = 2074 if (local_turl->last_modified() > sync_turl->last_modified() ||
1890 GetTemplateURLForKeyword(sync_turl->keyword()); 2075 local_turl->created_by_policy()) {
1891 // If there is no conflict, or it's just conflicting with itself, return.
1892 if (!existing_turl || existing_turl->sync_guid() == sync_turl->sync_guid())
1893 return false;
1894
1895 if (existing_turl->last_modified() > sync_turl->last_modified() ||
1896 existing_turl->created_by_policy()) {
1897 string16 new_keyword = UniquifyKeyword(*sync_turl); 2076 string16 new_keyword = UniquifyKeyword(*sync_turl);
1898 DCHECK(!GetTemplateURLForKeyword(new_keyword)); 2077 DCHECK(!GetTemplateURLForKeyword(new_keyword));
1899 sync_turl->data_.SetKeyword(new_keyword); 2078 sync_turl->data_.SetKeyword(new_keyword);
1900 // If we update the cloud TURL, we need to push an update back to sync 2079 // If we update the cloud TURL, we need to push an update back to sync
1901 // informing it that something has changed. 2080 // informing it that something has changed.
1902 SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl); 2081 SyncData sync_data = CreateSyncDataFromTemplateURL(*sync_turl);
1903 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data)); 2082 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
1904 } else { 2083 } else {
1905 string16 new_keyword = UniquifyKeyword(*existing_turl); 2084 string16 new_keyword = UniquifyKeyword(*local_turl);
1906 TemplateURLData data(existing_turl->data()); 2085 TemplateURLData data(local_turl->data());
1907 data.SetKeyword(new_keyword); 2086 data.SetKeyword(new_keyword);
1908 TemplateURL new_turl(existing_turl->profile(), data); 2087 TemplateURL new_turl(local_turl->profile(), data);
1909 UpdateNoNotify(existing_turl, new_turl); 2088 UpdateNoNotify(local_turl, new_turl);
1910 NotifyObservers(); 2089 NotifyObservers();
2090 if (!models_associated_) {
2091 // We're doing our initial sync, so UpdateNoNotify() won't have generated
2092 // an ACTION_UPDATE. If this local URL is one that was just newly brought
2093 // down from the sync server, we need to go ahead and generate an update
2094 // for it. If it was pre-existing, then this is unnecessary (and in fact
2095 // wrong) because MergeDataAndStartSyncing() will later add an ACTION_ADD
2096 // for this URL; but in this case, PreventDuplicateGUIDUpdates() will
2097 // prune out the ACTION_UPDATE we create here.
2098 SyncData sync_data = CreateSyncDataFromTemplateURL(*local_turl);
2099 change_list->push_back(SyncChange(SyncChange::ACTION_UPDATE, sync_data));
2100 }
1911 } 2101 }
1912 return true;
1913 } 2102 }
1914 2103
1915 TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL( 2104 TemplateURL* TemplateURLService::FindDuplicateOfSyncTemplateURL(
1916 const TemplateURL& sync_turl) { 2105 const TemplateURL& sync_turl) {
1917 TemplateURL* existing_turl = GetTemplateURLForKeyword(sync_turl.keyword()); 2106 TemplateURL* existing_turl = GetTemplateURLForKeyword(sync_turl.keyword());
1918 return existing_turl && (existing_turl->url() == sync_turl.url()) ? 2107 return existing_turl && (existing_turl->url() == sync_turl.url()) ?
1919 existing_turl : NULL; 2108 existing_turl : NULL;
1920 } 2109 }
1921 2110
1922 void TemplateURLService::MergeSyncAndLocalURLDuplicates( 2111 void TemplateURLService::MergeSyncAndLocalURLDuplicates(
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 i != template_urls->end(); ++i) { 2179 i != template_urls->end(); ++i) {
1991 TemplateURL* template_url = *i; 2180 TemplateURL* template_url = *i;
1992 DCHECK(template_url); 2181 DCHECK(template_url);
1993 // Extension keywords are never synced. 2182 // Extension keywords are never synced.
1994 // TODO(mpcomplete): If we allow editing extension keywords, then those 2183 // TODO(mpcomplete): If we allow editing extension keywords, then those
1995 // should be persisted to disk and synced. 2184 // should be persisted to disk and synced.
1996 if (template_url->sync_guid().empty() && 2185 if (template_url->sync_guid().empty() &&
1997 !template_url->IsExtensionKeyword()) { 2186 !template_url->IsExtensionKeyword()) {
1998 template_url->data_.sync_guid = guid::GenerateGUID(); 2187 template_url->data_.sync_guid = guid::GenerateGUID();
1999 if (service_.get()) 2188 if (service_.get())
2000 service_->UpdateKeyword(*template_url); 2189 service_->UpdateKeyword(template_url->data());
2001 } 2190 }
2002 } 2191 }
2003 } 2192 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698