Blame SOURCES/0003-account-display-nag-screen-periodically.patch

28c014
From 31844edad70876e26ab995179bc67fb3b23a1793 Mon Sep 17 00:00:00 2001
28c014
From: Ray Strode <rstrode@redhat.com>
28c014
Date: Mon, 6 Nov 2017 16:39:55 -0500
28c014
Subject: [PATCH 3/4] account: display nag screen periodically
28c014
28c014
This is configurable via a gsettings key.
28c014
---
28c014
 data/meson.build                              |  1 +
28c014
 ...ings-daemon.plugins.account.gschema.xml.in |  9 +++
28c014
 plugins/account/gsd-account-manager.c         | 55 +++++++++++++++++++
28c014
 3 files changed, 65 insertions(+)
28c014
 create mode 100644 data/org.gnome.settings-daemon.plugins.account.gschema.xml.in
28c014
28c014
diff --git a/data/meson.build b/data/meson.build
28c014
index e93ba641..5a2cd5a7 100644
28c014
--- a/data/meson.build
28c014
+++ b/data/meson.build
28c014
@@ -1,36 +1,37 @@
28c014
 data_inc = include_directories('.')
28c014
 
28c014
 schemas = [
28c014
   'org.gnome.settings-daemon.peripherals.gschema.xml',
28c014
   'org.gnome.settings-daemon.peripherals.wacom.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.gschema.xml',
28c014
+  'org.gnome.settings-daemon.plugins.account.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.color.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.housekeeping.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.media-keys.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.power.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.sharing.gschema.xml',
28c014
   'org.gnome.settings-daemon.plugins.xsettings.gschema.xml'
28c014
 ]
28c014
 
28c014
 schema_conf = configuration_data()
28c014
 schema_conf.set('GETTEXT_PACKAGE', meson.project_name())
28c014
 
28c014
 schemas_xml = []
28c014
 foreach schema: schemas
28c014
   schemas_xml += [configure_file(
28c014
     input: schema + '.in',
28c014
     output: schema,
28c014
     configuration: schema_conf,
28c014
     install: true,
28c014
     install_dir: gsd_schemadir
28c014
   )]
28c014
 endforeach
28c014
 
28c014
 enums_header = files('gsd-enums.h')
28c014
 
