gnome-shell/src/gdmuser/gdm-user.c
Ray Strode 735397aa89 gdm: fix empty real name check
gdm_user_get_real_name() checks for an empty real
name and automatically falls back to username if
real name is NULL.  It doesn't automatically fall
back to username if real name is empty, however.

This commit makes it fall back for both cases.

https://bugzilla.gnome.org/show_bug.cgi?id=644765
2011-03-15 15:49:15 -04:00

1100 lines
32 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
* Copyright (C) 2007-2008 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 <float.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#include "gdm-user-private.h"
#define GDM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_USER, GdmUserClass))
#define GDM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_USER))
#define GDM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), GDM_TYPE_USER, GdmUserClass))
#define GLOBAL_FACEDIR DATADIR "/faces"
#define MAX_FILE_SIZE 65536
#define ACCOUNTS_NAME "org.freedesktop.Accounts"
#define ACCOUNTS_USER_INTERFACE "org.freedesktop.Accounts.User"
enum {
PROP_0,
PROP_IS_LOADED
};
enum {
CHANGED,
SESSIONS_CHANGED,
LAST_SIGNAL
};
struct _GdmUser {
GObject parent;
DBusGConnection *connection;
DBusGProxy *accounts_proxy;
DBusGProxy *object_proxy;
DBusGProxyCall *get_all_call;
char *object_path;
uid_t uid;
char *user_name;
char *real_name;
char *icon_file;
GList *sessions;
gulong login_frequency;
guint is_loaded : 1;
};
struct _GdmUserClass
{
GObjectClass parent_class;
};
static void gdm_user_finalize (GObject *object);
static gboolean check_user_file (const char *filename);
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GdmUser, gdm_user, G_TYPE_OBJECT)
static int
session_compare (const char *a,
const char *b)
{
if (a == NULL) {
return 1;
} else if (b == NULL) {
return -1;
}
return strcmp (a, b);
}
void
_gdm_user_add_session (GdmUser *user,
const char *ssid)
{
GList *li;
g_return_if_fail (GDM_IS_USER (user));
g_return_if_fail (ssid != NULL);
li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
if (li == NULL) {
g_debug ("GdmUser: adding session %s", ssid);
user->sessions = g_list_prepend (user->sessions, g_strdup (ssid));
g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
} else {
g_debug ("GdmUser: session already present: %s", ssid);
}
}
void
_gdm_user_remove_session (GdmUser *user,
const char *ssid)
{
GList *li;
g_return_if_fail (GDM_IS_USER (user));
g_return_if_fail (ssid != NULL);
li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
if (li != NULL) {
g_debug ("GdmUser: removing session %s", ssid);
g_free (li->data);
user->sessions = g_list_delete_link (user->sessions, li);
g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
} else {
g_debug ("GdmUser: session not found: %s", ssid);
}
}
guint
gdm_user_get_num_sessions (GdmUser *user)
{
return g_list_length (user->sessions);
}
static void
gdm_user_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_user_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmUser *user;
user = GDM_USER (object);
switch (prop_id) {
case PROP_IS_LOADED:
g_value_set_boolean (value, user->is_loaded);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_user_class_init (GdmUserClass *class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = gdm_user_finalize;
gobject_class->set_property = gdm_user_set_property;
gobject_class->get_property = gdm_user_get_property;
g_object_class_install_property (gobject_class,
PROP_IS_LOADED,
g_param_spec_boolean ("is-loaded",
NULL,
NULL,
FALSE,
G_PARAM_READABLE));
signals [CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals [SESSIONS_CHANGED] =
g_signal_new ("sessions-changed",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
gdm_user_init (GdmUser *user)
{
GError *error;
user->user_name = NULL;
user->real_name = NULL;
user->sessions = NULL;
error = NULL;
user->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (user->connection == NULL) {
g_warning ("Couldn't connect to system bus: %s", error->message);
}
}
static void
gdm_user_finalize (GObject *object)
{
GdmUser *user;
user = GDM_USER (object);
g_free (user->user_name);
g_free (user->real_name);
g_free (user->icon_file);
g_free (user->object_path);
if (user->accounts_proxy != NULL) {
g_object_unref (user->accounts_proxy);
}
if (user->object_proxy != NULL) {
g_object_unref (user->object_proxy);
}
if (user->connection != NULL) {
dbus_g_connection_unref (user->connection);
}
if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize)
(*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object);
}
static void
set_is_loaded (GdmUser *user,
gboolean is_loaded)
{
if (user->is_loaded != is_loaded) {
user->is_loaded = is_loaded;
g_object_notify (G_OBJECT (user), "is-loaded");
}
}
/**
* _gdm_user_update_from_pwent:
* @user: the user object to update.
* @pwent: the user data to use.
*
* Updates the properties of @user using the data in @pwent.
**/
void
_gdm_user_update_from_pwent (GdmUser *user,
const struct passwd *pwent)
{
gchar *real_name = NULL;
gboolean changed;
g_return_if_fail (GDM_IS_USER (user));
g_return_if_fail (pwent != NULL);
g_return_if_fail (user->object_path == NULL);
changed = FALSE;
/* Display Name */
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
gchar *first_comma = NULL;
gchar *valid_utf8_name = NULL;
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
valid_utf8_name = pwent->pw_gecos;
first_comma = strchr (valid_utf8_name, ',');
} else {
g_warning ("User %s has invalid UTF-8 in GECOS field. "
"It would be a good thing to check /etc/passwd.",
pwent->pw_name ? pwent->pw_name : "");
}
if (first_comma) {
real_name = g_strndup (valid_utf8_name,
(first_comma - valid_utf8_name));
} else if (valid_utf8_name) {
real_name = g_strdup (valid_utf8_name);
} else {
real_name = NULL;
}
if (real_name && real_name[0] == '\0') {
g_free (real_name);
real_name = NULL;
}
} else {
real_name = NULL;
}
if (g_strcmp0 (real_name, user->real_name) != 0) {
g_free (user->real_name);
user->real_name = real_name;
changed = TRUE;
} else {
g_free (real_name);
}
/* UID */
if (pwent->pw_uid != user->uid) {
user->uid = pwent->pw_uid;
changed = TRUE;
}
/* Username */
if (g_strcmp0 (pwent->pw_name, user->user_name) != 0) {
g_free (user->icon_file);
user->icon_file = NULL;
if (pwent->pw_name != NULL) {
gboolean res;
user->icon_file = g_build_filename (GDM_CACHE_DIR, pwent->pw_name, "face", NULL);
res = check_user_file (user->icon_file);
if (!res) {
g_free (user->icon_file);
user->icon_file = g_build_filename (GLOBAL_FACEDIR, pwent->pw_name, NULL);
}
}
g_free (user->user_name);
user->user_name = g_strdup (pwent->pw_name);
changed = TRUE;
}
if (!user->is_loaded) {
set_is_loaded (user, TRUE);
}
if (changed) {
g_signal_emit (user, signals[CHANGED], 0);
}
}
/**
* _gdm_user_update_login_frequency:
* @user: the user object to update
* @login_frequency: the number of times the user has logged in
*
* Updates the login frequency of @user
**/
void
_gdm_user_update_login_frequency (GdmUser *user,
guint64 login_frequency)
{
g_return_if_fail (GDM_IS_USER (user));
if (login_frequency == user->login_frequency) {
return;
}
user->login_frequency = login_frequency;
g_signal_emit (user, signals[CHANGED], 0);
}
/**
* gdm_user_get_uid:
* @user: the user object to examine.
*
* Retrieves the ID of @user.
*
* Returns: (transfer none): a pointer to an array of characters which must not be modified or
* freed, or %NULL.
**/
gulong
gdm_user_get_uid (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), -1);
return user->uid;
}
/**
* gdm_user_get_real_name:
* @user: the user object to examine.
*
* Retrieves a displayable name for @user. By default this is the real name
* of the user, but will fall back to the user name if there is no real name
* defined.
*
* Returns: (transfer none): a pointer to an array of characters which must not be modified or
* freed, or %NULL.
**/
const char *
gdm_user_get_real_name (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), NULL);
if (user->real_name == NULL ||
user->real_name[0] == '\0') {
return user->user_name;
}
return user->real_name;
}
/**
* gdm_user_get_user_name:
* @user: the user object to examine.
*
* Retrieves the login name of @user.
*
* Returns: (transfer none): a pointer to an array of characters which must not be modified or
* freed, or %NULL.
**/
const char *
gdm_user_get_user_name (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), NULL);
return user->user_name;
}
/**
* gdm_user_get_login_frequency:
* @user: a #GdmUser
*
* Returns the number of times @user has logged in.
*
* Returns: the login frequency
*/
gulong
gdm_user_get_login_frequency (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), 0);
return user->login_frequency;
}
int
gdm_user_collate (GdmUser *user1,
GdmUser *user2)
{
const char *str1;
const char *str2;
gulong num1;
gulong num2;
guint len1;
guint len2;
g_return_val_if_fail (GDM_IS_USER (user1), 0);
g_return_val_if_fail (GDM_IS_USER (user2), 0);
num1 = user1->login_frequency;
num2 = user2->login_frequency;
if (num1 > num2) {
return -1;
}
if (num1 < num2) {
return 1;
}
len1 = g_list_length (user1->sessions);
len2 = g_list_length (user2->sessions);
if (len1 > len2) {
return -1;
}
if (len1 < len2) {
return 1;
}
/* if login frequency is equal try names */
if (user1->real_name != NULL) {
str1 = user1->real_name;
} else {
str1 = user1->user_name;
}
if (user2->real_name != NULL) {
str2 = user2->real_name;
} else {
str2 = user2->user_name;
}
if (str1 == NULL && str2 != NULL) {
return -1;
}
if (str1 != NULL && str2 == NULL) {
return 1;
}
if (str1 == NULL && str2 == NULL) {
return 0;
}
return g_utf8_collate (str1, str2);
}
static gboolean
check_user_file (const char *filename)
{
gssize max_file_size = MAX_FILE_SIZE;
struct stat fileinfo;
/* Exists/Readable? */
if (stat (filename, &fileinfo) < 0) {
return FALSE;
}
/* Is a regular file */
if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) {
return FALSE;
}
/* Size is kosher? */
if (G_UNLIKELY (fileinfo.st_size > max_file_size)) {
return FALSE;
}
return TRUE;
}
static void
rounded_rectangle (cairo_t *cr,
gdouble aspect,
gdouble x,
gdouble y,
gdouble corner_radius,
gdouble width,
gdouble height)
{
gdouble radius;
gdouble degrees;
radius = corner_radius / aspect;
degrees = G_PI / 180.0;
cairo_new_sub_path (cr);
cairo_arc (cr,
x + width - radius,
y + radius,
radius,
-90 * degrees,
0 * degrees);
cairo_arc (cr,
x + width - radius,
y + height - radius,
radius,
0 * degrees,
90 * degrees);
cairo_arc (cr,
x + radius,
y + height - radius,
radius,
90 * degrees,
180 * degrees);
cairo_arc (cr,
x + radius,
y + radius,
radius,
180 * degrees,
270 * degrees);
cairo_close_path (cr);
}
static cairo_surface_t *
surface_from_pixbuf (GdkPixbuf *pixbuf)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf));
cr = cairo_create (surface);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
return surface;
}
/**
* go_cairo_convert_data_to_pixbuf:
* @src: a pointer to pixel data in cairo format
* @dst: a pointer to pixel data in pixbuf format
* @width: image width
* @height: image height
* @rowstride: data rowstride
*
* Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
* to GDK_COLORSPACE_RGB pixbuf format and move them
* to @dst. If @src == @dst, pixel are converted in place.
**/
static void
go_cairo_convert_data_to_pixbuf (unsigned char *dst,
unsigned char const *src,
int width,
int height,
int rowstride)
{
int i,j;
unsigned int t;
unsigned char a, b, c;
g_return_if_fail (dst != NULL);
#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
if (src == dst || src == NULL) {
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT(a, dst[2], dst[3], t);
MULT(b, dst[1], dst[3], t);
MULT(c, dst[0], dst[3], t);
dst[0] = a;
dst[1] = b;
dst[2] = c;
#else
MULT(a, dst[1], dst[0], t);
MULT(b, dst[2], dst[0], t);
MULT(c, dst[3], dst[0], t);
dst[3] = dst[0];
dst[0] = a;
dst[1] = b;
dst[2] = c;
#endif
dst += 4;
}
dst += rowstride - width * 4;
}
} else {
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT(dst[0], src[2], src[3], t);
MULT(dst[1], src[1], src[3], t);
MULT(dst[2], src[0], src[3], t);
dst[3] = src[3];
#else
MULT(dst[0], src[1], src[0], t);
MULT(dst[1], src[2], src[0], t);
MULT(dst[2], src[3], src[0], t);
dst[3] = src[0];
#endif
src += 4;
dst += 4;
}
src += rowstride - width * 4;
dst += rowstride - width * 4;
}
}
#undef MULT
}
static void
cairo_to_pixbuf (guint8 *src_data,
GdkPixbuf *dst_pixbuf)
{
unsigned char *src;
unsigned char *dst;
guint w;
guint h;
guint rowstride;
w = gdk_pixbuf_get_width (dst_pixbuf);
h = gdk_pixbuf_get_height (dst_pixbuf);
rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
dst = gdk_pixbuf_get_pixels (dst_pixbuf);
src = src_data;
go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
}
static GdkPixbuf *
frame_pixbuf (GdkPixbuf *source)
{
GdkPixbuf *dest;
cairo_t *cr;
cairo_surface_t *surface;
guint w;
guint h;
guint rowstride;
int frame_width;
double radius;
guint8 *data;
frame_width = 2;
w = gdk_pixbuf_get_width (source) + frame_width * 2;
h = gdk_pixbuf_get_height (source) + frame_width * 2;
radius = w / 10;
dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE,
8,
w,
h);
rowstride = gdk_pixbuf_get_rowstride (dest);
data = g_new0 (guint8, h * rowstride);
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
w,
h,
rowstride);
cr = cairo_create (surface);
cairo_surface_destroy (surface);
/* set up image */
cairo_rectangle (cr, 0, 0, w, h);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
cairo_fill (cr);
rounded_rectangle (cr,
1.0,
frame_width + 0.5,
frame_width + 0.5,
radius,
w - frame_width * 2 - 1,
h - frame_width * 2 - 1);
cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
cairo_fill_preserve (cr);
surface = surface_from_pixbuf (source);
cairo_set_source_surface (cr, surface, frame_width, frame_width);
cairo_fill (cr);
cairo_surface_destroy (surface);
cairo_to_pixbuf (data, dest);
cairo_destroy (cr);
g_free (data);
return dest;
}
/**
* gdm_user_is_logged_in:
* @user: a #GdmUser
*
* Returns whether or not #GdmUser is currently logged in.
*
* Returns: %TRUE or %FALSE
*/
gboolean
gdm_user_is_logged_in (GdmUser *user)
{
return user->sessions != NULL;
}
/**
* gdm_user_render_icon:
* @user: a #GdmUser
* @icon_size: the size to render the icon at
*
* Returns a #GdkPixbuf of the account icon belonging to @user
* at the pixel size specified by @icon_size.
*
* Returns: (transfer full): a #GdkPixbuf
*/
GdkPixbuf *
gdm_user_render_icon (GdmUser *user,
gint icon_size)
{
GdkPixbuf *pixbuf;
GdkPixbuf *framed;
gboolean res;
GError *error;
g_return_val_if_fail (GDM_IS_USER (user), NULL);
g_return_val_if_fail (icon_size > 12, NULL);
pixbuf = NULL;
if (user->icon_file) {
res = check_user_file (user->icon_file);
if (res) {
pixbuf = gdk_pixbuf_new_from_file_at_size (user->icon_file,
icon_size,
icon_size,
NULL);
} else {
pixbuf = NULL;
}
}
if (pixbuf != NULL) {
goto out;
}
error = NULL;
pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
"avatar-default",
icon_size,
GTK_ICON_LOOKUP_FORCE_SIZE,
&error);
if (error) {
g_warning ("%s", error->message);
g_error_free (error);
}
out:
if (pixbuf != NULL) {
framed = frame_pixbuf (pixbuf);
if (framed != NULL) {
g_object_unref (pixbuf);
pixbuf = framed;
}
}
return pixbuf;
}
/**
* gdm_user_get_icon_file:
* @user: a #GdmUser
*
* Returns the path to the account icon belonging to @user.
*
* Returns: (transfer none): a path to an icon
*/
const char *
gdm_user_get_icon_file (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), NULL);
return user->icon_file;
}
/**
* gdm_user_get_object_path:
* @user: a #GdmUser
*
* Returns the user accounts service object path of @user,
* or %NULL if @user doesn't have an object path associated
* with it.
*
* Returns: (transfer none): the primary ConsoleKit session id of the user
*/
const char *
gdm_user_get_object_path (GdmUser *user)
{
g_return_val_if_fail (GDM_IS_USER (user), NULL);
return user->object_path;
}
/**
* gdm_user_get_primary_session_id:
* @user: a #GdmUser
*
* Returns the primary ConsoleKit session id of @user, or %NULL if @user isn't
* logged in.
*
* Returns: (transfer none): the primary ConsoleKit session id of the user
*/
const char *
gdm_user_get_primary_session_id (GdmUser *user)
{
if (!gdm_user_is_logged_in (user)) {
g_debug ("User %s is not logged in, so has no primary session",
gdm_user_get_user_name (user));
return NULL;
}
/* FIXME: better way to choose? */
return user->sessions->data;
}
static void
collect_props (const gchar *key,
const GValue *value,
GdmUser *user)
{
gboolean handled = TRUE;
if (strcmp (key, "Uid") == 0) {
user->uid = g_value_get_uint64 (value);
} else if (strcmp (key, "UserName") == 0) {
g_free (user->user_name);
user->user_name = g_value_dup_string (value);
} else if (strcmp (key, "RealName") == 0) {
g_free (user->real_name);
user->real_name = g_value_dup_string (value);
} else if (strcmp (key, "AccountType") == 0) {
/* ignore */
} else if (strcmp (key, "Email") == 0) {
/* ignore */
} else if (strcmp (key, "Language") == 0) {
/* ignore */
} else if (strcmp (key, "Location") == 0) {
/* ignore */
} else if (strcmp (key, "LoginFrequency") == 0) {
user->login_frequency = g_value_get_uint64 (value);
} else if (strcmp (key, "IconFile") == 0) {
gboolean res;
g_free (user->icon_file);
user->icon_file = g_value_dup_string (value);
res = check_user_file (user->icon_file);
if (!res) {
g_free (user->icon_file);
user->icon_file = g_build_filename (GLOBAL_FACEDIR, user->user_name, NULL);
}
} else if (strcmp (key, "Locked") == 0) {
/* ignore */
} else if (strcmp (key, "AutomaticLogin") == 0) {
/* ignore */
} else if (strcmp (key, "PasswordMode") == 0) {
/* ignore */
} else if (strcmp (key, "PasswordHint") == 0) {
/* ignore */
} else if (strcmp (key, "HomeDirectory") == 0) {
/* ignore */
} else if (strcmp (key, "Shell") == 0) {
/* ignore */
} else {
handled = FALSE;
}
if (!handled) {
g_debug ("unhandled property %s", key);
}
}
static void
on_get_all_finished (DBusGProxy *proxy,
DBusGProxyCall *call,
GdmUser *user)
{
GError *error;
GHashTable *hash_table;
gboolean res;
g_assert (user->get_all_call == call);
g_assert (user->object_proxy == proxy);
error = NULL;
res = dbus_g_proxy_end_call (proxy,
call,
&error,
dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
&hash_table,
G_TYPE_INVALID);
user->get_all_call = NULL;
user->object_proxy = NULL;
if (! res) {
g_debug ("Error calling GetAll() when retrieving properties for %s: %s",
user->object_path, error->message);
g_error_free (error);
goto out;
}
g_hash_table_foreach (hash_table, (GHFunc) collect_props, user);
g_hash_table_unref (hash_table);
if (!user->is_loaded) {
set_is_loaded (user, TRUE);
}
g_signal_emit (user, signals[CHANGED], 0);
out:
g_object_unref (proxy);
}
static gboolean
update_info (GdmUser *user)
{
DBusGProxy *proxy;
DBusGProxyCall *call;
proxy = dbus_g_proxy_new_for_name (user->connection,
ACCOUNTS_NAME,
user->object_path,
DBUS_INTERFACE_PROPERTIES);
call = dbus_g_proxy_begin_call (proxy,
"GetAll",
(DBusGProxyCallNotify)
on_get_all_finished,
user,
NULL,
G_TYPE_STRING,
ACCOUNTS_USER_INTERFACE,
G_TYPE_INVALID);
if (call == NULL) {
g_warning ("GdmUser: failed to make GetAll call");
goto failed;
}
user->get_all_call = call;
user->object_proxy = proxy;
return TRUE;
failed:
if (proxy != NULL) {
g_object_unref (proxy);
}
return FALSE;
}
static void
changed_handler (DBusGProxy *proxy,
gpointer *data)
{
GdmUser *user = GDM_USER (data);
update_info (user);
}
/**
* _gdm_user_update_from_object_path:
* @user: the user object to update.
* @object_path: the object path of the user to use.
*
* Updates the properties of @user from the accounts service via
* the object path in @object_path.
**/
void
_gdm_user_update_from_object_path (GdmUser *user,
const char *object_path)
{
g_return_if_fail (GDM_IS_USER (user));
g_return_if_fail (object_path != NULL);
g_return_if_fail (user->object_path == NULL);
user->object_path = g_strdup (object_path);
user->accounts_proxy = dbus_g_proxy_new_for_name (user->connection,
ACCOUNTS_NAME,
user->object_path,
ACCOUNTS_USER_INTERFACE);
dbus_g_proxy_set_default_timeout (user->accounts_proxy, INT_MAX);
dbus_g_proxy_add_signal (user->accounts_proxy, "Changed", G_TYPE_INVALID);
dbus_g_proxy_connect_signal (user->accounts_proxy, "Changed",
G_CALLBACK (changed_handler), user, NULL);
if (!update_info (user)) {
g_warning ("Couldn't update info for user with object path %s", object_path);
}
}
/**
* gdm_user_is_loaded:
* @user: a #GdmUser
*
* Determines whether or not the user object is loaded and ready to read from.
* #GdmUserManager:is-loaded property must be %TRUE before calling
* gdm_user_manager_list_users()
*
* Returns: %TRUE or %FALSE
*/
gboolean
gdm_user_is_loaded (GdmUser *user)
{
return user->is_loaded;
}