/*
  gyrus-admin.c

  GYRUS -- GNOME Cyrus Administrator. Administrator Class.
  
  Copyright (C) 2004-2005 Claudio Saavedra Valdés <csaavedra@alumnos.utalca.cl>

  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, see <http://www.gnu.org/licenses/>.
  
*/

#include <config.h>

#include <gtk/gtk.h>
#include <gio/gio.h>
#include <string.h>
#include <glib/gi18n.h>

#include "gyrus-main-app.h"
#include "gyrus-admin.h"
#include "gyrus-common.h"
#include "gyrus-session.h"
#include "gyrus-admin-private.h"
#include "gyrus-admin-mailbox.h"
#include "gyrus-admin-acl.h"

G_DEFINE_TYPE_WITH_PRIVATE (GyrusAdmin, gyrus_admin, GTK_TYPE_BOX)

/* #define DEBUG_PLAIN_CHANNEL */

enum {
	CONNECTED,
	DISCONNECTED,
	ACL_SELECTION_CHANGED,
	MAILBOX_SELECTION_CHANGED,
	SIGNAL_LAST
};

static gint admin_signals [SIGNAL_LAST];

static void gyrus_admin_finalize (GObject *object);

static void gyrus_admin_initialize_mailbox_tree_view (GyrusAdmin *admin, 
						      gboolean is_orphaned);
static void gyrus_admin_initialize_acl_tree_view (GyrusAdmin *admin);

GtkTreeModel * gyrus_admin_mailbox_tree_model_new (void);
GtkListStore * gyrus_admin_acl_tree_model_new (void);

void gyrus_admin_on_button_connect_clicked (GtkButton *button,
					    gpointer user_data);
/*void
gyrus_admin_on_entry_pass_activate (GtkEntry *entry,
gpointer user_data);*/
void
gyrus_admin_on_treeview_users_cursor_changed (GtkTreeView *treeview,
					      gpointer *data);

void
gyrus_admin_on_acl_selection_changed (GtkTreeSelection *selection,
				      gpointer user_data);

void
gyrus_admin_on_users_selection_changed (GtkTreeSelection *selection,
					gpointer user_data);

void gyrus_admin_on_renderer_toggled (GtkCellRendererToggle *renderer,
				      gchar *path,
				      gpointer user_data);

void gyrus_admin_on_acl_identifier_edited (GtkCellRendererText *cellrenderertext,
					   gchar *arg1,
					   gchar *arg2,
					   gpointer user_data);

gboolean
gyrus_admin_logout (GyrusAdmin *admin);

#define BUFFER_SIZE 10240

/*** private methods ****/

static void
gyrus_admin_class_init (GyrusAdminClass *class)
{
	GObjectClass *gobject_class = G_OBJECT_CLASS (class);

	GType selection_changed_types [1] = {
		G_TYPE_BOOLEAN
	};
	
	gyrus_admin_parent_class = g_type_class_peek_parent (class);

	gobject_class->finalize = gyrus_admin_finalize;
	
	admin_signals [CONNECTED] = 
		g_signal_newv ("connected", 
			       G_TYPE_FROM_CLASS (class),
			       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
			       NULL /* class closure */,
			       NULL /* accumulator */,
			       NULL /* accu_data */,
			       g_cclosure_marshal_VOID__VOID,
			       G_TYPE_NONE /* return_type */,
			       0     /* n_params */,
			       NULL  /* param_types */);

	admin_signals [DISCONNECTED] = 
		g_signal_newv ("disconnected", 
			       G_TYPE_FROM_CLASS (class),
			       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
			       NULL /* class closure */,
			       NULL /* accumulator */,
			       NULL /* accu_data */,
			       g_cclosure_marshal_VOID__VOID,
			       G_TYPE_NONE /* return_type */,
			       0     /* n_params */,
			       NULL  /* param_types */);

	admin_signals [ACL_SELECTION_CHANGED] = 
		g_signal_newv ("acl-selection-changed", 
			       G_TYPE_FROM_CLASS (class),
			       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
			       NULL /* class closure */,
			       NULL /* accumulator */,
			       NULL /* accu_data */,
			       g_cclosure_marshal_VOID__BOOLEAN,
			       G_TYPE_NONE /* return_type */,
			       1     /* n_params */,
			       selection_changed_types /* param_types */);

	admin_signals [MAILBOX_SELECTION_CHANGED] = 
		g_signal_newv ("mailbox-selection-changed", 
			       G_TYPE_FROM_CLASS (class),
			       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
			       NULL /* class closure */,
			       NULL /* accumulator */,
			       NULL /* accu_data */,
			       g_cclosure_marshal_VOID__BOOLEAN,
			       G_TYPE_NONE /* return_type */,
			       1     /* n_params */,
			       selection_changed_types /* param_types */);
}