28c014
 mkenums = gnome.mkenums(
28c014
   'org.gnome.settings-daemon.enums.xml',
28c014
   sources: enums_header,
28c014
   comments: '',
28c014
   fhead: '<schemalist>',
28c014
   vhead: '  <@type@ id="org.gnome.settings-daemon.@EnumName@">',
28c014
diff --git a/data/org.gnome.settings-daemon.plugins.account.gschema.xml.in b/data/org.gnome.settings-daemon.plugins.account.gschema.xml.in
28c014
new file mode 100644
28c014
index 00000000..f3d59e81
28c014
--- /dev/null
28c014
+++ b/data/org.gnome.settings-daemon.plugins.account.gschema.xml.in
28c014
@@ -0,0 +1,9 @@
28c014
+<schemalist>
28c014
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.account" path="/org/gnome/settings-daemon/plugins/account/">
28c014
+    <key name="notify-period" type="i">
28c014
+      <default>1440</default>
28c014
+      <summary>Time before repeated warning about account password expiration</summary>
28c014
+      <description>If a user's account is expiring, a notification will get displayed periodically after the specified number of minutes</description>
28c014
+    </key>
28c014
+  </schema>
28c014
+</schemalist>
28c014
diff --git a/plugins/account/gsd-account-manager.c b/plugins/account/gsd-account-manager.c
28c014
index cb37f466..ff054edd 100644
28c014
--- a/plugins/account/gsd-account-manager.c
28c014
+++ b/plugins/account/gsd-account-manager.c
28c014
@@ -20,126 +20,135 @@
28c014
 #include "config.h"
28c014
 
28c014
 #include <sys/types.h>
28c014
 #include <sys/wait.h>
28c014
 #include <stdlib.h>
28c014
 #include <stdio.h>
28c014
 #include <unistd.h>
28c014
 #include <string.h>
28c014
 #include <errno.h>
28c014
 
28c014
 #include <locale.h>
28c014
 
28c014
 #include <glib.h>
28c014
 #include <glib/gi18n.h>
28c014
 #include <glib/gstdio.h>
28c014
 
28c014
 #include <cups/cups.h>
28c014
 #include <cups/ppd.h>
28c014
 #include <libnotify/notify.h>
28c014
 
28c014
 #include "gnome-settings-profile.h"
28c014
 #include "gnome-settings-bus.h"
28c014
 #include "gsd-account-manager.h"
28c014
 #include "org.freedesktop.Accounts.h"
28c014
 #include "org.freedesktop.Accounts.User.h"
28c014
 
28c014
 #define GSD_ACCOUNT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_ACCOUNT_MANAGER, GsdAccountManagerPrivate))
28c014
 
28c014
 struct GsdAccountManagerPrivate
28c014
 {
28c014
+        GSettings            *settings;
28c014
+
28c014
         GsdAccounts          *accounts_proxy;
28c014
         GsdAccountsUser      *accounts_user_proxy;
28c014
         GCancellable         *cancellable;
28c014
 
28c014
         GsdScreenSaver       *screensaver_proxy;
28c014
 
28c014
         gint64                expiration_time;
28c014
         gint64                last_change_time;
28c014
         gint64                min_days_between_changes;
28c014
         gint64                max_days_between_changes;
28c014
         gint64                days_to_warn;
28c014
         gint64                days_after_expiration_until_lock;
28c014
 
28c014
         NotifyNotification   *notification;
28c014
+
28c014
+        gint64                last_notify_time;
28c014
+        int                   notify_period;
28c014
+        guint                 notify_period_timeout_id;
28c014
 };
28c014
 
28c014
 static void     gsd_account_manager_class_init  (GsdAccountManagerClass *klass);
28c014
 static void     gsd_account_manager_init        (GsdAccountManager      *account_manager);
28c014
 static void     gsd_account_manager_finalize    (GObject                *object);
28c014
+static void     fetch_password_expiration_policy (GsdAccountManager *manager);
28c014
 
28c014
 G_DEFINE_TYPE (GsdAccountManager, gsd_account_manager, G_TYPE_OBJECT)
28c014
 
28c014
 static gpointer manager_object = NULL;
28c014
 
28c014
 static void
28c014
 on_notification_closed (NotifyNotification *notification,
28c014
                         gpointer            user_data)
28c014
 {
28c014
         GsdAccountManager *manager = user_data;
28c014
 
28c014
         g_clear_object (&manager->priv->notification);
28c014
 }
28c014
 
28c014
 static void
28c014
 hide_notification (GsdAccountManager *manager)
28c014
 {
28c014
         if (manager->priv->notification == NULL)
28c014
                 return;
28c014
 
28c014
         notify_notification_close (manager->priv->notification, NULL);
28c014
         g_clear_object (&manager->priv->notification);
28c014
 }
28c014
 
28c014
 static void
28c014
 show_notification (GsdAccountManager *manager,
28c014
                    const char        *primary_text,
28c014
                    const char        *secondary_text)
28c014
 {
28c014
         g_assert (manager->priv->notification == NULL);
28c014
 
28c014
         manager->priv->notification = notify_notification_new (primary_text,
28c014
                                                                secondary_text,
28c014
                                                                "avatar-default-symbolic");
28c014
         notify_notification_set_app_name (manager->priv->notification, _("User Account"));
28c014
         notify_notification_set_hint (manager->priv->notification,
28c014
                                       "resident",
28c014
                                       g_variant_new_boolean (TRUE));
28c014
         notify_notification_set_timeout (manager->priv->notification,
28c014
                                          NOTIFY_EXPIRES_NEVER);
28c014
 
28c014
         g_signal_connect (manager->priv->notification,
28c014
                           "closed",
28c014
                           G_CALLBACK (on_notification_closed),
28c014
                           manager);
28c014
 
28c014
         notify_notification_show (manager->priv->notification, NULL);
28c014
+
28c014
+        manager->priv->last_notify_time = g_get_monotonic_time ();
28c014
 }
28c014
 
28c014
 static void
28c014
 update_password_notification (GsdAccountManager *manager)
28c014
 {
28c014
         gint64           days_since_epoch;
28c014
         gint64           days_until_expiration = -1;
28c014
         gint64           days_since_last_change = -1;
28c014
         gint64           days_left = -1;
28c014
         g_autofree char *primary_text = NULL;
28c014
         g_autofree char *secondary_text = NULL;
28c014
         gboolean         password_already_expired = FALSE;
28c014
 
28c014
         hide_notification (manager);
28c014
 
28c014
         days_since_epoch = g_get_real_time () / G_USEC_PER_SEC / 60 / 60 / 24;
28c014
 
28c014
         if (manager->priv->expiration_time > 0) {
28c014
                 days_until_expiration = manager->priv->expiration_time - days_since_epoch;
28c014
 
28c014
                 if (days_until_expiration <= 0) {
28c014
                         password_already_expired = TRUE;
28c014
                         goto out;
28c014
                 }
28c014
         }
28c014
 
28c014
         if (manager->priv->last_change_time == 0) {
28c014
                 password_already_expired = TRUE;
28c014
                 goto out;
28c014
         }
28c014
@@ -181,99 +190,127 @@ out:
28c014
                 primary_text = g_strdup_printf (_("Password Expired"));
28c014
                 secondary_text = g_strdup_printf (_("Your password is expired. Please update it."));
28c014
         } else if (days_left >= 0) {
28c014
                 primary_text = g_strdup_printf (_("Password Expiring Soon"));
28c014
                 if (days_left == 0)
28c014
                     secondary_text = g_strdup_printf (_("Your password is expiring today."));
28c014
                 else if (days_left == 1)
28c014
                     secondary_text = g_strdup_printf (_("Your password is expiring in a day."));
28c014
                 else
28c014
                     secondary_text = g_strdup_printf (_("Your password is expiring in %ld days."),
28c014
                                                       days_left);
28c014
         }
28c014
 
28c014
         if (primary_text != NULL && secondary_text != NULL)
28c014
                 show_notification (manager,
28c014
                                    primary_text,
28c014
                                    secondary_text);
28c014
 }
