/*
    GQ -- a GTK-based LDAP client
    Copyright (C) 1998-2003 Bert Vermeulen
    Copyright (C) 2002-2003 Peter Stamfest

    This program is released under the Gnu General Public License with
    the additional exemption that compiling, linking, and/or using
    OpenSSL is allowed.

    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
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */

#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

#include "common.h"
#include "configfile.h"
#include "gq-keyring.h"
#include "gq-input-form.h"
#include "gq-server-dialog.h"
#include "gq-server-list.h"
#include "gq-server-model.h"
#include "gq-tab-browse.h"
#include "gq-utilities.h"
#include "gq-window.h"
#include "prefs.h"
#include "state.h"
#include "template.h"
#include "errorchain.h"
#include "debug.h"

/* for now: only allow a single preferences window */
static GtkWidget *prefswindow;

GtkWidget *current_template_clist = NULL;
#warning "FIXME: used in template.c as well"

struct prefs_windata {
     GtkWidget *prefswindow;

     GtkWidget *templatelist;

     GtkWidget *showdn;
     GtkWidget *showoc;
     GtkWidget *show_rdn_only;
     GtkWidget *sort_search;
     GtkWidget *sort_browse;
     GtkWidget *restore_window_sizes;
     GtkWidget *restore_window_positions;
     GtkWidget *restore_search_history;
     GtkWidget *restore_tabs;

     GtkWidget *browse_use_user_friendly;

     /* template tab */
     GtkWidget *schemaserver;

     /* servers tab */
     GtkWidget *serverstab_server_view;

     /* security */
     GtkWidget *never_leak_credentials;
     GtkWidget *do_not_use_ldap_conf;

};

struct server_windata {
     GtkWidget *editwindow;

     GtkWidget *servername;
     GtkWidget *ldaphost;
     GtkWidget *ldapport;
     GtkWidget *basedn;
     GtkWidget *bindtype;
     GtkWidget *binddn;
     GtkWidget *bindpw;
     GtkWidget *show_pw_toggle;
     GtkWidget *clear_pw;
     GtkWidget *searchattr;
     GtkWidget *localcachetimeout;
     GtkWidget *ask_pw;
     GtkWidget *hide_internal;
     GtkWidget *cacheconn;
     GtkWidget *show_ref;
     GtkWidget *enabletls;
};

static void create_serverstab(GtkWidget *target, struct prefs_windata *pw);
static void create_templatestab(GtkWidget *target, struct prefs_windata *pw);
static void create_browse_optionstab(GtkWidget *target,
				     struct prefs_windata *pw);
static void create_search_optionstab(GtkWidget *target,
				     struct prefs_windata *pw);
static void create_guitab(GtkWidget *target, struct prefs_windata *);
static void create_security_tab(GtkWidget *target, struct prefs_windata *);

static void template_new_callback (struct prefs_windata *);
static void template_edit_callback(struct prefs_windata *);
static void template_selected_callback(GtkWidget *clist, gint row, gint column,
				       GdkEventButton *event,
				       struct prefs_windata *data);
static void template_delete_callback(GtkWidget *widget,
				     struct prefs_windata *pw);





typedef struct _prefs_callback_data {
     struct server_windata *sw;
     GqServer *server;
     int edit_new_server;
     /* is the server a dynamically added one */
     gboolean transient;
} prefs_callback_data;

#warning "FIXME: enable the client cache timeout setting in the server dialog"
#if 0 ||HAVE_LDAP_CLIENT_CACHE
     /* Use local cache */
     label = gq_label_new(_("LDAP cache timeo_ut"));
     gtk_misc_set_alignment(GTK_MISC(label), 0.0, .5);
     gtk_widget_show(label);
     gtk_table_attach(GTK_TABLE(table2), label, 0, 1, y, y + 1,
		      GTK_FILL, GTK_FILL, 0, 0);

     entry = gtk_entry_new();
     sw->localcachetimeout = entry;
     g_snprintf(tmp, sizeof(tmp), "%ld", server->local_cache_timeout);
     gtk_entry_set_text(GTK_ENTRY(entry), tmp);
     gtk_widget_show(entry);
     g_signal_connect(entry, "activate",
			G_CALLBACK(server_edit_callback), cb_data);
     gtk_table_attach(GTK_TABLE(table2), entry, 1, 2, y, y + 1,
		      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
     y++;

     gtk_tooltips_set_tip(tips, entry,
			  _("Should the OpenLDAP client-side cache be used? "
			    "And what is its timeout? Anything greater than "
			    "-1 turns on the cache."),
			  Q_("tooltip|Using this might speed up LDAP "
			     "operations, but it may also lead to slightly "
			     "out-of-date data.")
			  );
     gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);

