[epiphany/gnome-3-22] Save decision to allow or deny notifications



commit 0bda122235eb4bc86c35817ed5cbf4e7110e98f1
Author: Gustavo Noronha Silva <gns gnome org>
Date:   Wed Sep 28 12:25:41 2016 +0200

    Save decision to allow or deny notifications
    
    The decision is stored using gsettings database. No UI exists currently to
    forget or manage the decisions.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=748339

 data/Makefile.am                         |    2 +-
 data/org.gnome.epiphany.host.gschema.xml |   13 +++
 embed/Makefile.am                        |    2 +
 embed/ephy-embed-shell.c                 |   12 +++
 embed/ephy-embed-shell.h                 |    2 +
 embed/ephy-hosts-manager.c               |  152 ++++++++++++++++++++++++++++++
 embed/ephy-hosts-manager.h               |   45 +++++++++
 embed/ephy-web-view.c                    |   61 ++++++++++--
 8 files changed, 278 insertions(+), 11 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 1f49cf9..ead148f 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -14,7 +14,7 @@ convert_DATA = epiphany.convert
 gsettings_ENUM_NAMESPACE = org.gnome.Epiphany
 gsettings_ENUM_FILES = $(top_srcdir)/lib/ephy-prefs.h
 
-gsettings_SCHEMAS = org.gnome.epiphany.gschema.xml
+gsettings_SCHEMAS = org.gnome.epiphany.gschema.xml org.gnome.epiphany.host.gschema.xml
 @GSETTINGS_RULES@
 
 appstream_in_files = epiphany.appdata.xml.in
diff --git a/data/org.gnome.epiphany.host.gschema.xml b/data/org.gnome.epiphany.host.gschema.xml
new file mode 100644
index 0000000..f70c7b7
--- /dev/null
+++ b/data/org.gnome.epiphany.host.gschema.xml
@@ -0,0 +1,13 @@
+<schemalist>
+  <enum id="org.gnome.Epiphany.host.permissions">
+    <value nick="undecided" value="-1"/>
+    <value nick="deny" value="0"/>
+    <value nick="allow" value="1"/>
+  </enum>
+
+  <schema id="org.gnome.Epiphany.host" gettext-domain="">
+    <key name="notifications-permission" enum="org.gnome.Epiphany.host.permissions">
+      <default>"undecided"</default>
+    </key>
+  </schema>
+</schemalist>
diff --git a/embed/Makefile.am b/embed/Makefile.am
index 8969e1b..a470def 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -44,6 +44,8 @@ libephyembed_la_SOURCES = \
        ephy-find-toolbar.c             \
        ephy-find-toolbar.h             \
        ephy-embed-prefs.c              \
+       ephy-hosts-manager.c    \
+       ephy-hosts-manager.h    \
        ephy-web-view.c                 \
        ephy-web-view.h                 \
        ephy-web-extension-proxy.c      \
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 2d86f32..4c85ff2 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -54,6 +54,7 @@ typedef struct {
   EphyEmbedShellMode mode;
   WebKitUserContentManager *user_content;
   EphyDownloadsManager *downloads_manager;
+  EphyHostsManager *hosts_manager;
   EphyAboutHandler *about_handler;
   guint update_overview_timeout_id;
   guint hiding_overview_item;
@@ -102,6 +103,7 @@ ephy_embed_shell_dispose (GObject *object)
   g_clear_object (&priv->about_handler);
   g_clear_object (&priv->user_content);
   g_clear_object (&priv->downloads_manager);
+  g_clear_object (&priv->hosts_manager);
   g_clear_object (&priv->web_context);
   g_clear_object (&priv->dbus_server);
 
@@ -1234,3 +1236,13 @@ ephy_embed_shell_get_downloads_manager (EphyEmbedShell *shell)
     priv->downloads_manager = EPHY_DOWNLOADS_MANAGER (g_object_new (EPHY_TYPE_DOWNLOADS_MANAGER, NULL));
   return priv->downloads_manager;
 }
+
+EphyHostsManager *
+ephy_embed_shell_get_hosts_manager (EphyEmbedShell *shell)
+{
+  EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
+
+  if (!priv->hosts_manager)
+    priv->hosts_manager = ephy_hosts_manager_new ();
+  return priv->hosts_manager;
+}
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index 1617d45..d81e31f 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -22,6 +22,7 @@
 
 #include <webkit2/webkit2.h>
 #include "ephy-downloads-manager.h"
+#include "ephy-hosts-manager.h"
 
 G_BEGIN_DECLS
 
@@ -73,6 +74,7 @@ void               ephy_embed_shell_set_thumbnail_path         (EphyEmbedShell
                                                                 const char       *path);
 WebKitUserContentManager *ephy_embed_shell_get_user_content_manager (EphyEmbedShell *shell);
 EphyDownloadsManager     *ephy_embed_shell_get_downloads_manager    (EphyEmbedShell *shell);
+EphyHostsManager         *ephy_embed_shell_get_hosts_manager        (EphyEmbedShell *shell);
 
 G_END_DECLS
 
