/* 
 *  Contacts - A small libebook-based address book.
 *
 *  Authored By Chris Lord <chris@o-hand.com>
 *
 *  Copyright (c) 2005 OpenedHand Ltd - http://o-hand.com
 *
 *  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, 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.
 *
 */

#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <libebook/e-book.h>
#include "config.h"
#ifdef HAVE_GNOMEVFS
#include <libgnomevfs/gnome-vfs.h>
#endif

#include "contacts-defs.h"
#include "contacts-utils.h"
#include "contacts-ui.h"
#include "contacts-callbacks-ui.h"
#include "contacts-callbacks-ebook.h"
#include "contacts-edit-pane.h"
#include "contacts-main.h"

void
contacts_chooser_add_cb (GtkWidget *button, ContactsData *data)
{
	GtkWidget *treeview, *entry;
	GtkListStore *model;
	GtkTreeIter iter;
	const gchar *text;
	
	entry = data->ui->chooser_entry;
	text = gtk_entry_get_text (GTK_ENTRY (entry));
	
	if (g_utf8_strlen (text, -1) <= 0)
		return;
	
	treeview = data->ui->chooser_treeview;
	model = GTK_LIST_STORE (
		gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
	
	gtk_list_store_append (model, &iter);
	gtk_list_store_set (model, &iter, CHOOSER_TICK_COL, TRUE,
			    CHOOSER_NAME_COL, text, -1);
	
	gtk_entry_set_text (GTK_ENTRY (entry), "");

	contacts_ui_update_groups_list (data);
}



void
contacts_search_changed_cb (GtkWidget *widget, ContactsData *data)
{
	contacts_update_treeview (data);
}

void
contacts_chooser_toggle_cb (GtkCellRendererToggle * cell,
		   gchar * path_string, gpointer user_data)
{
	GtkTreeIter iter;
	GtkTreeModel *model = GTK_TREE_MODEL (user_data);

	gtk_tree_model_get_iter_from_string (model, &iter, path_string);
	if (gtk_cell_renderer_toggle_get_active (cell))
		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
				    CHOOSER_TICK_COL, FALSE, -1);
	else
		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
				    CHOOSER_TICK_COL, TRUE, -1);
}



void
contacts_selection_cb (GtkTreeSelection * selection, ContactsData *data)
{
	GtkWidget *widget;
	EContact *contact;

	/* Get the currently selected contact and update the contact summary */
	contact = contacts_contact_from_selection (selection,
						   data->contacts_table);
	if (contact) {
		contacts_display_summary (contact, data);
	} else {
		contacts_set_available_options (data, TRUE, FALSE, FALSE);
		widget = data->ui->summary_vbox;
		gtk_widget_hide (widget);
	}
}

void
contacts_new_cb (GtkWidget *source, ContactsData *data)
{
	data->contact = e_contact_new ();	
	contacts_edit_pane_show (data, TRUE);
}

void
contacts_edit_cb (GtkWidget *source, ContactsData *data)
{
	/* Disable the new/edit/delete options and get the contact to edit */
	data->contact = contacts_get_selected_contact (data,
						       data->contacts_table);
	if (data->contact) {
		contacts_set_available_options (data, FALSE, FALSE, FALSE);
		data->changed = FALSE;		
		contacts_edit_pane_show (data, FALSE);
	}
}

void
contacts_treeview_edit_cb (GtkTreeView *treeview, GtkTreePath *arg1,
	GtkTreeViewColumn *arg2, ContactsData *data)
{
	contacts_edit_cb (GTK_WIDGET (treeview), data);
}

