[gnome-session] gsm-consolekit: add support for ConsoleKit2
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-session] gsm-consolekit: add support for ConsoleKit2
- Date: Wed, 21 Jun 2017 22:23:41 +0000 (UTC)
commit 445aa5e10e0d3e5a20800bfcb2ac4b267977bcdf
Author: Eric Koegel <eric koegel gmail com>
Date: Sun May 28 05:48:54 2017 +0300
gsm-consolekit: add support for ConsoleKit2
This patch adds support for ConsoleKit2's suspend, hibernate, and
inhibit calls. In doing this, gsm-consolekit.c has been rebased
from the gsm-systemd.c file so that consolekit uses GDBus instead
of dbus-glib. Additionally, this continues to support ConsoleKit
+ HAVE_OLD_UPOWER code paths for any systems that haven't migrated
to ConsoleKit2.
https://bugzilla.gnome.org/show_bug.cgi?id=783313
gnome-session/gsm-consolekit.c | 1301 +++++++++++++++++++---------------------
1 files changed, 626 insertions(+), 675 deletions(-)
---
diff --git a/gnome-session/gsm-consolekit.c b/gnome-session/gsm-consolekit.c
index 3d3891e..34b5d35 100644
--- a/gnome-session/gsm-consolekit.c
+++ b/gnome-session/gsm-consolekit.c
@@ -20,14 +20,16 @@
#include <errno.h>
#include <string.h>
+#include <stdlib.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gi18n.h>
-
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
#ifdef HAVE_OLD_UPOWER
#define UPOWER_ENABLE_DEPRECATED 1
@@ -38,32 +40,30 @@
#include "gsm-consolekit.h"
#define CK_NAME "org.freedesktop.ConsoleKit"
-#define CK_PATH "/org/freedesktop/ConsoleKit"
-
-#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
-#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
-#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat"
-#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
-#define GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW "LoginWindow"
+#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE CK_NAME ".Manager"
+#define CK_SEAT_INTERFACE CK_NAME ".Seat"
+#define CK_SESSION_INTERFACE CK_NAME ".Session"
-#define GSM_CONSOLEKIT_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_CONSOLEKIT, GsmConsolekitPrivate))
struct _GsmConsolekitPrivate
{
- DBusGConnection *dbus_connection;
- DBusGProxy *bus_proxy;
- DBusGProxy *ck_proxy;
- DBusGProxy *session_proxy;
+ GDBusProxy *ck_proxy;
+ GDBusProxy *ck_session_proxy;
#ifdef HAVE_OLD_UPOWER
UpClient *up_client;
#endif
+ char *session_id;
+ gchar *session_path;
+
+ GSList *inhibitors;
+ gint inhibit_fd;
gboolean is_active;
- gboolean restarting;
- gchar *session_id;
+ gint delay_inhibit_fd;
+ gboolean prepare_for_shutdown_expected;
};
enum {
@@ -71,22 +71,6 @@ enum {
PROP_ACTIVE
};
-static void gsm_consolekit_class_init (GsmConsolekitClass *klass);
-static void gsm_consolekit_init (GsmConsolekit *ck);
-static void gsm_consolekit_finalize (GObject *object);
-
-static void gsm_consolekit_free_dbus (GsmConsolekit *manager);
-
-static DBusHandlerResult gsm_consolekit_dbus_filter (DBusConnection *connection,
- DBusMessage *message,
- void *user_data);
-
-static void gsm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy,
- const char *name,
- const char *prev_owner,
- const char *new_owner,
- GsmConsolekit *manager);
-
static void gsm_consolekit_system_init (GsmSystemInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT,
@@ -94,6 +78,49 @@ G_DEFINE_TYPE_WITH_CODE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT,
gsm_consolekit_system_init))
static void
+drop_system_inhibitor (GsmConsolekit *manager)
+{
+ if (manager->priv->inhibit_fd != -1) {
+ g_debug ("GsmConsolekit: Dropping system inhibitor");
+ close (manager->priv->inhibit_fd);
+ manager->priv->inhibit_fd = -1;
+ }
+}
+
+static void
+drop_delay_inhibitor (GsmConsolekit *manager)
+{
+ if (manager->priv->delay_inhibit_fd != -1) {
+ g_debug ("GsmConsolekit: Dropping delay inhibitor");
+ close (manager->priv->delay_inhibit_fd);
+ manager->priv->delay_inhibit_fd = -1;
+ }
+}
+
+static void
+gsm_consolekit_finalize (GObject *object)
+{
+ GsmConsolekit *consolekit = GSM_CONSOLEKIT (object);
+
+ g_clear_object (&consolekit->priv->ck_proxy);
+ g_clear_object (&consolekit->priv->ck_session_proxy);
+ free (consolekit->priv->session_id);
+ g_free (consolekit->priv->session_path);
+
+ if (consolekit->priv->inhibitors != NULL) {
+ g_slist_free_full (consolekit->priv->inhibitors, g_free);
+ }
+ drop_system_inhibitor (consolekit);
+ drop_delay_inhibitor (consolekit);
+
+#ifdef HAVE_OLD_UPOWER
+ g_clear_object (&manager->priv->up_client);
+#endif
+
+ G_OBJECT_CLASS (gsm_consolekit_parent_class)->finalize (object);
+}
+
+static void
gsm_consolekit_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -144,283 +171,126 @@ gsm_consolekit_class_init (GsmConsolekitClass *manager_class)
g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate));
}
-static DBusHandlerResult
-gsm_consolekit_dbus_filter (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- GsmConsolekit *manager;
-
- manager = GSM_CONSOLEKIT (user_data);
-
- if (dbus_message_is_signal (message,
- DBUS_INTERFACE_LOCAL, "Disconnected") &&
- strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
- gsm_consolekit_free_dbus (manager);
- /* let other filters get this disconnected signal, so that they
- * can handle it too */
- }
+static void ck_session_proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
+static void ck_proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data);
static void
-is_active_cb (DBusGProxy *proxy,
- DBusGProxyCall *call,
- gpointer data)
+ck_pid_get_session (GsmConsolekit *manager,
+ pid_t pid,
+ gchar **session_id)
{
- GsmConsolekit *self = data;
- GError *local_error = NULL;
- gboolean is_active;
+ GVariant *res;
- if (!dbus_g_proxy_end_call (proxy, call, &local_error,
- G_TYPE_BOOLEAN, &is_active,
- G_TYPE_INVALID)) {
- g_warning ("Failed IsActive call to ConsoleKit: %s",
- local_error->message);
- g_clear_error (&local_error);
+ *session_id = NULL;
+
+ if (pid < 0) {
+ g_warning ("Calling GetSessionForUnixProcess failed."
+ "Invalid pid.");
return;
}
- if (is_active != self->priv->is_active) {
- self->priv->is_active = is_active;
- g_object_notify ((GObject*) self, "active");
+ res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
+ "GetSessionForUnixProcess",
+ g_variant_new ("(u)", pid),
+ 0,
+ -1,
+ NULL,
+ NULL);
+ if (!res) {
+ g_warning ("Calling GetSessionForUnixProcess failed."
+ "Check that ConsoleKit is properly installed.");
+ return;
}
-}
-static void
-on_active_changed (DBusGProxy *proxy,
- gboolean is_active,
- GsmConsolekit *self)
-{
- if (is_active != self->priv->is_active) {
- self->priv->is_active = is_active;
- g_object_notify ((GObject*) self, "active");
- }
+ g_variant_get (res, "(o)", session_id);
+ g_variant_unref (res);
}
-static gboolean
-gsm_consolekit_ensure_ck_connection (GsmConsolekit *manager,
- GError **error)
+static void
+gsm_consolekit_init (GsmConsolekit *manager)
{
- GError *connection_error;
- gboolean is_connected;
- gboolean ret;
- guint32 pid;
-
- connection_error = NULL;
- manager->priv->session_id = NULL;
- is_connected = FALSE;
-
- if (manager->priv->dbus_connection == NULL) {
- DBusConnection *connection;
-
- manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM,
- &connection_error);
-
- if (manager->priv->dbus_connection == NULL) {
- g_propagate_error (error, connection_error);
- is_connected = FALSE;
- goto out;
- }
-
- connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
- dbus_connection_set_exit_on_disconnect (connection, FALSE);
- dbus_connection_add_filter (connection,
- gsm_consolekit_dbus_filter,
- manager, NULL);
- }
-
- if (manager->priv->bus_proxy == NULL) {
- manager->priv->bus_proxy =
- dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &connection_error);
-
- if (manager->priv->bus_proxy == NULL) {
- g_propagate_error (error, connection_error);
- is_connected = FALSE;
- goto out;
- }
-
- dbus_g_proxy_add_signal (manager->priv->bus_proxy,
- "NameOwnerChanged",
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_INVALID);
-
- dbus_g_proxy_connect_signal (manager->priv->bus_proxy,
- "NameOwnerChanged",
- G_CALLBACK (gsm_consolekit_on_name_owner_changed),
- manager, NULL);
- }
-
+ GError *error = NULL;
+ GDBusConnection *bus;
+ GVariant *res;
+
+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+ GSM_TYPE_CONSOLEKIT,
+ GsmConsolekitPrivate);
+
+ manager->priv->inhibit_fd = -1;
+ manager->priv->delay_inhibit_fd = -1;
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (bus == NULL)
+ g_error ("Failed to connect to system bus: %s",
+ error->message);
+ manager->priv->ck_proxy =
+ g_dbus_proxy_new_sync (bus,
+ 0,
+ NULL,
+ CK_NAME,
+ CK_MANAGER_PATH,
+ CK_MANAGER_INTERFACE,
+ NULL,
+ &error);
if (manager->priv->ck_proxy == NULL) {
- manager->priv->ck_proxy =
- dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection,
- CK_NAME,
- CK_MANAGER_PATH,
- CK_MANAGER_INTERFACE,
- &connection_error);
-
- if (manager->priv->ck_proxy == NULL) {
- g_propagate_error (error, connection_error);
- is_connected = FALSE;
- goto out;
- }
- }
-
- pid = getpid ();
- ret = dbus_g_proxy_call (manager->priv->ck_proxy, "GetSessionForUnixProcess", &connection_error,
- G_TYPE_UINT, pid,
- G_TYPE_INVALID,
- DBUS_TYPE_G_OBJECT_PATH, &manager->priv->session_id,
- G_TYPE_INVALID);
- if (!ret) {
- g_propagate_error (error, connection_error);
- goto out;
- }
-
- if (manager->priv->session_proxy == NULL) {
- manager->priv->session_proxy =
- dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection,
- CK_NAME,
- manager->priv->session_id,
- CK_SESSION_INTERFACE,
- &connection_error);
-
- if (manager->priv->session_proxy == NULL) {
- g_propagate_error (error, connection_error);
- is_connected = FALSE;
- goto out;
- }
-
- dbus_g_proxy_begin_call (manager->priv->session_proxy,
- "IsActive",
- is_active_cb, g_object_ref (manager),
- (GDestroyNotify)g_object_unref,
- G_TYPE_INVALID);
- dbus_g_proxy_add_signal (manager->priv->session_proxy, "ActiveChanged", G_TYPE_BOOLEAN,
G_TYPE_INVALID);
- dbus_g_proxy_connect_signal (manager->priv->session_proxy, "ActiveChanged",
- G_CALLBACK (on_active_changed), manager, NULL);
+ g_warning ("Failed to connect to consolekit: %s",
+ error->message);
+ g_clear_error (&error);
}
-#ifdef HAVE_OLD_UPOWER
- g_clear_object (&manager->priv->up_client);
- manager->priv->up_client = up_client_new ();
-#endif
+ g_signal_connect (manager->priv->ck_proxy, "g-signal",
+ G_CALLBACK (ck_proxy_signal_cb), manager);
- is_connected = TRUE;
-
- out:
- if (!is_connected) {
- if (manager->priv->dbus_connection == NULL) {
- if (manager->priv->bus_proxy != NULL) {
- g_object_unref (manager->priv->bus_proxy);
- manager->priv->bus_proxy = NULL;
- }
-
- if (manager->priv->ck_proxy != NULL) {
- g_object_unref (manager->priv->ck_proxy);
- manager->priv->ck_proxy = NULL;
- }
-
- g_clear_object (&manager->priv->session_proxy);
- g_clear_object (&manager->priv->session_id);
- } else if (manager->priv->bus_proxy == NULL) {
- if (manager->priv->ck_proxy != NULL) {
- g_object_unref (manager->priv->ck_proxy);
- manager->priv->ck_proxy = NULL;
- }
-
- g_clear_object (&manager->priv->session_proxy);
- g_clear_object (&manager->priv->session_id);
- }
- }
-
- return is_connected;
-}
+ ck_pid_get_session (manager, getpid (), &manager->priv->session_id);
-static void
-gsm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy,
- const char *name,
- const char *prev_owner,
- const char *new_owner,
- GsmConsolekit *manager)
-{
- if (name != NULL && strcmp (name, "org.freedesktop.ConsoleKit") != 0) {
+ if (manager->priv->session_id == NULL) {
+ g_warning ("Could not get session id for session. Check that ConsoleKit is "
+ "properly installed.");
return;
}
- g_clear_object (&manager->priv->ck_proxy);
- g_clear_object (&manager->priv->session_proxy);
-
- gsm_consolekit_ensure_ck_connection (manager, NULL);
-
-}
-
-static void
-gsm_consolekit_init (GsmConsolekit *manager)
-{
- GError *error;
-
- manager->priv = GSM_CONSOLEKIT_GET_PRIVATE (manager);
-
- error = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
+ /* in ConsoleKit, the session id is the session path */
+ manager->priv->session_path = g_strdup (manager->priv->session_id);
+
+ manager->priv->ck_session_proxy =
+ g_dbus_proxy_new_sync (bus,
+ 0,
+ NULL,
+ CK_NAME,
+ manager->priv->session_path,
+ CK_SESSION_INTERFACE,
+ NULL,
+ &error);
+ if (manager->priv->ck_proxy == NULL) {
+ g_warning ("Failed to connect to consolekit session: %s",
error->message);
- g_error_free (error);
+ g_clear_error (&error);
}
-}
-static void
-gsm_consolekit_free_dbus (GsmConsolekit *manager)
-{
- g_clear_object (&manager->priv->bus_proxy);
- g_clear_object (&manager->priv->ck_proxy);
- g_clear_object (&manager->priv->session_proxy);
- g_clear_object (&manager->priv->session_id);
+ g_signal_connect (manager->priv->ck_session_proxy, "g-signal",
+ G_CALLBACK (ck_session_proxy_signal_cb), manager);
+
#ifdef HAVE_OLD_UPOWER
g_clear_object (&manager->priv->up_client);
+ manager->priv->up_client = up_client_new ();
#endif
- if (manager->priv->dbus_connection != NULL) {
- DBusConnection *connection;
- connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
- dbus_connection_remove_filter (connection,
- gsm_consolekit_dbus_filter,
- manager);
-
- dbus_g_connection_unref (manager->priv->dbus_connection);
- manager->priv->dbus_connection = NULL;
- }
-}
-
-static void
-gsm_consolekit_finalize (GObject *object)
-{
- GsmConsolekit *manager;
- GObjectClass *parent_class;
-
- manager = GSM_CONSOLEKIT (object);
-
- parent_class = G_OBJECT_CLASS (gsm_consolekit_parent_class);
-
- gsm_consolekit_free_dbus (manager);
-
- if (parent_class->finalize != NULL) {
- parent_class->finalize (object);
- }
+ g_object_unref (bus);
}
static void
emit_restart_complete (GsmConsolekit *manager,
- GError *error)
+ GError *error)
{
GError *call_error;
@@ -442,7 +312,7 @@ emit_restart_complete (GsmConsolekit *manager,
static void
emit_stop_complete (GsmConsolekit *manager,
- GError *error)
+ GError *error)
{
GError *call_error;
@@ -463,28 +333,16 @@ emit_stop_complete (GsmConsolekit *manager,
}
static void
-gsm_consolekit_attempt_restart (GsmSystem *system)
+restart_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- gboolean res;
- GError *error;
-
- error = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- emit_restart_complete (manager, error);
- g_error_free (error);
- return;
- }
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsmConsolekit *manager = user_data;
+ GError *error = NULL;
+ GVariant *res;
- res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
- "Restart",
- INT_MAX,
- &error,
- G_TYPE_INVALID,
- G_TYPE_INVALID);
+ res = g_dbus_proxy_call_finish (proxy, result, &error);
if (!res) {
g_warning ("Unable to restart system: %s", error->message);
@@ -492,32 +350,38 @@ gsm_consolekit_attempt_restart (GsmSystem *system)
g_error_free (error);
} else {
emit_restart_complete (manager, NULL);
+ g_variant_unref (res);
}
}
static void
-gsm_consolekit_attempt_stop (GsmSystem *system)
+gsm_consolekit_attempt_restart (GsmSystem *system)
{
GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- gboolean res;
- GError *error;
- error = NULL;
+ /* Use Restart instead of Reboot because it will work on
+ * both CK and CK2 */
+ g_dbus_proxy_call (manager->priv->ck_proxy,
+ "Restart",
+ g_variant_new ("()"),
+ 0,
+ G_MAXINT,
+ NULL,
+ restart_done,
+ manager);
+}
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- emit_stop_complete (manager, error);
- g_error_free (error);
- return;
- }
+static void
+stop_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsmConsolekit *manager = user_data;
+ GError *error = NULL;
+ GVariant *res;
- res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
- "Stop",
- INT_MAX,
- &error,
- G_TYPE_INVALID,
- G_TYPE_INVALID);
+ res = g_dbus_proxy_call_finish (proxy, result, &error);
if (!res) {
g_warning ("Unable to stop system: %s", error->message);
@@ -525,312 +389,137 @@ gsm_consolekit_attempt_stop (GsmSystem *system)
g_error_free (error);
} else {
emit_stop_complete (manager, NULL);
+ g_variant_unref (res);
}
}
-static gboolean
-get_current_session_id (DBusConnection *connection,
- char **session_id)
-{
- DBusError local_error;
- DBusMessage *message;
- DBusMessage *reply;
- gboolean ret;
- DBusMessageIter iter;
- const char *value;
-
- ret = FALSE;
- reply = NULL;
-
- dbus_error_init (&local_error);
- message = dbus_message_new_method_call (CK_NAME,
- CK_MANAGER_PATH,
- CK_MANAGER_INTERFACE,
- "GetCurrentSession");
- if (message == NULL) {
- goto out;
- }
-
- dbus_error_init (&local_error);
- reply = dbus_connection_send_with_reply_and_block (connection,
- message,
- -1,
- &local_error);
- if (reply == NULL) {
- if (dbus_error_is_set (&local_error)) {
- g_warning ("Unable to determine session: %s", local_error.message);
- dbus_error_free (&local_error);
- goto out;
- }
- }
-
- dbus_message_iter_init (reply, &iter);
- dbus_message_iter_get_basic (&iter, &value);
- if (session_id != NULL) {
- *session_id = g_strdup (value);
- }
-
- ret = TRUE;
- out:
- if (message != NULL) {
- dbus_message_unref (message);
- }
- if (reply != NULL) {
- dbus_message_unref (reply);
- }
-
- return ret;
-}
-
-static gboolean
-get_seat_id_for_session (DBusConnection *connection,
- const char *session_id,
- char **seat_id)
+static void
+gsm_consolekit_attempt_stop (GsmSystem *system)
{
- DBusError local_error;
- DBusMessage *message;
- DBusMessage *reply;
- gboolean ret;
- DBusMessageIter iter;
- const char *value;
-
- ret = FALSE;
- reply = NULL;
-
- dbus_error_init (&local_error);
- message = dbus_message_new_method_call (CK_NAME,
- session_id,
- CK_SESSION_INTERFACE,
- "GetSeatId");
- if (message == NULL) {
- goto out;
- }
-
- dbus_error_init (&local_error);
- reply = dbus_connection_send_with_reply_and_block (connection,
- message,
- -1,
- &local_error);
- if (reply == NULL) {
- if (dbus_error_is_set (&local_error)) {
- g_warning ("Unable to determine seat: %s", local_error.message);
- dbus_error_free (&local_error);
- goto out;
- }
- }
-
- dbus_message_iter_init (reply, &iter);
- dbus_message_iter_get_basic (&iter, &value);
- if (seat_id != NULL) {
- *seat_id = g_strdup (value);
- }
-
- ret = TRUE;
- out:
- if (message != NULL) {
- dbus_message_unref (message);
- }
- if (reply != NULL) {
- dbus_message_unref (reply);
- }
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- return ret;
+ /* Use Stop insetad of PowerOff because it will work with
+ * Ck and CK2. */
+ g_dbus_proxy_call (manager->priv->ck_proxy,
+ "Stop",
+ g_variant_new ("()"),
+ 0,
+ G_MAXINT,
+ NULL,
+ stop_done,
+ manager);
}
-static char *
-get_current_seat_id (DBusConnection *connection)
+static void
+gsm_consolekit_set_session_idle (GsmSystem *system,
+ gboolean is_idle)
{
- gboolean res;
- char *session_id;
- char *seat_id;
-
- session_id = NULL;
- seat_id = NULL;
-
- res = get_current_session_id (connection, &session_id);
- if (res) {
- res = get_seat_id_for_session (connection, session_id, &seat_id);
- }
- g_free (session_id);
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- return seat_id;
+ g_debug ("Updating consolekit idle status: %d", is_idle);
+ g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
+ "SetIdleHint",
+ g_variant_new ("(b)", is_idle),
+ 0,
+ G_MAXINT,
+ NULL, NULL);
}
static void
-gsm_consolekit_set_session_idle (GsmSystem *system,
- gboolean is_idle)
+ck_session_get_seat (GsmConsolekit *manager,
+ gchar **seat)
{
- GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- gboolean res;
- GError *error;
- char *session_id;
- DBusMessage *message;
- DBusMessage *reply;
- DBusError dbus_error;
- DBusMessageIter iter;
-
- error = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- g_error_free (error);
- return;
- }
+ GVariant *res;
- session_id = NULL;
- res = get_current_session_id (dbus_g_connection_get_connection (manager->priv->dbus_connection),
- &session_id);
- if (!res) {
- goto out;
- }
+ *seat = NULL;
-
- g_debug ("Updating ConsoleKit idle status: %d", is_idle);
- message = dbus_message_new_method_call (CK_NAME,
- session_id,
- CK_SESSION_INTERFACE,
- "SetIdleHint");
- if (message == NULL) {
- g_debug ("Couldn't allocate the D-Bus message");
+ res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
+ "GetSeatId",
+ g_variant_new ("()"),
+ 0,
+ -1,
+ NULL, NULL);
+ if (!res) {
+ g_warning ("GsmConsoleKit: Calling GetSeatId failed.");
return;
}
- dbus_message_iter_init_append (message, &iter);
- dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &is_idle);
-
- /* FIXME: use async? */
- dbus_error_init (&dbus_error);
- reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection
(manager->priv->dbus_connection),
- message,
- -1,
- &dbus_error);
- dbus_message_unref (message);
-
- if (reply != NULL) {
- dbus_message_unref (reply);
- }
-
- if (dbus_error_is_set (&dbus_error)) {
- g_debug ("%s raised:\n %s\n\n", dbus_error.name, dbus_error.message);
- dbus_error_free (&dbus_error);
- }
-
-out:
- g_free (session_id);
+ g_variant_get (res, "(o)", seat);
+ g_variant_unref (res);
}
-static gboolean
-seat_can_activate_sessions (DBusConnection *connection,
- const char *seat_id)
+/* returns -1 on failure
+ * 0 seat is multi-session
+ * 1 seat is not multi-session
+ */
+static gint
+ck_seat_can_multi_session (GsmConsolekit *manager,
+ const gchar *seat)
{
- DBusError local_error;
- DBusMessage *message;
- DBusMessage *reply;
- DBusMessageIter iter;
- gboolean can_activate;
-
- can_activate = FALSE;
- reply = NULL;
-
- dbus_error_init (&local_error);
- message = dbus_message_new_method_call (CK_NAME,
- seat_id,
- CK_SEAT_INTERFACE,
- "CanActivateSessions");
- if (message == NULL) {
- goto out;
- }
-
- dbus_error_init (&local_error);
- reply = dbus_connection_send_with_reply_and_block (connection,
- message,
- -1,
- &local_error);
- if (reply == NULL) {
- if (dbus_error_is_set (&local_error)) {
- g_warning ("Unable to activate session: %s", local_error.message);
- dbus_error_free (&local_error);
- goto out;
- }
+ GDBusConnection *bus;
+ GVariant *res;
+ gboolean can_activate;
+
+
+ bus = g_dbus_proxy_get_connection (manager->priv->ck_proxy);
+ res = g_dbus_connection_call_sync (bus,
+ CK_NAME,
+ seat,
+ CK_SEAT_INTERFACE,
+ "CanActivateSessions",
+ g_variant_new ("()"),
+ G_VARIANT_TYPE_BOOLEAN,
+ 0,
+ -1,
+ NULL, NULL);
+ if (!res) {
+ g_warning ("GsmConsoleKit: Calling GetSeatId failed.");
+ return -1;
}
- dbus_message_iter_init (reply, &iter);
- dbus_message_iter_get_basic (&iter, &can_activate);
-
- out:
- if (message != NULL) {
- dbus_message_unref (message);
- }
- if (reply != NULL) {
- dbus_message_unref (reply);
- }
+ g_variant_get (res, "(b)", &can_activate);
+ g_variant_unref (res);
- return can_activate;
+ return can_activate == TRUE ? 1 : 0;
}
static gboolean
gsm_consolekit_can_switch_user (GsmSystem *system)
{
GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- GError *error;
- char *seat_id;
- gboolean ret;
+ gchar *seat;
+ gint ret;
- error = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- g_error_free (error);
- return FALSE;
- }
+ ck_session_get_seat (manager, &seat);
+ ret = ck_seat_can_multi_session (manager, seat);
+ free (seat);
- seat_id = get_current_seat_id (dbus_g_connection_get_connection (manager->priv->dbus_connection));
- if (seat_id == NULL || seat_id[0] == '\0') {
- g_debug ("seat id is not set; can't switch sessions");
- return FALSE;
- }
-
- ret = seat_can_activate_sessions (dbus_g_connection_get_connection (manager->priv->dbus_connection),
- seat_id);
- g_free (seat_id);
-
- return ret;
+ return ret > 0;
}
static gboolean
gsm_consolekit_can_restart (GsmSystem *system)
{
GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- gboolean res;
+ GVariant *res;
gboolean can_restart;
- GError *error;
-
- error = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- g_error_free (error);
- return FALSE;
- }
-
- res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
- "CanRestart",
- INT_MAX,
- &error,
- G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &can_restart,
- G_TYPE_INVALID);
+ res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
+ "CanRestart",
+ g_variant_new ("()"),
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL);
if (!res) {
- g_warning ("Could not query CanRestart from ConsoleKit: %s",
- error->message);
- g_error_free (error);
+ g_warning ("Calling CanRestart failed. Check that ConsoleKit is "
+ "properly installed.");
return FALSE;
}
+ g_variant_get (res, "(b)", &can_restart);
+ g_variant_unref (res);
+
return can_restart;
}
@@ -838,115 +527,75 @@ static gboolean
gsm_consolekit_can_stop (GsmSystem *system)
{
GsmConsolekit *manager = GSM_CONSOLEKIT (system);
- gboolean res;
+ GVariant *res;
gboolean can_stop;
- GError *error;
-
- error = NULL;
- if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- error->message);
- g_error_free (error);
+ res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
+ "CanStop",
+ g_variant_new ("()"),
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL);
+ if (!res) {
+ g_warning ("Calling CanStop failed. Check that ConsoleKit is "
+ "properly installed.");
return FALSE;
}
- res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
- "CanStop",
- INT_MAX,
- &error,
- G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &can_stop,
- G_TYPE_INVALID);
+ g_variant_get (res, "(b)", &can_stop);
+ g_variant_unref (res);
- if (!res) {
- g_warning ("Could not query CanStop from ConsoleKit: %s",
- error->message);
- g_error_free (error);
- return FALSE;
- }
return can_stop;
}
-static gchar *
-gsm_consolekit_get_current_session_type (GsmConsolekit *manager)
+/* returns -1 on failure, 0 on success */
+static gint
+ck_session_get_class (GsmConsolekit *manager,
+ gchar **session_class)
{
- GError *gerror;
- DBusConnection *connection;
- DBusError error;
- DBusMessage *message = NULL;
- DBusMessage *reply = NULL;
- gchar *session_id;
- gchar *ret;
- DBusMessageIter iter;
- const char *value;
-
- session_id = NULL;
- ret = NULL;
- gerror = NULL;
-
- if (!gsm_consolekit_ensure_ck_connection (manager, &gerror)) {
- g_warning ("Could not connect to ConsoleKit: %s",
- gerror->message);
- g_error_free (gerror);
- goto out;
- }
+ GVariant *res;
- connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
- if (!get_current_session_id (connection, &session_id)) {
- goto out;
- }
-
- dbus_error_init (&error);
- message = dbus_message_new_method_call (CK_NAME,
- session_id,
- CK_SESSION_INTERFACE,
- "GetSessionType");
- if (message == NULL) {
- goto out;
- }
+ *session_class = NULL;
- reply = dbus_connection_send_with_reply_and_block (connection,
- message,
- -1,
- &error);
-
- if (reply == NULL) {
- if (dbus_error_is_set (&error)) {
- g_warning ("Unable to determine session type: %s", error.message);
- dbus_error_free (&error);
- }
- goto out;
+ res = g_dbus_proxy_call_sync (manager->priv->ck_session_proxy,
+ "GetSessionClass",
+ g_variant_new ("()"),
+ 0,
+ -1,
+ NULL, NULL);
+ if (!res) {
+ g_warning ("GsmConsoleKit: Calling GetSessionClass failed.");
+ return -1;
}
- dbus_message_iter_init (reply, &iter);
- dbus_message_iter_get_basic (&iter, &value);
- ret = g_strdup (value);
-
-out:
- if (message != NULL) {
- dbus_message_unref (message);
- }
- if (reply != NULL) {
- dbus_message_unref (reply);
- }
- g_free (session_id);
+ g_variant_get (res, "(s)", session_class);
+ g_variant_unref (res);
- return ret;
+ return 0;
}
static gboolean
gsm_consolekit_is_login_session (GsmSystem *system)
{
- GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
- char *session_type;
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+ int res;
gboolean ret;
+ gchar *session_class = NULL;
- session_type = gsm_consolekit_get_current_session_type (consolekit);
+ ret = FALSE;
- ret = (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) == 0);
+ if (manager->priv->session_id == NULL) {
+ return ret;
+ }
- g_free (session_type);
+ res = ck_session_get_class (manager, &session_class);
+ if (res < 0) {
+ g_warning ("Could not get session class: %s", strerror (-res));
+ return FALSE;
+ }
+ ret = (g_strcmp0 (session_class, "greeter") == 0);
+ g_free (session_class);
return ret;
}
@@ -958,7 +607,33 @@ gsm_consolekit_can_suspend (GsmSystem *system)
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
return up_client_get_can_suspend (consolekit->priv->up_client);
#else
- return FALSE;
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+ gchar *rv;
+ GVariant *res;
+ gboolean can_suspend;
+
+ res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
+ "CanSuspend",
+ NULL,
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL);
+ if (!res) {
+ g_warning ("Calling CanSuspend failed. Check that ConsoleKit is "
+ "properly installed.");
+ return FALSE;
+ }
+
+ g_variant_get (res, "(s)", &rv);
+ g_variant_unref (res);
+
+ can_suspend = g_strcmp0 (rv, "yes") == 0 ||
+ g_strcmp0 (rv, "challenge") == 0;
+
+ g_free (rv);
+
+ return can_suspend;
#endif
}
@@ -969,11 +644,75 @@ gsm_consolekit_can_hibernate (GsmSystem *system)
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
return up_client_get_can_hibernate (consolekit->priv->up_client);
#else
- return FALSE;
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+ gchar *rv;
+ GVariant *res;
+ gboolean can_hibernate;
+
+ res = g_dbus_proxy_call_sync (manager->priv->ck_proxy,
+ "CanHibernate",
+ NULL,
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL);
+ if (!res) {
+ g_warning ("Calling CanHibernate failed. Check that ConsoleKit is "
+ "properly installed.");
+ return FALSE;
+ }
+
+ g_variant_get (res, "(s)", &rv);
+ g_variant_unref (res);
+
+ can_hibernate = g_strcmp0 (rv, "yes") == 0 ||
+ g_strcmp0 (rv, "challenge") == 0;
+
+ g_free (rv);
+
+ return can_hibernate;
#endif
}
static void
+suspend_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GError *error = NULL;
+ GVariant *res;
+
+ res = g_dbus_proxy_call_finish (proxy, result, &error);
+
+ if (!res) {
+ g_warning ("Unable to suspend system: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_unref (res);
+ }
+}
+
+static void
+hibernate_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GError *error = NULL;
+ GVariant *res;
+
+ res = g_dbus_proxy_call_finish (proxy, result, &error);
+
+ if (!res) {
+ g_warning ("Unable to hibernate system: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_unref (res);
+ }
+}
+
+static void
gsm_consolekit_suspend (GsmSystem *system)
{
#ifdef HAVE_OLD_UPOWER
@@ -986,6 +725,17 @@ gsm_consolekit_suspend (GsmSystem *system)
g_warning ("Unexpected suspend failure: %s", error->message);
g_error_free (error);
}
+#else
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+
+ g_dbus_proxy_call (manager->priv->ck_proxy,
+ "Suspend",
+ g_variant_new ("(b)", TRUE),
+ 0,
+ G_MAXINT,
+ NULL,
+ suspend_done,
+ manager);
#endif
}
@@ -1002,20 +752,126 @@ gsm_consolekit_hibernate (GsmSystem *system)
g_warning ("Unexpected hibernate failure: %s", error->message);
g_error_free (error);
}
+#else
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+
+ g_dbus_proxy_call (manager->priv->ck_proxy,
+ "Hibernate",
+ g_variant_new ("(b)", TRUE),
+ 0,
+ G_MAXINT,
+ NULL,
+ hibernate_done,
+ manager);
#endif
}
static void
+inhibit_done (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GsmConsolekit *manager = GSM_CONSOLEKIT (user_data);
+ GError *error = NULL;
+ GVariant *res;
+ GUnixFDList *fd_list = NULL;
+ gint idx;
+
+ res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
+
+ if (!res) {
+ g_warning ("Unable to inhibit system: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_variant_get (res, "(h)", &idx);
+ manager->priv->inhibit_fd = g_unix_fd_list_get (fd_list, idx, &error);
+ if (manager->priv->inhibit_fd == -1) {
+ g_warning ("Failed to receive system inhibitor fd: %s", error->message);
+ g_error_free (error);
+ }
+ g_debug ("System inhibitor fd is %d", manager->priv->inhibit_fd);
+ g_object_unref (fd_list);
+ g_variant_unref (res);
+ }
+
+ if (manager->priv->inhibitors == NULL) {
+ drop_system_inhibitor (manager);
+ }
+}
+
+static void
gsm_consolekit_add_inhibitor (GsmSystem *system,
- const gchar *id,
- GsmInhibitorFlag flag)
+ const gchar *id,
+ GsmInhibitorFlag flag)
{
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+
+ if ((flag & GSM_INHIBITOR_FLAG_SUSPEND) == 0)
+ return;
+
+ if (manager->priv->inhibitors == NULL) {
+ g_debug ("Adding system inhibitor");
+ g_dbus_proxy_call_with_unix_fd_list (manager->priv->ck_proxy,
+ "Inhibit",
+ g_variant_new ("(ssss)",
+ "sleep:shutdown",
+ g_get_user_name (),
+ "user session inhibited",
+ "block"),
+ 0,
+ G_MAXINT,
+ NULL,
+ NULL,
+ inhibit_done,
+ manager);
+ }
+ manager->priv->inhibitors = g_slist_prepend (manager->priv->inhibitors, g_strdup (id));
}
static void
gsm_consolekit_remove_inhibitor (GsmSystem *system,
- const gchar *id)
+ const gchar *id)
+{
+ GsmConsolekit *manager = GSM_CONSOLEKIT (system);
+ GSList *l;
+
+ l = g_slist_find_custom (manager->priv->inhibitors, id, (GCompareFunc)g_strcmp0);
+ if (l == NULL)
+ return;
+
+ g_free (l->data);
+ manager->priv->inhibitors = g_slist_delete_link (manager->priv->inhibitors, l);
+ if (manager->priv->inhibitors == NULL) {
+ drop_system_inhibitor (manager);
+ }
+}
+
+static void
+reboot_or_poweroff_done (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
+ GsmConsolekit *consolekit = user_data;
+ GVariant *result;
+ GError *error = NULL;
+
+ result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source),
+ res,
+ &error);
+
+ if (result == NULL) {
+ if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED)) {
+ g_warning ("Shutdown failed: %s", error->message);
+ }
+ g_error_free (error);
+ drop_delay_inhibitor (consolekit);
+ g_debug ("GsmConsolekit: shutdown preparation failed");
+ consolekit->priv->prepare_for_shutdown_expected = FALSE;
+ g_signal_emit_by_name (consolekit, "shutdown-prepared", FALSE);
+ } else {
+ g_variant_unref (result);
+ }
}
static void
@@ -1023,9 +879,51 @@ gsm_consolekit_prepare_shutdown (GsmSystem *system,
gboolean restart)
{
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
+ GUnixFDList *fd_list;
+ GVariant *res;
+ GError *error = NULL;
+ gint idx;
+
+ g_debug ("GsmConsolekit: prepare shutdown");
+
+ res = g_dbus_proxy_call_with_unix_fd_list_sync (consolekit->priv->ck_proxy,
+ "Inhibit",
+ g_variant_new ("(ssss)",
+ "shutdown",
+ g_get_user_name (),
+ "Preparing to end the session",
+ "delay"),
+ 0,
+ G_MAXINT,
+ NULL,
+ &fd_list,
+ NULL,
+ &error);
+ if (res == NULL) {
+ g_warning ("Failed to get delay inhibitor: %s", error->message);
+ g_error_free (error);
+ /* We may fail here with CK or UPOWER and that's ok */
+ } else {
+ g_variant_get (res, "(h)", &idx);
+
+ consolekit->priv->delay_inhibit_fd = g_unix_fd_list_get (fd_list, idx, NULL);
+
+ g_debug ("GsmConsolekit: got delay inhibitor, fd = %d", consolekit->priv->delay_inhibit_fd);
- consolekit->priv->restarting = restart;
- g_signal_emit_by_name (system, "shutdown-prepared", TRUE);
+ g_variant_unref (res);
+ g_object_unref (fd_list);
+ }
+
+ consolekit->priv->prepare_for_shutdown_expected = TRUE;
+
+ g_dbus_proxy_call (consolekit->priv->ck_proxy,
+ restart ? "Reboot" : "PowerOff",
+ g_variant_new ("(b)", TRUE),
+ 0,
+ G_MAXINT,
+ NULL,
+ reboot_or_poweroff_done,
+ consolekit);
}
static void
@@ -1033,10 +931,8 @@ gsm_consolekit_complete_shutdown (GsmSystem *system)
{
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
- if (consolekit->priv->restarting)
- gsm_consolekit_attempt_restart (system);
- else
- gsm_consolekit_attempt_stop (system);
+ /* remove delay inhibitor, if any */
+ drop_delay_inhibitor (consolekit);
}
static gboolean
@@ -1075,3 +971,58 @@ gsm_consolekit_new (void)
return manager;
}
+
+static void
+ck_proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GsmConsolekit *consolekit = user_data;
+ gboolean is_about_to_shutdown;
+
+ g_debug ("GsmConsolekit: received ConsoleKit signal: %s", signal_name);
+
+ if (g_strcmp0 (signal_name, "PrepareForShutdown") != 0) {
+ g_debug ("GsmConsolekit: ignoring %s signal", signal_name);
+ return;
+ }
+
+ g_variant_get (parameters, "(b)", &is_about_to_shutdown);
+ if (!is_about_to_shutdown) {
+ g_debug ("GsmConsolekit: ignoring %s signal since about-to-shutdown is FALSE", signal_name);
+ return;
+ }
+
+ if (consolekit->priv->prepare_for_shutdown_expected) {
+ g_debug ("GsmConsolekit: shutdown successfully prepared");
+ g_signal_emit_by_name (consolekit, "shutdown-prepared", TRUE);
+ consolekit->priv->prepare_for_shutdown_expected = FALSE;
+ }
+}
+
+static void
+ck_session_proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GsmConsolekit *consolekit = user_data;
+ gboolean is_active;
+
+ g_debug ("GsmConsolekit: received ConsoleKit signal: %s", signal_name);
+
+ if (g_strcmp0 (signal_name, "ActiveChanged") != 0) {
+ g_debug ("GsmConsolekit: ignoring %s signal", signal_name);
+ return;
+ }
+
+ g_variant_get (parameters, "(b)", &is_active);
+ if (consolekit->priv->is_active != is_active) {
+ g_debug ("GsmConsolekit: session state changed");
+ consolekit->priv->is_active = is_active;
+ g_object_notify (G_OBJECT (consolekit), "active");
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]