static void
gyrus_admin_init_get_widgets (GyrusAdmin *admin)
{
	GyrusAdminPrivate *priv = admin->priv;
	GtkWidget *table;
	GtkBuilder *builder;

        builder = gtk_builder_new ();
        gtk_builder_add_from_resource (builder, "/org/gnome/gyrus/page.xml", NULL);
	
	priv->treeview_users = GTK_TREE_VIEW (gtk_builder_get_object (builder,"treeview_users"));
	priv->treeview_corrupt_mailbox = GTK_TREE_VIEW (gtk_builder_get_object (builder,"treeview_corrupt_mailbox"));
	priv->treeview_acl = GTK_TREE_VIEW (gtk_builder_get_object (builder,"treeview_acl"));
	priv->label_acl = GTK_WIDGET (gtk_builder_get_object (builder, "label_acl"));
	priv->scrolled_acl = GTK_WIDGET (gtk_builder_get_object (builder, "scrolled_acl"));

	priv->label_host = GTK_WIDGET (gtk_builder_get_object (builder, "label_host"));
	priv->label_user = GTK_WIDGET (gtk_builder_get_object (builder, "label_user"));
	priv->label_port = GTK_WIDGET (gtk_builder_get_object (builder, "label_port"));
	priv->button_connect = GTK_WIDGET (gtk_builder_get_object (builder, "button_connect"));

	priv->label_mailbox_owner = GTK_WIDGET (gtk_builder_get_object (builder, "label_mailbox_owner"));
	priv->label_quota_limit = GTK_WIDGET (gtk_builder_get_object (builder, "label_assigned"));
	priv->label_quota_free = GTK_WIDGET (gtk_builder_get_object (builder, "label_free"));

	priv->entry_quota_new = GTK_WIDGET (gtk_builder_get_object (builder, "entry_quota_new"));
	priv->button_quota_apply = GTK_WIDGET (gtk_builder_get_object (builder, "button_quota_apply"));

	priv->button_user_create = GTK_WIDGET (gtk_builder_get_object (builder, "button_create_user"));
	priv->button_user_remove = GTK_WIDGET (gtk_builder_get_object (builder, "button_remove_user"));
	priv->label_mailbox_name = GTK_WIDGET (gtk_builder_get_object (builder, "label_mailbox_name"));

	priv->expander_modify_quota = GTK_WIDGET (gtk_builder_get_object (builder, "expander_modify_quota"));
	priv->expander_modify_acl = GTK_WIDGET (gtk_builder_get_object (builder, "expander_modify_acl"));
	
	table = GTK_WIDGET (gtk_builder_get_object (builder , "table_page"));
	gtk_box_pack_start (GTK_BOX (admin), table, TRUE, TRUE, 0);

	g_object_unref (builder);

	admin->priv = priv;
}

static void
gyrus_admin_init_connect_signals (GyrusAdmin *admin)
{
	g_signal_connect (G_OBJECT (admin->priv->button_connect), "clicked",
			  G_CALLBACK (gyrus_admin_on_button_connect_clicked),
			  admin);

/*	g_signal_connect (G_OBJECT (admin->priv->entry_pass), "activate",
			  G_CALLBACK (gyrus_admin_on_entry_pass_activate),
			  admin->priv->button_connect);
*/
	g_signal_connect (G_OBJECT (admin->priv->button_quota_apply),
			  "clicked",
			  G_CALLBACK (gyrus_admin_mailbox_on_button_quota_apply_clicked),
			  admin);
	g_signal_connect (G_OBJECT (admin->priv->entry_quota_new), "activate",
			  G_CALLBACK (gyrus_admin_mailbox_on_entry_quota_new_activate),
			  admin->priv->button_quota_apply);

}


static void
gyrus_admin_init (GyrusAdmin *admin)
{
	admin->priv = gyrus_admin_get_instance_private (admin);
	admin->priv->session = NULL;
	admin->priv->buffer = NULL;
	gtk_orientable_set_orientation (GTK_ORIENTABLE (admin),
	                                GTK_ORIENTATION_VERTICAL);

	gyrus_admin_init_get_widgets (admin);
	gyrus_admin_initialize_mailbox_tree_view (admin, FALSE);
	gyrus_admin_initialize_acl_tree_view (admin);
	gyrus_admin_initialize_mailbox_tree_view (admin, TRUE);
	gyrus_admin_init_connect_signals (admin);
	gyrus_admin_mailbox_set_sensitive (admin, FALSE);
	gtk_widget_show (GTK_WIDGET (admin));
}

static void
gyrus_admin_finalize (GObject *object)
{
	GyrusAdmin *admin;
	g_return_if_fail (GYRUS_IS_ADMIN(object));
	admin = GYRUS_ADMIN (object);
	if (gyrus_admin_is_connected (admin))
		gyrus_admin_logout (admin);
	
	gyrus_session_free (admin->priv->session);

	if (admin->priv->buffer) {
		g_free (admin->priv->buffer);
		admin->priv->buffer = NULL;
	}

	G_OBJECT_CLASS (gyrus_admin_parent_class)->finalize (object);
}

GtkTreeModel *
gyrus_admin_mailbox_tree_model_new (void)
{
	GtkTreeModel *model;

	model = GTK_TREE_MODEL(	gtk_tree_store_new (COL_MAILBOX_NUMBER, 
						    G_TYPE_STRING, 
						    G_TYPE_STRING,
						    G_TYPE_STRING));
	
	return model;
}

gchar *
gyrus_admin_get_mailbox_from_list_message (gchar *msg)
{
	int k, large;
	gchar *mb_name;
	gchar *iterator = msg;
	for (k = 0; k < 4; k++) {
			while (*iterator != ' ')
				iterator++;
			iterator ++;
	}
	/* to remove the "\0" */
	large = strlen (iterator) - 1;
	
	if (*iterator == '\"') {
		iterator ++;
		large -= 2; /* remove the '"' */
	}
	mb_name = g_strndup (iterator, large);

	return mb_name;
}

static void
gyrus_admin_set_separator_char_auto (GyrusAdmin *admin)
{
	gchar **str_v;
	gchar *msg = g_strdup (". list \"\" \"\"\n");

	gyrus_admin_write_channel (admin, msg);
	g_free (msg);

	gyrus_admin_listen_channel (admin, &msg, NULL);
	str_v = g_strsplit (msg, " ", -1);
	g_free (msg);

	gyrus_admin_listen_channel (admin, &msg, NULL);

	g_free (admin->priv->session->sep_char);
	admin->priv->session->sep_char = g_strdup_printf ("%c", str_v[3][1]);

	g_free (msg);
	g_strfreev (str_v);
}

