Blob Blame History Raw
From abdedafd3a530ad4baa992010a3cfc87645d98d1 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Sat, 16 May 2015 06:51:37 +0200
Subject: [PATCH] config UI: Automatic reporting from GSettings

If Privacy panels exists:
  Make the widget insensitive because the user can only read its value.
  Add a button launching Privacy panel.
Else:
  Read/write the GSettings and show a warning about modifying the
  GSettings.

Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
 po/POTFILES.in                                 |   1 +
 src/configuration-gui/abrt-config-widget.c     | 201 +++++++++++++++++++++++--
 src/configuration-gui/abrt-config-widget.glade |  82 ++++------
 3 files changed, 217 insertions(+), 67 deletions(-)

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0da1396..8c31438 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -3,6 +3,7 @@
 # Please keep this file sorted alphabetically.
 src/applet/abrt-applet.desktop.in
 src/applet/applet.c
+src/configuration-gui/abrt-config-widget.c
 src/configuration-gui/abrt-config-widget.glade
 src/configuration-gui/system-config-abrt.c
 src/configuration-gui/main.c
diff --git a/src/configuration-gui/abrt-config-widget.c b/src/configuration-gui/abrt-config-widget.c
index 8bfc269..c9b0b02 100644
--- a/src/configuration-gui/abrt-config-widget.c
+++ b/src/configuration-gui/abrt-config-widget.c
@@ -21,6 +21,8 @@
 #endif
 
 #include "abrt-config-widget.h"
+#include <satyr/utils.h>
+#include <gio/gdesktopappinfo.h>
 
 #include "libabrt.h"
 #include <assert.h>
@@ -32,19 +34,36 @@
 
 #define UI_FILE_NAME "abrt-config-widget.glade"
 
+/* AbrtConfigWidgetPrivate:
+ *     + AbrtConfigWidgetOption == "abrt-option" of GtkSwitch
+ *     + AbrtConfigWidgetOption == "abrt-option" of GtkSwitch
+ *     + ...
+ *
+ *     + AbrtAppConfiguration == config of AbrtConfigWidgetOption
+ *     + AbrtAppConfiguration == config of AbrtConfigWidgetOption
+ *     + ...
+ */
+
+/* This structure represents either an ABRT configuration file or a GSettings
+ * schema.
+ */
 typedef struct {
-    char *app_name;
-    map_string_t *settings;
+    char *app_name;             ///< e.g abrt-applet, org.gnome.desktop.privacy
+    map_string_t *settings;     ///< ABRT configuration file
+    GSettings *glib_settings;   ///< GSettings
 } AbrtAppConfiguration;
 
+/* This structure represents a single switch.
+ */
 typedef struct {
-    const char *name;
+    const char *name;           ///< e.g. ask_steal_dir, report-technical-problems
     GtkSwitch *widget;
     gboolean default_value;
     gboolean current_value;
     AbrtAppConfiguration *config;
 } AbrtConfigWidgetOption;
 
+/* Each configuration option has its own number. */
 enum AbrtOptions
 {
     _ABRT_OPT_BEGIN_,
@@ -60,11 +79,15 @@ enum AbrtOptions
     _ABRT_OPT_END_,
 };
 
+/* This structure holds private data of AbrtConfigWidget
+ */
 struct AbrtConfigWidgetPrivate {
     GtkBuilder   *builder;
     AbrtAppConfiguration *report_gtk_conf;
     AbrtAppConfiguration *abrt_applet_conf;
+    AbrtAppConfiguration *privacy_gsettings;
 
+    /* Static array for all switches */
     AbrtConfigWidgetOption options[_ABRT_OPT_END_];
 };
 
@@ -79,6 +102,8 @@ static guint s_signals[SN_LAST_SIGNAL] = { 0 };
 
 static void abrt_config_widget_finalize(GObject *object);
 