28c014
 
28c014
 static gboolean
28c014
 set_policy_number (gint64 *destination,
28c014
                    gint64  source)
28c014
 {
28c014
         if (*destination == source)
28c014
                 return FALSE;
28c014
 
28c014
         *destination = source;
28c014
         return TRUE;
28c014
 }
28c014
 
28c014
+static gboolean
28c014
+on_notify_period_elapsed (GsdAccountManager *manager)
28c014
+{
28c014
+        manager->priv->notify_period_timeout_id = 0;
28c014
+        fetch_password_expiration_policy (manager);
28c014
+        return G_SOURCE_REMOVE;
28c014
+}
28c014
+
28c014
+static void
28c014
+queue_periodic_timeout (GsdAccountManager *manager)
28c014
+{
28c014
+        if (manager->priv->notify_period_timeout_id != 0) {
28c014
+                g_source_remove (manager->priv->notify_period_timeout_id);
28c014
+                manager->priv->notify_period_timeout_id = 0;
28c014
+        }
28c014
+
28c014
+        if (manager->priv->notify_period > 0) {
28c014
+                gint64 already_elapsed_time;
28c014
+
28c014
+                already_elapsed_time = MAX (0, (g_get_monotonic_time () - manager->priv->last_notify_time) / G_USEC_PER_SEC);
28c014
+
28c014
+                manager->priv->notify_period_timeout_id = g_timeout_add_seconds (MAX (0, manager->priv->notify_period * 60 - already_elapsed_time),
28c014
+                                                                                 (GSourceFunc) on_notify_period_elapsed,
28c014
+                                                                                 manager);
28c014
+        }
28c014
+}
28c014
+
28c014
 static void
