/* PureAdmin
 * Copyright (C) 2003 Isak Savo
 *
 *  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.
 */

/*
 * Usermanager functions
 *
 * Copyright (C) 2003 Isak Savo
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <gtk/gtk.h>

#include "cfg.h"
#include "gui_helper.h"
#include "globals.h"
#include "helper.h"
#include "system_accounts.h"
#include "usr_manager.h"
#include "purepw.h"

GladeXML *usrm_xml = NULL;

typedef struct {
  GdkPixbuf *icon;
  gchar *login;
  gchar *realname;
} PGuiUsermanRow;

static GtkWidget *create_usermanager (void)
{
	gchar *our_path;
	
	our_path = g_build_filename (datadir, PACKAGE, "usermanager.glade", NULL);
	usrm_xml = glade_xml_new (our_path, NULL, NULL);
	g_free (our_path);

	glade_xml_signal_autoconnect (usrm_xml);

	return UW("usermanager");
}

static void free_usredit_struct (GtkWidget *dlg, gpointer data)
{
	struct usrman_info_widgets **w = (struct usrman_info_widgets **) data;
	
	g_free (*w);
	*w = NULL;
}

static void free_pwstruct (PWInfo *i)
{
	if (!i)
		return;
	g_free (i->login);
	g_free (i->pwd);
	g_free (i->home);
	g_free (i->gecos);
	g_free (i->allow_local_ip);
	g_free (i->deny_local_ip);    
	g_free (i->allow_client_ip);
	g_free (i->deny_client_ip);
	g_free (i);
}

static struct usrman_info_widgets *get_widgets (void)
{
	static struct usrman_info_widgets *ret = NULL;
   
	if (G_UNLIKELY (!ret))
	{
		ret = g_new0 (struct usrman_info_widgets, 1);

		ret->login		 = UW("entry_username");
		ret->realname		 = UW("entry_realname");
		ret->e_uid		 = UW("optmenu_uid");
		ret->e_gid		 = UW("optmenu_gid");
		ret->chk_chroot		 = UW("chk_chroot");
		ret->home		 = UW("entry_home");
		ret->root		 = UW("entry_fakeroot");
		ret->quota_files	 = UW("spin_maxfiles");
		ret->quota_size		 = UW("spin_maxsize");
		ret->timelimit		 = UW("entry_timerestrictions");
		ret->simsess		 = UW("spin_simsessions");
		ret->loc_allow		 = UW("entry_allowedlocalip");
		ret->loc_deny		 = UW("entry_deniedlocalip");
		ret->cli_allow		 = UW("entry_allowedclientip");
		ret->cli_deny		 = UW("entry_deniedclientip");
		ret->bw_ul		 = UW("spin_ulbwidth");
		ret->bw_dl		 = UW("spin_dlbwidth");
		ret->ul_ratio		 = UW("spin_ratioup");
		ret->dl_ratio		 = UW("spin_ratiodown");
		ret->btn_pwchange	 = UW("btn_change_pw");
		ret->btn_savechanges	 = UW("btn_save_changes");
		ret->btn_cancelchanges	 = UW("btn_cancel_changes");
		ret->lbl_invalid_uid	 = UW("lbl_invalid_uid");
		ret->lbl_invalid_gid	 = UW("lbl_invalid_gid");
		ret->btn_browse_homedir  = UW("btn_browse_homedir");
		ret->btn_browse_fakeroot = UW("btn_browse_fakeroot");
		
		g_signal_connect (G_OBJECT (UW("usermanager")), "destroy",
				  G_CALLBACK (free_usredit_struct), &ret);
	}
	
	return ret;
}

/* Returns all information stored in the user information widgets */
static PWInfo *usr_widgets_get_info (void)
{
	PWInfo *i;
	struct usrman_info_widgets *w;
	gchar *tmp, *t_home, *t_root;
	GList *items;
	gint sel;

	i = g_new0 (PWInfo, 1);
	w = get_widgets ();
	if (G_UNLIKELY (i == NULL || w == NULL))
		return NULL;
	
	i->login = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->login)));
	i->gecos = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->realname)));
	i->pwd = g_strdup ((gchar *) g_object_get_data (G_OBJECT (w->btn_pwchange), "usr_password"));

	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w->chk_chroot)))
	{
		/* Chroot user */
		i->chroot = TRUE;
		t_home = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->home)));
		t_root = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->root)));
		/* FIXME: Verify that this works for UTF-8 strings */
		tmp = t_home + strlen (t_home) - 1;
		while (*tmp == '/')
		{
			*tmp = 0;
			tmp--;
		}
		tmp = t_root + strlen (t_root) - 1;
		while (*tmp == '/')
		{
			*tmp = 0;
			tmp--;
		}
		if (strlen (t_root) > strlen (t_home) || strncmp (t_home, t_root, strlen (t_root)) != 0)
		{
			pur_log_nfo ("Fake root error: %s not part of %s", t_root, t_home);
			i->home = g_strdup_printf ("%s/./", t_home);
			gtk_entry_set_text (GTK_ENTRY (w->root), t_home);
			/* The fake root that the user specified wasn't part of the home directory and thus invalid! */
			gui_display_msgdialog (_("Invalid fake root"), 
					       _("The fake root you've selected is not a part of the homedirectory. The value has been defaulted to the users homedirectory."), 
					       MSGDLG_TYPE_WARNING, UW("usermanager"));
		}
		else if (strcmp (t_home, t_root) == 0)
			i->home = g_strdup_printf ("%s/./", t_home);
		else
		{
			tmp = t_home + strlen (t_root);
			*tmp = 0;
			tmp++; /* points to the remaining part of the home-dir */
			i->home = g_strdup_printf ("%s/./%s", t_root, tmp);
		}
		g_free (t_home);
		g_free (t_root);
	}
	else
	{
		i->chroot = FALSE;
		i->home = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->home)));
		tmp = i->home + strlen (i->home) - 1;
		while (*tmp == '/')
		{
			*tmp = 0;
			tmp--;
		}
	}

	if (!g_path_is_absolute (i->home))
	{
		/* Home directory *MUST* be an absolute path, starting with a '/' */
		pur_log_wrn ("Invalid homedir: %s is not absolute!", i->home);
		gui_display_msgdialog (_("Invalid home directory"), 
				       _("The home directory you have specified is not an absolute path (i.e. not starting with a '/'). Information could not be saved"),
				       MSGDLG_TYPE_ERROR, UW("usermanager"));
		free_pwstruct (i);
		return NULL;
	}

	/* UID / GID -- Needs conversion from menuitems to int */
	SystemAccount *tmp_account;
	sel = gtk_option_menu_get_history (GTK_OPTION_MENU (w->e_uid));
	items = g_object_get_data (G_OBJECT (w->e_uid), "items");
	tmp_account = (SystemAccount*) g_list_nth (items, sel)->data;
	if (tmp_account)
		i->uid = tmp_account->id;
   
	sel = gtk_option_menu_get_history (GTK_OPTION_MENU (w->e_gid));
	items = g_object_get_data (G_OBJECT (w->e_gid), "items");
	tmp_account = (SystemAccount*) g_list_nth (items, sel)->data;
	if (tmp_account)
		i->gid = tmp_account->id;
   
	/* Time -- Needs conversion from char to ints */
	tmp = (gchar *) gtk_entry_get_text (GTK_ENTRY (w->timelimit));
	sscanf (tmp, "%u-%u", &(i->time_begin), &(i->time_end));

	i->bw_dl = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->bw_dl));
	i->bw_ul = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->bw_ul));
	i->quota_files = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->quota_files));
	i->quota_size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->quota_size));
	i->ul_ratio = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->ul_ratio));
	i->dl_ratio = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->dl_ratio));
	i->per_user_max = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (w->simsess));
   
	i->allow_local_ip = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->loc_allow)));
	i->deny_local_ip = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->loc_deny)));
	i->allow_client_ip = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->cli_allow)));
	i->deny_client_ip = g_strdup (gtk_entry_get_text (GTK_ENTRY (w->cli_deny)));

	return i;
}