+/* New ABRT configuration file wrapper
+ */
 static AbrtAppConfiguration *
 abrt_app_configuration_new(const char *app_name)
 {
@@ -86,6 +111,7 @@ abrt_app_configuration_new(const char *app_name)
 
     conf->app_name = xstrdup(app_name);
     conf->settings = new_map_string();
+    conf->glib_settings = NULL;
 
     if(!load_app_conf_file(conf->app_name, conf->settings)) {
         g_warning("Failed to load config for '%s'", conf->app_name);
@@ -94,22 +120,50 @@ abrt_app_configuration_new(const char *app_name)
     return conf;
 }
 
+/* New GSettings wrapper
+ */
+static AbrtAppConfiguration *
+abrt_app_configuration_new_glib(const char *schema)
+{
+    AbrtAppConfiguration *conf = xmalloc(sizeof(*conf));
+
+    conf->app_name = xstrdup(schema);
+    conf->settings = NULL;
+    conf->glib_settings = g_settings_new(conf->app_name);
+
+    return conf;
+}
+
 static void
 abrt_app_configuration_set_value(AbrtAppConfiguration *conf, const char *name, const char *value)
 {
-    set_app_user_setting(conf->settings, name, value);
+    if (conf->settings)
+        set_app_user_setting(conf->settings, name, value);
+    else if (conf->glib_settings)
+        g_settings_set_boolean(conf->glib_settings, name, string_to_bool(value));
+    else
+        assert(!"BUG: not properly initialized AbrtAppConfiguration");
 }
 
 static const char *
 abrt_app_configuration_get_value(AbrtAppConfiguration *conf, const char *name)
 {
-    return get_app_user_setting(conf->settings, name);
+    if (conf->settings)
+        return get_app_user_setting(conf->settings, name);
+
+    if (conf->glib_settings)
+        return g_settings_get_boolean(conf->glib_settings, name) ? "yes" : "no";
+
+    assert(!"BUG: not properly initialized AbrtAppConfiguration");
 }
 
 static void
 abrt_app_configuration_save(AbrtAppConfiguration *conf)
 {
-    save_app_conf_file(conf->app_name, conf->settings);
+    if (conf->settings)
+        save_app_conf_file(conf->app_name, conf->settings);
+
+    /* No need to save GSettings because changes are applied instantly */
 }
 
 static void
@@ -121,8 +175,17 @@ abrt_app_configuration_free(AbrtAppConfiguration *conf)
     free(conf->app_name);
     conf->app_name = (void *)0xDEADBEAF;
 
-    free_map_string(conf->settings);
-    conf->settings = (void *)0xDEADBEAF;
+    if (conf->settings)
+    {
+        free_map_string(conf->settings);
+        conf->settings = (void *)0xDEADBEAF;
+    }
+
+    if (conf->glib_settings)
+    {
+        g_object_unref(conf->glib_settings);
+        conf->glib_settings = (void *)0xDEADBEAF;
+    }
 }
 
 static void
@@ -161,6 +224,9 @@ abrt_config_widget_finalize(GObject *object)
     abrt_app_configuration_free(self->priv->abrt_applet_conf);
     self->priv->abrt_applet_conf = NULL;
 
+    abrt_app_configuration_free(self->priv->privacy_gsettings);
+    self->priv->privacy_gsettings = NULL;
+
     G_OBJECT_CLASS(abrt_config_widget_parent_class)->finalize(object);
 }
 
@@ -217,8 +283,31 @@ connect_switch_with_option(AbrtConfigWidget *self, enum AbrtOptions opid, const
     g_signal_connect(G_OBJECT(gsw), "notify::active",
             G_CALLBACK(on_switch_activate), self);
 
-    if (option->config == NULL)
-        gtk_widget_set_sensitive(GTK_WIDGET(gsw), FALSE);
+    /* If the option has no config, make the corresponding insensitive. */
+    gtk_widget_set_sensitive(GTK_WIDGET(gsw), option->config != NULL);
+}
+
+static void
+pp_launcher_clicked(GtkButton *launcher, gpointer *unused_data)
+{
+    GDesktopAppInfo *app = g_object_get_data(G_OBJECT(launcher), "launched-app");
+    GError *err = NULL;
+    if (!g_app_info_launch(G_APP_INFO(app), NULL, NULL, &err))
+    {
+        perror_msg("Could not launch '%s': %s",
+                g_desktop_app_info_get_filename(G_DESKTOP_APP_INFO (app)),
+                err->message);
+    }
+}
+
+static void
+os_release_callback(char *key, char *value, void *data)
+{
+    if (strcmp(key, "PRIVACY_POLICY") == 0)
+        *(char **)data = value;
+    else
+        free(value);
+    free(key);
 }
 
 static void
@@ -249,6 +338,7 @@ abrt_config_widget_init(AbrtConfigWidget *self)
 
     self->priv->report_gtk_conf = abrt_app_configuration_new("report-gtk");
     self->priv->abrt_applet_conf = abrt_app_configuration_new("abrt-applet");
+    self->priv->privacy_gsettings = abrt_app_configuration_new_glib("org.gnome.desktop.privacy");
 
     /* Initialize options */
     /* report-gtk */