#endif

static void
serverstab_deletebutton_callback(GtkWidget*            widget,
				 struct prefs_windata* pw)
{
	GtkTreeModel* model;
	GtkTreeIter   iter;
	GqServer    * server;

#warning "FIXME: this check should be unnecessary if the button is disabled without selection"
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(pw->serverstab_server_view)),
					    &model, &iter))
	{
		return;
	}

	server = gq_server_model_get_server(GQ_SERVER_MODEL(model), &iter);
	if(server) {
	       GQServerList* list = gq_server_list_get();

	       g_object_ref(server);
	       gq_server_list_remove(list, server);

	       if (save_config(widget)) {
		    update_serverlist(&mainwin);
	       } else {
		    /* undo changes */
		    gq_server_list_add(list, server);
	       }
	       g_object_unref(server);
	}
}

static void
serverstab_newbutton_callback(struct prefs_windata* pw)
{
	GqServer * server = gq_server_new(NULL);
	GtkWidget* dialog = gq_server_dialog_new(server, GTK_WINDOW(pw->prefswindow));

	switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
	case GTK_RESPONSE_CLOSE:
		gq_server_list_add(gq_server_list_get(), server);
		break;
	default:
		// revert or deleted
		break;
	}

	gtk_widget_destroy(dialog);
	g_object_unref(server);
}


static void
serverstab_editbutton_callback(struct prefs_windata* pw)
{
	GtkTreeModel* model;
	GtkTreeIter   iter;
	GtkWidget   * server_dialog;
	GqServer    * server;

#warning "FIXME: don't allow the edit button and the delete button if no server is selected"
	if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(pw->serverstab_server_view)), &model, &iter))
	{
		return;
	}

	server = gq_server_model_get_server(GQ_SERVER_MODEL(model), &iter);
	g_return_if_fail(server);

	server_dialog = gq_server_dialog_new(server, GTK_WINDOW(pw->prefswindow));
	gtk_dialog_run(GTK_DIALOG(server_dialog));
	gtk_widget_destroy(server_dialog);
}


static gboolean
server_clicked_callback(struct prefs_windata* pw,
			GdkEventButton*       event,
			GtkWidget*            treeview)
{
	GtkTreeModel* model;
	GtkTreeIter   iter;

	if(event &&
	   event->type == GDK_2BUTTON_PRESS &&
	   gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),
					   &model, &iter))
	{
		GqServer *server = gq_server_model_get_server(GQ_SERVER_MODEL(model), &iter);
		GtkWidget* dialog = gq_server_dialog_new(server, GTK_WINDOW(pw->prefswindow));
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);
	}

	return FALSE;
}


