[svn-commits] anthonyl: branch group/res_config_ldap r48570 - /team/group/res_config_ldap/res/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Mon Dec 18 15:44:11 MST 2006


Author: anthonyl
Date: Mon Dec 18 16:44:11 2006
New Revision: 48570

URL: http://svn.digium.com/view/asterisk?view=rev&rev=48570
Log:
updated with cthorner's patch which adds update support

Modified:
    team/group/res_config_ldap/res/res_config_ldap.c

Modified: team/group/res_config_ldap/res/res_config_ldap.c
URL: http://svn.digium.com/view/asterisk/team/group/res_config_ldap/res/res_config_ldap.c?view=diff&rev=48570&r1=48569&r2=48570
==============================================================================
--- team/group/res_config_ldap/res/res_config_ldap.c (original)
+++ team/group/res_config_ldap/res/res_config_ldap.c Mon Dec 18 16:44:11 2006
@@ -23,6 +23,7 @@
  *
  * \author Mark Spencer <markster at digium.com>
  * \author Manuel Guesdon
+ * \author Carl-Einar Thorner <cthorner at voicerd.com>
  *
  * \arg http://www.openldap.org
  */
@@ -57,11 +58,11 @@
 AST_MUTEX_DEFINE_STATIC(ldap_lock);
 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
 static LDAP *ldapConn = NULL;
-static char dbhost[512] = "";
-static char dbuser[512] = "";
-static char dbpass[50] = "";
-static char dbbasedn[512] = "";
-static int dbport = 389;
+static char host[512] = "";
+static char user[512] = "";
+static char pass[50] = "";
+static char basedn[512] = "";
+static int port = 389;
 static time_t connect_time = 0;
 
 static int parse_config(void);
@@ -75,11 +76,12 @@
 	int metric;
 	char *variable_name;
 	char *variable_value;
+	int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */
 };
 
 static char cli_realtime_ldap_status_usage[] =
 	"Usage: realtime ldap status\n"
-	"       Shows connection information for the LDAP RealTime driver\n";
+	"		Shows connection information for the LDAP RealTime driver\n";
 
 static struct ast_cli_entry cli_realtime_ldap_status = {
 	{ "realtime", "ldap", "status", NULL }, realtime_ldap_status,
@@ -92,12 +94,16 @@
 	char *table_name;			/*!< table name */
 	char *additional_filter;		/*!< additional filter        */
 	struct ast_variable *attributes;	/*!< attribute names conversion */
+	struct ast_variable *escapes; /*!< characters to escape(i.e., * - the ldap wildchar) */
+	struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
 	struct ldap_table_config *next;		/*!< next entry */
+	
 };
 
 /*! \brief Should be locked before using it */
 static struct ldap_table_config *table_configs = NULL;
 static struct ldap_table_config *base_table_config = NULL;
+static struct ldap_table_config *static_table_config = NULL;
 
 /*! \brief Create a new table_config */
 static struct ldap_table_config *table_config_new(const char *table_name)
@@ -120,6 +126,112 @@
 	}
 	return NULL;
 }
+
+/*! \brief Find variable by name */
+static struct ast_variable *variable_named(struct ast_variable *var,
+					   const char *name)
+{
+	while (var) {
+		if (strcasecmp(name, var->name) == 0)
+			return var;
+		else
+			var = var->next;
+	}
+	return NULL;
+}
+
+/*! \brief for the semicolon delimiter
+	\param somestr - pointer to a string
+
+	\return number of occurances of the delimiter(semicolon)
+ */
+static int semicolon_count_str(const char * somestr){
+	int i=0;
+	int count=0;
+	while (somestr[i] != '\0'){
+		if (somestr[i] == ';'){
+			count++;
+		}
+		i++;
+	}
+	return count;
+} 
+
+/* takes a linked list of \a ast_variable variables, finds the one with the name variable_value
+ * and returns the number of semicolons in the value for that \a ast_variable
+ */
+static int semicolon_count_var(struct ast_variable * var){
+	int count = 0;
+	struct ast_variable * var_value =
+		variable_named(var, "variable_value");
+	if(var_value == NULL)
+		return 0;
+
+	if (option_debug)
+		ast_log(LOG_DEBUG, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
+
+	count = semicolon_count_str(var_value->value);
+
+	return count;
+}
+
+/*! \brief add escape characters to the table config (e.g., the * character)
+ */
+static void ldap_table_config_add_escape(struct ldap_table_config *table_config,
+					    const char *escape_string)
+{
+	if (escape_string && *escape_string) {
+		char *string = strdup(escape_string);
+		char *start = string;
+		if (option_debug)
+			ast_log(LOG_DEBUG, "LDAP RealTime: Add escape: start: %s\n", start);
+		char *p = strstr(start, "=>");
+		if (!p) {
+			ast_log(LOG_WARNING,
+					"LDAP RealTime: Missing '=>' in escape: %s in %s\n",
+					escape_string, table_config->table_name);
+		} else {
+			char *value = p + 2;	//skip =>      
+			// trim !
+			while (isspace(*start))
+				start++;
+			p--;
+			while (p >= start && isspace(*p)) {
+				*p = '\0';
+				p--;
+			}
+			while (isspace(*value))
+				value++;
+			p = value + strlen(value) - 1;
+			while (p >= value && isspace(*p)) {
+				*p = '\0';
+				p--;
+			}
+			if (*start == '\0') {
+				ast_log(LOG_WARNING,
+						"LDAP RealTime: Empty variable name in escape: %s in %s\n",
+						escape_string, table_config->table_name);
+			} else if (*value == '\0') {
+				ast_log(LOG_WARNING,
+						"LDAP RealTime: Empty ldap escape name in escape: %s in %s\n",
+						escape_string, table_config->table_name);
+			} else {
+				struct ast_variable *var = ast_variable_new(start, value);
+				if(option_debug)
+					ast_log(LOG_DEBUG, "LDAP RealTime: Add escape: VAR %s => %s\n",var->name,var->value);
+				if (table_config->escapes)
+					var->next = table_config->escapes;
+				table_config->escapes = var;
+				if(option_debug)
+					ast_log(LOG_DEBUG,
+							"LDAP RealTime (%d): Added escape in %s: %s -> %s\n",
+							__LINE__, table_config->table_name, start, value);
+			}
+		}
+		free(string);
+	}
+}
+					   
 
 /*! \brief add attribute to table config - Should be locked before using it */
 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
@@ -192,6 +304,9 @@
 		if (c->attributes) {
 			ast_variables_destroy(c->attributes);
 		}
+		if (c->escapes) {
+			ast_variables_destroy(c->escapes);
+		};
 		free(c);
 		c = next;
 	}
