[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