/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "ck-tty-idle-monitor.h"
#include "ck-session.h"
#include "ck-session-glue.h"
#include "ck-marshal.h"
#define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate))
#define CK_DBUS_PATH "/org/freedesktop/ConsoleKit"
#define CK_DBUS_NAME "org.freedesktop.ConsoleKit"
#define IDLE_TIME_SECS 60
struct CkSessionPrivate
{
char *id;
char *cookie;
char *seat_id;
char *session_type;
char *display_device;
char *x11_display_device;
char *x11_display;
char *remote_host_name;
guint uid;
gboolean active;
gboolean is_local;
GTimeVal creation_time;
CkTtyIdleMonitor *idle_monitor;
gboolean idle_hint;
GTimeVal idle_since_hint;
DBusGConnection *connection;
DBusGProxy *bus_proxy;
};
enum {
ACTIVATE,
LOCK,
UNLOCK,
ACTIVE_CHANGED,
IDLE_HINT_CHANGED,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_ID,
PROP_COOKIE,
PROP_USER,
PROP_UNIX_USER,
PROP_X11_DISPLAY,
PROP_X11_DISPLAY_DEVICE,
PROP_DISPLAY_DEVICE,
PROP_SESSION_TYPE,
PROP_REMOTE_HOST_NAME,
PROP_IS_LOCAL,
PROP_ACTIVE,
PROP_IDLE_HINT,
};
static guint signals [LAST_SIGNAL] = { 0, };
static void ck_session_class_init (CkSessionClass *klass);
static void ck_session_init (CkSession *session);
static void ck_session_finalize (GObject *object);
G_DEFINE_TYPE (CkSession, ck_session, G_TYPE_OBJECT)
GQuark
ck_session_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0) {
ret = g_quark_from_static_string ("ck_session_error");
}
return ret;
}
static gboolean
register_session (CkSession *session)
{
GError *error = NULL;
error = NULL;
session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (session->priv->connection == NULL) {
if (error != NULL) {
g_critical ("error getting system bus: %s", error->message);
g_error_free (error);
}
return FALSE;
}
session->priv->bus_proxy = dbus_g_proxy_new_for_name (session->priv->connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS);
dbus_g_connection_register_g_object (session->priv->connection, session->priv->id, G_OBJECT (session));
return TRUE;
}
/*
lock and unlock are separate functions because:
1. we don't maintain state for locked
2. so security policy can be handled separately
*/
gboolean
ck_session_lock (CkSession *session,
DBusGMethodInvocation *context)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_debug ("Emitting lock for session %s", session->priv->id);
g_signal_emit (session, signals [LOCK], 0);
dbus_g_method_return (context);
return TRUE;
}
gboolean
ck_session_unlock (CkSession *session,
DBusGMethodInvocation *context)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_debug ("Emitting unlock for session %s", session->priv->id);
g_signal_emit (session, signals [UNLOCK], 0);
dbus_g_method_return (context);
return TRUE;
}
/* adapted from PolicyKit */
static gboolean
get_caller_info (CkSession *session,
const char *sender,
uid_t *calling_uid,
pid_t *calling_pid)
{
gboolean res;
GError *error = NULL;
res = FALSE;
if (sender == NULL) {
goto out;
}
if (! dbus_g_proxy_call (session->priv->bus_proxy, "GetConnectionUnixUser", &error,
G_TYPE_STRING, sender,
G_TYPE_INVALID,
G_TYPE_UINT, calling_uid,
G_TYPE_INVALID)) {
g_warning ("GetConnectionUnixUser() failed: %s", error->message);
g_error_free (error);
goto out;
}
if (! dbus_g_proxy_call (session->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
G_TYPE_STRING, sender,
G_TYPE_INVALID,
G_TYPE_UINT, calling_pid,
G_TYPE_INVALID)) {
g_warning ("GetConnectionUnixProcessID() failed: %s", error->message);
g_error_free (error);
goto out;
}
res = TRUE;
g_debug ("uid = %d", *calling_uid);
g_debug ("pid = %d", *calling_pid);
out:
return res;
}
static gboolean
session_set_idle_hint_internal (CkSession *session,
gboolean idle_hint)
{
if (session->priv->idle_hint != idle_hint) {
session->priv->idle_hint = idle_hint;
g_object_notify (G_OBJECT (session), "idle-hint");
/* FIXME: can we get a time from the dbus message? */
g_get_current_time (&session->priv->idle_since_hint);
g_debug ("Emitting idle-changed for session %s", session->priv->id);
g_signal_emit (session, signals [IDLE_HINT_CHANGED], 0, idle_hint);
}
return TRUE;
}
/*
Example:
dbus-send --system --dest=org.freedesktop.ConsoleKit \
--type=method_call --print-reply --reply-timeout=2000 \
/org/freedesktop/ConsoleKit/Session1 \
org.freedesktop.ConsoleKit.Session.SetIdleHint boolean:TRUE
*/
gboolean
ck_session_set_idle_hint (CkSession *session,
gboolean idle_hint,
DBusGMethodInvocation *context)
{
char *sender;
uid_t calling_uid;
pid_t calling_pid;
gboolean res;
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
sender = dbus_g_method_get_sender (context);
res = get_caller_info (session,
sender,
&calling_uid,
&calling_pid);
g_free (sender);
if (! res) {
GError *error;
error = g_error_new (CK_SESSION_ERROR,
CK_SESSION_ERROR_GENERAL,
_("Unable to lookup information about calling process '%d'"),
calling_pid);
g_warning ("stat on pid %d failed", calling_pid);
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE;
}
/* only restrict this by UID for now */
if (session->priv->uid != calling_uid) {
GError *error;
error = g_error_new (CK_SESSION_ERROR,
CK_SESSION_ERROR_GENERAL,
_("Only session owner may set idle hint state"));
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE;
}
session_set_idle_hint_internal (session, idle_hint);
dbus_g_method_return (context);
return TRUE;
}
gboolean
ck_session_get_idle_hint (CkSession *session,
gboolean *idle_hint,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (idle_hint != NULL) {
*idle_hint = session->priv->idle_hint;
}
return TRUE;
}
#if GLIB_CHECK_VERSION(2,12,0)
#define _g_time_val_to_iso8601(t) g_time_val_to_iso8601(t)
#else
/* copied from GLib */
static gchar *
_g_time_val_to_iso8601 (GTimeVal *time_)
{
gchar *retval;
g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
#define ISO_8601_LEN 21
#define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ"
retval = g_new0 (gchar, ISO_8601_LEN + 1);
strftime (retval, ISO_8601_LEN,
ISO_8601_FORMAT,
gmtime (&(time_->tv_sec)));
return retval;
}
#endif
gboolean
ck_session_get_idle_since_hint (CkSession *session,
char **iso8601_datetime,
GError **error)
{
char *date_str;
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
date_str = NULL;
if (session->priv->idle_hint) {
date_str = _g_time_val_to_iso8601 (&session->priv->idle_since_hint);
}
if (iso8601_datetime != NULL) {
*iso8601_datetime = g_strdup (date_str);
}
g_free (date_str);
return TRUE;
}
gboolean
ck_session_activate (CkSession *session,
DBusGMethodInvocation *context)
{
gboolean res;
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
res = FALSE;
g_signal_emit (session, signals [ACTIVATE], 0, context, &res);
if (! res) {
GError *error;
/* if the signal is not handled then either:
a) aren't attached to seat
b) seat doesn't support activation changes */
g_debug ("Activate signal not handled");
error = g_error_new (CK_SESSION_ERROR,
CK_SESSION_ERROR_GENERAL,
_("Unable to activate session"));
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE;
}
return TRUE;
}
gboolean
ck_session_set_active (CkSession *session,
gboolean active,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (session->priv->active != active) {
session->priv->active = active;
g_signal_emit (session, signals [ACTIVE_CHANGED], 0, active);
}
return TRUE;
}
gboolean
ck_session_set_is_local (CkSession *session,
gboolean is_local,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (session->priv->is_local != is_local) {
session->priv->is_local = is_local;
}
return TRUE;
}
gboolean
ck_session_get_id (CkSession *session,
char **id,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (id != NULL) {
*id = g_strdup (session->priv->id);
}
return TRUE;
}
gboolean
ck_session_get_seat_id (CkSession *session,
char **id,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (id != NULL) {
*id = g_strdup (session->priv->seat_id);
}
return TRUE;
}
gboolean
ck_session_get_unix_user (CkSession *session,
guint *uid,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (uid != NULL) {
*uid = session->priv->uid;
}
return TRUE;
}
/* deprecated */
gboolean
ck_session_get_user (CkSession *session,
guint *uid,
GError **error)
{
return ck_session_get_unix_user (session, uid, error);
}
gboolean
ck_session_get_x11_display (CkSession *session,
char **x11_display,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (x11_display != NULL) {
*x11_display = g_strdup (session->priv->x11_display);
}
return TRUE;
}
gboolean
ck_session_get_display_device (CkSession *session,
char **display_device,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (display_device != NULL) {
*display_device = g_strdup (session->priv->display_device);
}
return TRUE;
}
gboolean
ck_session_get_x11_display_device (CkSession *session,
char **x11_display_device,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (x11_display_device != NULL) {
*x11_display_device = g_strdup (session->priv->x11_display_device);
}
return TRUE;
}
gboolean
ck_session_get_remote_host_name (CkSession *session,
char **remote_host_name,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (remote_host_name != NULL) {
*remote_host_name = g_strdup (session->priv->remote_host_name);
}
return TRUE;
}
gboolean
ck_session_get_creation_time (CkSession *session,
char **iso8601_datetime,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (iso8601_datetime != NULL) {
*iso8601_datetime = _g_time_val_to_iso8601 (&session->priv->creation_time);
}
return TRUE;
}
gboolean
ck_session_get_session_type (CkSession *session,
char **type,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (type != NULL) {
*type = g_strdup (session->priv->session_type);
}
return TRUE;
}
gboolean
ck_session_is_active (CkSession *session,
gboolean *active,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (active != NULL) {
*active = session->priv->active;
}
return TRUE;
}
gboolean
ck_session_is_local (CkSession *session,
gboolean *local,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
if (local != NULL) {
*local = session->priv->is_local;
}
return TRUE;
}
gboolean
ck_session_set_id (CkSession *session,
const char *id,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->id);
session->priv->id = g_strdup (id);
return TRUE;
}
gboolean
ck_session_set_cookie (CkSession *session,
const char *cookie,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->cookie);
session->priv->cookie = g_strdup (cookie);
return TRUE;
}
gboolean
ck_session_set_seat_id (CkSession *session,
const char *id,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->seat_id);
session->priv->seat_id = g_strdup (id);
return TRUE;
}
gboolean
ck_session_set_unix_user (CkSession *session,
guint uid,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
session->priv->uid = uid;
return TRUE;
}
gboolean
ck_session_set_x11_display (CkSession *session,
const char *x11_display,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->x11_display);
session->priv->x11_display = g_strdup (x11_display);
return TRUE;
}
gboolean
ck_session_set_display_device (CkSession *session,
const char *display_device,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->display_device);
session->priv->display_device = g_strdup (display_device);
return TRUE;
}
gboolean
ck_session_set_x11_display_device (CkSession *session,
const char *x11_display_device,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->x11_display_device);
session->priv->x11_display_device = g_strdup (x11_display_device);
return TRUE;
}
gboolean
ck_session_set_remote_host_name (CkSession *session,
const char *remote_host_name,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->remote_host_name);
session->priv->remote_host_name = g_strdup (remote_host_name);
return TRUE;
}
gboolean
ck_session_set_session_type (CkSession *session,
const char *type,
GError **error)
{
g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
g_free (session->priv->session_type);
session->priv->session_type = g_strdup (type);
return TRUE;
}
static void
ck_session_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CkSession *self;
self = CK_SESSION (object);
switch (prop_id) {
case PROP_ACTIVE:
ck_session_set_active (self, g_value_get_boolean (value), NULL);
break;
case PROP_IS_LOCAL:
ck_session_set_is_local (self, g_value_get_boolean (value), NULL);
break;
case PROP_ID:
ck_session_set_id (self, g_value_get_string (value), NULL);
break;
case PROP_COOKIE:
ck_session_set_cookie (self, g_value_get_string (value), NULL);
break;
case PROP_SESSION_TYPE:
ck_session_set_session_type (self, g_value_get_string (value), NULL);
break;
case PROP_X11_DISPLAY:
ck_session_set_x11_display (self, g_value_get_string (value), NULL);
break;
case PROP_X11_DISPLAY_DEVICE:
ck_session_set_x11_display_device (self, g_value_get_string (value), NULL);
break;
case PROP_DISPLAY_DEVICE:
ck_session_set_display_device (self, g_value_get_string (value), NULL);
break;
case PROP_UNIX_USER:
ck_session_set_unix_user (self, g_value_get_uint (value), NULL);
break;
case PROP_USER: /* deprecated */
ck_session_set_unix_user (self, g_value_get_uint (value), NULL);
break;
case PROP_REMOTE_HOST_NAME:
ck_session_set_remote_host_name (self, g_value_get_string (value), NULL);
break;
case PROP_IDLE_HINT:
session_set_idle_hint_internal (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
ck_session_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CkSession *self;
self = CK_SESSION (object);
switch (prop_id) {
case PROP_ACTIVE:
g_value_set_boolean (value, self->priv->active);
break;
case PROP_IS_LOCAL:
g_value_set_boolean (value, self->priv->is_local);
break;
case PROP_ID:
g_value_set_string (value, self->priv->id);
break;
case PROP_COOKIE:
g_value_set_string (value, self->priv->cookie);
break;
case PROP_SESSION_TYPE:
g_value_set_string (value, self->priv->session_type);
break;
case PROP_X11_DISPLAY:
g_value_set_string (value, self->priv->x11_display);
break;
case PROP_X11_DISPLAY_DEVICE:
g_value_set_string (value, self->priv->x11_display_device);
break;
case PROP_DISPLAY_DEVICE:
g_value_set_string (value, self->priv->display_device);
break;
case PROP_UNIX_USER:
g_value_set_uint (value, self->priv->uid);
break;
case PROP_USER: /* deprecated */
g_value_set_uint (value, self->priv->uid);
break;
case PROP_REMOTE_HOST_NAME:
g_value_set_string (value, self->priv->remote_host_name);
break;
case PROP_IDLE_HINT:
g_value_set_boolean (value, self->priv->idle_hint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
static gboolean
session_is_text (CkSession *session)
{
gboolean ret;
ret = FALSE;
if (! IS_STR_SET (session->priv->x11_display_device)
&& ! IS_STR_SET (session->priv->x11_display)
&& IS_STR_SET (session->priv->display_device)) {
ret = TRUE;
}
g_debug ("Identified session '%s' as %s",
session->priv->id,
ret ? "text" : "graphical");
return ret;
}
static void
tty_idle_changed_cb (CkTtyIdleMonitor *monitor,
gboolean idle_hint,
CkSession *session)
{
session_set_idle_hint_internal (session, idle_hint);
}
static void
session_add_activity_watch (CkSession *session)
{
if (session->priv->idle_monitor == NULL) {
session->priv->idle_monitor = ck_tty_idle_monitor_new (session->priv->display_device);
g_signal_connect (session->priv->idle_monitor,
"idle-hint-changed",
G_CALLBACK (tty_idle_changed_cb),
session);
}
ck_tty_idle_monitor_start (session->priv->idle_monitor);
}
static void
session_remove_activity_watch (CkSession *session)
{
if (session->priv->idle_monitor == NULL) {
return;
}
ck_tty_idle_monitor_stop (session->priv->idle_monitor);
g_object_unref (session->priv->idle_monitor);
session->priv->idle_monitor = NULL;
}
static GObject *
ck_session_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
CkSession *session;
CkSessionClass *klass;
klass = CK_SESSION_CLASS (g_type_class_peek (CK_TYPE_SESSION));
session = CK_SESSION (G_OBJECT_CLASS (ck_session_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
if (session_is_text (session)) {
session_add_activity_watch (session);
}
return G_OBJECT (session);
}
static void
ck_session_class_init (CkSessionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructor = ck_session_constructor;
object_class->get_property = ck_session_get_property;
object_class->set_property = ck_session_set_property;
object_class->finalize = ck_session_finalize;
signals [ACTIVE_CHANGED] =
g_signal_new ("active-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CkSessionClass, active_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE,
1, G_TYPE_BOOLEAN);
signals [ACTIVATE] =
g_signal_new ("activate",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CkSessionClass, activate),
NULL,
NULL,
ck_marshal_BOOLEAN__POINTER,
G_TYPE_BOOLEAN,
1, G_TYPE_POINTER);
signals [LOCK] =
g_signal_new ("lock",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CkSessionClass, lock),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
signals [UNLOCK] =
g_signal_new ("unlock",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CkSessionClass, unlock),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
signals [IDLE_HINT_CHANGED] =
g_signal_new ("idle-hint-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CkSessionClass, idle_hint_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE,
1, G_TYPE_BOOLEAN);
g_object_class_install_property (object_class,
PROP_ACTIVE,
g_param_spec_boolean ("active",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_IS_LOCAL,
g_param_spec_boolean ("is-local",
NULL,
NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_ID,
g_param_spec_string ("id",
"id",
"id",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_COOKIE,
g_param_spec_string ("cookie",
"cookie",
"cookie",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_SESSION_TYPE,
g_param_spec_string ("session-type",
"session-type",
"session type",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_X11_DISPLAY,
g_param_spec_string ("x11-display",
"x11-display",
"X11 Display",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_X11_DISPLAY_DEVICE,
g_param_spec_string ("x11-display-device",
"x11-display-device",
"X11 Display device",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_DISPLAY_DEVICE,
g_param_spec_string ("display-device",
"display-device",
"Display device",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_REMOTE_HOST_NAME,
g_param_spec_string ("remote-host-name",
"remote-host-name",
"Remote host name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_UNIX_USER,
g_param_spec_uint ("unix-user",
"POSIX User Id",
"POSIX User Id",
0,
G_MAXINT,
0,
G_PARAM_READWRITE));
/* deprecated */
g_object_class_install_property (object_class,
PROP_USER,
g_param_spec_uint ("user",
"User Id",
"User Id",
0,
G_MAXINT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ACTIVE,
g_param_spec_boolean ("idle-hint",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE));
g_type_class_add_private (klass, sizeof (CkSessionPrivate));
dbus_g_object_type_install_info (CK_TYPE_SESSION, &dbus_glib_ck_session_object_info);
}
static void
ck_session_init (CkSession *session)
{
session->priv = CK_SESSION_GET_PRIVATE (session);
/* FIXME: should we have a property for this? */
g_get_current_time (&session->priv->creation_time);
}
static void
ck_session_finalize (GObject *object)
{
CkSession *session;
g_return_if_fail (object != NULL);
g_return_if_fail (CK_IS_SESSION (object));
session = CK_SESSION (object);
g_return_if_fail (session->priv != NULL);
session_remove_activity_watch (session);
g_free (session->priv->id);
g_free (session->priv->cookie);
g_free (session->priv->seat_id);
g_free (session->priv->session_type);
g_free (session->priv->x11_display);
g_free (session->priv->display_device);
g_free (session->priv->x11_display_device);
g_free (session->priv->remote_host_name);
G_OBJECT_CLASS (ck_session_parent_class)->finalize (object);
}
CkSession *
ck_session_new (const char *ssid,
const char *cookie)
{
GObject *object;
gboolean res;
object = g_object_new (CK_TYPE_SESSION,
"id", ssid,
"cookie", cookie,
NULL);
res = register_session (CK_SESSION (object));
if (! res) {
g_object_unref (object);
return NULL;
}
return CK_SESSION (object);
}
#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \
G_TYPE_STRING, \
G_TYPE_VALUE, \
G_TYPE_INVALID))
CkSession *
ck_session_new_with_parameters (const char *ssid,
const char *cookie,
const GPtrArray *parameters)
{
GObject *object;
gboolean res;
int i;
GParameter *params;
guint n_allocated_params;
guint n_params;
GObjectClass *class;
GType object_type;
object_type = CK_TYPE_SESSION;
class = g_type_class_ref (object_type);
n_allocated_params = 2;
if (parameters != NULL) {
n_allocated_params += parameters->len;
}
params = g_new0 (GParameter, n_allocated_params);
n_params = 0;
params[n_params].name = g_strdup ("id");
params[n_params].value.g_type = 0;
g_value_init (¶ms[n_params].value, G_TYPE_STRING);
g_value_set_string (¶ms[n_params].value, ssid);
n_params++;
params[n_params].name = g_strdup ("cookie");
params[n_params].value.g_type = 0;
g_value_init (¶ms[n_params].value, G_TYPE_STRING);
g_value_set_string (¶ms[n_params].value, cookie);
n_params++;
if (parameters != NULL) {
for (i = 0; i < parameters->len; i++) {
gboolean res;
GValue val_struct = { 0, };
char *prop_name;
GValue *prop_val;
GParamSpec *pspec;
g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT);
g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i));
res = dbus_g_type_struct_get (&val_struct,
0, &prop_name,
1, &prop_val,
G_MAXUINT);
if (! res) {
g_debug ("Unable to extract parameter input");
goto cont;
}
if (prop_name == NULL) {
g_debug ("Skipping NULL parameter");
goto cont;
}
if (strcmp (prop_name, "id") == 0
|| strcmp (prop_name, "cookie") == 0) {
g_debug ("Skipping restricted parameter: %s", prop_name);
goto cont;
}
pspec = g_object_class_find_property (class, prop_name);
if (! pspec) {
g_debug ("Skipping unknown parameter: %s", prop_name);
goto cont;
}
if (!(pspec->flags & G_PARAM_WRITABLE)) {
g_debug ("property '%s' is not writable", pspec->name);
goto cont;
}
params[n_params].name = g_strdup (prop_name);
params[n_params].value.g_type = 0;
g_value_init (¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
res = g_value_transform (prop_val, ¶ms[n_params].value);
if (! res) {
g_debug ("unable to transform property value for '%s'", pspec->name);
goto cont;
}
n_params++;
cont:
g_free (prop_name);
if (prop_val != NULL) {
g_value_unset (prop_val);
g_free (prop_val);
}
}
}
object = g_object_newv (object_type, n_params, params);
while (n_params--) {
g_free ((char *)params[n_params].name);
g_value_unset (¶ms[n_params].value);
}
g_free (params);
g_type_class_unref (class);
res = register_session (CK_SESSION (object));
if (! res) {
g_object_unref (object);
return NULL;
}
return CK_SESSION (object);
}
syntax highlighted by Code2HTML, v. 0.9.1