---
 data/org.freedesktop.Accounts.User.xml |   45 ++++++++++++++++++++++
 src/libaccountsservice/act-user.c      |   66 ++++++++++++++++++++++++++++++++
 src/user.c                             |   67 +++++++++++++++++++++++++++++++++
 src/user.h                             |    3 +
 4 files changed, 181 insertions(+)

--- accountsservice.orig/data/org.freedesktop.Accounts.User.xml
+++ accountsservice/data/org.freedesktop.Accounts.User.xml
@@ -331,6 +331,41 @@
     </doc:doc>
   </method>
 
+  <method name="SetXHasMessages">
+    <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+    <arg name="has_messages" direction="in" type="b">
+      <doc:doc>
+        <doc:summary>
+          Whether the user has messages waiting for them.
+        </doc:summary>
+      </doc:doc>
+    </arg>
+    <doc:doc>
+      <doc:description>
+        <doc:para>
+          Sets whether the user has messages waiting for them.
+        </doc:para>
+      </doc:description>
+      <doc:permission>
+        The caller needs one of the following PolicyKit authorizations:
+        <doc:list>
+          <doc:item>
+            <doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
+            <doc:definition>To change his or her own status</doc:definition>
+          </doc:item>
+          <doc:item>
+            <doc:term>org.freedesktop.accounts.user-administration</doc:term>
+            <doc:definition>To change the status of another user</doc:definition>
+          </doc:item>
+        </doc:list>
+      </doc:permission>
+      <doc:errors>
+        <doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
+        <doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
+      </doc:errors>
+    </doc:doc>
+  </method>
+
   <method name="SetXKeyboardLayouts">
     <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
     <arg name="layouts" direction="in" type="as">
@@ -766,6 +801,16 @@
         </doc:para>
       </doc:description>
     </doc:doc>
+  </property>
+
+  <property name="XHasMessages" type="b" access="read">
+    <doc:doc>
+      <doc:description>
+        <doc:para>
+           Whether the user has messages waiting for them.
+        </doc:para>
+      </doc:description>
+    </doc:doc>
   </property>
 
   <property name="XKeyboardLayouts" type="as" access="read">
