/* * 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 * * * Authors: * Chris Toshok * Chris Lahey * Michael Zucchi * And no doubt others ... * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ /*#define STANDALONE*/ #include #include #include #include #include #include #ifdef G_OS_WIN32 /* Include early and work around DATADIR lossage */ #define DATADIR crap_DATADIR #include #undef DATADIR #endif #include #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 #ifndef SUNLDAP #include #endif #else #include #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 (_("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:"")); /* 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; }