diff --git a/embed/ephy-hosts-manager.c b/embed/ephy-hosts-manager.c
new file mode 100644
index 0000000..9a9d3df
--- /dev/null
+++ b/embed/ephy-hosts-manager.c
@@ -0,0 +1,152 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2015 Gustavo Noronha Silva <gns gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "ephy-hosts-manager.h"
+
+#include "ephy-embed-shell.h"
+#include "ephy-file-helpers.h"
+#include "ephy-string.h"
+
+#define G_SETTINGS_ENABLE_BACKEND 1
+#include <gio/gsettingsbackend.h>
+
+struct _EphyHostsManager
+{
+  GObject parent_instance;
+
+  GHashTable *hosts_mapping;
+  GHashTable *settings_mapping;
+};
+
+G_DEFINE_TYPE (EphyHostsManager, ephy_hosts_manager, G_TYPE_OBJECT)
+
+static void
+ephy_hosts_manager_init (EphyHostsManager *manager)
+{
+  manager->hosts_mapping = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+  manager->settings_mapping = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+}
+
+static void
+ephy_hosts_manager_dispose (GObject *object)
+{
+  EphyHostsManager *manager = EPHY_HOSTS_MANAGER (object);
+
+  g_clear_pointer (&manager->hosts_mapping, g_hash_table_destroy);
+  g_clear_pointer (&manager->settings_mapping, g_hash_table_destroy);
+
+  G_OBJECT_CLASS (ephy_hosts_manager_parent_class)->dispose (object);
+}
+
+static void
+ephy_hosts_manager_class_init (EphyHostsManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ephy_hosts_manager_dispose;
+
+  /**
+   * EphyHostsManager::setting-changed:
+   * @host_manager: the #EphyHostsManager that received the signal
+   * @host: the hostname for which the setting changed
+   * @key: the name of the key that changed
+   *
+   * The ::setting-changed signal is emitted when the a setting changes for
+   * one of the hosts managed by the manager. It can be used to represent the
+   * change on the UI for instance.
+   **/
+  g_signal_new ("setting-changed",
+                EPHY_TYPE_HOSTS_MANAGER,
+                G_SIGNAL_RUN_FIRST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE,
+                2,
+                G_TYPE_STRING,
+                G_TYPE_STRING);
+}
+
+static void
+setting_changed_cb (GSettings *settings,
+                    char *key,
+                    EphyHostsManager *manager)
+{
+  const char *host = g_hash_table_lookup (manager->settings_mapping, settings);
+  g_signal_emit_by_name (manager, "setting-changed", host, key);
+}
+
+static GSettings *
+ephy_hosts_manager_get_settings_for_address (EphyHostsManager *manager,
+                                             const char *address)
+{
+  char *host = ephy_string_get_host_name (address);
+  char *key_file = NULL;
+  char *host_path = NULL;
+  GSettingsBackend* backend = NULL;
+  GSettings *settings;
+
+  g_assert (host != NULL);
+
+  settings = g_hash_table_lookup (manager->hosts_mapping, host);
+  if (settings) {
+    g_free (host);
+    return settings;
+  }
+
+  key_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "hosts.ini", ephy_dot_dir ());
+  backend = g_keyfile_settings_backend_new (key_file, "/", "Hosts");
+  g_free (key_file);
+
+  host_path = g_strdup_printf ("/org/gnome/epiphany/hosts/%s/", host);
+
+  settings = g_settings_new_with_backend_and_path ("org.gnome.Epiphany.host", backend, host_path);
+
+  g_free (host_path);
+  g_object_unref (backend);
+
+  g_hash_table_insert (manager->hosts_mapping, host, settings);
+  g_hash_table_insert (manager->settings_mapping, settings, host);
+
+  g_signal_connect (settings, "changed",
+                    G_CALLBACK (setting_changed_cb), manager);
+
+  return settings;
+}
+
+EphyHostsManager *
+ephy_hosts_manager_new (void)
+{
+  return EPHY_HOSTS_MANAGER (g_object_new (EPHY_TYPE_HOSTS_MANAGER, NULL));
+}
+
+EphyHostPermission
+ephy_hosts_manager_get_notifications_permission_for_address (EphyHostsManager *manager,
+                                                             const char *address)
+{
+  GSettings *settings = ephy_hosts_manager_get_settings_for_address (manager, address);
+  return g_settings_get_enum (settings, "notifications-permission");
+}
+
+void
+ephy_hosts_manager_set_notifications_permission_for_address (EphyHostsManager *manager,
+                                                             const char *address,
+                                                             EphyHostPermission permission)
+{
+  GSettings *settings = ephy_hosts_manager_get_settings_for_address (manager, address);
+  g_settings_set_enum (settings, "notifications-permission", permission);
+}
diff --git a/embed/ephy-hosts-manager.h b/embed/ephy-hosts-manager.h
new file mode 100644
index 0000000..482337e
--- /dev/null
+++ b/embed/ephy-hosts-manager.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2015 Gustavo Noronha Silva <gns gnome org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EPHY_HOSTS_MANAGER_H
+#define EPHY_HOSTS_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_HOSTS_MANAGER (ephy_hosts_manager_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyHostsManager, ephy_hosts_manager, EPHY, HOSTS_MANAGER, GObject)
+
+typedef enum {
+  EPHY_HOST_PERMISSION_UNDECIDED = -1,
+  EPHY_HOST_PERMISSION_DENY = 0,
+  EPHY_HOST_PERMISSION_ALLOW = 1,
+} EphyHostPermission;
+
+EphyHostsManager*       ephy_hosts_manager_new                                      (void);
+EphyHostPermission      ephy_hosts_manager_get_notifications_permission_for_address (EphyHostsManager    
*manager,
+                                                                                     const char          
*address);
+void                    ephy_hosts_manager_set_notifications_permission_for_address (EphyHostsManager    
*manager,
+                                                                                     const char          
*address,
+                                                                                     EphyHostPermission   
permission);
+
+G_END_DECLS
+
+#endif /* EPHY_HOSTS_MANAGER_H */
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index bc149b7..10931d6 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -1235,24 +1235,41 @@ decide_policy_cb (WebKitWebView           *web_view,
   return TRUE;
 }
 