static void
prefs_okbutton_callback(struct prefs_windata* pw)
{
     /* use a dummy configuration to store current/old preferences for
	rollback */
     struct gq_config *save = new_config();

     /* saves a lot of typing */
#define CONFIG_TOGGLE_BUTTON(c,p,s,n) { \
	(s)->n = (c)->n; \
	(c)->n = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((p)->n)); \
	}

     /* WHEN ADDING STUFF: DO NOT FORGET TO CODE ROLLBACK AS WELL */
     /* Show DN */
     CONFIG_TOGGLE_BUTTON(config, pw, save, showdn);

     /* Show RDN only */
     CONFIG_TOGGLE_BUTTON(config, pw, save, show_rdn_only);

     /* Sorting: browse mode */
     CONFIG_TOGGLE_BUTTON(config, pw, save, sort_browse);

     /* browse mode: Use user-friendly attribute names */
     CONFIG_TOGGLE_BUTTON(config, pw, save, browse_use_user_friendly);

     /* browse mode: Use user-friendly attribute names */
     CONFIG_TOGGLE_BUTTON(config, pw, save, browse_use_user_friendly);

     /* GUI */
     /* restore window sizes */
     CONFIG_TOGGLE_BUTTON(config, pw, save, restore_window_sizes);

     /* restore window positions */
     CONFIG_TOGGLE_BUTTON(config, pw, save, restore_window_positions);

     /* restore search history */
     CONFIG_TOGGLE_BUTTON(config, pw, save, restore_search_history);

     /* WHEN ADDING STUFF: DO NOT FORGET TO CODE ROLLBACK AS WELL */
     /* restore tabs */
     CONFIG_TOGGLE_BUTTON(config, pw, save, restore_tabs);

     /* never_leak_credentials */
     CONFIG_TOGGLE_BUTTON(config, pw, save, never_leak_credentials);

     /* do_not_use_ldap_conf */
     CONFIG_TOGGLE_BUTTON(config, pw, save, do_not_use_ldap_conf);

     /* WHEN ADDING STUFF: DO NOT FORGET TO CODE ROLLBACK AS WELL */
     /* do_not_use_ldap_conf */
     CONFIG_TOGGLE_BUTTON(config, pw, save, do_not_use_ldap_conf);

     g_free_and_dup(save->schemaserver, config->schemaserver);
     if(pw->schemaserver) {
		GtkTreeIter iter;
		GqServer* server;
		if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pw->schemaserver), &iter)) {
			g_free(config->schemaserver);
			server = gq_server_model_get_server(GQ_SERVER_MODEL(gtk_combo_box_get_model(GTK_COMBO_BOX(pw->schemaserver))),
							    &iter);
			config->schemaserver = g_strdup(gq_server_get_name(server));
		}
     }

     if (save_config(pw->prefswindow)) {
	  gtk_widget_destroy(pw->prefswindow);
     } else {
/* saves typing */
#define CONFIG_ROLLBACK(o,s,n) (o)->n = (s)->n
	  CONFIG_ROLLBACK(config, save, showdn);
	  CONFIG_ROLLBACK(config, save, showoc);
	  CONFIG_ROLLBACK(config, save, show_rdn_only);
	  CONFIG_ROLLBACK(config, save, sort_search);
	  CONFIG_ROLLBACK(config, save, sort_browse);
	  CONFIG_ROLLBACK(config, save, browse_use_user_friendly);
	  CONFIG_ROLLBACK(config, save, restore_window_sizes);
	  CONFIG_ROLLBACK(config, save, restore_window_positions);
	  CONFIG_ROLLBACK(config, save, restore_search_history);
	  CONFIG_ROLLBACK(config, save, restore_tabs);
	  CONFIG_ROLLBACK(config, save, never_leak_credentials);
	  CONFIG_ROLLBACK(config, save, do_not_use_ldap_conf);

	  g_free_and_dup(config->schemaserver, save->schemaserver);
     }

     free_config(save);
}

static void destroy_prefswindow(GtkWidget *window,
				struct prefs_windata *pw) {
     g_assert(pw);
     g_assert(window == prefswindow);

     prefswindow = NULL;
     g_free(pw);
}


void create_prefs_window(GqWindow *win)
{
     GtkWidget *label, *vbox2;
     GtkWidget *notebook;
     GtkWidget *vbox_search_options, *vbox_browse_options;
     GtkWidget *vbox_servers, *vbox_templates, *vbox_gui;
     GtkWidget *vbox_sec;
     GtkWidget *hbox_buttons, *okbutton, *cancelbutton;

     struct prefs_windata *pw = NULL;

     if (prefswindow) {
	  gtk_window_present(GTK_WINDOW(prefswindow));
	  return;
     }

     pw = g_malloc0(sizeof(struct prefs_windata));

/*      prefswindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
/*      gtk_widget_set_usize(prefswindow, 520, 470); */

     prefswindow = stateful_gtk_window_new(GTK_WINDOW_TOPLEVEL,
					   "prefswindow", 520, 470); 
     pw->prefswindow = prefswindow;

     g_assert(win);

     gtk_window_set_modal(GTK_WINDOW(prefswindow), TRUE);
     gtk_window_set_transient_for(GTK_WINDOW(prefswindow), 
				  GTK_WINDOW(win->mainwin));

     gtk_container_border_width(GTK_CONTAINER(prefswindow), 
				CONTAINER_BORDER_WIDTH);
     gtk_window_set_title(GTK_WINDOW(prefswindow), _("Preferences"));
     gtk_window_set_policy(GTK_WINDOW(prefswindow), TRUE, TRUE, FALSE);
     g_signal_connect_swapped(prefswindow, "key_press_event",
			       G_CALLBACK(close_on_esc),
			       prefswindow);

     g_signal_connect(prefswindow, "destroy",
			G_CALLBACK(destroy_prefswindow),
			pw);

     vbox2 = gtk_vbox_new(FALSE, 0);
     gtk_widget_show(vbox2);
     gtk_container_add(GTK_CONTAINER(prefswindow), vbox2);

     notebook = gtk_notebook_new();
     gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
     gtk_widget_show(notebook);
     gtk_box_pack_start(GTK_BOX(vbox2), notebook, TRUE, TRUE, 0);

     /* Search Options tab */
     vbox_search_options = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_search_options), 
				CONTAINER_BORDER_WIDTH);
     create_search_optionstab(vbox_search_options, pw);
     gtk_widget_show(vbox_search_options);
     label = gq_label_new(_("Search _Options"));
     gtk_widget_show(label);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_NOTEBOOK(notebook), GTK_CAN_FOCUS);