static void setup_optmenus (void)
{
	GtkWidget *menu;
	GtkWidget *opt_menu;
	GList *IDs;
   
	opt_menu = UW("optmenu_uid");
	IDs = sys_get_user_ids();
	menu = gui_create_system_account_menu(IDs);
	gtk_option_menu_remove_menu (GTK_OPTION_MENU (opt_menu));
	gtk_option_menu_set_menu (GTK_OPTION_MENU (opt_menu), menu);
	/* Keep the list attached to the menu for fast access in the callbacks */
	g_object_set_data_full (G_OBJECT (opt_menu), "items", IDs, (GDestroyNotify) system_account_list_free);

	opt_menu = UW("optmenu_gid");
	IDs = sys_get_group_ids();
	menu = gui_create_system_account_menu(IDs);
	gtk_option_menu_remove_menu (GTK_OPTION_MENU (opt_menu));
	gtk_option_menu_set_menu (GTK_OPTION_MENU (opt_menu), menu);
	g_object_set_data_full (G_OBJECT (opt_menu), "items", IDs, (GDestroyNotify) system_account_list_free);
   
	g_object_set_data (G_OBJECT (UW("usermanager")), "editing", GINT_TO_POINTER (FALSE));
}

static void setup_treeview (void)
{
	GtkTreeView *tree;
	GtkListStore *model;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	const gchar *titles[N_USRMAN_COLUMNS] = { "", _("Username"), _("Real Name") };

	
	/* Set-up treeview */
	tree = GTK_TREE_VIEW (UW("tree_userlist"));
	model  = gtk_list_store_new (N_USRMAN_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
	
	gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (model));
	g_object_unref (G_OBJECT (model));
	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)),
				     GTK_SELECTION_SINGLE);
	
	
	renderer = gtk_cell_renderer_pixbuf_new();
	column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
							   "pixbuf", COL_USRMAN_ICON,
							   NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes (titles[1], renderer,
							   "text", COL_USRMAN_LOGIN,
							   NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
	
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes (titles[2], renderer,
							   "text", COL_USRMAN_REALNAME,
							   NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
}


static void select_first_user (void)
{
	static GtkWidget *tree_userman = NULL;
	static GtkTreeSelection *sel = NULL;
	GtkTreePath *path;

	if (!tree_userman)
	{
		tree_userman = UW("tree_userlist");
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_userman));
	}
	path = gtk_tree_path_new_from_string ("0"); /* First item */
	gtk_tree_selection_select_path (sel, path);
	gtk_tree_path_free (path);
	g_signal_emit_by_name ((gpointer) tree_userman, 
			       "cursor_changed", tree_userman, NULL);
}