--- accountsservice.orig/src/libaccountsservice/act-user.c
+++ accountsservice/src/libaccountsservice/act-user.c
@@ -57,6 +57,7 @@ enum {
         PROP_AUTOMATIC_LOGIN,
         PROP_SYSTEM_ACCOUNT,
         PROP_LOGIN_FREQUENCY,
+        PROP_X_HAS_MESSAGES,
         PROP_X_KEYBOARD_LAYOUTS,
         PROP_BACKGROUND_FILE,
         PROP_ICON_FILE,
@@ -101,6 +102,7 @@ struct _ActUser {
         ActUserAccountType  account_type;
         ActUserPasswordMode password_mode;
 
+        guint           x_has_messages : 1;
         guint           is_loaded : 1;
         guint           locked : 1;
         guint           automatic_login : 1;
@@ -237,6 +239,9 @@ act_user_get_property (GObject    *objec
         case PROP_LOCATION:
                 g_value_set_string (value, user->location);
                 break;
+        case PROP_X_HAS_MESSAGES:
+                g_value_set_boolean (value, user->x_has_messages);
+                break;
         case PROP_X_KEYBOARD_LAYOUTS:
                 g_value_set_boxed (value, g_strdupv (user->x_keyboard_layouts));
                 break;
@@ -372,6 +377,13 @@ act_user_class_init (ActUserClass *class
                                                            0,
                                                            G_PARAM_READABLE));
         g_object_class_install_property (gobject_class,
+                                         PROP_X_HAS_MESSAGES,
+                                         g_param_spec_boolean ("x-has-messages",
+                                                               "Has Messages",
+                                                               "Whether the user has messages waiting.",
+                                                               FALSE,
+                                                               G_PARAM_READABLE));
+        g_object_class_install_property (gobject_class,
                                          PROP_X_KEYBOARD_LAYOUTS,
                                          g_param_spec_boxed ("x-keyboard-layouts",
                                                              "Keyboard layouts",
@@ -841,6 +853,22 @@ act_user_is_system_account (ActUser *use
 }
 
 /**
+ * act_user_get_x_has_messages:
+ * @user: a #ActUser
+ *
+ * Returns whether @user has messages waiting for them.
+ *
+ * Returns: whether messages exist
+ */
+gboolean
+act_user_get_x_has_messages (ActUser *user)
+{
+        g_return_val_if_fail (ACT_IS_USER (user), FALSE);
+
+        return user->x_has_messages;
+}
+
+/**
  * act_user_get_x_keyboard_layouts:
  * @user: a #ActUser
  *
@@ -1124,6 +1152,14 @@ collect_props (const gchar    *key,
                         user->login_frequency = new_login_frequency;
                         g_object_notify (G_OBJECT (user), "login-frequency");
                 }
+        } else if (strcmp (key, "XHasMessages") == 0) {
+                gboolean new_has_messages;
+
+                new_has_messages = g_value_get_boolean (value);
+                if (new_has_messages != user->x_has_messages) {
+                        user->x_has_messages = new_has_messages;
+                        g_object_notify (G_OBJECT (user), "x-has-messages");
+                }
         } else if (strcmp (key, "XKeyboardLayouts") == 0) {
                 const char **new_x_keyboard_layouts;
 
@@ -1518,6 +1554,36 @@ act_user_set_user_name (ActUser    *user
                 g_error_free (error);
                 return;
         }
+}
+
+/**
+ * act_user_set_x_has_messages:
+ * @user: the user object to alter.
+ * @has_messages: whether the user has messages waiting
+ *
+ * Sets a new has-messages status for @user.
+ *
+ * Note this function is synchronous and ignores errors.
+ **/
+void
+act_user_set_x_has_messages (ActUser  *user,
+                             gboolean  has_messages)
+{
+        GError *error = NULL;
+
+        g_return_if_fail (ACT_IS_USER (user));
+        g_return_if_fail (DBUS_IS_G_PROXY (user->accounts_proxy));
+
+        if (!dbus_g_proxy_call (user->accounts_proxy,
+                                "SetXHasMessages",
+                                &error,
+                                G_TYPE_BOOLEAN, has_messages,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetXHasMessages call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
 }
 
 /**
--- accountsservice.orig/src/user.c
+++ accountsservice/src/user.c
@@ -66,6 +66,7 @@ enum {
         PROP_PASSWORD_MODE,
         PROP_PASSWORD_HINT,
         PROP_LOGIN_FREQUENCY,
+        PROP_X_HAS_MESSAGES,
         PROP_X_KEYBOARD_LAYOUTS,
         PROP_BACKGROUND_FILE,
         PROP_ICON_FILE,
@@ -104,6 +105,7 @@ struct User {
         gchar        *x_session;
         gchar        *location;
         guint64       login_frequency;
+        gboolean      x_has_messages;
         gchar       **x_keyboard_layouts;
         gchar        *background_file;
         gchar        *icon_file;
@@ -216,6 +218,9 @@ user_get_property (GObject    *object,
         case PROP_LOCATION:
                 g_value_set_string (value, user->location);
                 break;
+        case PROP_X_HAS_MESSAGES:
+                g_value_set_boolean (value, user->x_has_messages);
+                break;
         case PROP_X_KEYBOARD_LAYOUTS:
                 g_value_set_boxed (value, g_strdupv (user->x_keyboard_layouts));
                 break;
@@ -382,6 +387,13 @@ user_class_init (UserClass *class)
                                                               0,
                                                               G_PARAM_READWRITE));
         g_object_class_install_property (gobject_class,
+                                         PROP_X_HAS_MESSAGES,
+                                         g_param_spec_boolean ("x-has-messages",
+                                                               "Has Messages",
+                                                               "Whether the user has messages waiting.",
+                                                               FALSE,
+                                                               G_PARAM_READABLE));
+        g_object_class_install_property (gobject_class,
                                          PROP_X_KEYBOARD_LAYOUTS,
                                          g_param_spec_boxed ("x-keyboard-layouts",
                                                              "Keyboard layouts",
@@ -439,6 +451,7 @@ user_init (User *user)
         user->account_type = ACCOUNT_TYPE_STANDARD;
         user->home_dir = NULL;
         user->shell = NULL;
+        user->x_has_messages = FALSE;
         user->x_keyboard_layouts = NULL;
         user->background_file = NULL;
         user->icon_file = NULL;
@@ -1978,6 +1991,60 @@ become_user (gpointer data)
 }
 
 static void
+user_change_x_has_messages_authorized_cb (Daemon                *daemon,
+                                          User                  *user,
+                                          DBusGMethodInvocation *context,
+                                          gpointer               data)
+{
+        user->x_has_messages = GPOINTER_TO_INT (data);
+
+        g_signal_emit (user, signals[CHANGED], 0);
+
+        g_object_notify (G_OBJECT (user), "x-has-messages");
+
+        dbus_g_method_return (context);
+}
+
+gboolean
+user_set_xhas_messages (User                  *user,
+                        gboolean               has_messages,
+                        DBusGMethodInvocation *context)
+{
+        gchar *sender;
+        DBusConnection *connection;
+        DBusError dbus_error;
+        uid_t uid;
+        const gchar *action_id;
+
+        connection = dbus_g_connection_get_connection (user->system_bus_connection);
+        sender = dbus_g_method_get_sender (context);
+        dbus_error_init (&dbus_error);
+        uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
+        if (dbus_error_is_set (&dbus_error)) {
+                throw_error (context, ERROR_FAILED, dbus_error.message);
+                dbus_error_free (&dbus_error);
+
+                return TRUE;
+        }
+
+        if (user->uid == uid)
+                action_id = "org.freedesktop.accounts.change-own-user-data";
+        else
+                action_id = "org.freedesktop.accounts.user-administration";
+
+        daemon_local_check_auth (user->daemon,
+                                 user,
+                                 action_id,
+                                 TRUE,
+                                 user_change_x_has_messages_authorized_cb,
+                                 context,
+                                 GINT_TO_POINTER (has_messages),
+                                 NULL);
+
+        return TRUE;
+}
+
+static void
 user_change_x_keyboard_layouts_authorized_cb (Daemon                *daemon,
                                               User                  *user,
                                               DBusGMethodInvocation *context,
--- accountsservice.orig/src/user.h
+++ accountsservice/src/user.h
@@ -95,6 +95,9 @@ gboolean       user_set_home_directory (
 gboolean       user_set_shell          (User                  *user,
                                         const gchar           *shell,
                                         DBusGMethodInvocation *context);
+gboolean       user_set_xhas_messages  (User                  *user,
+                                        gboolean               has_messages,
+                                        DBusGMethodInvocation *context);
 gboolean       user_set_xkeyboard_layouts(User                  *user,
                                           const gchar * const   *layouts,
                                           DBusGMethodInvocation *context);