#endif
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
			      vbox_search_options, label);

     /* Browse Options tab */
     vbox_browse_options = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_browse_options),
				CONTAINER_BORDER_WIDTH);
     create_browse_optionstab(vbox_browse_options, pw);
     gtk_widget_show(vbox_browse_options);
     label = gq_label_new(_("Browse O_ptions"));
     gtk_widget_show(label);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
			      vbox_browse_options, label);

     /* Servers tab */
     vbox_servers = gtk_vbox_new(FALSE, 0);
     create_serverstab(vbox_servers, pw);
     gtk_widget_show(vbox_servers);
     label = gq_label_new(_("_Servers"));
     gtk_widget_show(label);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_servers, label);

#ifdef HAVE_LDAP_STR2OBJECTCLASS
     /* Templates tab */
     vbox_templates = gtk_vbox_new(FALSE, 0);
     create_templatestab(vbox_templates, pw);
     gtk_widget_show(vbox_templates);
     label = gq_label_new(_("_Templates"));
     gtk_widget_show(label);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_templates, label);
#else
     vbox_templates = NULL;
#endif

     /* GUI tab */
     vbox_gui = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_gui),
				CONTAINER_BORDER_WIDTH);
     create_guitab(vbox_gui, pw);
     gtk_widget_show(vbox_gui);
     label = gq_label_new(_("_GUI"));
     gtk_widget_show(label);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_gui, label);

     /* Security tab */
     vbox_sec = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_sec),
				CONTAINER_BORDER_WIDTH);
     create_security_tab(vbox_sec, pw);
     gtk_widget_show(vbox_sec);
     label = gq_label_new(_("Securit_y"));
     gtk_widget_show(label);
     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox_sec, label);

     /* OK and Cancel buttons outside notebook */
     hbox_buttons = gtk_hbutton_box_new();
     gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox_buttons), GTK_BUTTONBOX_END);
     gtk_widget_show(hbox_buttons);
     gtk_box_pack_start(GTK_BOX(vbox2), hbox_buttons, FALSE, TRUE, 10);
/*       gtk_container_border_width(GTK_CONTAINER(hbox_buttons), 10); */

     cancelbutton = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
     gtk_widget_show(cancelbutton);
     gtk_box_pack_end(GTK_BOX(hbox_buttons), cancelbutton, FALSE, TRUE, 0);
     g_signal_connect_swapped(cancelbutton, "clicked",
			       G_CALLBACK(gtk_widget_destroy),
			       GTK_OBJECT(prefswindow));

     okbutton = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
     gtk_widget_show(okbutton);
     g_signal_connect_swapped(okbutton, "clicked",
			G_CALLBACK(prefs_okbutton_callback),
			pw);
     gtk_box_pack_end(GTK_BOX(hbox_buttons), okbutton, FALSE, TRUE, 0);
     GTK_WIDGET_SET_FLAGS(okbutton, GTK_CAN_DEFAULT);
     gtk_widget_grab_focus(okbutton);
     gtk_widget_grab_default(okbutton);

     gtk_widget_show(prefswindow);

     statusbar_msg(_("Preferences window opened"));
}


void
create_serverstab(GtkWidget           * target,
		  struct prefs_windata* pw)
{
     GtkWidget *vbox0, *vbox1, *vbox2, *hbox1, *hbox2, *scrwin;
     GtkWidget *button_new, *button_edit, *button_delete;

     vbox1 = gtk_vbox_new(FALSE, 0);
     gtk_widget_show(vbox1);
     gtk_container_add(GTK_CONTAINER(target), vbox1);
     gtk_container_border_width(GTK_CONTAINER(vbox1),
				CONTAINER_BORDER_WIDTH);

     hbox2 = gtk_hbox_new(FALSE, 25);
     gtk_widget_show(hbox2);
     gtk_box_pack_start(GTK_BOX(vbox1), hbox2, TRUE, TRUE, 0);