static void
gyrus_admin_get_users_list (GyrusAdmin *admin)
{
	GtkTreeStore *store;
	GtkTreeStore *store_corrupt;
	gchar *msg;
	gchar **current_mailbox;
	gboolean success;
	gint depth, old_depth = 1;
	GtkTreeIter iter_new, iter_parent, iter_child, iter_corrupt;
	gboolean is_valid;
        gint n_users, n_orphaned;
        GtkTreeViewColumn *column;
	GyrusImapStatus status;
	gchar *mb_name;
	const gchar *sep_char = gyrus_admin_get_separator_char (admin);
	
	store =	GTK_TREE_STORE (gtk_tree_view_get_model
				(admin->priv->treeview_users));
	store_corrupt = GTK_TREE_STORE (gtk_tree_view_get_model 
					(admin->priv->treeview_corrupt_mailbox));

	gtk_tree_store_clear (store);
	gtk_tree_store_clear (store_corrupt);

	msg = g_strdup (". list * *\n");
	success = gyrus_admin_write_channel (admin, msg);
	g_free (msg);
	g_return_if_fail (success == TRUE);

	while ((status = gyrus_admin_listen_channel (admin, &msg, NULL)) ==
	       GYRUS_IMAP_STATUS_LIST) {
		mb_name = gyrus_admin_get_mailbox_from_list_message (msg);

		current_mailbox = g_strsplit (mb_name, 
					      sep_char, 
					      -1);

		depth = 0;

		/* this mailbox is fucked up */
		if (current_mailbox [1] == NULL) {
			/* add it somewhere */
			gtk_tree_store_append (store_corrupt, &iter_corrupt, NULL);
			gtk_tree_store_set (store_corrupt, &iter_corrupt,
					    COL_MAILBOX_ICON, "folder",
					    COL_MAILBOX_NAME, mb_name,
					    -1);
			g_strfreev (current_mailbox);
			g_free (msg);
			g_free (mb_name);
			continue;
		}

		is_valid = FALSE;
			
		while (current_mailbox [depth + 1] != NULL)
			depth ++;
			
		/* current folder is at same level than previous one */
		if (depth == old_depth) {
			gtk_tree_store_append (store, &iter_child,
 					       (depth == 1 ?
						NULL : &iter_parent));
			is_valid = TRUE;
		}
			
		/* current folder is child of the previous one */
		else if (depth == old_depth + 1) {
			gtk_tree_store_append (store, &iter_new, &iter_child);
			iter_parent = iter_child;
			iter_child = iter_new;
			old_depth ++;
			is_valid = TRUE;
		}
		/* current folder is at a parent level of the previous one */
		else if (depth < old_depth) {
			while (depth < old_depth) {
				gtk_tree_model_iter_parent (GTK_TREE_MODEL
							    (store),
							    &iter_new, &iter_child);
				iter_child = iter_new;
				old_depth --;
			}
			gtk_tree_model_iter_parent (GTK_TREE_MODEL (store),
						    &iter_parent, &iter_child);
			gtk_tree_store_append (store, &iter_child,
					       (depth == 1 ?
						NULL : &iter_parent));
			is_valid = TRUE;
		}

		if (is_valid) {
			gtk_tree_store_set (store, &iter_child,
					    COL_MAILBOX_ICON, "folder",
					    COL_MAILBOX_BASENAME, current_mailbox [depth],
					    COL_MAILBOX_NAME, mb_name,
					    -1);
			old_depth = depth;
		}
		else {
			gtk_tree_store_append (store_corrupt, &iter_corrupt, NULL);
			gtk_tree_store_set (store_corrupt, &iter_corrupt,
					    COL_MAILBOX_ICON, "folder",
					    COL_MAILBOX_NAME, mb_name,
					    -1);
		}
		g_strfreev (current_mailbox);
		g_free (msg);
		g_free (mb_name);
	}

	g_free (msg);

	if (status == GYRUS_IMAP_STATUS_BYE) {
		gyrus_admin_logged_out (admin);
		return;
	}
	
	/* get the number of users in the tree */
	n_users = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(store), NULL);
	column = gtk_tree_view_get_column (GTK_TREE_VIEW(admin->priv->treeview_users), 0);
	msg = g_strdup_printf (_("Users (%d)"), n_users);
	gtk_tree_view_column_set_title (column, msg);
	g_free (msg);
	
	n_orphaned = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(store_corrupt), NULL);
	column = gtk_tree_view_get_column (GTK_TREE_VIEW(admin->priv->treeview_corrupt_mailbox), 0);
	msg = g_strdup_printf (_("Orphaned mailboxes (%d)"), n_orphaned);
	gtk_tree_view_column_set_title (column, msg);
	g_free (msg);
}

static gboolean
gyrus_admin_on_treeview_focused (GtkWidget *widget,
				 GtkDirectionType arg1,
				 gpointer data)
{
	GyrusAdmin *admin = GYRUS_ADMIN (data);
	GtkTreeSelection *selection;

	g_object_set_data (G_OBJECT (admin), "selected-treeview", widget);

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));

	gyrus_admin_on_users_selection_changed (selection, data);
	
	return FALSE;
}

static void
gyrus_admin_initialize_mailbox_tree_view (GyrusAdmin *admin, 
					  gboolean is_orphaned)
{
	GtkTreeView *treeview;
	GtkTreeModel *model;
	GtkTreeViewColumn* column;
	GtkCellRenderer *renderer;
	GtkTreeSelection *selection;

	g_return_if_fail (GYRUS_IS_ADMIN (admin));
	
	if (is_orphaned) {
		treeview = admin->priv->treeview_corrupt_mailbox;
	} else {
		treeview = admin->priv->treeview_users;
	}
	
	gtk_tree_view_set_reorderable  (treeview, FALSE);

	column = gtk_tree_view_column_new ();
	gtk_tree_view_column_set_title (column, 
					is_orphaned ? _("Orphaned mailboxes") : _("Users"));
	renderer = gtk_cell_renderer_pixbuf_new ();
	gtk_tree_view_column_pack_start (column, renderer, FALSE);
	g_object_set (G_OBJECT (renderer),
	              "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR,
	              NULL);
	
	gtk_tree_view_column_set_attributes (column, renderer,
	                                     "icon-name", COL_MAILBOX_ICON,
	                                     NULL);
	
	renderer = gtk_cell_renderer_text_new ();
	gtk_tree_view_column_pack_start (column, renderer, TRUE);
	gtk_tree_view_column_set_attributes (column, renderer,
					     "text", is_orphaned ? COL_MAILBOX_NAME : COL_MAILBOX_BASENAME,
					     NULL);

	gtk_tree_view_append_column (treeview, column);

	model = gyrus_admin_mailbox_tree_model_new ();
	gtk_tree_view_set_model (treeview, model);

	selection = gtk_tree_view_get_selection (treeview);
	g_signal_connect (G_OBJECT (selection), "changed", 
			  G_CALLBACK (gyrus_admin_on_users_selection_changed), admin);
			  
	g_signal_connect (G_OBJECT (treeview), "focus-in-event", 
			  G_CALLBACK (gyrus_admin_on_treeview_focused), admin);
}

