/* -*- 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-usersconfig.h"
#include "oobs-user.h"
#include "oobs-defines.h"
#include "oobs-groupsconfig.h"
#include "oobs-group.h"
#include "utils.h"

#define USERS_CONFIG_REMOTE_OBJECT "UsersConfig"
#define OOBS_USERS_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), OOBS_TYPE_USERS_CONFIG, OobsUsersConfigPrivate))

typedef struct _OobsUsersConfigPrivate OobsUsersConfigPrivate;

struct _OobsUsersConfigPrivate
{
  OobsList *users_list;

  GList    *shells;

  gboolean  use_md5;
  uid_t     minimum_uid;
  uid_t     maximum_uid;
  gchar    *default_shell;
  gchar    *default_home;
  guint     id;

  OobsGroup *default_group;
};

static void oobs_users_config_class_init (OobsUsersConfigClass *class);
static void oobs_users_config_init       (OobsUsersConfig      *config);
static void oobs_users_config_finalize   (GObject              *object);

static void oobs_users_config_set_property (GObject      *object,
					    guint         prop_id,
					    const GValue *value,
					    GParamSpec   *pspec);
static void oobs_users_config_get_property (GObject      *object,
					    guint         prop_id,
					    GValue       *value,
					    GParamSpec   *pspec);

static void oobs_users_config_update     (OobsObject   *object);
static void oobs_users_config_commit     (OobsObject   *object);

enum
{
  PROP_0,
  PROP_USE_MD5,
  PROP_MINIMUM_UID,
  PROP_MAXIMUM_UID,
  PROP_DEFAULT_SHELL,
  PROP_DEFAULT_HOME,
  PROP_DEFAULT_GROUP
};

G_DEFINE_TYPE (OobsUsersConfig, oobs_users_config, OOBS_TYPE_OBJECT);


static void
oobs_users_config_class_init (OobsUsersConfigClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  OobsObjectClass *oobs_object_class = OOBS_OBJECT_CLASS (class);

  object_class->set_property = oobs_users_config_set_property;
  object_class->get_property = oobs_users_config_get_property;
  object_class->finalize     = oobs_users_config_finalize;

  oobs_object_class->commit  = oobs_users_config_commit;
  oobs_object_class->update  = oobs_users_config_update;

  g_object_class_install_property (object_class,
				   PROP_USE_MD5,
				   g_param_spec_boolean ("use-md5",
							 "Use MD5",
							 "Whether users' passwords are stored in MD5",
							 FALSE,
							 G_PARAM_READABLE));
  g_object_class_install_property (object_class,
				   PROP_MINIMUM_UID,
				   g_param_spec_int ("minimum-uid",
						     "Minimum UID",
						     "Minimum UID for non-system users",
						     0, OOBS_MAX_UID, OOBS_MAX_UID,
						     G_PARAM_READWRITE));
  g_object_class_install_property (object_class,
				   PROP_MAXIMUM_UID,
				   g_param_spec_int ("maximum-uid",
						     "Maximum UID",
						     "Maximum UID for non-system users",
						     0, OOBS_MAX_UID, OOBS_MAX_UID,
						     G_PARAM_READWRITE));
  g_object_class_install_property (object_class,
				   PROP_DEFAULT_SHELL,
				   g_param_spec_string ("default-shell",
							"Default shell",
							"Default shell for new users",
							NULL,
							G_PARAM_READWRITE));
  g_object_class_install_property (object_class,
				   PROP_DEFAULT_HOME,
				   g_param_spec_string ("default-home",
							"Default home directory",
							"Default home directory for new users",
							NULL,
							G_PARAM_READWRITE));
  g_object_class_install_property (object_class,
				   PROP_DEFAULT_GROUP,
				   g_param_spec_object ("default-group",
							"Default group",
							"Default group for new users",
							OOBS_TYPE_GROUP,
							G_PARAM_READABLE));
  g_type_class_add_private (object_class,
			    sizeof (OobsUsersConfigPrivate));
}

static void
oobs_users_config_init (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_if_fail (OOBS_IS_USERS_CONFIG (config));

  priv = OOBS_USERS_CONFIG_GET_PRIVATE (config);

  priv->users_list = _oobs_list_new (OOBS_TYPE_USER);
  config->_priv = priv;
}

static void
free_configuration (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  priv = config->_priv;

  oobs_list_clear (priv->users_list);
  g_free (priv->default_shell);
  g_free (priv->default_home);

  if (priv->shells)
    {
      g_list_foreach (priv->shells, (GFunc) g_free, NULL);
      g_list_free (priv->shells);
      priv->shells = NULL;
    }
}

static void
oobs_users_config_finalize (GObject *object)
{
  OobsUsersConfigPrivate *priv;

  g_return_if_fail (OOBS_IS_USERS_CONFIG (object));

  priv = OOBS_USERS_CONFIG (object)->_priv;

  if (priv)
    {
      free_configuration (OOBS_USERS_CONFIG (object));

      if (priv->users_list)
	g_object_unref (priv->users_list);
    }

  if (G_OBJECT_CLASS (oobs_users_config_parent_class)->finalize)
    (* G_OBJECT_CLASS (oobs_users_config_parent_class)->finalize) (object);
}

static void
oobs_users_config_set_property (GObject      *object,
				guint         prop_id,
				const GValue *value,
				GParamSpec   *pspec)
{
  OobsUsersConfigPrivate *priv;

  g_return_if_fail (OOBS_IS_USERS_CONFIG (object));

  priv = OOBS_USERS_CONFIG (object)->_priv;

  switch (prop_id)
    {
    case PROP_MINIMUM_UID:
      priv->minimum_uid = g_value_get_int (value);
      break;
    case PROP_MAXIMUM_UID:
      priv->maximum_uid = g_value_get_int (value);
      break;
    case PROP_DEFAULT_SHELL:
      g_free (priv->default_shell);
      priv->default_shell = g_value_dup_string (value);
      break;
    case PROP_DEFAULT_HOME:
      g_free (priv->default_home);
      priv->default_home = g_value_dup_string (value);
      break;
    }
}

static void
oobs_users_config_get_property (GObject      *object,
				guint         prop_id,
				GValue       *value,
				GParamSpec   *pspec)
{
  OobsUsersConfigPrivate *priv;

  g_return_if_fail (OOBS_IS_USERS_CONFIG (object));

  priv = OOBS_USERS_CONFIG (object)->_priv;

  switch (prop_id)
    {
    case PROP_USE_MD5:
      g_value_set_boolean (value, priv->use_md5);
      break;
    case PROP_MINIMUM_UID:
      g_value_set_int (value, priv->minimum_uid);
      break;
    case PROP_MAXIMUM_UID:
      g_value_set_int (value, priv->maximum_uid);
      break;
    case PROP_DEFAULT_SHELL:
      g_value_set_string (value, priv->default_shell);
      break;
    case PROP_DEFAULT_HOME:
      g_value_set_string (value, priv->default_home);
      break;
    }
}

static OobsUser*
create_user_from_dbus_reply (OobsObject      *object,
			     DBusMessage     *reply,
			     DBusMessageIter  struct_iter,
			     GHashTable      *hashtable,
			     guint           *max_id)
{
  OobsUser *user;
  DBusMessageIter iter, gecos_iter;
  int    uid, gid;
  guint  id;
  gchar *login, *passwd, *home, *shell;
  gchar *name, *room_number, *work_phone, *home_phone, *other_data;

  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, &login);
  dbus_message_iter_next (&iter);
  
  dbus_message_iter_get_basic (&iter, &passwd);
  dbus_message_iter_next (&iter);

  dbus_message_iter_get_basic (&iter, &uid);
  dbus_message_iter_next (&iter);

  dbus_message_iter_get_basic (&iter, &gid);
  dbus_message_iter_next (&iter);

  /* GECOS fields */
  dbus_message_iter_recurse (&iter, &gecos_iter);

  dbus_message_iter_get_basic (&gecos_iter, &name);
  dbus_message_iter_next (&gecos_iter);

  dbus_message_iter_get_basic (&gecos_iter, &room_number);
  dbus_message_iter_next (&gecos_iter);

  dbus_message_iter_get_basic (&gecos_iter, &work_phone);
  dbus_message_iter_next (&gecos_iter);

  dbus_message_iter_get_basic (&gecos_iter, &home_phone);
  dbus_message_iter_next (&gecos_iter);

  dbus_message_iter_get_basic (&gecos_iter, &other_data);
  dbus_message_iter_next (&gecos_iter);
  /* end of GECOS fields */

  dbus_message_iter_next (&iter);

  dbus_message_iter_get_basic (&iter, &home);
  dbus_message_iter_next (&iter);

  dbus_message_iter_get_basic (&iter, &shell);
  dbus_message_iter_next (&iter);

  user = g_object_new (OOBS_TYPE_USER,
		       "name", login,
		       "crypted-password", passwd,
		       "uid", uid,
		       "home-directory", home,
		       "shell", shell,
		       "full-name", name,
		       "room-number", room_number,
		       "work-phone", work_phone,
		       "home-phone", home_phone,
		       "other-data", other_data,
		       NULL);

  /* set the id by hand */
  user->id = id;
  *max_id = MAX (id, *max_id);

  /* put the GID in the hashtable, when the users list has
   * been completely generated, we may query the groups safely */
  g_hash_table_insert (hashtable,
		       g_object_ref (user),
		       (gpointer) gid);
  return user;
}

