commit 1da3edcffc63835c95769d3b2d12909b76672b9b Author: Toshaan Bharvani Date: Mon May 23 00:44:46 2022 +0200 inital package creation Signed-off-by: Toshaan Bharvani diff --git a/SOURCES/0001-power-Enable-power-saver-profile-when-low-on-battery.patch b/SOURCES/0001-power-Enable-power-saver-profile-when-low-on-battery.patch new file mode 100644 index 0000000..2092fec --- /dev/null +++ b/SOURCES/0001-power-Enable-power-saver-profile-when-low-on-battery.patch @@ -0,0 +1,458 @@ +From 8dd4c164f6ce166a5767588bd6fb8e4c3e8e1a09 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Fri, 16 Jul 2021 13:40:10 +0200 +Subject: [PATCH 1/4] power: Enable power-saver profile when low on battery + +When low on battery, and if the feature is enabled, hold the power +profile to "power-saver" until the battery is sufficiently recharged. +--- + ...ttings-daemon.plugins.power.gschema.xml.in | 5 + + plugins/power/gsd-power-manager.c | 128 ++++++++++++++++++ + plugins/power/test.py | 32 +++++ + 3 files changed, 165 insertions(+) + +diff --git a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in +index 93c704e9..04b287bd 100644 +--- a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in ++++ b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in +@@ -41,5 +41,10 @@ + Power button action + The action to take when the system power button is pressed. This action is hard-coded (and the setting ignored) on virtual machines (power off) and tablets (suspend). + ++ ++ true ++ Enable power-saver profile when battery is low ++ Automatically enable the "power-saver" profile using power-profiles-daemon if the battery is low. ++ + + +diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c +index 95cec9c3..1f125a6f 100644 +--- a/plugins/power/gsd-power-manager.c ++++ b/plugins/power/gsd-power-manager.c +@@ -59,6 +59,10 @@ + #define UPOWER_DBUS_INTERFACE "org.freedesktop.UPower" + #define UPOWER_DBUS_INTERFACE_KBDBACKLIGHT "org.freedesktop.UPower.KbdBacklight" + ++#define PPD_DBUS_NAME "net.hadess.PowerProfiles" ++#define PPD_DBUS_PATH "/net/hadess/PowerProfiles" ++#define PPD_DBUS_INTERFACE "net.hadess.PowerProfiles" ++ + #define GSD_POWER_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.power" + + #define GSD_POWER_DBUS_NAME GSD_DBUS_NAME ".Power" +@@ -185,6 +189,10 @@ struct _GsdPowerManager + gdouble ambient_last_absolute; + gint64 ambient_last_time; + ++ /* Power Profiles */ ++ GDBusProxy *power_profiles_proxy; ++ guint32 power_saver_cookie; ++ + /* Sound */ + guint32 critical_alert_timeout_id; + +@@ -1927,6 +1935,67 @@ idle_configure (GsdPowerManager *manager) + } + } + ++static void ++hold_profile_cb (GObject *source_object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ GsdPowerManager *manager = user_data; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GVariant) result = NULL; ++ ++ result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), ++ res, ++ &error); ++ if (result == NULL) { ++ g_warning ("Couldn't hold power-saver profile: %s", error->message); ++ return; ++ } ++ ++ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(u)"))) { ++ g_variant_get (result, "(u)", &manager->power_saver_cookie); ++ g_debug ("Holding power-saver profile with cookie %u", manager->power_saver_cookie); ++ } else { ++ g_warning ("Calling HoldProfile() did not return a uint32"); ++ } ++} ++ ++static void ++enable_power_saver (GsdPowerManager *manager) ++{ ++ if (!manager->power_profiles_proxy) ++ return; ++ if (!g_settings_get_boolean (manager->settings, "power-saver-profile-on-low-battery")) ++ return; ++ ++ g_debug ("Starting hold of power-saver profile"); ++ ++ g_dbus_proxy_call (manager->power_profiles_proxy, ++ "HoldProfile", ++ g_variant_new("(sss)", ++ "power-saver", ++ "Power saver profile when low on battery", ++ GSD_POWER_DBUS_NAME), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, manager->cancellable, hold_profile_cb, manager); ++} ++ ++static void ++disable_power_saver (GsdPowerManager *manager) ++{ ++ if (!manager->power_profiles_proxy || manager->power_saver_cookie == 0) ++ return; ++ ++ g_debug ("Releasing power-saver profile"); ++ ++ g_dbus_proxy_call (manager->power_profiles_proxy, ++ "ReleaseProfile", ++ g_variant_new ("(u)", manager->power_saver_cookie), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, dbus_call_log_error, "ReleaseProfile failed"); ++ manager->power_saver_cookie = 0; ++} ++ + static void + main_battery_or_ups_low_changed (GsdPowerManager *manager, + gboolean is_low) +@@ -1935,6 +2004,10 @@ main_battery_or_ups_low_changed (GsdPowerManager *manager, + return; + manager->battery_is_low = is_low; + idle_configure (manager); ++ if (is_low) ++ enable_power_saver (manager); ++ else ++ disable_power_saver (manager); + } + + static gboolean +@@ -2078,6 +2151,39 @@ screensaver_signal_cb (GDBusProxy *proxy, + handle_wake_up_screen (GSD_POWER_MANAGER (user_data)); + } + ++static void ++power_profiles_proxy_signal_cb (GDBusProxy *proxy, ++ const gchar *sender_name, ++ const gchar *signal_name, ++ GVariant *parameters, ++ gpointer user_data) ++{ ++ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data); ++ ++ if (g_strcmp0 (signal_name, "ProfileReleased") != 0) ++ return; ++ manager->power_saver_cookie = 0; ++} ++ ++static void ++power_profiles_proxy_ready_cb (GObject *source_object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ g_autoptr(GError) error = NULL; ++ GsdPowerManager *manager = GSD_POWER_MANAGER (user_data); ++ ++ manager->power_profiles_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); ++ if (manager->power_profiles_proxy == NULL) { ++ g_debug ("Could not connect to power-profiles-daemon: %s", error->message); ++ return; ++ } ++ ++ g_signal_connect (manager->power_profiles_proxy, "g-signal", ++ G_CALLBACK (power_profiles_proxy_signal_cb), ++ manager); ++} ++ + static void + power_keyboard_proxy_ready_cb (GObject *source_object, + GAsyncResult *res, +@@ -2289,6 +2395,14 @@ engine_settings_key_changed_cb (GSettings *settings, + idle_configure (manager); + return; + } ++ if (g_str_equal (key, "power-saver-profile-on-low-battery")) { ++ if (manager->battery_is_low && ++ g_settings_get_boolean (settings, key)) ++ enable_power_saver (manager); ++ else ++ disable_power_saver (manager); ++ return; ++ } + } + + static void +@@ -2599,6 +2713,17 @@ on_rr_screen_acquired (GObject *object, + g_signal_connect (manager->up_client, "notify::on-battery", + G_CALLBACK (up_client_on_battery_cb), manager); + ++ /* connect to power-profiles-daemon */ ++ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_NONE, ++ NULL, ++ PPD_DBUS_NAME, ++ PPD_DBUS_PATH, ++ PPD_DBUS_INTERFACE, ++ manager->cancellable, ++ power_profiles_proxy_ready_cb, ++ manager); ++ + /* connect to UPower for keyboard backlight control */ + manager->kbd_brightness_now = -1; + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, +@@ -2862,6 +2987,9 @@ gsd_power_manager_stop (GsdPowerManager *manager) + + g_clear_object (&manager->screensaver_proxy); + ++ disable_power_saver (manager); ++ g_clear_object (&manager->power_profiles_proxy); ++ + play_loop_stop (&manager->critical_alert_timeout_id); + + g_clear_object (&manager->idle_monitor); +diff --git a/plugins/power/test.py b/plugins/power/test.py +index bb5861a4..f554400e 100755 +--- a/plugins/power/test.py ++++ b/plugins/power/test.py +@@ -76,6 +76,13 @@ class PowerPluginBase(gsdtestcase.GSDTestCase): + 'gnome_screensaver', stdout=subprocess.PIPE) + gsdtestcase.set_nonblock(self.screensaver.stdout) + ++ # start mock power-profiles-daemon ++ try: ++ (self.ppd, self.obj_ppd) = self.spawn_server_template('power_profiles_daemon') ++ self.addCleanup(self.stop_process, self.ppd) ++ except ModuleNotFoundError: ++ self.ppd = None ++ + self.session_log = OutputChecker() + self.session = subprocess.Popen(['gnome-session', '-f', + '-a', os.path.join(self.workdir, 'autostart'), +@@ -1302,5 +1309,30 @@ class PowerPluginTest8(PowerPluginBase): + + self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!') + ++ def test_power_saver_on_low_battery(self): ++ '''Check that the power-saver profile gets held when low on battery''' ++ ++ if not self.ppd: ++ self.skipTest("power-profiles-daemon dbusmock support is not available") ++ ++ obj_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE) ++ ++ self.set_composite_battery_discharging() ++ time.sleep(0.5) ++ holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds') ++ self.assertEqual(len(holds), 0) ++ ++ self.set_composite_battery_critical() ++ time.sleep(0.5) ++ holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds') ++ self.assertEqual(len(holds), 1) ++ self.assertEqual(holds[0]['Profile'], 'power-saver') ++ self.assertEqual(holds[0]['ApplicationId'], 'org.gnome.SettingsDaemon.Power') ++ ++ self.set_composite_battery_discharging() ++ time.sleep(0.5) ++ holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds') ++ self.assertEqual(len(holds), 0) ++ + # avoid writing to stderr + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) +-- +2.31.1 + + +From 74ed476d1a37a43eeba8c8bee8f5be5d499b0805 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Wed, 28 Jul 2021 16:40:24 +0200 +Subject: [PATCH 2/4] power: Dim screen faster if power saver mode is on + +As done on other platforms, aggressively dim the screen after a +short period when the user has selected to enter power saver mode. + +The same aggressive screen dim will be used if the battery is low and +power-profiles-daemon is not available. If it is available, then it +fixes a screen dim happening when the battery was low which might +have been unwanted. + +See https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/232 + +Prior art: +https://support.apple.com/en-us/HT205234 +--- + plugins/power/gsd-power-manager.c | 46 +++++++++++++++++++++++++++++-- + 1 file changed, 44 insertions(+), 2 deletions(-) + +diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c +index 1f125a6f..cfef9718 100644 +--- a/plugins/power/gsd-power-manager.c ++++ b/plugins/power/gsd-power-manager.c +@@ -192,6 +192,7 @@ struct _GsdPowerManager + /* Power Profiles */ + GDBusProxy *power_profiles_proxy; + guint32 power_saver_cookie; ++ gboolean power_saver_enabled; + + /* Sound */ + guint32 critical_alert_timeout_id; +@@ -1780,6 +1781,20 @@ clear_idle_watch (GnomeIdleMonitor *monitor, + *id = 0; + } + ++static gboolean ++is_power_save_active (GsdPowerManager *manager) ++{ ++ /* ++ * If we have power-profiles-daemon, then we follow its setting, ++ * otherwise we go into power-save mode when the battery is low. ++ */ ++ if (manager->power_profiles_proxy && ++ g_dbus_proxy_get_name_owner (manager->power_profiles_proxy)) ++ return manager->power_saver_enabled; ++ else ++ return manager->battery_is_low; ++} ++ + static void + idle_configure (GsdPowerManager *manager) + { +@@ -1903,8 +1918,8 @@ idle_configure (GsdPowerManager *manager) + /* Don't dim when the screen lock is active */ + } else if (!on_battery) { + /* Don't dim when charging */ +- } else if (manager->battery_is_low) { +- /* Aggressively blank when battery is low */ ++ } else if (is_power_save_active (manager)) { ++ /* Try to save power by dimming agressively */ + timeout_dim = SCREENSAVER_TIMEOUT_BLANK; + } else { + if (g_settings_get_boolean (manager->settings, "idle-dim")) { +@@ -2165,6 +2180,27 @@ power_profiles_proxy_signal_cb (GDBusProxy *proxy, + manager->power_saver_cookie = 0; + } + ++static void ++update_active_power_profile (GsdPowerManager *manager) ++{ ++ g_autoptr(GVariant) v = NULL; ++ const char *active_profile; ++ gboolean power_saver_enabled; ++ ++ v = g_dbus_proxy_get_cached_property (manager->power_profiles_proxy, "ActiveProfile"); ++ if (v) { ++ active_profile = g_variant_get_string (v, NULL); ++ power_saver_enabled = g_strcmp0 (active_profile, "power-saver") == 0; ++ if (power_saver_enabled != manager->power_saver_enabled) { ++ manager->power_saver_enabled = power_saver_enabled; ++ idle_configure (manager); ++ } ++ } else { ++ /* p-p-d might have disappeared from the bus */ ++ idle_configure (manager); ++ } ++} ++ + static void + power_profiles_proxy_ready_cb (GObject *source_object, + GAsyncResult *res, +@@ -2179,9 +2215,15 @@ power_profiles_proxy_ready_cb (GObject *source_object, + return; + } + ++ g_signal_connect_swapped (manager->power_profiles_proxy, ++ "g-properties-changed", ++ G_CALLBACK (update_active_power_profile), ++ manager); + g_signal_connect (manager->power_profiles_proxy, "g-signal", + G_CALLBACK (power_profiles_proxy_signal_cb), + manager); ++ ++ update_active_power_profile (manager); + } + + static void +-- +2.31.1 + + +From 89e25ed7871258aa6df7f824e226a7b8a28f23f3 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Thu, 29 Jul 2021 12:05:40 +0200 +Subject: [PATCH 3/4] power: Respect dim screen settings when not on battery + +The dim screen settings in the UI was not well respected as it only +worked on discharging laptops. + +Closes: https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/837 +--- + plugins/power/gsd-power-manager.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c +index cfef9718..e7b9752f 100644 +--- a/plugins/power/gsd-power-manager.c ++++ b/plugins/power/gsd-power-manager.c +@@ -1916,8 +1916,6 @@ idle_configure (GsdPowerManager *manager) + timeout_dim = 0; + if (manager->screensaver_active) { + /* Don't dim when the screen lock is active */ +- } else if (!on_battery) { +- /* Don't dim when charging */ + } else if (is_power_save_active (manager)) { + /* Try to save power by dimming agressively */ + timeout_dim = SCREENSAVER_TIMEOUT_BLANK; +-- +2.31.1 + + +From f91abc0033b9cf17fd0e171cb7d652f88edac294 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Mon, 9 Aug 2021 17:57:11 +0200 +Subject: [PATCH 4/4] power: When dimming the screen, dim it quicker by default + +Now that we respect the "dim when idle" setting[1], dim quicker to try +and save more power. 4/5 of the timeout to the screensaver was always a +bit too undecided as a fraction, even when using the dimming as a +warning that the screen was going to go to the screensaver (see commit +7bc750a5). + +[1]: Except in power-saver mode where we always dim aggressively +--- + plugins/power/gsd-power-constants.h | 2 +- + plugins/power/gsdpowerconstants.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/plugins/power/gsd-power-constants.h b/plugins/power/gsd-power-constants.h +index 91e2296a..8bf9c641 100644 +--- a/plugins/power/gsd-power-constants.h ++++ b/plugins/power/gsd-power-constants.h +@@ -25,7 +25,7 @@ + #define IDLE_DIM_BLANK_DISABLED_MIN 60 /* seconds */ + + /* Which fraction of the idle-delay is the idle-dim delay */ +-#define IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER 4.0/5.0 ++#define IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER 1.0/2.0 + + /* The dim delay under which we do not bother dimming */ + #define MINIMUM_IDLE_DIM_DELAY 10 /* seconds */ +diff --git a/plugins/power/gsdpowerconstants.py b/plugins/power/gsdpowerconstants.py +index a07798ee..26fa5bfc 100644 +--- a/plugins/power/gsdpowerconstants.py ++++ b/plugins/power/gsdpowerconstants.py +@@ -8,7 +8,7 @@ + + SCREENSAVER_TIMEOUT_BLANK = 15; + IDLE_DIM_BLANK_DISABLED_MIN = 60; +-IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER = 4.0/5.0; ++IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER = 1.0/2.0; + MINIMUM_IDLE_DIM_DELAY = 10; + POWER_UP_TIME_ON_AC = 15; + GSD_MOCK_DEFAULT_BRIGHTNESS = 50; +-- +2.31.1 + diff --git a/SOURCES/org.gnome.settings-daemon.plugins.power.gschema.override b/SOURCES/org.gnome.settings-daemon.plugins.power.gschema.override new file mode 100644 index 0000000..c6b28c1 --- /dev/null +++ b/SOURCES/org.gnome.settings-daemon.plugins.power.gschema.override @@ -0,0 +1,2 @@ +[org.gnome.settings-daemon.plugins.power] +sleep-inactive-ac-timeout=0 diff --git a/SOURCES/subscription-manager-support.patch b/SOURCES/subscription-manager-support.patch new file mode 100644 index 0000000..5624f0a --- /dev/null +++ b/SOURCES/subscription-manager-support.patch @@ -0,0 +1,3575 @@ +From d85d6eb0ceeaabc65f71ec9b163d00a1e0840b81 Mon Sep 17 00:00:00 2001 +From: Richard Hughes +Date: Thu, 20 Aug 2020 11:16:09 -0400 +Subject: [PATCH 01/19] subman: Add a new plugin to provide system subscription + registration + +--- + meson.build | 1 + + plugins/meson.build | 1 + + plugins/subman/README.md | 56 + + plugins/subman/gsd-subman-common.c | 36 + + plugins/subman/gsd-subman-common.h | 40 + + plugins/subman/gsd-subman-helper.c | 378 +++++++ + plugins/subman/gsd-subscription-manager.c | 982 ++++++++++++++++++ + plugins/subman/gsd-subscription-manager.h | 63 ++ + plugins/subman/main.c | 8 + + plugins/subman/meson.build | 56 + + ...ome.SettingsDaemon.Subscription.desktop.in | 9 + + ...ettings-daemon.plugins.subman.policy.in.in | 27 + + ...gnome.settings-daemon.plugins.subman.rules | 7 + + 13 files changed, 1664 insertions(+) + create mode 100644 plugins/subman/README.md + create mode 100644 plugins/subman/gsd-subman-common.c + create mode 100644 plugins/subman/gsd-subman-common.h + create mode 100644 plugins/subman/gsd-subman-helper.c + create mode 100644 plugins/subman/gsd-subscription-manager.c + create mode 100644 plugins/subman/gsd-subscription-manager.h + create mode 100644 plugins/subman/main.c + create mode 100644 plugins/subman/meson.build + create mode 100644 plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in + create mode 100644 plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in + create mode 100644 plugins/subman/org.gnome.settings-daemon.plugins.subman.rules + +diff --git a/meson.build b/meson.build +index ba2a90ca..3cef1ae1 100644 +--- a/meson.build ++++ b/meson.build +@@ -102,6 +102,7 @@ libcanberra_gtk_dep = dependency('libcanberra-gtk3') + libgeoclue_dep = dependency('libgeoclue-2.0', version: '>= 2.3.1') + libnotify_dep = dependency('libnotify', version: '>= 0.7.3') + libpulse_mainloop_glib_dep = dependency('libpulse-mainloop-glib', version: '>= 2.0') ++jsonglib_dep = dependency('json-glib-1.0', version: '>= 1.1.1') + pango_dep = dependency('pango', version: '>= 1.20.0') + polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114') + upower_glib_dep = dependency('upower-glib', version: '>= 0.99.8') +diff --git a/plugins/meson.build b/plugins/meson.build +index 16397dc6..920b5cc9 100644 +--- a/plugins/meson.build ++++ b/plugins/meson.build +@@ -1,6 +1,7 @@ + all_plugins = [ + ['a11y-settings', 'A11ySettings', 'GNOME accessibility'], + ['color', 'Color', 'GNOME color management'], ++ ['subman', 'Subscription', 'GNOME subscription management'], + ['datetime', 'Datetime', 'GNOME date & time'], + ['power', 'Power', 'GNOME power management'], + ['housekeeping', 'Housekeeping', 'GNOME maintenance of expirable data'], +diff --git a/plugins/subman/README.md b/plugins/subman/README.md +new file mode 100644 +index 00000000..3e1cc3cd +--- /dev/null ++++ b/plugins/subman/README.md +@@ -0,0 +1,56 @@ ++GNOME Settings Daemon: Subscription Manager Plugin ++================================================== ++ ++Testing: ++ ++To add a test acccount on subscription.rhsm.stage.redhat.com, use Ethel: ++http://account-manager-stage.app.eng.rdu2.redhat.com/#view ++ ++Register with a username and password ++------------------------------------- ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'username'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'username':<'rhughes_test'>,'password':<'barbaz'>}" ++ ++To register with a certificate ++------------------------------ ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'key'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'organisation':<'foo'>,'activation-key':<'barbaz'>}" ++ ++To unregister ++------------- ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Unregister ++ ++Debugging ++--------- ++ ++Get the UNIX socket using `Subscription.Register` then call something like: ++ ++ sudo G_MESSAGES_DEBUG=all ./plugins/subman/gsd-subman-helper \ ++ --address="unix:abstract=/var/run/dbus-ulGB1wfnbn,guid=71e6bf329d861ce366df7a1d5d036a5b" \ ++ --kind="register-with-username" \ ++ --username="rhughes_test" \ ++ --password="barbaz" \ ++ --hostname="subscription.rhsm.stage.redhat.com" \ ++ --organisation="" ++ ++You can all see some basic debugging running `rhsmd` in the foreground: ++ ++ sudo /usr/libexec/rhsmd -d -k ++ ++Known Limitations ++================= ++ ++Proxy servers are not supported, nor are custom host ports or prefixes. +diff --git a/plugins/subman/gsd-subman-common.c b/plugins/subman/gsd-subman-common.c +new file mode 100644 +index 00000000..e515131e +--- /dev/null ++++ b/plugins/subman/gsd-subman-common.c +@@ -0,0 +1,36 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2019 Richard Hughes ++ * ++ * 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 of the License, 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 . ++ * ++ */ ++ ++#include "config.h" ++ ++#include "gsd-subman-common.h" ++ ++const gchar * ++gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status) ++{ ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID) ++ return "valid"; ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID) ++ return "invalid"; ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED) ++ return "disabled"; ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID) ++ return "partially-valid"; ++ return "unknown"; ++} +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +new file mode 100644 +index 00000000..fccf9f6a +--- /dev/null ++++ b/plugins/subman/gsd-subman-common.h +@@ -0,0 +1,40 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2019 Richard Hughes ++ * ++ * 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 of the License, 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 . ++ * ++ */ ++ ++#ifndef __GSD_SUBMAN_COMMON_H ++#define __GSD_SUBMAN_COMMON_H ++ ++#include ++ ++G_BEGIN_DECLS ++ ++typedef enum { ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST ++} GsdSubmanSubscriptionStatus; ++ ++const gchar *gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status); ++ ++G_END_DECLS ++ ++#endif /* __GSD_SUBMAN_COMMON_H */ +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +new file mode 100644 +index 00000000..182f7190 +--- /dev/null ++++ b/plugins/subman/gsd-subman-helper.c +@@ -0,0 +1,372 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2019 Richard Hughes ++ * ++ * Licensed under the GNU General Public License Version 2 ++ * ++ * 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 of the License, 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++static void ++_helper_convert_error (const gchar *json_txt, GError **error) ++{ ++ JsonNode *json_root; ++ JsonObject *json_obj; ++ const gchar *message; ++ g_autoptr(JsonParser) json_parser = json_parser_new (); ++ ++ /* this may be plain text or JSON :| */ ++ if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) { ++ g_set_error_literal (error, ++ G_IO_ERROR, ++ G_IO_ERROR_NOT_SUPPORTED, ++ json_txt); ++ return; ++ } ++ json_root = json_parser_get_root (json_parser); ++ json_obj = json_node_get_object (json_root); ++ if (!json_object_has_member (json_obj, "message")) { ++ g_set_error (error, ++ G_IO_ERROR, ++ G_IO_ERROR_INVALID_DATA, ++ "no message' in %s", json_txt); ++ return; ++ } ++ message = json_object_get_string_member (json_obj, "message"); ++ if (g_strstr_len (message, -1, "Invalid user credentials") != NULL) { ++ g_set_error_literal (error, ++ G_IO_ERROR, ++ G_IO_ERROR_PERMISSION_DENIED, ++ message); ++ return; ++ } ++ g_set_error_literal (error, ++ G_IO_ERROR, ++ G_IO_ERROR_NOT_SUPPORTED, ++ message); ++} ++ ++static gboolean ++_helper_unregister (GError **error) ++{ ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GVariantBuilder) proxy_options = NULL; ++ g_autoptr(GVariant) res = NULL; ++ ++ g_debug ("unregistering"); ++ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | ++ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, ++ NULL, ++ "com.redhat.RHSM1", ++ "/com/redhat/RHSM1/Unregister", ++ "com.redhat.RHSM1.Unregister", ++ NULL, error); ++ if (proxy == NULL) { ++ g_prefix_error (error, "Failed to get proxy: "); ++ return FALSE; ++ } ++ proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); ++ res = g_dbus_proxy_call_sync (proxy, ++ "Unregister", ++ g_variant_new ("(a{sv}s)", ++ proxy_options, ++ ""), /* lang */ ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ return res != NULL; ++} ++ ++static gboolean ++_helper_auto_attach (GError **error) ++{ ++ const gchar *str = NULL; ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GVariantBuilder) proxy_options = NULL; ++ g_autoptr(GVariant) res = NULL; ++ ++ g_debug ("auto-attaching subscriptions"); ++ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | ++ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, ++ NULL, ++ "com.redhat.RHSM1", ++ "/com/redhat/RHSM1/Attach", ++ "com.redhat.RHSM1.Attach", ++ NULL, error); ++ if (proxy == NULL) { ++ g_prefix_error (error, "Failed to get proxy: "); ++ return FALSE; ++ } ++ proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); ++ res = g_dbus_proxy_call_sync (proxy, ++ "AutoAttach", ++ g_variant_new ("(sa{sv}s)", ++ "", /* now? */ ++ proxy_options, ++ ""), /* lang */ ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (res == NULL) ++ return FALSE; ++ g_variant_get (res, "(&s)", &str); ++ g_debug ("Attach.AutoAttach: %s", str); ++ return TRUE; ++} ++ ++static gboolean ++_helper_save_config (const gchar *key, const gchar *value, GError **error) ++{ ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GVariant) res = NULL; ++ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | ++ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, ++ NULL, ++ "com.redhat.RHSM1", ++ "/com/redhat/RHSM1/Config", ++ "com.redhat.RHSM1.Config", ++ NULL, error); ++ if (proxy == NULL) { ++ g_prefix_error (error, "Failed to get proxy: "); ++ return FALSE; ++ } ++ res = g_dbus_proxy_call_sync (proxy, "Set", ++ g_variant_new ("(svs)", ++ key, ++ g_variant_new_string (value), ++ ""), /* lang */ ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ return res != NULL; ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ const gchar *userlang = ""; /* as root, so no translations */ ++ g_autofree gchar *activation_key = NULL; ++ g_autofree gchar *address = NULL; ++ g_autofree gchar *hostname = NULL; ++ g_autofree gchar *kind = NULL; ++ g_autofree gchar *organisation = NULL; ++ g_autofree gchar *password = NULL; ++ g_autofree gchar *port = NULL; ++ g_autofree gchar *prefix = NULL; ++ g_autofree gchar *proxy_server = NULL; ++ g_autofree gchar *username = NULL; ++ g_autoptr(GDBusConnection) conn_private = NULL; ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GOptionContext) context = g_option_context_new (NULL); ++ g_autoptr(GVariantBuilder) proxy_options = NULL; ++ g_autoptr(GVariantBuilder) subman_conopts = NULL; ++ g_autoptr(GVariantBuilder) subman_options = NULL; ++ ++ const GOptionEntry options[] = { ++ { "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &kind, "Kind, e.g. 'username' or 'key'", NULL }, ++ { "address", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &address, "UNIX address", NULL }, ++ { "username", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &username, "Username", NULL }, ++ { "password", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &password, "Password", NULL }, ++ { "organisation", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &organisation, "Organisation", NULL }, ++ { "activation-key", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, ++ &activation_key, "Activation keys", NULL }, ++ { "hostname", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, ++ &hostname, "Registration server hostname", NULL }, ++ { "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, ++ &prefix, "Registration server prefix", NULL }, ++ { "port", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, ++ &port, "Registration server port", NULL }, ++ { "proxy", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, ++ &proxy_server, "Proxy settings", NULL }, ++ { NULL} ++ }; ++ ++ /* check calling UID */ ++ if (getuid () != 0 || geteuid () != 0) { ++ g_printerr ("This program can only be used by the root user\n"); ++ return G_IO_ERROR_NOT_SUPPORTED; ++ } ++ g_option_context_add_main_entries (context, options, NULL); ++ if (!g_option_context_parse (context, &argc, &argv, &error)) { ++ g_printerr ("Failed to parse arguments: %s\n", error->message); ++ return G_IO_ERROR_NOT_SUPPORTED; ++ } ++ ++ /* uncommon actions */ ++ if (kind == NULL) { ++ g_printerr ("No --kind specified\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ if (g_strcmp0 (kind, "unregister") == 0) { ++ if (!_helper_unregister (&error)) { ++ g_printerr ("Failed to Unregister: %s\n", error->message); ++ return G_IO_ERROR_NOT_INITIALIZED; ++ } ++ return EXIT_SUCCESS; ++ } ++ if (g_strcmp0 (kind, "auto-attach") == 0) { ++ if (!_helper_auto_attach (&error)) { ++ g_printerr ("Failed to AutoAttach: %s\n", error->message); ++ return G_IO_ERROR_NOT_INITIALIZED; ++ } ++ return EXIT_SUCCESS; ++ } ++ ++ /* connect to abstract socket for reasons */ ++ if (address == NULL) { ++ g_printerr ("No --address specified\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ conn_private = g_dbus_connection_new_for_address_sync (address, ++ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, ++ NULL, NULL, ++ &error); ++ if (conn_private == NULL) { ++ g_printerr ("Invalid --address specified: %s\n", error->message); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ proxy = g_dbus_proxy_new_sync (conn_private, ++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, ++ NULL, /* GDBusInterfaceInfo */ ++ NULL, /* name */ ++ "/com/redhat/RHSM1/Register", ++ "com.redhat.RHSM1.Register", ++ NULL, &error); ++ if (proxy == NULL) { ++ g_printerr ("Count not contact RHSM: %s\n", error->message); ++ return G_IO_ERROR_NOT_FOUND; ++ } ++ ++ /* enable_content=1 auto attaches the subscription */ ++ subman_options = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); ++ ++ g_variant_builder_add (subman_options, "{ss}", "enable_content", "1"); ++ ++ /* set registration server */ ++ if (hostname == NULL || hostname[0] == '\0') ++ hostname = g_strdup ("subscription.rhsm.redhat.com"); ++ if (prefix == NULL || prefix[0] == '\0') ++ prefix = g_strdup ("/subscription"); ++ if (port == NULL || port[0] == '\0') ++ port = g_strdup ("443"); ++ subman_conopts = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); ++ g_variant_builder_add (subman_conopts, "{ss}", "host", hostname); ++ g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix); ++ g_variant_builder_add (subman_conopts, "{ss}", "port", port); ++ ++ /* call into RHSM */ ++ if (g_strcmp0 (kind, "register-with-key") == 0) { ++ g_auto(GStrv) activation_keys = NULL; ++ g_autoptr(GError) error_local = NULL; ++ g_autoptr(GVariant) res = NULL; ++ ++ if (activation_key == NULL) { ++ g_printerr ("Required --activation-key\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ if (organisation == NULL) { ++ g_printerr ("Required --organisation\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ ++ g_debug ("registering using activation key"); ++ activation_keys = g_strsplit (activation_key, ",", -1); ++ res = g_dbus_proxy_call_sync (proxy, ++ "RegisterWithActivationKeys", ++ g_variant_new ("(s^asa{ss}a{ss}s)", ++ organisation, ++ activation_keys, ++ subman_options, ++ subman_conopts, ++ userlang), ++ G_DBUS_CALL_FLAGS_NO_AUTO_START, ++ -1, NULL, &error_local); ++ if (res == NULL) { ++ g_dbus_error_strip_remote_error (error_local); ++ _helper_convert_error (error_local->message, &error); ++ g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); ++ return error->code; ++ } ++ } else if (g_strcmp0 (kind, "register-with-username") == 0) { ++ g_autoptr(GError) error_local = NULL; ++ g_autoptr(GVariant) res = NULL; ++ ++ g_debug ("registering using username and password"); ++ if (username == NULL) { ++ g_printerr ("Required --username\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ if (password == NULL) { ++ g_printerr ("Required --password\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ if (organisation == NULL) { ++ g_printerr ("Required --organisation\n"); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ res = g_dbus_proxy_call_sync (proxy, ++ "Register", ++ g_variant_new ("(sssa{ss}a{ss}s)", ++ organisation, ++ username, ++ password, ++ subman_options, ++ subman_conopts, ++ userlang), ++ G_DBUS_CALL_FLAGS_NO_AUTO_START, ++ -1, NULL, &error_local); ++ if (res == NULL) { ++ g_dbus_error_strip_remote_error (error_local); ++ _helper_convert_error (error_local->message, &error); ++ g_printerr ("Failed to Register: %s\n", error->message); ++ return error->code; ++ } ++ } else { ++ g_printerr ("Invalid --kind specified: %s\n", kind); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ ++ /* set the new hostname */ ++ if (!_helper_save_config ("server.hostname", hostname, &error)) { ++ g_printerr ("Failed to save hostname: %s\n", error->message); ++ return G_IO_ERROR_NOT_INITIALIZED; ++ } ++ if (!_helper_save_config ("server.prefix", prefix, &error)) { ++ g_printerr ("Failed to save prefix: %s\n", error->message); ++ return G_IO_ERROR_NOT_INITIALIZED; ++ } ++ if (!_helper_save_config ("server.port", port, &error)) { ++ g_printerr ("Failed to save port: %s\n", error->message); ++ return G_IO_ERROR_NOT_INITIALIZED; ++ } ++ ++ return EXIT_SUCCESS; ++} ++ +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +new file mode 100644 +index 00000000..08b13fa6 +--- /dev/null ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -0,0 +1,982 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2019 Richard Hughes ++ * ++ * 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 of the License, 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 . ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "gnome-settings-profile.h" ++#include "gsd-subman-common.h" ++#include "gsd-subscription-manager.h" ++ ++#define GSD_DBUS_NAME "org.gnome.SettingsDaemon" ++#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" ++#define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" ++ ++#define GSD_SUBSCRIPTION_DBUS_NAME GSD_DBUS_NAME ".Subscription" ++#define GSD_SUBSCRIPTION_DBUS_PATH GSD_DBUS_PATH "/Subscription" ++#define GSD_SUBSCRIPTION_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".Subscription" ++ ++static const gchar introspection_xml[] = ++"" ++" " ++" " ++" " ++" " ++" " ++" " ++" " ++""; ++ ++#define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate)) ++ ++typedef enum { ++ _RHSM_INTERFACE_CONFIG, ++ _RHSM_INTERFACE_REGISTER_SERVER, ++ _RHSM_INTERFACE_ATTACH, ++ _RHSM_INTERFACE_ENTITLEMENT, ++ _RHSM_INTERFACE_PRODUCTS, ++ _RHSM_INTERFACE_CONSUMER, ++ _RHSM_INTERFACE_SYSPURPOSE, ++ _RHSM_INTERFACE_LAST ++} _RhsmInterface; ++ ++struct GsdSubscriptionManagerPrivate ++{ ++ /* D-Bus */ ++ guint name_id; ++ GDBusNodeInfo *introspection_data; ++ GDBusConnection *connection; ++ GCancellable *bus_cancellable; ++ ++ GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; ++ const gchar *userlang; /* owned by GLib internally */ ++ GHashTable *config; /* str:str */ ++ gchar *address; ++ ++ GTimer *timer_last_notified; ++ NotifyNotification *notification_expired; ++ NotifyNotification *notification_registered; ++ NotifyNotification *notification_registration_required; ++ GsdSubmanSubscriptionStatus subscription_status; ++ GsdSubmanSubscriptionStatus subscription_status_last; ++}; ++ ++enum { ++ PROP_0, ++}; ++ ++static void gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass); ++static void gsd_subscription_manager_init (GsdSubscriptionManager *subscription_manager); ++static void gsd_subscription_manager_finalize (GObject *object); ++ ++G_DEFINE_TYPE (GsdSubscriptionManager, gsd_subscription_manager, G_TYPE_OBJECT) ++ ++static gpointer manager_object = NULL; ++ ++GQuark ++gsd_subscription_manager_error_quark (void) ++{ ++ static GQuark quark = 0; ++ if (!quark) ++ quark = g_quark_from_static_string ("gsd_subscription_manager_error"); ++ return quark; ++} ++ ++static GsdSubmanSubscriptionStatus ++_client_subscription_status_from_text (const gchar *status_txt) ++{ ++ if (g_strcmp0 (status_txt, "Unknown") == 0) ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++ if (g_strcmp0 (status_txt, "Current") == 0) ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; ++ if (g_strcmp0 (status_txt, "Invalid") == 0) ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ if (g_strcmp0 (status_txt, "Disabled") == 0) ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; ++ if (g_strcmp0 (status_txt, "Insufficient") == 0) ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; ++ g_warning ("Unknown subscription status: %s", status_txt); // 'Current'? ++ return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++} ++ ++static void ++_emit_property_changed (GsdSubscriptionManager *manager, ++ const gchar *property_name, ++ GVariant *property_value) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ GVariantBuilder builder; ++ GVariantBuilder invalidated_builder; ++ ++ /* not yet connected */ ++ if (priv->connection == NULL) ++ return; ++ ++ /* build the dict */ ++ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); ++ g_variant_builder_add (&builder, ++ "{sv}", ++ property_name, ++ property_value); ++ g_dbus_connection_emit_signal (priv->connection, ++ NULL, ++ GSD_SUBSCRIPTION_DBUS_PATH, ++ "org.freedesktop.DBus.Properties", ++ "PropertiesChanged", ++ g_variant_new ("(sa{sv}as)", ++ GSD_SUBSCRIPTION_DBUS_INTERFACE, ++ &builder, ++ &invalidated_builder), ++ NULL); ++ g_variant_builder_clear (&builder); ++ g_variant_builder_clear (&invalidated_builder); ++} ++ ++static gboolean ++_client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ JsonNode *json_root; ++ JsonObject *json_obj; ++ const gchar *json_txt = NULL; ++ const gchar *status_txt = NULL; ++ g_autoptr(GVariant) val = NULL; ++ g_autoptr(JsonParser) json_parser = json_parser_new (); ++ ++ /* save old value */ ++ priv->subscription_status_last = priv->subscription_status; ++ ++ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], ++ "GetStatus", ++ g_variant_new ("(ss)", ++ "", /* assumed as 'now' */ ++ priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_variant_get (val, "(&s)", &json_txt); ++ g_debug ("Entitlement.GetStatus JSON: %s", json_txt); ++ if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) ++ return FALSE; ++ json_root = json_parser_get_root (json_parser); ++ json_obj = json_node_get_object (json_root); ++ if (!json_object_has_member (json_obj, "status")) { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, ++ "no Entitlement.GetStatus status in %s", json_txt); ++ return FALSE; ++ } ++ ++ status_txt = json_object_get_string_member (json_obj, "status"); ++ g_debug ("Entitlement.GetStatus: %s", status_txt); ++ priv->subscription_status = _client_subscription_status_from_text (status_txt); ++ ++ /* emit notification for g-c-c */ ++ if (priv->subscription_status != priv->subscription_status_last) { ++ _emit_property_changed (manager, "SubscriptionStatus", ++ g_variant_new_uint32 (priv->subscription_status)); ++ } ++ ++ return TRUE; ++} ++ ++static gboolean ++_client_syspurpose_update (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ JsonNode *json_root; ++ JsonObject *json_obj; ++ const gchar *json_txt = NULL; ++ g_autoptr(GVariant) val = NULL; ++ g_autoptr(JsonParser) json_parser = json_parser_new (); ++ ++ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_SYSPURPOSE], ++ "GetSyspurpose", ++ g_variant_new ("(s)", priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_variant_get (val, "(&s)", &json_txt); ++ g_debug ("Syspurpose.GetSyspurpose JSON: %s", json_txt); ++ if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) ++ return FALSE; ++ json_root = json_parser_get_root (json_parser); ++ json_obj = json_node_get_object (json_root); ++ if (!json_object_has_member (json_obj, "status")) { ++ g_debug ("Syspurpose.GetSyspurpose: Unknown"); ++ return TRUE; ++ } ++ g_debug ("Syspurpose.GetSyspurpose: '%s", json_object_get_string_member (json_obj, "status")); ++ return TRUE; ++} ++ ++static gboolean ++_client_register_start (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ const gchar *address = NULL; ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GVariant) val = NULL; ++ ++ /* already started */ ++ if (priv->address != NULL) ++ return TRUE; ++ ++ /* apparently: "we can't send registration credentials over the regular ++ * system or session bus since those aren't really locked down..." */ ++ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_NONE, ++ NULL, ++ "com.redhat.RHSM1", ++ "/com/redhat/RHSM1/RegisterServer", ++ "com.redhat.RHSM1.RegisterServer", ++ NULL, error); ++ if (proxy == NULL) ++ return FALSE; ++ val = g_dbus_proxy_call_sync (proxy, "Start", ++ g_variant_new ("(s)", priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_variant_get (val, "(&s)", &address); ++ g_debug ("RegisterServer.Start: %s", address); ++ priv->address = g_strdup (address); ++ return TRUE; ++} ++ ++static gboolean ++_client_register_stop (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GDBusProxy) proxy = NULL; ++ g_autoptr(GVariant) val = NULL; ++ ++ /* already started */ ++ if (priv->address == NULL) ++ return TRUE; ++ ++ /* stop registration server */ ++ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_NONE, ++ NULL, ++ "com.redhat.RHSM1", ++ "/com/redhat/RHSM1/RegisterServer", ++ "com.redhat.RHSM1.RegisterServer", ++ NULL, error); ++ if (proxy == NULL) ++ return FALSE; ++ val = g_dbus_proxy_call_sync (proxy, "Stop", ++ g_variant_new ("(s)", priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_clear_pointer (&priv->address, g_free); ++ return TRUE; ++} ++ ++static gboolean ++_client_subprocess_wait_check (GSubprocess *subprocess, GError **error) ++{ ++ gint rc; ++ if (!g_subprocess_wait (subprocess, NULL, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); ++ return FALSE; ++ } ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ GInputStream *istream = g_subprocess_get_stderr_pipe (subprocess); ++ gchar buf[1024] = { 0x0 }; ++ gsize sz = 0; ++ g_input_stream_read_all (istream, buf, sizeof(buf) - 1, &sz, NULL, NULL); ++ if (sz == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ g_set_error_literal (error, G_IO_ERROR, rc, buf); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++typedef enum { ++ _NOTIFY_EXPIRED, ++ _NOTIFY_REGISTRATION_REQUIRED, ++ _NOTIFY_REGISTERED ++} _NotifyKind; ++ ++static void ++_show_notification (GsdSubscriptionManager *manager, _NotifyKind notify_kind) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ switch (notify_kind) { ++ case _NOTIFY_EXPIRED: ++ notify_notification_close (priv->notification_registered, NULL); ++ notify_notification_close (priv->notification_registration_required, NULL); ++ notify_notification_show (priv->notification_expired, NULL); ++ break; ++ case _NOTIFY_REGISTRATION_REQUIRED: ++ notify_notification_close (priv->notification_registered, NULL); ++ notify_notification_close (priv->notification_expired, NULL); ++ notify_notification_show (priv->notification_registration_required, NULL); ++ break; ++ case _NOTIFY_REGISTERED: ++ notify_notification_close (priv->notification_expired, NULL); ++ notify_notification_close (priv->notification_registration_required, NULL); ++ notify_notification_show (priv->notification_registered, NULL); ++ break; ++ default: ++ break; ++ } ++ g_timer_reset (priv->timer_last_notified); ++} ++ ++static void ++_client_maybe__show_notification (GsdSubscriptionManager *manager) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ ++ /* startup */ ++ if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && ++ priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ return; ++ } ++ ++ /* something changed */ ++ if (priv->subscription_status_last != priv->subscription_status) { ++ g_debug ("transisition from subscription status '%s' to '%s'", ++ gsd_subman_subscription_status_to_string (priv->subscription_status_last), ++ gsd_subman_subscription_status_to_string (priv->subscription_status)); ++ ++ /* needs registration */ ++ if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && ++ priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID) { ++ _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ return; ++ } ++ ++ /* was unregistered */ ++ if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && ++ priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ return; ++ } ++ ++ /* registered */ ++ if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && ++ priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && ++ g_timer_elapsed (priv->timer_last_notified, NULL) > 60) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } ++ } ++ ++ /* nag again */ ++ if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && ++ g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { ++ _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ return; ++ } ++ if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID && ++ g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { ++ _show_notification (manager, _NOTIFY_EXPIRED); ++ return; ++ } ++ if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID && ++ g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { ++ _show_notification (manager, _NOTIFY_EXPIRED); ++ return; ++ } ++} ++ ++static gboolean ++_client_register_with_keys (GsdSubscriptionManager *manager, ++ const gchar *hostname, ++ const gchar *organisation, ++ const gchar *activation_key, ++ GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GSubprocess) subprocess = NULL; ++ ++ /* apparently: "we can't send registration credentials over the regular ++ * system or session bus since those aren't really locked down..." */ ++ if (!_client_register_start (manager, error)) ++ return FALSE; ++ g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ "pkexec", LIBEXECDIR "/gsd-subman-helper", ++ "--kind", "register-with-key", ++ "--address", priv->address, ++ "--hostname", hostname, ++ "--organisation", organisation, ++ "--activation-key", activation_key, ++ NULL); ++ if (subprocess == NULL) { ++ g_prefix_error (error, "failed to find pkexec: "); ++ return FALSE; ++ } ++ if (!_client_subprocess_wait_check (subprocess, error)) ++ return FALSE; ++ ++ /* FIXME: also do on error? */ ++ if (!_client_register_stop (manager, error)) ++ return FALSE; ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ _client_maybe__show_notification (manager); ++ ++ /* success */ ++ return TRUE; ++} ++ ++static gboolean ++_client_register (GsdSubscriptionManager *manager, ++ const gchar *hostname, ++ const gchar *organisation, ++ const gchar *username, ++ const gchar *password, ++ GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GSubprocess) subprocess = NULL; ++ ++ /* fallback */ ++ if (organisation == NULL) ++ organisation = ""; ++ ++ /* apparently: "we can't send registration credentials over the regular ++ * system or session bus since those aren't really locked down..." */ ++ if (!_client_register_start (manager, error)) ++ return FALSE; ++ g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ "pkexec", LIBEXECDIR "/gsd-subman-helper", ++ "--kind", "register-with-username", ++ "--address", priv->address, ++ "--hostname", hostname, ++ "--organisation", organisation, ++ "--username", username, ++ "--password", password, ++ NULL); ++ if (subprocess == NULL) { ++ g_prefix_error (error, "failed to find pkexec: "); ++ return FALSE; ++ } ++ if (!_client_subprocess_wait_check (subprocess, error)) ++ return FALSE; ++ ++ /* FIXME: also do on error? */ ++ if (!_client_register_stop (manager, error)) ++ return FALSE; ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ _client_maybe__show_notification (manager); ++ return TRUE; ++} ++ ++static gboolean ++_client_unregister (GsdSubscriptionManager *manager, GError **error) ++{ ++ g_autoptr(GSubprocess) subprocess = NULL; ++ ++ /* apparently: "we can't send registration credentials over the regular ++ * system or session bus since those aren't really locked down..." */ ++ if (!_client_register_start (manager, error)) ++ return FALSE; ++ g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ "pkexec", LIBEXECDIR "/gsd-subman-helper", ++ "--kind", "unregister", ++ NULL); ++ if (subprocess == NULL) { ++ g_prefix_error (error, "failed to find pkexec: "); ++ return FALSE; ++ } ++ if (!_client_subprocess_wait_check (subprocess, error)) ++ return FALSE; ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ _client_maybe__show_notification (manager); ++ return TRUE; ++} ++ ++static gboolean ++_client_update_config (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GVariant) val = NULL; ++ g_autoptr(GVariant) val_server = NULL; ++ g_autoptr(GVariantDict) dict = NULL; ++ GVariantIter iter; ++ gchar *key; ++ gchar *value; ++ ++ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONFIG], ++ "GetAll", ++ g_variant_new ("(s)", priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ dict = g_variant_dict_new (g_variant_get_child_value (val, 0)); ++ val_server = g_variant_dict_lookup_value (dict, "server", G_VARIANT_TYPE("a{ss}")); ++ if (val_server != NULL) { ++ g_variant_iter_init (&iter, val_server); ++ while (g_variant_iter_next (&iter, "{ss}", &key, &value)) { ++ g_debug ("%s=%s", key, value); ++ g_hash_table_insert (priv->config, ++ g_steal_pointer (&key), ++ g_steal_pointer (&value)); ++ } ++ } ++ return TRUE; ++} ++ ++static void ++_subman_proxy_signal_cb (GDBusProxy *proxy, ++ const gchar *sender_name, ++ const gchar *signal_name, ++ GVariant *parameters, ++ GsdSubscriptionManager *manager) ++{ ++ g_autoptr(GError) error = NULL; ++ if (!_client_syspurpose_update (manager, &error)) { ++ g_warning ("failed to update syspurpose: %s", error->message); ++ g_clear_error (&error); ++ } ++ if (!_client_subscription_status_update (manager, &error)) { ++ g_warning ("failed to update subscription status: %s", error->message); ++ g_clear_error (&error); ++ } ++ _client_maybe__show_notification (manager); ++} ++ ++static void ++_client_unload (GsdSubscriptionManager *manager) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) ++ g_clear_object (&priv->proxies[i]); ++ g_hash_table_unref (priv->config); ++} ++ ++static const gchar * ++_rhsm_interface_to_string (_RhsmInterface kind) ++{ ++ if (kind == _RHSM_INTERFACE_CONFIG) ++ return "Config"; ++ if (kind == _RHSM_INTERFACE_REGISTER_SERVER) ++ return "RegisterServer"; ++ if (kind == _RHSM_INTERFACE_ATTACH) ++ return "Attach"; ++ if (kind == _RHSM_INTERFACE_ENTITLEMENT) ++ return "Entitlement"; ++ if (kind == _RHSM_INTERFACE_PRODUCTS) ++ return "Products"; ++ if (kind == _RHSM_INTERFACE_CONSUMER) ++ return "Consumer"; ++ if (kind == _RHSM_INTERFACE_SYSPURPOSE) ++ return "Syspurpose"; ++ return NULL; ++} ++ ++static gboolean ++_client_load (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ ++ priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); ++ ++ /* connect to all the interfaces on the *different* objects :| */ ++ for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) { ++ const gchar *kind = _rhsm_interface_to_string (i); ++ g_autofree gchar *opath = g_strdup_printf ("/com/redhat/RHSM1/%s", kind); ++ g_autofree gchar *iface = g_strdup_printf ("com.redhat.RHSM1.%s", kind); ++ priv->proxies[i] = ++ g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, ++ G_DBUS_PROXY_FLAGS_NONE, ++ NULL, ++ "com.redhat.RHSM1", ++ opath, iface, ++ NULL, ++ error); ++ if (priv->proxies[i] == NULL) ++ return FALSE; ++ /* we want to get notified if the status of the system changes */ ++ g_signal_connect (priv->proxies[i], "g-signal", ++ G_CALLBACK (_subman_proxy_signal_cb), manager); ++ } ++ ++ /* get initial status */ ++ priv->userlang = ""; ++ if (!_client_update_config (manager, error)) ++ return FALSE; ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ if (!_client_syspurpose_update (manager, error)) ++ return FALSE; ++ ++ /* success */ ++ return TRUE; ++} ++ ++gboolean ++gsd_subscription_manager_start (GsdSubscriptionManager *manager, GError **error) ++{ ++ gboolean ret; ++ g_debug ("Starting subscription manager"); ++ gnome_settings_profile_start (NULL); ++ ret = _client_load (manager, error); ++ _client_maybe__show_notification (manager); ++ gnome_settings_profile_end (NULL); ++ return ret; ++} ++ ++void ++gsd_subscription_manager_stop (GsdSubscriptionManager *manager) ++{ ++ g_debug ("Stopping subscription manager"); ++ _client_unload (manager); ++} ++ ++static void ++gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ object_class->finalize = gsd_subscription_manager_finalize; ++ notify_init ("gnome-settings-daemon"); ++ g_type_class_add_private (klass, sizeof (GsdSubscriptionManagerPrivate)); ++} ++ ++static void ++_launch_info_overview (void) ++{ ++ const gchar *argv[] = { "gnome-control-center", "info-overview", NULL }; ++ g_debug ("Running gnome-control-center info-overview"); ++ g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, ++ NULL, NULL, NULL, NULL); ++} ++ ++static void ++_notify_closed_cb (NotifyNotification *notification, gpointer user_data) ++{ ++ /* FIXME: only launch when clicking on the main body, not the window close */ ++ if (notify_notification_get_closed_reason (notification) == 0x400) ++ _launch_info_overview (); ++} ++ ++static void ++_notify_clicked_cb (NotifyNotification *notification, char *action, gpointer user_data) ++{ ++ _launch_info_overview (); ++} ++ ++static void ++gsd_subscription_manager_init (GsdSubscriptionManager *manager) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv = GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE (manager); ++ ++ priv->timer_last_notified = g_timer_new (); ++ ++ /* expired */ ++ priv->notification_expired = ++ notify_notification_new (_("Subscription Has Expired"), ++ _("Add or renew a subscription to continue receiving software updates."), ++ NULL); ++ notify_notification_set_app_name (priv->notification_expired, _("Subscription")); ++ notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_expired, "x-gnome-privacy-scope", "system"); ++ notify_notification_set_urgency (priv->notification_expired, NOTIFY_URGENCY_CRITICAL); ++ notify_notification_add_action (priv->notification_expired, ++ "info-overview", _("Subscribe System…"), ++ _notify_clicked_cb, ++ manager, NULL); ++ g_signal_connect (priv->notification_expired, "closed", ++ G_CALLBACK (_notify_closed_cb), manager); ++ ++ /* registered */ ++ priv->notification_registered = ++ notify_notification_new (_("Registration Successful"), ++ _("The system has been registered and software updates have been enabled."), ++ NULL); ++ notify_notification_set_app_name (priv->notification_registered, _("Subscription")); ++ notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_registered, "x-gnome-privacy-scope", "system"); ++ notify_notification_set_urgency (priv->notification_registered, NOTIFY_URGENCY_CRITICAL); ++ g_signal_connect (priv->notification_registered, "closed", ++ G_CALLBACK (_notify_closed_cb), manager); ++ ++ /* registration required */ ++ priv->notification_registration_required = ++ notify_notification_new (_("System Not Registered"), ++ _("Please register your system to receive software updates."), ++ NULL); ++ notify_notification_set_app_name (priv->notification_registration_required, _("Subscription")); ++ notify_notification_set_hint_string (priv->notification_registration_required, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_registration_required, "x-gnome-privacy-scope", "system"); ++ notify_notification_set_urgency (priv->notification_registration_required, NOTIFY_URGENCY_CRITICAL); ++ notify_notification_add_action (priv->notification_registration_required, ++ "info-overview", _("Register System…"), ++ _notify_clicked_cb, ++ manager, NULL); ++ g_signal_connect (priv->notification_registration_required, "closed", ++ G_CALLBACK (_notify_closed_cb), manager); ++} ++ ++static void ++gsd_subscription_manager_finalize (GObject *object) ++{ ++ GsdSubscriptionManager *manager; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GSD_IS_SUBSCRIPTION_MANAGER (object)); ++ ++ manager = GSD_SUBSCRIPTION_MANAGER (object); ++ ++ gsd_subscription_manager_stop (manager); ++ ++ if (manager->priv->bus_cancellable != NULL) { ++ g_cancellable_cancel (manager->priv->bus_cancellable); ++ g_clear_object (&manager->priv->bus_cancellable); ++ } ++ ++ g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref); ++ g_clear_object (&manager->priv->connection); ++ g_clear_object (&manager->priv->notification_expired); ++ g_clear_object (&manager->priv->notification_registered); ++ g_timer_destroy (manager->priv->timer_last_notified); ++ ++ if (manager->priv->name_id != 0) { ++ g_bus_unown_name (manager->priv->name_id); ++ manager->priv->name_id = 0; ++ } ++ ++ G_OBJECT_CLASS (gsd_subscription_manager_parent_class)->finalize (object); ++} ++ ++static void ++handle_method_call (GDBusConnection *connection, ++ const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *method_name, ++ GVariant *parameters, ++ GDBusMethodInvocation *invocation, ++ gpointer user_data) ++{ ++ GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); ++ g_autoptr(GError) error = NULL; ++ ++ if (g_strcmp0 (method_name, "Register") == 0) { ++ const gchar *organisation = NULL; ++ const gchar *hostname = NULL; ++ ++ if (FALSE) { ++ g_dbus_method_invocation_return_error_literal (invocation, ++ G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, ++ "Cannot register at this time"); ++ ++ return; ++ } ++ ++ g_autoptr(GVariantDict) dict = g_variant_dict_new (g_variant_get_child_value (parameters, 0)); ++ ++ const gchar *kind = NULL; ++ if (!g_variant_dict_lookup (dict, "kind", "&s", &kind)) { ++ g_dbus_method_invocation_return_error_literal (invocation, ++ G_IO_ERROR, G_IO_ERROR_FAILED, ++ "No kind specified"); ++ ++ return; ++ } ++ if (g_strcmp0 (kind, "username") == 0) { ++ const gchar *username = NULL; ++ const gchar *password = NULL; ++ g_variant_dict_lookup (dict, "hostname", "&s", &hostname); ++ g_variant_dict_lookup (dict, "organisation", "&s", &organisation); ++ g_variant_dict_lookup (dict, "username", "&s", &username); ++ g_variant_dict_lookup (dict, "password", "&s", &password); ++ if (!_client_register (manager, ++ hostname, ++ organisation, ++ username, ++ password, ++ &error)) { ++ g_dbus_method_invocation_return_gerror (invocation, error); ++ return; ++ } ++ } else if (g_strcmp0 (kind, "key") == 0) { ++ const gchar *activation_key = NULL; ++ g_variant_dict_lookup (dict, "hostname", "&s", &hostname); ++ g_variant_dict_lookup (dict, "organisation", "&s", &organisation); ++ g_variant_dict_lookup (dict, "activation-key", "&s", &activation_key); ++ if (!_client_register_with_keys (manager, ++ hostname, ++ organisation, ++ activation_key, ++ &error)) { ++ g_dbus_method_invocation_return_gerror (invocation, error); ++ return; ++ } ++ } else { ++ g_dbus_method_invocation_return_error_literal (invocation, ++ G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Invalid kind specified"); ++ ++ return; ++ } ++ g_dbus_method_invocation_return_value (invocation, NULL); ++ } else if (g_strcmp0 (method_name, "Unregister") == 0) { ++ if (!_client_unregister (manager, &error)) { ++ g_dbus_method_invocation_return_gerror (invocation, error); ++ return; ++ } ++ g_dbus_method_invocation_return_value (invocation, NULL); ++ } else { ++ g_assert_not_reached (); ++ } ++} ++ ++static GVariant * ++handle_get_property (GDBusConnection *connection, ++ const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, ++ GError **error, gpointer user_data) ++{ ++ GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ ++ if (g_strcmp0 (interface_name, GSD_SUBSCRIPTION_DBUS_INTERFACE) != 0) { ++ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, ++ "No such interface: %s", interface_name); ++ return NULL; ++ } ++ ++ if (g_strcmp0 (property_name, "SubscriptionStatus") == 0) ++ return g_variant_new_uint32 (priv->subscription_status); ++ ++ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, ++ "Failed to get property: %s", property_name); ++ return NULL; ++} ++ ++static gboolean ++handle_set_property (GDBusConnection *connection, ++ const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, ++ GVariant *value, ++ GError **error, gpointer user_data) ++{ ++ if (g_strcmp0 (interface_name, GSD_SUBSCRIPTION_DBUS_INTERFACE) != 0) { ++ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, ++ "No such interface: %s", interface_name); ++ return FALSE; ++ } ++ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, ++ "No such property: %s", property_name); ++ return FALSE; ++} ++ ++static const GDBusInterfaceVTable interface_vtable = ++{ ++ handle_method_call, ++ handle_get_property, ++ handle_set_property ++}; ++ ++static void ++name_lost_handler_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) ++{ ++ g_debug ("lost name, so exiting"); ++ gtk_main_quit (); ++} ++ ++static void ++on_bus_gotten (GObject *source_object, GAsyncResult *res, GsdSubscriptionManager *manager) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ GDBusConnection *connection; ++ g_autoptr(GError) error = NULL; ++ ++ connection = g_bus_get_finish (res, &error); ++ if (connection == NULL) { ++ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) ++ g_warning ("Could not get session bus: %s", error->message); ++ return; ++ } ++ ++ priv->connection = connection; ++ g_dbus_connection_register_object (connection, ++ GSD_SUBSCRIPTION_DBUS_PATH, ++ priv->introspection_data->interfaces[0], ++ &interface_vtable, ++ manager, ++ NULL, ++ NULL); ++ priv->name_id = g_bus_own_name_on_connection (connection, ++ GSD_SUBSCRIPTION_DBUS_NAME, ++ G_BUS_NAME_OWNER_FLAGS_NONE, ++ NULL, ++ name_lost_handler_cb, ++ manager, ++ NULL); ++} ++ ++static void ++register_manager_dbus (GsdSubscriptionManager *manager) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ ++ priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); ++ g_assert (priv->introspection_data != NULL); ++ priv->bus_cancellable = g_cancellable_new (); ++ ++ g_bus_get (G_BUS_TYPE_SESSION, priv->bus_cancellable, ++ (GAsyncReadyCallback) on_bus_gotten, manager); ++} ++ ++GsdSubscriptionManager * ++gsd_subscription_manager_new (void) ++{ ++ if (manager_object != NULL) { ++ g_object_ref (manager_object); ++ } else { ++ manager_object = g_object_new (GSD_TYPE_SUBSCRIPTION_MANAGER, NULL); ++ g_object_add_weak_pointer (manager_object, ++ (gpointer *) &manager_object); ++ register_manager_dbus (manager_object); ++ } ++ ++ return GSD_SUBSCRIPTION_MANAGER (manager_object); ++} +diff --git a/plugins/subman/gsd-subscription-manager.h b/plugins/subman/gsd-subscription-manager.h +new file mode 100644 +index 00000000..6a524b1b +--- /dev/null ++++ b/plugins/subman/gsd-subscription-manager.h +@@ -0,0 +1,63 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2019 Richard Hughes ++ * ++ * 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 of the License, 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 . ++ * ++ */ ++ ++#ifndef __GSD_SUBSCRIPTION_MANAGER_H ++#define __GSD_SUBSCRIPTION_MANAGER_H ++ ++#include ++ ++G_BEGIN_DECLS ++ ++#define GSD_TYPE_SUBSCRIPTION_MANAGER (gsd_subscription_manager_get_type ()) ++#define GSD_SUBSCRIPTION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManager)) ++#define GSD_SUBSCRIPTION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerClass)) ++#define GSD_IS_SUBSCRIPTION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER)) ++#define GSD_IS_SUBSCRIPTION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SUBSCRIPTION_MANAGER)) ++#define GSD_SUBSCRIPTION_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerClass)) ++#define GSD_SUBSCRIPTION_MANAGER_ERROR (gsd_subscription_manager_error_quark ()) ++ ++typedef struct GsdSubscriptionManagerPrivate GsdSubscriptionManagerPrivate; ++ ++typedef struct ++{ ++ GObject parent; ++ GsdSubscriptionManagerPrivate *priv; ++} GsdSubscriptionManager; ++ ++typedef struct ++{ ++ GObjectClass parent_class; ++} GsdSubscriptionManagerClass; ++ ++enum ++{ ++ GSD_SUBSCRIPTION_MANAGER_ERROR_FAILED ++}; ++ ++GType gsd_subscription_manager_get_type (void); ++GQuark gsd_subscription_manager_error_quark (void); ++ ++GsdSubscriptionManager *gsd_subscription_manager_new (void); ++gboolean gsd_subscription_manager_start (GsdSubscriptionManager *manager, ++ GError **error); ++void gsd_subscription_manager_stop (GsdSubscriptionManager *manager); ++ ++G_END_DECLS ++ ++#endif /* __GSD_SUBSCRIPTION_MANAGER_H */ +diff --git a/plugins/subman/main.c b/plugins/subman/main.c +new file mode 100644 +index 00000000..28ac995b +--- /dev/null ++++ b/plugins/subman/main.c +@@ -0,0 +1,8 @@ ++#define NEW gsd_subscription_manager_new ++#define START gsd_subscription_manager_start ++#define STOP gsd_subscription_manager_stop ++#define MANAGER GsdSubscriptionManager ++#define GDK_BACKEND "x11" ++#include "gsd-subscription-manager.h" ++ ++#include "daemon-skeleton-gtk.h" +diff --git a/plugins/subman/meson.build b/plugins/subman/meson.build +new file mode 100644 +index 00000000..bfd073b6 +--- /dev/null ++++ b/plugins/subman/meson.build +@@ -0,0 +1,56 @@ ++sources = files( ++ 'gsd-subscription-manager.c', ++ 'gsd-subman-common.c', ++ 'main.c' ++) ++ ++deps = plugins_deps + [ ++ libnotify_dep, ++ gtk_dep, ++ jsonglib_dep, ++ m_dep, ++] ++ ++cflags += ['-DBINDIR="@0@"'.format(gsd_bindir)] ++cflags += ['-DLIBEXECDIR="@0@"'.format(gsd_libexecdir)] ++ ++executable( ++ 'gsd-' + plugin_name, ++ sources, ++ include_directories: [top_inc, common_inc], ++ dependencies: deps, ++ c_args: cflags, ++ install: true, ++ install_rpath: gsd_pkglibdir, ++ install_dir: gsd_libexecdir ++) ++ ++# .Register needs to be called from root as subman can't do PolicyKit... ++policy = 'org.gnome.settings-daemon.plugins.subman.policy' ++policy_in = configure_file( ++ input: policy + '.in.in', ++ output: policy + '.in', ++ configuration: plugins_conf ++) ++ ++i18n.merge_file( ++ policy, ++ input: policy_in, ++ output: policy, ++ po_dir: po_dir, ++ install: true, ++ install_dir: join_paths(gsd_datadir, 'polkit-1', 'actions') ++) ++ ++install_data('org.gnome.settings-daemon.plugins.subman.rules', ++ install_dir : join_paths(gsd_datadir, 'polkit-1', 'rules.d')) ++ ++executable( ++ 'gsd-subman-helper', ++ 'gsd-subman-helper.c', ++ include_directories: top_inc, ++ dependencies: [gio_dep, jsonglib_dep], ++ install: true, ++ install_rpath: gsd_pkglibdir, ++ install_dir: gsd_libexecdir ++) +diff --git a/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in b/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in +new file mode 100644 +index 00000000..14fe5915 +--- /dev/null ++++ b/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in +@@ -0,0 +1,9 @@ ++[Desktop Entry] ++Type=Application ++Name=GNOME Settings Daemon's subscription manager plugin ++Exec=@libexecdir@/gsd-subman ++OnlyShowIn=GNOME; ++NoDisplay=true ++X-GNOME-Autostart-Phase=Initialization ++X-GNOME-Autostart-Notify=true ++X-GNOME-AutoRestart=true +diff --git a/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in b/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in +new file mode 100644 +index 00000000..59e9fdd4 +--- /dev/null ++++ b/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in +@@ -0,0 +1,27 @@ ++ ++ ++ ++ ++ ++ ++ GNOME Settings Daemon ++ http://git.gnome.org/browse/gnome-settings-daemon ++ emblem-synchronizing ++ ++ ++ Register the system ++ Authentication is required to register the system ++ ++ no ++ no ++ auth_admin_keep ++ ++ @libexecdir@/gsd-subman-helper ++ ++ ++ +diff --git a/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules b/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules +new file mode 100644 +index 00000000..1ed3a0ea +--- /dev/null ++++ b/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules +@@ -0,0 +1,7 @@ ++polkit.addRule(function(action, subject) { ++ if (action.id == "org.gnome.settings-daemon.plugins.subman.register" && ++ subject.active == true && subject.local == true && ++ subject.isInGroup("wheel")) { ++ return polkit.Result.YES; ++ } ++}); +-- +2.31.1 + + +From dd5490fb4e962d82598bbf83d0dc600c030a10a3 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Thu, 27 Jun 2019 16:12:00 +0200 +Subject: [PATCH 02/19] subman: Add InstalledProducts dbus property for g-c-c + +--- + plugins/subman/gsd-subscription-manager.c | 135 ++++++++++++++++++++++ + 1 file changed, 135 insertions(+) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 08b13fa6..a8c18a26 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -1,6 +1,7 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes ++ * Copyright (C) 2019 Kalev Lember + * + * 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 +@@ -44,6 +45,7 @@ static const gchar introspection_xml[] = + " " + " " + " " ++" " + " " + " " + ""; +@@ -72,6 +74,7 @@ struct GsdSubscriptionManagerPrivate + GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; + const gchar *userlang; /* owned by GLib internally */ + GHashTable *config; /* str:str */ ++ GPtrArray *installed_products; + gchar *address; + + GTimer *timer_last_notified; +@@ -92,6 +95,32 @@ static void gsd_subscription_manager_finalize (GObject *objec + + G_DEFINE_TYPE (GsdSubscriptionManager, gsd_subscription_manager, G_TYPE_OBJECT) + ++typedef struct ++{ ++ gchar *product_name; ++ gchar *product_id; ++ gchar *version; ++ gchar *arch; ++ gchar *status; ++ gchar *starts; ++ gchar *ends; ++} ProductData; ++ ++static void ++product_data_free (ProductData *product) ++{ ++ g_free (product->product_name); ++ g_free (product->product_id); ++ g_free (product->version); ++ g_free (product->arch); ++ g_free (product->status); ++ g_free (product->starts); ++ g_free (product->ends); ++ g_free (product); ++} ++ ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free); ++ + static gpointer manager_object = NULL; + + GQuark +@@ -120,6 +149,32 @@ _client_subscription_status_from_text (const gchar *status_txt) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + } + ++static GVariant * ++_make_installed_products_variant (GPtrArray *installed_products) ++{ ++ GVariantBuilder builder; ++ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); ++ ++ for (guint i = 0; i < installed_products->len; i++) { ++ ProductData *product = g_ptr_array_index (installed_products, i); ++ g_auto(GVariantDict) dict; ++ ++ g_variant_dict_init (&dict, NULL); ++ ++ g_variant_dict_insert (&dict, "product-name", "s", product->product_name); ++ g_variant_dict_insert (&dict, "product-id", "s", product->product_id); ++ g_variant_dict_insert (&dict, "version", "s", product->version); ++ g_variant_dict_insert (&dict, "arch", "s", product->arch); ++ g_variant_dict_insert (&dict, "status", "s", product->status); ++ g_variant_dict_insert (&dict, "starts", "s", product->starts); ++ g_variant_dict_insert (&dict, "ends", "s", product->ends); ++ ++ g_variant_builder_add_value (&builder, g_variant_dict_end (&dict)); ++ } ++ ++ return g_variant_builder_end (&builder); ++} ++ + static void + _emit_property_changed (GsdSubscriptionManager *manager, + const gchar *property_name, +@@ -154,6 +209,69 @@ _emit_property_changed (GsdSubscriptionManager *manager, + g_variant_builder_clear (&invalidated_builder); + } + ++static gboolean ++_client_installed_products_update (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ JsonNode *json_root; ++ JsonArray *json_products_array; ++ const gchar *json_txt = NULL; ++ g_autoptr(GVariant) val = NULL; ++ g_autoptr(JsonParser) json_parser = json_parser_new (); ++ ++ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_PRODUCTS], ++ "ListInstalledProducts", ++ g_variant_new ("(sa{sv}s)", ++ "" /* filter_string */, ++ NULL /* proxy_options */, ++ priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_variant_get (val, "(&s)", &json_txt); ++ g_debug ("Products.ListInstalledProducts JSON: %s", json_txt); ++ if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) ++ return FALSE; ++ json_root = json_parser_get_root (json_parser); ++ json_products_array = json_node_get_array (json_root); ++ if (json_products_array == NULL) { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, ++ "no InstalledProducts array in %s", json_txt); ++ return FALSE; ++ } ++ ++ g_ptr_array_set_size (priv->installed_products, 0); ++ ++ for (guint i = 0; i < json_array_get_length (json_products_array); i++) { ++ JsonArray *json_product = json_array_get_array_element (json_products_array, i); ++ g_autoptr(ProductData) product = g_new0 (ProductData, 1); ++ ++ if (json_product == NULL) ++ continue; ++ if (json_array_get_length (json_product) < 8) { ++ g_debug ("Unexpected number of array elements in InstalledProducts JSON"); ++ continue; ++ } ++ ++ product->product_name = g_strdup (json_array_get_string_element (json_product, 0)); ++ product->product_id = g_strdup (json_array_get_string_element (json_product, 1)); ++ product->version = g_strdup (json_array_get_string_element (json_product, 2)); ++ product->arch = g_strdup (json_array_get_string_element (json_product, 3)); ++ product->status = g_strdup (json_array_get_string_element (json_product, 4)); ++ product->starts = g_strdup (json_array_get_string_element (json_product, 6)); ++ product->ends = g_strdup (json_array_get_string_element (json_product, 7)); ++ ++ g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); ++ } ++ ++ /* emit notification for g-c-c */ ++ _emit_property_changed (manager, "InstalledProducts", ++ _make_installed_products_variant (priv->installed_products)); ++ ++ return TRUE; ++} ++ + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { +@@ -450,6 +568,8 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + + /* success */ +@@ -497,6 +617,8 @@ _client_register (GsdSubscriptionManager *manager, + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } +@@ -523,6 +645,8 @@ _client_unregister (GsdSubscriptionManager *manager, GError **error) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } +@@ -575,6 +699,10 @@ _subman_proxy_signal_cb (GDBusProxy *proxy, + g_warning ("failed to update subscription status: %s", error->message); + g_clear_error (&error); + } ++ if (!_client_installed_products_update (manager, &error)) { ++ g_warning ("failed to update installed products: %s", error->message); ++ g_clear_error (&error); ++ } + _client_maybe__show_notification (manager); + } + +@@ -640,6 +768,8 @@ _client_load (GsdSubscriptionManager *manager, GError **error) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + if (!_client_syspurpose_update (manager, error)) + return FALSE; + +@@ -703,6 +833,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv = GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE (manager); + ++ priv->installed_products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); + priv->timer_last_notified = g_timer_new (); + + /* expired */ +@@ -767,6 +898,7 @@ gsd_subscription_manager_finalize (GObject *object) + g_clear_object (&manager->priv->bus_cancellable); + } + ++ g_clear_pointer (&manager->priv->installed_products, g_ptr_array_unref); + g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref); + g_clear_object (&manager->priv->connection); + g_clear_object (&manager->priv->notification_expired); +@@ -884,6 +1016,9 @@ handle_get_property (GDBusConnection *connection, + if (g_strcmp0 (property_name, "SubscriptionStatus") == 0) + return g_variant_new_uint32 (priv->subscription_status); + ++ if (g_strcmp0 (property_name, "InstalledProducts") == 0) ++ return _make_installed_products_variant (priv->installed_products); ++ + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Failed to get property: %s", property_name); + return NULL; +-- +2.31.1 + + +From c67554c7ab37a4fea6abc80ca199de2671c34ee2 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 28 Jun 2019 18:10:36 +0200 +Subject: [PATCH 03/19] subman: Increase RHSM dbus call timeouts + +Increase the dbus timeouts to 5 minutes as the register/unregister calls +seem to routinely take more than a minute. +--- + plugins/subman/gsd-subman-helper.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index 182f7190..af7a82e9 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -28,6 +28,8 @@ + #include + #include + ++#define DBUS_TIMEOUT 300000 /* 5 minutes */ ++ + static void + _helper_convert_error (const gchar *json_txt, GError **error) + { +@@ -94,7 +96,8 @@ _helper_unregister (GError **error) + proxy_options, + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + return res != NULL; + } + +@@ -127,7 +130,8 @@ _helper_auto_attach (GError **error) + proxy_options, + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + if (res == NULL) + return FALSE; + g_variant_get (res, "(&s)", &str); +@@ -158,7 +162,8 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error) + g_variant_new_string (value), + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + return res != NULL; + } + +@@ -305,7 +310,8 @@ main (int argc, char *argv[]) + subman_conopts, + userlang), + G_DBUS_CALL_FLAGS_NO_AUTO_START, +- -1, NULL, &error_local); ++ DBUS_TIMEOUT, ++ NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +@@ -339,7 +345,8 @@ main (int argc, char *argv[]) + subman_conopts, + userlang), + G_DBUS_CALL_FLAGS_NO_AUTO_START, +- -1, NULL, &error_local); ++ DBUS_TIMEOUT, ++ NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +-- +2.31.1 + + +From efcbbf6a50eca888bde03f4425578bab9916ebaa Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 20 Aug 2020 11:20:47 -0400 +Subject: [PATCH 04/19] subman: Drop userlang field + +It's currently always erroneously set to empty string. + +This commit drops it, and just uses "C.UTF-8" everywhere, +which is what we actually want. +--- + plugins/subman/gsd-subscription-manager.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index a8c18a26..46f051a5 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -72,7 +72,6 @@ struct GsdSubscriptionManagerPrivate + GCancellable *bus_cancellable; + + GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; +- const gchar *userlang; /* owned by GLib internally */ + GHashTable *config; /* str:str */ + GPtrArray *installed_products; + gchar *address; +@@ -224,7 +223,7 @@ _client_installed_products_update (GsdSubscriptionManager *manager, GError **err + g_variant_new ("(sa{sv}s)", + "" /* filter_string */, + NULL /* proxy_options */, +- priv->userlang), ++ "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -290,7 +289,7 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ +- priv->userlang), ++ "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -332,7 +331,7 @@ _client_syspurpose_update (GsdSubscriptionManager *manager, GError **error) + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_SYSPURPOSE], + "GetSyspurpose", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -375,7 +374,7 @@ _client_register_start (GsdSubscriptionManager *manager, GError **error) + if (proxy == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy, "Start", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -408,7 +407,7 @@ _client_register_stop (GsdSubscriptionManager *manager, GError **error) + if (proxy == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy, "Stop", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -664,7 +663,7 @@ _client_update_config (GsdSubscriptionManager *manager, GError **error) + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONFIG], + "GetAll", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) +@@ -763,7 +762,6 @@ _client_load (GsdSubscriptionManager *manager, GError **error) + } + + /* get initial status */ +- priv->userlang = ""; + if (!_client_update_config (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) +-- +2.31.1 + + +From 3ff6f889049462b2b3029e26f7251e39904a3ddf Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 15:04:17 -0500 +Subject: [PATCH 05/19] subman: Use user locale for registration/subscription + operations + +This makes sure that error messages are in the correct locale. +--- + plugins/subman/gsd-subman-helper.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index af7a82e9..f84e91bf 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -24,11 +24,13 @@ + #include + #include + #include ++#include + + #include + #include + + #define DBUS_TIMEOUT 300000 /* 5 minutes */ ++static const char *locale; + + static void + _helper_convert_error (const gchar *json_txt, GError **error) +@@ -94,7 +96,7 @@ _helper_unregister (GError **error) + "Unregister", + g_variant_new ("(a{sv}s)", + proxy_options, +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); +@@ -128,7 +130,7 @@ _helper_auto_attach (GError **error) + g_variant_new ("(sa{sv}s)", + "", /* now? */ + proxy_options, +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); +@@ -160,7 +162,7 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error) + g_variant_new ("(svs)", + key, + g_variant_new_string (value), +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); +@@ -170,7 +172,6 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error) + int + main (int argc, char *argv[]) + { +- const gchar *userlang = ""; /* as root, so no translations */ + g_autofree gchar *activation_key = NULL; + g_autofree gchar *address = NULL; + g_autofree gchar *hostname = NULL; +@@ -218,6 +219,10 @@ main (int argc, char *argv[]) + g_printerr ("This program can only be used by the root user\n"); + return G_IO_ERROR_NOT_SUPPORTED; + } ++ ++ setlocale (LC_ALL, ""); ++ locale = setlocale (LC_MESSAGES, NULL); ++ + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("Failed to parse arguments: %s\n", error->message); +@@ -308,7 +313,7 @@ main (int argc, char *argv[]) + activation_keys, + subman_options, + subman_conopts, +- userlang), ++ locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); +@@ -343,7 +348,7 @@ main (int argc, char *argv[]) + password, + subman_options, + subman_conopts, +- userlang), ++ locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); +-- +2.31.1 + + +From 7bdca155acbe043c82e7abd9d2072c6502e10270 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 20 Aug 2020 13:34:19 -0400 +Subject: [PATCH 06/19] subman: Handle subscription-manager giving invalid + status better + +subscription-manager potentially returns status messages that the +subman plugin treats as enum values translated in some unknown +other language. It could be tied to system locale, or due to a +caching bug a previous locale used. + +This commit tries to work around that bug, by instead relying on +the GetUUID() method and valid attribute. If there's no UUID we +know the system is unregistered. If there's a UUID but the valid +attribute is FALSE we know the system is registered, but hasn't +got proper entitlements. +--- + plugins/subman/gsd-subscription-manager.c | 69 ++++++++++++----------- + 1 file changed, 36 insertions(+), 33 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 46f051a5..e2c16056 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -131,23 +131,6 @@ gsd_subscription_manager_error_quark (void) + return quark; + } + +-static GsdSubmanSubscriptionStatus +-_client_subscription_status_from_text (const gchar *status_txt) +-{ +- if (g_strcmp0 (status_txt, "Unknown") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; +- if (g_strcmp0 (status_txt, "Current") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; +- if (g_strcmp0 (status_txt, "Invalid") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; +- if (g_strcmp0 (status_txt, "Disabled") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; +- if (g_strcmp0 (status_txt, "Insufficient") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; +- g_warning ("Unknown subscription status: %s", status_txt); // 'Current'? +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; +-} +- + static GVariant * + _make_installed_products_variant (GPtrArray *installed_products) + { +@@ -275,40 +258,60 @@ static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GVariant) uuid = NULL; ++ const gchar *uuid_txt = NULL; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; +- const gchar *status_txt = NULL; +- g_autoptr(GVariant) val = NULL; ++ g_autoptr(GVariant) status = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; + +- val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], +- "GetStatus", +- g_variant_new ("(ss)", +- "", /* assumed as 'now' */ +- "C.UTF-8"), +- G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); +- if (val == NULL) ++ uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], ++ "GetUuid", ++ g_variant_new ("(s)", ++ "C.UTF-8"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (uuid == NULL) + return FALSE; +- g_variant_get (val, "(&s)", &json_txt); ++ ++ g_variant_get (uuid, "(&s)", &uuid_txt); ++ ++ status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], ++ "GetStatus", ++ g_variant_new ("(ss)", ++ "", /* assumed as 'now' */ ++ "C.UTF-8"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (status == NULL) ++ return FALSE; ++ g_variant_get (status, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); +- if (!json_object_has_member (json_obj, "status")) { ++ if (!json_object_has_member (json_obj, "valid")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, +- "no Entitlement.GetStatus status in %s", json_txt); ++ "no Entitlement.GetStatus valid in %s", json_txt); + return FALSE; + } + +- status_txt = json_object_get_string_member (json_obj, "status"); +- g_debug ("Entitlement.GetStatus: %s", status_txt); +- priv->subscription_status = _client_subscription_status_from_text (status_txt); ++ gboolean is_valid = json_object_get_boolean_member (json_obj, "valid"); ++ ++ if (uuid_txt[0] != '\0') { ++ if (is_valid) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; ++ } else { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ } ++ } else { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++ } + + /* emit notification for g-c-c */ + if (priv->subscription_status != priv->subscription_status_last) { +-- +2.31.1 + + +From 74fe856b8d2826520a7d324abe9727097cce8cfb Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 25 Aug 2020 10:34:03 -0400 +Subject: [PATCH 07/19] subman: Force re-subscribe if the admin already + subscribed + +It's possible for an admin to to half-enroll the system with RHN, +using the CLI tools. + +Meaning, it's possible for them to register the system with the +service, but not attach to a purchased license for the machine, +the, so called, entitlements. + +The subman module always does both halves of the registration process +in lock step. This means, if an admin tries to register using GNOME +while in a half-registered state, subman will fail because the first +step, the registration step, is already finished. + +This commit addresses that problem by trying to unregister up front +before registering. +--- + plugins/subman/gsd-subman-helper.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index f84e91bf..3931ef2e 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -78,7 +78,6 @@ _helper_unregister (GError **error) + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + +- g_debug ("unregistering"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, +@@ -235,6 +234,7 @@ main (int argc, char *argv[]) + return G_IO_ERROR_INVALID_DATA; + } + if (g_strcmp0 (kind, "unregister") == 0) { ++ g_debug ("unregistering"); + if (!_helper_unregister (&error)) { + g_printerr ("Failed to Unregister: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; +@@ -304,6 +304,9 @@ main (int argc, char *argv[]) + return G_IO_ERROR_INVALID_DATA; + } + ++ g_debug ("trying to unregister in case machine is already registered"); ++ _helper_unregister (NULL); ++ + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, +@@ -327,7 +330,6 @@ main (int argc, char *argv[]) + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + +- g_debug ("registering using username and password"); + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; +@@ -340,6 +342,11 @@ main (int argc, char *argv[]) + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } ++ ++ g_debug ("trying to unregister in case machine is already registered"); ++ _helper_unregister (NULL); ++ ++ g_debug ("registering using username and password"); + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", +-- +2.31.1 + + +From c0ca9c55632a52371acbbb76a279f28e26532e5e Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 25 Aug 2020 16:20:42 -0400 +Subject: [PATCH 08/19] subman: Don't send secrets through command line + +The command line is introspectable with "ps", and it even gets logged +to syslog, so it's not suitable for passing secrets. + +Unfortunately, the user's password is currently passed. + +This commit addresses that problem by passing the password through +stdin, instead. +--- + plugins/subman/gsd-subman-helper.c | 32 ++++++++------ + plugins/subman/gsd-subscription-manager.c | 52 ++++++++++++++++++++--- + plugins/subman/meson.build | 2 +- + 3 files changed, 66 insertions(+), 20 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index 3931ef2e..edf1e41f 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -21,12 +21,14 @@ + + #include "config.h" + ++ + #include + #include + #include + #include + + #include ++#include + #include + + #define DBUS_TIMEOUT 300000 /* 5 minutes */ +@@ -176,7 +178,6 @@ main (int argc, char *argv[]) + g_autofree gchar *hostname = NULL; + g_autofree gchar *kind = NULL; + g_autofree gchar *organisation = NULL; +- g_autofree gchar *password = NULL; + g_autofree gchar *port = NULL; + g_autofree gchar *prefix = NULL; + g_autofree gchar *proxy_server = NULL; +@@ -188,6 +189,7 @@ main (int argc, char *argv[]) + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariantBuilder) subman_conopts = NULL; + g_autoptr(GVariantBuilder) subman_options = NULL; ++ g_autoptr(GInputStream) standard_input_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE); + + const GOptionEntry options[] = { + { "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, +@@ -196,12 +198,8 @@ main (int argc, char *argv[]) + &address, "UNIX address", NULL }, + { "username", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &username, "Username", NULL }, +- { "password", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, +- &password, "Password", NULL }, + { "organisation", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &organisation, "Organisation", NULL }, +- { "activation-key", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, +- &activation_key, "Activation keys", NULL }, + { "hostname", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &hostname, "Registration server hostname", NULL }, + { "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, +@@ -294,16 +292,20 @@ main (int argc, char *argv[]) + g_auto(GStrv) activation_keys = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; ++ gchar activation_key[PIPE_BUF + 1] = ""; + +- if (activation_key == NULL) { +- g_printerr ("Required --activation-key\n"); +- return G_IO_ERROR_INVALID_DATA; +- } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + ++ g_input_stream_read (standard_input_stream, activation_key, sizeof (activation_key) - 1, NULL, &error_local); ++ ++ if (error_local != NULL) { ++ g_printerr ("Could not read activation key: %s\n", error_local->message); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + +@@ -329,20 +331,24 @@ main (int argc, char *argv[]) + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; ++ gchar password[PIPE_BUF + 1] = ""; + + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } +- if (password == NULL) { +- g_printerr ("Required --password\n"); +- return G_IO_ERROR_INVALID_DATA; +- } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + ++ g_input_stream_read (standard_input_stream, password, sizeof (password) - 1, NULL, &error_local); ++ ++ if (error_local != NULL) { ++ g_printerr ("Could not read password: %s\n", error_local->message); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index e2c16056..0838d490 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -21,6 +21,7 @@ + #include "config.h" + + #include ++#include + #include + #include + #include +@@ -544,26 +545,45 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stdin_buf = g_bytes_new (activation_key, strlen (activation_key) + 1); ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); +- subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-key", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, +- "--activation-key", activation_key, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } +- if (!_client_subprocess_wait_check (subprocess, error)) ++ ++ if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); + return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ g_bytes_get_size (stderr_buf), ++ g_bytes_get_data (stderr_buf, NULL)); ++ } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) +@@ -588,6 +608,9 @@ _client_register (GsdSubscriptionManager *manager, + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stdin_buf = g_bytes_new (password, strlen (password) + 1); ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; + + /* fallback */ + if (organisation == NULL) +@@ -598,21 +621,38 @@ _client_register (GsdSubscriptionManager *manager, + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); +- subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, ++ error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-username", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + "--username", username, +- "--password", password, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } +- if (!_client_subprocess_wait_check (subprocess, error)) ++ ++ if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); + return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ g_bytes_get_size (stderr_buf), ++ g_bytes_get_data (stderr_buf, NULL)); ++ } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) +diff --git a/plugins/subman/meson.build b/plugins/subman/meson.build +index bfd073b6..e4b4589d 100644 +--- a/plugins/subman/meson.build ++++ b/plugins/subman/meson.build +@@ -49,7 +49,7 @@ executable( + 'gsd-subman-helper', + 'gsd-subman-helper.c', + include_directories: top_inc, +- dependencies: [gio_dep, jsonglib_dep], ++ dependencies: [gio_dep, gio_unix_dep, jsonglib_dep], + install: true, + install_rpath: gsd_pkglibdir, + install_dir: gsd_libexecdir +-- +2.31.1 + + +From 590ad191dc3fec6c21dbfd22a5fc757a1409edbf Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 21 Jan 2021 09:52:19 -0500 +Subject: [PATCH 09/19] subman: Don't treat failure to attach as fatal + +Many organizations don't require specific subscriptions to get +updates (called "simple content access"). At the moment, +those systems get an error when registering. + +This commit quiets the error. +--- + plugins/subman/gsd-subman-helper.c | 46 ++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 9 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index edf1e41f..53a4d56b 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -52,6 +52,17 @@ _helper_convert_error (const gchar *json_txt, GError **error) + } + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); ++ if (json_object_has_member (json_obj, "severity")) { ++ const gchar *severity; ++ ++ /* warnings are non-fatal so we ignore them ++ */ ++ severity = json_object_get_string_member (json_obj, "severity"); ++ if (g_strstr_len (severity, -1, "warning") != NULL) { ++ return; ++ } ++ } ++ + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, +@@ -108,6 +119,7 @@ static gboolean + _helper_auto_attach (GError **error) + { + const gchar *str = NULL; ++ g_autoptr(GError) error_local = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; +@@ -120,9 +132,12 @@ _helper_auto_attach (GError **error) + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Attach", + "com.redhat.RHSM1.Attach", +- NULL, error); ++ NULL, &error_local); + if (proxy == NULL) { +- g_prefix_error (error, "Failed to get proxy: "); ++ g_dbus_error_strip_remote_error (error_local); ++ g_propagate_prefixed_error (error, ++ g_steal_pointer (&error_local), ++ "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); +@@ -134,9 +149,18 @@ _helper_auto_attach (GError **error) + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, +- NULL, error); +- if (res == NULL) +- return FALSE; ++ NULL, &error_local); ++ if (res == NULL) { ++ g_dbus_error_strip_remote_error (error_local); ++ _helper_convert_error (error_local->message, error); ++ ++ if (*error != NULL) { ++ g_prefix_error (error, "Failed to get proxy: "); ++ return FALSE; ++ } ++ ++ return TRUE; ++ } + g_variant_get (res, "(&s)", &str); + g_debug ("Attach.AutoAttach: %s", str); + return TRUE; +@@ -325,8 +349,10 @@ main (int argc, char *argv[]) + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +- g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); +- return error->code; ++ if (error != NULL) { ++ g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); ++ return error->code; ++ } + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; +@@ -368,8 +394,10 @@ main (int argc, char *argv[]) + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +- g_printerr ("Failed to Register: %s\n", error->message); +- return error->code; ++ if (error != NULL) { ++ g_printerr ("Failed to Register: %s\n", error->message); ++ return error->code; ++ } + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); +-- +2.31.1 + + +From 8c076516d48b5603132d3586a8040ef46011330f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:24:36 -0500 +Subject: [PATCH 10/19] subman: Add new no-installed-products state + +It's possible, though unlikley, the system has +no packages installed from Red Hat supported package sets. + +This commit adds a new state to track that situation. +--- + plugins/subman/gsd-subman-common.c | 2 ++ + plugins/subman/gsd-subman-common.h | 1 + + plugins/subman/gsd-subscription-manager.c | 17 +++++++---------- + 3 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/plugins/subman/gsd-subman-common.c b/plugins/subman/gsd-subman-common.c +index e515131e..eef5175d 100644 +--- a/plugins/subman/gsd-subman-common.c ++++ b/plugins/subman/gsd-subman-common.c +@@ -32,5 +32,7 @@ gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status) + return "disabled"; + if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID) + return "partially-valid"; ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS) ++ return "no-installed-products"; + return "unknown"; + } +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index fccf9f6a..f8a3d9f4 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -30,6 +30,7 @@ typedef enum { + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, + GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST + } GsdSubmanSubscriptionStatus; + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 0838d490..46f8d35c 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -269,6 +269,13 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; ++ if (!_client_installed_products_update (manager, error)) ++ goto out; ++ ++ if (priv->installed_products->len == 0) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS; ++ goto out; ++ } + + uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], + "GetUuid", +@@ -590,8 +597,6 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + _client_maybe__show_notification (manager); + + /* success */ +@@ -659,8 +664,6 @@ _client_register (GsdSubscriptionManager *manager, + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } +@@ -741,10 +744,6 @@ _subman_proxy_signal_cb (GDBusProxy *proxy, + g_warning ("failed to update subscription status: %s", error->message); + g_clear_error (&error); + } +- if (!_client_installed_products_update (manager, &error)) { +- g_warning ("failed to update installed products: %s", error->message); +- g_clear_error (&error); +- } + _client_maybe__show_notification (manager); + } + +@@ -809,8 +808,6 @@ _client_load (GsdSubscriptionManager *manager, GError **error) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + if (!_client_syspurpose_update (manager, error)) + return FALSE; + +-- +2.31.1 + + +From fad6580e4cf9e7f350d0d537a064bbb439457540 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:26:40 -0500 +Subject: [PATCH 11/19] subman: Fix some build warnings + +--- + plugins/subman/gsd-subscription-manager.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 46f8d35c..1f9ca447 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -588,8 +588,8 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", +- g_bytes_get_size (stderr_buf), +- g_bytes_get_data (stderr_buf, NULL)); ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ +@@ -655,8 +655,8 @@ _client_register (GsdSubscriptionManager *manager, + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", +- g_bytes_get_size (stderr_buf), +- g_bytes_get_data (stderr_buf, NULL)); ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ +-- +2.31.1 + + +From 6c99ee2eee9a1be3765db5a7b80ae86a4444f00b Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:27:42 -0500 +Subject: [PATCH 12/19] subman: Add DBus API to subscribe for updates on + already registered system + +It's possible an admin may have registered their system without +attaching any subscriptions to it. + +At the moment, gnome-settings-daemon only provides a way to register +and subscribe in one step. + +This commit adds an API to support doing the last half of the process +on its own. +--- + plugins/subman/gsd-subscription-manager.c | 51 +++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 1f9ca447..705f8b11 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -46,6 +46,7 @@ static const gchar introspection_xml[] = + " " + " " + " " ++" " + " " + " " + " " +@@ -696,6 +697,50 @@ _client_unregister (GsdSubscriptionManager *manager, GError **error) + return TRUE; + } + ++static gboolean ++_client_attach (GsdSubscriptionManager *manager, ++ GError **error) ++{ ++ g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; ++ ++ g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, ++ error, ++ "pkexec", LIBEXECDIR "/gsd-subman-helper", ++ "--kind", "auto-attach", ++ NULL); ++ if (subprocess == NULL) { ++ g_prefix_error (error, "failed to find pkexec: "); ++ return FALSE; ++ } ++ ++ if (!g_subprocess_communicate (subprocess, NULL, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); ++ return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); ++ } ++ ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ _client_maybe__show_notification (manager); ++ return TRUE; ++} ++ + static gboolean + _client_update_config (GsdSubscriptionManager *manager, GError **error) + { +@@ -1029,6 +1074,12 @@ handle_method_call (GDBusConnection *connection, + return; + } + g_dbus_method_invocation_return_value (invocation, NULL); ++ } else if (g_strcmp0 (method_name, "Attach") == 0) { ++ if (!_client_attach (manager, &error)) { ++ g_dbus_method_invocation_return_gerror (invocation, error); ++ return; ++ } ++ g_dbus_method_invocation_return_value (invocation, NULL); + } else { + g_assert_not_reached (); + } +-- +2.31.1 + + +From b340559f941ebd012711f357a8a0095776222d7a Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:34:03 -0500 +Subject: [PATCH 13/19] subman: Improve subscription status handling + +This commit improves how subscription-manager status is +parsed to give more detailed information about subscription +state. +--- + plugins/subman/gsd-subscription-manager.c | 33 +++++++++++++++++++---- + 1 file changed, 28 insertions(+), 5 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 705f8b11..6d80bfa9 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -289,6 +289,11 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + + g_variant_get (uuid, "(&s)", &uuid_txt); + ++ if (uuid_txt[0] == '\0') { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++ goto out; ++ } ++ + status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", +@@ -304,6 +309,13 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); ++ ++ const gchar *status_id = NULL; ++ ++ if (json_object_has_member (json_obj, "status_id")) { ++ status_id = json_object_get_string_member (json_obj, "status_id"); ++ } ++ + if (!json_object_has_member (json_obj, "valid")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "no Entitlement.GetStatus valid in %s", json_txt); +@@ -312,16 +324,27 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + + gboolean is_valid = json_object_get_boolean_member (json_obj, "valid"); + +- if (uuid_txt[0] != '\0') { +- if (is_valid) { ++ if (is_valid) { ++ if (g_strcmp0 (status_id, "disabled") != 0) { + priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; + } else { +- priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; ++ } ++ goto out; ++ } ++ ++ for (guint i = 0; i < priv->installed_products->len; i++) { ++ ProductData *product = g_ptr_array_index (priv->installed_products, i); ++ ++ if (g_strcmp0 (product->status, "subscribed") == 0) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; ++ goto out; + } +- } else { +- priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + } + ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ ++out: + /* emit notification for g-c-c */ + if (priv->subscription_status != priv->subscription_status_last) { + _emit_property_changed (manager, "SubscriptionStatus", +-- +2.31.1 + + +From e2caf6d353dfe6e3314be9c2e604dd4c025d7dc1 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:55:19 -0500 +Subject: [PATCH 14/19] subman: Drop "LAST" from status enum + +It's unused, so get rid of it. +--- + plugins/subman/gsd-subman-common.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index f8a3d9f4..88226564 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -31,7 +31,6 @@ typedef enum { + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, +- GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST + } GsdSubmanSubscriptionStatus; + + const gchar *gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status); +-- +2.31.1 + + +From 26ff144e7c5230f8b27a27e6eef5c109ae31ab0f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 12:41:20 -0500 +Subject: [PATCH 15/19] subman: Clean up notification behavior + +Notifications were only displayed for some status transitions. + +This commit introduces some booleans based on the old and new +statuses to make the code clearer and to make it easier to hit +all the cases. +--- + plugins/subman/gsd-subman-common.h | 1 + + plugins/subman/gsd-subscription-manager.c | 141 ++++++++++++++++++---- + 2 files changed, 120 insertions(+), 22 deletions(-) + +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index 88226564..9397dbe4 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -25,6 +25,7 @@ + G_BEGIN_DECLS + + typedef enum { ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ = -1, + GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, + GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 6d80bfa9..aaccbbc6 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -270,6 +270,7 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; ++ + if (!_client_installed_products_update (manager, error)) + goto out; + +@@ -512,55 +513,149 @@ static void + _client_maybe__show_notification (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; ++ gboolean was_read, was_registered, had_subscriptions, needed_subscriptions; ++ gboolean is_read, is_registered, has_subscriptions, needs_subscriptions; ++ ++ switch (priv->subscription_status_last) { ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: ++ was_read = FALSE; ++ was_registered = FALSE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: ++ was_read = TRUE; ++ was_registered = FALSE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = TRUE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = FALSE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS: ++ was_read = TRUE; ++ was_registered = FALSE; ++ needed_subscriptions = FALSE; ++ had_subscriptions = FALSE; ++ break; ++ } ++ ++ switch (priv->subscription_status) { ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: ++ is_read = FALSE; ++ is_registered = FALSE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: ++ is_read = TRUE; ++ is_registered = FALSE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = TRUE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = FALSE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS: ++ is_read = TRUE; ++ is_registered = FALSE; ++ needs_subscriptions = FALSE; ++ has_subscriptions = FALSE; ++ break; ++ } + + /* startup */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ if (!was_read && is_read && priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } + + /* something changed */ +- if (priv->subscription_status_last != priv->subscription_status) { ++ if (was_read && is_read && priv->subscription_status_last != priv->subscription_status) { + g_debug ("transisition from subscription status '%s' to '%s'", + gsd_subman_subscription_status_to_string (priv->subscription_status_last), + gsd_subman_subscription_status_to_string (priv->subscription_status)); + +- /* needs registration */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID) { +- _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ /* needs subscription */ ++ if (is_registered && needs_subscriptions && !has_subscriptions) { ++ _show_notification (manager, _NOTIFY_EXPIRED); + return; + } + + /* was unregistered */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ if (was_registered && !is_registered) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } + +- /* registered */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- g_timer_elapsed (priv->timer_last_notified, NULL) > 60) { +- _show_notification (manager, _NOTIFY_REGISTERED); +- return; ++ /* just registered */ ++ if (!was_registered && is_registered) { ++ if (!needs_subscriptions || has_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } ++ } ++ ++ /* subscriptions changed */ ++ if (was_registered && is_registered) { ++ /* subscribed */ ++ if (!had_subscriptions && ++ needs_subscriptions && has_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } ++ ++ /* simple content access enabled */ ++ if (needed_subscriptions && !had_subscriptions && !needs_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } + } + } + + /* nag again */ +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && ++ if (!is_registered && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID && +- g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { +- _show_notification (manager, _NOTIFY_EXPIRED); +- return; +- } +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID && ++ if (is_registered && !has_subscriptions && needs_subscriptions && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_EXPIRED); + return; +@@ -941,6 +1036,8 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + + priv->installed_products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); + priv->timer_last_notified = g_timer_new (); ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ; ++ priv->subscription_status_last = GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ; + + /* expired */ + priv->notification_expired = +-- +2.31.1 + + +From e4ecab298c016127ab75634e1e04c6ff4eab3c4e Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 12 Feb 2021 14:51:29 +0100 +Subject: [PATCH 16/19] subman: Update POTFILES.in + +--- + po/POTFILES.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/po/POTFILES.in b/po/POTFILES.in +index e721f526..7d5b7e9d 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -24,6 +24,8 @@ plugins/print-notifications/gsd-printer.c + plugins/print-notifications/gsd-print-notifications-manager.c + plugins/smartcard/gsd-smartcard-manager.c + plugins/smartcard/gsd-smartcard-service.c ++plugins/subman/gsd-subscription-manager.c ++plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in + plugins/usb-protection/gsd-usb-protection-manager.c + plugins/wacom/gsd-wacom-manager.c + plugins/wacom/org.gnome.settings-daemon.plugins.wacom.policy.in.in +-- +2.31.1 + + +From 0da1131d81b5ddee23d5afe9c21e8c0963180cc5 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Mon, 6 Sep 2021 21:31:14 +0200 +Subject: [PATCH 17/19] subman: Don't force X11 backend + +All of this should work just fine with Wayland. +--- + plugins/subman/main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/plugins/subman/main.c b/plugins/subman/main.c +index 28ac995b..839c1b79 100644 +--- a/plugins/subman/main.c ++++ b/plugins/subman/main.c +@@ -2,7 +2,6 @@ + #define START gsd_subscription_manager_start + #define STOP gsd_subscription_manager_stop + #define MANAGER GsdSubscriptionManager +-#define GDK_BACKEND "x11" + #include "gsd-subscription-manager.h" + + #include "daemon-skeleton-gtk.h" +-- +2.31.1 + + +From 7b2f231fd6c87ca929bdd099177c53b14ccaaad5 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Tue, 7 Sep 2021 13:08:12 +0200 +Subject: [PATCH 18/19] subman: Fix desktop file hint for notifications + +We don't have a separate subman-panel. It's all part of +info-overview-panel, as of now at least. +--- + plugins/subman/gsd-subscription-manager.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index aaccbbc6..be978fc3 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -1045,7 +1045,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + _("Add or renew a subscription to continue receiving software updates."), + NULL); + notify_notification_set_app_name (priv->notification_expired, _("Subscription")); +- notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_expired, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_expired, NOTIFY_URGENCY_CRITICAL); + notify_notification_add_action (priv->notification_expired, +@@ -1061,7 +1061,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + _("The system has been registered and software updates have been enabled."), + NULL); + notify_notification_set_app_name (priv->notification_registered, _("Subscription")); +- notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_registered, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_registered, NOTIFY_URGENCY_CRITICAL); + g_signal_connect (priv->notification_registered, "closed", +@@ -1073,7 +1073,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + _("Please register your system to receive software updates."), + NULL); + notify_notification_set_app_name (priv->notification_registration_required, _("Subscription")); +- notify_notification_set_hint_string (priv->notification_registration_required, "desktop-entry", "subman-panel"); ++ notify_notification_set_hint_string (priv->notification_registration_required, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_registration_required, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_registration_required, NOTIFY_URGENCY_CRITICAL); + notify_notification_add_action (priv->notification_registration_required, +-- +2.31.1 + + +From b610a954773262e60610c7732fbfeddbb3fa7fa0 Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Wed, 8 Sep 2021 13:25:07 +0200 +Subject: [PATCH 19/19] subman: Use preferences-system icon for notifications + +Use it as a placeholder until we get a new icon for subscription +management. +--- + plugins/subman/gsd-subscription-manager.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index be978fc3..dbb81098 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -1043,7 +1043,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + priv->notification_expired = + notify_notification_new (_("Subscription Has Expired"), + _("Add or renew a subscription to continue receiving software updates."), +- NULL); ++ "preferences-system"); + notify_notification_set_app_name (priv->notification_expired, _("Subscription")); + notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_expired, "x-gnome-privacy-scope", "system"); +@@ -1059,7 +1059,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + priv->notification_registered = + notify_notification_new (_("Registration Successful"), + _("The system has been registered and software updates have been enabled."), +- NULL); ++ "preferences-system"); + notify_notification_set_app_name (priv->notification_registered, _("Subscription")); + notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_registered, "x-gnome-privacy-scope", "system"); +@@ -1071,7 +1071,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + priv->notification_registration_required = + notify_notification_new (_("System Not Registered"), + _("Please register your system to receive software updates."), +- NULL); ++ "preferences-system"); + notify_notification_set_app_name (priv->notification_registration_required, _("Subscription")); + notify_notification_set_hint_string (priv->notification_registration_required, "desktop-entry", "gnome-info-overview-panel"); + notify_notification_set_hint_string (priv->notification_registration_required, "x-gnome-privacy-scope", "system"); +-- +2.31.1 + diff --git a/SPECS/gnome-settings-daemon.spec b/SPECS/gnome-settings-daemon.spec new file mode 100644 index 0000000..1d2d892 --- /dev/null +++ b/SPECS/gnome-settings-daemon.spec @@ -0,0 +1,1510 @@ +%global glib2_version 2.56 +%global colord_version 1.4.5 +%global geocode_glib_version 3.10.0 +%global gnome_desktop_version 3.37.1 +%global gsettings_desktop_schemas_version 40 +%global gtk3_version 3.15.3 +%global libgweather_version 40~alpha +%global geoclue_version 2.3.1 + +%global tarball_version %%(echo %{version} | tr '~' '.') + +Name: gnome-settings-daemon +Version: 40.0.1 +Release: 6%{?dist} +Summary: The daemon sharing settings from GNOME to GTK+/KDE applications + +License: GPLv2+ +URL: https://download.gnome.org/sources/%{name} +Source0: https://download.gnome.org/sources/%{name}/40/%{name}-%{tarball_version}.tar.xz +Source1: org.gnome.settings-daemon.plugins.power.gschema.override + +BuildRequires: meson >= 0.44.0 +BuildRequires: gcc +BuildRequires: cups-devel +BuildRequires: gettext +BuildRequires: perl-interpreter +BuildRequires: pkgconfig(alsa) +BuildRequires: pkgconfig(colord) >= %{colord_version} +BuildRequires: pkgconfig(fontconfig) +BuildRequires: pkgconfig(gcr-base-3) +BuildRequires: pkgconfig(geoclue-2.0) >= %{geoclue_version} +BuildRequires: pkgconfig(geocode-glib-1.0) >= %{geocode_glib_version} +BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version} +BuildRequires: pkgconfig(gnome-desktop-3.0) >= %{gnome_desktop_version} +BuildRequires: pkgconfig(gsettings-desktop-schemas) >= %{gsettings_desktop_schemas_version} +BuildRequires: pkgconfig(gtk+-3.0) >= %{gtk3_version} +BuildRequires: pkgconfig(gudev-1.0) +BuildRequires: pkgconfig(gweather-3.0) >= %{libgweather_version} +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(lcms2) >= 2.2 +BuildRequires: pkgconfig(libcanberra-gtk3) +BuildRequires: pkgconfig(libgeoclue-2.0) +BuildRequires: pkgconfig(libnm) +BuildRequires: pkgconfig(libnotify) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(libpulse-mainloop-glib) +BuildRequires: pkgconfig(librsvg-2.0) +BuildRequires: pkgconfig(mm-glib) +BuildRequires: pkgconfig(nss) +BuildRequires: pkgconfig(polkit-gobject-1) +BuildRequires: pkgconfig(upower-glib) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xi) +BuildRequires: pkgconfig(wayland-client) +%ifnarch s390 s390x +BuildRequires: pkgconfig(libwacom) >= 0.7 +BuildRequires: pkgconfig(xorg-wacom) +%endif + +Requires: colord >= %{colord_version} +Requires: iio-sensor-proxy +Requires: geoclue2 >= %{geoclue_version} +Requires: geocode-glib%{?_isa} >= %{geocode_glib_version} +Requires: glib2%{?_isa} >= %{glib2_version} +Requires: gnome-desktop3%{?_isa} >= %{gnome_desktop_version} +Requires: gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version} +Requires: gtk3%{?_isa} >= %{gtk3_version} +Requires: libgweather%{?_isa} >= %{libgweather_version} + +Patch00001: 0001-power-Enable-power-saver-profile-when-low-on-battery.patch +Patch00002: subscription-manager-support.patch + +%description +A daemon to share settings from GNOME to other applications. It also +handles global keybindings, as well as a number of desktop-wide settings. + +%package devel +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%prep +%autosetup -p1 -n %{name}-%{tarball_version} + +%build +%meson +%meson_build + +%install +%meson_install + +cp %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas + +%find_lang %{name} --with-gnome + +%files -f %{name}.lang +%license COPYING +%doc AUTHORS NEWS + +# list daemons explicitly, so we notice if one goes missing +# some of these don't have a separate gschema +%{_libexecdir}/gsd-datetime +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Datetime.desktop + +%{_libexecdir}/gsd-housekeeping +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Housekeeping.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.housekeeping.gschema.xml + +%{_libexecdir}/gsd-keyboard +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Keyboard.desktop + +%{_libexecdir}/gsd-media-keys +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.MediaKeys.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.media-keys.gschema.xml + +%{_libexecdir}/gsd-backlight-helper +%{_datadir}/polkit-1/actions/org.gnome.settings-daemon.plugins.power.policy +%{_libexecdir}/gsd-power +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Power.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.power.gschema.xml +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.power.gschema.override + +%{_libexecdir}/gsd-print-notifications +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.PrintNotifications.desktop +%{_libexecdir}/gsd-printer + +%{_libexecdir}/gsd-rfkill +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Rfkill.desktop + +%{_libexecdir}/gsd-screensaver-proxy +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.ScreensaverProxy.desktop + +%{_libexecdir}/gsd-smartcard +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Smartcard.desktop + +%{_libexecdir}/gsd-sound +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Sound.desktop + +%{_libexecdir}/gsd-usb-protection +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.UsbProtection.desktop + +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.peripherals.gschema.xml +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.peripherals.wacom.gschema.xml +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Wacom.desktop + +%ifnarch s390 s390x +%{_libexecdir}/gsd-wacom +%{_libexecdir}/gsd-wacom-oled-helper +%{_datadir}/polkit-1/actions/org.gnome.settings-daemon.plugins.wacom.policy +%endif + +%{_libexecdir}/gsd-xsettings +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.XSettings.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.xsettings.gschema.xml + +%{_libexecdir}/gsd-a11y-settings +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.A11ySettings.desktop + +%{_libexecdir}/gsd-color +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Color.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.color.gschema.xml + +%{_libexecdir}/gsd-sharing +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Sharing.desktop +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.sharing.gschema.xml + +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Wwan.desktop +%{_libexecdir}/gsd-wwan +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.wwan.gschema.xml + +%{_sysconfdir}/xdg/autostart/org.gnome.SettingsDaemon.Subscription.desktop +%{_libexecdir}/gsd-subman +%{_libexecdir}/gsd-subman-helper +%{_datadir}/polkit-1/actions/org.gnome.settings-daemon.plugins.subman.policy +%{_datadir}/polkit-1/rules.d/org.gnome.settings-daemon.plugins.subman.rules + +%dir %{_libdir}/gnome-settings-daemon-40 +%{_libdir}/gnome-settings-daemon-40/libgsd.so + +%{_sysconfdir}/xdg/Xwayland-session.d/00-xrdb +%{_userunitdir}/* +/usr/lib/udev/rules.d/*.rules +%{_datadir}/gnome-settings-daemon/ +%{_datadir}/GConf/gsettings/gnome-settings-daemon.convert + +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.enums.xml +%{_datadir}/glib-2.0/schemas/org.gnome.settings-daemon.plugins.gschema.xml + +%files devel +%{_includedir}/gnome-settings-daemon-40 +%{_libdir}/pkgconfig/gnome-settings-daemon.pc + +%changelog +* Mon Feb 14 2022 Ray Strode - 40.0.1-6 +- Update for non-deprecated subscription management API + Resolves: #2049734 + +* Wed Sep 08 2021 Kalev Lember - 40.0.1-5 +- Fix the icon shown for subscription manager notifications +- Related: #1937113 + +* Thu Sep 02 2021 Kalev Lember - 40.0.1-4 +- Forward port subscription manager support from RHEL 8 +- Resolves: #1937113 + +* Thu Aug 19 2021 Carlos Garnacho - 40.0.1-3 +- Backport power saving changes + Resolves: #1994476 + +* Mon Aug 09 2021 Mohan Boddu - 40.0.1-2 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Fri May 07 2021 Kalev Lember - 40.0.1-1 +- Update to 40.0.1 + +* Thu Apr 15 2021 Mohan Boddu - 40.0-2 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Mon Mar 22 2021 Kalev Lember - 40.0-1 +- Update to 40.0 +- Drop old obsoletes/conflicts + +* Mon Mar 15 2021 Kalev Lember - 40~rc-1 +- Update to 40.rc + +* Mon Feb 15 2021 Kalev Lember - 40~beta-2 +- Fix loading gtk modules +- Update versioned dependencies + +* Mon Feb 15 2021 Florian Müllner - 40~beta-1 +- Update to 40.beta + +* Mon Feb 15 2021 Florian Müllner - 40~alpha.1-1 +- Update to 40.alpha.1 + +* Tue Jan 26 2021 Fedora Release Engineering - 3.38.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Fri Oct 9 2020 Kalev Lember - 3.38.1-1 +- Update to 3.38.1 + +* Mon Sep 14 2020 Kalev Lember - 3.38.0-1 +- Update to 3.38.0 + +* Mon Sep 07 2020 Kalev Lember - 3.37.92-1 +- Update to 3.37.92 + +* Sat Aug 29 2020 Kalev Lember - 3.37.1-1 +- Update to 3.37.1 + +* Mon Aug 17 2020 Kalev Lember - 3.37.0-1 +- Update to 3.37.0 + +* Sat Aug 01 2020 Fedora Release Engineering - 3.36.1-3 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon Jul 27 2020 Fedora Release Engineering - 3.36.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Thu Apr 30 2020 Kalev Lember - 3.36.1-1 +- Update to 3.36.1 + +* Mon Mar 09 2020 Kalev Lember - 3.36.0-1 +- Update to 3.36.0 + +* Mon Mar 02 2020 Kalev Lember - 3.35.92-1 +- Update to 3.35.92 + +* Tue Feb 18 2020 Kalev Lember - 3.35.91-1 +- Update to 3.35.91 + +* Tue Jan 28 2020 Fedora Release Engineering - 3.35.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Jan 16 2020 Kalev Lember - 3.35.0-2 +- Rebuilt for libgnome-desktop soname bump + +* Tue Jan 07 2020 Kalev Lember - 3.35.0-1 +- Update to 3.35.0 + +* Mon Oct 14 2019 Kalev Lember - 3.34.1-1 +- Update to 3.34.1 + +* Mon Sep 09 2019 Kalev Lember - 3.34.0-1 +- Update to 3.34.0 + +* Fri Sep 06 2019 Kalev Lember - 3.33.92-1 +- Update to 3.33.92 + +* Mon Aug 26 2019 Kalev Lember - 3.33.90-1 +- Update to 3.33.90 +- Drop old versioned conflicts + +* Thu Jul 25 2019 Fedora Release Engineering - 3.33.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Sun Jul 21 2019 Kalev Lember - 3.33.0-3 +- Rebuilt for libgnome-desktop soname bump + +* Mon Jul 08 2019 Kalev Lember - 3.33.0-2 +- Rebuilt for libgweather soname bump + +* Tue Jun 25 2019 Kalev Lember - 3.33.0-1 +- Update to 3.33.0 + +* Wed Jun 19 2019 Kalev Lember - 3.32.1-1 +- Update to 3.32.1 + +* Tue May 28 2019 Marek Kasik - 3.32.0-2 +- Fix NSS crash at smartcard plugin (#1688791) + +* Mon Mar 11 2019 Kalev Lember - 3.32.0-1 +- Update to 3.32.0 + +* Wed Mar 06 2019 Kalev Lember - 3.31.92-1 +- Update to 3.31.92 + +* Wed Feb 20 2019 Kalev Lember - 3.31.91-1 +- Update to 3.31.91 + +* Wed Feb 06 2019 Kalev Lember - 3.31.90-1 +- Update to 3.31.90 + +* Thu Jan 31 2019 Fedora Release Engineering - 3.31.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Wed Jan 09 2019 Kalev Lember - 3.31.2-1 +- Update to 3.31.2 + +* Tue Nov 20 2018 Pete Walter - 3.30.1.2-3 +- Move gnome-remote-desktop recommends to gnome-control-center + +* Fri Nov 09 2018 Ray Strode - 3.30.1.2-2 +- Add recommends for gnome-remote-desktop after irc discussion + +* Thu Oct 04 2018 Kalev Lember - 3.30.1.2-1 +- Update to 3.30.1.2 + +* Fri Sep 28 2018 Kalev Lember - 3.30.1.1-1 +- Update to 3.30.1.1 + +* Thu Sep 06 2018 Kalev Lember - 3.30.0-1 +- Update to 3.30.0 + +* Sun Aug 12 2018 Kalev Lember - 3.29.90.1-1 +- Update to 3.29.90.1 + +* Tue Jul 31 2018 Florian Weimer - 3.28.1-3 +- Rebuild with fixed binutils + +* Fri Jul 13 2018 Fedora Release Engineering - 3.28.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Apr 12 2018 Kalev Lember - 3.28.1-1 +- Update to 3.28.1 + +* Tue Apr 10 2018 Michael Catanzaro - 3.28.0-2 +- Disable automatic suspend, except when on battery power + +* Mon Mar 12 2018 Kalev Lember - 3.28.0-1 +- Update to 3.28.0 + +* Mon Mar 05 2018 Kalev Lember - 3.27.92-1 +- Update to 3.27.92 + +* Fri Mar 02 2018 Kalev Lember - 3.27.91-1 +- Update to 3.27.91 + +* Sat Feb 10 2018 Bastien Nocera - 3.27.90-4 ++ gnome-settings-daemon-3.27.90-4 +- Rebuild against newer gnome-desktop3 package + +* Fri Feb 09 2018 Bastien Nocera - 3.27.90-3 ++ gnome-settings-daemon-3.27.90-3 +- Really fix gsd-* helper linkage +- Build fix for highly parallel builds + +* Wed Feb 07 2018 Kalev Lember - 3.27.90-2 +- Fix missing libcommon.so library + +* Tue Feb 06 2018 Kalev Lember - 3.27.90-1 +- Update to 3.27.90 +- Switch to meson build system + +* Mon Feb 05 2018 Kalev Lember - 3.26.2-5 +- Rebuilt for libgweather soname bump + +* Sat Jan 20 2018 Björn Esser - 3.26.2-4 +- Rebuilt for switch to libxcrypt + +* Fri Jan 12 2018 Bastien Nocera - 3.26.2-3 +- Fix gdm session trying to change the backlight, resulting in a lot + of spurious error messages (#1322588) + +* Fri Jan 05 2018 Igor Gnatenko - 3.26.2-2 +- Remove obsolete scriptlets + +* Thu Nov 02 2017 Kalev Lember - 3.26.2-1 +- Update to 3.26.2 + +* Sun Oct 08 2017 Kalev Lember - 3.26.1-1 +- Update to 3.26.1 + +* Wed Sep 13 2017 Kalev Lember - 3.26.0-1 +- Update to 3.26.0 + +* Tue Sep 05 2017 Kalev Lember - 3.25.92-1 +- Update to 3.25.92 + +* Thu Aug 24 2017 Kalev Lember - 3.25.91-1 +- Update to 3.25.91 + +* Tue Aug 15 2017 Kalev Lember - 3.25.90-1 +- Update to 3.25.90 + +* Mon Jul 31 2017 Kalev Lember - 3.25.4-2 +- Add explicit conflicts to not break older gdm, gnome-session and gnome-shell + +* Mon Jul 31 2017 Kalev Lember - 3.25.4-1 +- Update to 3.25.4 + +* Wed Jul 26 2017 Fedora Release Engineering - 3.25.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Mon Jun 12 2017 Kalev Lember - 3.25.2-1 +- Update to 3.25.2 + +* Wed May 10 2017 Kalev Lember - 3.24.2-1 +- Update to 3.24.2 + +* Wed Apr 12 2017 Kalev Lember - 3.24.1-1 +- Update to 3.24.1 + +* Tue Mar 21 2017 Kalev Lember - 3.24.0-1 +- Update to 3.24.0 + +* Thu Mar 16 2017 Kalev Lember - 3.23.92-1 +- Update to 3.23.92 + +* Wed Feb 15 2017 Richard Hughes - 3.23.90-1 +- Update to 3.23.90 + +* Fri Feb 10 2017 Fedora Release Engineering - 3.23.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Bastien Nocera - 3.23.3-1 ++ gnome-settings-daemon-3.23.3-1 +- Update to 3.23.3 + +* Tue Oct 11 2016 Bastien Nocera - 3.23.2-1 ++ gnome-settings-daemon-3.23.2-1 +- Update to 3.23.2 + +* Thu Sep 22 2016 Kalev Lember - 3.22.0-1 +- Update to 3.22.0 + +* Wed Sep 14 2016 Kalev Lember - 3.21.92.1-1 +- Update to 3.21.92.1 + +* Wed Sep 14 2016 Kalev Lember - 3.21.92-1 +- Update to 3.21.92 +- Don't set group tags + +* Fri Aug 26 2016 Kalev Lember - 3.21.90-1 +- Update to 3.21.90 + +* Sun Apr 17 2016 Bastien Nocera - 3.20.1-3 +- Fix crasher in newly enabled audio device selection dialogue + +* Sun Apr 17 2016 Bastien Nocera - 3.20.1-2 +- Require alsa to enable the audio device selection dialogue + +* Wed Apr 13 2016 Kalev Lember - 3.20.1-1 +- Update to 3.20.1 + +* Tue Mar 22 2016 Kalev Lember - 3.20.0-1 +- Update to 3.20.0 + +* Thu Mar 17 2016 Kalev Lember - 3.19.92-1 +- Update to 3.19.92 + +* Fri Mar 04 2016 Kalev Lember - 3.19.91-1 +- Update to 3.19.91 + +* Wed Feb 17 2016 Richard Hughes - 3.19.90-1 +- Update to 3.19.90 + +* Wed Feb 03 2016 Fedora Release Engineering - 3.19.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jan 20 2016 Kalev Lember - 3.19.5-1 +- Update to 3.19.5 + +* Thu Dec 17 2015 Kalev Lember - 3.19.4-1 +- Update to 3.19.4 + +* Tue Dec 15 2015 Kalev Lember - 3.19.3-1 +- Update to 3.19.3 + +* Tue Nov 10 2015 Kalev Lember - 3.18.2-1 +- Update to 3.18.2 + +* Mon Oct 12 2015 Kalev Lember - 3.18.1-1 +- Update to 3.18.1 + +* Mon Sep 21 2015 Kalev Lember - 3.18.0-1 +- Update to 3.18.0 + +* Mon Sep 14 2015 Kalev Lember - 3.17.92-1 +- Update to 3.17.92 + +* Mon Aug 17 2015 Kalev Lember - 3.17.90-1 +- Update to 3.17.90 +- Use make_install macro + +* Wed Jul 22 2015 David King - 3.17.3-1 +- Update to 3.17.3 +- Use pkgconfig for BuildRequires + +* Wed Jun 17 2015 Fedora Release Engineering - 3.17.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Thu Jun 11 2015 Richard Hughes - 3.17.2-2 +- Add runtime dep on iio-sensor-proxy for the ambient light sensor + +* Fri Jun 05 2015 Kalev Lember - 3.17.2-1 +- Update to 3.17.2 + +* Tue May 12 2015 Kalev Lember - 3.16.2-1 +- Update to 3.16.2 + +* Tue Apr 14 2015 Kalev Lember - 3.16.1-1 +- Update to 3.16.1 + +* Mon Mar 23 2015 Kalev Lember - 3.16.0-1 +- Update to 3.16.0 + +* Tue Mar 17 2015 Kalev Lember - 3.15.92-1 +- Update to 3.15.92 + +* Tue Mar 03 2015 Kalev Lember - 3.15.91-1 +- Update to 3.15.91 +- Use the %%license macro for the COPYING file + +* Tue Feb 17 2015 Richard Hughes - 3.15.90-1 +- Update to 3.15.90 + +* Thu Jan 22 2015 Richard Hughes - 3.15.4-1 +- Update to 3.15.4 + +* Thu Nov 27 2014 Kalev Lember - 3.15.1-1 +- Update to 3.15.1 + +* Tue Nov 11 2014 Kalev Lember - 3.14.2-1 +- Update to 3.14.2 + +* Sat Nov 01 2014 Richard Hughes - 3.14.1-3 +- Fix compile on RHEL + +* Sun Oct 26 2014 Kalev Lember - 3.14.1-2 +- Obsolete drwright + +* Tue Oct 14 2014 Rui Matos - 3.14.1-1 +- Update to 3.14.1 + +* Mon Sep 22 2014 Kalev Lember - 3.14.0-1 +- Update to 3.14.0 + +* Tue Sep 16 2014 Kalev Lember - 3.13.92-1 +- Update to 3.13.92 + +* Wed Sep 03 2014 Kalev Lember - 3.13.91-1 +- Update to 3.13.91 + +* Mon Aug 18 2014 Kalev Lember - 3.13.90-1 +- Update to 3.13.90 + +* Sat Aug 16 2014 Fedora Release Engineering - 3.13.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Wed Jul 23 2014 Kalev Lember - 3.13.4-1 +- Update to 3.13.4 + +* Thu Jun 26 2014 Richard Hughes - 3.13.3-1 +- Update to 3.13.3 + +* Wed Jun 25 2014 Richard Hughes - 3.13.2-1 +- Update to 3.13.2 + +* Sat Jun 07 2014 Fedora Release Engineering - 3.13.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Thu May 01 2014 Kalev Lember - 3.13.1-1 +- Update to 3.13.1 +- Remove and obsolete the updates plugin + +* Wed Apr 16 2014 Kalev Lember - 3.12.1-1 +- Update to 3.12.1 +- Tighten subpackage deps + +* Mon Apr 14 2014 Kalev Lember - 3.12.0.1-3 +- Drop control-center-filesystem dependency + +* Sat Apr 05 2014 Kalev Lember - 3.12.0.1-2 +- Update dep versions + +* Wed Mar 26 2014 Richard Hughes - 3.12.0.1-1 +- Update to 3.12.0.1 + +* Mon Mar 24 2014 Richard Hughes - 3.12.0-1 +- Update to 3.12.0 + +* Tue Mar 18 2014 Richard Hughes - 3.11.92-1 +- Update to 3.11.92 + +* Tue Mar 04 2014 Richard Hughes - 3.11.91-1 +- Update to 3.11.91 + +* Wed Feb 19 2014 Richard Hughes - 3.11.90-2 +- Rebuilt for gnome-desktop soname bump + +* Tue Feb 18 2014 Richard Hughes - 3.11.90-1 +- Update to 3.11.90 + +* Tue Feb 04 2014 Richard Hughes - 3.11.5-1 +- Update to 3.11.5 + +* Thu Jan 30 2014 Richard Hughes - 3.11.3-2 +- Rebuild for libpackagekit-glib soname bump + +* Tue Dec 17 2013 Richard Hughes - 3.11.3-1 +- Update to 3.11.3 + +* Mon Nov 25 2013 Richard Hughes - 3.11.2-1 +- Update to 3.11.2 + +* Thu Oct 31 2013 Florian Müllner - 3.11.1-1 +- Update to 3.11.1 + +* Mon Oct 28 2013 Richard Hughes - 3.10.1-1 +- Update to 3.10.1 + +* Fri Oct 11 2013 Richard Hughes - 3.10.0-3 +- Apply the previous patch on Fedora too. + +* Fri Oct 11 2013 Richard Hughes - 3.10.0-2 +- Grab a patch from upstream to fix the multiple notifications about updates. +- Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1009132 + +* Tue Sep 24 2013 Kalev Lember - 3.10.0-1 +- Update to 3.10.0 + +* Wed Sep 18 2013 Kalev Lember - 3.9.92-1 +- Update to 3.9.92 + +* Tue Sep 17 2013 Richard Hughes - 3.9.91.1-2 +- Grab a patch from upstream so that the offline updates feature can + actually work when reboot returns with success. + +* Tue Sep 03 2013 Matthias Clasen - 3.9.91.1-1 +- Update to 3.9.91.1 + +* Tue Sep 03 2013 Kalev Lember - 3.9.91-1 +- Update to 3.9.91 +- Include the new datetime plugin + +* Fri Aug 23 2013 Kalev Lember - 3.9.90-2 +- Keep middle click paste enabled for now + +* Thu Aug 22 2013 Kalev Lember - 3.9.90-1 +- Update to 3.9.90 + +* Fri Aug 09 2013 Kalev Lember - 3.9.5-1 +- Update to 3.9.5 +- Remove empty /etc/gnome-settings-daemon directory +- Install new rfkill plugin and add back the smartcard plugin + +* Tue Jul 30 2013 Richard Hughes - 3.9.3-3 +- Rebuild for colord soname bump + +* Mon Jul 22 2013 Bastien Nocera 3.9.3-2 +- Remove obsolete GStreamer 0.10 BRs + +* Thu Jun 20 2013 Kalev Lember - 3.9.3-1 +- Update to 3.9.3 + +* Sun Jun 02 2013 Kalev Lember - 3.9.2-1 +- Update to 3.9.2 +- Drop the ibus-kkc-libpinyin patch; the hardcoded input sources + list is gone from g-s-d +- Set the minimum required gnome-desktop3 version + +* Tue May 14 2013 Richard Hughes - 3.8.2-1 +- Update to 3.8.2 + +* Thu May 9 2013 Jens Petersen - 3.8.1-2 +- default ibus engine in Fedora is now kkc for Japanese + and libpinyin for Chinese (#948117) + +* Tue Apr 16 2013 Richard Hughes - 3.8.1-1 +- Update to 3.8.1 + +* Tue Mar 26 2013 Richard Hughes - 3.8.0-1 +- Update to 3.8.0 + +* Tue Mar 19 2013 Matthias Clasen - 3.7.92-1 +- Update to 3.7.92 + +* Tue Mar 5 2013 Matthias Clasen - 3.7.91-1 +- Update to 3.7.91 + +* Wed Feb 20 2013 Richard Hughes - 3.7.90-1 +- Update to 3.7.90 + +* Thu Feb 07 2013 Richard Hughes - 3.7.5.1-1 +- Update to 3.7.5.1 + +* Wed Feb 06 2013 Debarshi Ray - 3.7.5-2 +- Bump the gtk3 BuildRequires + +* Tue Feb 05 2013 Richard Hughes - 3.7.5-1 +- Update to 3.7.5 + +* Wed Jan 16 2013 Richard Hughes - 3.7.4-1 +- Update to 3.7.4 + +* Mon Dec 31 2012 Dan Horák - 3.7.3-2 +- fix filelist for s390(x) (and ppc/ppc64 in RHEL) + +* Thu Dec 20 2012 Kalev Lember - 3.7.3-1 +- Update to 3.7.3 +- Adjust the spec file for the (temporarly) disabled smartcard plugin + +* Tue Nov 20 2012 Richard Hughes - 3.7.1-1 +- Update to 3.7.1 +- Remove upstreamed patches + +* Wed Nov 14 2012 Kalev Lember - 3.6.3-1 +- Update to 3.6.3 +- Drop the static man page patch and BR docbook-style-xsl instead + +* Thu Nov 08 2012 Bastien Nocera 3.6.2-1 +- Update to 3.6.2 + +* Thu Oct 18 2012 Matthias Clasen - 3.6.1-3 +- Fix a typo in the suspend patch (#858259) + +* Mon Oct 08 2012 Dan Horák - 3.6.1-2 +- fix build on s390(x) + +* Mon Oct 08 2012 Bastien Nocera 3.6.1-1 +- Update to 3.6.1 + +* Fri Oct 5 2012 Olivier Fourdan - 3.6.0-5 +- Adds Wacom OSD window from upstream bug #679062 + +* Wed Oct 3 2012 Matthias Clasen - 3.6.0-4 +- Fix an inhibitor leak in the previous patch + +* Tue Oct 2 2012 Matthias Clasen - 3.6.0-3 +- Fix lid close handling with new systemd + +* Fri Sep 28 2012 Peter Robinson - 3.6.0-2 +- Split out PackageKit into a sub package. Fixes #699348 + +* Tue Sep 25 2012 Richard Hughes - 3.6.0-1 +- Update to 3.6.0 + +* Wed Sep 19 2012 Richard Hughes - 3.5.92-1 +- Update to 3.5.92 + +* Wed Sep 05 2012 Cosimo Cecchi - 3.5.91-1 +- Update to 3.5.91 + +* Wed Aug 22 2012 Richard Hughes - 3.5.90-1 +- Update to 3.5.90 + +* Tue Aug 21 2012 Richard Hughes - 3.5.6-1 +- Update to 3.5.6 + +* Fri Jul 27 2012 Fedora Release Engineering - 3.5.5-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jul 24 2012 Dan Horák - 3.5.5-3 +- fix build without wacom + +* Thu Jul 19 2012 Matthias Clasen - 3.5.5-2 +- Fix the updates plugin to load + +* Thu Jul 19 2012 Matthias Clasen - 3.5.5-1 +- Update to 3.5.5 + +* Tue Jul 17 2012 Dan Horák - 3.5.4-3 +- fix build on s390(x) - cherry-picked from f17 branch +- allow build without wacom on ppc/ppc64 + +* Tue Jul 17 2012 Matthias Clasen - 3.5.4-2 +- Rebuild against new PackageKit + +* Wed Jun 27 2012 Richard Hughes - 3.5.4-1 +- Update to 3.5.4 + +* Tue Jun 26 2012 Richard Hughes - 3.5.3-1 +- Update to 3.5.3 + +* Thu Jun 14 2012 Matthias Clasen - 3.5.2-4 +- Drop calculator patch, no longer needed + +* Thu Jun 07 2012 Matthias Clasen - 3.5.2-3 +- Fix file lists + +* Thu Jun 07 2012 Richard Hughes - 3.5.2-2 +- Add missing BR + +* Wed Jun 06 2012 Richard Hughes - 3.5.2-1 +- Update to 3.5.2 + +* Fri May 18 2012 Richard Hughes - 3.4.2-1 +- Update to 3.4.2 + +* Mon Apr 16 2012 Richard Hughes - 3.4.1-1 +- Update to 3.4.1 + +* Mon Mar 26 2012 Richard Hughes - 3.4.0-1 +- New upstream version. + +* Tue Mar 20 2012 Richard Hughes 3.3.92-1 +- Update to 3.3.92 + +* Mon Mar 05 2012 Bastien Nocera 3.3.91-1 +- Update to 3.3.91 + +* Wed Feb 22 2012 Bastien Nocera 3.3.90.1-1 +- Update to 3.3.90.1 + +* Thu Feb 9 2012 Matthias Clasen 3.3.5-2 +- Use systemd for session tracking + +* Tue Feb 7 2012 Matthias Clasen 3.3.5-1 +- Update to 3.3.5 + +* Fri Jan 20 2012 Matthias Clasen 3.3.4-2 +- Some crash fixes + +* Tue Jan 17 2012 Bastien Nocera 3.3.4-1 +- Update to 3.3.4 + +* Fri Jan 13 2012 Fedora Release Engineering - 3.3.3.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 27 2011 Matthias Clasen - 3.3.3.1-2 +- Fix a path problem in the gnome-settings-daemon autostart file + +* Fri Dec 23 2011 Matthias Clasen - 3.3.3.1-1 +- Update to 3.3.3.1 + +* Wed Dec 21 2011 Matthias Clasen - 3.3.3-1 +- Update to 3.3.3 + +* Wed Nov 23 2011 Matthias Clasen - 3.3.2-1 +- Update to 3.3.2 + +* Fri Nov 11 2011 Bastien Nocera 3.2.2-1 +- Update to 3.2.2 + +* Wed Oct 26 2011 Fedora Release Engineering - 3.2.1-4 +- Rebuilt for glibc bug#747377 + +* Tue Oct 25 2011 Marek Kasik - 3.2.1-3 +- Fix a typo in registration of an object on DBus (#747318) + +* Mon Oct 24 2011 Matthias Clasen - 3.2.1-2 +- Fix calculator keybinding (#745367) + +* Mon Oct 17 2011 Bastien Nocera 3.2.1-1 +- Update to 3.2.1 + +* Wed Oct 12 2011 Adam Williamson - 3.2.0-2 +- backport some greatest hits from git to stop the same bugs being + reported over and over (all will be in 3.2.1) + +* Tue Sep 27 2011 Ray - 3.2.0-1 +- Update to 3.2.0 + +* Tue Sep 20 2011 Matthias Clasen - 3.1.92-1 +- Update to 3.1.92 + +* Tue Sep 6 2011 Matthias Clasen - 3.1.91-1 +- Update to 3.1.91 + +* Tue Jul 26 2011 Cosimo Cecchi - 3.1.4-2 +- Add a patch to make the fallback mounter to build correctly +- Include the new power plugin + +* Mon Jul 25 2011 Matthias Clasen - 3.1.4-1 +- Update to 3.1.4 + +* Fri Jul 22 2011 Tomas Bzatek - 3.1.3-2 +- Add support for chrony (#723212) + +* Mon Jul 04 2011 Bastien Nocera 3.1.3-1 +- Update to 3.1.3 + +* Tue Jun 21 2011 Tomas Bzatek - 3.1.2-2 +- Fix fortify fail in gsd-color-manager.c (#714625) + +* Wed Jun 15 2011 Tomas Bzatek - 3.1.2-1 +- Update to 3.1.2 + +* Wed Jun 15 2011 Bastien Nocera 3.1.1-3 +- Rebuild for new gnome-desktop3 libs + +* Mon Jun 13 2011 Marek Kasik 3.1.1-2 +- Remove requirement of system-config-printer-udev (#704381) + +* Wed May 11 2011 Tomas Bzatek - 3.1.1-1 +- Update to 3.1.1 + +* Sat May 07 2011 Christopher Aillon - 3.0.1-5 +- Update gsettings schema scriptlet + +* Mon May 2 2011 Matthias Clasen 3.0.1-4 +- Try to fix a crash (#698533) + +* Thu Apr 28 2011 Bastien Nocera 3.0.1-2 +- Fix setting ntpd usage with SystemD + +* Tue Apr 26 2011 Bastien Nocera 3.0.1-1 +- Update to 3.0.1 + +* Wed Apr 06 2011 Bastien Nocera 3.0.0.1-1 +- Update to 3.0.0.1 + +* Mon Apr 04 2011 Bastien Nocera 3.0.0-1 +- Update to 3.0.0 + +* Wed Mar 30 2011 Marek Kasik 2.91.93-2 +- Make CUPS' subscriptions expirable + +* Fri Mar 25 2011 Bastien Nocera 2.91.93-1 +- Update to 2.91.93 + +* Mon Mar 21 2011 Matthias Clasen 2.91.92-1 +- Update 2.91.92 + +* Wed Mar 16 2011 Richard Hughes 2.91.91-3 +- Add a patch from upstream to fix the updates plugin. + +* Fri Mar 11 2011 Bastien Nocera 2.91.91-2 +- Add libXxf86misc-devel requires so that key repeat/delay works + +* Tue Mar 08 2011 Bastien Nocera 2.91.91-1 +- Update to 2.91.91 + +* Fri Feb 25 2011 Matthias Clasen - 2.91.90-4 +- Fix undefined symbols in the updates plugin + +* Wed Feb 23 2011 Matthias Clasen - 2.91.90-3 +- BR PackageKit and cups +- Explicitly list plugins so we notice if they go missing + +* Wed Feb 23 2011 Cosimo Cecchi - 2.91.90-2 +- Include an upstream patch to fix a possible crasher + +* Tue Feb 22 2011 Matthias Clasen 2.91.90-1 +- Update to 2.91.90 + +* Wed Feb 16 2011 Bastien Nocera 2.91.9-6 +- Fix crasher when media keys GSettings value changes + +* Sun Feb 13 2011 Christopher Aillon - 2.91.9-5 +- Rebuild for new libxklavier + +* Fri Feb 11 2011 Matthias Clasen 2.91.9-4 +- Rebuild against newer gtk + +* Tue Feb 08 2011 Fedora Release Engineering - 2.91.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Feb 08 2011 Bastien Nocera 2.91.9-2 +- Fix setting timezones in the date & time panel (#674999) + +* Wed Feb 2 2011 Matthias Clasen 2.91.9-1 +- 2.91.9 + +* Tue Jan 11 2011 Matthias Clasen 2.91.8-1 +- 2.91.8 + +* Tue Jan 11 2011 Matthias Clasen 2.91.7-2 +- Own %%{_libdir}/gnome-settings-daemon-3.0/gtk-modules + +* Mon Jan 10 2011 Matthias Clasen 2.91.7-1 +- Update to 2.91.7 + +* Sat Jan 8 2011 Matthias Clasen 2.91.6.2-1 +- Update to 2.91.6.2 + +* Fri Dec 3 2010 Matthias Clasen 2.91.5.1-1 +- Update to 2.91.5.1 + +* Thu Dec 2 2010 Dan Williams - 2.91.5-4 +- Re-add patch handling org.gnome.media-handling gsettings schema rename + +* Wed Dec 1 2010 Dan Williams - 2.91.5-3 +- Fix various cases of forgetting to draw the background + +* Tue Nov 30 2010 Owen Taylor - 2.91.5-2 +- Add a patch handling org.gnome.media-handling gsettings schema rename + +* Tue Nov 30 2010 Tomas Bzatek 2.91.5-1 +- Update to 2.91.5 + +* Fri Nov 26 2010 Bastien Nocera 2.91.4-2 +- Fix crasher on startup + +* Thu Nov 25 2010 Bastien Nocera 2.91.4-1 +- Update to 2.91.4 + +* Wed Nov 17 2010 Richard Hughes 2.91.3-1 +- Update to 2.91.3 + +* Wed Nov 10 2010 Bastien Nocera 2.91.2.1-0.4. +- Update to 2.91.2.1 + +* Wed Nov 3 2010 Matthias Clasen 2.91.2-0.4.20101102 +- Rebuild against new libnotify + +* Tue Nov 2 2010 Matthias Clasen 2.91.2-0.3.20101102 +- Make theme changing work + +* Tue Nov 02 2010 Richard Hughes 2.91.2-0.2.20101102 +- Add BR gsettings-desktop-schemas-devel + +* Tue Nov 02 2010 Richard Hughes 2.91.2-0.1.20101102 +- Update to a git snapshot to fix rawhide. + +* Wed Oct 06 2010 Richard Hughes 2.91.0-3 +- Fix the pkgconfig file manually + +* Wed Oct 06 2010 Richard Hughes 2.91.0-2 +- Rebuild against the new libgnomekbd library + +* Mon Oct 4 2010 Matthias Clasen - 2.91.0-1 +- Update to 2.91.0 + +* Wed Sep 29 2010 jkeating - 2.90.1-2 +- Rebuilt for gcc bug 634757 + +* Wed Sep 22 2010 Bastien Nocera 2.90.1-1 +- Update to 2.90.1 + +* Tue Aug 31 2010 Matthias Clasen 2.31.91-1 +- Update to 2.31.91 + +* Fri Aug 27 2010 Matthias Clasen 2.31.6-2 +- Fix a problem with warning bubbles in virtual machines (#624624) + +* Tue Aug 3 2010 Matthias Clasen 2.31.6-1 +- Update to 2.31.6 + +* Tue Jul 13 2010 Matthias Clasen 2.31.5.1-1 +- Update to 2.31.5.1 + +* Mon Jul 12 2010 Matthias Clasen 2.31.5-1 +- Update to 2.31.5 + +* Wed Jun 30 2010 Matthias Clasen 2.31.4.2-1 +- Update to 2.31.4.2 + +* Tue Jun 29 2010 Matthias Clasen 2.31.4.1-1 +- Update to 2.31.4.1 + +* Tue Jun 29 2010 Matthias Clasen 2.31.4-1 +- Update to 2.31.4 + +* Mon Jun 28 2010 Bastien Nocera 2.31.3-3 +- Don't remove the sound plugin if we want the caches to be + updated + +* Tue Jun 8 2010 Matthias Clasen 2.31.3-1 +- Update to 2.31.3 + +* Thu May 27 2010 Matthias Clasen 2.31.2-1 +- Update to 2.31.2 + +* Sun May 16 2010 Matthias Clasen 2.31.1-1 +- Update to 2.31.1 + +* Fri Apr 30 2010 Matthias Clasen 2.30.1-4 +- Waah, one more mistake in these macros + +* Tue Apr 27 2010 Matthias Clasen 2.30.1-3 +- Nobody understands macro processors... + +* Tue Apr 27 2010 Matthias Clasen 2.30.1-2 +- Fix a typo + +* Mon Apr 26 2010 Matthias Clasen 2.30.1-1 +- Update to 2.30.1 +- Spec file cleanups + +* Mon Mar 29 2010 Matthias Clasen 2.30.0-1 +- Update to 2.30.0 + +* Mon Mar 22 2010 Bastien Nocera 2.29.92-3 +- Disable the font plugin by default + +* Wed Mar 10 2010 Bastien Nocera 2.29.92-2 +- Remove unneeded icons, already upstream + +* Tue Mar 09 2010 Bastien Nocera 2.29.92-1 +- Update to 2.29.92 + +* Sat Feb 27 2010 Matthias Clasen 2.29.91.1-2 +- Fix Fn-F8 OSD icon +- Modernize scriptlets + +* Wed Feb 24 2010 Matthias Clasen 2.29.91.1-1 +- Update to 2.29.91.1 + +* Wed Feb 17 2010 Matthias Clasen 2.29.90-2 +- Set a name for the keyboard statusicon + +* Wed Feb 10 2010 Tomas Bzatek 2.29.90-1 +- Update to 2.29.90 + +* Tue Jan 26 2010 Matthias Clasen 2.29.6-1 +- Update to 2.29.6 + +* Fri Dec 18 2009 Matthias Clasen 2.28.1-10 +- Avoid warning messages from the OSD code + +* Tue Dec 15 2009 Matthias Clasen 2.28.1-9 +- Survive when running without XKB (#547780) + +* Thu Nov 12 2009 Matthias Clasen 2.28.1-8 +- Avoid a 'whitespace leak' around the display statusicon (gnome #601696) + +* Mon Nov 9 2009 Matthias Clasen 2.28.1-7 +- React to screen changes when showing the background (gnome #601203) + +* Thu Nov 05 2009 Bastien Nocera 2.28.1-6 +- Fix the volume going over 100% in the OSD + +* Wed Oct 28 2009 Bastien Nocera 2.28.1-5 +- Update OSD code again + +* Tue Oct 27 2009 Bastien Nocera 2.28.1-4 +- Fix bluriness in OSD + +* Mon Oct 26 2009 Matthias Clasen - 2.28.1-3 +- Change default font rendering to use slight hinting + +* Mon Oct 26 2009 Peter Hutterer 2.28.1-2 +- left-handed-touchpad.patch: change physical touchpad buttons to + left-handed, not tapping though (#498249) + +* Mon Oct 19 2009 Matthias Clasen - 2.28.1-1 +- Update to 2.28.1 + +* Thu Oct 1 2009 Matthias Clasen - 2.28.0-4 +- Fix keyboard variant handling + +* Fri Sep 25 2009 Matthias Clasen - 2.28.0-3 +- Align the OSD visuals with the notification theme + +* Tue Sep 22 2009 Adam Jackson 2.28.0-2 +- BuildRequires: libcanberra-devel + +* Mon Sep 21 2009 Matthias Clasen - 2.28.0-1 +- Update to 2.28.0 + +* Wed Sep 09 2009 Bastien Nocera 2.27.92-2 +- Update left-hand touchpad patch + +* Mon Sep 7 2009 Matthias Clasen - 2.27.92-1 +- Update to 2.27.92 + +* Sun Aug 30 2009 Matthias Clasen - 2.27.91-3 +- Make 'Locate Pointer' work with metacity again + +* Wed Aug 26 2009 Peter Hutterer 2.27.91-2 +- buttonmapping.patch: Don't check for IsXExtensionDevice, only skip button + mappings for core devices instead (#502129). + +* Mon Aug 24 2009 Bastien Nocera 2.27.91-1 +- Update to 2.27.91 + +* Fri Aug 14 2009 Bastien Nocera 2.27.90-2 +- Update gnome-volume-control code + +* Fri Aug 14 2009 Bastien Nocera 2.27.90-1 +- Update to 2.27.90 + +* Tue Jul 28 2009 Matthias Clasen 2.27.5-1 +- Update to 2.27.5 + +* Fri Jul 24 2009 Fedora Release Engineering - 2.27.4-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jul 21 2009 Matthias Clasen 2.27.4-3 +- Make locate-pointer not interfere with media keys + +* Wed Jul 15 2009 Matthias Clasen 2.27.4-2 +- Rebuild against new libgnomekbd + +* Tue Jul 14 2009 Matthias Clasen 2.27.4-1 +- Update ot 2.27.4 + +* Tue Jun 30 2009 Matthias Clasen 2.27.3-2 +- Rebuild against new libxklavier + +* Tue Jun 16 2009 Matthias Clasen 2.27.3-1 +- Update to 2.27.3 + +* Mon Jun 8 2009 Matthias Clasen 2.27.1-2 +- Make the 'locate pointer' effect cope with changing compositing + managers + +* Sat May 16 2009 Matthias Clasen 2.27.1-1 +- Update to 2.27.1 + +* Fri May 08 2009 Bastien Nocera 2.26.1-4 +- Remove useless patch, see: +http://bugzilla.gnome.org/show_bug.cgi?id=580761 for details + +* Wed Apr 29 2009 Bastien Nocera 2.26.1-3 +- Don't set touchpads to be left-handed, otherwise the tap + behaves like the 2nd mouse button (#483639) + +* Mon Apr 27 2009 Matthias Clasen - 2.26.1-2 +- Don't drop schemas translations from po files + +* Tue Apr 14 2009 Matthias Clasen - 2.26.1-1 +- Update to 2.26.1 + +* Wed Apr 8 2009 Matthias Clasen - 2.26.0-2 +- Support touchpads + +* Mon Mar 16 2009 Matthias Clasen - 2.26.0-1 +- Update to 2.26.0 + +* Mon Mar 2 2009 Matthias Clasen - 2.25.92-1 +- Update to 2.25.92 + +* Tue Feb 24 2009 Fedora Release Engineering - 2.25.90-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Feb 5 2009 Matthias Clasen - 2.25.90-2 +- Fix a warning (#484132) + +* Wed Feb 4 2009 Matthias Clasen - 2.25.90-1 +- Update to 2.25.90 + +* Mon Jan 19 2009 - Ray Strode - 2.25.3-4 +- Update fade patch for new gnome-desktop release + +* Thu Dec 18 2008 - Bastien Nocera - 2.25.3-3 +- Rebuild + +* Thu Dec 18 2008 - Ray Strode - 2.25.3-2 +- Drop touchpad patch for now + +* Thu Dec 18 2008 - Bastien Nocera - 2.25.3-1 +- Update to 2.25.3 + +* Thu Dec 18 2008 - Bastien Nocera - 2.25.2-11 +- Fix touchpad patches + +* Wed Dec 17 2008 Matthias Clasen - 2.25.2-10 +- Rebuild against new gnome-desktop + +* Wed Dec 10 2008 Ray Strode - 2.25.2-9 +- Don't call SetPointerMapping when using Xinput since + it duplicates effort but gets touchpads wrong (bug 324721) + +* Wed Dec 10 2008 Ray Strode - 2.25.2-8 +- Shutdown cleanly when bus goes away (bug 445898 again) + +* Wed Dec 10 2008 Ray Strode - 2.25.2-7 +- Don't map touch pad tap to right-click for left-handed + users (bug 324721) + +* Wed Dec 10 2008 Ray Strode - 2.25.2-6 +- Listen for DeviceAdded signals when configuring mouse + (in addition to DeviceEnabled). This may help with + bug 474758. + +* Tue Dec 9 2008 Ray Strode - 2.25.2-5 +- Shutdown cleanly on TERM signal (bug 445898) + +* Sun Dec 7 2008 Behdad Esfahbod - 2.25.2-4 +- Add gnome-settings-daemon-2.24.1-umask.patch + +* Thu Dec 4 2008 Ray Strode - 2.25.2-2 +- Rebase fade patch to apply with Behdad's updates to + g-s-d + +* Wed Dec 3 2008 Matthias Clasen - 2.25.2-1 +- Ypdate to 2.25.2 + +* Thu Nov 13 2008 Matthias Clasen - 2.25.1-4 +- Rebuild + +* Wed Nov 12 2008 Matthias Clasen - 2.25.1-2 +- Update to 2.25.1 + +* Fri Oct 24 2008 Ray Strode - 2.24.0-14 +- At fontconfig-devel buildrequires (bug 468304) + +* Wed Oct 15 2008 Matthias Clasen - 2.24.0-13 +- Save some space + +* Tue Oct 14 2008 Ray Strode - 2.24.0-12 +- Hold off on settings-daemon fade if nautilus is going to do + it anyway. + +* Tue Oct 14 2008 Matthias Clasen - 2.24.0-11 +- Show the shutdown dialog when the power button is pressed + +* Tue Oct 14 2008 Matthias Clasen - 2.24.0-9 +- Drop a patch that is no longer needed with the evdev ruleset + in xkeyboard-config + +* Sun Oct 12 2008 Matthias Clasen - 2.24.0-7 +- Try harder not to override peoples configured keyboard layouts + +* Sun Oct 12 2008 Ray Strode - 2.24.0-6 +- Update fade patch to skip crossfade when changing frames in + slideshow background. + +* Fri Oct 10 2008 Matthias Clasen - 2.24.0-5 +- Fix the picking up of the gdm keyboard layout even more + +* Tue Sep 30 2008 Matthias Clasen - 2.24.0-3 +- Fix the picking up of the gdm keyboard layout + +* Sun Sep 28 2008 Ray Strode - 2.24.0-2 +- Don't draw background twice at startup + +* Tue Sep 23 2008 Matthias Clasen - 2.24.0-1 +- Update to 2.24.0 + +* Thu Sep 18 2008 Ray Strode - 2.23.92-3 +- When switching desktop backgrounds fade between them + +* Thu Sep 11 2008 Soren Sandmann - 2.23.92-2 +- Fix various bugs in the fn-F7 support + +* Mon Sep 8 2008 Matthias Clasen - 2.23.92-1 +- Update to 2.23.92 + +* Fri Sep 5 2008 Matthias Clasen - 2.23.91-5 +- Try harder to use the keyboard layout that gdm tells us + +* Thu Sep 04 2008 Soren Sandmann - 2.23.91-4 +- Use the fn-F7 key, not the F7 key. + +* Wed Sep 03 2008 Soren Sandmann - 2.23.91-3 +- Bump gnome-desktop requirement + +* Wed Sep 03 2008 Soren Sandmann - 2.23.91-2 +- Add patch to do fn-f7 cycling + +* Mon Sep 01 2008 - Bastien Nocera - 2.23.91-1 +- Update to 2.23.91 + +* Thu Aug 28 2008 Jon McCann - 2.23.91-0.2008.08.28.2 +- BuildRequires libnotify-devel + +* Thu Aug 28 2008 Jon McCann - 2.23.91-0.2008.08.28.1 +- Update to snapshot + +* Fri Aug 22 2008 Matthias Clasen - 2.23.90-1 +- Update to 2.23.90 + +* Thu Aug 14 2008 Lennart Poettering - 2.23.6-3 +- Rerun autotools after patching configure.ac + +* Thu Aug 14 2008 Lennart Poettering - 2.23.6-2 +- Apply patch from gnome bug 545386. This hasn't been accepted in this form yet + by upstream, will however very likely be merged in a similar form. +- Disable esd/sounds module since we don't need it to start PA anymore + +* Tue Aug 5 2008 Matthias Clasen - 2.23.6-1 +- Update to 2.23.6 + +* Fri Jul 25 2008 Matthias Clasen - 2.23.5-3 +- Use standard icon names in the volume OSD + +* Fri Jul 25 2008 - Bastien Nocera - 2.23.5-2 +- Fix build, call gtk-update-icon-cache as required + +* Thu Jul 24 2008 Soren Sandmann - 2.23.5-1 +- Update to 2.23.5 + +* Wed Jun 18 2008 Matthias Clasen - 2.23.4-1 +- Update to 2.23.4 + +* Tue Jun 17 2008 Colin Walters - 2.23.3-2 +- Add (now upstreamed) patch to legacy ESD preference; see + http://bugzilla.gnome.org/show_bug.cgi?id=533198 + https://bugzilla.redhat.com/show_bug.cgi?id=430624 + +* Wed Jun 4 2008 Matthias Clasen - 2.23.3-1 +- Update to 2.23.3 + +* Wed May 14 2008 Matthias Clasen - 2.23.2-0.2008.05.14.2 +- Fix BuildRequires + +* Wed May 14 2008 Jon McCann - 2.23.2-0.2008.05.14.1 +- Build snapshot + +* Tue May 13 2008 Matthias Clasen - 2.23.1-1-5 +- Rebuild + +* Mon May 5 2008 Matthias Clasen - 2.23.1-1-4 +- Pick up the keyboard layout from the login screen + +* Mon May 5 2008 Matthias Clasen - 2.23.1-1-3 +- Fix background drawing without nautilus + +* Tue Apr 29 2008 - Bastien Nocera - 2.23.1.1-2 +- Add patch from upstream to avoid the Stop button triggering an Eject (#346201) + +* Fri Apr 25 2008 Matthias Clasen - 2.23.1.1-1 +- Update to 2.23.1.1 + +* Tue Apr 22 2008 Matthias Clasen - 2.22.1-2008.03.26.6 +- Make the xrandr plugin survive the absence of Xrandr + +* Sat Apr 5 2008 - Soren Sandmann - 2.22.1-2008.03.26.5 +- Update randr plugin + +* Mon Mar 31 2008 - Ray Strode - 2.22.1-0.2008.03.26.4 +- Over the releases we've accumulated default.png, default-wide.png default-5_4.png + and default.jpg. We haven't been able to drop them because it would leave some + users with white backgrounds on upgrade. This patch just falls back to the + default image if the user's background doesn't exist. + +* Wed Mar 26 2008 - Bastien Nocera - 2.22.1-0.2008.03.26.3 +- Add patch for the mouse plugin not to eat multimedia key events (#438942) + +* Wed Mar 26 2008 Jon McCann - 2.22.1-0.2008.03.26.2 +- Rebuild + +* Wed Mar 26 2008 Jon McCann - 2.22.1-0.2008.03.26.1 +- Update to snapshot +- Enable profiling + +* Wed Mar 26 2008 - Bastien Nocera - 2.22.0-3 +- apps_gnome_settings_daemon_default_editor.schemas is obsolete (#438937) + +* Thu Mar 20 2008 Matthias Clasen 2.22.0-2 +- Fix interaction between "Locate Pointer" and volume keys + +* Mon Mar 10 2008 Matthias Clasen 2.22.0-1 +- Update to 2.22.0 + +* Sun Mar 9 2008 Ray Strode - 2.21.92-3 +- Don't set keyboard model on startup from gconf if evdev is being used. + Evdev needs to use its own keyboard model to work right. + +* Sun Mar 2 2008 Soren Sandmann - 2.21.92-2 +- Update randr patch to handle video key + +* Fri Feb 29 2008 Jon McCann - 2.21.92-1 +- Update to 2.21.92 + +* Tue Feb 12 2008 Soren Sandmann - 2.21.91-3 +- Add patch to make the xrandr plugin listen for client messages from + the control panel and reread the configuration file. + +* Mon Feb 11 2008 Matthias Clasen - 2.21.91-2 +- Remove obsolete control-center translations + +* Mon Feb 11 2008 - Bastien Nocera - 2.21.91-1 +- Update to 2.21.91 +- Remove obsolete patches + +* Thu Feb 7 2008 Matthias Clasen - 2.21.90.1-3 +- Load xkb settings initially + +* Thu Jan 31 2008 - Bastien Nocera - 2.21.90.1-2 +- Fix the path for g-s-d, from upstream patch + +* Tue Jan 29 2008 - Bastien Nocera - 2.21.90.1-1 +- Update to 2.21.90.1 + +* Tue Jan 29 2008 - Bastien Nocera - 2.21.90-1 +- Update to 2.21.90 + +* Tue Jan 15 2008 Matthias Clasen - 2.21.5.2-2 +- Incorporate review feedback (#428833) + +* Tue Jan 15 2008 Matthias Clasen - 2.21.5.2-1 +- Update to 2.21.5.2 + +* Tue Jan 15 2008 Matthias Clasen - 2.21.5.1-1 +- Update to 2.21.5.1 +- Fix up BuildRequires + +* Thu Dec 06 2007 - Bastien Nocera - 2.21.5-1 +- First package +