void
contacts_delete_cb (GtkWidget *source, ContactsData *data)
{
	GtkWidget *dialog, *main_window;
	gint result, count_selected;
	EContact *contact;
	GList *widgets, *selected_paths, *current_path;
	GList *contact_list = NULL;
	const gchar *name;
	gchar *message = NULL;
	GtkTreeModel *model;

	GtkWidget *widget;
	GtkTreeSelection *selection;

	widget = data->ui->contacts_treeview;
	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
	count_selected = gtk_tree_selection_count_selected_rows (selection);

	if (count_selected < 2) {
		contact = contacts_get_selected_contact (data,
						data->contacts_table);
		if (!contact) return;

		name = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
		if ((!name) || (g_utf8_strlen (name, 4) <= 0))
			name = _("Unknown");

		contact_list = g_list_prepend (contact_list, e_contact_get (contact, E_CONTACT_UID));

		message = g_strdup_printf (_("Are you sure you want to delete "\
				 "'%s'?"), name);
	}
	else {
		message = g_strdup_printf (_("Are you sure you want to delete "\
					"%d contacts?"), count_selected);

		selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
		
		current_path = g_list_first (selected_paths);
		while (current_path) {
			contact = contacts_contact_from_tree_path (model, current_path->data, data->contacts_table);
			contact_list = g_list_prepend (contact_list, e_contact_get(contact, E_CONTACT_UID));
			current_path = g_list_next (current_path);
		}

		g_list_foreach (selected_paths, (GFunc)gtk_tree_path_free, NULL);
		g_list_free (selected_paths);
	}


	main_window = data->ui->main_window;
	dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
					 0, GTK_MESSAGE_QUESTION,
					 GTK_BUTTONS_CANCEL,
					 message);
	gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_DELETE,
		GTK_RESPONSE_YES, NULL);

	widgets = contacts_set_widgets_desensitive (main_window);
	result = gtk_dialog_run (GTK_DIALOG (dialog));
	switch (result) {
		case GTK_RESPONSE_YES:
			/* TODO: add progress indicator and callback here */
			e_book_async_remove_contacts (data->book, contact_list, NULL, NULL);
			break;
		default:
			break;
	}
	g_list_foreach (contact_list, (GFunc) g_free, NULL);
	g_list_free (contact_list);
	gtk_widget_destroy (dialog);
	contacts_set_widgets_sensitive (widgets);
	g_list_free (widgets);
}