     /* scrolled window to hold the server clist */
     scrwin = gtk_scrolled_window_new(NULL, NULL);
     gtk_widget_show(scrwin);
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
				    GTK_POLICY_AUTOMATIC,
				    GTK_POLICY_AUTOMATIC);
     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwin), GTK_SHADOW_IN);
     gtk_box_pack_start(GTK_BOX(hbox2), scrwin, TRUE, TRUE, 0);

     pw->serverstab_server_view = gtk_tree_view_new();
     {
		GtkTreeViewColumn* column;
		GtkCellRenderer  * renderer;
		GtkTreeModel     * model = gq_server_model_new(gq_server_list_get());
		gtk_tree_view_set_model(GTK_TREE_VIEW(pw->serverstab_server_view),
					model);
		g_object_unref(model);

		column = gtk_tree_view_column_new();
		renderer = gtk_cell_renderer_pixbuf_new();
		gtk_tree_view_column_pack_start(column, renderer, FALSE);
		gtk_tree_view_column_add_attribute(column, renderer,
						   "icon-name", GQ_SERVER_MODEL_COL_STATUS);
		renderer = gtk_cell_renderer_text_new();
		gtk_tree_view_column_pack_start(column, renderer, TRUE);
		gtk_tree_view_column_add_attribute(column, renderer,
						   "text", GQ_SERVER_MODEL_COL_NAME);
		gtk_tree_view_append_column(GTK_TREE_VIEW(pw->serverstab_server_view), column);
     }

	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(pw->serverstab_server_view)),
				    GTK_SELECTION_SINGLE);
	g_signal_connect_swapped(pw->serverstab_server_view, "button-press-event",
				 G_CALLBACK(server_clicked_callback), pw);
	gtk_widget_show(pw->serverstab_server_view);

	gtk_container_add(GTK_CONTAINER(scrwin), pw->serverstab_server_view);

     vbox0 = gtk_vbox_new(FALSE, 10);
     gtk_widget_show(vbox0);
     gtk_box_pack_start(GTK_BOX(hbox2), vbox0, FALSE, FALSE, 0);

     vbox2 = gtk_vbutton_box_new(); /*FALSE, 10); */
     gtk_widget_show(vbox2);
     gtk_box_pack_start(GTK_BOX(vbox0), vbox2, FALSE, FALSE, 0);

     /* New button */

     button_new = gtk_button_new_from_stock(GTK_STOCK_NEW);

#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_new, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_new);
     g_signal_connect_swapped(button_new, "clicked",
			G_CALLBACK(serverstab_newbutton_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_new, FALSE, TRUE, 0);

     /* Edit button */
     button_edit = gq_button_new_with_label(_("_Edit"));
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_edit, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_edit);
     g_signal_connect_swapped(button_edit, "clicked",
			G_CALLBACK(serverstab_editbutton_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_edit, FALSE, TRUE, 0);

     /* Delete button */
     button_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_delete, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_delete);
     g_signal_connect(button_delete, "clicked",
			G_CALLBACK(serverstab_deletebutton_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_delete, FALSE, TRUE, 0);

     hbox1 = gtk_hbox_new(FALSE, 10);
     gtk_widget_show(hbox1);
     gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
     gtk_container_border_width(GTK_CONTAINER(hbox1),
				CONTAINER_BORDER_WIDTH);
}