GtkListStore *
gyrus_admin_acl_tree_model_new (void)
{
	GtkListStore *model;
	GtkTreeSortable *sortable;

	model = gtk_list_store_new (COL_ACL_NUMBER, 
				    G_TYPE_STRING,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,	
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN,
				    G_TYPE_BOOLEAN);
	
	sortable = GTK_TREE_SORTABLE (model);
	gtk_tree_sortable_set_sort_column_id (sortable,
					      COL_ACL_IDENTIFIER,
					      GTK_SORT_ASCENDING);

	return model;
}


static void
gyrus_admin_initialize_acl_tree_view (GyrusAdmin *admin)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkListStore *model;
	GtkTreeView *view;
	gint i;
	gchar *perms[9] = {
		_("lookup"),
		_("read"),
		_("seen"),
		_("write"),
		_("insert"),
		_("post"),
		_("create"),
		_("delete"),
		_("admin")
	};

	g_return_if_fail (GYRUS_IS_ADMIN (admin));

	view = admin->priv->treeview_acl;
	
	column = gtk_tree_view_column_new ();
	gtk_tree_view_column_set_title (column, _("Identifier"));
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_append_column (view, column);

	renderer = gtk_cell_renderer_text_new ();
	g_object_set (renderer, "editable", TRUE, NULL);
	g_signal_connect (G_OBJECT(renderer), "edited",
			  G_CALLBACK (gyrus_admin_on_acl_identifier_edited), admin);
	
	gtk_tree_view_column_pack_start (column, renderer, TRUE);
	gtk_tree_view_column_set_attributes (column, renderer,
					     "text", COL_ACL_IDENTIFIER,
					     NULL);

	g_object_set_data (G_OBJECT (view),
			   "column-identifier", column);

	/* create ACLs columns */
	for (i = 0; i < 9; i++) {
		column = gtk_tree_view_column_new ();

		/* This may be obvlious or maybe not. We need to know wich
		   permission correspond to each column, so we can later
		   recover it in a clean way.
		*/
		g_object_set_data (G_OBJECT (column), "permission", GINT_TO_POINTER (COL_ACL_RIGHT_L + i));
		g_object_set_data (G_OBJECT (column), "parent-admin", admin);
		
		gtk_tree_view_column_set_title (column, perms[i]);
		gtk_tree_view_column_set_resizable(column, TRUE);
		gtk_tree_view_append_column (view, column);
		
		renderer = gtk_cell_renderer_toggle_new ();
		gtk_cell_renderer_set_fixed_size (renderer, 30, -1);
		gtk_tree_view_column_pack_start (column, renderer, TRUE);
		gtk_tree_view_column_set_attributes (column, renderer, 
						     "active", i+1,
						     NULL);

		g_signal_connect (G_OBJECT (renderer), "toggled",
				  G_CALLBACK (gyrus_admin_on_renderer_toggled),
				  column);
	}

	selection = gtk_tree_view_get_selection (view);
	g_signal_connect (G_OBJECT (selection), "changed",
			  G_CALLBACK (gyrus_admin_on_acl_selection_changed),
			  admin);
	
/*	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
	gtk_tree_selection_set_select_function (selection,
						gyrus_acl_selection_func,
						admin->button_acl_remove,
						NULL);
*/
	model = gyrus_admin_acl_tree_model_new ();
	gtk_tree_view_set_model (view, GTK_TREE_MODEL (model));
}

static GSocketClient *
gyrus_admin_create_socket_from_session (GyrusAdmin *admin, GyrusSession *session)
{
	GSocketClient *sock;
	GSocketConnectable *connectable;
	gchar *msg;

	g_return_val_if_fail (session, NULL);

	sock = g_socket_client_new ();
	if (sock == NULL) {
		msg = g_strdup (_("Couldn't create the client socket."));
		gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR, msg);
		g_free (msg);
		return NULL;
	}

	connectable = g_network_address_parse (session->host, session->port, NULL);
	if (connectable == NULL) {
		msg = g_strdup (_("Couldn't parse the server address."));
		gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR, msg);
		g_free (msg);
		g_object_unref (sock);
		return NULL;
	}

	admin->priv->connection = g_socket_client_connect (sock, connectable, NULL, NULL);
	if (admin->priv->connection == NULL) {
		msg = g_strdup_printf (_("Could not connect to %s, port %d."),
				       session->host, session->port);
		gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR, msg);
		g_free (msg);
		g_object_unref (sock);
		return NULL;
	}
	g_object_unref (connectable);

	return sock;
}

static gchar *
socket_readline (GyrusAdmin *admin, gsize *len)
{
	GInputStream *stream;
	gchar *retval;
	gchar **toks;
	gchar *n_buffer;
	stream = g_io_stream_get_input_stream (G_IO_STREAM (admin->priv->connection));

	if (admin->priv->buffer == NULL) {
		admin->priv->buffer = g_malloc0 (BUFFER_SIZE * sizeof (gchar));
		g_input_stream_read (stream, admin->priv->buffer,
				     BUFFER_SIZE - 1, NULL, NULL);
	}

	toks = g_strsplit (admin->priv->buffer, "\n", 2);
	g_free (admin->priv->buffer);

	/* "Someth". We need to feed the buffer. */
	while (toks[0] != NULL && toks[1] == NULL) {
		admin->priv->buffer = g_malloc0 (BUFFER_SIZE * sizeof (gchar));
		g_input_stream_read (stream,
				     admin->priv->buffer,
				     BUFFER_SIZE - 1,
				     NULL, NULL);

		n_buffer = g_strconcat (toks[0], admin->priv->buffer, NULL);
		g_free (admin->priv->buffer);
		g_strfreev (toks);
		toks = g_strsplit (n_buffer, "\n", 2);
		g_free (n_buffer);
	}

	retval = toks[0];
	admin->priv->buffer = toks[1];
	g_free (toks);

	if (admin->priv->buffer && strcmp (admin->priv->buffer, "") == 0) {
		g_free (admin->priv->buffer);
		admin->priv->buffer = NULL;
	}

	*len = strlen (retval);

	return retval;
}

