/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) version 3.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
* Authors:
* Chris Toshok <toshok@ximian.com>
* Chris Lahey <clahey@ximian.com>
* Michael Zucchi <notzed@ximian.com>
* And no doubt others ...
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
/*#define STANDALONE*/
#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#ifdef G_OS_WIN32
/* Include <windows.h> early and work around DATADIR lossage */
#define DATADIR crap_DATADIR
#include <windows.h>
#undef DATADIR
#endif
#include <glade/glade.h>
#include "addressbook.h"
#include "addressbook-config.h"
#include "e-util/e-error.h"
#include "e-util/e-util-private.h"
#include "addressbook/gui/widgets/eab-config.h"
#define d(x)
#ifdef HAVE_LDAP
#ifndef G_OS_WIN32
#include <ldap.h>
#ifndef SUNLDAP
#include <ldap_schema.h>
#endif
#else
#include <winldap.h>
#include "openldap-extract.h"
#endif
#endif
#define LDAP_PORT_STRING "389"
#define LDAPS_PORT_STRING "636"
#define GLADE_FILE_NAME "ldap-config.glade"
GtkWidget* supported_bases_create_table (char *name, char *string1, char *string2,
int num1, int num2);
/* default objectclasses */
#define TOP "top"
#define PERSON "person"
#define ORGANIZATIONALPERSON "organizationalPerson"
#define INETORGPERSON "inetOrgPerson"
#define EVOLUTIONPERSON "evolutionPerson"
#define CALENTRY "calEntry"
typedef struct _AddressbookSourceDialog AddressbookSourceDialog;
struct _AddressbookSourceDialog {
GladeXML *gui;
EABConfig *config; /* the config manager */
GtkWidget *window;
/* Source selection (druid only) */
ESourceList *source_list;
GSList *menu_source_groups;
GtkWidget *group_optionmenu;
/* ESource we're currently editing */
ESource *source;
/* The original source in edit mode. Also used to flag when we are in edit mode. */
ESource *original_source;
/* Source group we're creating/editing a source in */
ESourceGroup *source_group;
/* info page fields */
GtkWidget *host;
GtkWidget *auth_optionmenu;
AddressbookLDAPAuthType auth;
GtkWidget *auth_principal;
/* connecting page fields */
GtkWidget *port_combo;
GtkWidget *ssl_optionmenu;
AddressbookLDAPSSLType ssl;
/* searching page fields */
GtkWidget *rootdn;
AddressbookLDAPScopeType scope;
GtkWidget *scope_optionmenu;
GtkWidget *search_filter;
GtkWidget *timeout_scale;
GtkWidget *limit_spinbutton;
GtkWidget *canbrowsecheck;
/* display name page fields */
GtkWidget *display_name;
};
#ifdef HAVE_LDAP
static char *
ldap_unparse_auth (AddressbookLDAPAuthType auth_type)
{
switch (auth_type) {
case ADDRESSBOOK_LDAP_AUTH_NONE:
return "none";
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
return "ldap/simple-email";
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
return "ldap/simple-binddn";
default:
g_return_val_if_reached ("none");
}
}
static AddressbookLDAPAuthType
ldap_parse_auth (const char *auth)
{
if (!auth)
return ADDRESSBOOK_LDAP_AUTH_NONE;
if (!strcmp (auth, "ldap/simple-email") || !strcmp (auth, "simple"))
return ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL;
else if (!strcmp (auth, "ldap/simple-binddn"))
return ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN;
else
return ADDRESSBOOK_LDAP_AUTH_NONE;
}
static char *
ldap_unparse_scope (AddressbookLDAPScopeType scope_type)
{
switch (scope_type) {
case ADDRESSBOOK_LDAP_SCOPE_BASE:
return "base";
case ADDRESSBOOK_LDAP_SCOPE_ONELEVEL:
return "one";
case ADDRESSBOOK_LDAP_SCOPE_SUBTREE:
return "sub";
default:
g_return_val_if_reached ("");
}
}
static char *
ldap_unparse_ssl (AddressbookLDAPSSLType ssl_type)
{
switch (ssl_type) {
case ADDRESSBOOK_LDAP_SSL_NEVER:
return "never";
case ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE:
return "whenever_possible";
case ADDRESSBOOK_LDAP_SSL_ALWAYS:
return "always";
default:
g_return_val_if_reached ("");
}
}
static AddressbookLDAPSSLType
ldap_parse_ssl (const char *ssl)
{
if (!ssl)
return ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE; /* XXX good default? */
if (!strcmp (ssl, "always"))
return ADDRESSBOOK_LDAP_SSL_ALWAYS;
else if (!strcmp (ssl, "never"))
return ADDRESSBOOK_LDAP_SSL_NEVER;
else
return ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE;
}
static gboolean
source_to_uri_parts (ESource *source, gchar **host, gchar **rootdn, AddressbookLDAPScopeType *scope, gchar **search_filter, gint *port)
{
gchar *uri;
LDAPURLDesc *lud;
gint ldap_error;
g_return_val_if_fail (source, FALSE);
uri = e_source_get_uri (source);
ldap_error = ldap_url_parse ((gchar *) uri, &lud);
g_free (uri);
if (ldap_error != LDAP_SUCCESS)
return FALSE;
if (host)
*host = g_strdup (lud->lud_host ? lud->lud_host : "");
if (rootdn)
*rootdn = g_strdup (lud->lud_dn ? lud->lud_dn : "");
if (port)
*port = lud->lud_port ? lud->lud_port : LDAP_PORT;
if (scope)
*scope = lud->lud_scope == LDAP_SCOPE_BASE ? ADDRESSBOOK_LDAP_SCOPE_BASE :
lud->lud_scope == LDAP_SCOPE_ONELEVEL ? ADDRESSBOOK_LDAP_SCOPE_ONELEVEL :
lud->lud_scope == LDAP_SCOPE_SUBTREE ? ADDRESSBOOK_LDAP_SCOPE_SUBTREE :
ADDRESSBOOK_LDAP_SCOPE_ONELEVEL;
if (search_filter && lud->lud_filter)
*search_filter = g_strdup (lud->lud_filter);
ldap_free_urldesc (lud);
return TRUE;
}
static gboolean
source_group_is_remote (ESourceGroup *group)
{
return strncmp ("ldap:", e_source_group_peek_base_uri (group), 5) == 0;
}
/* ldap api foo */
static LDAP *
addressbook_ldap_init (GtkWidget *window, ESource *source)
{
LDAP *ldap;
gchar *host;
gint port;
int ldap_error;
int protocol_version = LDAP_VERSION3;
if (!source_to_uri_parts (source, &host, NULL, NULL, NULL, &port))
return NULL;
if (!(ldap = ldap_init (host, port))) {
e_error_run ((GtkWindow *) window, "addressbook:ldap-init", NULL);
goto done;
}
ldap_error = ldap_set_option (ldap, LDAP_OPT_PROTOCOL_VERSION, &protocol_version);
if (LDAP_SUCCESS != ldap_error)
g_warning ("failed to set protocol version to LDAPv3");
/* XXX do TLS if it's configured in */
done:
g_free (host);
return ldap;
}
static gint
addressbook_ldap_auth (GtkWidget *window, LDAP *ldap)
{
gint ldap_error;
/* XXX use auth info from source */
ldap_error = ldap_simple_bind_s (ldap, NULL, NULL);
if (LDAP_SUCCESS != ldap_error)
e_error_run ((GtkWindow *) window, "addressbook:ldap-auth", NULL);
return ldap_error;
}
static int
addressbook_root_dse_query (AddressbookSourceDialog *dialog, LDAP *ldap,
char **attrs, LDAPMessage **resp)
{
int ldap_error;
struct timeval timeout;
timeout.tv_sec = (gint) gtk_adjustment_get_value (GTK_RANGE(dialog->timeout_scale)->adjustment);
timeout.tv_usec = 0;
ldap_error = ldap_search_ext_s (ldap,
LDAP_ROOT_DSE, LDAP_SCOPE_BASE,
"(objectclass=*)",
attrs, 0, NULL, NULL, &timeout, LDAP_NO_LIMIT, resp);
if (LDAP_SUCCESS != ldap_error)
e_error_run (GTK_WINDOW (dialog->window), "addressbook:ldap-search-base", NULL);
return ldap_error;
}
/* searching page */
GtkWidget*
supported_bases_create_table (char *name, char *string1, char *string2, int num1, int num2)
{
GtkWidget *table, *scrolled;
GtkTreeSelection *selection;
GtkCellRenderer *renderer;
GtkListStore *model;
scrolled = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN);
model = gtk_list_store_new (1, G_TYPE_STRING);
table = gtk_tree_view_new_with_model ((GtkTreeModel *) model);
g_object_unref (model);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes ((GtkTreeView *) table, -1, _("Base"), renderer, "text", 0, NULL);
gtk_tree_view_set_headers_visible ((GtkTreeView *) table, FALSE);
selection = gtk_tree_view_get_selection ((GtkTreeView *) table);
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
gtk_container_add (GTK_CONTAINER (scrolled), table);
g_object_set_data((GObject *)scrolled, "table", table);
return scrolled;
}
static gboolean
do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, GtkListStore *model, ESource *source)
{
LDAP *ldap;
char *attrs[2];
int ldap_error;
char **values;
LDAPMessage *resp;
int i;
ldap = addressbook_ldap_init (sdialog->window, source);
if (!ldap)
return FALSE;
if (LDAP_SUCCESS != addressbook_ldap_auth (sdialog->window, ldap))
goto fail;
attrs[0] = "namingContexts";
attrs[1] = NULL;
ldap_error = addressbook_root_dse_query (sdialog, ldap, attrs, &resp);
if (ldap_error != LDAP_SUCCESS)
goto fail;
values = ldap_get_values (ldap, resp, "namingContexts");
if (!values || values[0] == NULL || strlen (values[0]) == 0) {
e_error_run (GTK_WINDOW (sdialog->window), "addressbook:ldap-search-base", NULL);
goto fail;
}
for (i = 0; values[i]; i++) {
GtkTreeIter iter;
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, 0, values[i], -1);
}
ldap_value_free (values);
ldap_unbind_s (ldap);
return TRUE;
fail:
ldap_unbind_s (ldap);
return FALSE;
}
static void
search_base_selection_model_changed (GtkTreeSelection *selection, GtkWidget *dialog)
{
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
gtk_tree_selection_get_selected(selection, NULL, NULL));
}
static void
query_for_supported_bases (GtkWidget *button, AddressbookSourceDialog *sdialog)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeView *table;
GtkWidget *dialog;
GtkWidget *supported_bases_table;
GladeXML *gui;
GtkTreeIter iter;
char *gladefile;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, "supported-bases-dialog", NULL);
g_free (gladefile);
dialog = glade_xml_get_widget (gui, "supported-bases-dialog");
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (sdialog->window));
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_widget_ensure_style (dialog);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 0);
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12);
supported_bases_table = glade_xml_get_widget (gui, "supported-bases-table");
gtk_widget_show_all (supported_bases_table);
table = g_object_get_data (G_OBJECT (supported_bases_table), "table");
model = gtk_tree_view_get_model (table);
selection = gtk_tree_view_get_selection (table);
g_signal_connect (selection, "changed", G_CALLBACK (search_base_selection_model_changed), dialog);
search_base_selection_model_changed (selection, dialog);
if (do_ldap_root_dse_query (sdialog, GTK_LIST_STORE (model), sdialog->source)) {
gtk_widget_show (dialog);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK
&& gtk_tree_selection_get_selected (selection, &model, &iter)) {
char *dn;
gtk_tree_model_get (model, &iter, 0, &dn, -1);
gtk_entry_set_text((GtkEntry *)sdialog->rootdn, dn);
g_free(dn);
}
}
gtk_widget_destroy (dialog);
}
#endif /* HAVE_LDAP */
GtkWidget*
addressbook_config_create_new_source (GtkWidget *parent)
{
return addressbook_config_edit_source(parent, NULL);
}
/* ********************************************************************** */
static void
eabc_type_changed(GtkComboBox *dropdown, AddressbookSourceDialog *sdialog)
{
int id = gtk_combo_box_get_active(dropdown);
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_combo_box_get_model(dropdown);
if (id == -1 || !gtk_tree_model_iter_nth_child(model, &iter, NULL, id))
return;
/* TODO: when we change the group type, we lose all of the pre-filled dialog info */
gtk_tree_model_get(model, &iter, 1, &sdialog->source_group, -1);
/* HACK: doesn't work if you don't do this */
e_source_set_absolute_uri(sdialog->source, NULL);
e_source_set_group(sdialog->source, sdialog->source_group);
/* BIG HACK: We load the defaults for each type here.
I guess plugins will have to use the do it in their factory callbacks */
if (!strncmp(e_source_group_peek_base_uri(sdialog->source_group), "groupwise:", 10)) {
GSList *l;
ESource *source;
char *tmp;
l = e_source_group_peek_sources(sdialog->source_group);
if (l && l->data ) {
source = l->data;
e_source_set_property(sdialog->source, "auth", e_source_get_property(source, "auth"));
e_source_set_property(sdialog->source, "user", e_source_get_property(source, "user"));
e_source_set_property(sdialog->source, "user_ssl", e_source_get_property(source, "use_ssl"));
}
e_source_set_property(sdialog->source, "auth-domain", "Groupwise");
tmp = g_strconcat (";", e_source_peek_name(sdialog->source), NULL);
e_source_set_relative_uri (sdialog->source, tmp);
g_free (tmp);
#ifdef HAVE_LDAP
} else if (!strncmp(e_source_group_peek_base_uri(sdialog->source_group), "ldap:", 5)) {
char *tmp;
tmp = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s",
"", LDAP_PORT_STRING,
"",
"one");
e_source_set_relative_uri (sdialog->source, tmp);
g_free (tmp);
e_source_set_property(sdialog->source, "timeout", "3");
e_source_set_property(sdialog->source, "limit", "100");
#endif
} else {
e_source_set_relative_uri (sdialog->source, e_source_peek_uid (sdialog->source));
}
e_config_target_changed((EConfig *)sdialog->config, E_CONFIG_TARGET_CHANGED_REBUILD);
}
static GtkWidget *
eabc_general_type(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
GtkComboBox *dropdown;
GtkCellRenderer *cell;
GtkListStore *store;
GtkTreeIter iter;
GSList *l;
GtkWidget *w, *label;
int i, row = 0;
if (old)
return old;
w = gtk_hbox_new(FALSE, 6);
label = gtk_label_new_with_mnemonic(_("_Type:"));
gtk_box_pack_start((GtkBox *)w, label, FALSE, FALSE, 0);
dropdown = (GtkComboBox *)gtk_combo_box_new();
cell = gtk_cell_renderer_text_new();
store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
i = 0;
for (l=sdialog->menu_source_groups;l;l=g_slist_next(l)) {
ESourceGroup *group = l->data;
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, e_source_group_peek_name(group), 1, group, -1);
if (e_source_peek_group(sdialog->source) == group)
row = i;
i++;
}
gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE);
gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL);
gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store);
gtk_combo_box_set_active(dropdown, -1);
gtk_combo_box_set_active(dropdown, row);
g_signal_connect(dropdown, "changed", G_CALLBACK(eabc_type_changed), sdialog);
gtk_widget_show((GtkWidget *)dropdown);
gtk_box_pack_start((GtkBox *)w, (GtkWidget *)dropdown, TRUE, TRUE, 0);
gtk_label_set_mnemonic_widget((GtkLabel *)label, (GtkWidget *)dropdown);
gtk_box_pack_start((GtkBox *)parent, (GtkWidget *)w, FALSE, FALSE, 0);
gtk_widget_show_all(w);
return (GtkWidget *)w;
}
static void
name_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
e_source_set_name (sdialog->source, gtk_entry_get_text (GTK_ENTRY (sdialog->display_name)));
}
static void
offline_status_changed_cb (GtkWidget *widget, AddressbookSourceDialog *sdialog)
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
e_source_set_property (sdialog->source, "offline_sync", "1");
else
e_source_set_property (sdialog->source, "offline_sync", "0");
}
static GtkWidget *
eabc_general_name(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
const char *uri;
GtkWidget *w;
GladeXML *gui;
char *gladefile;
if (old)
return old;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, item->label, NULL);
g_free (gladefile);
w = glade_xml_get_widget(gui, item->label);
gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
sdialog->display_name = glade_xml_get_widget (gui, "account-editor-display-name-entry");
g_signal_connect(sdialog->display_name, "changed", G_CALLBACK(name_changed_cb), sdialog);
gtk_entry_set_text((GtkEntry *)sdialog->display_name, e_source_peek_name(sdialog->source));
/* Hardcoded: groupwise can't edit the name (or anything else) */
if (sdialog->original_source) {
uri = e_source_group_peek_base_uri (sdialog->source_group);
if (uri && strncmp(uri, "groupwise:", 10) == 0) {
gtk_widget_set_sensitive (GTK_WIDGET(sdialog->display_name), FALSE);
}
}
g_object_unref(gui);
return w;
}
static GtkWidget *
eabc_general_offline(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
GtkWidget *offline_setting;
const char *offline_sync;
gboolean is_local_book;
is_local_book = g_str_has_prefix (e_source_group_peek_base_uri (sdialog->source_group), "file:");
offline_sync = e_source_get_property (sdialog->source, "offline_sync");
if (old)
return old;
else {
offline_setting = gtk_check_button_new_with_mnemonic (N_("Copy _book content locally for offline operation"));
gtk_widget_show (offline_setting);
gtk_container_add (GTK_CONTAINER (parent), offline_setting);
g_signal_connect (offline_setting, "toggled", G_CALLBACK (offline_status_changed_cb), sdialog);
}
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (offline_setting), (offline_sync && g_str_equal (offline_sync, "1")) ? TRUE : FALSE);
if (is_local_book)
gtk_widget_hide (offline_setting);
return offline_setting;
}
#ifdef HAVE_LDAP
static gchar *
form_ldap_search_filter (GtkWidget *w)
{
gchar *filter;
const gchar *search_filter = gtk_entry_get_text ((GtkEntry *) w);
/* this function can be used to format the search filter entered */
if ((strlen (search_filter) !=0) && *search_filter != '(' && *(search_filter + (strlen (search_filter-1))) != ')')
filter = g_strdup_printf ("(%s)", search_filter);
else
filter = g_strdup_printf ("%s", search_filter);
return filter;
}
static void
url_changed(AddressbookSourceDialog *sdialog)
{
gchar *str, *search_filter;
search_filter = form_ldap_search_filter (sdialog->search_filter);
str = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s?%s",
gtk_entry_get_text (GTK_ENTRY (sdialog->host)),
gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (sdialog->port_combo)->entry)),
gtk_entry_get_text (GTK_ENTRY (sdialog->rootdn)),
ldap_unparse_scope (sdialog->scope),
search_filter);
e_source_set_relative_uri (sdialog->source, str);
g_free (search_filter);
g_free (str);
}
static void
host_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
url_changed(sdialog);
}
static void
port_entry_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
const char *port = gtk_entry_get_text((GtkEntry *)w);
if (!strcmp (port, LDAPS_PORT_STRING)) {
sdialog->ssl = ADDRESSBOOK_LDAP_SSL_ALWAYS;
gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->ssl_optionmenu), sdialog->ssl);
gtk_widget_set_sensitive (sdialog->ssl_optionmenu, FALSE);
} else {
gtk_widget_set_sensitive (sdialog->ssl_optionmenu, TRUE);
}
url_changed(sdialog);
}
static void
ssl_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
sdialog->ssl = gtk_option_menu_get_history((GtkOptionMenu *)w);
e_source_set_property (sdialog->source, "ssl", ldap_unparse_ssl (sdialog->ssl));
}
static GtkWidget *
eabc_general_host(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
const char *tmp;
GtkWidget *w;
char *uri, port[16];
LDAPURLDesc *lud;
GladeXML *gui;
char *gladefile;
if (!source_group_is_remote(sdialog->source_group))
return NULL;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, item->label, NULL);
g_free (gladefile);
w = glade_xml_get_widget(gui, item->label);
gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
uri = e_source_get_uri(sdialog->source);
if (ldap_url_parse(uri, &lud) != LDAP_SUCCESS)
lud = NULL;
g_free(uri);
sdialog->host = glade_xml_get_widget (gui, "server-name-entry");
gtk_entry_set_text((GtkEntry *)sdialog->host, lud && lud->lud_host ? lud->lud_host : "");
g_signal_connect (sdialog->host, "changed", G_CALLBACK (host_changed_cb), sdialog);
sdialog->port_combo = glade_xml_get_widget (gui, "port-combo");
sprintf(port, "%u", lud && lud->lud_port? lud->lud_port : LDAP_PORT);
gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (sdialog->port_combo)->entry), port);
g_signal_connect (GTK_COMBO(sdialog->port_combo)->entry, "changed", G_CALLBACK (port_entry_changed_cb), sdialog);
if (lud)
ldap_free_urldesc (lud);
sdialog->ssl_optionmenu = glade_xml_get_widget (gui, "ssl-optionmenu");
tmp = e_source_get_property (sdialog->source, "ssl");
sdialog->ssl = tmp ? ldap_parse_ssl (tmp) : ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE;
gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->ssl_optionmenu), sdialog->ssl);
gtk_widget_set_sensitive (sdialog->ssl_optionmenu, strcmp (port, LDAPS_PORT_STRING) != 0);
g_signal_connect(sdialog->ssl_optionmenu, "changed", G_CALLBACK(ssl_optionmenu_changed_cb), sdialog);
g_object_unref(gui);
return w;
}
static void
auth_entry_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
const char *principal = gtk_entry_get_text((GtkEntry *)w);
/* seems messy ... but the api is */
switch (sdialog->auth) {
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
e_source_set_property(sdialog->source, "email_addr", NULL);
e_source_set_property(sdialog->source, "binddn", principal);
break;
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
e_source_set_property(sdialog->source, "binddn", NULL);
e_source_set_property(sdialog->source, "email_addr", principal);
break;
case ADDRESSBOOK_LDAP_AUTH_NONE:
default:
e_source_set_property(sdialog->source, "email_addr", NULL);
e_source_set_property(sdialog->source, "binddn", NULL);
break;
}
}
static void
auth_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
sdialog->auth = gtk_option_menu_get_history((GtkOptionMenu *)w);
e_source_set_property (sdialog->source, "auth", ldap_unparse_auth (sdialog->auth));
/* make sure the right property is set for the auth - ugh, funny api */
auth_entry_changed_cb(sdialog->auth_principal, sdialog);
}
static GtkWidget *
eabc_general_auth(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
GtkWidget *w;
const char *tmp;
GladeXML *gui;
char *gladefile;
if (!source_group_is_remote(sdialog->source_group))
return NULL;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, item->label, NULL);
g_free (gladefile);
w = glade_xml_get_widget(gui, item->label);
gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
sdialog->auth_optionmenu = glade_xml_get_widget (gui, "auth-optionmenu");
tmp = e_source_get_property(sdialog->source, "auth");
sdialog->auth = tmp ? ldap_parse_auth(tmp) : ADDRESSBOOK_LDAP_AUTH_NONE;
gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->auth_optionmenu), sdialog->auth);
g_signal_connect(sdialog->auth_optionmenu, "changed", G_CALLBACK(auth_optionmenu_changed_cb), sdialog);
sdialog->auth_principal = glade_xml_get_widget (gui, "auth-entry");
switch (sdialog->auth) {
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
tmp = e_source_get_property(sdialog->source, "email_addr");
break;
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
tmp = e_source_get_property(sdialog->source, "binddn");
break;
case ADDRESSBOOK_LDAP_AUTH_NONE:
default:
tmp = "";
break;
}
gtk_entry_set_text((GtkEntry *)sdialog->auth_principal, tmp?tmp:"");
g_signal_connect (sdialog->auth_principal, "changed", G_CALLBACK (auth_entry_changed_cb), sdialog);
g_object_unref(gui);
return w;
}
static void
rootdn_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
url_changed(sdialog);
}
static void
search_filter_changed_cb (GtkWidget *w, AddressbookSourceDialog *sdialog)
{
url_changed (sdialog);
}
static void
scope_optionmenu_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
sdialog->scope = gtk_option_menu_get_history((GtkOptionMenu *)w);
url_changed(sdialog);
}
static GtkWidget *
eabc_details_search(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
GtkWidget *w;
LDAPURLDesc *lud;
char *uri;
GladeXML *gui;
char *gladefile;
if (!source_group_is_remote(sdialog->source_group))
return NULL;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, item->label, NULL);
g_free (gladefile);
w = glade_xml_get_widget(gui, item->label);
gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
uri = e_source_get_uri(sdialog->source);
if (ldap_url_parse(uri, &lud) != LDAP_SUCCESS)
lud = NULL;
g_free(uri);
sdialog->rootdn = glade_xml_get_widget (gui, "rootdn-entry");
gtk_entry_set_text((GtkEntry *)sdialog->rootdn, lud && lud->lud_dn ? lud->lud_dn : "");
g_signal_connect (sdialog->rootdn, "changed", G_CALLBACK (rootdn_changed_cb), sdialog);
sdialog->scope_optionmenu = glade_xml_get_widget (gui, "scope-optionmenu");
if (lud) {
switch (lud->lud_scope) {
case LDAP_SCOPE_BASE:
sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_BASE;
break;
default:
case LDAP_SCOPE_ONELEVEL:
sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_ONELEVEL;
break;
case LDAP_SCOPE_SUBTREE:
sdialog->scope = ADDRESSBOOK_LDAP_SCOPE_SUBTREE;
break;
}
}
gtk_option_menu_set_history (GTK_OPTION_MENU(sdialog->scope_optionmenu), sdialog->scope);
g_signal_connect(sdialog->scope_optionmenu, "changed", G_CALLBACK(scope_optionmenu_changed_cb), sdialog);
sdialog->search_filter = glade_xml_get_widget (gui, "search-filter-entry");
gtk_entry_set_text((GtkEntry *)sdialog->search_filter, lud && lud->lud_filter ? lud->lud_filter : "");
g_signal_connect (sdialog->search_filter, "changed", G_CALLBACK (search_filter_changed_cb), sdialog);
g_signal_connect (glade_xml_get_widget(gui, "rootdn-button"), "clicked",
G_CALLBACK(query_for_supported_bases), sdialog);
if (lud)
ldap_free_urldesc (lud);
g_object_unref(gui);
return w;
}
static void
timeout_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
char *timeout;
timeout = g_strdup_printf("%f", gtk_adjustment_get_value(((GtkRange *)sdialog->timeout_scale)->adjustment));
e_source_set_property(sdialog->source, "timeout", timeout);
g_free(timeout);
}
static void
limit_changed_cb(GtkWidget *w, AddressbookSourceDialog *sdialog)
{
char limit[16];
sprintf(limit, "%d", gtk_spin_button_get_value_as_int((GtkSpinButton *)sdialog->limit_spinbutton));
e_source_set_property(sdialog->source, "limit", limit);
}
static void
canbrowse_toggled_cb (GtkWidget *toggle_button, ESource *source)
{
if (!source || !toggle_button)
return;
e_source_set_property (source, "can-browse", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle_button)) ? "1" : NULL);
}
static GtkWidget *
eabc_details_limit(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data)
{
AddressbookSourceDialog *sdialog = data;
GtkWidget *w;
const char *tmp;
GladeXML *gui;
char *gladefile;
if (!source_group_is_remote(sdialog->source_group))
return NULL;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
gui = glade_xml_new (gladefile, item->label, NULL);
g_free (gladefile);
w = glade_xml_get_widget(gui, item->label);
gtk_box_pack_start((GtkBox *)parent, w, FALSE, FALSE, 0);
sdialog->timeout_scale = glade_xml_get_widget (gui, "timeout-scale");
tmp = e_source_get_property(sdialog->source, "timeout");
gtk_adjustment_set_value(((GtkRange *)sdialog->timeout_scale)->adjustment, tmp?g_strtod(tmp, NULL):3.0);
g_signal_connect (GTK_RANGE(sdialog->timeout_scale)->adjustment, "value_changed", G_CALLBACK (timeout_changed_cb), sdialog);
sdialog->limit_spinbutton = glade_xml_get_widget (gui, "download-limit-spinbutton");
tmp = e_source_get_property(sdialog->source, "limit");
gtk_spin_button_set_value((GtkSpinButton *)sdialog->limit_spinbutton, tmp?g_strtod(tmp, NULL):100.0);
g_signal_connect (sdialog->limit_spinbutton, "value_changed", G_CALLBACK (limit_changed_cb), sdialog);
sdialog->canbrowsecheck = glade_xml_get_widget (gui, "canbrowsecheck");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sdialog->canbrowsecheck), e_source_get_property (sdialog->source, "can-browse") && strcmp (e_source_get_property (sdialog->source, "can-browse"), "1") == 0);
g_signal_connect (sdialog->canbrowsecheck, "toggled", G_CALLBACK (canbrowse_toggled_cb), sdialog->source);
g_object_unref(gui);
return w;
}
#endif
static EConfigItem eabc_items[] = {
{ E_CONFIG_BOOK, "", },
{ E_CONFIG_PAGE, "00.general", N_("General") },
{ E_CONFIG_SECTION, "00.general/10.display", N_("Address Book") },
{ E_CONFIG_ITEM, "00.general/10.display/10.name", "hbox122", eabc_general_name },
{ E_CONFIG_ITEM, "00.general/10.display/20.offline", NULL, eabc_general_offline },
#ifdef HAVE_LDAP
{ E_CONFIG_SECTION, "00.general/20.server", N_("Server Information") },
{ E_CONFIG_ITEM, "00.general/20.server/00.host", "table31", eabc_general_host },
{ E_CONFIG_SECTION, "00.general/30.auth", N_("Authentication") },
{ E_CONFIG_ITEM, "00.general/30.auth/00.auth", "table32", eabc_general_auth },
{ E_CONFIG_PAGE, "10.details", N_("Details") },
{ E_CONFIG_SECTION, "10.details/00.search", N_("Searching") },
{ E_CONFIG_ITEM, "10.details/00.search/00.search", "table33", eabc_details_search },
{ E_CONFIG_SECTION, "10.details/10.limit", N_("Downloading") },
{ E_CONFIG_ITEM, "10.details/10.limit/00.limit", "table34", eabc_details_limit },
#endif
{ 0 },
};
/* items needed for the 'new addressbook' window */
static EConfigItem eabc_new_items[] = {
{ E_CONFIG_ITEM, "00.general/10.display/00.type", NULL, eabc_general_type },
{ 0 },
};
static void
eabc_commit(EConfig *ec, GSList *items, void *data)
{
AddressbookSourceDialog *sdialog = data;
xmlNodePtr xml;
#if d(!)0
char *txt;
#endif
if (sdialog->original_source) {
d(printf("committing addressbook changes\n"));
/* these api's kinda suck */
xml = xmlNewNode(NULL, (const unsigned char *)"dummy");
e_source_dump_to_xml_node(sdialog->source, xml);
e_source_update_from_xml_node(sdialog->original_source, xml->children, NULL);
xmlFreeNode(xml);
#if d(!)0
txt = e_source_to_standalone_xml(sdialog->original_source);
printf("source is now:\n%s\n", txt);
g_free(txt);
#endif
} else {
d(printf("committing new source\n"));
e_source_group_add_source(sdialog->source_group, sdialog->source, -1);
e_source_list_sync(sdialog->source_list, NULL);
}
#if d(!)0
txt = e_source_to_standalone_xml(sdialog->source);
printf("running source is now:\n%s\n", txt);
g_free(txt);
#endif
}
static void
eabc_free(EConfig *ec, GSList *items, void *data)
{
AddressbookSourceDialog *sdialog = data;
g_slist_free(items);
g_object_unref(sdialog->source);
if (sdialog->original_source)
g_object_unref(sdialog->original_source);
if (sdialog->source_list)
g_object_unref(sdialog->source_list);
g_slist_free(sdialog->menu_source_groups);
g_object_unref(sdialog->gui);
g_free(sdialog);
}
static gboolean
eabc_check_complete(EConfig *ec, const char *pageid, void *data)
{
AddressbookSourceDialog *sdialog = data;
int valid = TRUE;
const char *tmp;
ESource *source;
d(printf("check complete, pageid = '%s'\n", pageid?pageid:"<all>"));
/* have name, and unique */
tmp = e_source_peek_name(sdialog->source);
valid = tmp && tmp[0] != 0
&& ((source = e_source_group_peek_source_by_name(sdialog->source_group, tmp)) == NULL
|| source == sdialog->original_source);
#ifdef HAVE_LDAP
if (valid && source_group_is_remote(sdialog->source_group)) {
char *uri = e_source_get_uri(sdialog->source);
LDAPURLDesc *lud;
/* check host and port set */
if (ldap_url_parse(uri, &lud) == LDAP_SUCCESS) {
valid = lud->lud_host != NULL
&& lud->lud_host[0] != 0
&& lud->lud_port != 0;
ldap_free_urldesc (lud);
} else
valid = FALSE;
g_free(uri);
/* check auth name provided if auth set */
if (valid && (tmp = e_source_get_property(sdialog->source, "auth"))) {
switch (ldap_parse_auth(tmp)) {
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_EMAIL:
tmp = e_source_get_property(sdialog->source, "email_addr");
break;
case ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN:
tmp = e_source_get_property(sdialog->source, "binddn");
break;
default:
tmp = "dummy";
break;
}
valid = tmp && tmp[0];
}
/* check timeout isn't too short (why don't we just force it?) */
if (valid) {
tmp = e_source_get_property(sdialog->source, "timeout");
valid = tmp && g_strtod(tmp, NULL) > 0.0;
}
}
#endif
return valid;
}
/* debug only: */
#if d(!)0
static void
source_changed(ESource *source, AddressbookSourceDialog *sdialog)
{
char *xml;
xml = e_source_to_standalone_xml(source);
printf("source changed:\n%s\n", xml);
g_free(xml);
}
#endif
GtkWidget*
addressbook_config_edit_source (GtkWidget *parent, ESource *source)
{
AddressbookSourceDialog *sdialog = g_new0 (AddressbookSourceDialog, 1);
EABConfig *ec;
int i;
GSList *items = NULL;
EABConfigTargetSource *target;
char *xml;
char *gladefile;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
GLADE_FILE_NAME,
NULL);
sdialog->gui = glade_xml_new (gladefile, "account-editor-notebook", NULL);
g_free (gladefile);
if (source) {
sdialog->original_source = source;
g_object_ref(source);
sdialog->source_group = e_source_peek_group (source);
xml = e_source_to_standalone_xml(source);
sdialog->source = e_source_new_from_standalone_xml(xml);
g_free(xml);
} else {
GConfClient *gconf;
GSList *l;
sdialog->source = e_source_new("", "");
gconf = gconf_client_get_default();
sdialog->source_list = e_source_list_new_for_gconf(gconf, "/apps/evolution/addressbook/sources");
l = e_source_list_peek_groups(sdialog->source_list);
if (!l) {
g_warning ("Address Book source groups are missing! Check your GConf setup.");
g_object_unref (gconf);
g_free (sdialog);
return NULL;
}
sdialog->menu_source_groups = g_slist_copy(l);
#ifndef HAVE_LDAP
for (;l;l = g_slist_next(l))
if (!strncmp("ldap:", e_source_group_peek_base_uri(l->data), 5))
sdialog->menu_source_groups = g_slist_remove (sdialog->menu_source_groups, l->data);
#endif
sdialog->source_group = (ESourceGroup *)sdialog->menu_source_groups->data;
for (i=0;eabc_new_items[i].path;i++)
items = g_slist_prepend(items, &eabc_new_items[i]);
g_object_unref(gconf);
}
/* HACK: doesn't work if you don't do this */
e_source_set_group(sdialog->source, sdialog->source_group);
#if d(!)0
xml = e_source_to_standalone_xml(sdialog->source);
printf("but working standalone xml: %s\n", xml);
g_free(xml);
g_signal_connect(sdialog->source, "changed", source_changed, sdialog);
#endif
sdialog->config = ec = eab_config_new(E_CONFIG_BOOK, "com.novell.evolution.addressbook.config.accountEditor");
for (i=0;eabc_items[i].path;i++) {
if (eabc_items[i].label)
eabc_items[i].label = gettext(eabc_items[i].label);
items = g_slist_prepend(items, &eabc_items[i]);
}
e_config_add_items((EConfig *)ec, items, eabc_commit, NULL, eabc_free, sdialog);
e_config_add_page_check((EConfig *)ec, NULL, eabc_check_complete, sdialog);
target = eab_config_target_new_source(ec, sdialog->source);
e_config_set_target((EConfig *)ec, (EConfigTarget *)target);
if(source)
sdialog->window = e_config_create_window((EConfig *)ec, NULL, _("Address Book Properties"));
else
sdialog->window = e_config_create_window((EConfig *)ec, NULL, _("New Address Book"));
/* forces initial validation */
if (!sdialog->original_source)
e_config_target_changed((EConfig *)ec, E_CONFIG_TARGET_CHANGED_STATE);
return sdialog->window;
}