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/ui/webui/options/content_settings_handler.h"
6
7#include "base/callback.h"
8#include "base/command_line.h"
9#include "base/utf_string_conversions.h"
10#include "base/values.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/content_settings/content_settings_details.h"
13#include "chrome/browser/content_settings/host_content_settings_map.h"
14#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
15#include "chrome/browser/notifications/desktop_notification_service.h"
16#include "chrome/browser/notifications/desktop_notification_service_factory.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/browser_list.h"
19#include "chrome/common/chrome_switches.h"
20#include "chrome/common/content_settings_helper.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/url_constants.h"
23#include "content/common/notification_service.h"
24#include "content/common/notification_source.h"
25#include "content/common/notification_type.h"
26#include "grit/generated_resources.h"
27#include "grit/locale_settings.h"
28#include "ui/base/l10n/l10n_util.h"
29
30namespace {
31
32const char* kDisplayPattern = "displayPattern";
33const char* kSetting = "setting";
34const char* kOrigin = "origin";
35const char* kEmbeddingOrigin = "embeddingOrigin";
36
37const char* const kContentSettingsTypeGroupNames[] = {
38  "cookies",
39  "images",
40  "javascript",
41  "plugins",
42  "popups",
43  "location",
44  "notifications",
45  "prerender",
46};
47COMPILE_ASSERT(arraysize(kContentSettingsTypeGroupNames) ==
48               CONTENT_SETTINGS_NUM_TYPES,
49               invalid_content_settings_type_group_names_size);
50
51
52ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
53
54  for (int content_settings_type = CONTENT_SETTINGS_TYPE_COOKIES;
55       content_settings_type < CONTENT_SETTINGS_NUM_TYPES;
56       ++content_settings_type) {
57    if (name == kContentSettingsTypeGroupNames[content_settings_type])
58      return static_cast<ContentSettingsType>(content_settings_type);
59  }
60
61  NOTREACHED() << name << " is not a recognized content settings type.";
62  return CONTENT_SETTINGS_TYPE_DEFAULT;
63}
64
65std::string ContentSettingToString(ContentSetting setting) {
66  switch (setting) {
67    case CONTENT_SETTING_ALLOW:
68      return "allow";
69    case CONTENT_SETTING_ASK:
70      return "ask";
71    case CONTENT_SETTING_BLOCK:
72      return "block";
73    case CONTENT_SETTING_SESSION_ONLY:
74      return "session";
75    case CONTENT_SETTING_DEFAULT:
76      return "default";
77    case CONTENT_SETTING_NUM_SETTINGS:
78      NOTREACHED();
79  }
80
81  return "";
82}
83
84ContentSetting ContentSettingFromString(const std::string& name) {
85  if (name == "allow")
86    return CONTENT_SETTING_ALLOW;
87  if (name == "ask")
88    return CONTENT_SETTING_ASK;
89  if (name == "block")
90    return CONTENT_SETTING_BLOCK;
91  if (name == "session")
92    return CONTENT_SETTING_SESSION_ONLY;
93
94  NOTREACHED() << name << " is not a recognized content setting.";
95  return CONTENT_SETTING_DEFAULT;
96}
97
98std::string GeolocationExceptionToString(const GURL& origin,
99                                         const GURL& embedding_origin) {
100  if (origin == embedding_origin)
101    return content_settings_helper::OriginToString(origin);
102
103  // TODO(estade): the page needs to use CSS to indent the string.
104  std::string indent(" ");
105  if (embedding_origin.is_empty()) {
106    // NOTE: As long as the user cannot add/edit entries from the exceptions
107    // dialog, it's impossible to actually have a non-default setting for some
108    // origin "embedded on any other site", so this row will never appear.  If
109    // we add the ability to add/edit exceptions, we'll need to decide when to
110    // display this and how "removing" it will function.
111    return indent +
112        l10n_util::GetStringUTF8(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ANY_OTHER);
113  }
114
115  return indent + l10n_util::GetStringFUTF8(
116      IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST,
117      UTF8ToUTF16(content_settings_helper::OriginToString(embedding_origin)));
118}
119
120// Create a DictionaryValue* that will act as a data source for a single row
121// in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
122// Ownership of the pointer is passed to the caller.
123DictionaryValue* GetExceptionForPage(
124    const ContentSettingsPattern& pattern,
125    ContentSetting setting) {
126  DictionaryValue* exception = new DictionaryValue();
127  exception->Set(
128      kDisplayPattern,
129      new StringValue(pattern.AsString()));
130  exception->Set(
131      kSetting,
132      new StringValue(ContentSettingToString(setting)));
133  return exception;
134}
135
136// Create a DictionaryValue* that will act as a data source for a single row
137// in the Geolocation exceptions table. Ownership of the pointer is passed to
138// the caller.
139DictionaryValue* GetGeolocationExceptionForPage(const GURL& origin,
140                                                const GURL& embedding_origin,
141                                                ContentSetting setting) {
142  DictionaryValue* exception = new DictionaryValue();
143  exception->Set(
144      kDisplayPattern,
145      new StringValue(GeolocationExceptionToString(origin, embedding_origin)));
146  exception->Set(
147      kSetting,
148      new StringValue(ContentSettingToString(setting)));
149  exception->Set(
150      kOrigin,
151      new StringValue(origin.spec()));
152  exception->Set(
153      kEmbeddingOrigin,
154      new StringValue(embedding_origin.spec()));
155  return exception;
156}
157
158// Create a DictionaryValue* that will act as a data source for a single row
159// in the desktop notifications exceptions table. Ownership of the pointer is
160// passed to the caller.
161DictionaryValue* GetNotificationExceptionForPage(
162    const GURL& url,
163    ContentSetting setting) {
164  DictionaryValue* exception = new DictionaryValue();
165  exception->Set(
166      kDisplayPattern,
167      new StringValue(content_settings_helper::OriginToString(url)));
168  exception->Set(
169      kSetting,
170      new StringValue(ContentSettingToString(setting)));
171  exception->Set(
172      kOrigin,
173      new StringValue(url.spec()));
174  return exception;
175}
176
177}  // namespace
178
179ContentSettingsHandler::ContentSettingsHandler() {
180}
181
182ContentSettingsHandler::~ContentSettingsHandler() {
183}
184
185void ContentSettingsHandler::GetLocalizedValues(
186    DictionaryValue* localized_strings) {
187  DCHECK(localized_strings);
188
189  static OptionsStringResource resources[] = {
190    { "content_exceptions", IDS_COOKIES_EXCEPTIONS_BUTTON },
191    { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
192    { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
193    { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
194    { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
195    { "addExceptionRow", IDS_EXCEPTIONS_ADD_BUTTON },
196    { "removeExceptionRow", IDS_EXCEPTIONS_REMOVE_BUTTON },
197    { "editExceptionRow", IDS_EXCEPTIONS_EDIT_BUTTON },
198    { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
199    { "examplePattern", IDS_EXCEPTIONS_PATTERN_EXAMPLE },
200    { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
201    { "manage_exceptions", IDS_EXCEPTIONS_MANAGE },
202    { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
203    { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
204    // Cookies filter.
205    { "cookies_tab_label", IDS_COOKIES_TAB_LABEL },
206    { "cookies_header", IDS_COOKIES_HEADER },
207    { "cookies_allow", IDS_COOKIES_ALLOW_RADIO },
208    { "cookies_ask", IDS_COOKIES_ASK_EVERY_TIME_RADIO },
209    { "cookies_block", IDS_COOKIES_BLOCK_RADIO },
210    { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
211    { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
212    { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
213    { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
214    { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
215    { "flash_storage_url", IDS_FLASH_STORAGE_URL },
216    // Image filter.
217    { "images_tab_label", IDS_IMAGES_TAB_LABEL },
218    { "images_header", IDS_IMAGES_HEADER },
219    { "images_allow", IDS_IMAGES_LOAD_RADIO },
220    { "images_block", IDS_IMAGES_NOLOAD_RADIO },
221    // JavaScript filter.
222    { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL },
223    { "javascript_header", IDS_JAVASCRIPT_HEADER },
224    { "javascript_allow", IDS_JS_ALLOW_RADIO },
225    { "javascript_block", IDS_JS_DONOTALLOW_RADIO },
226    // Plug-ins filter.
227    { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL },
228    { "plugins_header", IDS_PLUGIN_HEADER },
229    { "plugins_ask", IDS_PLUGIN_ASK_RADIO },
230    { "plugins_allow", IDS_PLUGIN_LOAD_RADIO },
231    { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO },
232    { "disable_individual_plugins", IDS_PLUGIN_SELECTIVE_DISABLE },
233    // Pop-ups filter.
234    { "popups_tab_label", IDS_POPUP_TAB_LABEL },
235    { "popups_header", IDS_POPUP_HEADER },
236    { "popups_allow", IDS_POPUP_ALLOW_RADIO },
237    { "popups_block", IDS_POPUP_BLOCK_RADIO },
238    // Location filter.
239    { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL },
240    { "location_header", IDS_GEOLOCATION_HEADER },
241    { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO },
242    { "location_ask", IDS_GEOLOCATION_ASK_RADIO },
243    { "location_block", IDS_GEOLOCATION_BLOCK_RADIO },
244    // Notifications filter.
245    { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL },
246    { "notifications_header", IDS_NOTIFICATIONS_HEADER },
247    { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO },
248    { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO },
249    { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO },
250  };
251
252  RegisterStrings(localized_strings, resources, arraysize(resources));
253  RegisterTitle(localized_strings, "contentSettingsPage",
254                IDS_CONTENT_SETTINGS_TITLE);
255  localized_strings->SetBoolean("enable_click_to_play",
256      CommandLine::ForCurrentProcess()->HasSwitch(
257          switches::kEnableClickToPlay));
258}
259
260void ContentSettingsHandler::Initialize() {
261  const HostContentSettingsMap* settings_map = GetContentSettingsMap();
262  scoped_ptr<Value> block_3rd_party(Value::CreateBooleanValue(
263      settings_map->BlockThirdPartyCookies()));
264  web_ui_->CallJavascriptFunction("ContentSettings.setBlockThirdPartyCookies",
265                                  *block_3rd_party.get());
266
267  notification_registrar_.Add(
268      this, NotificationType::OTR_PROFILE_CREATED,
269      NotificationService::AllSources());
270  notification_registrar_.Add(
271      this, NotificationType::PROFILE_DESTROYED,
272      NotificationService::AllSources());
273
274  UpdateAllExceptionsViewsFromModel();
275  notification_registrar_.Add(
276      this, NotificationType::CONTENT_SETTINGS_CHANGED,
277      NotificationService::AllSources());
278  notification_registrar_.Add(
279      this, NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED,
280      NotificationService::AllSources());
281  notification_registrar_.Add(
282      this, NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
283      NotificationService::AllSources());
284
285  PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
286  pref_change_registrar_.Init(prefs);
287  pref_change_registrar_.Add(prefs::kGeolocationDefaultContentSetting, this);
288  pref_change_registrar_.Add(prefs::kGeolocationContentSettings, this);
289}
290
291void ContentSettingsHandler::Observe(NotificationType type,
292                                     const NotificationSource& source,
293                                     const NotificationDetails& details) {
294  switch (type.value) {
295    case NotificationType::PROFILE_DESTROYED: {
296      Profile* profile = static_cast<Source<Profile> >(source).ptr();
297      if (profile->IsOffTheRecord()) {
298        web_ui_->CallJavascriptFunction(
299            "ContentSettingsExceptionsArea.OTRProfileDestroyed");
300      }
301      break;
302    }
303
304    case NotificationType::OTR_PROFILE_CREATED: {
305      UpdateAllOTRExceptionsViewsFromModel();
306      break;
307    }
308
309    case NotificationType::CONTENT_SETTINGS_CHANGED: {
310      const ContentSettingsDetails* settings_details =
311          Details<const ContentSettingsDetails>(details).ptr();
312
313      // TODO(estade): we pretend update_all() is always true.
314      if (settings_details->update_all_types())
315        UpdateAllExceptionsViewsFromModel();
316      else
317        UpdateExceptionsViewFromModel(settings_details->type());
318      break;
319    }
320
321    case NotificationType::PREF_CHANGED: {
322      const std::string& pref_name = *Details<std::string>(details).ptr();
323      if (pref_name == prefs::kGeolocationDefaultContentSetting)
324        UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
325      else if (pref_name == prefs::kGeolocationContentSettings)
326        UpdateGeolocationExceptionsView();
327      break;
328    }
329
330    case NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED: {
331      UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
332      break;
333    }
334
335    case NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
336      UpdateNotificationExceptionsView();
337      break;
338    }
339
340    default:
341      OptionsPageUIHandler::Observe(type, source, details);
342  }
343}
344
345void ContentSettingsHandler::UpdateSettingDefaultFromModel(
346    ContentSettingsType type) {
347  DictionaryValue filter_settings;
348  filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
349      GetSettingDefaultFromModel(type));
350  filter_settings.SetBoolean(ContentSettingsTypeToGroupName(type) + ".managed",
351      GetDefaultSettingManagedFromModel(type));
352
353  web_ui_->CallJavascriptFunction(
354      "ContentSettings.setContentFilterSettingsValue", filter_settings);
355}
356
357std::string ContentSettingsHandler::GetSettingDefaultFromModel(
358    ContentSettingsType type) {
359  ContentSetting default_setting;
360  if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
361    default_setting = web_ui_->GetProfile()->
362        GetGeolocationContentSettingsMap()->GetDefaultContentSetting();
363  } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
364    default_setting = DesktopNotificationServiceFactory::GetForProfile(
365        web_ui_->GetProfile())->GetDefaultContentSetting();
366  } else {
367    default_setting = GetContentSettingsMap()->GetDefaultContentSetting(type);
368  }
369
370  return ContentSettingToString(default_setting);
371}
372
373bool ContentSettingsHandler::GetDefaultSettingManagedFromModel(
374    ContentSettingsType type) {
375  if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
376    return web_ui_->GetProfile()->
377        GetGeolocationContentSettingsMap()->IsDefaultContentSettingManaged();
378  } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
379    return DesktopNotificationServiceFactory::GetForProfile(
380        web_ui_->GetProfile())->IsDefaultContentSettingManaged();
381  } else {
382    return GetContentSettingsMap()->IsDefaultContentSettingManaged(type);
383  }
384}
385
386void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
387  for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
388       type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
389    UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
390  }
391}
392
393void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
394  for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
395       type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
396    UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
397  }
398}
399
400void ContentSettingsHandler::UpdateExceptionsViewFromModel(
401    ContentSettingsType type) {
402  switch (type) {
403    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
404      UpdateGeolocationExceptionsView();
405      break;
406    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
407      UpdateNotificationExceptionsView();
408      break;
409    case CONTENT_SETTINGS_TYPE_PRERENDER:
410      // Prerender is currently (02/24/2011) an experimental feature which is
411      // only turned on via about:flags. There is intentionally no UI in
412      // chrome://preferences for CONTENT_SETTINGS_TYPE_PRERENDER.
413      // TODO(cbentzel): Change once prerender moves out of about:flags.
414      break;
415    default:
416      UpdateExceptionsViewFromHostContentSettingsMap(type);
417      break;
418  }
419}
420
421void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
422    ContentSettingsType type) {
423  switch (type) {
424    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
425    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
426    case CONTENT_SETTINGS_TYPE_PRERENDER:
427      break;
428    default:
429      UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
430      break;
431  }
432}
433
434void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
435  GeolocationContentSettingsMap* map =
436      web_ui_->GetProfile()->GetGeolocationContentSettingsMap();
437  GeolocationContentSettingsMap::AllOriginsSettings all_settings =
438      map->GetAllOriginsSettings();
439  GeolocationContentSettingsMap::AllOriginsSettings::const_iterator i;
440
441  ListValue exceptions;
442  for (i = all_settings.begin(); i != all_settings.end(); ++i) {
443    const GURL& origin = i->first;
444    const GeolocationContentSettingsMap::OneOriginSettings& one_settings =
445        i->second;
446
447    GeolocationContentSettingsMap::OneOriginSettings::const_iterator parent =
448        one_settings.find(origin);
449
450    // Add the "parent" entry for the non-embedded setting.
451    ContentSetting parent_setting =
452        parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
453    exceptions.Append(
454        GetGeolocationExceptionForPage(origin, origin, parent_setting));
455
456    // Add the "children" for any embedded settings.
457    GeolocationContentSettingsMap::OneOriginSettings::const_iterator j;
458    for (j = one_settings.begin(); j != one_settings.end(); ++j) {
459      // Skip the non-embedded setting which we already added above.
460      if (j == parent)
461        continue;
462
463      exceptions.Append(
464          GetGeolocationExceptionForPage(origin, j->first, j->second));
465    }
466  }
467
468  StringValue type_string(
469      ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
470  web_ui_->CallJavascriptFunction("ContentSettings.setExceptions",
471                                  type_string, exceptions);
472
473  // This is mainly here to keep this function ideologically parallel to
474  // UpdateExceptionsViewFromHostContentSettingsMap().
475  UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
476}
477
478void ContentSettingsHandler::UpdateNotificationExceptionsView() {
479  DesktopNotificationService* service =
480      DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile());
481
482  std::vector<GURL> allowed(service->GetAllowedOrigins());
483  std::vector<GURL> blocked(service->GetBlockedOrigins());
484
485  ListValue exceptions;
486  for (size_t i = 0; i < allowed.size(); ++i) {
487    exceptions.Append(
488        GetNotificationExceptionForPage(allowed[i], CONTENT_SETTING_ALLOW));
489  }
490  for (size_t i = 0; i < blocked.size(); ++i) {
491    exceptions.Append(
492        GetNotificationExceptionForPage(blocked[i], CONTENT_SETTING_BLOCK));
493  }
494
495  StringValue type_string(
496      ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
497  web_ui_->CallJavascriptFunction("ContentSettings.setExceptions",
498                                  type_string, exceptions);
499
500  // This is mainly here to keep this function ideologically parallel to
501  // UpdateExceptionsViewFromHostContentSettingsMap().
502  UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
503}
504
505void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
506    ContentSettingsType type) {
507  HostContentSettingsMap::SettingsForOneType entries;
508  GetContentSettingsMap()->GetSettingsForOneType(type, "", &entries);
509
510  ListValue exceptions;
511  for (size_t i = 0; i < entries.size(); ++i) {
512    exceptions.Append(GetExceptionForPage(entries[i].first, entries[i].second));
513  }
514
515  StringValue type_string(ContentSettingsTypeToGroupName(type));
516  web_ui_->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
517                                  exceptions);
518
519  UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
520
521  // The default may also have changed (we won't get a separate notification).
522  // If it hasn't changed, this call will be harmless.
523  UpdateSettingDefaultFromModel(type);
524}
525
526void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
527    ContentSettingsType type) {
528  const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
529  if (!otr_settings_map)
530    return;
531
532  HostContentSettingsMap::SettingsForOneType otr_entries;
533  otr_settings_map->GetSettingsForOneType(type, "", &otr_entries);
534
535  ListValue otr_exceptions;
536  for (size_t i = 0; i < otr_entries.size(); ++i) {
537    otr_exceptions.Append(GetExceptionForPage(otr_entries[i].first,
538                                              otr_entries[i].second));
539  }
540
541  StringValue type_string(ContentSettingsTypeToGroupName(type));
542  web_ui_->CallJavascriptFunction("ContentSettings.setOTRExceptions",
543                                  type_string, otr_exceptions);
544}
545
546void ContentSettingsHandler::RegisterMessages() {
547  web_ui_->RegisterMessageCallback("setContentFilter",
548      NewCallback(this,
549                  &ContentSettingsHandler::SetContentFilter));
550  web_ui_->RegisterMessageCallback("setAllowThirdPartyCookies",
551      NewCallback(this,
552                  &ContentSettingsHandler::SetAllowThirdPartyCookies));
553  web_ui_->RegisterMessageCallback("removeException",
554      NewCallback(this,
555                  &ContentSettingsHandler::RemoveException));
556  web_ui_->RegisterMessageCallback("setException",
557      NewCallback(this,
558                  &ContentSettingsHandler::SetException));
559  web_ui_->RegisterMessageCallback("checkExceptionPatternValidity",
560      NewCallback(this,
561                  &ContentSettingsHandler::CheckExceptionPatternValidity));
562}
563
564void ContentSettingsHandler::SetContentFilter(const ListValue* args) {
565  DCHECK_EQ(2U, args->GetSize());
566  std::string group, setting;
567  if (!(args->GetString(0, &group) &&
568        args->GetString(1, &setting))) {
569    NOTREACHED();
570    return;
571  }
572
573  ContentSetting default_setting = ContentSettingFromString(setting);
574  ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
575  if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
576    web_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
577        SetDefaultContentSetting(default_setting);
578  } else if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
579    DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
580        SetDefaultContentSetting(default_setting);
581  } else {
582    GetContentSettingsMap()->
583        SetDefaultContentSetting(content_type, default_setting);
584  }
585}
586
587void ContentSettingsHandler::SetAllowThirdPartyCookies(const ListValue* args) {
588  string16 allow = ExtractStringValue(args);
589
590  GetContentSettingsMap()->SetBlockThirdPartyCookies(
591      LowerCaseEqualsASCII(allow, "true"));
592}
593
594void ContentSettingsHandler::RemoveException(const ListValue* args) {
595  size_t arg_i = 0;
596  std::string type_string;
597  CHECK(args->GetString(arg_i++, &type_string));
598
599  ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
600  if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
601    std::string origin;
602    std::string embedding_origin;
603    bool rv = args->GetString(arg_i++, &origin);
604    DCHECK(rv);
605    rv = args->GetString(arg_i++, &embedding_origin);
606    DCHECK(rv);
607
608    web_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
609        SetContentSetting(GURL(origin),
610                          GURL(embedding_origin),
611                          CONTENT_SETTING_DEFAULT);
612  } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
613    std::string origin;
614    std::string setting;
615    bool rv = args->GetString(arg_i++, &origin);
616    DCHECK(rv);
617    rv = args->GetString(arg_i++, &setting);
618    DCHECK(rv);
619    ContentSetting content_setting = ContentSettingFromString(setting);
620    if (content_setting == CONTENT_SETTING_ALLOW) {
621      DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
622          ResetAllowedOrigin(GURL(origin));
623    } else {
624      DCHECK_EQ(content_setting, CONTENT_SETTING_BLOCK);
625      DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
626          ResetBlockedOrigin(GURL(origin));
627    }
628  } else {
629    std::string mode;
630    bool rv = args->GetString(arg_i++, &mode);
631    DCHECK(rv);
632
633    std::string pattern;
634    rv = args->GetString(arg_i++, &pattern);
635    DCHECK(rv);
636
637    HostContentSettingsMap* settings_map =
638        mode == "normal" ? GetContentSettingsMap() :
639                           GetOTRContentSettingsMap();
640    // The settings map could be null if the mode was OTR but the OTR profile
641    // got destroyed before we received this message.
642    if (settings_map) {
643      settings_map->SetContentSetting(
644          ContentSettingsPattern(pattern),
645          ContentSettingsTypeFromGroupName(type_string),
646          "",
647          CONTENT_SETTING_DEFAULT);
648    }
649  }
650}
651
652void ContentSettingsHandler::SetException(const ListValue* args) {
653  size_t arg_i = 0;
654  std::string type_string;
655  CHECK(args->GetString(arg_i++, &type_string));
656  std::string mode;
657  CHECK(args->GetString(arg_i++, &mode));
658  std::string pattern;
659  CHECK(args->GetString(arg_i++, &pattern));
660  std::string setting;
661  CHECK(args->GetString(arg_i++, &setting));
662
663  ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
664  if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
665      type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
666    NOTREACHED();
667    return;
668  }
669
670  HostContentSettingsMap* settings_map =
671      mode == "normal" ? GetContentSettingsMap() :
672                         GetOTRContentSettingsMap();
673
674  // The settings map could be null if the mode was OTR but the OTR profile
675  // got destroyed before we received this message.
676  if (!settings_map)
677    return;
678
679  settings_map->SetContentSetting(ContentSettingsPattern(pattern),
680                                  type,
681                                  "",
682                                  ContentSettingFromString(setting));
683}
684
685void ContentSettingsHandler::CheckExceptionPatternValidity(
686    const ListValue* args) {
687  size_t arg_i = 0;
688  Value* type;
689  CHECK(args->Get(arg_i++, &type));
690  std::string mode_string;
691  CHECK(args->GetString(arg_i++, &mode_string));
692  std::string pattern_string;
693  CHECK(args->GetString(arg_i++, &pattern_string));
694
695  ContentSettingsPattern pattern(pattern_string);
696
697  scoped_ptr<Value> mode_value(Value::CreateStringValue(mode_string));
698  scoped_ptr<Value> pattern_value(Value::CreateStringValue(pattern_string));
699  scoped_ptr<Value> valid_value(Value::CreateBooleanValue(pattern.IsValid()));
700
701  web_ui_->CallJavascriptFunction(
702      "ContentSettings.patternValidityCheckComplete",
703      *type,
704      *mode_value.get(),
705      *pattern_value.get(),
706      *valid_value.get());
707}
708
709// static
710std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
711    ContentSettingsType type) {
712  if (type < CONTENT_SETTINGS_TYPE_COOKIES ||
713      type >= CONTENT_SETTINGS_NUM_TYPES) {
714    NOTREACHED();
715    return "";
716  }
717  return kContentSettingsTypeGroupNames[type];
718}
719
720HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
721  return web_ui_->GetProfile()->GetHostContentSettingsMap();
722}
723
724HostContentSettingsMap*
725    ContentSettingsHandler::GetOTRContentSettingsMap() {
726  Profile* profile = web_ui_->GetProfile();
727  if (profile->HasOffTheRecordProfile())
728    return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
729  return NULL;
730}
731