/* Allocates @msg_len bytes of memory to store the message.
   Returns the kind of message read */ 
GyrusImapStatus
gyrus_admin_listen_channel (GyrusAdmin *admin, gchar **message, gint *msg_len)
{
	gsize bytes_read;
	gchar **tokens = NULL;
	GyrusImapStatus imap_status;

	*message = NULL;

	/* Trick to ignore the ALERTs */

	do {
		g_free (*message);
		g_strfreev (tokens);

		imap_status = GYRUS_IMAP_STATUS_OK;
		*message = socket_readline (admin, &bytes_read);

#ifdef DEBUG_PLAIN_CHANNEL
		g_print ("read:  %s", *message);
#endif
		tokens = g_strsplit (*message, " ", 0);
		if (msg_len != NULL)
			*msg_len = bytes_read;
		
		/* Displays a popup with the alert. As the user is not supposed 
		   to decide if displays or not the alert, we do it always */
		if (g_ascii_strcasecmp (tokens [2], "[ALERT]") == 0) {
			gyrus_common_show_message (NULL, GTK_MESSAGE_INFO, 
						   *message + strlen ("* OK "));

		}
	} while (g_ascii_strcasecmp (tokens [2], "[ALERT]") == 0);
	
	if (g_ascii_strcasecmp (tokens[1], "BYE") == 0)
		imap_status = GYRUS_IMAP_STATUS_BYE;
	else if (g_ascii_strcasecmp (tokens[1], "OK") == 0)
		imap_status = GYRUS_IMAP_STATUS_OK;
	else if (g_ascii_strcasecmp (tokens[1], "BAD") == 0)
		imap_status = GYRUS_IMAP_STATUS_BAD;
	else if (g_ascii_strcasecmp (tokens[1], "NO") == 0)
		imap_status = GYRUS_IMAP_STATUS_NO;
	else if (g_ascii_strcasecmp (tokens [1], "LIST") == 0)
		imap_status = GYRUS_IMAP_STATUS_LIST;
	
	g_strfreev (tokens);

	return imap_status;
}

gboolean
gyrus_admin_write_channel (GyrusAdmin *admin, gchar *message)
{
	GOutputStream *stream;
	guint msg_len;
	GError *error = NULL;

	msg_len = g_utf8_strlen (message, -1);
	stream = g_io_stream_get_output_stream (G_IO_STREAM (admin->priv->connection));
	g_output_stream_write (stream, message, msg_len, NULL, &error);
#ifdef DEBUG_PLAIN_CHANNEL
	g_print ("written: %s", message);
#endif
	if (error) {
		g_error_free (error);
		return FALSE;
	} else {
		return TRUE;
	}
}

gboolean
gyrus_admin_logout (GyrusAdmin *admin)
{
	gchar *msg = g_strdup (". logout\n");
	GyrusImapStatus status;
	
	gyrus_admin_write_channel (admin, msg);
	g_free (msg);

	status = gyrus_admin_listen_channel (admin, &msg, NULL);

	if (status == GYRUS_IMAP_STATUS_BYE) {
		g_io_stream_close (G_IO_STREAM (admin->priv->connection), NULL, NULL);
		g_object_unref (admin->priv->connection);
		admin->priv->connection = NULL;

		g_object_unref (admin->priv->tcp_socket);
		admin->priv->tcp_socket = NULL;

		g_free (admin->priv->buffer);
		admin->priv->buffer = NULL;
		g_free (msg);
	}

	return (status == GYRUS_IMAP_STATUS_BYE);
}

static void
gyrus_admin_clean_mailbox_treeview (GtkTreeView *treeview, const gchar *title)
{
	GtkTreeStore *store;
	GtkTreeViewColumn *column;
	
	g_return_if_fail (GTK_IS_TREE_VIEW (treeview));

	store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
	gtk_tree_store_clear (store);

	column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
        gtk_tree_view_column_set_title (column, title);
	
}

void
gyrus_admin_logged_out (GyrusAdmin *admin)
{
	gtk_button_set_label (GTK_BUTTON (admin->priv->button_connect),
			      "gtk-connect");

	gyrus_admin_clean_mailbox_treeview (GTK_TREE_VIEW (admin->priv->treeview_users), 
					    _("Users"));
	gyrus_admin_clean_mailbox_treeview (GTK_TREE_VIEW (admin->priv->treeview_corrupt_mailbox), 
					    _("Orphaned mailboxes"));

	gyrus_admin_mailbox_clear_info (admin);
	gyrus_admin_mailbox_set_sensitive (admin, FALSE);
	
	g_signal_emit (admin, admin_signals [ACL_SELECTION_CHANGED],
		       0,
		       NULL);
	g_signal_emit (admin, admin_signals [DISCONNECTED],
		       0, NULL);
	
}

/* This function was taken from camel.
   Copyright 2000 Ximian, Inc. (www.ximian.com)
*/
/**
 * imap_quote_string:
 * @str: the string to quote, which must not contain CR or LF
 *
 * Return value: an IMAP "quoted" corresponding to the string, which
 * the caller must free.
 **/
static char *
imap_quote_string (const char *str)
{
	const char *p;
	char *quoted, *q;
	int len;
	
	g_assert (strchr (str, '\r') == NULL);
	
	len = strlen (str);
	p = str;
	while ((p = strpbrk (p, "\"\\"))) {
		len++;
		p++;
	}
	
	quoted = q = g_malloc (len + 3);
	*q++ = '"';
	for (p = str; *p; ) {
		if (strchr ("\"\\", *p))
			*q++ = '\\';
		*q++ = *p++;
	}
	*q++ = '"';
	*q = '\0';
	
	return quoted;
}

