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

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