/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* Copyright (C) 2005 Carlos Garnacho
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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.
*
* Authors: Carlos Garnacho Parro <carlosg@gnome.org>
*/
#include <dbus/dbus.h>
#include <glib-object.h>
#include <string.h>
#include "oobs-object.h"
#include "oobs-object-private.h"
#include "oobs-list.h"
#include "oobs-list-private.h"
#include "oobs-groupsconfig.h"
#include "oobs-usersconfig.h"
#include "oobs-group.h"
#include "oobs-defines.h"
#include "utils.h"
#define GROUPS_CONFIG_REMOTE_OBJECT "GroupsConfig"
#define OOBS_GROUPS_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), OOBS_TYPE_GROUPS_CONFIG, OobsGroupsConfigPrivate))
typedef struct _OobsGroupsConfigPrivate OobsGroupsConfigPrivate;
struct _OobsGroupsConfigPrivate
{
OobsList *groups_list;
gid_t minimum_gid;
gid_t maximum_gid;
guint id;
};
static void oobs_groups_config_class_init (OobsGroupsConfigClass *class);
static void oobs_groups_config_init (OobsGroupsConfig *config);
static void oobs_groups_config_finalize (GObject *object);
static void oobs_groups_config_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void oobs_groups_config_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void oobs_groups_config_update (OobsObject *object);
static void oobs_groups_config_commit (OobsObject *object);
enum {
PROP_0,
PROP_MINIMUM_GID,
PROP_MAXIMUM_GID
};
G_DEFINE_TYPE (OobsGroupsConfig, oobs_groups_config, OOBS_TYPE_OBJECT);
static void
oobs_groups_config_class_init (OobsGroupsConfigClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
OobsObjectClass *oobs_object_class = OOBS_OBJECT_CLASS (class);
object_class->set_property = oobs_groups_config_set_property;
object_class->get_property = oobs_groups_config_get_property;
object_class->finalize = oobs_groups_config_finalize;
oobs_object_class->commit = oobs_groups_config_commit;
oobs_object_class->update = oobs_groups_config_update;
g_object_class_install_property (object_class,
PROP_MINIMUM_GID,
g_param_spec_int ("minimum-gid",
"Minimum GID",
"Minimum GID for non-system groups",
0, OOBS_MAX_GID, OOBS_MAX_GID,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_MAXIMUM_GID,
g_param_spec_int ("maximum-gid",
"Maximum GID",
"Maximum GID for non-system groups",
0, OOBS_MAX_GID, OOBS_MAX_GID,
G_PARAM_READWRITE));
g_type_class_add_private (object_class,
sizeof (OobsGroupsConfigPrivate));
}
static void
oobs_groups_config_init (OobsGroupsConfig *config)
{
OobsGroupsConfigPrivate *priv;
g_return_if_fail (OOBS_IS_GROUPS_CONFIG (config));
priv = OOBS_GROUPS_CONFIG_GET_PRIVATE (config);
config->_priv = priv;
priv->groups_list = _oobs_list_new (OOBS_TYPE_GROUP);
}
static void
oobs_groups_config_finalize (GObject *object)
{
OobsGroupsConfigPrivate *priv;
g_return_if_fail (OOBS_IS_GROUPS_CONFIG (object));
priv = OOBS_GROUPS_CONFIG (object)->_priv;
if (priv && priv->groups_list)
g_object_unref (priv->groups_list);
if (G_OBJECT_CLASS (oobs_groups_config_parent_class)->finalize)
(* G_OBJECT_CLASS (oobs_groups_config_parent_class)->finalize) (object);
}
static void
oobs_groups_config_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
OobsGroupsConfigPrivate *priv;
g_return_if_fail (OOBS_IS_GROUPS_CONFIG (object));
priv = OOBS_GROUPS_CONFIG (object)->_priv;
switch (prop_id)
{
case PROP_MINIMUM_GID:
priv->minimum_gid = g_value_get_int (value);
break;
case PROP_MAXIMUM_GID:
priv->maximum_gid = g_value_get_int (value);
break;
}
}
static void
oobs_groups_config_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
OobsGroupsConfigPrivate *priv;
g_return_if_fail (OOBS_IS_GROUPS_CONFIG (object));
priv = OOBS_GROUPS_CONFIG (object)->_priv;
switch (prop_id)
{
case PROP_MINIMUM_GID:
g_value_set_int (value, priv->minimum_gid);
break;
case PROP_MAXIMUM_GID:
g_value_set_int (value, priv->maximum_gid);
break;
}
}
static OobsGroup*
create_group_from_dbus_reply (OobsObject *object,
DBusMessage *reply,
DBusMessageIter struct_iter,
GHashTable *hashtable,
guint *max_id)
{
DBusMessageIter iter;
int gid;
guint id;
gchar *groupname, *passwd;
GList *users;
OobsGroup *group;
dbus_message_iter_recurse (&struct_iter, &iter);
dbus_message_iter_get_basic (&iter, &id);
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &groupname);
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &passwd);
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &gid);
dbus_message_iter_next (&iter);
users = utils_get_string_list_from_dbus_reply (reply, iter);
group = g_object_new (OOBS_TYPE_GROUP,
"name", groupname,
"crypted-password", passwd,
"gid", gid,
NULL);
/* set the id by hand */
group->id = id;
*max_id = MAX (id, *max_id);
/* put the users list in the hashtable, when the groups list has
* been completely generated, we may query the users config safely */
g_hash_table_insert (hashtable,
g_object_ref (group),
users);
return OOBS_GROUP (group);
}
static GList*
get_users_list (OobsGroup *group)
{
GList *users, *elem, *usernames = NULL;
OobsUser *user;
users = elem = oobs_group_get_users (group);
while (elem)
{
user = elem->data;
usernames = g_list_prepend (usernames, (gpointer) oobs_user_get_login_name (user));
elem = elem->next;
}
g_list_free (users);
return usernames;
}
static void
create_dbus_struct_from_group (GObject *group,
DBusMessage *message,
DBusMessageIter *array_iter)
{
DBusMessageIter struct_iter;
int gid;
gchar *groupname, *passwd;
GList *users;
g_object_get (group,
"name", &groupname,
"crypted-password", &passwd,
"gid", &gid,
NULL);
users = get_users_list (OOBS_GROUP (group));
dbus_message_iter_open_container (array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter);
dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_UINT32, &(OOBS_GROUP(group)->id));
utils_append_string (&struct_iter, groupname);
utils_append_string (&struct_iter, passwd);
dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &gid);
utils_create_dbus_array_from_string_list (users, message, &struct_iter);
dbus_message_iter_close_container (array_iter, &struct_iter);
g_list_free (users);
g_free (groupname);
g_free (passwd);
}
static OobsUser*
find_user (OobsList *users_list, gchar *username)
{
OobsListIter iter;
OobsUser *user;
gboolean valid;
valid = oobs_list_get_iter_first (users_list, &iter);
while (valid)
{
user = OOBS_USER (oobs_list_get (users_list, &iter));
if (strcmp (username, oobs_user_get_login_name (user)) == 0)
return user;
valid = oobs_list_iter_next (users_list, &iter);
g_object_unref (user);
}
return NULL;
}
static void
query_users_foreach (OobsGroup *group,
GList *users,
gpointer data)
{
OobsUsersConfig *users_config = OOBS_USERS_CONFIG (data);
OobsList *users_list = oobs_users_config_get_users (users_config);
OobsUser *user;
while (users)
{
user = find_user (users_list, users->data);
if (user)
{
oobs_group_add_user (group, user);
g_object_unref (user);
}
users = users->next;
}
}
static void
query_users (OobsGroupsConfig *groups_config,
GHashTable *hashtable)
{
OobsObject *users_config;
OobsSession *session;
g_object_get (G_OBJECT (groups_config),
"session", &session,
NULL);
users_config = oobs_users_config_get (session);
g_hash_table_foreach (hashtable, (GHFunc) query_users_foreach, users_config);
g_object_unref (session);
}
static void
free_users_foreach (OobsGroup *group,
GList *users,
gpointer data)
{
g_list_foreach (users, (GFunc) g_free, NULL);
}
static void
oobs_groups_config_update (OobsObject *object)
{
OobsGroupsConfigPrivate *priv;
DBusMessage *reply;
DBusMessageIter iter, elem_iter;
OobsListIter list_iter;
GObject *group;
GHashTable *hashtable;
guint id;
priv = OOBS_GROUPS_CONFIG (object)->_priv;
reply = _oobs_object_get_dbus_message (object);
hashtable = g_hash_table_new_full (NULL, NULL,
(GDestroyNotify) g_object_unref,
(GDestroyNotify) g_list_free);
id = 0;
/* First of all, free the previous list */
oobs_list_clear (priv->groups_list);
dbus_message_iter_init (reply, &iter);
dbus_message_iter_recurse (&iter, &elem_iter);
while (dbus_message_iter_get_arg_type (&elem_iter) == DBUS_TYPE_STRUCT)
{
group = G_OBJECT (create_group_from_dbus_reply (object, reply,
elem_iter, hashtable, &id));
oobs_list_append (priv->groups_list, &list_iter);
oobs_list_set (priv->groups_list, &list_iter, G_OBJECT (group));
g_object_unref (group);
dbus_message_iter_next (&elem_iter);
}
priv->id = id;
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &priv->minimum_gid);
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &priv->maximum_gid);
/* last of all, query the groups now that the list is generated */
query_users (OOBS_GROUPS_CONFIG (object), hashtable);
g_hash_table_foreach (hashtable, (GHFunc) free_users_foreach, NULL);
g_hash_table_unref (hashtable);
}
static void
oobs_groups_config_commit (OobsObject *object)
{
OobsGroupsConfigPrivate *priv;
DBusMessage *message;
DBusMessageIter iter, array_iter;
OobsListIter list_iter;
GObject *group;
gboolean valid;
priv = OOBS_GROUPS_CONFIG (object)->_priv;
message = _oobs_object_get_dbus_message (object);
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY,
DBUS_STRUCT_BEGIN_CHAR_AS_STRING
DBUS_TYPE_UINT32_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_INT32_AS_STRING
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_STRUCT_END_CHAR_AS_STRING,
&array_iter);
valid = oobs_list_get_iter_first (priv->groups_list, &list_iter);
while (valid)
{
group = oobs_list_get (priv->groups_list, &list_iter);
create_dbus_struct_from_group (group, message, &array_iter);
g_object_unref (group);
valid = oobs_list_iter_next (priv->groups_list, &list_iter);
}
dbus_message_iter_close_container (&iter, &array_iter);
}
/**
* oobs_groups_config_get:
* @session: An #OobsSession.
*
* Returns the #OobsGroupsConfig singleton, which
* represents the groups configuration.
*
* Return Value: the singleton #OobsGoupsConfig
**/
OobsObject*
oobs_groups_config_get (OobsSession *session)
{
static OobsObject *object = NULL;
g_return_val_if_fail (session != NULL, NULL);
g_return_val_if_fail (OOBS_IS_SESSION (session), NULL);
if (!object)
{
object = g_object_new (OOBS_TYPE_GROUPS_CONFIG,
"remote-object", GROUPS_CONFIG_REMOTE_OBJECT,
"session", session,
NULL);
oobs_object_update (object);
}
return object;
}
/**
* oobs_groups_config_get_groups:
* @config: An #OobsGroupsConfig.
*
* Returns an #OobsList containing objects of type #OobsGroup.
*
* Return Value: An OobsList containing the groups configuration.
**/
OobsList*
oobs_groups_config_get_groups (OobsGroupsConfig *config)
{
OobsGroupsConfigPrivate *priv;
g_return_val_if_fail (config != NULL, NULL);
g_return_val_if_fail (OOBS_IS_GROUPS_CONFIG (config), NULL);
priv = config->_priv;
return priv->groups_list;
}
guint
_oobs_groups_config_get_id (OobsGroupsConfig *config)
{
OobsGroupsConfigPrivate *priv;
priv = config->_priv;
/* FIXME: this could overflow */
return ++priv->id;
}
syntax highlighted by Code2HTML, v. 0.9.1