static gboolean
create_dbus_struct_from_user (OobsUser        *user,
			      DBusMessage     *message,
			      DBusMessageIter *array_iter)
{
  OobsGroup *group;
  gint uid, gid;
  gchar *login, *password, *shell, *homedir;
  gchar *name, *room_number, *work_phone, *home_phone, *other_data;
  DBusMessageIter struct_iter, data_iter;

  g_object_get (user,
		"name", &login,
		"crypted-password", &password,
		"uid", &uid,
		"home-directory", &homedir,
		"shell", &shell,
		"full-name", &name,
		"room-number", &room_number,
		"work-phone", &work_phone,
		"home-phone", &home_phone,
		"other-data", &other_data,
		NULL);

  g_return_val_if_fail ((login && password && homedir && shell), FALSE);

  group = oobs_user_get_main_group (user);
  gid = oobs_group_get_gid (group);

  dbus_message_iter_open_container (array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter);

  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_UINT32,  &user->id);
  utils_append_string (&struct_iter, login);
  utils_append_string (&struct_iter, password);
  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32,  &uid);
  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32,  &gid);
  
  dbus_message_iter_open_container (&struct_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &data_iter);

  /* GECOS fields */
  utils_append_string (&data_iter, name);
  utils_append_string (&data_iter, room_number);
  utils_append_string (&data_iter, work_phone);
  utils_append_string (&data_iter, home_phone);
  utils_append_string (&data_iter, other_data);

  dbus_message_iter_close_container (&struct_iter, &data_iter);

  utils_append_string (&struct_iter, homedir);
  utils_append_string (&struct_iter, shell);
  dbus_message_iter_close_container (array_iter, &struct_iter);

  g_free (login);
  g_free (password);
  g_free (shell);
  g_free (homedir);
  g_free (name);
  g_free (room_number);
  g_free (work_phone);
  g_free (home_phone);
  g_free (other_data);

  return TRUE;
}