static void add_to_users_list (PGuiUsermanRow line)
{
	GtkTreeIter iter;
	static GtkWidget *tree = NULL;
	static GtkTreeModel *model = NULL;

	if (!tree)
	{
		tree = UW("tree_userlist");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree));
	}
	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
			    COL_USRMAN_ICON, line.icon,
			    COL_USRMAN_LOGIN, line.login,
			    COL_USRMAN_REALNAME, line.realname,
			    -1);
}

static void clear_users_list (void)
{
	static GtkWidget *tree_userman = NULL;
	static GtkTreeModel *model = NULL;
   
	if (!tree_userman)
	{
		tree_userman = UW("tree_userlist");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_userman));
	}
	gtk_list_store_clear (GTK_LIST_STORE (model));
}

/* Case insensitive compare between two (PAvailableUser) users */
static gint userlist_compare_available_users (gconstpointer p1, gconstpointer p2)
{
	PAvailableUser *u1, *u2;
	gchar *s1, *s2;
	gint rv;
	
	u1 = (PAvailableUser *) p1;
	u2 = (PAvailableUser *) p2;
	s1 = g_utf8_collate_key (u1->login, -1);
	s2 = g_utf8_collate_key (u2->login, -1);
   
	rv = strcmp (s1, s2);
	   
	g_free (s1);
	g_free (s2);
	
	return rv;
}

/** GLOBAL FUNCTIONS **/
void usr_select_user (const gchar *user)
{
	static GtkWidget *tree_userman = NULL;
	static GtkTreeModel *model = NULL;
	static GtkTreeSelection *sel = NULL;
	GtkTreeIter iter;
	gboolean more, found = FALSE;
	gchar *fetched_user;

	if (!tree_userman)
	{
		tree_userman = UW("tree_userlist");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_userman));
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_userman));
	}
	more = gtk_tree_model_get_iter_first (model, &iter);
	while (more)
	{
		gtk_tree_model_get (model, &iter,
				    COL_USR_USER, &fetched_user,
				    -1);
		if (g_str_equal (fetched_user, user))
		{
			found = TRUE;
			break;
		}
		more = gtk_tree_model_iter_next (model, &iter);
	}
	if (found)
	{
		gtk_tree_selection_select_iter (sel, &iter);
		g_signal_emit_by_name ((gpointer) tree_userman, "cursor-changed", tree_userman, NULL);
	}
}