@@ -247,28 +362,23 @@
 	return attribute_name;
 }
 
-/*! \brief Find variable by name */
-static struct ast_variable *variable_named(struct ast_variable *var,
-					   const char *name)
-{
-	while (var) {
-		if (strcasecmp(name, var->name) == 0)
-			return var;
-		else
-			var = var->next;
-	}
-	return NULL;
-}
-
-/*! \brief Get variables from ldap entry attributes - Should be locked before using it */
+/*! \brief Get variables from ldap entry attributes - Should be locked before using it
+ *
+ *	
+ * \return a linked list of ast_variable variables.
+ **/
 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
 						       LDAPMessage *ldap_entry)
 {
 	BerElement *ber = NULL;
 	struct ast_variable *var = NULL;
 	struct ast_variable *prev = NULL;
+	int is_delimited=0;
+	int i=0;
 
 	char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
+	char *value;
+	int pos=0;
 
 	while (ldap_attribute_name) {
 		const char *attribute_name =
@@ -276,14 +386,14 @@
 		int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
 		char **values = NULL;
 
-		values = ldap_get_values(ldapConn, ldap_entry, ldap_attribute_name);
+		values = ldap_get_values(ldapConn, ldap_entry, ldap_attribute_name);/*these are freed at the end*/
 		if (values) {
 			char **v = values;
 
 			while (*v) {
-				char *value = *v;
+				value = *v;
 				if (option_debug > 1)
-					ast_log(LOG_DEBUG, "attribute_name: %s value: %s\n", attribute_name, value);
+					ast_log(LOG_DEBUG, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, value);
 				if (is_realmed_password_attribute) {
 					if (strncasecmp(value, "{md5}", 5) == 0)
 						value += 5;
@@ -293,12 +403,34 @@
 						ast_log(LOG_DEBUG, "md5: %s\n", value);
 				}
 				if (value) {
+					/* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
+					if( is_delimited != 0){
+						i=0;
+						pos=0;
+						while ( !ast_strlen_zero(value + i) ){
+							if (value[i] == ';'){
+								value[i] = '\0';
+								if (prev) {
+									prev->next = ast_variable_new(attribute_name, &value[pos]);
+									if (prev->next) {
+										prev = prev->next;
+									}
+								} else {
+									prev = var = ast_variable_new(attribute_name, &value[pos]);
+								}
+								pos = i + 1;
+							}
+							i++;
+						}
+					}
+					/* for the last delimited value or if the value is not delimited: */
 					if (prev) {
-						prev->next = ast_variable_new(attribute_name, value);
-						if (prev->next) 
+						prev->next = ast_variable_new(attribute_name, &value[pos]);
+						if (prev->next) {
 							prev = prev->next;
+						}
 					} else {
-						prev = var = ast_variable_new(attribute_name, value);
+						prev = var = ast_variable_new(attribute_name, &value[pos]);
 					}
 				}
 				v++;
@@ -312,13 +444,218 @@
 	return var;
 }
 
+/*! \brief Get variables from ldap entry attributes - Should be locked before using it
+ *
+ * The results are freed outside this function so is the \a vars array.
+ *	
+ * \return \a vars - an array of ast_variable variables terminated with a null.
+ **/
+static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
+							LDAPMessage * ldap_result, unsigned int *entries_count_ptr)
+{
+	struct ast_variable ** vars;
+	int i=0;
+	int tot_count=0;
+	int entry_index=0;
+	LDAPMessage *ldap_entry = NULL;
+
+	
+	/* First find the total count */
+	ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+	
+	for (tot_count = 0; ldap_entry; tot_count++){ 
+		tot_count += semicolon_count_var( realtime_ldap_entry_to_var(table_config,ldap_entry) );
+		ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
+	}
+	
+	if (entries_count_ptr)
+		*entries_count_ptr = tot_count;
+	/* Now that we have the total count we allocate space and create the variables
+	 * Remember that each element in vars is a linked list that points to realtime variable.
+	 * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
+	 * value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element.
+	 * This memory must be freed outside of this function. */
+	vars = ast_calloc(1, sizeof(struct ast_variable *) *(tot_count + 1));
+	
+	ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+	
+	BerElement *ber = NULL;
+	struct ast_variable *var = NULL;
+	struct ast_variable *prev = NULL;
+	int is_delimited=0;
+	i=0;
+	char * delim_value = NULL;
+	int delim_tot_count = 0;
+	int delim_count = 0;
+
+	
+	/*For each static realtime variable we may create several entries in the \a vars array if it's delimited*/
+	for (entry_index = 0; ldap_entry; ){ 
+		delim_value = NULL;
+		delim_tot_count = 0;
+		delim_count=0;
+		int pos=0;
+		
+		do{/* while delim_count */
+
+			/*Starting new static var*/
+			char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
+			char *value;
+			while (ldap_attribute_name) {
+			
+				const char *attribute_name =
+					convert_attribute_name_from_ldap(table_config,ldap_attribute_name);
+				int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
+				char **values = NULL;
+
+				values = ldap_get_values(ldapConn, ldap_entry, ldap_attribute_name);
+				if (values) {
+					char **v = values;
+
+					while (*v) {
+						value = *v;
+						if (is_realmed_password_attribute) {
+							if (strncasecmp(value, "{md5}", 5) == 0)
+								value += 5;
+							else
+								value = NULL;
+							if (option_debug > 1)
+								ast_log(LOG_DEBUG, "md5: %s\n", value);
+						}
+						if (value) {
+							
+							if( delim_value == NULL 
+							&& !is_realmed_password_attribute 
+							&& (static_table_config != table_config || strcmp(attribute_name,"variable_value") == 0) ){
+
+								delim_value = ast_calloc(1,sizeof(char)*(strlen(value)+1));
+								ast_copy_string(delim_value,value,strlen(value)+1);
+								
+								if( (delim_tot_count = semicolon_count_str(delim_value)) > 0){
+									if (option_debug > 3)
+										ast_log(LOG_DEBUG, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
+									is_delimited = 1;
+								}
+							}
+
+							if( is_delimited != 0 
+								&& !is_realmed_password_attribute 
+								&& (static_table_config != table_config || strcmp(attribute_name,"variable_value") == 0)){
+								/* for non-Static RealTime, first */
+																		
+								
+								i=pos;
+								while ( !ast_strlen_zero(value + i) ){
+									if (option_debug > 3)
+										ast_log(LOG_DEBUG, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
+									if (delim_value[i] == ';'){
+										delim_value[i] = '\0';
+
+										if (option_debug > 1)
+											ast_log(LOG_DEBUG, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
+							
+										if (prev) {
+											prev->next = ast_variable_new(attribute_name, &delim_value[pos]);
+											if (prev->next) {
+												prev = prev->next;
+											}
+										} else {
+											prev = var = ast_variable_new(attribute_name, &delim_value[pos]);
+										}
+										pos = i + 1;
+
+										if(static_table_config == table_config){
+											break;
+										}
+									}
+									i++;
+								}
+								if(ast_strlen_zero(value + i)){
+									if (option_debug > 3)
+										ast_log(LOG_DEBUG, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i,delim_count);
+									/* Last delimited value */
+									if (option_debug > 3)
+										ast_log(LOG_DEBUG, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
+									if (prev) {
+										prev->next = ast_variable_new(attribute_name, &delim_value[pos]);
+										if (prev->next) {
+											prev = prev->next;
+										}
+									} else {
+										prev = var = ast_variable_new(attribute_name, &delim_value[pos]);
+									}
+									/* Remembering to free memory */
+									is_delimited = 0;
+									pos=0;
+									free(delim_value);
+									delim_value = NULL;
+								}
+								
+								if (option_debug > 3)
+									ast_log(LOG_DEBUG, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
+							} else {
+								/* not delimited */
+								if(delim_value != NULL){
+									free(delim_value);
+									delim_value = NULL;
+								}
+								if (option_debug > 1)
+									ast_log(LOG_DEBUG, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, value);
+
+								if (prev) {
+									prev->next = ast_variable_new(attribute_name, value);
+									if (prev->next) {
+										prev = prev->next;
+									}
+								} else {
+									prev = var = ast_variable_new(attribute_name, value);
+								}
+							}
+						}
+						v++;
+					}/*!<while(*v)*/
+					ldap_value_free(values);
+				}/*!<if (values)*/
+				ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
+			} /*!< while (ldap_attribute_name) */
+			ber_free(ber, 0);
+			if(static_table_config == table_config){
+				if (option_debug > 2){
+					const struct ast_variable * tmpdebug = variable_named(var,"variable_name");
+					const struct ast_variable * tmpdebug2 = variable_named(var,"variable_value");
+					if(tmpdebug && tmpdebug2){
+						ast_log(LOG_DEBUG, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value,tmpdebug2->value);
+					}
+				}
+				vars[entry_index++] = var;
+				prev = NULL;
+			}
+
+			delim_count++;
+		} while(delim_count <= delim_tot_count && static_table_config == table_config );
+		if(static_table_config != table_config){
+			if (option_debug > 2)
+				ast_log(LOG_DEBUG, "LINE(%d) Added to vars - non static\n", __LINE__ );
+				
+			vars[entry_index++] = var;
+			prev = NULL;
+		}
+		ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
+	} /*!< end for loop over ldap_entry */
+
+	return vars;
+}
+
+
 static int is_ldap_connect_error(int err)
 {
 	return (err == LDAP_SERVER_DOWN
 			|| err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
 }
 
-/*! \brief LGet LDAP entry by dn and return attributes as variables  - Should be locked before using it */
+/*! \brief Get LDAP entry by dn and return attributes as variables  - Should be locked before using it 
+	This is used for setting the default values of an object(i.e., with accountBaseDN)
+*/
 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
 					   const char *dn)
 {
@@ -326,6 +663,7 @@
 		ast_log(LOG_ERROR, "No table config\n");
 		return NULL;
 	} else {
+		struct ast_variable **vars = NULL;
 		struct ast_variable *var = NULL;
 		int result = -1;
 		LDAPMessage *ldap_result = NULL;
@@ -335,8 +673,8 @@
 			ast_log(LOG_DEBUG, "ldap_loadentry dn=%s\n", dn);
 
 		do {
-			result = ldap_search_s(ldapConn, dn, LDAP_SCOPE_BASE,
-					   "(objectclass=*)", NULL, 0, &ldap_result);
+			result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
+					   "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result);
 			if (result < 0 && is_ldap_connect_error(result)) {
 				ast_log(LOG_WARNING,
 					"Failed to query database. Try %d/3\n",
@@ -345,7 +683,7 @@
 				if (tries < 3) {
 					usleep(500000L * tries);
 					if (ldapConn) {
-						ldap_unbind_s(ldapConn);
+						ldap_unbind_ext_s(ldapConn,NULL,NULL);
 						ldapConn = NULL;
 					}
 					if (!ldap_reconnect())
@@ -366,13 +704,12 @@
 			return NULL;
 		} else {
 			int num_entry = 0;
+			unsigned int *entries_count_ptr; /*!< not using this*/
 			if ((num_entry = ldap_count_entries(ldapConn, ldap_result)) > 0) {
-				LDAPMessage *ldap_entry = NULL;
-				if (option_debug)
+				if (option_debug>2)
 					ast_log(LOG_DEBUG, "num_entry: %d\n", num_entry);
 
-				ldap_entry = ldap_first_entry(ldapConn, ldap_result);
-				var = realtime_ldap_entry_to_var(table_config, ldap_entry);
+				vars = realtime_ldap_result_to_vars(table_config,ldap_result,entries_count_ptr);
 				if (num_entry > 1)
 					ast_log(LOG_WARNING, "More than one entry for dn=%s. Take only 1st one\n", dn);
 			} else {
@@ -380,6 +717,20 @@
 			}
 		}
 		ldap_msgfree(ldap_result);
+
+		/* Chopping \a vars down to one variable */
+		if(vars != NULL){
+			struct ast_variable **p = vars;
+			p++;
+			var = *p;
+			while(var){
+				ast_variables_destroy(var);
+				p++;
+			}
+			vars = realloc(vars, sizeof(struct ast_variable *));
+		}
+		
+		var = *vars;
 
 		return var;
 	}
@@ -490,6 +841,31 @@
 	char *new_name = NULL;
 	char *new_value = NULL;
 	char *wsPos = strstr(name, " LIKE");
+
+	/* getting some escape character filter mods */
+	int foundEscape = 0;
+	struct ast_variable *nextEscape = table_config->escapes;
+	char *esc_value = NULL;
+	char *esc_tmp;
+	esc_tmp = (char *) ast_calloc(1,2);
+	
+	
+	for(nextEscape = table_config->escapes; nextEscape ; nextEscape = nextEscape->next ){
+		if(strcmp(name,nextEscape->name) == 0){
+			foundEscape = 1; 
+			break;
+		}
+	}
+	
+	if(foundEscape == 1){
+		esc_value = strdup(value);
+		strcpy(esc_tmp,"\\");
+		strcat(esc_tmp,nextEscape->value);
+		replace_string_in_string(esc_value, nextEscape->value,esc_tmp); 
+		value = esc_value;
+	}
+	/* The remaining filter mods */
+
 	if (option_debug > 1)
 		ast_log(LOG_DEBUG, "name='%s' value='%s'\n", name, value);
 	if (wsPos) {
@@ -541,159 +917,160 @@
 	if (!newparam || !newval) {
 		ast_log(LOG_WARNING,
 				"Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		return NULL;
+	}
+
+	ast_mutex_lock(&ldap_lock);
+
+	/* We now have our complete statement; Lets connect to the server and execute it.  */
+	if (!ldap_reconnect()) {
+		ast_mutex_unlock(&ldap_lock);
+		return NULL;
+	}
+	
+	struct ldap_table_config *table_config = NULL;
+
+	table_config = table_config_for_table_name(table_name);
+	if (!table_config) {
+		ast_log(LOG_WARNING,
+				"No table named '%s'.\n",
+				table_name);
+		ast_mutex_unlock(&ldap_lock);
+		return NULL;
+	}
+	
+	char *clean_basedn = cleaned_basedn(NULL, basedn);
+	char *filter = NULL;
+	int filter_size = 0;
+	int tries = 0;
+
+	int result = 0;
+	LDAPMessage *ldap_result = NULL;
+
+	append_string_to_filter(&filter, &filter_size, "(&");
+
+	if (table_config && table_config->additional_filter) {
+		append_string_to_filter(&filter, &filter_size,
+			table_config->additional_filter);
+	}
+	if (table_config != base_table_config && base_table_config
+		&& base_table_config->additional_filter) {
+			append_string_to_filter(&filter, &filter_size,
+				base_table_config->additional_filter);
+	}
+
+	/* Create the first part of the query using the first parameter/value pairs we just extracted */
+	/*   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
+
+	append_var_and_value_to_filter(&filter, &filter_size,
+		   table_config, newparam, newval);
+	while ((newparam = va_arg(ap, const char *))) {
+		newval = va_arg(ap, const char *);
+		append_var_and_value_to_filter(&filter, &filter_size,
+			   table_config, newparam, newval);
+	}
+	append_string_to_filter(&filter, &filter_size, ")");
+
+	if (option_debug)
+		ast_log(LOG_DEBUG, "filter: %s\n", filter);
+
+
+	do {
+		/* freeing ldap_result further down */
+		result = ldap_search_ext_s(ldapConn, clean_basedn,
+				  LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
+				  &ldap_result);
+		if (result < 0 && is_ldap_connect_error(result)) {
+			ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
+				tries + 1);
+			tries++;
+			if (tries < 3) {
+				usleep(500000L * tries);
+				if (ldapConn) {
+					ldap_unbind_ext_s(ldapConn,NULL,NULL);
+					ldapConn = NULL;
+				}
+				if (!ldap_reconnect())
+					break;
+			}
+		}
+	} while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+
+	if (result < 0) {
+		ast_log(LOG_WARNING,
+				"Failed to query database. Check debug for more info.\n");
+		ast_log(LOG_WARNING, "Query: %s\n",
+				filter);
+		ast_log(LOG_WARNING,
+				"Query Failed because: %s\n",
+					ldap_err2string(result));
 	} else {
-		ast_mutex_lock(&ldap_lock);
-
-		/* We now have our complete statement; Lets connect to the server and execute it.  */
-		if (ldap_reconnect()) {
-			struct ldap_table_config *table_config = NULL;
-
-			table_config = table_config_for_table_name(table_name);
-			if (!table_config) {
-				ast_log(LOG_WARNING,
-						"No table named '%s'.\n",
-						table_name);
-			} else {
-				char *clean_basedn = cleaned_basedn(NULL, basedn);
-				char *filter = NULL;
-				int filter_size = 0;
-				int tries = 0;
-
-				int result = 0;
-				LDAPMessage *ldap_result = NULL;
-
-				append_string_to_filter(&filter, &filter_size, "(&");
-
-				if (table_config && table_config->additional_filter) {
-					append_string_to_filter(&filter, &filter_size,
-						table_config->additional_filter);
-				}
-				if (table_config != base_table_config && base_table_config
-					&& base_table_config->additional_filter) {
-						append_string_to_filter(&filter, &filter_size,
-							base_table_config->additional_filter);
-				}
-
-				/* Create the first part of the query using the first parameter/value pairs we just extracted */
-				/*   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-
-				append_var_and_value_to_filter(&filter, &filter_size,
-				       table_config, newparam, newval);
-				while ((newparam = va_arg(ap, const char *))) {
-					newval = va_arg(ap, const char *);
-					append_var_and_value_to_filter(&filter, &filter_size,
-					       table_config, newparam, newval);
-				}
-				append_string_to_filter(&filter, &filter_size, ")");
-
-				if (option_debug)
-					ast_log(LOG_DEBUG, "filter: %s\n", filter);
-
-
-				do {
-					result = ldap_search_s(ldapConn, clean_basedn,
-							  LDAP_SCOPE_SUBTREE, filter, NULL, 0,
-							  &ldap_result);
-					if (result < 0 && is_ldap_connect_error(result)) {
-						ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
-							tries + 1);
-						tries++;
-						if (tries < 3) {
-							usleep(500000L * tries);
-							if (ldapConn) {
-								ldap_unbind_s(ldapConn);
-								ldapConn = NULL;
+		/* this is where we create the variables from the search result 
+		 * freeing this \a vars outside this function */
+		if (ldap_count_entries(ldapConn, ldap_result) > 0) {
+			//is this a static var or some other? they are handled different for delimited values
+			vars = realtime_ldap_result_to_vars(table_config,ldap_result,entries_count_ptr);
+		} else {
+			ast_log(LOG_WARNING, "Could not find any entry matching %s in base dn %s.\n",
+				filter, clean_basedn);
+		}
+
+
+		ldap_msgfree(ldap_result);
+
+		/* TODO: get the default variables from the accountBaseDN, not implemented with delimited values */
+		if (vars) {
+			struct ast_variable **p = vars;
+			while (*p) {
+				struct ast_variable *append_var = NULL;
+				struct ast_variable *tmp = *p;
+				while (tmp) {
+					if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
+						/* Get the variable to compare with for the defaults */
+						struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
+						
+						while (base_var) {
+							struct ast_variable *next = base_var->next;
+							struct ast_variable *test_var = *p;
+							int base_var_found = 0;
+
+							/* run throught the default values and fill it inn if it is missing */
+							while (test_var) {
+								if (strcasecmp(test_var->name, base_var->name) == 0) {
+									base_var_found = 1;
+									break;
+								} else
+									test_var = test_var->next;
 							}
-							if (!ldap_reconnect())
-								break;
+							if (base_var_found) {
+								base_var->next = NULL;
+								ast_variables_destroy (base_var);
+								base_var = next;
+							} else {
+								if (append_var)
+									base_var->next = append_var;
+								else
+									base_var->next = NULL;
+								append_var = base_var;
+								base_var = next;
+							}
 						}
 					}
-				} while (result < 0 && tries < 3 && is_ldap_connect_error(result));
-
-				if (result < 0) {
-					ast_log(LOG_WARNING,
-							"Failed to query database. Check debug for more info.\n");
-					ast_log(LOG_WARNING, "Query: %s\n",
-							filter);
-					ast_log(LOG_WARNING,
-							"Query Failed because: %s\n",
-								ldap_err2string(result));
-				} else {
-					int num_entry = 0;
-					if ((num_entry = ldap_count_entries(ldapConn, ldap_result)) > 0) {
-						LDAPMessage *ldap_entry = NULL;
-						int entry_index = 0;
-						if (entries_count_ptr)
-							*entries_count_ptr = num_entry;
-						vars = ast_calloc(1, sizeof(struct ast_variable *) *(num_entry + 1));
-						if (option_debug)
-							ast_log(LOG_DEBUG, "num_entry: %d\n", num_entry);
-
-						ldap_entry = ldap_first_entry(ldapConn, ldap_result);
-
-						for (entry_index = 0; ldap_entry; entry_index++) {
-							vars[entry_index] = realtime_ldap_entry_to_var(table_config,ldap_entry);
-							ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
-						}
-					} else {
-						ast_log(LOG_WARNING, "Could not find any entry matching %s in base dn %s.\n",
-							filter, clean_basedn);
-					}
-
-					ldap_msgfree(ldap_result);
-
-					if (vars) {
-						struct ast_variable **p = vars;
-						while (*p) {
-							struct ast_variable *append_var = NULL;
-							struct ast_variable *tmp = *p;
-							while (tmp) {
-								if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
-									struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
-									while (base_var) {
-										struct ast_variable *next = base_var->next;
-										struct ast_variable *test_var = *p;
-										int base_var_found = 0;
-
-										while (test_var) {
-											if (strcasecmp(test_var->name, base_var->name) == 0) {
-												base_var_found = 1;
-												break;
-											} else
-												test_var = test_var->next;
-										}
-										if (base_var_found) {
-											base_var->next = NULL;
-											ast_variables_destroy (base_var);
-											base_var = next;
-										} else {
-											if (append_var)
-												base_var->next = append_var;
-											else
-												base_var->next = NULL;
-											append_var = base_var;
-											base_var = next;
-										}
-									}
-								}
-								if (!tmp->next && append_var) {
-									tmp->next = append_var;
-									tmp = NULL;
-								} else
-									tmp = tmp->next;
-							}
-							p++;
-						}
-					}
+					if (!tmp->next && append_var) {
+						tmp->next = append_var;
+						tmp = NULL;
+					} else
+						tmp = tmp->next;
 				}
-				if (filter)
-					free(filter);
-				if (clean_basedn)
-					free(clean_basedn);
-			}
-		}
-		ast_mutex_unlock(&ldap_lock);
-	}
+				p++;
+			}
+		}
+	}
+	if (filter)
+		free(filter);
+	if (clean_basedn)
+		free(clean_basedn);
+	ast_mutex_unlock(&ldap_lock);
 	return vars;
 }
 
@@ -710,7 +1087,10 @@
 	return vars;
 }
 
-/*! \brief See Asterisk doc */
+/*! \brief See Asterisk doc
+*
+* For Realtime Dynamic(i.e., switch, queues, and directory) -- I think
+*/
 static struct ast_variable *realtime_ldap(const char *basedn,
 					  const char *table_name, va_list ap)
 {
@@ -736,7 +1116,13 @@
 	return var;
 }
 
-/*! \brief See Asterisk doc */
+/*! \brief See Asterisk doc
+*
+* this function will be called for the switch statment if no match is found with the realtime_ldap function(i.e. it is a failover);
+* however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
+* this is an area of asterisk that could do with a lot of modification
+* I think this function returns Realtime dynamic objects
+*/
 static struct ast_config *realtime_multi_ldap(const char *basedn,
       const char *table_name, va_list ap)
 {
@@ -776,26 +1162,51 @@
 
 }
 
+/*! 
+ * \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
+ * \param \a a pointer to category_and_metric struct
+ * \param \a b pointer to category_and_metric struct
+ *
+ * \return the -1,0,1 (zero for equal, -1 for if b is greater, and 1 if a is greater)
+ */
 static int compare_categories(const void *a, const void *b)
 {
 	struct category_and_metric *as = (struct category_and_metric *) a;
 	struct category_and_metric *bs = (struct category_and_metric *) b;
-	if (as->metric < bs->metric)
+	if (as->metric < bs->metric){
 		return -1;
-	else if (as->metric > bs->metric)
+	} else if (as->metric > bs->metric){
 		return 1;
-	else
+	} else if ( as->metric == bs->metric && strcmp(as->name, bs->name) < 0){
 		return strcmp(as->name, bs->name);
-}
-
-/*! \brief See Asterisk doc */
+	} else if ( as->metric == bs->metric && strcmp(as->name, bs->name) > 0){
+		return strcmp(as->name, bs->name);
+	} 
+	/* if the metric and the category name is the same, we check the variable metric */
+	if(as->var_metric < bs->var_metric){
+		return -1;
+	} else if(as->var_metric > bs->var_metric){
+		return 1;
+	}
+	return 0;
+}
+
+/*! \brief See Asterisk doc
+ *
+*	This is for Static Realtime (again: I think...)
+*	
+*	load the configuration stuff for the .conf files
+*	called on a reload
+*/
 static struct ast_config *config_ldap(const char *basedn,
 				      const char *table_name,
 				      const char *file,
 				      struct ast_config *cfg,
 				      int withcomments)
 {
-	ast_log(LOG_DEBUG, "config_ldap: basedn: %s table_name: %s\n",	basedn, table_name);
+	if(option_debug)
+		ast_log(LOG_DEBUG, "config_ldap: basedn: %s table_name: %s\n",	basedn, table_name);
+
 	if (!file || !strcmp(file, RES_CONFIG_LDAP_CONF)) {
 		ast_log(LOG_WARNING, "Cannot configure myself.\n");
 	} else {
@@ -804,7 +1215,10 @@
 			realtime_ldap_base_(&vars_count, basedn, table_name, "filename",
 								file, "commented", "FALSE", NULL);
 
+
+ast_log(LOG_DEBUG, "LINE(%d)\n",__LINE__);
 		if (vars) {
+ast_log(LOG_DEBUG, "LINE(%d)\n",__LINE__);
 			int i = 0;
 			struct ast_variable *new_v = NULL;
 			struct ast_category *cur_cat = NULL;
@@ -813,7 +1227,7 @@
 
 			/* sort on metric and category */
 			struct category_and_metric *categories =
-				malloc(sizeof(struct category_and_metric) * vars_count);
+				ast_calloc(1,sizeof(struct category_and_metric) * vars_count);
 			struct ast_variable **p = vars;
 			vars_count = 0;
 			while (*p) {
@@ -825,6 +1239,8 @@
 					variable_named(*p, "variable_name");
 				struct ast_variable *var_val =
 					variable_named(*p, "variable_value");
+				struct ast_variable *var_metric =
+					variable_named(*p, "var_metric");
 				if (option_debug) {
 					ast_log(LOG_DEBUG, "category: %s\n",
 						category->value);
@@ -845,6 +1261,11 @@
 					ast_log(LOG_ERROR,
 							"No category metric in entry '%s'(category: %s) for file '%s'.\n",
 							(dn ? dn->value : "?"), category->value, file);
+				} else if (!var_metric) {
+					struct ast_variable *dn = variable_named(*p, "dn");
+					ast_log(LOG_ERROR,
+							"No variable metric in entry '%s'(category: %s) for file '%s'.\n",
+							(dn ? dn->value : "?"), category->value, file);
 				} else if (!var_name) {
 					struct ast_variable *dn = variable_named(*p, "dn");
 					ast_log(LOG_ERROR,
@@ -862,6 +1283,7 @@
 					categories[vars_count].metric = atoi(cat_metric->value);
 					categories[vars_count].variable_name = var_name->value;
 					categories[vars_count].variable_value = var_val->value;
+					categories[vars_count].var_metric = atoi(var_metric->value);
 					vars_count++;
 				}
 				p++;
@@ -902,16 +1324,217 @@
 
 }
 
+/* \brief Function to update a set of values in ldap
+static
+*/
+static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
+                                                const char *lookup, va_list ap)
+{
+	int error=0;
+	LDAPMessage *ldap_entry = NULL;
+	struct ast_variable **vars = NULL;
+	/*!< done defining counting vars */
+	LDAPMod ** ldap_mods;
+	const char *newparam = NULL;
+	const char *newval = NULL;
+	char * dn;
+	int num_entries=0; 
+	int i=0;
+	int mods_size=0;
+	int mod_exists=0;
+	struct ldap_table_config *table_config = NULL;
+	char *clean_basedn = NULL;
+	char *filter = NULL;
+	int filter_size = 0;
+	int tries = 0;
+	int result = 0;
+	LDAPMessage *ldap_result = NULL;
+
+
+	if (option_debug > 1)
+		ast_log(LOG_DEBUG,
+			"realtime_ldap_base: basedn: %s table_name: %s\n", basedn, table_name);
+	if (!table_name) {
+		ast_log(LOG_WARNING, "No table_name specified.\n");
+		return -1;
+	} 
+
+	if (!attribute || !lookup) {
+		ast_log(LOG_WARNING,
+				"LINE(%d): search parameters are empty.\n",__LINE__);
+		return -1;
+	}
+	ast_mutex_lock(&ldap_lock);
+
+	/* We now have our complete statement; Lets connect to the server and execute it.  */
+	if (!ldap_reconnect()) {
+		ast_mutex_unlock(&ldap_lock);
+		return -1;
+	}
+
+	table_config = table_config_for_table_name(table_name);
+	if (!table_config) {
+		ast_log(LOG_WARNING,
+				"No table named '%s'.\n",
+				table_name);
+		ast_mutex_unlock(&ldap_lock);
+		return -1;
+	}
+
+	clean_basedn = cleaned_basedn(NULL, basedn);
+
+	/* Create the filter with the table additional filter and the parameter/value pairs we were given */
+	append_string_to_filter(&filter, &filter_size, "(&");
+	if (table_config && table_config->additional_filter) {
+		append_string_to_filter(&filter, &filter_size,
+			table_config->additional_filter);
+	}
+	if (table_config != base_table_config && base_table_config
+		&& base_table_config->additional_filter) {
+			append_string_to_filter(&filter, &filter_size,
+				base_table_config->additional_filter);
+	}
+	append_var_and_value_to_filter(&filter, &filter_size, table_config, attribute, lookup);
+	append_string_to_filter(&filter, &filter_size, ")");
+	if (option_debug)
+		ast_log(LOG_DEBUG, "filter: %s\n", filter);
+	
+	/* Create the modification array with the parameter/value pairs we were given, if there are several parameters with the same name, we collect them into one parameter/value pair and delimit them with a semicolon */
+	newparam = va_arg(ap, const char *);
+	newparam = convert_attribute_name_to_ldap(table_config, newparam);
+	newval = va_arg(ap, const char *);
+	if (!newparam || !newval) {
+		ast_log(LOG_WARNING,
+				"LINE(%d): need at least one paramter to modify.\n",__LINE__);
+		return -1;
+	}
+
+	mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
+	ldap_mods = ast_calloc(1,sizeof(LDAPMod *)*mods_size);
+	ldap_mods[0] = ast_calloc(1,sizeof(LDAPMod));
+	
+	ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
+	ldap_mods[0]->mod_type = ast_calloc(1,sizeof(char)*(strlen(newparam)+1));
+	strcpy(ldap_mods[0]->mod_type, newparam);
+	
+	ldap_mods[0]->mod_values = ast_calloc(1,sizeof(char *)*2);
+	ldap_mods[0]->mod_values[0] = ast_calloc(1,sizeof(char)*(strlen(newval)+1));
+	strcpy(ldap_mods[0]->mod_values[0],newval);
+
+	while ((newparam = va_arg(ap, const char *))) {
+		newparam = convert_attribute_name_to_ldap(table_config, newparam);
+		
+		newval = va_arg(ap, const char *);
+		mod_exists = 0;
+		
+		for(i=0;i<mods_size-1;i++){
+			if(ldap_mods[i] != NULL && strcmp(ldap_mods[i]->mod_type, newparam) == 0){
+					/* We have the parameter allready, adding the value as a semicolon delimited value */
+				ldap_mods[i]->mod_values[0] = realloc(ldap_mods[i]->mod_values[0], sizeof(char)*( strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2 ));
+				strcat(ldap_mods[i]->mod_values[0],";");
+				strcat(ldap_mods[i]->mod_values[0],newval);
+				mod_exists = 1;	
+				break;
+			}
+		}
+
+		/* create new mod */
+		if (!mod_exists){
+			mods_size++;
+			ldap_mods = realloc(ldap_mods, sizeof(LDAPMod *)*mods_size);
+			ldap_mods[mods_size - 1] = NULL;
+			ldap_mods[mods_size - 2] = ast_calloc(1,sizeof(LDAPMod));
+
+			ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
+			
+			ldap_mods[mods_size - 2]->mod_type = ast_calloc(1,sizeof(char)*(strlen(newparam)+1));
+			strcpy(ldap_mods[mods_size - 2]->mod_type,newparam);
+			
+			ldap_mods[mods_size - 2]->mod_values = ast_calloc(1,sizeof(char *)*2);
+			ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(1,sizeof(char)*(strlen(newval)+1));
+			strcpy(ldap_mods[mods_size - 2]->mod_values[0],newval);
+		}
+	}
+		/* freeing ldap_mods further down */
+
+	do {
+		/* freeing ldap_result further down */
+		result = ldap_search_ext_s(ldapConn, clean_basedn,
+				  LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
+				  &ldap_result);
+		if (result < 0 && is_ldap_connect_error(result)) {
+			ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
+				tries + 1);
+			tries++;
+			if (tries < 3) {
+				usleep(500000L * tries);
+				if (ldapConn) {
+					ldap_unbind_ext_s(ldapConn,NULL,NULL);
+					ldapConn = NULL;
+				}
+				if (!ldap_reconnect())
+					break;
+			}
+		}
+	} while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+
+	if (result < 0) {
+		ast_log(LOG_WARNING,
+				"Failed to query directory. Check debug for more info.\n");
+		ast_log(LOG_WARNING, "Query: %s\n",
+				filter);
+		ast_log(LOG_WARNING,
+				"Query Failed because: %s\n",
+					ldap_err2string(result));
+
+		ast_mutex_unlock(&ldap_lock);
+		if (filter)
+			free(filter);
+		if (clean_basedn)
+			free(clean_basedn);
+		ldap_msgfree(ldap_result);
+		ldap_mods_free(ldap_mods,0);
+		return -1;
+	}
+	/* Ready to update */
+	if ((num_entries = ldap_count_entries(ldapConn, ldap_result)) > 0) {
+		if (option_debug>2){
+			ast_log(LOG_DEBUG, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__,attribute,lookup,num_entries);
+			for(i=0;i<mods_size-1;i++){
+				ast_log(LOG_DEBUG, "LINE(%d) %s=%s \n", __LINE__,ldap_mods[i]->mod_type,ldap_mods[i]->mod_values[0]);
+			}
+		}
+		
+		ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+
+		for (i = 0; ldap_entry; i++){ 
+			dn = ldap_get_dn(ldapConn,ldap_entry);

[... 237 lines stripped ...]


More information about the svn-commits mailing list