28c014
 on_got_password_expiration_policy (GsdAccountsUser *accounts_user_proxy,
28c014
                                    GAsyncResult    *res,
28c014
                                    gpointer         user_data)
28c014
 {
28c014
         GsdAccountManager *manager = user_data;
28c014
         g_autoptr(GError)  error = NULL;
28c014
         gboolean           succeeded;
28c014
         gint64             expiration_time;
28c014
         gint64             last_change_time;
28c014
         gint64             min_days_between_changes;
28c014
         gint64             max_days_between_changes;
28c014
         gint64             days_to_warn;
28c014
         gint64             days_after_expiration_until_lock;
28c014
 
28c014
         gnome_settings_profile_start (NULL);
28c014
         succeeded = gsd_accounts_user_call_get_password_expiration_policy_finish (accounts_user_proxy,
28c014
                                                                                   &expiration_time,
28c014
                                                                                   &last_change_time,
28c014
                                                                                   &min_days_between_changes,
28c014
                                                                                   &max_days_between_changes,
28c014
                                                                                   &days_to_warn,
28c014
                                                                                   &days_after_expiration_until_lock,
28c014
                                                                                   res,
28c014
                                                                                   &error);
28c014
 
28c014
         if (!succeeded) {
28c014
                 g_warning ("Failed to get password expiration policy for user: %s", error->message);
28c014
                 goto out;
28c014
         }
28c014
 
28c014
         set_policy_number (&manager->priv->expiration_time, expiration_time);
28c014
         set_policy_number (&manager->priv->last_change_time, last_change_time);
28c014
         set_policy_number (&manager->priv->min_days_between_changes, min_days_between_changes);
28c014
         set_policy_number (&manager->priv->max_days_between_changes, max_days_between_changes);
28c014
         set_policy_number (&manager->priv->days_to_warn, days_to_warn);
28c014
         set_policy_number (&manager->priv->days_after_expiration_until_lock, days_after_expiration_until_lock);
28c014
 
28c014
         update_password_notification (manager);
28c014
+        queue_periodic_timeout (manager);
28c014
 out:
28c014
         gnome_settings_profile_end (NULL);
28c014
 }
28c014
 
28c014
 static void
28c014
 fetch_password_expiration_policy (GsdAccountManager *manager)
28c014
 {
28c014
         gsd_accounts_user_call_get_password_expiration_policy (manager->priv->accounts_user_proxy,
28c014
                                                                manager->priv->cancellable,
28c014
                                                                (GAsyncReadyCallback)
28c014
                                                                on_got_password_expiration_policy,
28c014
                                                                manager);
28c014
 }
28c014
 
28c014
 static void
28c014
 on_screensaver_signal (GDBusProxy  *proxy,
28c014
                        const gchar *sender_name,
28c014
                        const gchar *signal_name,
28c014
                        GVariant    *parameters,
28c014
                        gpointer     user_data)