gint usr_fill_users_list (void)
{
	GList *user_list = NULL, *node;
	gint ret = 0;
	static GdkPixbuf *icon_usr = NULL;
	PGuiUsermanRow line;
	PAvailableUser *usr;
   
	if (!icon_usr)
		icon_usr = create_pixbuf ("user.png");
       
	clear_users_list ();
	user_list = usr_get_available_users (NULL);
	user_list = g_list_sort (user_list, (GCompareFunc) userlist_compare_available_users);
	node = user_list;
	line.icon = icon_usr;
	while (node)
	{
		ret++;
		usr = (PAvailableUser *) node->data;
		line.login =  usr->login;
		line.realname = usr->realname;

		add_to_users_list (line);
		g_free (line.login);
		g_free (line.realname);
		g_free (node->data);
		node = g_list_next (node);
	}
	g_list_free (user_list);

	return ret;
}

void usr_widgets_set_active_state (gboolean active)
{
	struct usrman_info_widgets *w;
   
	w = get_widgets ();
	//   gtk_widget_set_sensitive (w->login, active);
	gtk_widget_set_sensitive (w->realname, active);
	gtk_widget_set_sensitive (w->e_uid, active);
	gtk_widget_set_sensitive (w->e_gid, active);
	gtk_widget_set_sensitive (w->chk_chroot, active);
	gtk_widget_set_sensitive (w->home, active);

	if (active && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w->chk_chroot)))
		gtk_widget_set_sensitive (w->root, active);
	else if (!active)
		gtk_widget_set_sensitive (w->root, FALSE);

	gtk_widget_set_sensitive (w->quota_files, active);
	gtk_widget_set_sensitive (w->quota_size, active);
	gtk_widget_set_sensitive (w->timelimit, active);
	gtk_widget_set_sensitive (w->simsess, active);
	gtk_widget_set_sensitive (w->loc_allow, active);
	gtk_widget_set_sensitive (w->loc_deny, active);
	gtk_widget_set_sensitive (w->cli_allow, active);
	gtk_widget_set_sensitive (w->cli_deny, active);
	gtk_widget_set_sensitive (w->bw_ul, active);
	gtk_widget_set_sensitive (w->bw_dl, active);
	gtk_widget_set_sensitive (w->ul_ratio, active);
	gtk_widget_set_sensitive (w->dl_ratio, active);
	gtk_widget_set_sensitive (w->btn_pwchange, active);
	gtk_widget_set_sensitive (w->btn_savechanges, active);
	gtk_widget_set_sensitive (w->btn_cancelchanges, active);
	gtk_widget_set_sensitive (w->btn_browse_homedir, active);
	gtk_widget_set_sensitive (w->btn_browse_fakeroot, active);
}

