1 /*
2  * Copyright (C) 2011 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19 
20 #include <string.h>
21 #include <glib/gi18n-lib.h>
22 #include <libgda/gda-data-model-ldap.h>
23 #include <libgda/gda-connection.h>
24 #include <libgda/gda-data-model-iter.h>
25 #include <libgda/gda-holder.h>
26 #include <libgda/gda-util.h>
27 #include <libgda/sqlite/virtual/gda-virtual-connection.h>
28 #include <libgda/sqlite/virtual/gda-ldap-connection.h>
29 #include "gda-ldap.h"
30 #include "gda-ldap-util.h"
31 #include "gdaprov-data-model-ldap.h"
32 #include <libgda/gda-debug-macros.h>
33 
34 #define GDA_DEBUG_SUBSEARCHES
35 #undef GDA_DEBUG_SUBSEARCHES
36 
37 /*
38  * What to do in case of a multi value in a cell
39  */
40 typedef enum {
41 	MULTIPLE_VALUE_ACTION_SET_NULL,
42 	MULTIPLE_VALUE_ACTION_CSV_STRING,
43 	MULTIPLE_VALUE_ACTION_MULTIPLY,
44 	MULTIPLE_VALUE_ACTION_SET_INVALID,
45 	MULTIPLE_VALUE_ACTION_FIRST,
46 	MULTIPLE_VALUE_ACTION_CONCAT
47 } MultipleValueAction;
48 
49 typedef struct _LdapPart LdapPart;
50 struct _LdapPart {
51 	gchar           *base_dn;
52 	GdaLdapSearchScope scope;
53 	gboolean         executed; /* %TRUE if @ldap_msg of @children have already had the
54 				    * opportunity of being computed */
55 
56 	/* result of execution, both %NULL if data was truncated when executing */
57 	LDAPMessage     *ldap_msg;
58 	gint             nb_entries;
59 	LDAPMessage     *ldap_row; /* no ref! */
60 
61 	/* tree-like structure */
62 	GSList          *children; /* list of #LdapPart, ref held there */
63 	LdapPart        *parent; /* no ref held */
64 };
65 #define LDAP_PART(x) ((LdapPart*)(x))
66 
67 static LdapPart *ldap_part_new (LdapPart *parent, const gchar *base_dn, GdaLdapSearchScope scope);
68 static void ldap_part_free (LdapPart *part, LdapConnectionData *cdata);
69 static gboolean ldap_part_split (LdapPart *part, GdaDataModelLdap *model, gboolean *out_error);
70 static LdapPart *ldap_part_next (LdapPart *part, gboolean executed);
71 #ifdef GDA_DEBUG_SUBSEARCHES
72 static void ldap_part_dump (LdapPart *part);
73 #endif
74 
75 static void add_exception (GdaDataModelLdap *model, GError *e);
76 
77 typedef struct {
78 	GdaHolder *holder;
79 	gint       index;
80 	GArray    *values; /* array of #GValue, or %NULL on error */
81 } ColumnMultiplier;
82 static ColumnMultiplier *column_multiplier_new (GdaHolder *holder,
83 						const GValue *value);
84 
85 typedef struct {
86 	GArray *cms; /* array of ColumnMultiplier pointers, stores in reverse order */
87 } RowMultiplier;
88 static RowMultiplier *row_multiplier_new (void);
89 static gboolean row_multiplier_index_next (RowMultiplier *rm);
90 static void row_multiplier_free (RowMultiplier *rm);
91 static void row_multiplier_set_holders (RowMultiplier *rm);
92 
93 struct _GdaDataModelLdapPrivate {
94 	GdaConnection      *cnc;
95 	gchar              *base_dn;
96 	gboolean            use_rdn;
97 	gchar              *filter;
98 	GArray             *attributes;
99 	GdaLdapSearchScope  scope;
100 	MultipleValueAction default_mv_action;
101 	GList              *columns;
102 	GArray             *column_mv_actions; /* array of #MultipleValueAction, notincluding column 0 */
103 	gint                n_columns; /* length of @columns */
104 	gint                n_rows;
105 	gboolean            truncated;
106 
107 	gint                iter_row;
108 	LdapPart           *top_exec; /* ref held */
109 	LdapPart           *current_exec; /* no ref held, only a pointer in the @top_exec tree */
110 
111 	RowMultiplier      *row_mult;
112 
113 	GArray             *exceptions; /* array of GError pointers */
114 };
115 
116 /* properties */
117 enum {
118 	PROP_0,
119 	PROP_CNC,
120 	PROP_BASE,
121 	PROP_FILTER,
122 	PROP_ATTRIBUTES,
123 	PROP_SCOPE,
124 	PROP_USE_RDN
125 };
126 
127 static void gda_data_model_ldap_class_init (GdaDataModelLdapClass *klass);
128 static void gda_data_model_ldap_init       (GdaDataModelLdap *model,
129 					    GdaDataModelLdapClass *klass);
130 static void gda_data_model_ldap_dispose    (GObject *object);
131 
132 static void gda_data_model_ldap_set_property (GObject *object,
133 					      guint param_id,
134 					      const GValue *value,
135 					      GParamSpec *pspec);
136 static void gda_data_model_ldap_get_property (GObject *object,
137 					      guint param_id,
138 					      GValue *value,
139 					      GParamSpec *pspec);
140 
141 static GList *_ldap_compute_columns (GdaConnection *cnc, const gchar *attributes,
142 				     GArray **out_attrs_array,
143 				     MultipleValueAction default_mva, GArray **out_mv_actions);
144 
145 /* GdaDataModel interface */
146 static void                 gda_data_model_ldap_data_model_init (GdaDataModelIface *iface);
147 static gint                 gda_data_model_ldap_get_n_rows      (GdaDataModel *model);
148 static gint                 gda_data_model_ldap_get_n_columns   (GdaDataModel *model);
149 static GdaColumn           *gda_data_model_ldap_describe_column (GdaDataModel *model, gint col);
150 static GdaDataModelAccessFlags gda_data_model_ldap_get_access_flags(GdaDataModel *model);
151 static gboolean             gda_data_model_ldap_iter_next       (GdaDataModel *model, GdaDataModelIter *iter);
152 static GdaValueAttribute    gda_data_model_ldap_get_attributes_at (GdaDataModel *model, gint col, gint row);
153 static GError             **gda_data_model_ldap_get_exceptions  (GdaDataModel *model);
154 
155 static GObjectClass *parent_class = NULL;
156 #define CLASS(model) (GDA_DATA_MODEL_LDAP_CLASS (G_OBJECT_GET_CLASS (model)))
157 
158 /*
159  * Object init and dispose
160  */
161 static void
gda_data_model_ldap_data_model_init(GdaDataModelIface * iface)162 gda_data_model_ldap_data_model_init (GdaDataModelIface *iface)
163 {
164         iface->i_get_n_rows = gda_data_model_ldap_get_n_rows;
165         iface->i_get_n_columns = gda_data_model_ldap_get_n_columns;
166         iface->i_describe_column = gda_data_model_ldap_describe_column;
167         iface->i_get_access_flags = gda_data_model_ldap_get_access_flags;
168         iface->i_get_value_at = NULL;
169         iface->i_get_attributes_at = gda_data_model_ldap_get_attributes_at;
170 
171         iface->i_create_iter = NULL;
172         iface->i_iter_at_row = NULL;
173         iface->i_iter_next = gda_data_model_ldap_iter_next;
174         iface->i_iter_prev = NULL;
175 
176         iface->i_set_value_at = NULL;
177 	iface->i_iter_set_value = NULL;
178         iface->i_set_values = NULL;
179         iface->i_append_values = NULL;
180         iface->i_append_row = NULL;
181         iface->i_remove_row = NULL;
182         iface->i_find_row = NULL;
183 
184         iface->i_set_notify = NULL;
185         iface->i_get_notify = NULL;
186         iface->i_send_hint = NULL;
187 
188 	iface->i_get_exceptions = gda_data_model_ldap_get_exceptions;
189 }
190 
191 static void
gda_data_model_ldap_init(GdaDataModelLdap * model,G_GNUC_UNUSED GdaDataModelLdapClass * klass)192 gda_data_model_ldap_init (GdaDataModelLdap *model,
193 			  G_GNUC_UNUSED GdaDataModelLdapClass *klass)
194 {
195 	GdaColumn *col;
196 
197 	g_return_if_fail (GDA_IS_DATA_MODEL_LDAP (model));
198 
199 	model->priv = g_new0 (GdaDataModelLdapPrivate, 1);
200 	model->priv->cnc = NULL;
201 	model->priv->base_dn = NULL;
202 	model->priv->use_rdn = FALSE;
203 	model->priv->filter = g_strdup ("(objectClass=*)");
204 	model->priv->iter_row = -1;
205 	model->priv->default_mv_action = MULTIPLE_VALUE_ACTION_SET_INVALID;
206 	model->priv->top_exec = NULL;
207 	model->priv->current_exec = NULL;
208 	model->priv->attributes = NULL;
209 	model->priv->truncated = FALSE;
210 	model->priv->exceptions = NULL;
211 	model->priv->row_mult = NULL;
212 
213 	/* add the "dn" column */
214 	col = gda_column_new ();
215 	gda_column_set_name (col, "dn");
216 	gda_column_set_g_type (col, G_TYPE_STRING);
217 	gda_column_set_allow_null (col, FALSE);
218 	gda_column_set_description (col, _("Distinguished name"));
219 	model->priv->columns = g_list_prepend (NULL, col);
220 	model->priv->column_mv_actions = g_array_new (FALSE, FALSE, sizeof (MultipleValueAction));
221 
222 	model->priv->n_columns = g_list_length (model->priv->columns);
223 	model->priv->scope = GDA_LDAP_SEARCH_BASE;
224 }
225 
226 static void
gda_data_model_ldap_class_init(GdaDataModelLdapClass * klass)227 gda_data_model_ldap_class_init (GdaDataModelLdapClass *klass)
228 {
229 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
230 
231 	parent_class = g_type_class_peek_parent (klass);
232 
233 	/* properties */
234         object_class->set_property = gda_data_model_ldap_set_property;
235         object_class->get_property = gda_data_model_ldap_get_property;
236         g_object_class_install_property (object_class, PROP_CNC,
237                                          g_param_spec_object ("cnc", NULL, "LDAP connection",
238 							      GDA_TYPE_LDAP_CONNECTION,
239                                                               G_PARAM_READABLE | G_PARAM_WRITABLE |
240                                                               G_PARAM_CONSTRUCT_ONLY));
241         g_object_class_install_property (object_class, PROP_BASE,
242                                          g_param_spec_string ("base", NULL, "Base DN", NULL,
243                                                               G_PARAM_READABLE | G_PARAM_WRITABLE |
244                                                               G_PARAM_CONSTRUCT_ONLY));
245 	g_object_class_install_property (object_class, PROP_FILTER,
246                                          g_param_spec_string ("filter", NULL, "LDAP filter", NULL,
247                                                               G_PARAM_READABLE | G_PARAM_WRITABLE |
248                                                               G_PARAM_CONSTRUCT_ONLY));
249         g_object_class_install_property (object_class, PROP_ATTRIBUTES,
250                                          g_param_spec_string ("attributes", NULL, "LDAP attributes", NULL,
251                                                               G_PARAM_WRITABLE |
252                                                               G_PARAM_CONSTRUCT_ONLY));
253 	g_object_class_install_property (object_class, PROP_SCOPE,
254                                          g_param_spec_int ("scope", NULL, "LDAP search scope",
255 							   GDA_LDAP_SEARCH_BASE,
256 							   GDA_LDAP_SEARCH_SUBTREE,
257 							   GDA_LDAP_SEARCH_BASE,
258 							   G_PARAM_WRITABLE | G_PARAM_READABLE |
259 							   G_PARAM_CONSTRUCT_ONLY));
260 
261 	g_object_class_install_property (object_class, PROP_USE_RDN,
262                                          g_param_spec_boolean ("use-rdn", NULL, "Return Relative DN instead of complete DN",
263 							       FALSE, G_PARAM_WRITABLE | G_PARAM_READABLE));
264 
265 
266 	/* virtual functions */
267 	object_class->dispose = gda_data_model_ldap_dispose;
268 }
269 
270 static void
gda_data_model_ldap_dispose(GObject * object)271 gda_data_model_ldap_dispose (GObject *object)
272 {
273 	GdaDataModelLdap *model = (GdaDataModelLdap *) object;
274 
275 	g_return_if_fail (GDA_IS_DATA_MODEL_LDAP (model));
276 
277 	if (model->priv) {
278 		if (model->priv->row_mult)
279 			row_multiplier_free (model->priv->row_mult);
280 		if (model->priv->cnc)
281 			g_object_unref (model->priv->cnc);
282 		if (model->priv->columns) {
283                         g_list_foreach (model->priv->columns, (GFunc) g_object_unref, NULL);
284                         g_list_free (model->priv->columns);
285                         model->priv->columns = NULL;
286                 }
287 		if (model->priv->attributes) {
288 			gint i;
289 			for (i = 0; i < model->priv->attributes->len; i++) {
290 				gchar *tmp;
291 				tmp = g_array_index (model->priv->attributes, gchar*, i);
292 				g_free (tmp);
293 			}
294 			g_array_free (model->priv->attributes, TRUE);
295 		}
296 		if (model->priv->column_mv_actions)
297 			g_array_free (model->priv->column_mv_actions, TRUE);
298 
299 		if (model->priv->top_exec) {
300 			LdapConnectionData *cdata;
301 			cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (model->priv->cnc));
302 			ldap_part_free (model->priv->top_exec, cdata);
303 		}
304 
305 		g_free (model->priv->base_dn);
306 		g_free (model->priv->filter);
307 
308 		if (model->priv->exceptions) {
309 			gint i;
310 			for (i = 0; i < model->priv->exceptions->len; i++) {
311 				GError *e;
312 				e = g_array_index (model->priv->exceptions, GError*, i);
313 				g_error_free (e);
314 			}
315 			g_array_free (model->priv->exceptions, TRUE);
316 		}
317 
318 		g_free (model->priv);
319 		model->priv = NULL;
320 	}
321 
322 	parent_class->dispose (object);
323 }
324 
325 GType
gdaprov_data_model_ldap_get_type(void)326 gdaprov_data_model_ldap_get_type (void)
327 {
328 	static GType type = 0;
329 
330 	if (G_UNLIKELY (type == 0)) {
331 		static GMutex registering;
332 		static const GTypeInfo info = {
333 			sizeof (GdaDataModelLdapClass),
334 			(GBaseInitFunc) NULL,
335 			(GBaseFinalizeFunc) NULL,
336 			(GClassInitFunc) gda_data_model_ldap_class_init,
337 			NULL,
338 			NULL,
339 			sizeof (GdaDataModelLdap),
340 			0,
341 			(GInstanceInitFunc) gda_data_model_ldap_init,
342 			0
343 		};
344 		static const GInterfaceInfo data_model_info = {
345                         (GInterfaceInitFunc) gda_data_model_ldap_data_model_init,
346                         NULL,
347                         NULL
348                 };
349 
350 		g_mutex_lock (&registering);
351 		if (type == 0) {
352 			type = g_type_register_static (G_TYPE_OBJECT, "GdaDataModelLdap", &info, 0);
353 			g_type_add_interface_static (type, GDA_TYPE_DATA_MODEL, &data_model_info);
354 		}
355 		g_mutex_unlock (&registering);
356 	}
357 	return type;
358 }
359 
360 static void
gda_data_model_ldap_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)361 gda_data_model_ldap_set_property (GObject *object,
362 				  guint param_id,
363 				  const GValue *value,
364 				  GParamSpec *pspec)
365 {
366         GdaDataModelLdap *model;
367         const gchar *string;
368 
369         model = GDA_DATA_MODEL_LDAP (object);
370         if (model->priv) {
371                 switch (param_id) {
372                 case PROP_CNC: {
373 			GdaConnection *cnc;
374 			cnc = g_value_get_object (value);
375 			if (cnc) {
376 				if (g_object_get_data ((GObject*) cnc,
377 						       "__gda_connection_LDAP") != (gpointer) 0x01) {
378 					g_warning ("cnc is not an LDAP connection");
379 					break;
380 				}
381 				model->priv->cnc = g_object_ref (cnc);
382 			}
383 			break;
384 		}
385                 case PROP_BASE:
386 			string = g_value_get_string (value);
387 			if (string)
388 				model->priv->base_dn = g_strdup (string);
389 			break;
390 		case PROP_FILTER:
391 			string = g_value_get_string (value);
392 			if (string) {
393 				g_free (model->priv->filter);
394 				model->priv->filter = g_strdup (string);
395 			}
396 			break;
397 		case PROP_ATTRIBUTES: {
398 			const gchar *csv;
399 			csv = g_value_get_string (value);
400 			if (csv && *csv) {
401 				if (model->priv->columns) {
402 					g_list_foreach (model->priv->columns, (GFunc) g_object_unref, NULL);
403 					g_list_free (model->priv->columns);
404 				}
405 				if (model->priv->column_mv_actions) {
406 					g_array_free (model->priv->column_mv_actions, TRUE);
407 					model->priv->column_mv_actions = NULL;
408 				}
409 
410 				model->priv->columns = _ldap_compute_columns (model->priv->cnc, csv,
411 									      &model->priv->attributes,
412 									      model->priv->default_mv_action,
413 									      &model->priv->column_mv_actions);
414 				if (model->priv->use_rdn)
415 					gda_column_set_description (GDA_COLUMN (model->priv->columns->data),
416 								    _("Relative distinguished name"));
417 				else
418 					gda_column_set_description (GDA_COLUMN (model->priv->columns->data),
419 								    _("Distinguished name"));
420 				model->priv->n_columns = g_list_length (model->priv->columns);
421 			}
422 			break;
423 		}
424 		case PROP_SCOPE:
425 			model->priv->scope = g_value_get_int (value);
426 			break;
427 		case PROP_USE_RDN:
428 			model->priv->use_rdn = g_value_get_boolean (value);
429 			if (model->priv->columns && model->priv->use_rdn)
430 				gda_column_set_description (GDA_COLUMN (model->priv->columns->data),
431 							    _("Relative distinguished name"));
432 			else
433 				gda_column_set_description (GDA_COLUMN (model->priv->columns->data),
434 							    _("Distinguished name"));
435 			break;
436 		default:
437 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
438 			break;
439 		}
440 	}
441 }
442 
443 static void
gda_data_model_ldap_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)444 gda_data_model_ldap_get_property (GObject *object,
445 				  guint param_id,
446 				  GValue *value,
447 				  GParamSpec *pspec)
448 {
449         GdaDataModelLdap *model;
450 
451         model = GDA_DATA_MODEL_LDAP (object);
452         if (model->priv) {
453                 switch (param_id) {
454                 case PROP_CNC:
455 			g_value_set_object (value, model->priv->cnc);
456 			break;
457                 case PROP_BASE:
458 			g_value_set_string (value, model->priv->base_dn);
459 			break;
460                 case PROP_FILTER:
461 			g_value_set_string (value, model->priv->filter);
462 			break;
463 		case PROP_SCOPE:
464 			g_value_set_int (value, model->priv->scope);
465 			break;
466 		case PROP_USE_RDN:
467 		        g_value_set_boolean (value, model->priv->use_rdn);
468 			break;
469 		default:
470 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
471 			break;
472 		}
473 	}
474 }
475 
476 GList *
gdaprov_data_model_ldap_compute_columns(GdaConnection * cnc,const gchar * attributes)477 gdaprov_data_model_ldap_compute_columns (GdaConnection *cnc, const gchar *attributes)
478 {
479 	return _ldap_compute_columns (cnc, attributes, NULL, MULTIPLE_VALUE_ACTION_SET_INVALID,
480 				      NULL);
481 }
482 
483 /*
484  * _ldap_compute_columns
485  * @cnc: a #GdaConnection
486  * @attributes: a string
487  * @out_attrs_array: a place to store an array of strings (terminated by a %NULL), or %NULL
488  * @default_mva: the default #MultipleValueAction if none speficied
489  * @out_mv_actions: a place to store an array of MultipleValueAction, or %NULL
490  *
491  * Returns: (transfer full) (element-type GdaColumn): a list of #GdaColumn objects
492  */
493 static GList *
_ldap_compute_columns(GdaConnection * cnc,const gchar * attributes,GArray ** out_attrs_array,MultipleValueAction default_mva,GArray ** out_mv_actions)494 _ldap_compute_columns (GdaConnection *cnc, const gchar *attributes,
495 		       GArray **out_attrs_array,
496 		       MultipleValueAction default_mva, GArray **out_mv_actions)
497 {
498 	gchar **array;
499 	gint i;
500 	GdaColumn *col;
501 	LdapConnectionData *cdata = NULL;
502 	GList *columns = NULL;
503 	GArray *attrs = NULL, *mva = NULL;
504 	GHashTable *colnames; /* key = column name, 0x01 */
505 	colnames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
506 
507 	if (out_attrs_array) {
508 		attrs = g_array_new (TRUE, FALSE, sizeof (gchar*));
509 		*out_attrs_array = attrs;
510 	}
511 	if (out_mv_actions) {
512 		mva = g_array_new (FALSE, FALSE, sizeof (MultipleValueAction));
513 		*out_mv_actions = mva;
514 	}
515 
516 	/* always add the DN column */
517 	col = gda_column_new ();
518 	gda_column_set_name (col, "dn");
519 	gda_column_set_g_type (col, G_TYPE_STRING);
520 	gda_column_set_allow_null (col, FALSE);
521 	columns = g_list_prepend (NULL, col);
522 	g_hash_table_insert (colnames, g_strdup ("dn"), (gpointer) 0x01);
523 
524 	if (!attributes || !*attributes)
525 		return columns;
526 
527 	/* parse input string */
528 	if (cnc) {
529 		g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
530 		cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
531 	}
532 	array = g_strsplit (attributes, ",", 0);
533 	for (i = 0; array [i]; i++) {
534 		GType coltype = GDA_TYPE_NULL;
535 		gchar **sub, *tmp;
536 		const gchar *mvaspec = NULL;
537 		MultipleValueAction act = default_mva;
538 
539 		g_strstrip (array [i]);
540 		sub = g_strsplit (array[i], "::", 3);
541 		g_strstrip (sub [0]);
542 		if (sub [1]) {
543 			g_strstrip (sub [1]);
544 			if (sub [2]) {
545 				g_strstrip (sub [2]);
546 				mvaspec = sub [2];
547 			}
548 		}
549 
550 		coltype = gda_ldap_get_g_type (cdata, sub [0], sub [1]);
551 		tmp = g_strdup (sub [0]);
552 		if (attrs)
553 			g_array_append_val (attrs, tmp);
554 		if (g_hash_table_lookup (colnames, sub [0])) {
555 			/* can't have twice the same LDAP attribute */
556 			g_strfreev (sub);
557 			continue;
558 		}
559 		col = gda_column_new ();
560 		gda_column_set_name (col, sub [0]);
561 		gda_column_set_description (col, sub [0]);
562 		g_hash_table_insert (colnames, g_strdup (sub [0]), (gpointer) 0x01);
563 		gda_column_set_g_type (col, coltype);
564 		gda_column_set_allow_null (col, TRUE);
565 		columns = g_list_prepend (columns, col);
566 		if (mva) {
567 			if (! mvaspec && sub [1] && (gda_g_type_from_string (sub [1]) == G_TYPE_INVALID))
568 				mvaspec = sub [1];
569 			if (mvaspec) {
570 				if ((*mvaspec == '0' && !mvaspec[1]) || !g_ascii_strcasecmp (mvaspec, "null"))
571 					act = MULTIPLE_VALUE_ACTION_SET_NULL;
572 				else if (!g_ascii_strcasecmp (mvaspec, "csv"))
573 					act = MULTIPLE_VALUE_ACTION_CSV_STRING;
574 				if ((*mvaspec == '*' && !mvaspec[1]) || !g_ascii_strncasecmp (mvaspec, "mult", 4))
575 					act = MULTIPLE_VALUE_ACTION_MULTIPLY;
576 				else if (!g_ascii_strcasecmp (mvaspec, "error"))
577 					act = MULTIPLE_VALUE_ACTION_SET_INVALID;
578 				else if (!strcmp (mvaspec, "1"))
579 					act = MULTIPLE_VALUE_ACTION_FIRST;
580 				else if (!g_ascii_strcasecmp (mvaspec, "concat"))
581 					act = MULTIPLE_VALUE_ACTION_CONCAT;
582 			}
583 			g_array_append_val (mva, act);
584 		}
585 		/*g_print ("Defined model column %s (type=>%s) (mva=>%d)\n", array[i],
586 		  gda_g_type_to_string (coltype), act);*/
587 		g_strfreev (sub);
588 	}
589 	g_strfreev (array);
590 	g_hash_table_destroy (colnames);
591 	return g_list_reverse (columns);
592 }
593 
594 
595 /*
596  * _gdaprov_data_model_ldap_new:
597  * @cnc: an LDAP opened connection
598  * @base_dn: the base DN to search on, or %NULL
599  * @filter: an LDAP filter (for example "(objectClass=*)");
600  * @attributes: the list of attributes to fetch, each in the format <attname>[::<GType>] (+CSV,...)
601  * @scope: the search scope
602  *
603  * Creates a new #GdaDataModel object to extract some LDAP contents
604  *
605  * Returns: a new #GdaDataModel
606  */
607 GdaDataModel *
_gdaprov_data_model_ldap_new(GdaConnection * cnc,const gchar * base_dn,const gchar * filter,const gchar * attributes,GdaLdapSearchScope scope)608 _gdaprov_data_model_ldap_new (GdaConnection *cnc, const gchar *base_dn, const gchar *filter,
609 			      const gchar *attributes, GdaLdapSearchScope scope)
610 {
611 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
612 
613 	return (GdaDataModel *) g_object_new (GDA_TYPE_DATA_MODEL_LDAP, "cnc", cnc,
614 					      "base", base_dn,
615 					      "filter", filter, "attributes", attributes,
616 					      "scope", scope,
617 					      NULL);
618 }
619 
620 static gint
gda_data_model_ldap_get_n_rows(GdaDataModel * model)621 gda_data_model_ldap_get_n_rows (GdaDataModel *model)
622 {
623 	GdaDataModelLdap *imodel = (GdaDataModelLdap *) model;
624 
625 	g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (imodel), -1);
626 	g_return_val_if_fail (imodel->priv != NULL, -1);
627 
628 	return -1;
629 }
630 
631 static gint
gda_data_model_ldap_get_n_columns(GdaDataModel * model)632 gda_data_model_ldap_get_n_columns (GdaDataModel *model)
633 {
634 	GdaDataModelLdap *imodel;
635         g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), 0);
636         imodel = GDA_DATA_MODEL_LDAP (model);
637         g_return_val_if_fail (imodel->priv, 0);
638 
639         if (imodel->priv->columns)
640                 return imodel->priv->n_columns;
641         else
642                 return 0;
643 }
644 
645 static GdaColumn *
gda_data_model_ldap_describe_column(GdaDataModel * model,gint col)646 gda_data_model_ldap_describe_column (GdaDataModel *model, gint col)
647 {
648 	GdaDataModelLdap *imodel;
649         g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), NULL);
650         imodel = GDA_DATA_MODEL_LDAP (model);
651         g_return_val_if_fail (imodel->priv, NULL);
652 
653         if (imodel->priv->columns)
654                 return g_list_nth_data (imodel->priv->columns, col);
655         else
656                 return NULL;
657 }
658 
659 static GdaDataModelAccessFlags
gda_data_model_ldap_get_access_flags(GdaDataModel * model)660 gda_data_model_ldap_get_access_flags (GdaDataModel *model)
661 {
662 	GdaDataModelLdap *imodel;
663         GdaDataModelAccessFlags flags;
664 
665         g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), 0);
666         imodel = GDA_DATA_MODEL_LDAP (model);
667         g_return_val_if_fail (imodel->priv, 0);
668 
669 	flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
670 
671         return flags;
672 }
673 
674 static gchar *
csv_quote(const gchar * string)675 csv_quote (const gchar *string)
676 {
677 	gchar *retval, *ptrd;
678 	const gchar *ptrs;
679 	retval = g_new (gchar, strlen (string) * 2 + 3);
680 	*retval = '"';
681 	for (ptrd = retval + 1, ptrs = string; *ptrs; ptrs++) {
682 		if (*ptrs == '"') {
683 			*ptrd = '"';
684 			ptrd++;
685 		}
686 		*ptrd = *ptrs;
687 		ptrd++;
688 	}
689 	*ptrd = '"';
690 	ptrd++;
691 	*ptrd = 0;
692 	return retval;
693 }
694 
695 static void
update_iter_from_ldap_row(GdaDataModelLdap * imodel,GdaDataModelIter * iter)696 update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
697 {
698 	gboolean update_model;
699 	BerElement* ber;
700 	char *attr;
701 	GdaHolder *holder;
702 	gint j, nb;
703 	LdapConnectionData *cdata;
704 	GSList *holders_set = NULL;
705 	cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (imodel->priv->cnc));
706 	g_return_if_fail (cdata);
707 
708 	/* LDAP connection must have been kept opened */
709 	g_assert (cdata->handle);
710 
711 	g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL);
712 	g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
713 
714 	/* column 0 is the DN */
715 	holder = GDA_HOLDER (GDA_SET (iter)->holders->data);
716 	attr = ldap_get_dn (cdata->handle, imodel->priv->current_exec->ldap_row);
717 	if (attr) {
718 		gchar *userdn;
719 		if (gda_ldap_parse_dn (attr, &userdn)) {
720 			if (imodel->priv->base_dn && *imodel->priv->base_dn &&
721 			    imodel->priv->use_rdn &&
722 			    g_str_has_suffix (userdn, imodel->priv->base_dn)) {
723 				gint i;
724 				i = strlen (userdn) - strlen (imodel->priv->base_dn);
725 				if (i > 0) {
726 					userdn [i] = 0;
727 					for (i--; (i >= 0) && (userdn [i] != ','); i--);
728 					if ((i >= 0) && userdn [i] == ',')
729 						userdn [i] = 0;
730 				}
731 			}
732 			gda_holder_set_value_str (holder, NULL, userdn, NULL);
733 			g_free (userdn);
734 		}
735 		else
736 			gda_holder_force_invalid (holder);
737 		ldap_memfree (attr);
738 	}
739 	else
740 		gda_holder_force_invalid (holder);
741 
742 	nb = g_slist_length (((GdaSet*) iter)->holders);
743 	for (j = 1; j < nb; j++) {
744 		holder = (GdaHolder*) (g_slist_nth_data (((GdaSet*) iter)->holders, j));
745 		gda_holder_set_value (holder, NULL, NULL);
746 	}
747 
748 	if (imodel->priv->row_mult)
749 		goto out;
750 
751 	for (attr = ldap_first_attribute (cdata->handle, imodel->priv->current_exec->ldap_row, &ber);
752 	     attr;
753 	     attr = ldap_next_attribute (cdata->handle, imodel->priv->current_exec->ldap_row, ber)) {
754 		BerValue **bvals;
755 		gboolean holder_added_to_cm = FALSE;
756 
757 		holder = gda_set_get_holder ((GdaSet*) iter, attr);
758 		if (!holder)
759 			continue;
760 
761 		j = g_slist_index (((GdaSet*) iter)->holders, holder);
762 
763 		bvals = ldap_get_values_len (cdata->handle,
764 					     imodel->priv->current_exec->ldap_row, attr);
765 		if (bvals) {
766 			if (bvals[0] && bvals[1]) {
767 				/* multiple values */
768 				MultipleValueAction act;
769 				act = g_array_index (imodel->priv->column_mv_actions,
770 						     MultipleValueAction, j-1);
771 				switch (act) {
772 				case MULTIPLE_VALUE_ACTION_SET_NULL:
773 					gda_holder_set_value (holder, NULL, NULL);
774 					break;
775 				case MULTIPLE_VALUE_ACTION_CSV_STRING:
776 					if ((gda_holder_get_g_type (holder) == G_TYPE_STRING)) {
777 						GString *string = NULL;
778 						gint i;
779 						GValue *value;
780 						for (i = 0; bvals[i]; i++) {
781 							gchar *tmp;
782 							if (string)
783 								g_string_append_c (string, ',');
784 							else
785 								string = g_string_new ("");
786 							tmp = csv_quote (bvals[i]->bv_val);
787 							g_string_append (string, tmp);
788 							g_free (tmp);
789 						}
790 						value = gda_value_new (G_TYPE_STRING);
791 						g_value_take_string (value, string->str);
792 						g_string_free (string, FALSE);
793 						gda_holder_take_value (holder, value, NULL);
794 					}
795 					else
796 						gda_holder_force_invalid (holder);
797 					break;
798 				case MULTIPLE_VALUE_ACTION_MULTIPLY: {
799 					ColumnMultiplier *cm;
800 					if (! imodel->priv->row_mult) {
801 						imodel->priv->row_mult = row_multiplier_new ();
802 						/* create @cm for the previous columns */
803 						GSList *list;
804 						for (list = holders_set; list; list = list->next) {
805 							GdaHolder *ch;
806 							ch = (GdaHolder*) list->data;
807 							cm = column_multiplier_new (ch,
808 							               gda_holder_get_value (ch));
809 							g_array_append_val (imodel->priv->row_mult->cms, cm);
810 						}
811 					}
812 					/* add new @cm */
813 					cm = column_multiplier_new (holder, NULL);
814 					gint i;
815 					for (i = 0; bvals[i]; i++) {
816 						GValue *value;
817 						value = gda_ldap_attr_value_to_g_value (cdata,
818 											gda_holder_get_g_type (holder),
819 											bvals[i]);
820 						g_array_append_val (cm->values, value); /* value can be %NULL */
821 					}
822 					g_array_append_val (imodel->priv->row_mult->cms, cm);
823 					holder_added_to_cm = TRUE;
824 					break;
825 				}
826 				case MULTIPLE_VALUE_ACTION_FIRST:
827 					if ((gda_holder_get_g_type (holder) == G_TYPE_STRING)) {
828 						GValue *value;
829 						value = gda_value_new (G_TYPE_STRING);
830 						g_value_set_string (value, bvals[0]->bv_val);
831 						gda_holder_take_value (holder, value, NULL);
832 					}
833 					else
834 						gda_holder_force_invalid (holder);
835 					break;
836 				case MULTIPLE_VALUE_ACTION_CONCAT:
837 					if ((gda_holder_get_g_type (holder) == G_TYPE_STRING)) {
838 						GString *string = NULL;
839 						gint i;
840 						GValue *value;
841 						for (i = 0; bvals[i]; i++) {
842 							if (string)
843 								g_string_append_c (string, '\n');
844 							else
845 								string = g_string_new ("");
846 							g_string_append (string, bvals[i]->bv_val);
847 						}
848 						value = gda_value_new (G_TYPE_STRING);
849 						g_value_take_string (value, string->str);
850 						g_string_free (string, FALSE);
851 						gda_holder_take_value (holder, value, NULL);
852 					}
853 					else
854 						gda_holder_force_invalid (holder);
855 					break;
856 				case MULTIPLE_VALUE_ACTION_SET_INVALID:
857 				default:
858 					gda_holder_force_invalid (holder);
859 					break;
860 				}
861 			}
862 			else if (bvals[0]) {
863 				/* convert string to the correct type */
864 				GValue *value;
865 				value = gda_ldap_attr_value_to_g_value (cdata, gda_holder_get_g_type (holder),
866 									bvals[0]);
867 				if (value)
868 					gda_holder_take_value (holder, value, NULL);
869 				else
870 					gda_holder_force_invalid (holder);
871 			}
872 			else
873 				gda_holder_set_value (holder, NULL, NULL);
874 			ldap_value_free_len (bvals);
875 		}
876 		else
877 			gda_holder_set_value (holder, NULL, NULL);
878 		ldap_memfree (attr);
879 		holders_set = g_slist_prepend (holders_set, holder);
880 		if (imodel->priv->row_mult && !holder_added_to_cm) {
881 			ColumnMultiplier *cm;
882 			cm = column_multiplier_new (holder, gda_holder_get_value (holder));
883 			g_array_append_val (imodel->priv->row_mult->cms, cm);
884 		}
885 	}
886 	if (holders_set)
887 		g_slist_free (holders_set);
888 
889 	if (ber)
890 		ber_free (ber, 0);
891 
892  out:
893 	if (imodel->priv->row_mult)
894 		row_multiplier_set_holders (imodel->priv->row_mult);
895 
896 	if (gda_data_model_iter_is_valid (iter)) {
897 		imodel->priv->iter_row ++;
898 		if ((imodel->priv->iter_row == imodel->priv->n_rows - 1) && imodel->priv->truncated) {
899 			GError *e = NULL;
900 			g_set_error (&e, GDA_DATA_MODEL_ERROR,
901 				     GDA_DATA_MODEL_TRUNCATED_ERROR,
902 				     "%s", _("Truncated result because LDAP server limit encountered"));
903 			add_exception (imodel, e);
904 		}
905 	}
906 	else
907 		imodel->priv->iter_row = 0;
908 
909 	g_object_set (G_OBJECT (iter), "current-row", imodel->priv->iter_row,
910 		      "update-model", update_model, NULL);
911 }
912 
913 /*
914  * Add an exception to @model
915  * WARNING: steals @e
916  */
917 static void
add_exception(GdaDataModelLdap * model,GError * e)918 add_exception (GdaDataModelLdap *model, GError *e)
919 {
920 	if (!model->priv->exceptions)
921 		model->priv->exceptions = g_array_new (TRUE, FALSE, sizeof (GError*));
922 	g_array_append_val (model->priv->exceptions, e);
923 }
924 
925 /*
926  * Execute model->priv->current_exec and either:
927  *     - sets model->priv->current_exec->ldap_msg, or
928  *     - create some children and execute one, or
929  *     - sets model->priv->current_exec->ldap_msg to %NULL if an error occurred
930  *
931  * In any case model->priv->current_exec->executed is set to %TRUE and should be %FALSE when entering
932  * the function (ie. for any LdapConnectionData this function has to be called at most once)
933  */
934 static void
execute_ldap_search(GdaDataModelLdap * model)935 execute_ldap_search (GdaDataModelLdap *model)
936 {
937 	LDAPMessage *msg = NULL;
938 	int lscope, res = 0;
939 	LdapConnectionData *cdata;
940 	cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (model->priv->cnc));
941 	g_return_if_fail (cdata);
942 
943 	GError *e = NULL;
944 	if (! gda_ldap_ensure_bound (cdata, &e)) {
945 		add_exception (model, e);
946 		return;
947 	}
948 
949 	g_assert (model->priv->current_exec);
950 	g_assert (! model->priv->current_exec->executed);
951 
952 	switch (model->priv->current_exec->scope) {
953 	default:
954 	case GDA_LDAP_SEARCH_BASE:
955 		lscope = LDAP_SCOPE_BASE;
956 		break;
957 	case GDA_LDAP_SEARCH_ONELEVEL:
958 		lscope = LDAP_SCOPE_ONELEVEL;
959 		break;
960 	case GDA_LDAP_SEARCH_SUBTREE:
961 		lscope = LDAP_SCOPE_SUBTREE;
962 		break;
963 	}
964 
965 #ifdef GDA_DEBUG_SUBSEARCHES
966 	if (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) {
967 		g_print ("Model %p model->priv->top_exec:\n", model);
968 		ldap_part_dump (model->priv->top_exec);
969 	}
970 #endif
971 
972 #ifdef GDA_DEBUG_SUBSEARCHES_FORCE
973 	/* force sub searches for 2 levels */
974 	static gint sims = 10;
975  retry:
976 	if ((sims > 0) &&
977 	    (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) &&
978 	    (! model->priv->current_exec->parent || ! model->priv->current_exec->parent->parent)) {
979 		g_print ("Simulating LDAP_ADMINLIMIT_EXCEEDED\n");
980 		res = LDAP_ADMINLIMIT_EXCEEDED;
981 		sims --;
982 	}
983 	if (res == 0)
984 #else
985 	retry:
986 #endif
987 	res = ldap_search_ext_s (cdata->handle, model->priv->current_exec->base_dn, lscope,
988 				 model->priv->filter,
989 				 (char**) model->priv->attributes->data, 0,
990 				 NULL, NULL, NULL, -1,
991 				 &msg);
992 	model->priv->current_exec->executed = TRUE;
993 
994 #define GDA_DEBUG_FORCE_ERROR
995 #undef GDA_DEBUG_FORCE_ERROR
996 #ifdef GDA_DEBUG_FORCE_ERROR
997 	/* error */
998 	GError *e = NULL;
999 	int ldap_errno;
1000 	g_print ("SIMULATING error\n");
1001 	ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1002 	g_set_error (&e, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
1003 		     "%s", "Simulated error");
1004 	add_exception (model, e);
1005 	return;
1006 #else
1007 	switch (res) {
1008 	case LDAP_SUCCESS:
1009 	case LDAP_NO_SUCH_OBJECT:
1010 		/* all Ok */
1011 		model->priv->current_exec->ldap_msg = msg;
1012 		model->priv->current_exec->nb_entries = ldap_count_entries (cdata->handle, msg);
1013 
1014 		/* keep the connection opened for this LdapPart */
1015 		cdata->keep_bound_count ++;
1016 
1017 #ifdef GDA_DEBUG_SUBSEARCHES
1018 		g_print ("model->priv->current_exec->nb_entries = %d\n",
1019 			 model->priv->current_exec->nb_entries);
1020 #endif
1021 		break;
1022 	case LDAP_ADMINLIMIT_EXCEEDED:
1023 	case LDAP_SIZELIMIT_EXCEEDED:
1024 	case LDAP_TIMELIMIT_EXCEEDED: {
1025 #ifdef GDA_DEBUG_SUBSEARCHES
1026 		g_print ("LIMIT_EXCEEDED!\n");
1027 #endif
1028 		gboolean handled = FALSE;
1029 		if ((cdata->time_limit == 0) && (cdata->size_limit == 0) &&
1030 		    (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE)) {
1031 			gboolean split_error;
1032 			if (ldap_part_split (model->priv->current_exec, model, &split_error)) {
1033 				/* create some children to re-run the search */
1034 				if (msg)
1035 					ldap_msgfree (msg);
1036 				model->priv->current_exec = LDAP_PART (model->priv->current_exec->children->data);
1037 				execute_ldap_search (model);
1038 				handled = TRUE;
1039 			}
1040 			else if (!split_error) {
1041 				LdapPart *next;
1042 				next = ldap_part_next (model->priv->current_exec, FALSE);
1043 				if (next) {
1044 					model->priv->current_exec = next;
1045 					execute_ldap_search (model);
1046 					handled = TRUE;
1047 				}
1048 			}
1049 		}
1050 		if (!handled) {
1051 			/* truncated output */
1052 #ifdef GDA_DEBUG_SUBSEARCHES
1053 			g_print ("Output truncated!\n");
1054 #endif
1055 			model->priv->truncated = TRUE;
1056 			model->priv->current_exec->ldap_msg = msg;
1057 			model->priv->current_exec->nb_entries = ldap_count_entries (cdata->handle, msg);
1058 
1059 			/* keep the connection opened for this LdapPart */
1060 			cdata->keep_bound_count ++;
1061 		}
1062 		break;
1063 	}
1064 	case LDAP_SERVER_DOWN: {
1065 		gint i;
1066 		for (i = 0; i < 5; i++) {
1067 			if (gda_ldap_rebind (cdata, NULL))
1068 				goto retry;
1069 			g_usleep (G_USEC_PER_SEC * 2);
1070 		}
1071 	}
1072 	default: {
1073 		/* error */
1074 		GError *e = NULL;
1075 		int ldap_errno;
1076 		ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1077 		g_set_error (&e, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
1078 			     "%s", ldap_err2string (ldap_errno));
1079 		add_exception (model, e);
1080 		gda_ldap_may_unbind (cdata);
1081 		return;
1082 	}
1083 	}
1084 #endif /*GDA_DEBUG_FORCE_ERROR*/
1085 
1086 	if (model->priv->truncated) {
1087 		/* compute totel number of rows now that we know it */
1088 		if (model->priv->top_exec->ldap_msg)
1089 			model->priv->n_rows = model->priv->current_exec->nb_entries;
1090 		else {
1091 			LdapPart *iter;
1092 			model->priv->n_rows = 0;
1093 			for (iter = model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
1094 				model->priv->n_rows += iter->nb_entries;
1095 		}
1096 	}
1097 
1098 #ifdef GDA_DEBUG_NO
1099 	gint tmpnb = 0;
1100 	if (model->priv->top_exec->ldap_msg)
1101 		tmpnb = model->priv->current_exec->nb_entries;
1102 	else {
1103 		LdapPart *iter;
1104 		for (iter = model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
1105 			tmpnb += iter->nb_entries;
1106 	}
1107 	g_print ("So far found %d\n", tmpnb);
1108 #endif
1109 }
1110 
1111 static gboolean
gda_data_model_ldap_iter_next(GdaDataModel * model,GdaDataModelIter * iter)1112 gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
1113 {
1114 	GdaDataModelLdap *imodel;
1115 	LdapConnectionData *cdata;
1116 	LdapPart *cpart;
1117 
1118         g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), FALSE);
1119         g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE);
1120         imodel = GDA_DATA_MODEL_LDAP (model);
1121         g_return_val_if_fail (imodel->priv, FALSE);
1122 
1123 	if (! imodel->priv->cnc) {
1124 		/* error */
1125 		gda_data_model_iter_invalidate_contents (iter);
1126 		return FALSE;
1127 	}
1128 
1129 	cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (imodel->priv->cnc));
1130 	if (!cdata || ! gda_ldap_ensure_bound (cdata, NULL)) {
1131 		/* error */
1132 		gda_data_model_iter_invalidate_contents (iter);
1133 		return FALSE;
1134 	}
1135 
1136 	/* initialize LDAP search if necessary */
1137 	if (! imodel->priv->base_dn)
1138 		imodel->priv->base_dn = g_strdup (cdata->base_dn);
1139 	if (! imodel->priv->attributes)
1140 		imodel->priv->attributes = g_array_new (TRUE, FALSE, sizeof (gchar*));
1141 	if (! imodel->priv->top_exec) {
1142 		imodel->priv->top_exec = ldap_part_new (NULL, imodel->priv->base_dn, imodel->priv->scope);
1143 		imodel->priv->current_exec = imodel->priv->top_exec;
1144 	}
1145 
1146 	while (imodel->priv->current_exec) {
1147 		cpart = imodel->priv->current_exec;
1148 		if (! cpart->executed)
1149 			execute_ldap_search (imodel);
1150 		cpart = imodel->priv->current_exec;
1151 		if (! cpart->ldap_msg) {
1152 			/* error somewhere */
1153 			gda_data_model_iter_invalidate_contents (iter);
1154 			gda_ldap_may_unbind (cdata);
1155 			return FALSE;
1156 		}
1157 
1158 		if (! cpart->ldap_row)
1159 			/* not yet on 1st row */
1160 			cpart->ldap_row = ldap_first_entry (cdata->handle, cpart->ldap_msg);
1161 		else {
1162 			if (imodel->priv->row_mult) {
1163 				if (! row_multiplier_index_next (imodel->priv->row_mult)) {
1164 					row_multiplier_free (imodel->priv->row_mult);
1165 					imodel->priv->row_mult = NULL;
1166 				}
1167 			}
1168 			if (! imodel->priv->row_mult) {
1169 				/* move to the next row */
1170 				cpart->ldap_row = ldap_next_entry (cdata->handle, cpart->ldap_row);
1171 			}
1172 		}
1173 
1174 		if (cpart->ldap_row) {
1175 			update_iter_from_ldap_row (imodel, iter);
1176 			break;
1177 		}
1178 		else {
1179 			/* nothing more for this part, switch to the next one */
1180 			ldap_msgfree (imodel->priv->current_exec->ldap_msg);
1181 			imodel->priv->current_exec->ldap_msg = NULL;
1182 
1183 			g_assert (cdata->keep_bound_count > 0);
1184 			cdata->keep_bound_count --;
1185 			gda_ldap_may_unbind (cdata);
1186 
1187 			imodel->priv->current_exec = ldap_part_next (cpart, FALSE);
1188 		}
1189 	}
1190 
1191 	if (!imodel->priv->current_exec) {
1192 		/* execution is over */
1193 		gda_data_model_iter_invalidate_contents (iter);
1194                 g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
1195 		if (imodel->priv->truncated) {
1196 			GError *e = NULL;
1197 			g_set_error (&e, GDA_DATA_MODEL_ERROR,
1198 				     GDA_DATA_MODEL_TRUNCATED_ERROR,
1199 				     "%s", _("Truncated result because LDAP server limit encountered"));
1200 			add_exception (imodel, e);
1201 		}
1202 		g_signal_emit_by_name (iter, "end-of-data");
1203 		gda_ldap_may_unbind (cdata);
1204                 return FALSE;
1205 	}
1206 
1207 	gda_ldap_may_unbind (cdata);
1208 	return TRUE;
1209 }
1210 
1211 static GdaValueAttribute
gda_data_model_ldap_get_attributes_at(GdaDataModel * model,gint col,G_GNUC_UNUSED gint row)1212 gda_data_model_ldap_get_attributes_at (GdaDataModel *model, gint col, G_GNUC_UNUSED gint row)
1213 {
1214 	GdaDataModelLdap *imodel;
1215 	GdaValueAttribute flags;
1216 	GdaColumn *column;
1217 	g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), 0);
1218         imodel = GDA_DATA_MODEL_LDAP (model);
1219 
1220 	if ((col < 0) || (col > imodel->priv->n_columns)) {
1221 		/* error */
1222 		/*
1223 		gchar *tmp;
1224 		tmp = g_strdup_printf (_("Column %d out of range (0-%d)"), col, imodel->priv->n_columns - 1);
1225 		add_error (imodel, tmp);
1226 		g_free (tmp);
1227 		*/
1228 		return 0;
1229 	}
1230 
1231 	flags = GDA_VALUE_ATTR_NO_MODIF;
1232 	column = g_list_nth_data (imodel->priv->columns, col);
1233 	if (gda_column_get_allow_null (column))
1234 		flags |= GDA_VALUE_ATTR_CAN_BE_NULL;
1235 
1236 	return flags;
1237 }
1238 
1239 static GError **
gda_data_model_ldap_get_exceptions(GdaDataModel * model)1240 gda_data_model_ldap_get_exceptions (GdaDataModel *model)
1241 {
1242 	GdaDataModelLdap *imodel;
1243 	g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), NULL);
1244 	imodel = GDA_DATA_MODEL_LDAP (model);
1245 	if (imodel->priv->exceptions)
1246 		return (GError**) imodel->priv->exceptions->data;
1247 	else
1248 		return NULL;
1249 }
1250 
1251 /*
1252  * Parts manipulations
1253  */
1254 static LdapPart *
ldap_part_new(LdapPart * parent,const gchar * base_dn,GdaLdapSearchScope scope)1255 ldap_part_new (LdapPart *parent, const gchar *base_dn, GdaLdapSearchScope scope)
1256 {
1257 	LdapPart *part;
1258 	if (!base_dn || !*base_dn)
1259 		return NULL;
1260 	part = g_new0 (LdapPart, 1);
1261 	part->base_dn = g_strdup (base_dn);
1262 	part->scope = scope;
1263 	part->ldap_msg = NULL;
1264 	part->ldap_row = NULL;
1265 	part->children = NULL;
1266 	part->parent = parent;
1267 	return part;
1268 }
1269 
1270 static void
ldap_part_free(LdapPart * part,LdapConnectionData * cdata)1271 ldap_part_free (LdapPart *part, LdapConnectionData *cdata)
1272 {
1273 	g_assert (part);
1274 	g_free (part->base_dn);
1275 	if (part->children) {
1276 		g_slist_foreach (part->children, (GFunc) ldap_part_free, cdata);
1277 		g_slist_free (part->children);
1278 	}
1279 	if (part->ldap_msg) {
1280 		ldap_msgfree (part->ldap_msg);
1281 
1282 		/* Release the connection being opened for this LdapPart */
1283 		g_assert (cdata);
1284 		g_assert (cdata->keep_bound_count > 0);
1285 		cdata->keep_bound_count --;
1286 		gda_ldap_may_unbind (cdata);
1287 	}
1288 	g_free (part);
1289 }
1290 
1291 /*
1292  * Go to the next part in the tree
1293  */
1294 static LdapPart *
ldap_part_next(LdapPart * part,gboolean executed)1295 ldap_part_next (LdapPart *part, gboolean executed)
1296 {
1297 	LdapPart *parent, *retval = NULL;
1298 	if (part->children)
1299 		retval = LDAP_PART (part->children->data);
1300 	else {
1301 		LdapPart *tmp;
1302 		tmp = part;
1303 		for (parent = tmp->parent; parent; parent = tmp->parent) {
1304 			gint i;
1305 			i = g_slist_index (parent->children, tmp);
1306 			tmp = g_slist_nth_data (parent->children, i+1);
1307 			if (tmp) {
1308 				retval = tmp;
1309 				break;
1310 			}
1311 			else
1312 				tmp = parent;
1313 		}
1314 	}
1315 
1316 	if (retval) {
1317 		if (executed && !retval->executed)
1318 			return ldap_part_next (retval, executed);
1319 		else if (!executed && retval->executed)
1320 			return ldap_part_next (retval, executed);
1321 	}
1322 
1323 	if (retval == part) {
1324 		TO_IMPLEMENT;
1325 	}
1326 	g_assert (retval != part);
1327 	return retval;
1328 }
1329 
1330 /*
1331  * Creates sub parts of @part, one for each immediate child pf @part->base_dn
1332  *
1333  * Returns: %TRUE if part->children is not %NULL
1334  */
1335 static gboolean
ldap_part_split(LdapPart * part,GdaDataModelLdap * model,gboolean * out_error)1336 ldap_part_split (LdapPart *part, GdaDataModelLdap *model, gboolean *out_error)
1337 {
1338 	/* fetch all children entries of @part, and build a child part
1339 	 * for each of them */
1340 	GdaDataModel *mparts;
1341 	GdaDataModelIter *iter;
1342 
1343 	if (out_error)
1344 		*out_error = FALSE;
1345 	g_assert (!part->children);
1346 	mparts = _gdaprov_data_model_ldap_new (model->priv->cnc, part->base_dn, NULL, NULL,
1347 					      GDA_LDAP_SEARCH_ONELEVEL);
1348 	if (!mparts) {
1349 		if (out_error)
1350 			*out_error = TRUE;
1351 		return FALSE;
1352 	}
1353 
1354 	if (part->scope == GDA_LDAP_SEARCH_SUBTREE) {
1355 		/* create a part for the node itself */
1356 		LdapPart *sub = NULL;
1357 		sub = ldap_part_new (part, part->base_dn, GDA_LDAP_SEARCH_BASE);
1358 		g_assert (sub);
1359 		part->children = g_slist_prepend (part->children, sub);
1360 	}
1361 
1362         iter = gda_data_model_create_iter (mparts);
1363         for (; gda_data_model_iter_move_next (iter); ) {
1364 		const GValue *cvalue;
1365 		LdapPart *sub = NULL;
1366 		cvalue = gda_data_model_iter_get_value_at (iter, 0);
1367 		if (cvalue) {
1368 			gchar *tmp;
1369 			tmp = gda_value_stringify (cvalue);
1370 			sub = ldap_part_new (part, tmp, part->scope);
1371 			if (sub)
1372 				part->children = g_slist_prepend (part->children, sub);
1373                         g_free (tmp);
1374 		}
1375 		if (!sub) {
1376 			/* error */
1377 			LdapConnectionData *cdata;
1378 			cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (model->priv->cnc));
1379 			g_slist_foreach (part->children, (GFunc) ldap_part_free, cdata);
1380 			g_slist_free (part->children);
1381 			part->children = NULL;
1382 			break;
1383                 }
1384         }
1385 	g_object_unref (mparts);
1386 
1387 	return part->children ? TRUE : FALSE;
1388 }
1389 
1390 #ifdef GDA_DEBUG_SUBSEARCHES
1391 static void
ldap_part_dump_to_string(LdapPart * part,GString * string,gint index,gboolean recurs)1392 ldap_part_dump_to_string (LdapPart *part, GString *string, gint index, gboolean recurs)
1393 {
1394 	gchar *indent;
1395 	indent = g_new (gchar, index * 4 + 1);
1396 	memset (indent, ' ', sizeof (gchar) * index * 4);
1397 	indent [index * 4] = 0;
1398 	g_string_append (string, indent);
1399 	g_free (indent);
1400 
1401 	g_string_append_printf (string, "part[%p] scope[%d] base[%s] %s nb_entries[%d]\n", part,
1402 				part->scope, part->base_dn,
1403 				part->executed ? "EXEC" : "non exec", part->nb_entries);
1404 
1405 	if (recurs && part->children) {
1406 		GSList *list;
1407 		for (list = part->children; list; list = list->next)
1408 			ldap_part_dump_to_string (LDAP_PART (list->data), string, index+1, recurs);
1409 	}
1410 }
1411 
1412 static void
ldap_part_dump(LdapPart * part)1413 ldap_part_dump (LdapPart *part)
1414 {
1415 	GString *string;
1416 	string = g_string_new ("");
1417 	ldap_part_dump_to_string (part, string, 0, TRUE);
1418 	g_print ("%s\n", string->str);
1419 	g_string_free (string, TRUE);
1420 }
1421 #endif
1422 
1423 
1424 /*
1425  * Row & column multiplier
1426  */
1427 
1428 static ColumnMultiplier *
column_multiplier_new(GdaHolder * holder,const GValue * value)1429 column_multiplier_new (GdaHolder *holder, const GValue *value)
1430 {
1431 	ColumnMultiplier *cm;
1432 	cm = g_new0 (ColumnMultiplier, 1);
1433 	cm->holder = g_object_ref (holder);
1434 	cm->index = 0;
1435 	cm->values = g_array_new (FALSE, FALSE, sizeof (GValue*));
1436 	if (value) {
1437 		GValue *copy;
1438 		copy = gda_value_copy (value);
1439 		g_array_append_val (cm->values, copy);
1440 	}
1441 	return cm;
1442 }
1443 
1444 static RowMultiplier *
row_multiplier_new(void)1445 row_multiplier_new (void)
1446 {
1447 	RowMultiplier *rm;
1448 	rm = g_new0 (RowMultiplier, 1);
1449 	rm->cms = g_array_new (FALSE, FALSE, sizeof (ColumnMultiplier*));
1450 	return rm;
1451 }
1452 
1453 static void
row_multiplier_set_holders(RowMultiplier * rm)1454 row_multiplier_set_holders (RowMultiplier *rm)
1455 {
1456 	gint i;
1457 	for (i = 0; i < rm->cms->len; i++) {
1458 		ColumnMultiplier *cm;
1459 		GValue *value;
1460 		cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1461 		value = g_array_index (cm->values, GValue *, cm->index);
1462 		if (value)
1463 			gda_holder_set_value (cm->holder, value, NULL);
1464 		else
1465 			gda_holder_force_invalid (cm->holder);
1466 	}
1467 }
1468 
1469 static void
row_multiplier_free(RowMultiplier * rm)1470 row_multiplier_free (RowMultiplier *rm)
1471 {
1472 	gint i;
1473 	for (i = 0; i < rm->cms->len; i++) {
1474 		ColumnMultiplier *cm;
1475 		cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1476 		gint j;
1477 		for (j = 0; j < cm->values->len; j++) {
1478 			GValue *value;
1479 			value = g_array_index (cm->values, GValue *, j);
1480 			if (value)
1481 				gda_value_free (value);
1482 		}
1483 		g_array_free (cm->values, TRUE);
1484 		g_object_unref (cm->holder);
1485 		g_free (cm);
1486 	}
1487 	g_array_free (rm->cms, TRUE);
1488 	g_free (rm);
1489 }
1490 
1491 /*
1492  * move indexes one step forward
1493  */
1494 static gboolean
row_multiplier_index_next(RowMultiplier * rm)1495 row_multiplier_index_next (RowMultiplier *rm)
1496 {
1497 	gint i;
1498 #ifdef GDA_DEBUG_NO
1499 	g_print ("RM %p before:\n", rm);
1500 	for (i = 0; i < rm->cms->len; i++) {
1501 		ColumnMultiplier *cm;
1502 		cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1503 		g_print (" %d ", cm->index);
1504 	}
1505 	g_print ("\n");
1506 #endif
1507 
1508 	for (i = 0; ; i++) {
1509 		ColumnMultiplier *cm;
1510 		if (i == rm->cms->len) {
1511 #ifdef GDA_DEBUG_NO
1512 			g_print ("RM %p [FALSE]:\n", rm);
1513 			for (i = 0; i < rm->cms->len; i++) {
1514 				ColumnMultiplier *cm;
1515 				cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1516 				g_print (" %d ", cm->index);
1517 			}
1518 			g_print ("\n");
1519 #endif
1520 			return FALSE;
1521 		}
1522 
1523 		cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1524 		if (cm->index < (cm->values->len - 1)) {
1525 			cm->index ++;
1526 #ifdef GDA_DEBUG_NO
1527 			g_print ("RM %p [TRUE]:\n", rm);
1528 			for (i = 0; i < rm->cms->len; i++) {
1529 				ColumnMultiplier *cm;
1530 				cm = g_array_index (rm->cms, ColumnMultiplier*, i);
1531 				g_print (" %d ", cm->index);
1532 			}
1533 			g_print ("\n");
1534 #endif
1535 			return TRUE;
1536 		}
1537 		else {
1538 			gint j;
1539 			for (j = 0; j < i; j++) {
1540 				cm = g_array_index (rm->cms, ColumnMultiplier*, j);
1541 				cm->index = 0;
1542 			}
1543 		}
1544 	}
1545 }
1546 
1547 /*
1548  * Writing support
1549  */
1550 
1551 typedef struct {
1552 	LdapConnectionData *cdata;
1553 	GArray *mods_array;
1554 } FHData;
1555 static void removed_attrs_func (const gchar *attr_name, GdaLdapAttribute *attr, FHData *data);
1556 
1557 gboolean
gdaprov_ldap_modify(GdaLdapConnection * cnc,GdaLdapModificationType modtype,GdaLdapEntry * entry,GdaLdapEntry * ref_entry,GError ** error)1558 gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
1559 		     GdaLdapEntry *entry, GdaLdapEntry *ref_entry, GError **error)
1560 {
1561 	LdapConnectionData *cdata;
1562 	int res;
1563 
1564 	g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1565 	g_return_val_if_fail (entry, FALSE);
1566 	if (entry)
1567 		g_return_val_if_fail (gdaprov_ldap_is_dn (entry->dn), FALSE);
1568 	if (ref_entry)
1569 		g_return_val_if_fail (gdaprov_ldap_is_dn (ref_entry->dn), FALSE);
1570 
1571 	cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
1572 	g_return_val_if_fail (cdata, FALSE);
1573 
1574 	if (! gda_ldap_ensure_bound (cdata, error))
1575 		return FALSE;
1576 
1577 	/* checks */
1578 	if ((modtype != GDA_LDAP_MODIFICATION_INSERT) &&
1579 	    (modtype != GDA_LDAP_MODIFICATION_ATTR_ADD) &&
1580 	    (modtype != GDA_LDAP_MODIFICATION_ATTR_DEL) &&
1581 	    (modtype != GDA_LDAP_MODIFICATION_ATTR_REPL) &&
1582 	    (modtype != GDA_LDAP_MODIFICATION_ATTR_DIFF)) {
1583 		g_warning (_("Unknown GdaLdapModificationType %d"), modtype);
1584 		gda_ldap_may_unbind (cdata);
1585 		return FALSE;
1586 	}
1587 
1588 	if (((modtype == GDA_LDAP_MODIFICATION_DELETE) || (modtype == GDA_LDAP_MODIFICATION_INSERT)) &&
1589 	    !entry) {
1590 		g_warning ("%s", _("No GdaLdapEntry specified"));
1591 		gda_ldap_may_unbind (cdata);
1592 		return FALSE;
1593 	}
1594 
1595 	if ((modtype == GDA_LDAP_MODIFICATION_ATTR_ADD) && !entry) {
1596 		g_warning ("%s", _("No GdaLdapEntry specified to define attributes to add"));
1597 		gda_ldap_may_unbind (cdata);
1598 		return FALSE;
1599 	}
1600 
1601 	if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DEL) && !entry) {
1602 		g_warning ("%s", _("No GdaLdapEntry specified to define attributes to remove"));
1603 		gda_ldap_may_unbind (cdata);
1604 		return FALSE;
1605 	}
1606 
1607 	if ((modtype == GDA_LDAP_MODIFICATION_ATTR_REPL) && !entry) {
1608 		g_warning ("%s", _("No GdaLdapEntry specified to define attributes to replace"));
1609 		gda_ldap_may_unbind (cdata);
1610 		return FALSE;
1611 	}
1612 
1613 	if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) && (!entry || !ref_entry)) {
1614 		g_warning ("%s", _("No GdaLdapEntry specified to compare attributes"));
1615 		gda_ldap_may_unbind (cdata);
1616 		return FALSE;
1617 	}
1618 	if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) && strcmp (entry->dn, ref_entry->dn)) {
1619 		g_warning ("%s", _("GdaLdapEntry specified to compare have different DN"));
1620 		gda_ldap_may_unbind (cdata);
1621 		return FALSE;
1622 	}
1623 
1624 	/* handle DELETE operation */
1625 	if (modtype == GDA_LDAP_MODIFICATION_DELETE) {
1626 		res = ldap_delete_ext_s (cdata->handle, entry->dn, NULL, NULL);
1627 		if (res != LDAP_SUCCESS) {
1628 			g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
1629 				     "%s", ldap_err2string (res));
1630 			gda_ldap_may_unbind (cdata);
1631 			return FALSE;
1632 		}
1633 		else {
1634 			gda_ldap_may_unbind (cdata);
1635 			return TRUE;
1636 		}
1637 	}
1638 
1639 	/* build array of modifications to perform */
1640 	GArray *mods_array;
1641 	mods_array = g_array_new (TRUE, FALSE, sizeof (LDAPMod*));
1642 	if (modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) {
1643 		/* index ref_entry's attributes */
1644 		GHashTable *hash;
1645 		guint i;
1646 		hash = g_hash_table_new (g_str_hash, g_str_equal);
1647 		for (i = 0; i < ref_entry->nb_attributes; i++) {
1648 			GdaLdapAttribute *attr;
1649 			attr = ref_entry->attributes [i];
1650 			g_hash_table_insert (hash, attr->attr_name, attr);
1651 		}
1652 
1653 		for (i = 0; i < entry->nb_attributes; i++) {
1654 			LDAPMod *mod;
1655 			GdaLdapAttribute *attr, *ref_attr;
1656 			guint j;
1657 
1658 			attr = entry->attributes [i];
1659 			ref_attr = g_hash_table_lookup (hash, attr->attr_name);
1660 
1661 			mod = g_new0 (LDAPMod, 1);
1662 			mod->mod_type = attr->attr_name; /* no duplication */
1663 			if (ref_attr) {
1664 				mod->mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE;
1665 				g_hash_table_remove (hash, attr->attr_name);
1666 			}
1667 			else
1668 				mod->mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD;
1669 
1670 			mod->mod_bvalues = g_new0 (struct berval *, attr->nb_values + 1); /* last is NULL */
1671 			for (j = 0; j < attr->nb_values; j++)
1672 				mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (cdata, attr->values [j]);
1673 			g_array_append_val (mods_array, mod);
1674 		}
1675 
1676 		FHData fhdata;
1677 		fhdata.cdata = cdata;
1678 		fhdata.mods_array = mods_array;
1679 		g_hash_table_foreach (hash, (GHFunc) removed_attrs_func, &fhdata);
1680 		g_hash_table_destroy (hash);
1681 	}
1682 	else {
1683 		guint i;
1684 		for (i = 0; i < entry->nb_attributes; i++) {
1685 			LDAPMod *mod;
1686 			GdaLdapAttribute *attr;
1687 			guint j;
1688 
1689 			attr = entry->attributes [i];
1690 			mod = g_new0 (LDAPMod, 1);
1691 			mod->mod_op = LDAP_MOD_BVALUES;
1692 			if ((modtype == GDA_LDAP_MODIFICATION_INSERT) ||
1693 			    (modtype == GDA_LDAP_MODIFICATION_ATTR_ADD))
1694 				mod->mod_op |= LDAP_MOD_ADD;
1695 			else if (modtype == GDA_LDAP_MODIFICATION_ATTR_DEL)
1696 				mod->mod_op |= LDAP_MOD_DELETE;
1697 			else
1698 				mod->mod_op |= LDAP_MOD_REPLACE;
1699 			mod->mod_type = attr->attr_name; /* no duplication */
1700 			mod->mod_bvalues = g_new0 (struct berval *, attr->nb_values + 1); /* last is NULL */
1701 			for (j = 0; j < attr->nb_values; j++)
1702 				mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (cdata, attr->values [j]);
1703 			g_array_append_val (mods_array, mod);
1704 		}
1705 	}
1706 
1707 	gboolean retval = TRUE;
1708 	if (mods_array->len > 0) {
1709 		/* apply modifications */
1710 		if (modtype == GDA_LDAP_MODIFICATION_INSERT)
1711 			res = ldap_add_ext_s (cdata->handle, entry->dn, (LDAPMod **) mods_array->data, NULL, NULL);
1712 		else
1713 			res = ldap_modify_ext_s (cdata->handle, entry->dn, (LDAPMod **) mods_array->data, NULL, NULL);
1714 
1715 		if (res != LDAP_SUCCESS) {
1716 			g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
1717 				     "%s", ldap_err2string (res));
1718 			retval = FALSE;
1719 		}
1720 	}
1721 
1722 	/* clear tmp data */
1723 	guint i;
1724 	for (i = 0; i < mods_array->len; i++) {
1725 		LDAPMod *mod;
1726 		mod = g_array_index (mods_array, LDAPMod*, i);
1727 		if (mod->mod_values) {
1728 			guint j;
1729 			for (j = 0; mod->mod_values [j]; j++)
1730 				gda_ldap_attr_value_free (cdata, mod->mod_bvalues [j]);
1731 			g_free (mod->mod_values);
1732 		}
1733 		g_free (mod);
1734 	}
1735 	g_array_free (mods_array, TRUE);
1736 
1737 	gda_ldap_may_unbind (cdata);
1738 	return retval;
1739 }
1740 
1741 static void
removed_attrs_func(const gchar * attr_name,GdaLdapAttribute * attr,FHData * data)1742 removed_attrs_func (const gchar *attr_name, GdaLdapAttribute *attr, FHData *data)
1743 {
1744 	LDAPMod *mod;
1745 	guint j;
1746 
1747 	mod = g_new0 (LDAPMod, 1);
1748 	mod->mod_op = LDAP_MOD_BVALUES | LDAP_MOD_DELETE;
1749 	mod->mod_type = attr->attr_name; /* no duplication */
1750 	mod->mod_bvalues = g_new0 (struct berval *, attr->nb_values + 1); /* last is NULL */
1751 	for (j = 0; j < attr->nb_values; j++)
1752 		mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (data->cdata, attr->values [j]);
1753 	g_array_append_val (data->mods_array, mod);
1754 }
1755 
1756 gboolean
gdaprov_ldap_rename_entry(GdaLdapConnection * cnc,const gchar * current_dn,const gchar * new_dn,GError ** error)1757 gdaprov_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, const gchar *new_dn,
1758 			   GError **error)
1759 {
1760 	g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1761 	g_return_val_if_fail (current_dn && *current_dn, FALSE);
1762 	g_return_val_if_fail (gdaprov_ldap_is_dn (current_dn), FALSE);
1763 	g_return_val_if_fail (new_dn && *new_dn, FALSE);
1764 	g_return_val_if_fail (gdaprov_ldap_is_dn (new_dn), FALSE);
1765 
1766 	LdapConnectionData *cdata;
1767 	cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
1768 	g_return_val_if_fail (cdata, FALSE);
1769 
1770 	if (! gda_ldap_ensure_bound (cdata, error))
1771 		return FALSE;
1772 
1773 	gchar **carray, **narray;
1774 	int res;
1775 	gboolean retval = TRUE;
1776 	gchar *parent = NULL;
1777 
1778 	carray = gda_ldap_dn_split (current_dn, FALSE);
1779 	narray = gda_ldap_dn_split (new_dn, FALSE);
1780 
1781 	if (carray[1] && narray[1] && strcmp (carray[1], narray[1]))
1782 		parent = narray [1];
1783 	else if (! carray[1] && narray[1])
1784 		parent = narray [1];
1785 
1786 	res = ldap_rename_s (cdata->handle, current_dn, narray[0], parent, 1, NULL, NULL);
1787 	g_strfreev (carray);
1788 	g_strfreev (narray);
1789 
1790 	if (res != LDAP_SUCCESS) {
1791 		g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
1792 			     "%s", ldap_err2string (res));
1793 		retval = FALSE;
1794 	}
1795 
1796 	gda_ldap_may_unbind (cdata);
1797 	return retval;
1798 }
1799