@@ -259,15 +349,98 @@ abrt_config_widget_init(AbrtConfigWidget *self)
     self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].name = "abrt_analyze_smart_ask_upload_coredump";
     self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].default_value = TRUE;
     self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].config = self->priv->report_gtk_conf;
-
     self->priv->options[ABRT_OPT_PRIVATE_TICKET].name = CREATE_PRIVATE_TICKET;
     self->priv->options[ABRT_OPT_PRIVATE_TICKET].default_value = FALSE;
     self->priv->options[ABRT_OPT_PRIVATE_TICKET].config = self->priv->report_gtk_conf;
 
     /* abrt-applet */
-    self->priv->options[ABRT_OPT_SEND_UREPORT].name = "AutoreportingEnabled";
-    self->priv->options[ABRT_OPT_SEND_UREPORT].default_value = g_settings_autoreporting;
-    self->priv->options[ABRT_OPT_SEND_UREPORT].config = self->priv->abrt_applet_conf;
+    self->priv->options[ABRT_OPT_SEND_UREPORT].name = "report-technical-problems";
+    self->priv->options[ABRT_OPT_SEND_UREPORT].default_value =
+            string_to_bool(abrt_app_configuration_get_value(self->priv->privacy_gsettings,
+                                                            "report-technical-problems"));
+    {
+        /* Get the container widget for the lauch button and warnings */
+        GtkWidget *hbox_auto_reporting = WID("hbox_auto_reporting");
+        assert(hbox_auto_reporting);
+
+        /* Be able to use another desktop file while debugging */
+        const char *gpp_app = getenv("ABRT_PRIVACY_APP_DESKTOP");
+        if (gpp_app == NULL)
+            gpp_app = "gnome-privacy-panel.desktop";
+
+        GDesktopAppInfo *app = g_desktop_app_info_new(gpp_app);
+        char *message = NULL;
+        char *markup = NULL;
+        if (!app)
+        {
+            /* Make the switch editable */
+            self->priv->options[ABRT_OPT_SEND_UREPORT].config = self->priv->privacy_gsettings;
+
+            char *os_release = xmalloc_open_read_close("/etc/os-release", /*no size limit*/NULL);
+            char *privacy_policy = NULL;
+
+            /* Try to get the value of PRIVACY_POLICY from /etc/os-release */
+            sr_parse_os_release(os_release, os_release_callback, (void *)&privacy_policy);
+
+            message = xasprintf(_("The configuration option above has been moved to GSettings and "
+                                  "the switch is linked to the value of the setting 'report-technical-problems' "
+                                  "from the schema 'org.gnome.desktop.privacy'."));
+
+            /* Do not add Privacy Policy link if /etc/os-release does not contain PRIVACY_POLICY */
+            if (privacy_policy != NULL)
+                markup = xasprintf("<i>%s</i>\n\n<a href=\"%s\">Privacy Policy</a>", message, privacy_policy);
+            else
+                markup = xasprintf("<i>%s</i>", message);
+
+            free(privacy_policy);
+            free(os_release);
+        }
+        else
+        {
+            /* Make the switch read-only */
+            self->priv->options[ABRT_OPT_SEND_UREPORT].config = NULL;
+
+            message = xasprintf(_("The configuration option above can be configured in"));
+            markup = xasprintf("<i>%s</i>", message);
+
+            GtkWidget *launcher = gtk_button_new_with_label(g_app_info_get_display_name(G_APP_INFO(app)));
+
+            /* Here we could pass the launcher to pp_launcher_clicked() as the
+             * 4th argument of g_signal_connect() but we would leek the
+             * launcher's memory. Therefore we need to find a way how to free
+             * the launcher when it is not needed anymore. GtkWidget inherits
+             * from GObject which offers a functionality for attaching an
+             * arbitrary data to its instances. The last argument is a function
+             * called to destroy the arbirarty data when the instance is being
+             * destoryed. */
+            g_object_set_data_full(G_OBJECT(launcher), "launched-app", app, g_object_unref);
+            g_signal_connect(launcher, "clicked", G_CALLBACK(pp_launcher_clicked), NULL);
+
+            /* Make the launcher button narrow, otherwise it would expand to
+             * the width of the warninig. */
+            gtk_widget_set_hexpand(launcher, FALSE);
+            gtk_widget_set_vexpand(launcher, FALSE);
+
+            /* Make the launcher button alligned on center of the warning. */
+            gtk_widget_set_halign(launcher, GTK_ALIGN_CENTER);
+            gtk_widget_set_valign(launcher, GTK_ALIGN_CENTER);
+
+            gtk_box_pack_end(GTK_BOX(hbox_auto_reporting), launcher, false, false, 0);
+        }
+
+
+        GtkWidget *lbl = gtk_label_new(message);
+        gtk_label_set_markup(GTK_LABEL(lbl), markup);
+        /* Do not expand the window by too long warning. */
+        gtk_label_set_line_wrap(GTK_LABEL(lbl), TRUE);
+        /* Let users to copy the warning. */
+        gtk_label_set_selectable(GTK_LABEL(lbl), TRUE);
+
+        free(markup);
+        free(message);
+
+        gtk_box_pack_start(GTK_BOX(hbox_auto_reporting), lbl, false, false, 0);
+    }
 
     self->priv->options[ABRT_OPT_SHORTENED_REPORTING].name = "ShortenedReporting";
     self->priv->options[ABRT_OPT_SHORTENED_REPORTING].default_value = g_settings_shortenedreporting;