static OobsGroup*
get_group_with_gid (OobsGroupsConfig *config,
		    gint              gid)
{
  OobsList *groups_list;
  OobsListIter iter;
  OobsGroup *group;
  gboolean valid;

  groups_list = oobs_groups_config_get_groups (config);
  valid = oobs_list_get_iter_first (groups_list, &iter);

  while (valid)
    {
      group = OOBS_GROUP (oobs_list_get (groups_list, &iter));

      if (oobs_group_get_gid (group) == gid)
	return group;

      g_object_unref (group);
      valid = oobs_list_iter_next (groups_list, &iter);
    }

  return NULL;
}

static void
query_groups_foreach (OobsUser *user,
		      gint      gid,
		      gpointer  data)
{
  OobsGroupsConfig *groups_config = OOBS_GROUPS_CONFIG (data);
  OobsGroup *group;

  group = get_group_with_gid (groups_config, gid);
  oobs_user_set_main_group (user, group);

  if (group)
    g_object_unref (group);
}

static void
query_groups (OobsUsersConfig *users_config,
	      GHashTable      *hashtable,
	      gint             default_gid)
{
  OobsObject *groups_config;
  OobsSession *session;
  OobsGroup *group;

  g_object_get (G_OBJECT (users_config),
		"session", &session,
		NULL);

  groups_config = oobs_groups_config_get (session);
  g_hash_table_foreach (hashtable, (GHFunc) query_groups_foreach, groups_config);

  /* get the default group */
  if (default_gid > 0)
    {
      group = get_group_with_gid (OOBS_GROUPS_CONFIG (groups_config), default_gid);
      ((OobsUsersConfigPrivate *) users_config->_priv)->default_group = group;

      if (group)
	g_object_unref (group);
    }

  g_object_unref (session);
}

