/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Authors: * Chris Toshok * Chris Lahey **/ /*#define STANDALONE*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "addressbook.h" #include "addressbook-component.h" #include "addressbook-config.h" #include "widgets/misc/e-error.h" #include "evolution-config-control.h" #include #include #ifdef HAVE_LDAP #include "ldap.h" #include "ldap_schema.h" #endif #define LDAP_PORT_STRING "389" #define LDAPS_PORT_STRING "636" #define GLADE_FILE_NAME "ldap-config.glade" #define CONFIG_CONTROL_FACTORY_ID "OAFIID:GNOME_Evolution_Addressbook_ConfigControlFactory:" BASE_VERSION #define LDAP_CONFIG_CONTROL_ID "OAFIID:GNOME_Evolution_LDAPStorage_ConfigControl:" BASE_VERSION 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 { GtkWidget *notebook; int page_num; } FocusHelpClosure; typedef struct _AddressbookSourceDialog AddressbookSourceDialog; typedef void (*ModifyFunc)(GtkWidget *item, AddressbookSourceDialog *dialog); struct _AddressbookSourceDialog { GladeXML *gui; GtkWidget *window; GtkWidget *druid; /* only used (obviously) in the druid */ /* Source selection (druid only) */ ESourceList *source_list; GSList *menu_source_groups; GtkWidget *group_optionmenu; /* ESource we're currently editing (editor only) */ ESource *source; /* Source group we're creating/editing a source in */ ESourceGroup *source_group; /* info page fields */ ModifyFunc general_modify_func; GtkWidget *host; GtkWidget *auth_optionmenu; AddressbookLDAPAuthType auth; GtkWidget *auth_label_notebook; GtkWidget *auth_entry_notebook; GtkWidget *email; GtkWidget *binddn; /* connecting page fields */ ModifyFunc connecting_modify_func; GtkWidget *port_combo; GtkWidget *ssl_optionmenu; AddressbookLDAPSSLType ssl; /* searching page fields */ ModifyFunc searching_modify_func; GtkWidget *rootdn; AddressbookLDAPScopeType scope; GtkWidget *scope_optionmenu; GtkWidget *timeout_scale; GtkWidget *limit_spinbutton; /* new dialog stuff */ GtkWidget *auth_frame; GtkWidget *server_frame; /* display name page fields */ GtkWidget *display_name; gboolean display_name_changed; /* only used in the druid */ gboolean schema_query_successful; /* stuff for the account editor window */ GtkWidget *ok_button; GtkWidget *cancel_button; GtkWidget *advanced_button_notebook; GtkWidget *notebook; /* the toplevel notebook */ gboolean advanced; }; #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_assert(0); return "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_assert(0); return ""; } } 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_assert(0); return ""; } } 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; } #endif static void dialog_to_source (AddressbookSourceDialog *dialog, ESource *source, gboolean temporary) { gchar *str; g_assert (source); e_source_set_name (source, gtk_entry_get_text (GTK_ENTRY (dialog->display_name))); if (!strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) { #ifdef HAVE_LDAP e_source_set_property (source, "email_addr", gtk_entry_get_text (GTK_ENTRY (dialog->email))); e_source_set_property (source, "binddn", gtk_entry_get_text (GTK_ENTRY (dialog->binddn))); str = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->limit_spinbutton))); e_source_set_property (source, "limit", str); g_free (str); str = g_strdup_printf ("%f", gtk_adjustment_get_value (GTK_RANGE(dialog->timeout_scale)->adjustment)); e_source_set_property (source, "timeout", str); g_free (str); e_source_set_property (source, "ssl", ldap_unparse_ssl (dialog->ssl)); e_source_set_property (source, "auth", ldap_unparse_auth (dialog->auth)); str = g_strdup_printf ("%s:%s/%s?" /* trigraph prevention */ "?%s", gtk_entry_get_text (GTK_ENTRY (dialog->host)), gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (dialog->port_combo)->entry)), gtk_entry_get_text (GTK_ENTRY (dialog->rootdn)), ldap_unparse_scope (dialog->scope)); e_source_set_relative_uri (source, str); g_free (str); #endif }else if (g_str_has_prefix (e_source_group_peek_base_uri (dialog->source_group), "groupwise://") && !e_source_peek_group (source)) { /* if this is an existing book we don't change anything else */ GSList *groupwise_source_list; ESource *existing_source = NULL; const char *property_value = NULL; groupwise_source_list = e_source_group_peek_sources(dialog->source_group); if (groupwise_source_list) existing_source = E_SOURCE (groupwise_source_list->data); if (existing_source) { property_value = e_source_get_property (existing_source, "auth"); e_source_set_property (source, "auth", property_value); property_value = e_source_get_property (existing_source, "user"); e_source_set_property (source, "user", property_value); } str = g_strconcat (";", gtk_entry_get_text (GTK_ENTRY (dialog->display_name)), NULL); e_source_set_relative_uri (source, str); g_free (str); } else { const gchar *relative_uri; relative_uri = e_source_peek_relative_uri (source); if (!relative_uri || !strlen (relative_uri)) e_source_set_relative_uri (source, e_source_peek_uid (source)); } if (!temporary) { if (!e_source_peek_group (source)) e_source_group_add_source (dialog->source_group, source, -1); e_source_list_sync (dialog->source_list, NULL); } } static ESource * dialog_to_temp_source (AddressbookSourceDialog *dialog) { ESource *source; source = e_source_new ("", ""); e_source_set_group (source, dialog->source_group); dialog_to_source (dialog, source, TRUE); return source; } #ifdef HAVE_LDAP static gboolean source_to_uri_parts (ESource *source, gchar **host, gchar **rootdn, AddressbookLDAPScopeType *scope, gint *port) { gchar *uri; LDAPURLDesc *lud; gint ldap_error; g_assert (source); 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; ldap_free_urldesc (lud); return TRUE; } #endif #define SOURCE_PROP_STRING(source, prop) \ (source && e_source_get_property (source, prop) ? e_source_get_property (source, prop) : "") static void source_to_dialog_new (AddressbookSourceDialog *dialog) { ESource *source = dialog->source; gtk_entry_set_text (GTK_ENTRY (dialog->display_name), source ? e_source_peek_name (source) : ""); #ifdef HAVE_LDAP gtk_entry_set_text (GTK_ENTRY (dialog->email), SOURCE_PROP_STRING (source, "email_addr")); if (dialog->binddn) gtk_entry_set_text (GTK_ENTRY (dialog->binddn), SOURCE_PROP_STRING (source, "binddn")); gtk_spin_button_set_value ( GTK_SPIN_BUTTON (dialog->limit_spinbutton), g_strtod ( source && e_source_get_property (source, "limit") ? e_source_get_property (source, "limit") : "100", NULL)); gtk_adjustment_set_value (GTK_RANGE(dialog->timeout_scale)->adjustment, g_strtod ( source && e_source_get_property (source, "timeout") ? e_source_get_property (source, "timeout") : "3", NULL)); dialog->auth = source && e_source_get_property (source, "auth") ? ldap_parse_auth (e_source_get_property (source, "auth")) : ADDRESSBOOK_LDAP_AUTH_NONE; dialog->ssl = source && e_source_get_property (source, "ssl") ? ldap_parse_ssl (e_source_get_property (source, "ssl")) : ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE; if (source && !strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) { gchar *host; gchar *rootdn; AddressbookLDAPScopeType scope; gint port; if (source_to_uri_parts (source, &host, &rootdn, &scope, &port)) { gchar *port_str; gtk_entry_set_text (GTK_ENTRY (dialog->host), host); gtk_entry_set_text (GTK_ENTRY (dialog->rootdn), rootdn); dialog->scope = scope; port_str = g_strdup_printf ("%d", port); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (dialog->port_combo)->entry), port_str); g_free (port_str); g_free (host); g_free (rootdn); } } gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->auth_optionmenu), dialog->auth); gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->scope_optionmenu), dialog->scope); gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->ssl_optionmenu), dialog->ssl); #endif } static void source_to_dialog (AddressbookSourceDialog *dialog) { ESource *source = dialog->source; gtk_entry_set_text (GTK_ENTRY (dialog->display_name), source ? e_source_peek_name (source) : ""); #ifdef HAVE_LDAP gtk_entry_set_text (GTK_ENTRY (dialog->email), SOURCE_PROP_STRING (source, "email_addr")); gtk_entry_set_text (GTK_ENTRY (dialog->binddn), SOURCE_PROP_STRING (source, "binddn")); gtk_spin_button_set_value ( GTK_SPIN_BUTTON (dialog->limit_spinbutton), g_strtod ( source && e_source_get_property (source, "limit") ? e_source_get_property (source, "limit") : "100", NULL)); gtk_adjustment_set_value (GTK_RANGE(dialog->timeout_scale)->adjustment, g_strtod ( source && e_source_get_property (source, "timeout") ? e_source_get_property (source, "timeout") : "3", NULL)); dialog->auth = source && e_source_get_property (source, "auth") ? ldap_parse_auth (e_source_get_property (source, "auth")) : ADDRESSBOOK_LDAP_AUTH_NONE; dialog->ssl = source && e_source_get_property (source, "ssl") ? ldap_parse_ssl (e_source_get_property (source, "ssl")) : ADDRESSBOOK_LDAP_SSL_WHENEVER_POSSIBLE; if (source && !strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) { gchar *host; gchar *rootdn; AddressbookLDAPScopeType scope; gint port; if (source_to_uri_parts (source, &host, &rootdn, &scope, &port)) { gchar *port_str; gtk_entry_set_text (GTK_ENTRY (dialog->host), host); gtk_entry_set_text (GTK_ENTRY (dialog->rootdn), rootdn); dialog->scope = scope; port_str = g_strdup_printf ("%d", port); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (dialog->port_combo)->entry), port_str); g_free (port_str); g_free (host); g_free (rootdn); } } gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->auth_optionmenu), dialog->auth); if (dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE) { gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->auth_entry_notebook), dialog->auth - 1); } gtk_widget_set_sensitive (dialog->auth_entry_notebook, dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE); gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->scope_optionmenu), dialog->scope); gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->ssl_optionmenu), dialog->ssl); #endif } #ifdef HAVE_LDAP /* ldap api foo */ static LDAP * addressbook_ldap_init (GtkWidget *window, ESource *source) { LDAP *ldap; gchar *host; gint port; if (!source_to_uri_parts (source, &host, NULL, NULL, &port)) return NULL; if (!(ldap = ldap_init (host, port))) e_error_run ((GtkWindow *) window, "addressbook:ldap-init", NULL); /* XXX do TLS if it's configured in */ 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, GtkWindow *window, 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 ((GtkWindow *) window, "addressbook:ldap-search-base", NULL); return ldap_error; } #endif static void addressbook_source_dialog_destroy (gpointer data, GObject *where_object_was) { AddressbookSourceDialog *dialog = data; g_object_unref (dialog->gui); g_object_unref (dialog->source_list); g_slist_free (dialog->menu_source_groups); g_free (dialog); } static void addressbook_add_server_dialog_finish (GtkWidget *widget, AddressbookSourceDialog *sdialog) { sdialog->source = e_source_new ("", ""); dialog_to_source (sdialog, sdialog->source, FALSE); /* tear down the widgets */ gtk_widget_destroy (sdialog->window); } static void addressbook_add_server_dialog_cancel (GtkWidget *widget, AddressbookSourceDialog *dialog) { gtk_widget_destroy (dialog->window); } static void auth_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog) { dialog->auth = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)), item); dialog->general_modify_func (item, dialog); if (dialog->auth == 0) { gtk_widget_set_sensitive (dialog->auth_entry_notebook, FALSE); } else { gtk_widget_set_sensitive (dialog->auth_entry_notebook, TRUE); gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->auth_entry_notebook), dialog->auth - 1); } } static void add_auth_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog) { g_signal_connect (item, "activate", G_CALLBACK (auth_optionmenu_activated), dialog); } static void setup_general_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func) { GtkWidget *menu; dialog->general_modify_func = modify_func; dialog->host = glade_xml_get_widget (dialog->gui, "server-name-entry"); g_signal_connect (dialog->host, "changed", G_CALLBACK (modify_func), dialog); dialog->auth_entry_notebook = glade_xml_get_widget (dialog->gui, "auth-entry-notebook"); dialog->email = glade_xml_get_widget (dialog->gui, "email-entry"); g_signal_connect (dialog->email, "changed", G_CALLBACK (modify_func), dialog); dialog->binddn = glade_xml_get_widget (dialog->gui, "dn-entry"); if (dialog->binddn) g_signal_connect (dialog->binddn, "changed", G_CALLBACK (modify_func), dialog); dialog->auth_optionmenu = glade_xml_get_widget (dialog->gui, "auth-optionmenu"); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->auth_optionmenu)); gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_auth_activate_cb, dialog); } static gboolean general_tab_check (AddressbookSourceDialog *dialog) { gboolean valid = TRUE; const char *string; if (strcmp ("ldap://", e_source_group_peek_base_uri (dialog->source_group))) return TRUE; string = gtk_entry_get_text (GTK_ENTRY (dialog->host)); if (!string || !string[0]) valid = FALSE; if (valid) { if (dialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE) { if (dialog->auth == ADDRESSBOOK_LDAP_AUTH_SIMPLE_BINDDN) string = gtk_entry_get_text (GTK_ENTRY (dialog->binddn)); else string = gtk_entry_get_text (GTK_ENTRY (dialog->email)); if (!string || !string[0]) valid = FALSE; } } return valid; } /* connecting page */ static void ssl_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog) { dialog->ssl = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)), item); dialog->connecting_modify_func (item, dialog); } static void add_ssl_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog) { g_signal_connect (item, "activate", G_CALLBACK (ssl_optionmenu_activated), dialog); } static void port_changed_func (GtkWidget *item, AddressbookSourceDialog *dialog) { /* if the port value is ldaps, set the SSL/TLS option menu to Always and desensitize it */ const char *string = gtk_entry_get_text (GTK_ENTRY (item)); dialog->connecting_modify_func (item, dialog); if (!strcmp (string, LDAPS_PORT_STRING)) { dialog->ssl = ADDRESSBOOK_LDAP_SSL_ALWAYS; gtk_option_menu_set_history (GTK_OPTION_MENU(dialog->ssl_optionmenu), dialog->ssl); gtk_widget_set_sensitive (dialog->ssl_optionmenu, FALSE); } else { gtk_widget_set_sensitive (dialog->ssl_optionmenu, TRUE); } } static void setup_connecting_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func) { GtkWidget *menu; dialog->connecting_modify_func = modify_func; dialog->port_combo = glade_xml_get_widget (dialog->gui, "port-combo"); g_signal_connect (GTK_COMBO(dialog->port_combo)->entry, "changed", G_CALLBACK (modify_func), dialog); g_signal_connect (GTK_COMBO(dialog->port_combo)->entry, "changed", G_CALLBACK (port_changed_func), dialog); dialog->ssl_optionmenu = glade_xml_get_widget (dialog->gui, "ssl-optionmenu"); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->ssl_optionmenu)); gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_ssl_activate_cb, dialog); } static gboolean connecting_tab_check (AddressbookSourceDialog *dialog) { gboolean valid = TRUE; const char *string; string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO(dialog->port_combo)->entry)); if (!string || !string[0]) valid = FALSE; return valid; } #ifdef HAVE_LDAP /* searching page */ static ETableMemoryStoreColumnInfo bases_table_columns[] = { E_TABLE_MEMORY_STORE_STRING, E_TABLE_MEMORY_STORE_TERMINATOR }; #define BASES_TABLE_SPEC \ " \ \ \ \ \ \ " GtkWidget* supported_bases_create_table (char *name, char *string1, char *string2, int num1, int num2) { GtkWidget *table; ETableModel *model; model = e_table_memory_store_new (bases_table_columns); table = e_table_scrolled_new (model, NULL, BASES_TABLE_SPEC, NULL); g_object_set_data (G_OBJECT (table), "model", model); return table; } static gboolean do_ldap_root_dse_query (AddressbookSourceDialog *sdialog, GtkWidget *dialog, ETableModel *model, ESource *source, char ***rvalues) { LDAP *ldap; char *attrs[2]; int ldap_error; char **values; LDAPMessage *resp; int i; ldap = addressbook_ldap_init (dialog, source); if (!ldap) return FALSE; if (LDAP_SUCCESS != addressbook_ldap_auth (dialog, ldap)) goto fail; attrs[0] = "namingContexts"; attrs[1] = NULL; ldap_error = addressbook_root_dse_query (sdialog, GTK_WINDOW (dialog), ldap, attrs, &resp); if (ldap_error != LDAP_SUCCESS) goto fail; values = ldap_get_values (ldap, resp, "namingContexts"); if (!values || values[0] == NULL) { e_error_run ((GtkWindow *) dialog, "addressbook:ldap-search-base", NULL); goto fail; } for (i = 0; values[i]; i++) e_table_memory_store_insert (E_TABLE_MEMORY_STORE (model), -1, GINT_TO_POINTER(i), values[i]); *rvalues = values; ldap_unbind_s (ldap); return TRUE; fail: ldap_unbind_s (ldap); return FALSE; } static void search_base_selection_model_changed (ESelectionModel *selection_model, GtkWidget *dialog) { gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, e_selection_model_selected_count (selection_model) == 1); } static void query_for_supported_bases (GtkWidget *button, AddressbookSourceDialog *sdialog) { ESelectionModel *selection_model; ESource *source; GtkWidget *dialog; GtkWidget *supported_bases_table; ETableModel *model; GladeXML *gui; int id; char **values; source = dialog_to_temp_source (sdialog); gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "supported-bases-dialog", NULL); dialog = glade_xml_get_widget (gui, "supported-bases-dialog"); gtk_widget_realize (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 (supported_bases_table); selection_model = e_table_get_selection_model (e_table_scrolled_get_table (E_TABLE_SCROLLED(supported_bases_table))); model = g_object_get_data (G_OBJECT (supported_bases_table), "model"); g_signal_connect (selection_model, "selection_changed", G_CALLBACK (search_base_selection_model_changed), dialog); search_base_selection_model_changed (selection_model, dialog); if (do_ldap_root_dse_query (sdialog, dialog, model, source, &values)) { id = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_hide (dialog); if (id == GTK_RESPONSE_OK) { int i; /* OK was clicked */ /* ugh. */ for (i = 0; values[i]; i ++) { if (e_selection_model_is_row_selected (selection_model, i)) { gtk_entry_set_text (GTK_ENTRY (sdialog->rootdn), values[i]); break; /* single selection, so we can quit when we've found it. */ } } } ldap_value_free (values); e_table_memory_store_clear (E_TABLE_MEMORY_STORE (model)); } g_object_unref (source); } static void scope_optionmenu_activated (GtkWidget *item, AddressbookSourceDialog *dialog) { dialog->scope = g_list_index (gtk_container_get_children (GTK_CONTAINER (item->parent)), item); if (dialog->searching_modify_func) dialog->searching_modify_func (item, dialog); } static void add_scope_activate_cb (GtkWidget *item, AddressbookSourceDialog *dialog) { g_signal_connect (item, "activate", G_CALLBACK (scope_optionmenu_activated), dialog); } static void setup_searching_tab (AddressbookSourceDialog *dialog, ModifyFunc modify_func) { GtkWidget *menu; GtkWidget *rootdn_button; dialog->searching_modify_func = modify_func; dialog->rootdn = glade_xml_get_widget (dialog->gui, "rootdn-entry"); if (modify_func) g_signal_connect (dialog->rootdn, "changed", G_CALLBACK (modify_func), dialog); dialog->scope_optionmenu = glade_xml_get_widget (dialog->gui, "scope-optionmenu"); menu = gtk_option_menu_get_menu (GTK_OPTION_MENU(dialog->scope_optionmenu)); gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback)add_scope_activate_cb, dialog); dialog->timeout_scale = glade_xml_get_widget (dialog->gui, "timeout-scale"); if (modify_func) g_signal_connect (GTK_RANGE(dialog->timeout_scale)->adjustment, "value_changed", G_CALLBACK (modify_func), dialog); dialog->limit_spinbutton = glade_xml_get_widget (dialog->gui, "download-limit-spinbutton"); if (modify_func) g_signal_connect (dialog->limit_spinbutton, "changed", G_CALLBACK (modify_func), dialog); /* special handling for the "Show Supported Bases button" */ rootdn_button = glade_xml_get_widget (dialog->gui, "rootdn-button"); g_signal_connect (rootdn_button, "clicked", G_CALLBACK(query_for_supported_bases), dialog); } static gboolean searching_tab_check (AddressbookSourceDialog *dialog) { gboolean valid = TRUE; gdouble timeout = 3; timeout = gtk_adjustment_get_value (GTK_RANGE(dialog->timeout_scale)->adjustment); if(!timeout) return FALSE; return valid; } #endif /* display name page */ static gboolean display_name_check (AddressbookSourceDialog *dialog) { gboolean valid = TRUE; const char *string; string = gtk_entry_get_text (GTK_ENTRY (dialog->display_name)); if (!string || !string[0]) valid = FALSE; return valid; } static gboolean source_group_is_remote (ESourceGroup *group) { return !strcmp ("ldap://", e_source_group_peek_base_uri (group)); } static void add_folder_modify (GtkWidget *widget, AddressbookSourceDialog *sdialog) { gboolean valid = TRUE; gboolean remote = FALSE; valid = display_name_check (sdialog); remote = source_group_is_remote (sdialog->source_group); remote = source_group_is_remote (sdialog->source_group); if (sdialog->server_frame) gtk_widget_set_sensitive (sdialog->server_frame, remote); if (sdialog->auth_frame) gtk_widget_set_sensitive (sdialog->auth_frame, remote); #ifdef HAVE_LDAP gtk_widget_set_sensitive (sdialog->email, sdialog->auth != ADDRESSBOOK_LDAP_AUTH_NONE); if (valid) valid = general_tab_check (sdialog); if (valid) valid = connecting_tab_check (sdialog); gtk_widget_set_sensitive (glade_xml_get_widget (sdialog->gui, "details-label"), valid && remote); gtk_widget_set_sensitive (glade_xml_get_widget (sdialog->gui, "details-vbox"), valid && remote); if (valid) valid = searching_tab_check (sdialog); #endif gtk_widget_set_sensitive (sdialog->ok_button, valid); } static void source_group_changed_cb (GtkWidget *widget, AddressbookSourceDialog *sdialog) { sdialog->source_group = g_slist_nth (sdialog->menu_source_groups, gtk_option_menu_get_history (GTK_OPTION_MENU (sdialog->group_optionmenu)))->data; if (sdialog->auth_frame) add_folder_modify (widget, sdialog); } static void source_group_menu_add_groups (GtkMenuShell *menu_shell, ESourceList *source_list) { GSList *groups, *sl; groups = e_source_list_peek_groups (source_list); for (sl = groups; sl; sl = g_slist_next (sl)) { GtkWidget *menu_item; ESourceGroup *group = sl->data; #ifndef HAVE_LDAP /* If LDAP isn't configured, skip LDAP groups */ if (!strcmp ("ldap://", e_source_group_peek_base_uri (group))) continue; #endif menu_item = gtk_menu_item_new_with_label (e_source_group_peek_name (group)); gtk_widget_show (menu_item); gtk_menu_shell_append (menu_shell, menu_item); if (!strcmp ("exchange://", e_source_group_peek_base_uri (group))) gtk_widget_set_sensitive (menu_item, FALSE); } } static AddressbookSourceDialog * addressbook_add_server_dialog (void) { AddressbookSourceDialog *sdialog = g_new0 (AddressbookSourceDialog, 1); GConfClient *gconf_client; GSList *source_groups; sdialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "account-add-window", NULL); sdialog->window = glade_xml_get_widget (sdialog->gui, "account-add-window"); sdialog->display_name = glade_xml_get_widget (sdialog->gui, "display-name-entry"); g_signal_connect (sdialog->display_name, "changed", G_CALLBACK (add_folder_modify), sdialog); gconf_client = gconf_client_get_default (); sdialog->source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources"); source_groups = e_source_list_peek_groups (sdialog->source_list); sdialog->menu_source_groups = g_slist_copy (source_groups); #ifndef HAVE_LDAP for ( ; source_groups != NULL; source_groups = g_slist_next (source_groups)) if (!strcmp ("ldap://", e_source_group_peek_base_uri (source_groups->data))) sdialog->menu_source_groups = g_slist_remove (sdialog->menu_source_groups, source_groups->data); #endif sdialog->group_optionmenu = glade_xml_get_widget (sdialog->gui, "group-optionmenu"); if (!GTK_IS_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (sdialog->group_optionmenu)))) { GtkWidget *menu = gtk_menu_new (); gtk_option_menu_set_menu (GTK_OPTION_MENU (sdialog->group_optionmenu), menu); gtk_widget_show (menu); } /* NOTE: This assumes that we have sources. If they don't exist, they're set up * on startup of the Addressbook component. */ source_group_menu_add_groups (GTK_MENU_SHELL (gtk_option_menu_get_menu ( GTK_OPTION_MENU (sdialog->group_optionmenu))), sdialog->source_list); gtk_option_menu_set_history (GTK_OPTION_MENU (sdialog->group_optionmenu), 0); sdialog->source_group = e_source_list_peek_groups (sdialog->source_list)->data; g_signal_connect (sdialog->group_optionmenu, "changed", G_CALLBACK (source_group_changed_cb), sdialog); setup_general_tab (sdialog, add_folder_modify); #ifdef HAVE_LDAP setup_searching_tab (sdialog, add_folder_modify); #endif setup_connecting_tab (sdialog, add_folder_modify); sdialog->auth_frame = glade_xml_get_widget (sdialog->gui, "authentication-frame"); sdialog->server_frame = glade_xml_get_widget (sdialog->gui, "server-frame"); sdialog->ok_button = glade_xml_get_widget (sdialog->gui, "ok-button"); g_signal_connect (sdialog->ok_button, "clicked", G_CALLBACK(addressbook_add_server_dialog_finish), sdialog); sdialog->cancel_button = glade_xml_get_widget (sdialog->gui, "cancel-button"); g_signal_connect (sdialog->cancel_button, "clicked", G_CALLBACK(addressbook_add_server_dialog_cancel), sdialog); g_object_weak_ref (G_OBJECT (sdialog->window), addressbook_source_dialog_destroy, sdialog); g_object_unref (gconf_client); /* make sure we fill in the default values */ source_to_dialog_new (sdialog); gtk_window_set_type_hint (GTK_WINDOW (sdialog->window), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_modal (GTK_WINDOW (sdialog->window), TRUE); add_folder_modify (sdialog->window, sdialog); gtk_widget_show_all (sdialog->window); return sdialog; } static void editor_modify_cb (GtkWidget *item, AddressbookSourceDialog *dialog) { gboolean valid = TRUE; valid = display_name_check (dialog); #ifdef HAVE_LDAP if (valid) valid = general_tab_check (dialog); if (valid) valid = connecting_tab_check (dialog); if (valid) valid = searching_tab_check (dialog); #endif gtk_widget_set_sensitive (dialog->ok_button, valid); } static void set_advanced_button_state (AddressbookSourceDialog *dialog) { if (dialog->advanced) { gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->advanced_button_notebook), 0); #ifdef NEW_ADVANCED_UI gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->objectclasses_tab, dialog->objectclasses_label); gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->mappings_tab, dialog->mappings_label); gtk_notebook_append_page (GTK_NOTEBOOK(dialog->notebook), dialog->dn_customization_tab, dialog->dn_customization_label); #endif } else { #ifdef NEW_ADVANCED_UI gtk_notebook_set_current_page (GTK_NOTEBOOK(dialog->advanced_button_notebook), 1); /* hide the advanced tabs of the main notebook */ gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 5); gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 4); gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 3); #endif } } #ifdef NEW_ADVANCED_UI static void advanced_button_clicked (GtkWidget *button, AddressbookSourceDialog *dialog) { dialog->advanced = !dialog->advanced; set_advanced_button_state (dialog); } static gboolean do_schema_query (AddressbookSourceDialog *sdialog) { LDAP *ldap; int ldap_error; char *schema_dn; char *attrs[3]; char **values; int i; AddressbookSource *source = addressbook_dialog_get_source (sdialog); LDAPMessage *resp; struct timeval timeout; ldap = addressbook_ldap_init (sdialog->window, source); if (!ldap) goto fail; if (LDAP_SUCCESS != addressbook_ldap_auth (sdialog->window, source, ldap)) goto fail; attrs[0] = "subschemaSubentry"; attrs[1] = NULL; ldap_error = addressbook_root_dse_query (sdialog->window, source, ldap, attrs, &resp); if (ldap_error != LDAP_SUCCESS) goto fail; values = ldap_get_values (ldap, resp, "subschemaSubentry"); if (!values || values[0] == NULL) { e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-v3-schema", NULL); goto fail; } schema_dn = g_strdup (values[0]); ldap_value_free (values); ldap_msgfree (resp); attrs[0] = "objectClasses"; attrs[1] = NULL; timeout.tv_sec = (gint) gtk_adjustment_get_value (GTK_RANGE(sdialog->timeout_scale)->adjustment); timeout.tv_usec = 0; ldap_error = ldap_search_ext_s (ldap, schema_dn, LDAP_SCOPE_BASE, "(objectClass=subschema)", attrs, 0, NULL, NULL, &timeout, LDAP_NO_LIMIT, &resp); if (LDAP_SUCCESS != ldap_error) { e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-get-schema", NULL); goto fail; } if (!(values = ldap_get_values (ldap, resp, "objectClasses"))) { e_error_run ((GtkWindow *) sdialog->window, "addressbook:ldap-invalid-schema", NULL); goto fail; } for (i = 0; values[i]; i ++) { int j; int code; const char *err; LDAPObjectClass *oc = ldap_str2objectclass (values[i], &code, &err, 0); if (!oc) continue; /* we fill in the default list of classes here */ for (j = 0; oc->oc_names[j]; j ++) { if (!g_strcasecmp (oc->oc_names[j], EVOLUTIONPERSON) || !g_strcasecmp (oc->oc_names[j], INETORGPERSON) || !g_strcasecmp (oc->oc_names[j], ORGANIZATIONALPERSON) || !g_strcasecmp (oc->oc_names[j], PERSON) || !g_strcasecmp (oc->oc_names[j], CALENTRY) || !g_strcasecmp (oc->oc_names[j], TOP)) g_ptr_array_add (sdialog->default_objectclasses, oc); } g_ptr_array_add (sdialog->server_objectclasses, oc); } addressbook_source_free (source); ldap_unbind_s (ldap); return TRUE; fail: addressbook_source_free (source); if (ldap) ldap_unbind_s (ldap); return FALSE; } static void edit_dialog_switch_page (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, AddressbookSourceDialog *sdialog) { if (page_num >= 3 && !sdialog->schema_query_successful) { int i; gtk_widget_set_sensitive (GTK_WIDGET (notebook), FALSE); sdialog->schema_query_successful = do_schema_query (sdialog); if (sdialog->schema_query_successful) { /* fill in the objectclasses model */ for (i = 0; i < sdialog->server_objectclasses->len; i ++) { LDAPObjectClass *oc = g_ptr_array_index (sdialog->server_objectclasses, i); e_table_memory_store_insert (E_TABLE_MEMORY_STORE (sdialog->objectclasses_server_model), -1, oc, oc->oc_names[0]); } gtk_widget_set_sensitive (page->child, TRUE); } else { gtk_widget_set_sensitive (page->child, FALSE); } gtk_widget_set_sensitive (GTK_WIDGET (notebook), TRUE); } } #endif static gboolean edit_dialog_store_change (AddressbookSourceDialog *sdialog) { dialog_to_source (sdialog, sdialog->source, FALSE); /* check the display name for uniqueness */ if (FALSE /* XXX */) { return FALSE; } return TRUE; } static void edit_dialog_cancel_clicked (GtkWidget *item, AddressbookSourceDialog *sdialog) { gtk_widget_destroy (sdialog->window); } static void edit_dialog_ok_clicked (GtkWidget *item, AddressbookSourceDialog *sdialog) { if (edit_dialog_store_change (sdialog)) { gtk_widget_destroy (sdialog->window); } } void addressbook_config_edit_source (GtkWidget *parent, ESource *source) { AddressbookSourceDialog *sdialog = g_new0 (AddressbookSourceDialog, 1); GConfClient *gconf_client; gconf_client = gconf_client_get_default (); sdialog->source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources"); g_object_unref (gconf_client); sdialog->gui = glade_xml_new (EVOLUTION_GLADEDIR "/" GLADE_FILE_NAME, "account-editor-window", NULL); sdialog->window = glade_xml_get_widget (sdialog->gui, "account-editor-window"); gtk_widget_realize (sdialog->window); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->vbox), 0); gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (sdialog->window)->action_area), 12); sdialog->source = source; sdialog->source_group = e_source_peek_group (source); sdialog->display_name = glade_xml_get_widget (sdialog->gui, "account-editor-display-name-entry"); g_signal_connect (sdialog->display_name, "changed", G_CALLBACK (editor_modify_cb), sdialog); #ifdef HAVE_LDAP setup_general_tab (sdialog, editor_modify_cb); setup_connecting_tab (sdialog, editor_modify_cb); setup_searching_tab (sdialog, editor_modify_cb); #endif sdialog->notebook = glade_xml_get_widget (sdialog->gui, "account-editor-notebook"); sdialog->ok_button = glade_xml_get_widget (sdialog->gui, "account-editor-ok-button"); sdialog->cancel_button = glade_xml_get_widget (sdialog->gui, "account-editor-cancel-button"); #ifdef HAVE_LDAP if (strcmp ("ldap://", e_source_group_peek_base_uri (sdialog->source_group))) { gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox")); gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox")); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdialog->notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (sdialog->notebook), FALSE); gtk_container_set_border_width (GTK_CONTAINER (glade_xml_get_widget (sdialog->gui, "account-editor-general-vbox")), 0); gtk_window_set_default_size (GTK_WINDOW (sdialog->window), 332, 124); } else { gtk_widget_show (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox")); gtk_widget_show (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox")); } #else gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-connecting-vbox")); gtk_widget_hide (glade_xml_get_widget (sdialog->gui, "account-editor-searching-vbox")); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sdialog->notebook), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (sdialog->notebook), FALSE); gtk_container_set_border_width (GTK_CONTAINER (glade_xml_get_widget (sdialog->gui, "account-editor-general-vbox")), 0); #endif source_to_dialog (sdialog); set_advanced_button_state (sdialog); g_signal_connect (sdialog->ok_button, "clicked", G_CALLBACK(edit_dialog_ok_clicked), sdialog); g_signal_connect (sdialog->cancel_button, "clicked", G_CALLBACK(edit_dialog_cancel_clicked), sdialog); g_object_weak_ref (G_OBJECT (sdialog->window), addressbook_source_dialog_destroy, sdialog); gtk_widget_set_sensitive (sdialog->ok_button, FALSE); gtk_window_set_modal (GTK_WINDOW (sdialog->window), TRUE); gtk_widget_show (sdialog->window); } void addressbook_config_create_new_source (GtkWidget *parent) { AddressbookSourceDialog *dialog; dialog = addressbook_add_server_dialog (); }