[gnome-settings-daemon] updates: port the gpk-update-icon update checking functionality



commit 6d347b9f838383f452b070419faf4fcddd3f697a
Author: Richard Hughes <richard hughsie com>
Date:   Wed Feb 16 21:44:16 2011 +0000

    updates: port the gpk-update-icon update checking functionality
    
    This provides libnotify messages if the user has not selected the updates
    to be automatically installed. It does *not* provide a status icon.
    
    I have also hooked up the distribution upgrades to present the user
    a libnotify dialog if the option is selected by the admin in GSettings.

 configure.ac                                       |    2 +-
 data/gsd-enums.h                                   |    7 +
 ...ttings-daemon.plugins.updates.gschema.xml.in.in |   75 ++
 plugins/updates/Makefile.am                        |    5 +
 plugins/updates/gsd-updates-manager.c              |  720 +++++++++++++++++++-
 plugins/updates/gsd-updates-refresh.c              |  629 +++++++++++++++++
 plugins/updates/gsd-updates-refresh.h              |   69 ++
 po/POTFILES.in                                     |    1 +
 8 files changed, 1498 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bcaf431..48c016a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -281,7 +281,7 @@ AC_ARG_ENABLE(packagekit,
 
 if test x$WANT_PACKAGEKIT = xyes ; then
        PK_REQUIRED_VERSION=0.6.4
-       PKG_CHECK_MODULES(PACKAGEKIT, glib-2.0 packagekit-glib2 >= $PK_REQUIRED_VERSION,
+       PKG_CHECK_MODULES(PACKAGEKIT, glib-2.0 packagekit-glib2 >= $PK_REQUIRED_VERSION upower-glib >= 0.9.1,
              [have_packagekit=true
               AC_DEFINE(HAVE_PACKAGEKIT, 1, [Define if PackageKit should be used])],
              [have_packagekit=false])
diff --git a/data/gsd-enums.h b/data/gsd-enums.h
index c75f78d..59d2919 100644
--- a/data/gsd-enums.h
+++ b/data/gsd-enums.h
@@ -100,4 +100,11 @@ typedef enum
   GSD_POWER_ACTION_NOTHING
 } GsdPowerActionType;
 
+typedef enum
+{
+  GSD_UPDATE_TYPE_ALL,
+  GSD_UPDATE_TYPE_SECURITY,
+  GSD_UPDATE_TYPE_NONE
+} GsdUpdateType;
+
 #endif /* __gsd_enums_h__ */
diff --git a/data/org.gnome.settings-daemon.plugins.updates.gschema.xml.in.in b/data/org.gnome.settings-daemon.plugins.updates.gschema.xml.in.in
index 2be6096..208f6cb 100644
--- a/data/org.gnome.settings-daemon.plugins.updates.gschema.xml.in.in
+++ b/data/org.gnome.settings-daemon.plugins.updates.gschema.xml.in.in
@@ -15,5 +15,80 @@
       <_summary>The install root to use when adding and removing packages</_summary>
       <_description>The install root to use when processing packages, which is changed when using LTSP or when testing.</_description>
     </key>
+    <key name="connection-use-mobile" type="b">
+      <default>false</default>
+      <_summary>Use mobile broadband connections</_summary>
+      <_description>Use mobile broadband connections such as GSM and CDMA to check for updates.</_description>
+    </key>
+    <key name="connection-use-wifi" type="b">
+      <default>true</default>
+      <_summary>Use WiFi connections</_summary>
+      <_description>Use WiFi (wireless LAN) connections to check for updates. It may be faster to download packages when on a wired connection, and the VPN or proxy required may also only be available on wired connections.</_description>
+    </key>
+    <key name="auto-update-type" enum="org.gnome.settings-daemon.GsdUpdateType">
+      <default>'security'</default>
+      <_summary>Automatically update these types of updates</_summary>
+      <_description>Automatically update these types of updates.</_description>
+    </key>
+    <key name="force-get-updates-login" type="b">
+      <default>false</default>
+      <_summary>Get the update list when the session starts</_summary>
+      <_description>Get the update list when the session starts, even if not scheduled to. This ensures the user has up to date and valid data in the tray at startup.</_description>
+    </key>
+    <key name="frequency-get-updates" type="i">
+      <default>86400</default>
+      <_summary>How often to check for updates</_summary>
+      <_description>How often to check for updates. Value is in seconds.</_description>
+    </key>
+    <key name="frequency-get-upgrades" type="i">
+      <default>604800</default>
+      <_summary>How often to check for distribution upgrades</_summary>
+      <_description>How often to check for distribution upgrades. Value is in seconds.</_description>
+    </key>
+    <key name="frequency-refresh-cache" type="i">
+      <default>86400</default>
+      <_summary>How often to refresh the package cache</_summary>
+      <_description>How often to refresh the package cache. Value is in seconds.</_description>
+    </key>
+    <key name="session-startup-timeout" type="i">
+      <default>300</default>
+      <_summary>The number of seconds at session startup to wait before checking for updates</_summary>
+      <_description>The number of seconds at session startup to wait before checking for updates. Value is in seconds.</_description>
+    </key>
+    <key name="update-battery" type="b">
+      <default>false</default>
+      <_summary>Install updates automatically when running on battery power</_summary>
+      <_description>Install updates automatically when running on battery power.</_description>
+    </key>
+    <key name="notify-distro-upgrades" type="b">
+      <default>true</default>
+      <_summary>Notify the user when distribution upgrades are available</_summary>
+      <_description>Notify the user when distribution upgrades are available.</_description>
+    </key>
+    <key name="notify-update-complete" type="b">
+      <default>false</default>
+      <_summary>Notify the user for completed updates</_summary>
+      <_description>Notify the user for completed updates. This may be a useful notification for some users as installing updates prevents shutdown.</_description>
+    </key>
+    <key name="notify-update-complete-restart" type="b">
+      <default>true</default>
+      <_summary>Notify the user for completed updates where the user needs to restart</_summary>
+      <_description>Notify the user for completed updates where the user needs to restart.</_description>
+    </key>
+    <key name="notify-update-not-battery" type="b">
+      <default>false</default>
+      <_summary>Notify the user when the automatic update was not started on battery power</_summary>
+      <_description>Notify the user when the update was not automatically started because the machine is running on battery power.</_description>
+    </key>
+    <key name="notify-update-started" type="b">
+      <default>true</default>
+      <_summary>Notify the user when the update was started</_summary>
+      <_description>Notify the user when the update was started.</_description>
+    </key>
+    <key name="notify-update-type" enum="org.gnome.settings-daemon.GsdUpdateType">
+      <default>'security'</default>
+      <_summary>Notify the user when the update type is available</_summary>
+      <_description>Notify the user when updates are available of a certain type and not auto-installed.</_description>
+    </key>
   </schema>
 </schemalist>
diff --git a/plugins/updates/Makefile.am b/plugins/updates/Makefile.am
index fd00290..b06469a 100644
--- a/plugins/updates/Makefile.am
+++ b/plugins/updates/Makefile.am
@@ -4,6 +4,8 @@ plugin_LTLIBRARIES = \
 libupdates_la_SOURCES = \
 	gsd-updates-plugin.h \
 	gsd-updates-plugin.c \
+	gsd-updates-refresh.h \
+	gsd-updates-refresh.c \
 	gsd-updates-manager.h \
 	gsd-updates-manager.c
 
@@ -17,6 +19,9 @@ libupdates_la_CFLAGS = \
 	$(GNOME_CFLAGS)	\
 	$(PACKAGEKIT_CFLAGS) \
 	-DI_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE \
+	-DDATADIR=\"$(datadir)\" \
+	-DBINDIR=\"$(bindir)\" \
+	-I$(top_srcdir)/data \
 	$(AM_CFLAGS)
 
 libupdates_la_LDFLAGS = \
diff --git a/plugins/updates/gsd-updates-manager.c b/plugins/updates/gsd-updates-manager.c
index 63b1918..038c3ea 100644
--- a/plugins/updates/gsd-updates-manager.c
+++ b/plugins/updates/gsd-updates-manager.c
@@ -25,33 +25,708 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-
-#ifdef HAVE_PACKAGEKIT
 #include <packagekit-glib2/packagekit.h>
-#endif
+#include <libnotify/notify.h>
 
+#include "gsd-enums.h"
 #include "gsd-updates-manager.h"
+#include "gsd-updates-refresh.h"
 #include "gnome-settings-profile.h"
 
 #define GSD_UPDATES_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_UPDATES_MANAGER, GsdUpdatesManagerPrivate))
 
 struct GsdUpdatesManagerPrivate
 {
-        GSettings *settings_http;
-        GSettings *settings_ftp;
-        GSettings *settings_gsd;
-        PkControl *control;
-        guint      timeout;
+        GCancellable            *cancellable;
+        GsdUpdatesRefresh       *refresh;
+        GSettings               *settings_ftp;
+        GSettings               *settings_gsd;
+        GSettings               *settings_http;
+        guint                    number_updates_critical_last_shown;
+        guint                    timeout;
+        NotifyNotification      *notification_updates_available;
+        PkControl               *control;
+        PkTask                  *task;
 };
 
 static void gsd_updates_manager_class_init (GsdUpdatesManagerClass *klass);
 static void gsd_updates_manager_init (GsdUpdatesManager *updates_manager);
 static void gsd_updates_manager_finalize (GObject *object);
+static void update_packages_finished_cb (PkTask *task, GAsyncResult *res, GsdUpdatesManager *manager);
 
 G_DEFINE_TYPE (GsdUpdatesManager, gsd_updates_manager, G_TYPE_OBJECT)
 
 static gpointer manager_object = NULL;
 
+static void
+libnotify_action_cb (NotifyNotification *notification,
+                     gchar *action,
+                     gpointer user_data)
+{
+        gboolean ret;
+        GError *error = NULL;
+        GsdUpdatesManager *manager = GSD_UPDATES_MANAGER (user_data);
+
+        if (g_strcmp0 (action, "distro-upgrade-info") == 0) {
+                ret = g_spawn_command_line_async (DATADIR "/PackageKit/pk-upgrade-distro.sh",
+                                                  &error);
+                if (!ret) {
+                        g_warning ("Failure launching pk-upgrade-distro.sh: %s",
+                                   error->message);
+                        g_error_free (error);
+                }
+                goto out;
+        }
+        if (g_strcmp0 (action, "show-update-viewer") == 0) {
+                ret = g_spawn_command_line_async (BINDIR "/gpk-update-viewer",
+                                                  &error);
+                if (!ret) {
+                        g_warning ("Failure launching update viewer: %s",
+                                   error->message);
+                        g_error_free (error);
+                }
+                goto out;
+        }
+        if (g_strcmp0 (action, "update-all-packages") == 0) {
+                pk_task_update_system_async (manager->priv->task,
+                                             manager->priv->cancellable,
+                                             NULL, NULL,
+                                             (GAsyncReadyCallback) update_packages_finished_cb,
+                                             manager);
+                goto out;
+        }
+        if (g_strcmp0 (action, "cancel") == 0) {
+                /* try to cancel */
+                g_cancellable_cancel (manager->priv->cancellable);
+                goto out;
+        }
+        g_warning ("unknown action id: %s", action);
+out:
+        return;
+}
+
+static void
+get_distro_upgrades_finished_cb (GObject *object,
+                                 GAsyncResult *res,
+                                 GsdUpdatesManager *manager)
+{
+        const gchar *title;
+        gboolean ret;
+        gchar *name = NULL;
+        GError *error = NULL;
+        GPtrArray *array = NULL;
+        GString *string = NULL;
+        guint i;
+        NotifyNotification *notification;
+        PkClient *client = PK_CLIENT(object);
+        PkDistroUpgrade *item;
+        PkError *error_code = NULL;
+        PkResults *results;
+        PkUpdateStateEnum state;
+
+        /* get the results */
+        results = pk_client_generic_finish (PK_CLIENT(client), res, &error);
+        if (results == NULL) {
+                g_warning ("failed to get upgrades: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* check error code */
+        error_code = pk_results_get_error_code (results);
+        if (error_code != NULL) {
+                g_warning ("failed to get upgrades: %s, %s",
+                           pk_error_enum_to_text (pk_error_get_code (error_code)),
+                           pk_error_get_details (error_code));
+                goto out;
+        }
+
+        /* process results */
+        array = pk_results_get_distro_upgrade_array (results);
+
+        /* any updates? */
+        if (array->len == 0) {
+                g_debug ("no upgrades");
+                goto out;
+        }
+
+        /* do we do the notification? */
+        ret = g_settings_get_boolean (manager->priv->settings_gsd,
+                                      GSD_SETTINGS_NOTIFY_DISTRO_UPGRADES);
+        if (!ret) {
+                g_debug ("ignoring due to GSettings");
+                goto out;
+        }
+
+        /* find the upgrade string */
+        string = g_string_new ("");
+        for (i=0; i < array->len; i++) {
+                item = (PkDistroUpgrade *) g_ptr_array_index (array, i);
+                g_object_get (item,
+                              "name", &name,
+                              "state", &state,
+                              NULL);
+                g_string_append_printf (string, "%s (%s)\n",
+                                        name,
+                                        pk_distro_upgrade_enum_to_text (state));
+                g_free (name);
+        }
+        if (string->len != 0)
+                g_string_set_size (string, string->len-1);
+
+        /* TRANSLATORS: a distro update is available, e.g. Fedora 8 to Fedora 9 */
+        title = _("Distribution upgrades available");
+        notification = notify_notification_new (title, string->str, NULL);
+        if (notification == NULL) {
+                g_warning ("failed to create notification");
+                goto out;
+        }
+        notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER);
+        notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL);
+        notify_notification_add_action (notification, "distro-upgrade-info",
+                                        /* TRANSLATORS: provides more information about the upgrade */
+                                        _("More information"),
+                                        libnotify_action_cb,
+                                        manager, NULL);
+        ret = notify_notification_show (notification, &error);
+        if (!ret) {
+                g_warning ("error: %s", error->message);
+                g_error_free (error);
+        }
+out:
+        if (error_code != NULL)
+                g_object_unref (error_code);
+        if (array != NULL)
+                g_ptr_array_unref (array);
+        if (string != NULL)
+                g_string_free (string, TRUE);
+        if (results != NULL)
+                g_object_unref (results);
+}
+
+static void
+due_get_upgrades_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager)
+{
+        /* optimize the amount of downloaded data by setting the cache age */
+        pk_client_set_cache_age (PK_CLIENT(manager->priv->task),
+                                 g_settings_get_int (manager->priv->settings_gsd,
+                                                     GSD_SETTINGS_FREQUENCY_GET_UPGRADES));
+
+        /* get new distro upgrades list */
+        pk_client_get_distro_upgrades_async (PK_CLIENT(manager->priv->task),
+                                             NULL,
+                                             NULL, NULL,
+                                             (GAsyncReadyCallback) get_distro_upgrades_finished_cb,
+                                             manager);
+}
+
+static void
+refresh_cache_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager)
+{
+        PkClient *client = PK_CLIENT(object);
+        PkResults *results;
+        GError *error = NULL;
+        PkError *error_code = NULL;
+
+        /* get the results */
+        results = pk_client_generic_finish (PK_CLIENT(client), res, &error);
+        if (results == NULL) {
+                g_warning ("failed to refresh the cache: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* check error code */
+        error_code = pk_results_get_error_code (results);
+        if (error_code != NULL) {
+                g_warning ("failed to refresh the cache: %s, %s",
+                           pk_error_enum_to_text (pk_error_get_code (error_code)),
+                           pk_error_get_details (error_code));
+                goto out;
+        }
+out:
+        if (error_code != NULL)
+                g_object_unref (error_code);
+        if (results != NULL)
+                g_object_unref (results);
+}
+
+static void
+due_refresh_cache_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager)
+{
+        /* optimize the amount of downloaded data by setting the cache age */
+        pk_client_set_cache_age (PK_CLIENT(manager->priv->task),
+                                 g_settings_get_int (manager->priv->settings_gsd,
+                                                     GSD_SETTINGS_FREQUENCY_REFRESH_CACHE));
+
+        pk_client_refresh_cache_async (PK_CLIENT(manager->priv->task),
+                                       TRUE,
+                                       NULL,
+                                       NULL, NULL,
+                                       (GAsyncReadyCallback) refresh_cache_finished_cb,
+                                       manager);
+}
+
+static void
+notify_critical_updates (GsdUpdatesManager *manager, GPtrArray *array)
+{
+        const gchar *message;
+        const gchar *title;
+        gboolean ret;
+        GError *error = NULL;
+        GsdUpdateType update_type;
+        NotifyNotification *notification;
+
+        /* do we do the notification? */
+        update_type = g_settings_get_enum (manager->priv->settings_gsd,
+                                           GSD_SETTINGS_NOTIFY_UPDATE_TYPE);
+        if (update_type == GSD_UPDATE_TYPE_NONE) {
+                g_debug ("ignoring due to GSettings");
+                return;
+        }
+
+        /* if the number of critical updates is the same as the last notification,
+         * then skip the notifcation as we don't want to bombard the user every hour */
+        if (array->len == manager->priv->number_updates_critical_last_shown) {
+                g_debug ("ignoring as user ignored last warning");
+                return;
+        }
+
+        /* save for comparison later */
+        manager->priv->number_updates_critical_last_shown = array->len;
+
+        /* TRANSLATORS: title in the libnotify popup */
+        title = ngettext ("Security update available", "Security updates available", array->len);
+
+        /* TRANSLATORS: message when there are security updates */
+        message = ngettext ("An important update is available for your computer:",
+                            "Important updates are available for your computer:", array->len);
+
+        /* close any existing notification */
+        if (manager->priv->notification_updates_available != NULL) {
+                notify_notification_close (manager->priv->notification_updates_available, NULL);
+                manager->priv->notification_updates_available = NULL;
+        }
+
+        /* do the bubble */
+        g_debug ("title=%s, message=%s", title, message);
+        notification = notify_notification_new (title, message, NULL);
+        if (notification == NULL) {
+                g_warning ("failed to get bubble");
+                return;
+        }
+        notify_notification_set_timeout (notification, 15000);
+        notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL);
+        notify_notification_add_action (notification, "show-update-viewer",
+                                        /* TRANSLATORS: button: open the update viewer to install updates*/
+                                        _("Install updates"), libnotify_action_cb, manager, NULL);
+        ret = notify_notification_show (notification, &error);
+        if (!ret) {
+                g_warning ("error: %s", error->message);
+                g_error_free (error);
+        }
+        /* track so we can prevent doubled notifications */
+        manager->priv->notification_updates_available = notification;
+}
+
+static gboolean
+update_check_on_battery (GsdUpdatesManager *manager)
+{
+        const gchar *message;
+        gboolean ret;
+        GError *error = NULL;
+        NotifyNotification *notification;
+
+        ret = g_settings_get_boolean (manager->priv->settings_gsd,
+                                      GSD_SETTINGS_UPDATE_BATTERY);
+        if (ret) {
+                g_debug ("okay to update due to policy");
+                return TRUE;
+        }
+
+        ret = gsd_updates_refresh_get_on_battery (manager->priv->refresh);
+        if (!ret) {
+                g_debug ("okay to update as on AC");
+                return TRUE;
+        }
+
+        /* do we do the notification? */
+        ret = g_settings_get_boolean (manager->priv->settings_gsd,
+                                      GSD_SETTINGS_NOTIFY_UPDATE_NOT_BATTERY);
+        if (!ret) {
+                g_debug ("ignoring due to GSettings");
+                return FALSE;
+        }
+
+        /* TRANSLATORS: policy says update, but we are on battery and so prompt */
+        message = _("Automatic updates are not being installed as the computer is running on battery power");
+        /* TRANSLATORS: informs user will not install by default */
+        notification = notify_notification_new (_("Updates not installed"),
+                                                message, NULL);
+        notify_notification_set_timeout (notification, 15000);
+        notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+        notify_notification_add_action (notification, "update-all-packages",
+                                        /* TRANSLATORS: to hell with my battery life, just do it */
+                                        _("Install the updates anyway"), libnotify_action_cb, manager, NULL);
+        ret = notify_notification_show (notification, &error);
+        if (!ret) {
+                g_warning ("error: %s", error->message);
+                g_error_free (error);
+        }
+
+        return FALSE;
+}
+
+static const gchar *
+restart_enum_to_localised_text (PkRestartEnum restart)
+{
+        const gchar *text = NULL;
+        switch (restart) {
+        case PK_RESTART_ENUM_NONE:
+                text = _("No restart is required.");
+                break;
+        case PK_RESTART_ENUM_SYSTEM:
+                text = _("A restart is required.");
+                break;
+        case PK_RESTART_ENUM_SESSION:
+                text = _("You need to log out and log back in.");
+                break;
+        case PK_RESTART_ENUM_APPLICATION:
+                text = _("You need to restart the application.");
+                break;
+        case PK_RESTART_ENUM_SECURITY_SESSION:
+                text = _("You need to log out and log back in to remain secure.");
+                break;
+        case PK_RESTART_ENUM_SECURITY_SYSTEM:
+                text = _("A restart is required to remain secure.");
+                break;
+        default:
+                g_warning ("restart unrecognised: %i", restart);
+        }
+        return text;
+}
+
+static void
+notify_update_finished (GsdUpdatesManager *manager, PkResults *results)
+{
+        const gchar *message;
+        gboolean ret;
+        gchar *package_id = NULL;
+        gchar **split;
+        gchar *summary = NULL;
+        GError *error = NULL;
+        GPtrArray *array;
+        GString *message_text = NULL;
+        guint i;
+        guint skipped_number = 0;
+        NotifyNotification *notification;
+        PkInfoEnum info;
+        PkPackage *item;
+        PkRestartEnum restart;
+
+        /* check we got some packages */
+        array = pk_results_get_package_array (results);
+        g_debug ("length=%i", array->len);
+        if (array->len == 0) {
+                g_debug ("no updates");
+                goto out;
+        }
+
+        message_text = g_string_new ("");
+
+        /* find any we skipped */
+        for (i=0; i<array->len; i++) {
+                item = g_ptr_array_index (array, i);
+                g_object_get (item,
+                              "info", &info,
+                              "package-id", &package_id,
+                              "summary", &summary,
+                              NULL);
+
+                split = pk_package_id_split (package_id);
+                g_debug ("%s, %s, %s", pk_info_enum_to_text (info),
+                           split[PK_PACKAGE_ID_NAME], summary);
+                if (info == PK_INFO_ENUM_BLOCKED) {
+                        skipped_number++;
+                        g_string_append_printf (message_text, "<b>%s</b> - %s\n",
+                                                split[PK_PACKAGE_ID_NAME], summary);
+                }
+                g_free (package_id);
+                g_free (summary);
+                g_strfreev (split);
+        }
+
+        /* notify the user if there were skipped entries */
+        if (skipped_number > 0) {
+                /* TRANSLATORS: we did the update, but some updates were skipped and not applied */
+                message = ngettext ("One package was skipped:",
+                                    "Some packages were skipped:", skipped_number);
+                g_string_prepend (message_text, message);
+                g_string_append_c (message_text, '\n');
+        }
+
+        /* add a message that we need to restart */
+        restart = pk_results_get_require_restart_worst (results);
+        if (restart != PK_RESTART_ENUM_NONE) {
+                message = restart_enum_to_localised_text (restart);
+
+                /* add a gap if we are putting both */
+                if (skipped_number > 0)
+                        g_string_append (message_text, "\n");
+
+                g_string_append (message_text, message);
+                g_string_append_c (message_text, '\n');
+        }
+
+        /* trim off extra newlines */
+        if (message_text->len != 0)
+                g_string_set_size (message_text, message_text->len-1);
+
+        /* do we do the notification? */
+        ret = g_settings_get_boolean (manager->priv->settings_gsd,
+                                      GSD_SETTINGS_NOTIFY_UPDATE_COMPLETE);
+        if (!ret) {
+                g_debug ("ignoring due to GSettings");
+                goto out;
+        }
+
+        /* TRANSLATORS: title: system update completed all okay */
+        notification = notify_notification_new (_("The system update has completed"),
+                                                 message_text->str, NULL);
+        notify_notification_set_timeout (notification, 15000);
+        notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+        if (restart == PK_RESTART_ENUM_SYSTEM) {
+                notify_notification_add_action (notification, "restart",
+                                                /* TRANSLATORS: restart computer as system packages need update */
+                                                _("Restart computer now"),
+                                                libnotify_action_cb,
+                                                manager, NULL);
+        }
+        ret = notify_notification_show (notification, &error);
+        if (!ret) {
+                g_warning ("error: %s", error->message);
+                g_error_free (error);
+        }
+out:
+        if (message_text != NULL)
+                g_string_free (message_text, TRUE);
+        if (array != NULL)
+                g_ptr_array_unref (array);
+}
+
+static void
+update_packages_finished_cb (PkTask *task,
+                             GAsyncResult *res,
+                             GsdUpdatesManager *manager)
+{
+        PkResults *results;
+        GError *error = NULL;
+        PkError *error_code = NULL;
+
+        /* get the results */
+        results = pk_task_generic_finish (task, res, &error);
+        if (results == NULL) {
+                g_warning ("failed to update system: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* check error code */
+        error_code = pk_results_get_error_code (results);
+        if (error_code != NULL) {
+                g_warning ("failed to update system: %s, %s",
+                           pk_error_enum_to_text (pk_error_get_code (error_code)),
+                           pk_error_get_details (error_code));
+                goto out;
+        }
+
+        /* notify */
+        notify_update_finished (manager, results);
+        manager->priv->number_updates_critical_last_shown = 0;
+out:
+        if (error_code != NULL)
+                g_object_unref (error_code);
+        if (results != NULL)
+                g_object_unref (results);
+}
+
+static void
+notify_doing_updates (GsdUpdatesManager *manager)
+{
+        gboolean ret;
+        GError *error = NULL;
+        GsdUpdateType update_type;
+        NotifyNotification *notification;
+
+        /* in GSettings? */
+        update_type = g_settings_get_enum (manager->priv->settings_gsd,
+                                           GSD_SETTINGS_NOTIFY_UPDATE_TYPE);
+        if (update_type == GSD_UPDATE_TYPE_SECURITY ||
+            update_type == GSD_UPDATE_TYPE_NONE) {
+                g_debug ("ignoring due to GSettings");
+                goto out;
+        }
+
+        /* TRANSLATORS: title: notification when we scheduled an automatic update */
+        notification = notify_notification_new (_("Updates are being installed"),
+                                                /* TRANSLATORS: tell the user why the hard disk is grinding... */
+                                                _("Updates are being automatically installed on your computer"),
+                                                "software-update-urgent");
+        notify_notification_set_timeout (notification, 15000);
+        notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+        /* TRANSLATORS: button: cancel the update system */
+        notify_notification_add_action (notification, "cancel",
+                                        _("Cancel update"),
+                                        libnotify_action_cb,
+                                        manager, NULL);
+        ret = notify_notification_show (notification, &error);
+        if (!ret) {
+                g_warning ("error: %s", error->message);
+                g_error_free (error);
+        }
+out:
+        return;
+}
+
+static void
+get_updates_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager)
+{
+        PkClient *client = PK_CLIENT(object);
+        PkResults *results;
+        GError *error = NULL;
+        PkPackage *item;
+        guint i;
+        gboolean ret;
+        GsdUpdateType update;
+        GPtrArray *security_array = NULL;
+        gchar **package_ids;
+        GPtrArray *array = NULL;
+        PkError *error_code = NULL;
+
+        /* get the results */
+        results = pk_client_generic_finish (PK_CLIENT(client), res, &error);
+        if (results == NULL) {
+                g_warning ("failed to get updates: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* check error code */
+        error_code = pk_results_get_error_code (results);
+        if (error_code != NULL) {
+                g_warning ("failed to get updates: %s, %s",
+                           pk_error_enum_to_text (pk_error_get_code (error_code)),
+                           pk_error_get_details (error_code));
+                goto out;
+        }
+
+        /* get data */
+        array = pk_results_get_package_array (results);
+
+        /* we have no updates */
+        if (array->len == 0) {
+                g_debug ("no updates");
+                goto out;
+        }
+
+        /* we have updates to process */
+        security_array = g_ptr_array_new_with_free_func (g_free);
+
+        /* find the security updates first */
+        for (i=0; i<array->len; i++) {
+                item = g_ptr_array_index (array, i);
+                if (pk_package_get_info (item) != PK_INFO_ENUM_SECURITY)
+                        continue;
+                g_ptr_array_add (security_array, g_strdup (pk_package_get_id (item)));
+        }
+
+        /* do we do the automatic updates? */
+        update = g_settings_get_enum (manager->priv->settings_gsd,
+                                      GSD_SETTINGS_AUTO_UPDATE_TYPE);
+
+        /* is policy none? */
+        if (update == GSD_UPDATE_TYPE_NONE) {
+                g_debug ("not updating as policy NONE");
+                /* do we warn the user? */
+                if (security_array->len > 0)
+                        notify_critical_updates (manager, security_array);
+                goto out;
+        }
+
+        /* are we on battery and configured to skip the action */
+        ret = update_check_on_battery (manager);
+        if (!ret &&
+            ((update == GSD_UPDATE_TYPE_SECURITY && security_array->len > 0) ||
+              update == GSD_UPDATE_TYPE_ALL)) {
+                g_debug ("on battery so not doing update");
+                if (security_array->len > 0)
+                        notify_critical_updates (manager, security_array);
+                goto out;
+        }
+
+        /* just do security updates */
+        if (update == GSD_UPDATE_TYPE_SECURITY) {
+                if (security_array->len == 0) {
+                        g_debug ("policy security, but none available");
+                        goto out;
+                }
+
+                /* convert */
+                package_ids = pk_ptr_array_to_strv (security_array);
+                pk_task_update_packages_async (manager->priv->task, package_ids,
+                                               manager->priv->cancellable,
+                                               NULL, NULL,
+                                               (GAsyncReadyCallback) update_packages_finished_cb, manager);
+                notify_doing_updates (manager);
+                g_strfreev (package_ids);
+                goto out;
+        }
+
+        /* just do everything */
+        if (update == GSD_UPDATE_TYPE_ALL) {
+                g_debug ("we should do the update automatically!");
+                pk_task_update_system_async (manager->priv->task,
+                                             manager->priv->cancellable,
+                                             NULL, NULL,
+                                             (GAsyncReadyCallback) update_packages_finished_cb,
+                                             manager);
+                notify_doing_updates (manager);
+                goto out;
+        }
+
+        /* shouldn't happen */
+        g_warning ("unknown update mode");
+out:
+        if (error_code != NULL)
+                g_object_unref (error_code);
+        if (security_array != NULL)
+                g_ptr_array_unref (security_array);
+        if (array != NULL)
+                g_ptr_array_unref (array);
+        if (results != NULL)
+                g_object_unref (results);
+}
+
+static void
+due_get_updates_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager)
+{
+        /* optimize the amount of downloaded data by setting the cache age */
+        pk_client_set_cache_age (PK_CLIENT(manager->priv->task),
+                                 g_settings_get_int (manager->priv->settings_gsd,
+                                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES));
+
+        /* get new update list */
+        pk_client_get_updates_async (PK_CLIENT(manager->priv->task),
+                                     pk_bitfield_value (PK_FILTER_ENUM_NONE),
+                                     manager->priv->cancellable,
+                                     NULL, NULL,
+                                     (GAsyncReadyCallback) get_updates_finished_cb,
+                                     manager);
+}
+
 static gchar *
 get_proxy_http (GsdUpdatesManager *manager)
 {
@@ -227,9 +902,24 @@ gboolean
 gsd_updates_manager_start (GsdUpdatesManager *manager,
                            GError **error)
 {
-
         /* use PackageKit */
+        manager->priv->cancellable = g_cancellable_new ();
         manager->priv->control = pk_control_new ();
+        manager->priv->task = pk_task_new ();
+        g_object_set (manager->priv->task,
+                      "background", TRUE,
+                      "interactive", FALSE,
+                      NULL);
+
+        /* get automatic callbacks about when we should check for
+         * updates, refresh-caches and upgrades */
+        manager->priv->refresh = gsd_updates_refresh_new ();
+        g_signal_connect (manager->priv->refresh, "get-upgrades",
+                          G_CALLBACK (due_get_upgrades_cb), manager);
+        g_signal_connect (manager->priv->refresh, "refresh-cache",
+                          G_CALLBACK (due_refresh_cache_cb), manager);
+        g_signal_connect (manager->priv->refresh, "get-updates",
+                          G_CALLBACK (due_get_updates_cb), manager);
 
         /* get http settings */
         manager->priv->settings_http = g_settings_new ("org.gnome.system.proxy.http");
@@ -276,6 +966,18 @@ gsd_updates_manager_stop (GsdUpdatesManager *manager)
                 g_object_unref (manager->priv->control);
                 manager->priv->control = NULL;
         }
+        if (manager->priv->task != NULL) {
+                g_object_unref (manager->priv->task);
+                manager->priv->task = NULL;
+        }
+        if (manager->priv->refresh != NULL) {
+                g_object_unref (manager->priv->refresh);
+                manager->priv->refresh = NULL;
+        }
+        if (manager->priv->cancellable != NULL) {
+                g_object_unref (manager->priv->cancellable);
+                manager->priv->cancellable = NULL;
+        }
 
         if (manager->priv->timeout) {
                 g_source_remove (manager->priv->timeout);
diff --git a/plugins/updates/gsd-updates-refresh.c b/plugins/updates/gsd-updates-refresh.c
new file mode 100644
index 0000000..9571df5
--- /dev/null
+++ b/plugins/updates/gsd-updates-refresh.c
@@ -0,0 +1,629 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2011 Richard Hughes <richard hughsie com>
+ *
+ * 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 <glib/gi18n.h>
+#include <packagekit-glib2/packagekit.h>
+#include <libupower-glib/upower.h>
+
+#include "gsd-updates-refresh.h"
+
+static void     gsd_updates_refresh_finalize    (GObject            *object);
+
+#define GSD_UPDATES_REFRESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefreshPrivate))
+
+#define PERIODIC_CHECK_TIME     60*60   /* poke PackageKit every hour */
+#define LOGIN_TIMEOUT           3       /* seconds */
+
+enum {
+        PRESENCE_STATUS_AVAILABLE = 0,
+        PRESENCE_STATUS_INVISIBLE,
+        PRESENCE_STATUS_BUSY,
+        PRESENCE_STATUS_IDLE,
+        PRESENCE_STATUS_UNKNOWN
+};
+
+/*
+ * at startup, after a small delay, force a GetUpdates call
+ * every hour (or any event) check:
+   - if we are online, idle and on AC power, it's been more than a day
+     since we refreshed then RefreshCache
+   - if we are online and it's been longer than the timeout since
+     getting the updates period then GetUpdates
+*/
+
+struct GsdUpdatesRefreshPrivate
+{
+        gboolean                 session_idle;
+        gboolean                 on_battery;
+        gboolean                 network_active;
+        gboolean                 force_get_updates_login;
+        guint                    force_get_updates_login_timeout_id;
+        guint                    timeout_id;
+        guint                    periodic_id;
+        UpClient                *client;
+        GSettings               *settings;
+        GDBusProxy              *proxy_session;
+        PkControl               *control;
+};
+
+enum {
+        REFRESH_CACHE,
+        GET_UPDATES,
+        GET_UPGRADES,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GsdUpdatesRefresh, gsd_updates_refresh, G_TYPE_OBJECT)
+
+static void
+gsd_updates_refresh_class_init (GsdUpdatesRefreshClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        object_class->finalize = gsd_updates_refresh_finalize;
+        g_type_class_add_private (klass, sizeof (GsdUpdatesRefreshPrivate));
+        signals [REFRESH_CACHE] =
+                g_signal_new ("refresh-cache",
+                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                              0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+        signals [GET_UPDATES] =
+                g_signal_new ("get-updates",
+                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                              0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+        signals [GET_UPGRADES] =
+                g_signal_new ("get-upgrades",
+                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                              0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+}
+
+static void
+get_time_refresh_cache_cb (GObject *object,
+                           GAsyncResult *res,
+                           GsdUpdatesRefresh *refresh)
+{
+        PkControl *control = PK_CONTROL (object);
+        GError *error = NULL;
+        guint seconds;
+        guint thresh;
+
+        /* get the result */
+        seconds = pk_control_get_time_since_action_finish (control, res, &error);
+        if (seconds == 0) {
+                g_warning ("failed to get time: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        /* have we passed the timout? */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES);
+        if (seconds < thresh) {
+                g_debug ("not before timeout, thresh=%u, now=%u", thresh, seconds);
+                return;
+        }
+
+        /* send signal */
+        g_debug ("emitting refresh-cache");
+        g_signal_emit (refresh, signals [REFRESH_CACHE], 0);
+}
+
+static void
+maybe_refresh_cache (GsdUpdatesRefresh *refresh)
+{
+        guint thresh;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        /* if we don't want to auto check for updates, don't do this either */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES);
+        if (thresh == 0) {
+                g_debug ("not when policy is set to never");
+                return;
+        }
+
+        /* not on battery */
+        if (refresh->priv->on_battery) {
+                g_debug ("not when on battery");
+                return;
+        }
+
+        /* only do the refresh cache when the user is idle */
+        if (!refresh->priv->session_idle) {
+                g_debug ("not when session active");
+                return;
+        }
+
+        /* get this each time, as it may have changed behind out back */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_REFRESH_CACHE);
+        if (thresh == 0) {
+                g_debug ("not when policy is set to never");
+                return;
+        }
+
+        /* get the time since the last refresh */
+        pk_control_get_time_since_action_async (refresh->priv->control,
+                                                PK_ROLE_ENUM_REFRESH_CACHE,
+                                                NULL,
+                                                (GAsyncReadyCallback) get_time_refresh_cache_cb,
+                                                refresh);
+}
+
+static void
+get_time_get_updates_cb (GObject *object, GAsyncResult *res, GsdUpdatesRefresh *refresh)
+{
+        PkControl *control = PK_CONTROL (object);
+        GError *error = NULL;
+        guint seconds;
+        guint thresh;
+
+        /* get the result */
+        seconds = pk_control_get_time_since_action_finish (control, res, &error);
+        if (seconds == 0) {
+                g_warning ("failed to get time: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        /* have we passed the timout? */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES);
+        if (seconds < thresh) {
+                g_debug ("not before timeout, thresh=%u, now=%u", thresh, seconds);
+                return;
+        }
+
+        /* send signal */
+        g_debug ("emitting get-updates");
+        g_signal_emit (refresh, signals [GET_UPDATES], 0);
+}
+
+static void
+maybe_get_updates (GsdUpdatesRefresh *refresh)
+{
+        guint thresh;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        if (!refresh->priv->force_get_updates_login) {
+                refresh->priv->force_get_updates_login = TRUE;
+                if (g_settings_get_boolean (refresh->priv->settings,
+                                            GSD_SETTINGS_FORCE_GET_UPDATES_LOGIN)) {
+                        g_debug ("forcing get update due to GSettings");
+                        g_signal_emit (refresh, signals [GET_UPDATES], 0);
+                        return;
+                }
+        }
+
+        /* if we don't want to auto check for updates, don't do this either */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES);
+        if (thresh == 0) {
+                g_debug ("not when policy is set to never");
+                return;
+        }
+
+        /* get the time since the last refresh */
+        pk_control_get_time_since_action_async (refresh->priv->control,
+                                                PK_ROLE_ENUM_GET_UPDATES,
+                                                NULL,
+                                                (GAsyncReadyCallback) get_time_get_updates_cb,
+                                                refresh);
+}
+
+static void
+get_time_get_upgrades_cb (GObject *object,
+                          GAsyncResult *res,
+                          GsdUpdatesRefresh *refresh)
+{
+        PkControl *control = PK_CONTROL (object);
+        GError *error = NULL;
+        guint seconds;
+        guint thresh;
+
+        /* get the result */
+        seconds = pk_control_get_time_since_action_finish (control, res, &error);
+        if (seconds == 0) {
+                g_warning ("failed to get time: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        /* have we passed the timout? */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPDATES);
+        if (seconds < thresh) {
+                g_debug ("not before timeout, thresh=%u, now=%u",
+                         thresh, seconds);
+                return;
+        }
+
+        /* send signal */
+        g_debug ("emitting get-upgrades");
+        g_signal_emit (refresh, signals [GET_UPGRADES], 0);
+}
+
+static void
+maybe_get_upgrades (GsdUpdatesRefresh *refresh)
+{
+        guint thresh;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        /* get this each time, as it may have changed behind out back */
+        thresh = g_settings_get_int (refresh->priv->settings,
+                                     GSD_SETTINGS_FREQUENCY_GET_UPGRADES);
+        if (thresh == 0) {
+                g_debug ("not when policy is set to never");
+                return;
+        }
+
+        /* get the time since the last refresh */
+        pk_control_get_time_since_action_async (refresh->priv->control,
+                                                PK_ROLE_ENUM_GET_DISTRO_UPGRADES,
+                                                NULL,
+                                                (GAsyncReadyCallback) get_time_get_upgrades_cb,
+                                                refresh);
+}
+
+static gboolean
+change_state_cb (GsdUpdatesRefresh *refresh)
+{
+        /* check all actions */
+        maybe_refresh_cache (refresh);
+        maybe_get_updates (refresh);
+        maybe_get_upgrades (refresh);
+        return FALSE;
+}
+
+static gboolean
+maybe_get_updates_logon_cb (GsdUpdatesRefresh *refresh)
+{
+        maybe_get_updates (refresh);
+        /* never repeat, even if failure */
+        return FALSE;
+}
+
+static gboolean
+change_state (GsdUpdatesRefresh *refresh)
+{
+        gboolean force;
+        guint value;
+
+        g_return_val_if_fail (GSD_IS_UPDATES_REFRESH (refresh), FALSE);
+
+        /* no point continuing if we have no network */
+        if (!refresh->priv->network_active) {
+                g_debug ("not when no network");
+                return FALSE;
+        }
+
+        /* only force a check if the user REALLY, REALLY wants to break
+         * set policy and have an update at startup */
+        if (!refresh->priv->force_get_updates_login) {
+                force = g_settings_get_boolean (refresh->priv->settings,
+                                                GSD_SETTINGS_FORCE_GET_UPDATES_LOGIN);
+                if (force) {
+                        /* don't immediately send the signal, if we are
+                         * called during object initialization
+                         * we need to wait until upper layers finish
+                         * hooking up to the signal first */
+                        if (refresh->priv->force_get_updates_login_timeout_id == 0) {
+                                refresh->priv->force_get_updates_login_timeout_id =
+                                        g_timeout_add_seconds (LOGIN_TIMEOUT,
+                                                               (GSourceFunc) maybe_get_updates_logon_cb,
+                                                               refresh);
+                                g_source_set_name_by_id (refresh->priv->force_get_updates_login_timeout_id,
+                                                         "[GsdUpdatesRefresh] maybe-get-updates");
+                        }
+                }
+        }
+
+        /* wait a little time for things to settle down */
+        if (refresh->priv->timeout_id != 0)
+                g_source_remove (refresh->priv->timeout_id);
+        value = g_settings_get_int (refresh->priv->settings,
+                                    GSD_SETTINGS_SESSION_STARTUP_TIMEOUT);
+        g_debug ("defering action for %i seconds", value);
+        refresh->priv->timeout_id =
+                g_timeout_add_seconds (value, (GSourceFunc) change_state_cb, refresh);
+        g_source_set_name_by_id (refresh->priv->timeout_id,
+                                 "[GsdUpdatesRefresh] change-state");
+
+        return TRUE;
+}
+
+static void
+settings_key_changed_cb (GSettings *client,
+                         const gchar *key,
+                         GsdUpdatesRefresh *refresh)
+{
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+        if (g_strcmp0 (key, GSD_SETTINGS_SESSION_STARTUP_TIMEOUT) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_FORCE_GET_UPDATES_LOGIN) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_GET_UPDATES) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_GET_UPGRADES) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_REFRESH_CACHE) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_AUTO_UPDATE_TYPE) == 0 ||
+            g_strcmp0 (key, GSD_SETTINGS_UPDATE_BATTERY) == 0)
+                change_state (refresh);
+}
+
+gboolean
+gsd_updates_refresh_get_on_battery (GsdUpdatesRefresh *refresh)
+{
+        g_return_val_if_fail (GSD_IS_UPDATES_REFRESH (refresh), FALSE);
+        return refresh->priv->on_battery;
+}
+
+static gboolean
+convert_network_state (GsdUpdatesRefresh *refresh, PkNetworkEnum state)
+{
+        /* offline */
+        if (state == PK_NETWORK_ENUM_OFFLINE)
+                return FALSE;
+
+        /* online */
+        if (state == PK_NETWORK_ENUM_ONLINE ||
+            state == PK_NETWORK_ENUM_WIRED)
+                return TRUE;
+
+        /* check policy */
+        if (state == PK_NETWORK_ENUM_MOBILE)
+                return g_settings_get_boolean (refresh->priv->settings,
+                                               GSD_SETTINGS_CONNECTION_USE_MOBILE);
+
+        /* check policy */
+        if (state == PK_NETWORK_ENUM_WIFI)
+                return g_settings_get_boolean (refresh->priv->settings,
+                                               GSD_SETTINGS_CONNECTION_USE_WIFI);
+
+        /* not recognised */
+        g_warning ("state unknown: %i", state);
+        return TRUE;
+}
+
+static void
+notify_network_state_cb (PkControl *control,
+                         GParamSpec *pspec,
+                         GsdUpdatesRefresh *refresh)
+{
+        PkNetworkEnum state;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        g_object_get (control, "network-state", &state, NULL);
+        refresh->priv->network_active = convert_network_state (refresh, state);
+        g_debug ("setting online %i", refresh->priv->network_active);
+        if (refresh->priv->network_active)
+                change_state (refresh);
+}
+
+static gboolean
+periodic_timeout_cb (gpointer user_data)
+{
+        GsdUpdatesRefresh *refresh = GSD_UPDATES_REFRESH (user_data);
+
+        g_return_val_if_fail (GSD_IS_UPDATES_REFRESH (refresh), FALSE);
+
+        /* debug so we can catch polling */
+        g_debug ("polling check");
+
+        /* triggered once an hour */
+        change_state (refresh);
+
+        /* always return */
+        return TRUE;
+}
+
+static void
+gsd_updates_refresh_client_changed_cb (UpClient *client,
+                                       GsdUpdatesRefresh *refresh)
+{
+        gboolean on_battery;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        /* get the on-battery state */
+        on_battery = up_client_get_on_battery (refresh->priv->client);
+        if (on_battery == refresh->priv->on_battery) {
+                g_debug ("same state as before, ignoring");
+                return;
+        }
+
+        /* save in local cache */
+        g_debug ("setting on_battery %i", on_battery);
+        refresh->priv->on_battery = on_battery;
+        if (!on_battery)
+                change_state (refresh);
+}
+
+static void
+get_properties_cb (GObject *object,
+                   GAsyncResult *res,
+                   GsdUpdatesRefresh *refresh)
+{
+        PkNetworkEnum state;
+        GError *error = NULL;
+        PkControl *control = PK_CONTROL(object);
+        gboolean ret;
+
+        /* get the result */
+        ret = pk_control_get_properties_finish (control, res, &error);
+        if (!ret) {
+                /* TRANSLATORS: backend is broken, and won't tell us what it supports */
+                g_warning ("could not get properties");
+                g_error_free (error);
+                goto out;
+        }
+
+        /* get values */
+        g_object_get (control,
+                      "network-state", &state,
+                      NULL);
+        refresh->priv->network_active = convert_network_state (refresh, state);
+out:
+        return;
+}
+
+static void
+session_presence_signal_cb (GDBusProxy *proxy,
+                            gchar *sender_name,
+                            gchar *signal_name,
+                            GVariant *parameters,
+                            GsdUpdatesRefresh *refresh)
+{
+        guint status;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh));
+
+        if (g_strcmp0 (signal_name, "StatusChanged") != 0)
+                return;
+
+        /* map stauts code into boolean */
+        g_variant_get (parameters, "(u)", &status);
+        refresh->priv->session_idle = (status == PRESENCE_STATUS_IDLE);
+        g_debug ("setting is_idle %i",
+                 refresh->priv->session_idle);
+        if (refresh->priv->session_idle)
+                change_state (refresh);
+
+}
+
+static void
+gsd_updates_refresh_init (GsdUpdatesRefresh *refresh)
+{
+        GError *error = NULL;
+        GVariant *status;
+        guint status_code;
+
+        refresh->priv = GSD_UPDATES_REFRESH_GET_PRIVATE (refresh);
+        refresh->priv->on_battery = FALSE;
+        refresh->priv->network_active = FALSE;
+        refresh->priv->force_get_updates_login = FALSE;
+        refresh->priv->timeout_id = 0;
+        refresh->priv->periodic_id = 0;
+        refresh->priv->force_get_updates_login_timeout_id = 0;
+
+        /* we need to know the updates frequency */
+        refresh->priv->settings = g_settings_new (GSD_SETTINGS_SCHEMA);
+        g_signal_connect (refresh->priv->settings, "changed",
+                          G_CALLBACK (settings_key_changed_cb), refresh);
+
+        /* we need to query the last cache refresh time */
+        refresh->priv->control = pk_control_new ();
+        g_signal_connect (refresh->priv->control, "notify::network-state",
+                          G_CALLBACK (notify_network_state_cb),
+                          refresh);
+
+        /* get network state */
+        pk_control_get_properties_async (refresh->priv->control,
+                                         NULL,
+                                         (GAsyncReadyCallback) get_properties_cb,
+                                         refresh);
+
+        /* use a UpClient */
+        refresh->priv->client = up_client_new ();
+        g_signal_connect (refresh->priv->client, "changed",
+                          G_CALLBACK (gsd_updates_refresh_client_changed_cb), refresh);
+
+        /* get the battery state */
+        refresh->priv->on_battery = up_client_get_on_battery (refresh->priv->client);
+        g_debug ("setting on battery %i", refresh->priv->on_battery);
+
+        /* use gnome-session for the idle detection */
+        refresh->priv->proxy_session =
+                g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                               G_DBUS_PROXY_FLAGS_NONE,
+                                               NULL, /* GDBusInterfaceInfo */
+                                               "org.gnome.SessionManager",
+                                               "/org/gnome/SessionManager/Presence",
+                                               "org.gnome.SessionManager.Presence",
+                                               NULL, /* GCancellable */
+                                               &error);
+        if (refresh->priv->proxy_session == NULL) {
+                g_warning ("Error creating proxy: %s",
+                           error->message);
+                g_error_free (error);
+        } else {
+                g_signal_connect (refresh->priv->proxy_session,
+                                  "g-signal",
+                                  G_CALLBACK (session_presence_signal_cb),
+                                  refresh);
+                status = g_dbus_proxy_get_cached_property (refresh->priv->proxy_session,
+                                                           "status");
+                g_variant_get (status, "(u)", &status_code);
+                refresh->priv->session_idle = (status_code == PRESENCE_STATUS_IDLE);
+                g_variant_unref (status);
+        }
+
+        /* we check this in case we miss one of the async signals */
+        refresh->priv->periodic_id =
+                g_timeout_add_seconds (PERIODIC_CHECK_TIME,
+                                       periodic_timeout_cb, refresh);
+        g_source_set_name_by_id (refresh->priv->periodic_id,
+                                 "[GsdUpdatesRefresh] periodic check");
+
+        /* check system state */
+        change_state (refresh);
+}
+
+static void
+gsd_updates_refresh_finalize (GObject *object)
+{
+        GsdUpdatesRefresh *refresh;
+
+        g_return_if_fail (GSD_IS_UPDATES_REFRESH (object));
+
+        refresh = GSD_UPDATES_REFRESH (object);
+        g_return_if_fail (refresh->priv != NULL);
+
+        if (refresh->priv->timeout_id != 0)
+                g_source_remove (refresh->priv->timeout_id);
+        if (refresh->priv->periodic_id != 0)
+                g_source_remove (refresh->priv->periodic_id);
+        if (refresh->priv->force_get_updates_login_timeout_id != 0)
+                g_source_remove (refresh->priv->force_get_updates_login_timeout_id);
+
+        g_object_unref (refresh->priv->control);
+        g_object_unref (refresh->priv->settings);
+        g_object_unref (refresh->priv->client);
+        if (refresh->priv->proxy_session != NULL)
+                g_object_unref (refresh->priv->proxy_session);
+
+        G_OBJECT_CLASS (gsd_updates_refresh_parent_class)->finalize (object);
+}
+
+GsdUpdatesRefresh *
+gsd_updates_refresh_new (void)
+{
+        GsdUpdatesRefresh *refresh;
+        refresh = g_object_new (GSD_TYPE_UPDATES_REFRESH, NULL);
+        return GSD_UPDATES_REFRESH (refresh);
+}
+
diff --git a/plugins/updates/gsd-updates-refresh.h b/plugins/updates/gsd-updates-refresh.h
new file mode 100644
index 0000000..ad45dfe
--- /dev/null
+++ b/plugins/updates/gsd-updates-refresh.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2011 Richard Hughes <richard hughsie com>
+ *
+ * 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.
+ */
+
+#ifndef __GSD_UPDATES_REFRESH_H
+#define __GSD_UPDATES_REFRESH_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_UPDATES_REFRESH        (gsd_updates_refresh_get_type ())
+#define GSD_UPDATES_REFRESH(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefresh))
+#define GSD_UPDATES_REFRESH_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefreshClass))
+#define GSD_IS_UPDATES_REFRESH(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_UPDATES_REFRESH))
+
+typedef struct GsdUpdatesRefreshPrivate GsdUpdatesRefreshPrivate;
+
+typedef struct
+{
+         GObject                         parent;
+         GsdUpdatesRefreshPrivate       *priv;
+} GsdUpdatesRefresh;
+
+typedef struct
+{
+        GObjectClass    parent_class;
+} GsdUpdatesRefreshClass;
+
+#define GSD_SETTINGS_SCHEMA                             "org.gnome.settings-daemon.plugins.updates"
+#define GSD_SETTINGS_AUTO_UPDATE_TYPE                   "auto-update-type"
+#define GSD_SETTINGS_CONNECTION_USE_MOBILE              "connection-use-mobile"
+#define GSD_SETTINGS_CONNECTION_USE_WIFI                "connection-use-wifi"
+#define GSD_SETTINGS_FORCE_GET_UPDATES_LOGIN            "force-get-updates-login"
+#define GSD_SETTINGS_FREQUENCY_GET_UPDATES              "frequency-get-updates"
+#define GSD_SETTINGS_FREQUENCY_GET_UPGRADES             "frequency-get-upgrades"
+#define GSD_SETTINGS_FREQUENCY_REFRESH_CACHE            "frequency-refresh-cache"
+#define GSD_SETTINGS_NOTIFY_UPDATE_TYPE                 "notify-update-type"
+#define GSD_SETTINGS_NOTIFY_DISTRO_UPGRADES             "notify-distro-upgrades"
+#define GSD_SETTINGS_NOTIFY_UPDATE_COMPLETE             "notify-update-complete"
+#define GSD_SETTINGS_NOTIFY_UPDATE_COMPLETE_RESTART     "notify-update-complete-restart"
+#define GSD_SETTINGS_NOTIFY_UPDATE_NOT_BATTERY          "notify-update-not-battery"
+#define GSD_SETTINGS_SESSION_STARTUP_TIMEOUT            "session-startup-timeout"
+#define GSD_SETTINGS_UPDATE_BATTERY                     "update-battery"
+
+GType                    gsd_updates_refresh_get_type           (void);
+GsdUpdatesRefresh       *gsd_updates_refresh_new                (void);
+gboolean                 gsd_updates_refresh_get_on_battery     (GsdUpdatesRefresh *refresh);
+
+G_END_DECLS
+
+#endif /* __GSD_UPDATES_REFRESH_H */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b896f80..4d18a83 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -46,3 +46,4 @@ plugins/xsettings/gsd-xsettings-manager.c
 plugins/smartcard/gsd-smartcard-manager.c
 plugins/smartcard/gsd-smartcard.c
 plugins/datetime/org.gnome.settingsdaemon.datetimemechanism.policy.in
+plugins/updates/gsd-updates-manager.c



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