static void
oobs_users_config_update (OobsObject *object)
{
  OobsUsersConfigPrivate *priv;
  DBusMessage     *reply;
  DBusMessageIter  iter, elem_iter;
  OobsListIter     list_iter;
  GObject         *user;
  gchar           *str;
  GHashTable      *hashtable;
  gint             default_gid;
  guint            id;

  priv  = OOBS_USERS_CONFIG (object)->_priv;
  reply = _oobs_object_get_dbus_message (object);
  hashtable = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
  id = 0;

  /* First of all, free the previous configuration */
  free_configuration (OOBS_USERS_CONFIG (object));

  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)
    {
      user = G_OBJECT (create_user_from_dbus_reply (object, reply,
						    elem_iter, hashtable, &id));

      oobs_list_append (priv->users_list, &list_iter);
      oobs_list_set    (priv->users_list, &list_iter, G_OBJECT (user));
      g_object_unref   (user);

      dbus_message_iter_next (&elem_iter);
    }

  priv->id = id;

  dbus_message_iter_next (&iter);
  priv->shells = utils_get_string_list_from_dbus_reply (reply, iter);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &priv->use_md5);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &priv->minimum_uid);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &priv->maximum_uid);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &str);
  priv->default_home = g_strdup (str);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &str);
  priv->default_shell = g_strdup (str);

  dbus_message_iter_next (&iter);
  dbus_message_iter_get_basic (&iter, &default_gid);

  /* last of all, query the groups now that the list is generated */
  query_groups (OOBS_USERS_CONFIG (object), hashtable, default_gid);
  g_hash_table_unref (hashtable);
}

static void
oobs_users_config_commit (OobsObject *object)
{
  OobsUsersConfigPrivate *priv;
  DBusMessage *message;
  DBusMessageIter iter, array_iter;
  OobsListIter list_iter;
  GObject *user;
  gboolean valid, correct;
  gint default_gid;

  priv = OOBS_USERS_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_INT32_AS_STRING
				    DBUS_TYPE_ARRAY_AS_STRING
				    DBUS_TYPE_STRING_AS_STRING
				    DBUS_TYPE_STRING_AS_STRING
				    DBUS_TYPE_STRING_AS_STRING
				    DBUS_STRUCT_END_CHAR_AS_STRING
				    DBUS_TYPE_INT32_AS_STRING
				    DBUS_TYPE_INT32_AS_STRING
				    DBUS_TYPE_INT32_AS_STRING
				    DBUS_TYPE_STRING_AS_STRING
				    DBUS_TYPE_STRING_AS_STRING,
				    &array_iter);
  valid = oobs_list_get_iter_first (priv->users_list, &list_iter);
  correct = TRUE;

  while (valid && correct)
    {
      user = oobs_list_get (priv->users_list, &list_iter);
      correct = create_dbus_struct_from_user (OOBS_USER (user), message, &array_iter);

      g_object_unref (user);
      valid = oobs_list_iter_next (priv->users_list, &list_iter);
    }

  dbus_message_iter_close_container (&iter, &array_iter);

  utils_create_dbus_array_from_string_list (priv->shells, message, &iter);
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32,  &priv->use_md5);
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32,  &priv->minimum_uid);
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32,  &priv->maximum_uid);
  utils_append_string (&iter, priv->default_home);
  utils_append_string (&iter, priv->default_shell);

  default_gid = (priv->default_group) ? oobs_group_get_gid (priv->default_group) : -1;
  dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &default_gid);

  if (!correct)
    {
      /* malformed data, unset the message */
      _oobs_object_set_dbus_message (object, NULL);
    }
}

/**
 * oobs_users_config_get:
 * @session: An #OobsSession.
 * 
 * Returns the #OobsUsersConfig singleton, which represents
 * the system users and their configuration.
 * 
 * Return Value: the singleton #OobsUsersConfig object.
 **/
OobsObject*
oobs_users_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_USERS_CONFIG,
			     "remote-object", USERS_CONFIG_REMOTE_OBJECT,
			     "session",       session,
			     NULL);
      oobs_object_update (object);
    }

  return object;
}

/**
 * oobs_users_config_get_users:
 * @config: An #OobsUsersConfig.
 * 
 * Returns an #OobsList containing objects of type #OobsUser.
 * 
 * Return Value: an #OobsList containing the system users.
 **/
OobsList*
oobs_users_config_get_users (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, NULL);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), NULL);

  priv = config->_priv;

  return priv->users_list;
}

/**
 * oobs_users_config_get_minimum_users_uid:
 * @config: An #OobsUsersConfig.
 * 
 * Returns the default minimum UID for non-system users.
 * 
 * Return Value: minimum UID for non-system users.
 **/
uid_t
oobs_users_config_get_minimum_users_uid (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, OOBS_MAX_UID);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), OOBS_MAX_UID);

  priv = config->_priv;

  return priv->minimum_uid;
}

/**
 * oobs_users_config_set_minimum_users_uid:
 * @config: An #OobsUsersConfig.
 * @uid: new minimum UID for non-system users.
 * 
 * Sets the minimum UID for non-system users.
 **/