gboolean usr_widgets_set_info (gchar *user)
{
	PWInfo *info;
	struct usrman_info_widgets *w;
	gchar *tmp, **t_arr;
	GtkWidget *menu;
	GList *items = NULL;
	gint i;
	gboolean found = FALSE;
	GError *err = NULL;
	
	info = pw_get_user_information (user, &err);

	if (G_UNLIKELY (!info))
	{
		pur_log_wrn ("Error getting user information for %s: %s", user, err->message);
		g_error_free (err);
		return FALSE;
	}
	w = get_widgets ();
	gtk_entry_set_text (GTK_ENTRY (w->login), info->login);
	gtk_entry_set_text (GTK_ENTRY (w->realname), info->gecos);
   
	/* Hmm, this should be safe if g_object_get_data returns NULL upon failure */
	g_free (g_object_get_data (G_OBJECT (w->btn_pwchange), "usr_password"));
	if (MISC_VALID_STRING (info->pwd))
		g_object_set_data (G_OBJECT (w->btn_pwchange), "usr_password", g_strdup (info->pwd));
	else
		g_object_set_data (G_OBJECT (w->btn_pwchange), "usr_password", NULL);

	t_arr = g_strsplit (info->home, "/./", 2);
	if (t_arr[1] != NULL)
	{
		/* User is chroot'ed */
		if (t_arr[1])
			tmp = g_strdup_printf ("%s/%s", t_arr[0], t_arr[1]);
		else
			tmp = g_strdup (t_arr[0]);
		gtk_entry_set_text (GTK_ENTRY (w->home), tmp);
		g_free (tmp);
      
		tmp = g_strdup (t_arr[0]);
		gtk_entry_set_text (GTK_ENTRY (w->root), tmp);
		g_free (tmp);
      
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_chroot), TRUE);
	}
	else
	{
		/* No chroot */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_chroot), FALSE);
		gtk_entry_set_text (GTK_ENTRY (w->home), info->home);
		gtk_entry_set_text (GTK_ENTRY (w->root), "");
	}
	g_strfreev (t_arr);
	tmp = g_strdup_printf ("%04u-%04u", info->time_begin, info->time_end);
	gtk_entry_set_text (GTK_ENTRY (w->timelimit), tmp);
	g_free (tmp);
   
	gtk_entry_set_text (GTK_ENTRY (w->loc_allow), info->allow_local_ip);
	gtk_entry_set_text (GTK_ENTRY (w->loc_deny), info->deny_local_ip);
	gtk_entry_set_text (GTK_ENTRY (w->cli_allow), info->allow_client_ip);
	gtk_entry_set_text (GTK_ENTRY (w->cli_deny), info->deny_client_ip);
   
	/* UID / GID */
	menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (w->e_uid));
	items = (GList *) g_object_get_data (G_OBJECT (w->e_uid), "items");
	i = 0;
	found = FALSE;
	while (items)
	{
		if (info->uid == ((SystemAccount *) items->data)->id)
		{
			found = TRUE;
			break;
		}
		i++;
		items = g_list_next (items);
	}
	if (found)
	{
		gtk_option_menu_set_history (GTK_OPTION_MENU (w->e_uid), i);
		gtk_widget_hide (w->lbl_invalid_uid);
	}
	else
	{
		gtk_option_menu_set_history (GTK_OPTION_MENU (w->e_uid), 0);
		gtk_widget_show (w->lbl_invalid_uid);
	}

	menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (w->e_gid));
	items = (GList *) g_object_get_data (G_OBJECT (w->e_gid), "items");
	i = 0;
	found = FALSE;
	while (items)
	{
		if (info->gid == ((SystemAccount *) items->data)->id)
		{
			found = TRUE;
			break;
		}
		i++;
		items = g_list_next (items);
	}
	if (found)
	{
		gtk_option_menu_set_history (GTK_OPTION_MENU (w->e_gid), i);
		gtk_widget_hide (w->lbl_invalid_gid);
	}
	else
	{
		gtk_option_menu_set_history (GTK_OPTION_MENU (w->e_gid), 0);
		gtk_widget_show (w->lbl_invalid_gid);
	}


	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->bw_ul), (gdouble) info->bw_ul);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->bw_dl), (gdouble) info->bw_dl);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->quota_files), (gdouble) info->quota_files);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->quota_size), (gdouble) info->quota_size);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->ul_ratio), (gdouble) info->ul_ratio);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->dl_ratio), (gdouble) info->dl_ratio);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w->simsess), (gdouble) info->per_user_max);
	free_pwstruct (info);
   
	return TRUE;
}

gboolean usr_user_exists (const gchar *user)
{
	GError *err = NULL;

	if (!user || strlen (user) < 1)
		return FALSE;

	if (!pw_user_exists (user, &err))
	{
		if (err)
		{
			pur_log_wrn ("Error checking for user %s: %s", user, err->message);
			g_error_free (err);
		}
		return FALSE;
	}
	
	return TRUE;
}

GtkWidget *usr_init_usermanager_window (GtkWidget *parent_window)
{
	static GtkWidget *window = NULL;
	
	if (!window)
	{
		window = create_usermanager ();
		setup_treeview ();
		setup_optmenus ();
	}
	usr_fill_users_list ();
	select_first_user ();
	gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (parent_window));
	
	return window;
}