void
contacts_import (ContactsData *data, const gchar *filename, gboolean do_confirm)
{
	gchar *vcard_string, *card;
	gchar **vcard_array = NULL;
	gint i = 0;
#ifdef HAVE_GNOMEVFS
	int size;
	GnomeVFSResult vfs_result;

	vfs_result = gnome_vfs_read_entire_file (
		filename, &size, &vcard_string);
	if (vfs_result == GNOME_VFS_OK) {
#else
	if (g_file_get_contents (
		filename, &vcard_string, NULL, NULL)) {
#endif
		vcard_array = g_strsplit (vcard_string, "END:VCARD\n", 0);
		while ((card = vcard_array[i++]))
		{
			EContact *contact = NULL;
			gchar *str1;
			/* make sure we haven't reached the end */
			if (strlen (card) < 1)
				continue;
			/* END:VCARD is stripped by strsplit, so add it again here */
			str1 = g_strconcat (card, "END:VCARD", NULL);
			contact = e_contact_new_from_vcard (str1);
			g_free (str1);

			if (contact) {
				gint result = GTK_RESPONSE_YES;
				if (do_confirm) {
					GtkWidget *dialog, *main_window;
					GList *widgets;
					
					main_window = data->ui->main_window;
					dialog = gtk_message_dialog_new (
						GTK_WINDOW (main_window),
						0, GTK_MESSAGE_QUESTION,
						GTK_BUTTONS_NONE,
						_("Would you like to import contact "\
						"'%s'?"),
						(const char *)e_contact_get_const (
							contact, E_CONTACT_FULL_NAME));
					gtk_dialog_add_buttons (GTK_DIALOG (dialog),
						_("_Show contact"), GTK_RESPONSE_NO,
						_("_Import contact"), GTK_RESPONSE_YES,
						NULL);
					widgets = contacts_set_widgets_desensitive (
						main_window);
					result = gtk_dialog_run (GTK_DIALOG (dialog));
					gtk_widget_destroy (dialog);
					contacts_set_widgets_sensitive (widgets);
					g_list_free (widgets);
				}
				if (result == GTK_RESPONSE_YES) {
					GList *lcontact =
						g_list_prepend (NULL, contact);
					/* Add contact to db and select it */
					/* TODO: add progress indicator and callback here */
					e_book_async_add_contact (data->book, contact,
								   NULL, NULL);
					/* Maually trigger the added callback so that
					 * the contact can be selected.
					 */
					#if 0
					contacts_added_cb (data->book_view, lcontact,
						data);
					contacts_set_selected_contact (data->xml,
						(const gchar *)e_contact_get_const (
							contact, E_CONTACT_UID));
					#endif
					g_list_free (lcontact);
				} else {
					contacts_display_summary (contact, data);
					contacts_set_available_options (
						data, TRUE, FALSE, FALSE);
				}
				g_object_unref (contact);
			}
		}
		g_free (vcard_string);
		g_strfreev (vcard_array);
	}
#ifdef HAVE_GNOMEVFS
	else {
		g_warning ("Error loading '%s': %s",
			filename, gnome_vfs_result_to_string (vfs_result));
	}
#endif
}

void
contacts_import_cb (GtkWidget *source, ContactsData *data)
{
	GList *widgets;
	GtkFileFilter *filter;
	GtkWidget *main_window =
		data->ui->main_window;
	GtkWidget *dialog = gtk_file_chooser_dialog_new (
		_("Import Contact"),
		GTK_WINDOW (main_window),
		GTK_FILE_CHOOSER_ACTION_OPEN,
		GTK_STOCK_CANCEL,
		GTK_RESPONSE_CANCEL,
		GTK_STOCK_OPEN,
		GTK_RESPONSE_ACCEPT,
		NULL);

	filter = gtk_file_filter_new ();
	gtk_file_filter_add_mime_type (filter, "text/x-vcard");
	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
#ifdef HAVE_GNOMEVFS
	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
#endif
	
	widgets = contacts_set_widgets_desensitive (main_window);
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
		gchar *filename = gtk_file_chooser_get_filename 
					(GTK_FILE_CHOOSER (dialog));
		if (filename) {
			contacts_import (data, filename, FALSE);
			g_free (filename);
		}
	}
	
	contacts_set_widgets_sensitive (widgets);
	gtk_widget_destroy (dialog);
	g_list_free (widgets);
}

void
contacts_export (ContactsData *data, const gchar *filename)
{
	char *vcard = e_vcard_to_string (
		E_VCARD (data->contact), EVC_FORMAT_VCARD_30);
		
	if (vcard) {
#ifdef HAVE_GNOMEVFS
		GnomeVFSHandle *file;
		GnomeVFSFileSize bytes_written;
		if (gnome_vfs_open (&file, filename, GNOME_VFS_OPEN_WRITE) ==
		    GNOME_VFS_OK) {
			if (gnome_vfs_write (file, vcard, strlen (vcard),
			    &bytes_written) != GNOME_VFS_OK)
				g_warning ("Writing to '%s' failed, %lld bytes "
					"written", filename,
					bytes_written);
			gnome_vfs_close (file);
		}
#else
		FILE *file = fopen (filename, "w");
		if (file) {
			fputs (vcard, file);
			fclose (file);
		}
#endif
		g_free (vcard);
	}
}