#ifdef HAVE_LDAP_STR2OBJECTCLASS
void create_templatestab(GtkWidget *target, struct prefs_windata *pw)
{
     GtkWidget *vbox0, *vbox1, *vbox2, *hbox1, *hbox2, *scrwin;
     GtkWidget *button_new, *button_edit, *button_delete;
     GtkWidget *template_clist, *label;

     vbox1 = gtk_vbox_new(FALSE, 0);
     gtk_widget_show(vbox1);
     gtk_container_add(GTK_CONTAINER(target), vbox1);
     gtk_container_border_width(GTK_CONTAINER(vbox1),
				CONTAINER_BORDER_WIDTH);

     hbox1 = gtk_hbox_new(FALSE, 10);
     gtk_widget_show(hbox1);
     gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);


     /* Schema server */
     label = gq_label_new(_("Last _resort schema server"));
     gtk_widget_show(label);
     gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);

	pw->schemaserver = gtk_combo_box_new();
	{
		GtkCellRenderer* renderer;
		GtkTreeModel* model = gq_server_model_new(gq_server_list_get());

		gtk_combo_box_set_model(GTK_COMBO_BOX(pw->schemaserver),
					model);
		g_object_unref(model);

		renderer = gtk_cell_renderer_text_new();
		gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pw->schemaserver),
					   renderer, TRUE);
		gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pw->schemaserver),
					       renderer,
					       "text", GQ_SERVER_MODEL_COL_NAME,
					       NULL);
	}

	if(config->schemaserver && *config->schemaserver) {
		GtkTreeModel* model;
		GtkTreeIter   iter;
		GqServer    * server = gq_server_list_get_by_name(gq_server_list_get(), config->schemaserver);
		model = gtk_combo_box_get_model(GTK_COMBO_BOX(pw->schemaserver));
		if(server && gq_server_model_get_iter(GQ_SERVER_MODEL(model), &iter, server)) {
			gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pw->schemaserver), &iter);
		}
	}
	gtk_widget_show(pw->schemaserver);
	gtk_box_pack_start(GTK_BOX(hbox1), pw->schemaserver, FALSE, FALSE, 0);

     hbox2 = gtk_hbox_new(FALSE, 25);
     gtk_widget_show(hbox2);
     gtk_box_pack_start(GTK_BOX(vbox1), hbox2, TRUE, TRUE, 10);

     /* scrolled window to hold the server clist */
     scrwin = gtk_scrolled_window_new(NULL, NULL);
     gtk_widget_set_usize(scrwin, 200, 300);
     gtk_widget_show(scrwin);
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
				    GTK_POLICY_AUTOMATIC,
				    GTK_POLICY_AUTOMATIC);
     gtk_box_pack_start(GTK_BOX(hbox2), scrwin, TRUE, TRUE, 0);

     template_clist = gtk_clist_new(1);
     current_template_clist = template_clist;

     pw->templatelist = template_clist;
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(template_clist, GTK_CAN_FOCUS);
#endif
     gtk_clist_set_selection_mode(GTK_CLIST(template_clist),
				  GTK_SELECTION_SINGLE);
     gtk_clist_set_shadow_type(GTK_CLIST(template_clist),
			       GTK_SHADOW_ETCHED_IN);
     g_signal_connect(template_clist, "select_row",
			G_CALLBACK(template_selected_callback), pw);
     gtk_widget_show(template_clist);
     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrwin),
					   template_clist);

     fill_clist_templates(template_clist);

     vbox0 = gtk_vbox_new(FALSE, 10);
     gtk_widget_show(vbox0);
     gtk_box_pack_start(GTK_BOX(hbox2), vbox0, FALSE, FALSE, 0);

     vbox2 = gtk_vbutton_box_new(); /*FALSE, 10); */
     gtk_widget_show(vbox2);
     gtk_box_pack_start(GTK_BOX(vbox0), vbox2, FALSE, FALSE, 0);

     /* New button */
     button_new = gtk_button_new_from_stock(GTK_STOCK_NEW);

#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_new, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_new);
     g_signal_connect_swapped(button_new, "clicked",
			G_CALLBACK(template_new_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_new, FALSE, TRUE, 0);

     /* Edit button */
     button_edit = gq_button_new_with_label(_("_Edit"));
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_edit, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_edit);
     g_signal_connect_swapped(button_edit, "clicked",
			G_CALLBACK(template_edit_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_edit, FALSE, TRUE, 0);

     /* Delete button */
     button_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(button_delete, GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button_delete);
     g_signal_connect(button_delete, "clicked",
			G_CALLBACK(template_delete_callback),
			pw);
     gtk_box_pack_start(GTK_BOX(vbox2), button_delete, FALSE, TRUE, 0);
}

#endif     

void create_search_optionstab(GtkWidget *target, struct prefs_windata *pw)
{
     GtkWidget *viewframe, *vbox_view;
     GtkWidget *dnbutton;
     GtkWidget *hbox_options;

     hbox_options = gtk_hbox_new(TRUE, 10);
     gtk_widget_show(hbox_options);
     gtk_box_pack_start(GTK_BOX(target), hbox_options, FALSE, TRUE, 5);

     /* View frame in Options tab */
     viewframe = gtk_frame_new(_("View"));
     gtk_widget_show(viewframe);
     gtk_box_pack_start(GTK_BOX(target), viewframe, FALSE, TRUE, 5);
     vbox_view = gtk_vbox_new(TRUE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_view),
				CONTAINER_BORDER_WIDTH);
     gtk_widget_show(vbox_view);
     gtk_container_add(GTK_CONTAINER(viewframe), vbox_view);

     /* Show Distinguished Name checkbox */
     dnbutton = gq_check_button_new_with_label(_("Show _Distinguished Name"));

     pw->showdn = dnbutton;
     if(config->showdn)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dnbutton), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(dnbutton), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(dnbutton);
     gtk_box_pack_start(GTK_BOX(vbox_view), dnbutton, FALSE, TRUE, 5);
}


void create_browse_optionstab(GtkWidget *target, struct prefs_windata *pw)
{
     GtkWidget *viewframe, *vbox_view;
     GtkWidget *show_rdn_only_button, *sort_browse_button;
     GtkTooltips *tips;

     tips = gtk_tooltips_new();

  /* View frame in Options tab */
     viewframe = gtk_frame_new(_("View"));
     gtk_widget_show(viewframe);
     gtk_box_pack_start(GTK_BOX(target), viewframe, FALSE, TRUE, 5);
     vbox_view = gtk_vbox_new(TRUE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox_view),
				CONTAINER_BORDER_WIDTH);
     gtk_widget_show(vbox_view);
     gtk_container_add(GTK_CONTAINER(viewframe), vbox_view);

  /* show rdn only button */
     show_rdn_only_button = gq_check_button_new_with_label(_("Show Relative _Distinguished Name only"));
     pw->show_rdn_only = show_rdn_only_button;
     if(config->show_rdn_only)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(show_rdn_only_button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(show_rdn_only_button), GTK_CAN_FOCUS);
