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 (®istering);
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 (®istering);
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