/* returns whether the conection can be established or not. */
static GyrusAdminLoginError
gyrus_admin_login (GyrusAdmin *admin)
{
	GSocketClient *socket;
	gchar *msg;
	gchar *q_password;
	GyrusImapStatus status;
	GyrusAdminLoginError error = GYRUS_ADMIN_LOGIN_OK;
	socket = gyrus_admin_create_socket_from_session (admin, admin->priv->session);
	if (!socket)
		return GYRUS_ADMIN_LOGIN_NO_HOST;
	
	admin->priv->tcp_socket = socket;

	status = gyrus_admin_listen_channel (admin, &msg, NULL);
	g_free (msg);

	g_return_val_if_fail (status == GYRUS_IMAP_STATUS_OK, FALSE);

	q_password = imap_quote_string (gyrus_admin_get_current_passwd (admin));
	msg = g_strdup_printf (". login \"%s\" %s\n",
			       gyrus_admin_get_current_user (admin),
			       q_password);
	g_free (q_password);
	gyrus_admin_write_channel (admin, msg);
	g_free (msg);

	status = gyrus_admin_listen_channel (admin, &msg, NULL);
	g_free (msg);

	switch (status) {
	case GYRUS_IMAP_STATUS_BAD: {
		error = GYRUS_ADMIN_LOGIN_NO_PASS;
		break;
	}
	case GYRUS_IMAP_STATUS_NO: {
		error = GYRUS_ADMIN_LOGIN_BAD_LOGIN;
		break;
	}
	case GYRUS_IMAP_STATUS_OK: {
		    error = GYRUS_ADMIN_LOGIN_OK;
		    break;
	}
	case GYRUS_IMAP_STATUS_BYE:
	case GYRUS_IMAP_STATUS_LIST:
		break;
	default:
		break;
	}
	
	return error;
}

static void
gyrus_admin_post_login (GyrusAdmin *admin)
{
	if (strcmp (gyrus_admin_get_separator_char (admin), "auto") == 0)
		gyrus_admin_set_separator_char_auto (admin);

	g_signal_emit (admin, admin_signals [CONNECTED],
		       0,
		       NULL);
	
	gyrus_admin_get_users_list (admin);
}

static void
gyrus_admin_pre_logout (GyrusAdmin *admin)
{
	gyrus_admin_logout (admin);
	gyrus_admin_logged_out (admin);
}

static void
gyrus_admin_pre_login (GyrusAdmin *admin)
{
	GyrusAdminLoginError error;
	gboolean keep_asking = TRUE;
	
	while (keep_asking) {
		if (admin->priv->session->passwd) {
			g_free (admin->priv->session->passwd);
			admin->priv->session->passwd = NULL;
		}
		
		admin->priv->session->passwd = gyrus_dialog_password_new ();
		if (admin->priv->session->passwd == NULL)
			/* user canceled */
			keep_asking = FALSE;
		else {
			error = gyrus_admin_login (admin);
			
			if (error == GYRUS_ADMIN_LOGIN_NO_PASS) {
				gyrus_admin_logout (admin);
				gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR,
							   _("Unable to connect with empty "
							     "passwords. Please introduce your "
							     "password."));
			}
			else if (error == GYRUS_ADMIN_LOGIN_BAD_LOGIN) {
				gyrus_admin_logout (admin);
				gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR,
							   _("Incorrect login/password"));
			}
			else if (error == GYRUS_ADMIN_LOGIN_NO_HOST) {
				/* do something useful here */
			}
			else {
				gtk_button_set_label (GTK_BUTTON (admin->priv->button_connect),
						      "gtk-disconnect");
				gyrus_admin_post_login (admin);
				/* correctly logged in */
				keep_asking = FALSE;
				return;
			}
		}
	}
}


/*** Public Methods ****/
static gboolean
gyrus_admin_select_foreach_func (GtkTreeModel *model, GtkTreePath *path,
				 GtkTreeIter *iter, gpointer data)
{
	GyrusAdmin *admin = GYRUS_ADMIN (data);
	
	gchar *this_mailbox;
	gtk_tree_model_get (model, iter,
			    COL_MAILBOX_NAME, &this_mailbox,
			    -1);

	if (!strcmp (gtk_label_get_text (GTK_LABEL (admin->priv->label_mailbox_name)),
		     this_mailbox)) {
		GtkTreeSelection *selection =
			gtk_tree_view_get_selection (admin->priv->treeview_users);
		gtk_tree_view_expand_to_path (admin->priv->treeview_users, path);

		gtk_tree_selection_select_iter (selection, iter);
		g_free (this_mailbox);
		return TRUE;
	}
	g_free (this_mailbox);
	return FALSE;
}

void
gyrus_admin_select_mailbox (GyrusAdmin *admin,
			    const gchar *mailbox)
{
	GtkTreeModel *model =
		gtk_tree_view_get_model (admin->priv->treeview_users);
	
	gtk_tree_model_foreach (model, gyrus_admin_select_foreach_func,
				admin);
	
}

/* return the path of the currently selected mailbox in the treeview of
 users
*/
gchar *
gyrus_admin_get_selected_mailbox (GyrusAdmin *admin)
{
	GtkTreeSelection *selection;
	GtkTreeView *treeview;
	GtkTreeModel *model;
	GtkTreeIter iter;
	
	gchar *current_mailbox = NULL;
	
	treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT (admin), 
						     "selected-treeview"));
	/* case we haven't already set it */
	if (treeview == NULL)
		return NULL;

	selection = gtk_tree_view_get_selection	(treeview);

	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {

		gtk_tree_model_get (model, &iter,
				    COL_MAILBOX_NAME, &current_mailbox,
				    -1);
	}
	return current_mailbox;
}

gboolean
gyrus_admin_is_connected (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), FALSE);
	g_return_val_if_fail (admin != NULL, FALSE);
	return (admin->priv->connection != NULL);
}

const gchar*
gyrus_admin_get_current_host (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);
	g_return_val_if_fail (admin->priv && admin->priv->session, NULL);

	return admin->priv->session->host;
}

const gchar*
gyrus_admin_get_current_user (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);
	g_return_val_if_fail (admin->priv && admin->priv->session, NULL);

	return admin->priv->session->user;
}

gint
gyrus_admin_get_current_port (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), -1);
	g_return_val_if_fail (admin->priv && admin->priv->session, -1);

	return admin->priv->session->port;
}