#endif
     gtk_tooltips_set_tip(tips, show_rdn_only_button,
			  _("If set, only show the most specific part of the "
			    "DN in the object tree."),
			  Q_("tooltip|")
			  );

     gtk_widget_show(show_rdn_only_button);
     gtk_box_pack_start(GTK_BOX(vbox_view), show_rdn_only_button, FALSE, FALSE, 5);

  /* Sort in browse mode button */
     sort_browse_button = gq_check_button_new_with_label(_("Sort _results"));
     pw->sort_browse = sort_browse_button;
     if(config->sort_browse)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(sort_browse_button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(sort_browse_button), GTK_CAN_FOCUS);
#endif
     gtk_tooltips_set_tip(tips, sort_browse_button,
			  _("If set, turns on sorting of entries shown in a "
			    "browse tree. Changing this only has an effect "
			    "for new browse tabs."),
			  Q_("tooltip|")
			  );

     gtk_widget_show(sort_browse_button);
     gtk_box_pack_start(GTK_BOX(vbox_view), sort_browse_button, FALSE, FALSE, 5);


     /* browse_use_user_friendly button */
     pw->browse_use_user_friendly = gq_check_button_new_with_label(_("Use _user friendly attribute names"));

     if(config->browse_use_user_friendly)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pw->browse_use_user_friendly), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(pw->browse_use_user_friendly),
			    GTK_CAN_FOCUS);
#endif
     gtk_tooltips_set_tip(tips, pw->browse_use_user_friendly,
			  _("If set, turns on to use user-friendly attribute "
			    "names (if configured) in browse mode."),
			  Q_("tooltip|")
			  );

     gtk_widget_show(pw->browse_use_user_friendly);
     gtk_box_pack_start(GTK_BOX(vbox_view), pw->browse_use_user_friendly,
			FALSE, FALSE, 5);

}

static void create_guitab(GtkWidget *target, struct prefs_windata *pw)
{
     GtkWidget *persistframe;
     GtkWidget *vbox1, *button;
     GtkTooltips *tips;

     tips = gtk_tooltips_new();

     /* Persistency frame */
     persistframe = gtk_frame_new(_("Persistency"));
     gtk_widget_show(persistframe);
     gtk_box_pack_start(GTK_BOX(target), persistframe, FALSE, TRUE, 5);

     vbox1 = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox1),
				CONTAINER_BORDER_WIDTH);
     gtk_container_add(GTK_CONTAINER(persistframe), vbox1);
     gtk_widget_show(vbox1);

     /* Restore Window Sizes checkbox */
     button = gq_check_button_new_with_label(_("Restore Window Si_zes"));
     pw->restore_window_sizes = button;

     if(config->restore_window_sizes)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);

     gtk_tooltips_set_tip(tips, button,
			  _("Turn on if the sizes of some windows should be "
			    "saved and restored across program invocations."),
			  Q_("tooltip|")
			  );

     /* Restore Window Positions checkbox */
     button = gq_check_button_new_with_label(_("Restore Window Pos_itions"));
     pw->restore_window_positions = button;

     if(config->restore_window_positions)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);

     gtk_tooltips_set_tip(tips, button,
			  _("If turned on, the program will try to save and "
			    "restore the on-screen position of some windows "
			    "across program invocations. This will not work "
			    "with certain window managers."),
			  Q_("tooltip|")
			  );

     /* Restore Search History checkbox */
     button = gq_check_button_new_with_label(_("Restore Search _History"));
     pw->restore_search_history = button;

     if(config->restore_search_history)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);

     gtk_tooltips_set_tip(tips, button,
			  _("If set then save and restore the search "
			    "history across program invocations."),
			  Q_("tooltip|")
			  );

     /* Restore Tabs */
     button = gq_check_button_new_with_label(_("Restore Ta_bs"));
     pw->restore_tabs = button;

     if(config->restore_tabs)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);
     
     gtk_tooltips_set_tip(tips, button,
			  _("If set then save and restore the state "
			    "of the main window tabs."),
			  Q_("tooltip|")
			  );
}