void
oobs_users_config_set_minimum_users_uid (OobsUsersConfig *config, uid_t uid)
{
  g_return_if_fail (config != NULL);
  g_return_if_fail (OOBS_IS_USERS_CONFIG (config));

  g_object_set (G_OBJECT (config), "minimum-uid", uid, NULL);
}

/**
 * oobs_users_config_get_maximum_users_uid:
 * @config: An #OobsUsersConfig.
 * 
 * Returns the default maximum UID for non-system users.
 * 
 * Return Value: maximum UID for non-system users.
 **/
uid_t
oobs_users_config_get_maximum_users_uid (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, OOBS_MAX_UID);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), OOBS_MAX_UID);

  priv = config->_priv;

  return priv->maximum_uid;
}

/**
 * oobs_users_config_set_maximum_users_uid:
 * @config: An #OobsUsersConfig.
 * @uid: a new maximum UID for non-system users.
 * 
 * Sets the maximum UID for non-system users.
 **/
void
oobs_users_config_set_maximum_users_uid (OobsUsersConfig *config, uid_t uid)
{
  g_return_if_fail (config != NULL);
  g_return_if_fail (OOBS_IS_USERS_CONFIG (config));

  g_object_set (G_OBJECT (config), "maximum-uid", uid, NULL);
}

/**
 * oobs_users_config_get_default_shell:
 * @config: An #OobsUsersConfig
 * 
 * Returns the default shell that will be used for new users.
 * 
 * Return Value: A pointer to the default shell as a string. This
 *               string must not be freed, modified or stored.
 **/
G_CONST_RETURN gchar*
oobs_users_config_get_default_shell (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, NULL);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), NULL);

  priv = config->_priv;

  return priv->default_shell;
}

/**
 * oobs_users_config_set_default_shell:
 * @config: An #OobsUsersConfig
 * @shell: new default shell for new users.
 * 
 * Sets a new default shell for new users, replacing the old one.
 **/
void
oobs_users_config_set_default_shell (OobsUsersConfig *config, const gchar *shell)
{
  g_return_if_fail (config != NULL);
  g_return_if_fail (OOBS_IS_USERS_CONFIG (config));

  g_object_set (G_OBJECT (config), "default-shell", shell, NULL);
}

/**
 * oobs_users_config_get_default_home_dir:
 * @config: An #OobsUsersConfig.
 * 
 * Returns the default home directory prefix for new users. when new users
 * are created a directory with the user login name is created in that prefix.
 * 
 * Return Value: A pointer to the default home directory prefix as a string. This
 *               string must not be freed, modified or stored.
 **/
G_CONST_RETURN gchar*
oobs_users_config_get_default_home_dir (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, NULL);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), NULL);

  priv = config->_priv;

  return priv->default_home;
}

/**
 * oobs_users_config_set_default_home_dir:
 * @config: An #OobsIfacesConfig.
 * @home_dir: new default home directory prefix.
 * 
 * Sets a new home directory prefix used for newly created users, replacing the old one.
 **/
void
oobs_users_config_set_default_home_dir (OobsUsersConfig *config, const gchar *home_dir)
{
  g_return_if_fail (config != NULL);
  g_return_if_fail (OOBS_IS_USERS_CONFIG (config));

  g_object_set (G_OBJECT (config), "default-home", home_dir, NULL);
}

/**
 * oobs_users_config_get_default_group:
 * @config: An #OobsUsersConfig.
 * 
 * Returns an #OobsGroup defining the default group used for new users.
 * 
 * Return Value: An #OobsGroup, you must not unref this object.
 **/
OobsGroup*
oobs_users_config_get_default_group (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, NULL);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), NULL);

  priv = config->_priv;

  return priv->default_group;
}

/**
 * oobs_users_config_get_available_shells:
 * @config: An #OobsUsersConfig
 * 
 * Returns a #GList containing strings with paths to the available shells.
 * 
 * Return Value: a #GList containing strings, you must not free
 * neither this list or its elements.
 **/
GList*
oobs_users_config_get_available_shells (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  g_return_val_if_fail (config != NULL, NULL);
  g_return_val_if_fail (OOBS_IS_USERS_CONFIG (config), NULL);

  priv = config->_priv;

  return priv->shells;
}

guint
_oobs_users_config_get_id (OobsUsersConfig *config)
{
  OobsUsersConfigPrivate *priv;

  priv = config->_priv;

  /* FIXME: this could overflow */
  return ++priv->id;
}


syntax highlighted by Code2HTML, v. 0.9.1