28c014
 {
28c014
         GsdAccountManager *manager = user_data;
28c014
 
28c014
         if (g_strcmp0 (signal_name, "ActiveChanged") == 0) {
28c014
                 gboolean active;
28c014
 
28c014
                 g_variant_get (parameters, "(b)", &active);
28c014
 
28c014
                 if (!active) {
28c014
                         fetch_password_expiration_policy (manager);
28c014
@@ -346,91 +383,109 @@ on_got_user_object_path (GsdAccounts  *accounts_proxy,
28c014
                                      manager);
28c014
 
28c014
 out:
28c014
         gnome_settings_profile_end (NULL);
28c014
 }
28c014
 
28c014
 static void
28c014
 on_got_accounts_proxy (GObject      *source_object,
28c014
                        GAsyncResult *res,
28c014
                        gpointer      user_data)
28c014
 {
28c014
         GsdAccountManager *manager = user_data;
28c014
         g_autoptr(GError)  error = NULL;
28c014
 
28c014
         gnome_settings_profile_start (NULL);
28c014
         manager->priv->accounts_proxy = gsd_accounts_proxy_new_for_bus_finish (res, &error);
28c014
 
28c014
         if (manager->priv->accounts_proxy != NULL) {
28c014
                 gsd_accounts_call_find_user_by_id (manager->priv->accounts_proxy,
28c014
                                                    getuid (),
28c014
                                                    manager->priv->cancellable,
28c014
                                                    (GAsyncReadyCallback)
28c014
                                                    on_got_user_object_path,
28c014
                                                    manager);
28c014
         } else {
28c014
                 g_warning ("Failed to get proxy to accounts service: %s", error->message);
28c014
         }
28c014
         gnome_settings_profile_end (NULL);
28c014
 }
28c014
 
28c014
+static void
28c014
+on_notify_period_changed (GsdAccountManager *manager)
28c014
+{
28c014
+        manager->priv->notify_period = g_settings_get_int (manager->priv->settings, "notify-period");
28c014
+
28c014
+        queue_periodic_timeout (manager);
28c014
+}
28c014
+
28c014
 gboolean
28c014
 gsd_account_manager_start (GsdAccountManager  *manager,
28c014
                            GError            **error)
28c014
 {
28c014
         g_debug ("Starting accounts manager");
28c014
 
28c014
         gnome_settings_profile_start (NULL);
28c014
         manager->priv->cancellable = g_cancellable_new ();
28c014
+        manager->priv->settings = g_settings_new ("org.gnome.settings-daemon.plugins.account");
28c014
+
28c014
+        manager->priv->notify_period = g_settings_get_int (manager->priv->settings, "notify-period");
28c014
+        g_signal_connect_object (G_OBJECT (manager->priv->settings),
28c014
+                          "changed::notify-period",
28c014
+                          G_CALLBACK (on_notify_period_changed),
28c014
+                          manager,
28c014
+                          G_CONNECT_SWAPPED);
28c014
+
28c014
         gsd_accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
28c014
                                         G_DBUS_PROXY_FLAGS_NONE,
28c014
                                         "org.freedesktop.Accounts",
28c014
                                         "/org/freedesktop/Accounts",
28c014
                                         manager->priv->cancellable,
28c014
                                         (GAsyncReadyCallback)
28c014
                                         on_got_accounts_proxy,
28c014
                                         manager);
28c014
         gnome_settings_profile_end (NULL);
28c014
 
28c014
         return TRUE;
28c014
 }
28c014
 
28c014
 void
28c014
 gsd_account_manager_stop (GsdAccountManager *manager)
28c014
 {
28c014
         g_debug ("Stopping accounts manager");
28c014
 
28c014
         if (manager->priv->cancellable != NULL) {
28c014
                 g_cancellable_cancel (manager->priv->cancellable);
28c014
                 g_clear_object (&manager->priv->cancellable);
28c014
         }
28c014
 
28c014
+        g_clear_object (&manager->priv->settings);
28c014
         g_clear_object (&manager->priv->accounts_proxy);
28c014
         g_clear_object (&manager->priv->accounts_user_proxy);
28c014
         g_clear_object (&manager->priv->notification);
28c014
         g_clear_object (&manager->priv->screensaver_proxy);
28c014
 }
28c014
 
28c014
 static void
28c014
 gsd_account_manager_class_init (GsdAccountManagerClass *klass)
28c014
 {
28c014
         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
28c014
 
28c014
         object_class->finalize = gsd_account_manager_finalize;
28c014
 
28c014
         notify_init ("gnome-settings-daemon");
28c014
 
28c014
         g_type_class_add_private (klass, sizeof (GsdAccountManagerPrivate));
28c014
 }
28c014
 
28c014
 static void
28c014
 gsd_account_manager_init (GsdAccountManager *manager)
28c014
 {
28c014
         manager->priv = GSD_ACCOUNT_MANAGER_GET_PRIVATE (manager);
28c014
 }
28c014
 
28c014
 static void
28c014
 gsd_account_manager_finalize (GObject *object)
28c014
 {
28c014
         GsdAccountManager *manager;
28c014
 
28c014
         g_return_if_fail (object != NULL);
28c014
-- 
28c014
2.21.0
28c014