void
contacts_export_cb (GtkWidget *source, ContactsData *data)
{
	GList *widgets;
	GtkWidget *main_window =
		data->ui->main_window;
	GtkWidget *dialog = gtk_file_chooser_dialog_new (
		_("Export Contact"),
		GTK_WINDOW (main_window),
		GTK_FILE_CHOOSER_ACTION_SAVE,
		GTK_STOCK_CANCEL,
		GTK_RESPONSE_CANCEL,
		GTK_STOCK_SAVE,
		GTK_RESPONSE_ACCEPT,
		NULL);
	
	/* Gtk 2.8 feature */
/*	gtk_file_chooser_set_do_overwrite_confirmation (
		GTK_FILE_CHOOSER (dialog), TRUE);*/
#ifdef HAVE_GNOMEVFS
	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
#endif

	widgets = contacts_set_widgets_desensitive (main_window);
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
		gchar *filename = gtk_file_chooser_get_filename 
					(GTK_FILE_CHOOSER (dialog));
		if (filename) {
#ifdef HAVE_GNOMEVFS
			GnomeVFSURI *uri = gnome_vfs_uri_new (filename);
			if (gnome_vfs_uri_exists (uri))
#else
			if (g_file_test (
			    filename, G_FILE_TEST_EXISTS))
#endif
			{
				GtkWidget *button, *image;
				GtkWidget *overwrite_dialog =
				gtk_message_dialog_new_with_markup (
					GTK_WINDOW (dialog),
					GTK_DIALOG_MODAL,
					GTK_MESSAGE_QUESTION,
					GTK_BUTTONS_CANCEL,
                                        /* TODO: make it nicer for i18n */
					_("<big><b>The file \"%s\""
					" already exists.\n"
					"Do you want to replace it?</b></big>"),
					filename);
				gtk_message_dialog_format_secondary_markup (
					GTK_MESSAGE_DIALOG (overwrite_dialog),
					_("Replacing it will overwrite its "
					"contents."));
				button = gtk_dialog_add_button (
					GTK_DIALOG (overwrite_dialog),
					_("_Replace"),
					GTK_RESPONSE_OK);
				image = gtk_image_new_from_stock (
					GTK_STOCK_SAVE_AS,
					GTK_ICON_SIZE_BUTTON);
				gtk_button_set_image (
					GTK_BUTTON (button), image);
				
				if (gtk_dialog_run (
				     GTK_DIALOG (overwrite_dialog)) ==
				      GTK_RESPONSE_OK)
					contacts_export (data, filename);
				
				gtk_widget_destroy (overwrite_dialog);
			} else
				contacts_export (data, filename);
			
			g_free (filename);
#ifdef HAVE_GNOMEVFS
			gnome_vfs_uri_unref (uri);
#endif
		}
	}
	
	contacts_set_widgets_sensitive (widgets);
	gtk_widget_destroy (dialog);
	g_list_free (widgets);
}

void
contacts_edit_menu_activate_cb (GtkWidget *widget, ContactsData *data)
{
	gboolean can_cutcopy, can_paste;

	widget = data->ui->main_window;
	widget = gtk_window_get_focus (GTK_WINDOW (widget));
	if ((GTK_IS_EDITABLE (widget) || GTK_IS_TEXT_VIEW (widget) || GTK_IS_LABEL (widget)))
	{
		GtkClipboard *clip;
		clip = gtk_clipboard_get_for_display (gtk_widget_get_display (widget), GDK_SELECTION_CLIPBOARD);
		can_paste = gtk_clipboard_wait_is_text_available (clip);

		if (GTK_IS_EDITABLE (widget))
			can_cutcopy = gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), NULL, NULL);
		else if (GTK_IS_TEXT_VIEW (widget))
		{
			GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
			can_cutcopy = gtk_text_buffer_get_selection_bounds (buf, NULL, NULL);
		}
		else if (GTK_IS_LABEL (widget))
			can_cutcopy = gtk_label_get_selection_bounds (GTK_LABEL (widget), NULL, NULL);
		else
			/* if we can't work out whether we can cut/copy, assume we can */
			can_cutcopy = TRUE;
	}
	else
		can_cutcopy = can_paste = FALSE;

	widget = data->ui->cut_menuitem;
	gtk_widget_set_sensitive (widget, can_cutcopy);
	widget = data->ui->copy_menuitem;
	gtk_widget_set_sensitive (widget, can_cutcopy);
	widget = data->ui->paste_menuitem;
	gtk_widget_set_sensitive (widget, can_paste);
}