const gchar*
gyrus_admin_get_current_session_name (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);
	g_return_val_if_fail (admin->priv && admin->priv->session, NULL);

	return admin->priv->session->name;
}

const gchar*
gyrus_admin_get_current_passwd (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);
	g_return_val_if_fail (admin->priv && admin->priv->session, NULL);

	return admin->priv->session->passwd;
}

const gchar*
gyrus_admin_get_separator_char (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);
	g_return_val_if_fail (admin->priv && admin->priv->session, NULL);

	return admin->priv->session->sep_char;
}

gboolean
gyrus_admin_has_current_acl_access (GyrusAdmin *admin)
{
	gboolean is_visible;
	g_object_get (G_OBJECT (admin->priv->label_acl),
		      "visible", &is_visible,
		      NULL);

	return !is_visible;
}

static void
gyrus_admin_load_session_info (GyrusAdmin *admin, GyrusSession *session)
{
	gchar *port;

	g_return_if_fail (GYRUS_IS_ADMIN (admin));

	if (session == NULL)
		return;
	
	port = g_strdup_printf ("%d", session->port);
	
	if (!admin->priv->session) {
		admin->priv->session = g_new0 (GyrusSession, 1);
	}
	else {
		g_free (admin->priv->session->host);
		g_free (admin->priv->session->user);
		g_free (admin->priv->session->name);
	}

	/** store in the private structure GyrusSession **/
	
	admin->priv->session->host = g_strdup (session->host);
	admin->priv->session->user = g_strdup (session->user);
	admin->priv->session->name = g_strdup (session->name);
	admin->priv->session->port = session->port;
	admin->priv->session->sep_char = g_strdup (session->sep_char);

	/* set the interface */
	gtk_label_set_label (GTK_LABEL (admin->priv->label_host),
			    session->host);
	gtk_label_set_label (GTK_LABEL (admin->priv->label_port), port);
	gtk_label_set_label (GTK_LABEL (admin->priv->label_user),
			     session->user);

	g_free (port);
}

void
gyrus_admin_refresh_users_list (GyrusAdmin *admin)
{
	gyrus_admin_get_users_list (admin);
}

GtkTreeView *
gyrus_admin_get_users_treeview (GyrusAdmin *admin)
{
	g_return_val_if_fail (GYRUS_IS_ADMIN (admin), NULL);

	return g_object_ref (admin->priv->treeview_users);
}

GtkWidget *
gyrus_admin_new (GyrusSession *session)
{
	GyrusAdmin *admin;
	admin = g_object_new (GYRUS_TYPE_ADMIN, NULL);
	gyrus_admin_load_session_info (GYRUS_ADMIN (admin), session);
/*	gtk_widget_grab_focus (GTK_WIDGET (admin->priv->entry_pass));*/
	return GTK_WIDGET (admin);
}

/** callbacks ***/

void
gyrus_admin_on_button_connect_clicked (GtkButton *button,
				       gpointer user_data)
{
	GyrusAdmin *admin;

	g_return_if_fail (GYRUS_ADMIN (user_data));

	admin = GYRUS_ADMIN (user_data);

	if (gyrus_admin_is_connected (admin)) {
		gyrus_admin_pre_logout (admin);
	} else {
		gyrus_admin_pre_login (admin);
	}
}
/*
void
gyrus_admin_on_entry_pass_activate (GtkEntry *entry,
				    gpointer user_data)
{
	GtkButton *button = GTK_BUTTON (user_data);
	gtk_button_clicked (button);
}
*/
void
gyrus_admin_on_acl_selection_changed (GtkTreeSelection *selection,
				      gpointer user_data)

{
	GyrusAdmin *admin = GYRUS_ADMIN (user_data);
	GtkTreeModel *model;
	GtkTreeIter  iter;

	g_signal_emit (admin, admin_signals [ACL_SELECTION_CHANGED],
		       0,
		       gtk_tree_selection_get_selected (selection, &model, &iter),
		       NULL);
}

void 
gyrus_admin_on_users_selection_changed (GtkTreeSelection *selection,
					gpointer          user_data) 
{

	GtkTreeIter iter;
	GtkTreeModel *model;
	gchar *mailbox_path;
	gchar **tokens;
	gboolean is_selected;
	GyrusAdmin *admin = GYRUS_ADMIN (user_data);

	if (!gyrus_admin_is_connected (admin))
	        return;

	is_selected = gtk_tree_selection_get_selected (selection, &model, &iter);
	if (is_selected)
	{
		gtk_tree_model_get (model, &iter,
				    COL_MAILBOX_NAME, &mailbox_path,
				    -1);

		tokens = g_strsplit (mailbox_path, gyrus_admin_get_separator_char (admin), 3);
		gyrus_admin_mailbox_show_info (admin, tokens[1],
					       mailbox_path);
		g_strfreev (tokens);
		g_free (mailbox_path);
		gyrus_admin_mailbox_set_sensitive (admin, TRUE);
		
	}
	else {
		gyrus_admin_mailbox_clear_info (admin);
		gyrus_admin_mailbox_set_sensitive (admin, FALSE);
	}

	g_signal_emit (admin, admin_signals [MAILBOX_SELECTION_CHANGED],
		       0,
		       is_selected,
		       NULL);	
}

/***************************************
+ On editing permissions.
*
*
*/