diff --git a/src/configuration-gui/abrt-config-widget.glade b/src/configuration-gui/abrt-config-widget.glade
index 3aa566c..7f613c7 100644
--- a/src/configuration-gui/abrt-config-widget.glade
+++ b/src/configuration-gui/abrt-config-widget.glade
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
 <interface>
-  <!-- interface-requires gtk+ 3.0 -->
+  <requires lib="gtk+" version="3.0"/>
   <object class="GtkWindow" id="window1">
     <property name="can_focus">False</property>
     <child>
@@ -11,7 +12,6 @@
         <property name="margin_right">10</property>
         <property name="margin_top">10</property>
         <property name="margin_bottom">10</property>
-        <property name="row_homogeneous">True</property>
         <child>
           <object class="GtkLabel" id="label2">
             <property name="visible">True</property>
@@ -26,8 +26,6 @@
           <packing>
             <property name="left_attach">0</property>
             <property name="top_attach">1</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -44,8 +42,6 @@
           <packing>
             <property name="left_attach">0</property>
             <property name="top_attach">3</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -59,8 +55,6 @@
           <packing>
             <property name="left_attach">1</property>
             <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -74,13 +68,12 @@
           <packing>
             <property name="left_attach">1</property>
             <property name="top_attach">1</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
           <object class="GtkSwitch" id="switch_send_ureport">
             <property name="visible">True</property>
+            <property name="sensitive">False</property>
             <property name="can_focus">True</property>
             <property name="halign">end</property>
             <property name="valign">center</property>
@@ -89,8 +82,6 @@
           <packing>
             <property name="left_attach">1</property>
             <property name="top_attach">3</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -106,9 +97,7 @@
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">4</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">5</property>
           </packing>
         </child>
         <child>
@@ -121,9 +110,7 @@
           </object>
           <packing>
             <property name="left_attach">1</property>
-            <property name="top_attach">4</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">5</property>
           </packing>
         </child>
         <child>
@@ -136,9 +123,7 @@
           </object>
           <packing>
             <property name="left_attach">1</property>
-            <property name="top_attach">5</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">6</property>
           </packing>
         </child>
         <child>
@@ -154,9 +139,7 @@
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">5</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">6</property>
           </packing>
         </child>
         <child>
@@ -172,8 +155,6 @@
           <packing>
             <property name="left_attach">2</property>
             <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -188,8 +169,6 @@
           <packing>
             <property name="left_attach">2</property>
             <property name="top_attach">1</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -204,8 +183,6 @@
           <packing>
             <property name="left_attach">2</property>
             <property name="top_attach">3</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -219,9 +196,7 @@
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">4</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">5</property>
           </packing>
         </child>
         <child>
@@ -235,9 +210,7 @@
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">5</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">6</property>
           </packing>
         </child>
         <child>
@@ -254,8 +227,6 @@
           <packing>
             <property name="left_attach">0</property>
             <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -270,8 +241,6 @@
           <packing>
             <property name="left_attach">2</property>
             <property name="top_attach">2</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -286,8 +255,6 @@
           <packing>
             <property name="left_attach">0</property>
             <property name="top_attach">2</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -301,8 +268,6 @@
           <packing>
             <property name="left_attach">1</property>
             <property name="top_attach">2</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
@@ -316,9 +281,7 @@
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">6</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">7</property>
           </packing>
         </child>
         <child>
@@ -331,9 +294,7 @@
           </object>
           <packing>
             <property name="left_attach">1</property>
-            <property name="top_attach">6</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">7</property>
           </packing>
         </child>
         <child>
@@ -347,11 +308,26 @@
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">6</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
+            <property name="top_attach">7</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkBox" id="hbox_auto_reporting">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">4</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
       </object>
     </child>
   </object>
-- 
2.4.1