+typedef struct {
+  EphyWebView *web_view;
+  WebKitPermissionRequest *request;
+} PermissionRequestData;
+
 static void
 decide_on_permission_request (GtkWidget               *info_bar,
                               int                      response,
-                              WebKitPermissionRequest *request)
+                              PermissionRequestData   *data)
 {
   gtk_widget_destroy (info_bar);
 
   switch (response) {
     case GTK_RESPONSE_YES:
-      webkit_permission_request_allow (request);
+      webkit_permission_request_allow (data->request);
       break;
     default:
-      webkit_permission_request_deny (request);
+      webkit_permission_request_deny (data->request);
       break;
   }
 
+  if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST (data->request) && response != GTK_RESPONSE_NONE) {
+    const char *address = ephy_web_view_get_address (data->web_view);
+    if (ephy_embed_utils_address_has_web_scheme (address)) {
+      EphyHostsManager *hosts_manager = ephy_embed_shell_get_hosts_manager (ephy_embed_shell_get_default ());
+      ephy_hosts_manager_set_notifications_permission_for_address (
+        hosts_manager,
+        address,
+        response == GTK_RESPONSE_YES ? EPHY_HOST_PERMISSION_ALLOW : EPHY_HOST_PERMISSION_DENY);
+    }
+  }
+
   gtk_widget_destroy (info_bar);
-  g_object_unref (request);
+  g_object_unref (data->request);
+  g_slice_free (PermissionRequestData, data);
 }
 
 static gboolean
@@ -1263,6 +1280,7 @@ permission_request_cb (WebKitWebView           *web_view,
   GtkWidget *action_area;
   GtkWidget *content_area;
   GtkWidget *label;
+  PermissionRequestData *data;
   char *message;
   char *host;
 
@@ -1270,11 +1288,30 @@ permission_request_cb (WebKitWebView           *web_view,
       !WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST (decision))
     return FALSE;
 
-  /* Application mode implies being OK with notifications. */
-  if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST (decision) &&
-      ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) == EPHY_EMBED_SHELL_MODE_APPLICATION) {
-    webkit_permission_request_allow (decision);
-    return TRUE;
+  if (WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST (decision)) {
+    /* Application mode implies being OK with notifications. */
+    if (ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) == EPHY_EMBED_SHELL_MODE_APPLICATION) {
+      webkit_permission_request_allow (decision);
+      return TRUE;
+    }
+
+    {
+      const char *address = ephy_web_view_get_address (EPHY_WEB_VIEW (web_view));
+      EphyHostsManager *hosts_manager = ephy_embed_shell_get_hosts_manager (ephy_embed_shell_get_default ());
+      EphyHostPermission permission = ephy_hosts_manager_get_notifications_permission_for_address 
(hosts_manager, address);
+
+      switch (permission) {
+      case EPHY_HOST_PERMISSION_ALLOW:
+        webkit_permission_request_allow (decision);
+        return TRUE;
+      case EPHY_HOST_PERMISSION_DENY:
+        webkit_permission_request_deny (decision);
+        return TRUE;
+      case EPHY_HOST_PERMISSION_UNDECIDED:
+      default:
+        break;
+      }
+    }
   }
 
   info_bar = gtk_info_bar_new_with_buttons (_("Deny"), GTK_RESPONSE_NO,
@@ -1312,9 +1349,13 @@ permission_request_cb (WebKitWebView           *web_view,
   gtk_widget_show_all (info_bar);
 
   /* Ref the decision, to keep it alive while we decide */
+  data = g_new (PermissionRequestData, 1);
+  data->web_view = EPHY_WEB_VIEW (web_view);
+  data->request = g_object_ref (decision);
+
   g_signal_connect (info_bar, "response",
                     G_CALLBACK (decide_on_permission_request),
-                    g_object_ref (decision));
+                    data);
 
   if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST (decision))
     ephy_web_view_track_info_bar (info_bar, &EPHY_WEB_VIEW (web_view)->geolocation_info_bar);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]