void
gyrus_admin_on_renderer_toggled (GtkCellRendererToggle *renderer,
				 gchar *path,
				 gpointer user_data)
{
	GyrusAdmin *admin;
	GyrusColumnAcl col;
	GtkListStore *store;
	GtkTreeIter iter;
	gboolean has_permission;
	GtkTreeViewColumn *column;
	const gchar *permissions = "lrswipcda";
	gchar *user;
	gchar *perm;
	gchar *mailbox;
	gchar *error;

	g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (user_data));

	column = GTK_TREE_VIEW_COLUMN (user_data);

	admin = g_object_get_data (G_OBJECT (column),
				   "parent-admin");
	col = GPOINTER_TO_INT (
		g_object_get_data (G_OBJECT (column),
				   "permission"));

	store = GTK_LIST_STORE (
		gtk_tree_view_get_model (admin->priv->treeview_acl));
	gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store),
					     &iter, path);
	
	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
			    COL_ACL_IDENTIFIER, &user,
			    col, &has_permission,
			    -1);
	
	perm = g_strdup_printf ("%c%c",
				(has_permission)? '-' : '+',
				permissions[col - 1]);

	mailbox = g_strdup (gtk_label_get_text
			    (GTK_LABEL (admin->priv->label_mailbox_name)));
	
	if (gyrus_admin_acl_set_entry (admin, mailbox, user, perm,
				       &error)) {
		gtk_list_store_set (store, &iter, col, !has_permission, -1);
		
	} else {
		gchar *display_error = g_strconcat (_("Could not change permission. Server error: "),
						    error, NULL);
		gyrus_common_show_message (NULL, GTK_MESSAGE_ERROR, display_error);
		g_free (display_error);
		g_free (error);
	}
	
	g_free (user);
	g_free (perm);
	g_free (mailbox);
}

static gboolean
gyrus_admin_acl_eliminate_model_entry (GtkTreeModel *model,
				       GtkTreePath *path,
				       GtkTreeIter *iter,
				       gpointer data)
{
	gchar *target_identifier = (gchar *)data;
	gchar *this_identifier;
	gtk_tree_model_get (model, iter,
			    COL_ACL_IDENTIFIER, &this_identifier,
			    -1);
	if (strcmp (this_identifier, target_identifier) == 0) {
		gtk_list_store_remove (GTK_LIST_STORE (model), iter);
		g_free (this_identifier);
		return TRUE;
	}

	g_free (this_identifier);
	return FALSE;
}

static gboolean
gyrus_admin_ask_user_if_overwrite (GyrusAdmin *admin,
				   gchar *entry_name)
{
	GtkWidget *dialog;
	int result;

	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
					 GTK_MESSAGE_QUESTION,
					 GTK_BUTTONS_YES_NO,
					 _("An entry called '%s' already exists. Overwrite it?"),
					 entry_name);
	
	result = gtk_dialog_run (GTK_DIALOG (dialog));
	gtk_widget_destroy (dialog);
	
	return (result == GTK_RESPONSE_YES);
}

void
gyrus_admin_on_acl_identifier_edited (GtkCellRendererText *cellrenderertext,
				      gchar *path_string,
				      gchar *newname,
				      gpointer user_data)
{
	GtkTreeIter iter;
	GyrusImapAclEntry *entry;
	gboolean duplicated = FALSE;
	GtkTreeModel *model;
	gchar *oldname;
	gchar *error;
	gchar *mailbox;
	GList *acl, *l_iter;
	gchar *rights;
	GyrusAdmin *admin = GYRUS_ADMIN (user_data);
	
	model = gtk_tree_view_get_model (admin->priv->treeview_acl);
	if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string)) {
		return;
	}

	gtk_tree_model_get (model, &iter,
			    COL_ACL_IDENTIFIER, &oldname,
			    -1);

	/* If oldname == newname, there is nothing to rename */
	if (strcmp (oldname, newname) == 0) {
		g_free (oldname);
		return;
	}

	mailbox = g_strdup (gtk_label_get_text
				   (GTK_LABEL (admin->priv->label_mailbox_name)));
	acl = gyrus_admin_acl_get (admin, mailbox, NULL);

	/* check it the new name already exists. */
	l_iter = acl;
	while (l_iter != NULL && !duplicated) {
		entry = GYRUS_IMAP_ACL_ENTRY (l_iter->data);
		if (strcmp (entry->identifier, newname) == 0)
			duplicated = TRUE;
		l_iter = g_list_next (l_iter);
	}

	/* Obtain the rights of the entry to be renamed */
	rights = NULL;
	l_iter = acl;
	while (l_iter != NULL && rights == NULL) {
		entry = GYRUS_IMAP_ACL_ENTRY (l_iter->data);
		if (strcmp (entry->identifier, oldname) == 0)
			rights = g_strdup (entry->rights);
		l_iter = g_list_next (l_iter);
	}

	if (!duplicated) {
		if (!gyrus_admin_acl_set_entry (admin, mailbox,
						newname, rights, &error)) {
			g_warning ("%s", error);
			g_free (error);
		} else if (!gyrus_admin_acl_delete_entry (admin, mailbox,
							  oldname, &error)) {
			g_warning ("%s", error);
			g_free (error);
		} else {
			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
					    COL_ACL_IDENTIFIER, newname,
					    -1);
		}
	} else if (gyrus_admin_ask_user_if_overwrite (admin, newname)) {
		/* DELETE EXISTING ONE */
		if (!gyrus_admin_acl_delete_entry (admin, mailbox,
						   newname, &error)) {
			g_warning ("%s", error);
			g_free (error);
		} else if (!gyrus_admin_acl_set_entry (admin, mailbox,
						       newname, rights,
						       &error)) {
			g_warning ("%s", error);
			g_free (error);
		} else if (!gyrus_admin_acl_delete_entry (admin, mailbox,
							  oldname, &error)) {
			g_warning ("%s", error);
			g_free (error);
		} else {
			/* All OK! */
			gtk_tree_model_foreach (model,
						gyrus_admin_acl_eliminate_model_entry,
						newname);
			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
					    COL_ACL_IDENTIFIER, newname,
					    -1);
		}
	}
	
	g_free (oldname);
	g_free (mailbox);
	g_free (rights);
	gyrus_admin_acl_list_free (acl);
}

/*** Following code intents to show the flexibility of GyrusAdmin objects. ***/
/*
int
main (int argc, char *argv[])
{
	GtkWidget *admin;
	GtkWidget *window;
	gtk_init (&argc, &argv);
	gnome_program_init ("gyrus", VERSION, LIBGNOMEUI_MODULE,
			    argc, argv,
			    GNOME_PARAM_APP_DATADIR, GYRUS_DATA_DIR, NULL);

	admin = gyrus_admin_new ();
	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	
	gtk_container_add (GTK_CONTAINER (window), admin);
	
	gtk_widget_show (window);

	gtk_main ();

	return 0;
}
*/