static void create_security_tab(GtkWidget *target, struct prefs_windata *pw)
{
     GtkWidget *frame;
     GtkWidget *vbox1, *button;
     GtkTooltips *tips;

     tips = gtk_tooltips_new();

     /* Persistency frame */
     frame = gtk_frame_new(_("Security"));
     gtk_widget_show(frame);
     gtk_box_pack_start(GTK_BOX(target), frame, FALSE, TRUE, 5);

     vbox1 = gtk_vbox_new(FALSE, 0);
     gtk_container_border_width(GTK_CONTAINER(vbox1),
				CONTAINER_BORDER_WIDTH);
     gtk_container_add(GTK_CONTAINER(frame), vbox1);
     gtk_widget_show(vbox1);

     /* Restore Window Sizes checkbox */
     button = gq_check_button_new_with_label(_("_Never leak credentials"));
     pw->never_leak_credentials = button;

     if(config->never_leak_credentials)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);

     gtk_tooltips_set_tip(tips, button,
			  _("Turn off if you want to use heuristics to find the credentials needed to follow referrals. The problems with these heuristics is that they may leak credential information: If you follow a referral to some untrusted server, then your currently used credentials might get sent to this untrusted server. This might allow an attacker to sniff credentials during transit to or on the untrusted server. If turned on, a referral will always use an anonymous bind."),
			  Q_("tooltip|")
			  );

     /* Do not use ldap.conf ... checkbox */
     button = gq_check_button_new_with_label(_("Do not _use ldap.conf/.ldaprc file"));
     pw->do_not_use_ldap_conf = button;

     if(config->do_not_use_ldap_conf)
	  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#ifdef OLD_FOCUS_HANDLING
     GTK_WIDGET_UNSET_FLAGS(GTK_CHECK_BUTTON(button), GTK_CAN_FOCUS);
#endif
     gtk_widget_show(button);
     gtk_box_pack_start(GTK_BOX(vbox1), button, FALSE, TRUE, 5);

     gtk_tooltips_set_tip(tips, button,
			  _("Turn off the standard use of the system-wide ldap.conf configuration file and/or the per-user .ldaprc. This works by setting the environment variable LDAPNOINIT. Note that the this feature only set this variable, but never deletes it. This means that the default behaviour when not selecting this depends on the environment variable being set or not prior to the start of gq. Changing this will only affect future program runs."),
			  Q_("tooltip|")
			  );
}


#ifdef HAVE_LDAP_STR2OBJECTCLASS
void template_new_callback(struct prefs_windata *pw)
{
     GqServer *server;
     const char *servername;

     if (pw->schemaserver == NULL) return;

     if( (servername = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(pw->schemaserver)->entry))) == NULL)
	  return;

     if( (server = gq_server_list_get_by_name(gq_server_list_get(), servername)) == NULL)
	  return;

     create_template_edit_window(server, NULL, pw->prefswindow);
}


void template_edit_callback(struct prefs_windata *pw)
{
     GqServer *server;
     const char *servername, *templatename;

     if (pw->schemaserver == NULL)
	  return;

     if( (servername = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(pw->schemaserver)->entry))) == NULL)
	  return;

     if( (server = gq_server_list_get_by_name(gq_server_list_get(), servername)) == NULL)
	  return;

     if (pw->templatelist == NULL)
	  return;

     if( (templatename = get_clist_selection(pw->templatelist)) == NULL)
	  return;

     create_template_edit_window(server, templatename, pw->prefswindow);

}

void
template_selected_callback(GtkWidget           * clist  G_GNUC_UNUSED,
			   gint                  row    G_GNUC_UNUSED,
			   gint                  column G_GNUC_UNUSED,
			   GdkEventButton      * event,
			   struct prefs_windata* data)
{
     if (event) {
	  if(event->type == GDK_2BUTTON_PRESS) {
	       template_edit_callback(data);
	  }
     }
}

void template_delete_callback(GtkWidget *widget, struct prefs_windata *pw)
{
     GList *list;
     struct gq_template *tmpl;
     char *templatename;

     if( pw->templatelist == NULL)
	  return;

     if( (templatename = get_clist_selection(pw->templatelist)) == NULL)
	  return;

     if( (tmpl = find_template_by_name(templatename))) {
	  int index = g_list_index(config->templates, tmpl);
	  config->templates = g_list_remove(config->templates, tmpl);

	  if (save_config(widget)) {
	       if( (list = GTK_CLIST(pw->templatelist)->selection))
		    gtk_clist_remove(GTK_CLIST(pw->templatelist), 
				     GPOINTER_TO_INT(list->data));
	  } else {
	       /* save failed - undo changes */
	       config->templates = g_list_insert(config->templates, tmpl, index);
	  }
     }
}
#endif