#if FALSE
gboolean usr_manager_check_prerequisites (void)
{
	static gboolean first_time = TRUE;
	gboolean need_group, need_user, ret;
	gchar *str;
	gint val;

	if (first_time == FALSE)
		return TRUE;
	pur_log_dbg ("usr_manager: First time run!");
	if (!g_file_test (cfg.pwfile, G_FILE_TEST_EXISTS))
	{
		/* No password-files found */
		ret = gui_display_confirmdialog (_("Create Password File?"),
						 _("The file containing the login-names for virtual users could not be found. You need this file in order to create and edit ftp-users.\n"
						   "Do you want to create this file?"),
						 _("_Yes, Create File"), NULL, MW("main_window"));
		if (ret == GTK_RESPONSE_YES)
		{
			if (misc_create_passwd_file () == FALSE)
			{
				/* Couldn't create password file. Report error to user */
				str = g_strdup_printf (_("There was an error when trying to create password file [%s].\n"
							 "The error reported was: '%s'"), cfg.pwfile, g_strerror (errno));
				gui_display_msgdialog (_("File Creation Failed"),
						       str, MSGDLG_TYPE_ERROR, MW("main_window"));
				return FALSE;
			}
		}
		else
			return FALSE;
	}
	else if ((val = access (cfg.pwfile, R_OK | W_OK)) != 0)
	{
		if (val == -1)
			pur_log_err ("access(%s, R_OK | W_OK) failed: %s", cfg.pwfile, g_strerror (errno));
		/* We didn't have permission to read/write to the password file */
		gui_display_msgdialog (_("Permission Denied"),
				       _("You don't have permission to read and write to the password file."
					 "This probably means that you have to run PureAdmin as root before beeing able to manage "
					 "your users."), MSGDLG_TYPE_ERROR, MW("main_window"));
		return FALSE;
	}
	need_group = need_user = FALSE;
	/* Check if there exist a dedicated ftpgroup and ftpuser */
	if (cfg.default_gid < 1)
		need_group = TRUE;
	if (cfg.default_uid < 1)
		need_user = TRUE;
	if (cfg.seen_usrdlg_welcome == FALSE && (need_user || need_group))
	{
		GError *err = NULL;
		ret = gui_display_confirmdialog (_("Create User and Group"), 
						 _("It seems that you do not have a dedicated ftp-user and -group to use with the FTP users.\n"
						   "Do you want to create ftpgroup and ftpuser and assign them as default for new users?"),
						 _("_Yes, Create Account"), NULL, MW("main_window"));
		if (ret == GTK_RESPONSE_YES)
		{
			ret = misc_create_system_account (need_user, need_group, &err);
			if (!ret)
			{
				gui_display_msgdialog (_("Account Creation Failed"), 
						       _("PureAdmin was unable to create the system-accounts. You will have to create them manually. "
							 "Use the appropriate tools for your distribution and read README.VirtualUsers distributed "
							 "with the PureFTPd package."),
						       MSGDLG_TYPE_ERROR, MW("main_window"));
				pur_log_err ("Error creating system accounts: %s", err->message);
				g_error_free (err);
				err = NULL;
				/* We want to show this dialog again, so we return here, before first_time is set to TRUE */
				return FALSE;
			}
		}
		if (need_group)
			cfg.default_gid = cfg_find_ftpgroup_gid ();
		if (need_user)
			cfg.default_uid = cfg_find_ftpuser_uid ();
		
		cfg.seen_usrdlg_welcome = TRUE;
	}
	first_time = FALSE;
	return TRUE;
}
#endif

gboolean usr_remove_user (const gchar *user, GError **err)
{
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
	
	return pw_remove_user (user, err);
}

/* Adds a user into the db.
 * arguments:
 *	user: The user to add
 *	passwd: The password for the user
 */
gboolean usr_add_user (const gchar *user, const gchar *passwd, GError **err)
{
	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);

	return pw_add_user (user, passwd, err);
}

gboolean usr_save_user_info (GError **err)
{
	PWInfo *i;
	gint ret;

	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
	
	i = usr_widgets_get_info ();
	if (i == NULL || !MISC_VALID_STRING (i->login))
	{
		pur_log_err ("Invalid information structure");
		g_set_error (err,
			     PUREADMIN_USERMANAGER_ERROR,
			     PA_USR_ERROR_FAILED,
			     "Couldn't get information from GUI");
		return FALSE;
	}
	ret = pw_set_user_information (i, err);
	free_pwstruct (i);
	return ret;
}

GList *usr_get_available_users (GError **err)
{
	g_return_val_if_fail (err == NULL || *err == NULL, NULL);

	return pw_get_available_users (err);
}


syntax highlighted by Code2HTML, v. 0.9.1