/* -*- 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 */ #include #include #include #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; }