[Commits] ldap-plugin.c 1.5 1.6
miras at claws-mail.org
miras at claws-mail.org
Sun Nov 20 22:24:22 CET 2011
Update of /home/claws-mail/contacts/plugins/ldap
In directory claws-mail:/tmp/cvs-serv324/plugins/ldap
Modified Files:
ldap-plugin.c
Log Message:
2011-11-20 [mir] 0.6.0cvs22
* plugins/example/example-plugin.c
* plugins/ldap/ldap-plugin.c
* plugins/xml/xml-plugin.c
* src/callbacks.c
* src/callbacks.h
* src/contactwindow.c
* src/mainwindow.h
* src/plugin-loader.c
* src/plugin-loader.h
* src/plugin.h
* src/utils.c
* src/utils.h
Lots of bug fixes, some feature enhancements and complete
read-only support for LDAP with advanced search
capabilities.
Index: ldap-plugin.c
===================================================================
RCS file: /home/claws-mail/contacts/plugins/ldap/ldap-plugin.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- ldap-plugin.c 14 Nov 2011 22:10:55 -0000 1.5
+++ ldap-plugin.c 20 Nov 2011 21:24:20 -0000 1.6
@@ -55,8 +55,10 @@
LDAP* ldap;
GSList* baseDN;
gchar* search_base;
+ gchar* dn;
gint max_entries;
gint timeout;
+ gint error_code;
} Server;
typedef struct {
@@ -130,6 +132,10 @@
if (server->baseDN) {
gslist_free(&server->baseDN, g_free);
}
+ if (server->dn) {
+ g_free(server->dn);
+ server->dn = NULL;
+ }
if (server->search_base) {
g_free(server->search_base);
server->search_base = NULL;
@@ -163,7 +169,7 @@
}
if (abook_con->connection) {
connect_info_free(&abook_con->connection);
- }
+ }
if (abook_con->server) {
deconnect(abook_con->server);
g_free(abook_con->server);
@@ -264,6 +270,27 @@
return info;
}
+static const gchar* get_ldap_error(int rc) {
+ const gchar* error = ldap_err2string(rc);
+
+
+ debug_print("%s\n", error);
+ if (rc == LDAP_TIMELIMIT_EXCEEDED) {
+ show_message(NULL, GTK_UTIL_MESSAGE_WARNING,
+ _("Configured timeout limit exceeded. Try increase timeout on "
+ "advanced configuration page"));
+ error = NULL;
+ }
+ else if (rc == LDAP_SIZELIMIT_EXCEEDED) {
+ show_message(NULL, GTK_UTIL_MESSAGE_WARNING,
+ _("Configured number of entries limit exceeded. Try increase entries on "
+ "advanced configuration page"));
+ error = NULL;
+ }
+
+ return error;
+}
+
static int ldap_bind(AbookConnection* abook_con) {
struct berval cred;
AddressBook* abook = find_addressbook(abook_con);
@@ -308,11 +335,11 @@
for (cur = config; cur; cur = g_slist_next(cur)) {
conf = (ExtraConfig *) cur->data;
if (conf->label && strcasecmp("timeout (sec)", conf->label) == 0)
- (*server)->timeout = conf->default_value.spin_btn;
+ (*server)->timeout = conf->preset_value.spin_btn;
else if (conf->label && strcasecmp("search base", conf->label) == 0)
- (*server)->search_base = g_strdup(conf->default_value.entry);
+ (*server)->search_base = g_strdup(conf->preset_value.entry);
else if (conf->label && strcasecmp("max entries", conf->label) == 0)
- (*server)->max_entries = conf->default_value.spin_btn;
+ (*server)->max_entries = conf->preset_value.spin_btn;
}
gslist_free(&config, extra_config_free);
@@ -328,11 +355,11 @@
for (cur = abook->extra_config; cur; cur = g_slist_next(cur)) {
conf = (ExtraConfig *) cur->data;
if (conf->label && strcasecmp("timeout (sec)", conf->label) == 0)
- server->timeout = conf->value.spin_btn;
+ server->timeout = conf->current_value.spin_btn;
else if (conf->label && strcasecmp("search base", conf->label) == 0)
- server->search_base = g_strdup(conf->value.entry);
+ server->search_base = g_strdup(conf->current_value.entry);
else if (conf->label && strcasecmp("max entries", conf->label) == 0)
- server->max_entries = conf->value.spin_btn;
+ server->max_entries = conf->current_value.spin_btn;
}
return server;
@@ -391,9 +418,9 @@
}
else {
if (error)
- *error = g_strdup(ldap_err2string(rc));
- debug_print("%s\n", ldap_err2string(rc));
- *err = rc;
+ *error = g_strdup(get_ldap_error(rc));
+ if (*error)
+ *err = rc;
}
if (result)
ldap_msgfree(result);
@@ -678,14 +705,14 @@
if (conf) {
switch (conf->type) {
case PLUGIN_CONFIG_EXTRA_CHECKBOX:
- conf->value.check_btn =
+ conf->current_value.check_btn =
(strcmp("true", value) == 0) ? TRUE : FALSE;
break;
case PLUGIN_CONFIG_EXTRA_ENTRY:
- conf->value.entry = g_strdup(value);
+ conf->current_value.entry = g_strdup(value);
break;
case PLUGIN_CONFIG_EXTRA_SPINBUTTON:
- conf->value.spin_btn = atoi(value);
+ conf->current_value.spin_btn = atoi(value);
break;
}
abook->extra_config =
@@ -698,6 +725,9 @@
gslist_free(&values, g_free);
g_strfreev(keys);
}
+ else {
+ address_book_free(&abook);
+ }
return abook;
}
@@ -771,6 +801,71 @@
return g_string_free(filter, FALSE);
}
+static void gslist_free_ldapmessage(GSList** list) {
+ GSList* cur;
+
+ if (! list || ! *list)
+ return;
+
+ cur = *list;
+ while (cur) {
+ LDAPMessage* msg = (LDAPMessage *) cur->data;
+ ldap_msgfree(msg);
+ msg = NULL;
+ cur = cur->next;
+ }
+ g_slist_free(*list);
+ *list = NULL;
+}
+
+static GSList* call_server(Server* server,
+ int scope,
+ const gchar* search_filter,
+ gchar** error) {
+ GSList *cur, *response = NULL;
+ gchar** ldap_attributes;
+ int rc = 0;
+ struct timeval timeOut;
+ LDAPMessage* res = NULL;
+ gint max_size;
+
+ if (server->timeout > 0)
+ timeOut.tv_sec = server->timeout;
+ else
+ timeOut.tv_sec = TIMEOUT;
+ timeOut.tv_usec = 0;
+ max_size = server->max_entries;
+ ldap_attributes = attriblist2ldap();
+
+ if (server->search_base) {
+ rc = ldap_search_ext_s(server->ldap, server->search_base,
+ scope, search_filter, ldap_attributes,
+ 0, NULL, NULL, &timeOut, max_size, &res);
+ if (rc == LDAP_SUCCESS || rc == LDAP_TIMELIMIT_EXCEEDED || LDAP_SIZELIMIT_EXCEEDED)
+ response = g_slist_append(response, res);
+ }
+ else {
+ for (cur = server->baseDN; cur; cur = g_slist_next(cur)) {
+ rc = ldap_search_ext_s(server->ldap, (gchar *) cur->data,
+ scope, search_filter, ldap_attributes,
+ 0, NULL, NULL, &timeOut, max_size, &res);
+ if (rc == LDAP_SUCCESS || rc == LDAP_TIMELIMIT_EXCEEDED || LDAP_SIZELIMIT_EXCEEDED) {
+ response = g_slist_append(response, res);
+ }
+ }
+ }
+
+ g_strfreev(ldap_attributes);
+
+ if (rc) {
+ if (error)
+ *error = g_strdup(get_ldap_error(rc));
+ server->error_code = rc;
+ }
+
+ return response;
+}
+
static GList* fetch_data(Server* server, LDAPMessage* res) {
LDAPMessage* entry;
BerElement* ber;
@@ -789,7 +884,7 @@
contact = contact_new();
value = ldap_get_dn(server->ldap, entry);
debug_print("Found: DN->%s\n", value);
- g_free(value);
+ ldap_memfree(value);
/* Process attributes */
for (attribute = ldap_first_attribute(server->ldap, entry, &ber);
attribute; attribute = ldap_next_attribute(server->ldap, entry, ber)) {
@@ -833,26 +928,77 @@
return result;
}
+static void find_dn(AbookConnection* ac, gchar** error) {
+ GString* filter;
+ GSList *msgs, *cur, *msgs1, *cur1;
+ LDAPMessage *res, *res1, *entry;
+ gchar* search_filter;
+ gchar* tmp;
+ gboolean found = FALSE;
+
+ search_filter = filter_build(ac->contact, ac->intersection);
+ filter = g_string_new("(&");
+ filter = g_string_append(filter, search_filter);
+ g_free(search_filter);
+ search_filter = filter_build_standard();
+ filter = g_string_append(filter, search_filter);
+ filter = g_string_append(filter, ")");
+ g_free(search_filter);
+ search_filter = g_string_free(filter, FALSE);
+ debug_print("Filter: %s\n", search_filter);
+
+ msgs = call_server(ac->server, LDAP_SCOPE_BASE, search_filter, error);
+
+ for (cur = msgs; ! *error && cur && ! found; cur = g_slist_next(cur)) {
+ res = (LDAPMessage *) cur->data;
+ if (res) {
+ entry = ldap_first_entry(ac->server->ldap, res);
+ if (entry) {
+ tmp = ldap_get_dn(ac->server->ldap, entry);
+ debug_print("Useing '%s' as DN for new entries\n", tmp);
+ ac->server->dn = g_strdup(tmp);
+ ldap_memfree(tmp);
+ found = TRUE;
+ }
+ else {
+ msgs1 = call_server(ac->server, LDAP_SCOPE_ONELEVEL, search_filter, error);
+ for (cur1 = msgs1; cur1 && ! found; cur1 = g_slist_next(cur1)) {
+ res1 = (LDAPMessage *) cur1->data;
+ if (res1) {
+ entry = ldap_first_entry(ac->server->ldap, res1);
+ if (entry) {
+ tmp = ldap_get_dn(ac->server->ldap, entry);
+ debug_print("Useing '%s' as DN for new entries\n", tmp);
+ ac->server->dn = g_strdup(tmp);
+ ldap_memfree(tmp);
+ found = TRUE;
+ }
+ else {
+ if (error) {
+ *error = g_strdup_printf(_("%s: Cannot get DN\n"), search_filter);
+ }
+ }
+ }
+ }
+
+ gslist_free_ldapmessage(&msgs1);
+ }
+ }
+ }
+ gslist_free_ldapmessage(&msgs);
+
+ g_free(search_filter);
+}
+
static gboolean fetch_all(AddressBook* book,
AbookConnection* ac,
gchar** error) {
- GSList* cur;
+ GSList *msgs, *cur;
Server* server = ac->server;
- gchar** ldap_attributes;
- int rc = 0;
- struct timeval timeOut;
LDAPMessage* res = NULL;
gchar* search_filter;
GString* filter;
- gint max_size;
- if (server->timeout > 0)
- timeOut.tv_sec = server->timeout;
- else
- timeOut.tv_sec = TIMEOUT;
- timeOut.tv_usec = 0;
- max_size = server->max_entries;
- ldap_attributes = attriblist2ldap();
search_filter = filter_build(ac->contact, ac->intersection);
filter = g_string_new("(&");
filter = g_string_append(filter, search_filter);
@@ -862,46 +1008,26 @@
filter = g_string_append(filter, ")");
g_free(search_filter);
search_filter = g_string_free(filter, FALSE);
- //debug_set_mode(TRUE);
debug_print("Filter: %s\n", search_filter);
- //debug_set_mode(FALSE);
- if (server->search_base) {
- rc = ldap_search_ext_s(server->ldap, server->search_base,
- LDAP_SCOPE_SUBTREE, search_filter, ldap_attributes,
- 0, NULL, NULL, &timeOut, max_size, &res);
- }
- else {
- for (cur = server->baseDN; cur; cur = g_slist_next(cur)) {
- rc = ldap_search_ext_s(server->ldap, (gchar *) cur->data,
- LDAP_SCOPE_SUBTREE, search_filter, ldap_attributes,
- 0, NULL, NULL, &timeOut, max_size, &res);
- if (rc == LDAP_SUCCESS) {
- GList* list = fetch_data(server, res);
- if (list) {
- book->contacts = g_list_concat(book->contacts, list);
- list = NULL;
- }
- }
- if (res)
- ldap_msgfree(res);
- }
- }
- g_free(search_filter);
- book->contacts = fetch_data(server, res);
- //debug_set_mode(FALSE);
- if (res)
- ldap_msgfree(res);
+
+ msgs = call_server(ac->server, LDAP_SCOPE_SUBTREE, search_filter, error);
- g_strfreev(ldap_attributes);
+ g_free(search_filter);
- if (rc) {
- if (error)
- *error = g_strdup(ldap_err2string(rc));
- debug_print("bind: %s\n", ldap_err2string(rc));
- return TRUE;
- }
-
- return FALSE;
+ if (*error) {
+ if (! (ac->server->error_code == LDAP_TIMELIMIT_EXCEEDED ||
+ ac->server->error_code == LDAP_SIZELIMIT_EXCEEDED))
+ goto skip;
+ }
+ for (cur = msgs; cur; cur = g_slist_next(cur)) {
+ res = (LDAPMessage *) cur->data;
+ if (res)
+ book->contacts = g_list_concat(book->contacts, fetch_data(server, res));
+ }
+ skip:
+ gslist_free_ldapmessage(&msgs);
+
+ return (error) ? TRUE : FALSE;
}
static void set_extra_config() {
@@ -920,14 +1046,14 @@
ec->type = PLUGIN_CONFIG_EXTRA_SPINBUTTON;
ec->label = g_strdup(_("Timeout (Sec)"));
ec->tooltip = g_strdup(_("Timeout in seconds. 0 means wait infinite."));
- ec->default_value.spin_btn = 20;
+ ec->preset_value.spin_btn = 20;
extra_config = g_slist_append(extra_config, ec);
ec = g_new0(ExtraConfig, 1);
ec->type = PLUGIN_CONFIG_EXTRA_SPINBUTTON;
ec->label = g_strdup(_("Max entries"));
ec->tooltip = g_strdup(_("Maximum number of contacts to receive. 0 means all."));
- ec->default_value.spin_btn = 30;
+ ec->preset_value.spin_btn = 30;
extra_config = g_slist_append(extra_config, ec);
}
@@ -936,10 +1062,7 @@
* @param error Pointer to memory where error is supposed to be saved
*/
void plugin_reset(gchar** error) {
- if (*error != NULL) {
- g_free(*error);
- *error = NULL;
- }
+ abooks_free();
}
/**
@@ -987,6 +1110,36 @@
}
/**
+ * This macro is borrowed from the Balsa project
+ * Creates a LDAPMod structure
+ *
+ * \param mods Empty LDAPMod structure
+ * \param modarr Array with values to insert
+ * \param op Operation to perform on LDAP
+ * \param attr Attribute to insert
+ * \param strv Empty array which is NULL terminated
+ * \param val Value for attribute
+ */
+#define SETMOD(mods,modarr,op,attr,strv,val) \
+ do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
+ (strv)[0]=(val); (modarr).mod_values=strv; \
+ } while(0)
+
+/**
+ * Creates a LDAPMod structure
+ *
+ * \param mods Empty LDAPMod structure
+ * \param modarr Array with values to insert
+ * \param op Operation to perform on LDAP
+ * \param attr Attribute to insert
+ * \param strv Array with values to insert. Must be NULL terminated
+ */
+#define SETMODS(mods,modarr,op,attr,strv) \
+ do { (mods) = &(modarr); (modarr).mod_type=attr; \
+ (modarr).mod_op=op; (modarr).mod_values=strv; \
+ } while(0)
+
+/**
* Get a contact(s) using a search string.
* @param abook Pointer to AddressBook
* @param search_token Search string
@@ -996,7 +1149,8 @@
GSList* plugin_get_contact(
AddressBook* abook, const gchar* search_token, gchar** error) {
GList* cur;
- GSList *contacts = NULL;
+ GSList *contacts = NULL, *basic, *list;
+ gboolean found = FALSE;
Contact* contact = NULL;
if (abook && search_token) {
@@ -1004,10 +1158,19 @@
contact = (Contact *) cur->data;
if (! contact)
continue;
- /*
- * Iterate contacts in AddressBook and compare basic
- * attributes to search_token
- */
+
+ list = get_basic_attributes(contact);
+ for (basic = list; !found && basic; basic = g_slist_next(basic)) {
+ gchar* attr = (gchar *) basic->data;
+ if (attr) {
+ found = match_string_pattern(search_token, attr, FALSE);
+ }
+ }
+ gslist_free(&list, g_free);
+ if (found) {
+ contacts = g_slist_prepend(contacts, contact);
+ found = FALSE;
+ }
}
}
@@ -1029,17 +1192,32 @@
GList* cur;
GSList *contacts = NULL;
Contact* contact = NULL;
+ Compare* comp;
if (abook && search_tokens && (search_tokens->data || search_tokens->emails)) {
+ comp = g_new0(Compare, 1);
for (cur = abook->contacts; cur; cur = g_list_next(cur)) {
contact = (Contact *) cur->data;
if (! contact)
continue;
- /*
- * Iterate contacts in AddressBook and compare
- * all attributes to search_token
- */
+
+ comp->hash = contact->data;
+ comp->is_and = is_and;
+ comp->equal = -1;
+
+ g_hash_table_foreach(search_tokens->data,
+ contact_compare_values, comp);
+ if ((comp->is_and && comp->equal > 0) ||
+ (comp->equal < 1 && !comp->is_and)) {
+ gint res = email_compare_values(
+ search_tokens->emails, contact->emails, is_and);
+ if (res != -1)
+ comp->equal = res;
+ }
+ if (comp->equal > 0)
+ contacts = g_slist_prepend(contacts, contact);
}
+ g_free(comp);
}
return contacts;
@@ -1130,7 +1308,8 @@
g_list_book_remove(&abooks, abook);
return FALSE;
}
- if (fetch_all(abook, ac, error)) {
+ find_dn(ac, error);
+ if (*error) {
show_message(NULL, GTK_UTIL_MESSAGE_WARNING, "%s", *error);
g_free(*error);
*error = NULL;
@@ -1139,6 +1318,17 @@
g_list_book_remove(&abooks, abook);
return FALSE;
}
+ if (fetch_all(abook, ac, error)) {
+ if (*error) {
+ show_message(NULL, GTK_UTIL_MESSAGE_WARNING, "%s", *error);
+ g_free(*error);
+ *error = NULL;
+ if (removed)
+ closed_books = g_list_prepend(closed_books, abook);
+ g_list_book_remove(&abooks, abook);
+ return FALSE;
+ }
+ }
abook->dirty = FALSE;
}
abook->open = TRUE;
@@ -1215,6 +1405,27 @@
}
/**
+ * Get list of all address book names.
+ * @return GSList* List of AddressBook names
+ */
+GSList* plugin_addrbook_names_all() {
+ GList *list;
+ GSList* names = NULL;
+
+ for (list = abooks; list; list = g_list_next(list)) {
+ AddressBook* book = (AddressBook *) list->data;
+ names = g_slist_prepend(names, g_strdup(book->abook_name));
+ }
+
+ for (list = closed_books; list; list = g_list_next(list)) {
+ AddressBook* book = (AddressBook *) list->data;
+ names = g_slist_prepend(names, g_strdup(book->abook_name));
+ }
+
+ return names;
+}
+
+/**
* Save config for an address book. If new is NULL write config for
* new address book update otherwise.
* @param old Pointer to AddressBook
@@ -1240,8 +1451,11 @@
if (new) {
/* Update config for existing address book */
self->abook_delete(old, error);
- if (*error)
- return TRUE;
+ if (*error) {
+ /* ignore in case we open a previously closed book */
+ g_free(*error);
+ *error = NULL;
+ }
abook = new;
}
else {
@@ -1269,15 +1483,15 @@
switch (conf->type) {
case PLUGIN_CONFIG_EXTRA_CHECKBOX:
g_key_file_set_boolean(config->key_file,
- abook->abook_name, conf->label, conf->value.check_btn);
+ abook->abook_name, conf->label, conf->current_value.check_btn);
break;
case PLUGIN_CONFIG_EXTRA_ENTRY:
g_key_file_set_string(config->key_file,
- abook->abook_name, conf->label, conf->value.entry);
+ abook->abook_name, conf->label, conf->current_value.entry);
break;
case PLUGIN_CONFIG_EXTRA_SPINBUTTON:
g_key_file_set_integer(config->key_file,
- abook->abook_name, conf->label, conf->value.spin_btn);
+ abook->abook_name, conf->label, conf->current_value.spin_btn);
break;
}
}
@@ -1346,6 +1560,7 @@
GSList *cur;
ConfiguredBooks* cf_books;
ClosedBooks* cl_books;
+ gboolean ok = FALSE;
self = (Plugin *) self_ref;
if (*error != NULL) {
@@ -1381,10 +1596,21 @@
if (cf_books) {
for (cur = cf_books->books; cur; cur = g_slist_next(cur)) {
gchar* book = (gchar *) cur->data;
- AddressBook* abook = get_addressbook(book);
- gboolean ok = self->abook_open(abook, error);
- if (! ok)
- closed_books = g_list_prepend(closed_books, abook);
+ if (book) {
+ AddressBook* abook = get_addressbook(book);
+ if (abook) {
+ ok = self->abook_open(abook, error);
+ if (! ok)
+ closed_books = g_list_prepend(closed_books, abook);
+ }
+ else {
+ if (error)
+ *error = g_strconcat(
+ "'", book, "': ",
+ _("Missing matching configuration"),
+ NULL);
+ }
+ }
}
}
if (cl_books) {
@@ -1432,7 +1658,8 @@
return NULL;
}
- feature->support = PLUGIN_READ_WRITE | PLUGIN_ADVANCED_SEARCH;
+ /*feature->support = PLUGIN_READ_WRITE | PLUGIN_ADVANCED_SEARCH;*/
+ feature->support = PLUGIN_READ_ONLY | PLUGIN_ADVANCED_SEARCH;
feature->subtype = subtype;
return feature;
More information about the Commits
mailing list