void
contacts_copy_cb (GtkWindow *main_window)
{
	GtkWidget *widget = gtk_window_get_focus (main_window);

	if (widget) {
		if (GTK_IS_EDITABLE (widget))
			gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
		else if (GTK_IS_TEXT_VIEW (widget)) {
			GtkTextBuffer *buffer = gtk_text_view_get_buffer (
				GTK_TEXT_VIEW (widget));
			gtk_text_buffer_copy_clipboard (buffer,
				gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
		} else if (GTK_IS_LABEL (widget)) {
			gint start, end;
			if (gtk_label_get_selection_bounds (GTK_LABEL (widget),
							    &start, &end)) {
				const gchar *text =
					gtk_label_get_text (GTK_LABEL (widget));
				gchar *start_text =
					g_utf8_offset_to_pointer (text, start);
				gchar *copy_text =
					g_strndup (start_text, end-start);
				gtk_clipboard_set_text (
				    gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
				    copy_text, end-start);
				g_free (copy_text);
			}
		}
	}
}

void
contacts_cut_cb (GtkWindow *main_window)
{
	GtkWidget *widget = gtk_window_get_focus (main_window);
	
	if (widget) {
		if (GTK_IS_EDITABLE (widget))
			gtk_editable_cut_clipboard (GTK_EDITABLE (widget));
		else if (GTK_IS_TEXT_VIEW (widget)) {
			GtkTextBuffer *buffer = gtk_text_view_get_buffer (
				GTK_TEXT_VIEW (widget));
			gtk_text_buffer_cut_clipboard (buffer,
				gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
				TRUE);
		} else
			contacts_copy_cb (main_window);
	}
}

void
contacts_paste_cb (GtkWindow *main_window)
{
	GtkWidget *widget = gtk_window_get_focus (main_window);

	if (widget) {
		if (GTK_IS_EDITABLE (widget))
			gtk_editable_paste_clipboard (GTK_EDITABLE (widget));
		else if (GTK_IS_TEXT_VIEW (widget)) {
			GtkTextBuffer *buffer = gtk_text_view_get_buffer (
				GTK_TEXT_VIEW (widget));
			gtk_text_buffer_paste_clipboard (buffer,
				gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
				NULL, TRUE);
		}
	}
}

void
contacts_about_cb (GtkWidget *parent)
{
	const char *authors[] = {"Chris Lord <chris@openedhand.com>",
			    "Ross Burton <ross@openedhand.com>",
			    "Matthew Allum <mallum@openedhand.com>",
			    "Thomas Wood <thomas@openedhand.com>",
			    NULL};
	const char *license = {
	  N_(
	     "Contacts 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.\n\n"
	     "Contacts 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.\n\n"
	     "You should have received a copy of the GNU General Public License "
	     "along with Contacts; if not, write to the Free Software Foundation, Inc., "
	     "51 Franklin St, Fifth Floor, Boston, MA 0110-1301, USA"
	     )
	};
	/* Translators: please translate this as your own name and optionally email
	   like so: "Your Name <your@email.com>" */
	const char *translator_credits = _("translator-credits");

	gtk_show_about_dialog (GTK_WINDOW (parent),
		"name", GETTEXT_PACKAGE,
		"version", VERSION,
		"authors", authors,
		"logo-icon-name", "contacts",
		"website", "http://projects.o-hand.com/contacts/",
		"copyright", "\302\251 2006 OpenedHand Ltd",
		"translator-credits", translator_credits,
		"license", license,
		"wrap-license", TRUE,
		NULL);

}

gboolean
contacts_treeview_search_cb (GtkWidget *search_entry, GdkEventKey *event,
	GtkTreeView *treeview)
{
	gtk_widget_event (search_entry, (GdkEvent *)event);
	gtk_editable_set_position (GTK_EDITABLE (search_entry), -1);
	
	return FALSE;
}

gboolean
contacts_is_row_visible_cb (GtkTreeModel * model, GtkTreeIter * iter,
			    GHashTable *contacts_table)
{
	gboolean result = FALSE;
	gchar *group = NULL;
	GList *groups, *g;
	gchar *uid;
	EContactListHash *hash;
	const gchar *search_string;
	ContactsData *data;

	/* Check if the contact is in the currently selected group. */
	gtk_tree_model_get (model, iter, CONTACT_UID_COL, &uid, -1);
	if (!uid) return FALSE;
	hash = g_hash_table_lookup (contacts_table, uid);
	g_free (uid);
	if (!hash || !hash->contact) return FALSE;
	data = hash->contacts_data;

	if (data->selected_group && strcmp ("All", data->selected_group))
	{
		groups = e_contact_get (hash->contact, E_CONTACT_CATEGORY_LIST);
		if ((group = data->selected_group)) {
			for (g = groups; g; g = g->next) {
				if (strcmp (group, g->data) == 0)
					result = TRUE;
				g_free (g->data);
			}
			if (groups)
				g_list_free (groups);
		} else
			result = TRUE;
		if (!result)
			return FALSE;
	}
	else
		result = TRUE;

	/* Search for any occurrence of the string in the search box in the 
	 * contact file-as name; if none is found, row isn't visible. Ignores 
	 * empty searches.
	 */
	if (GTK_WIDGET_VISIBLE (data->ui->search_entry)) {
		search_string = gtk_entry_get_text (
			GTK_ENTRY (data->ui->search_entry));
		if ((search_string) &&
		    (g_utf8_strlen (search_string, -1) > 0)) {
			gchar *name_string;
			gtk_tree_model_get (model, iter, CONTACT_NAME_COL,
				&name_string, -1);
			if (name_string) {
				gunichar *isearch =
				    kozo_utf8_strcasestrip (search_string);
				if (!kozo_utf8_strstrcasestrip
				    (name_string, isearch))
					result = FALSE;
				g_free (name_string);
				g_free (isearch);
			}
		}
	} else if ((data->ui->symbols_radiobutton)){
		gint i;
		gchar *name, *uname;
		gunichar c;
		GSList *b, *buttons = gtk_radio_button_get_group (
			GTK_RADIO_BUTTON (data->ui->symbols_radiobutton));
		
		/* Find the active radio button */
		for (b = buttons, i = 0; b; b = b->next, i++)
			if (gtk_toggle_button_get_active (
				GTK_TOGGLE_BUTTON (b->data))) break;
		
		gtk_tree_model_get (model, iter, CONTACT_NAME_COL,
			&name, -1);
		uname = g_utf8_strup (name, -1);
		c = g_utf8_get_char (uname);
		
		switch (i) {
			case 4 :
				if (c >= 'A' || c <= 'Z')
					return FALSE;
				break;
			case 3 :
				if (c < 'A' || c > 'G')
					return FALSE;
				break;
			case 2 :
				if (c < 'H' || c > 'N')
					return FALSE;
				break;
			case 1 :
				if (c < 'O' || c > 'U')
					return FALSE;
				break;
			case 0 :
				if (c < 'V' || c > 'Z')
					return FALSE;
				break;
			default :
				g_warning ("Unknown search tab state %d", i);
				break;
		}
		
		g_free (name);
	}
	return result;
}

gint
contacts_sort_treeview_cb (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b,
			   gpointer user_data)
{
	gchar *string1, *string2;
	gint returnval;

	gtk_tree_model_get (model, a, CONTACT_NAME_COL, &string1, -1);
	gtk_tree_model_get (model, b, CONTACT_NAME_COL, &string2, -1);
	if (!string1) string1 = g_new0 (gchar, 1);
	if (!string2) string2 = g_new0 (gchar, 1);
	returnval = strcasecmp ((const char *) string1,
				(const char *) string2);
	g_free (string1);
	g_free (string2);

	return returnval;
}

gboolean
contacts_main_window_delete_event_cb (GtkWidget *main_window, gpointer data)
{
#ifdef HAVE_GCONF
	GConfClient *client;
	gint width, height;
	client = gconf_client_get_default ();
	gtk_window_get_size (GTK_WINDOW (main_window), &width, &height);
	gconf_client_set_int (client, GCONF_PATH "/width", width, NULL);
	gconf_client_set_int (client, GCONF_PATH "/height", height, NULL);
	g_object_unref (G_OBJECT (client));
#endif
	return FALSE;
}
