/* * Copyright (C) 2005 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #ifdef __sun #include #endif #include #include #include #include #include "gconf/gconf.h" #include "gconf/gconf-backend.h" #include "gconf/gconf-internals.h" typedef struct { GConfSource source; char *conf_file; char *ldap_host; int ldap_port; char *base_dn; char *filter_str; xmlDocPtr xml_doc; xmlNodePtr template_account; xmlNodePtr template_addressbook; xmlNodePtr template_calendar; xmlNodePtr template_tasks; LDAP *connection; GConfValue *accounts_value; GConfValue *addressbook_value; GConfValue *calendar_value; GConfValue *tasks_value; guint conf_file_parsed : 1; guint queried_ldap : 1; } EvoSource; static void x_shutdown (GError **err); static GConfSource *resolve_address (const char *address, GError **err); static void lock (GConfSource *source, GError **err); static void unlock (GConfSource *source, GError **err); static gboolean readable (GConfSource *source, const char *key, GError **err); static gboolean writable (GConfSource *source, const char *key, GError **err); static GConfValue *query_value (GConfSource *source, const char *key, const char **locales, char **schema_name, GError **err); static GConfMetaInfo *query_metainfo (GConfSource *source, const char *key, GError **err); static void set_value (GConfSource *source, const char *key, const GConfValue *value, GError **err); static GSList *all_entries (GConfSource *source, const char *dir, const char **locales, GError **err); static GSList *all_subdirs (GConfSource *source, const char *dir, GError **err); static void unset_value (GConfSource *source, const char *key, const char *locale, GError **err); static gboolean dir_exists (GConfSource *source, const char *dir, GError **err); static void remove_dir (GConfSource *source, const char *dir, GError **err); static void set_schema (GConfSource *source, const char *key, const char *schema_key, GError **err); static gboolean sync_all (GConfSource *source, GError **err); static void destroy_source (GConfSource *source); static void clear_cache (GConfSource *source); static void blow_away_locks (const char *address); static GConfBackendVTable evoldap_vtable = { sizeof (GConfBackendVTable), x_shutdown, resolve_address, lock, unlock, readable, writable, query_value, query_metainfo, set_value, all_entries, all_subdirs, unset_value, dir_exists, remove_dir, set_schema, sync_all, destroy_source, clear_cache, blow_away_locks, NULL, /* set_notify_func */ NULL, /* add_listener */ NULL /* remove_listener */ }; static void x_shutdown (GError **err) { } static GConfSource * resolve_address (const char *address, GError **err) { EvoSource *esource; char *conf_file; if ((conf_file = gconf_address_resource (address)) == NULL) { g_set_error (err, GCONF_ERROR, GCONF_ERROR_BAD_ADDRESS, _("Failed to get configuration file path from '%s'"), address); return NULL; } esource = g_new0 (EvoSource, 1); esource->conf_file = conf_file; esource->source.flags = GCONF_SOURCE_ALL_READABLE | GCONF_SOURCE_NEVER_WRITEABLE; gconf_log (GCL_DEBUG, _("Created Evolution/LDAP source using configuration file '%s'"), esource->conf_file); return (GConfSource *) esource; } static void lock (GConfSource *source, GError **err) { } static void unlock (GConfSource *source, GError **err) { } static gboolean readable (GConfSource *source, const char *key, GError **err) { return TRUE; } static gboolean writable (GConfSource *source, const char *key, GError **err) { return FALSE; } /* * Taken from evolution/e-util/e-uid.c */ static char * get_evolution_uid (void) { static char *hostname; static int serial; if (!hostname) { static char buffer [512]; if ((gethostname (buffer, sizeof (buffer) - 1) == 0) && (buffer [0] != 0)) hostname = buffer; else hostname = "localhost"; } return g_strdup_printf ("%lu.%lu.%d@%s", (unsigned long) time (NULL), (unsigned long) getpid (), serial++, hostname); } static char * get_variable (const char *varname, LDAP *connection, LDAPMessage *entry) { BerElement *berptr; const char *attr; char *retval; if (strcmp (varname, "USER") == 0) return g_strdup (g_get_user_name ()); if (strcmp (varname, "EVOLUTION_UID") == 0) return get_evolution_uid (); if (connection == NULL || entry == NULL) return g_strdup (""); if (strncmp (varname, "LDAP_ATTR_", 10) != 0) return g_strdup (""); varname += 10; retval = NULL; berptr = NULL; attr = ldap_first_attribute (connection, entry, &berptr); while (attr != NULL && retval == NULL) { struct berval **values; if (strcmp (attr, varname) == 0) { values = ldap_get_values_len (connection, entry, attr); if (values != NULL && values[0] != NULL) retval = g_strdup (values[0]->bv_val); ldap_value_free_len (values); } attr = ldap_next_attribute (connection, entry, berptr); } ber_free (berptr, 0); return retval ? retval : g_strdup (""); } /* * Copied from gconf/gconf-internals.c */ static char * subst_variables (const char *src, LDAP *connection, LDAPMessage *entry) { const char *iter; char *retval; guint retval_len; guint pos; g_return_val_if_fail (src != NULL, NULL); retval_len = strlen (src) + 1; pos = 0; retval = g_malloc0 (retval_len + 3); /* add 3 just to avoid off-by-one segvs - yeah I know it bugs you, but C sucks */ iter = src; while (*iter) { gboolean performed_subst = FALSE; if (pos >= retval_len) { retval_len *= 2; retval = g_realloc (retval, retval_len+3); /* add 3 for luck */ } if (*iter == '$' && *(iter + 1) == '(') { const char *varstart = iter + 2; const char *varend = strchr (varstart, ')'); if (varend != NULL) { char *varname; char *varval; guint varval_len; performed_subst = TRUE; varname = g_strndup (varstart, varend - varstart); varval = get_variable (varname, connection, entry); g_free (varname); varval_len = strlen (varval); if ((retval_len - pos) < varval_len) { retval_len = pos + varval_len; retval = g_realloc (retval, retval_len+3); } strcpy (&retval[pos], varval); g_free(varval); pos += varval_len; iter = varend + 1; } } if (!performed_subst) { retval[pos] = *iter; ++pos; ++iter; } } retval[pos] = '\0'; return retval; } static void parse_server_info (xmlNodePtr node, char **host, char **base_dn, int *port) { const char *node_name = (const char *) node->name; g_assert (strcmp (node_name, "server") == 0); node = node->children; while (node != NULL) { node_name = (const char *) node->name; if (strcmp (node_name, "host") == 0) { xmlChar *host_value; host_value = xmlNodeGetContent (node); g_free (*host); *host = g_strdup ((char *) host_value); xmlFree (host_value); } else if (strcmp (node_name, "port") == 0) { xmlChar *port_value; if ((port_value = xmlNodeGetContent (node)) != NULL) { char *end; long l; end = NULL; l = strtol ((char *) port_value, &end, 10); if (end != NULL && end != (char *)port_value && *end == '\0') *port = (int) l; xmlFree (port_value); } } else if (strcmp (node_name, "base_dn") == 0) { xmlChar *base_dn_value; base_dn_value = xmlNodeGetContent (node); g_free (*base_dn); *base_dn = g_strdup ((char *) base_dn_value); if (base_dn_value != NULL) xmlFree (base_dn_value); } node = node->next; } } static gboolean parse_conf_file (EvoSource *esource, GError **err) { xmlDocPtr doc; xmlNodePtr node; xmlNodePtr template; xmlChar *filter_str; char *contents; gsize length; if (esource->conf_file_parsed) return TRUE; length = 0; contents = NULL; if (!g_file_get_contents (esource->conf_file, &contents, &length, err)) return FALSE; doc = xmlParseMemory (contents, length); g_free (contents); if (doc == NULL) { g_set_error (err, GCONF_ERROR, GCONF_ERROR_PARSE_ERROR, _("Unable to parse XML file '%s'"), esource->conf_file); return FALSE; } if (doc->children == NULL) { g_set_error (err, GCONF_ERROR, GCONF_ERROR_PARSE_ERROR, _("Config file '%s' is empty"), esource->conf_file); xmlFreeDoc (doc); return FALSE; } node = doc->children; if (strcmp ((char *) node->name, "evoldap") != 0) { g_set_error (err, GCONF_ERROR, GCONF_ERROR_PARSE_ERROR, _("Root node of '%s' must be , not <%s>"), esource->conf_file, node->name); xmlFreeDoc (doc); return FALSE; } esource->xml_doc = doc; esource->conf_file_parsed = TRUE; g_assert (esource->ldap_host == NULL); g_assert (esource->base_dn == NULL); esource->ldap_port = 389; /* standard LDAP port number */ template = NULL; node = node->children; while (node != NULL) { const char *node_name = (const char *) node->name; if (strcmp (node_name, "server") == 0) { parse_server_info (node, &esource->ldap_host, &esource->base_dn, &esource->ldap_port); } else if (strcmp (node_name, "template") == 0) { template = node; } node = node->next; } if (template == NULL) { gconf_log (GCL_ERR, _("No