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 <glib/gi18n-lib.h>
21 #include <string.h>
22 #include <gda-util.h>
23 #include "gda-ldap-connection.h"
24 #include <libgda/gda-connection-private.h>
25 #include <sql-parser/gda-sql-parser.h>
26 #include <libgda/gda-debug-macros.h>
27
28 /* "inherits" GdaVconnectionDataModelSpec */
29 typedef struct {
30 GdaVconnectionDataModelSpec spec;
31 GdaConnection *ldap_cnc;
32 gchar *table_name;
33 gchar *base_dn;
34 gchar *filter;
35 gchar *attributes;
36 GList *columns;
37 GdaLdapSearchScope scope;
38
39 GHashTable *filters_hash; /* key = string; value = a ComputedFilter pointer */
40 } LdapTableMap;
41
42 static void
_ldap_table_map_free(LdapTableMap * map)43 _ldap_table_map_free (LdapTableMap *map)
44 {
45 if (map->ldap_cnc)
46 g_object_unref (map->ldap_cnc);
47 g_free (map->table_name);
48 g_free (map->base_dn);
49 g_free (map->filter);
50 g_free (map->attributes);
51 if (map->columns) {
52 g_list_foreach (map->columns, (GFunc) g_object_unref, NULL);
53 g_list_free (map->columns);
54 }
55 if (map->filters_hash)
56 g_hash_table_destroy (map->filters_hash);
57 g_free (map);
58 }
59
60 struct _GdaLdapConnectionPrivate {
61 GSList *maps; /* list of #LdapTableMap, no ref held there */
62 gchar *startup_file;
63 gboolean loading_startup_file;
64 };
65
66 static void gda_ldap_connection_class_init (GdaLdapConnectionClass *klass);
67 static void gda_ldap_connection_init (GdaLdapConnection *cnc, GdaLdapConnectionClass *klass);
68 static void gda_ldap_connection_dispose (GObject *object);
69 static void gda_ldap_connection_set_property (GObject *object,
70 guint param_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static void gda_ldap_connection_get_property (GObject *object,
74 guint param_id,
75 GValue *value,
76 GParamSpec *pspec);
77
78 static GObjectClass *parent_class = NULL;
79
80 /* properties */
81 enum
82 {
83 PROP_0,
84 PROP_STARTUP_FILE
85 };
86
87 static void
update_connection_startup_file(GdaLdapConnection * cnc)88 update_connection_startup_file (GdaLdapConnection *cnc)
89 {
90 if (! cnc->priv->startup_file || cnc->priv->loading_startup_file)
91 return;
92
93 GSList *list;
94 GString *string = NULL;
95 GError *lerror = NULL;
96
97 string = g_string_new ("");
98 for (list = cnc->priv->maps; list; list = list->next) {
99 LdapTableMap *map = (LdapTableMap*) list->data;
100 g_string_append_printf (string, "CREATE LDAP TABLE %s ", map->table_name);
101 if (map->base_dn)
102 g_string_append_printf (string, "BASE='%s' ", map->base_dn);
103 if (map->filter)
104 g_string_append_printf (string, "FILTER='%s' ", map->filter);
105 if (map->attributes)
106 g_string_append_printf (string, "ATTRIBUTES='%s' ", map->attributes);
107 g_string_append (string, "SCOPE=");
108 switch (map->scope) {
109 case GDA_LDAP_SEARCH_BASE:
110 g_string_append (string, "'BASE';\n");
111 break;
112 case GDA_LDAP_SEARCH_ONELEVEL:
113 g_string_append (string, "'ONELEVEL';\n");
114 break;
115 case GDA_LDAP_SEARCH_SUBTREE:
116 g_string_append (string, "'SUBTREE';\n");
117 break;
118 default:
119 g_assert_not_reached ();
120 }
121 }
122 if (! g_file_set_contents (cnc->priv->startup_file, string->str, -1, &lerror)) {
123 GdaConnectionEvent *event;
124 gchar *msg;
125 event = gda_connection_point_available_event (GDA_CONNECTION (cnc),
126 GDA_CONNECTION_EVENT_WARNING);
127 msg = g_strdup_printf (_("Error storing list of created LDAP tables: %s"),
128 lerror && lerror->message ? lerror->message : _("No detail"));
129 gda_connection_event_set_description (event, msg);
130 gda_connection_add_event (GDA_CONNECTION (cnc), event);
131 g_free (msg);
132 g_clear_error (&lerror);
133 }
134 }
135
136 #ifdef GDA_DEBUG_NO
137 static void
dump_vtables(GdaLdapConnection * cnc)138 dump_vtables (GdaLdapConnection *cnc)
139 {
140 GSList *list;
141 g_print ("LDAP tables: %d\n", g_slist_length (cnc->priv->maps));
142 for (list = cnc->priv->maps; list; list = list->next) {
143 LdapTableMap *map = (LdapTableMap*) list->data;
144 g_print (" LDAP Vtable: %s (map %p)\n", map->table_name, map);
145 }
146 }
147 #endif
148
149 static void
vtable_created(GdaVconnectionDataModel * cnc,const gchar * table_name)150 vtable_created (GdaVconnectionDataModel *cnc, const gchar *table_name)
151 {
152 #ifdef GDA_DEBUG_NO
153 g_print ("VTable created: %s\n", table_name);
154 dump_vtables (GDA_LDAP_CONNECTION (cnc));
155 #endif
156 if (GDA_VCONNECTION_DATA_MODEL_CLASS (parent_class)->vtable_created)
157 GDA_VCONNECTION_DATA_MODEL_CLASS (parent_class)->vtable_created (cnc, table_name);
158 update_connection_startup_file (GDA_LDAP_CONNECTION (cnc));
159 }
160
161 static void
vtable_dropped(GdaVconnectionDataModel * cnc,const gchar * table_name)162 vtable_dropped (GdaVconnectionDataModel *cnc, const gchar *table_name)
163 {
164 GdaLdapConnection *lcnc;
165 LdapTableMap *map = NULL;
166 GSList *list;
167
168 lcnc = GDA_LDAP_CONNECTION (cnc);
169 for (list = lcnc->priv->maps; list; list = list->next) {
170 if (!strcmp (((LdapTableMap*)list->data)->table_name, table_name)) {
171 map = (LdapTableMap*)list->data;
172 break;
173 }
174 }
175 if (map) {
176 lcnc->priv->maps = g_slist_remove (lcnc->priv->maps, map);
177 #ifdef GDA_DEBUG_NO
178 g_print ("VTable dropped: %s\n", table_name);
179 dump_vtables (lcnc);
180 #endif
181 }
182 if (GDA_VCONNECTION_DATA_MODEL_CLASS (parent_class)->vtable_dropped)
183 GDA_VCONNECTION_DATA_MODEL_CLASS (parent_class)->vtable_dropped (cnc, table_name);
184 update_connection_startup_file (GDA_LDAP_CONNECTION (cnc));
185 }
186
187 /*
188 * GdaLdapConnection class implementation
189 */
190 static void
gda_ldap_connection_class_init(GdaLdapConnectionClass * klass)191 gda_ldap_connection_class_init (GdaLdapConnectionClass *klass)
192 {
193 GObjectClass *object_class = G_OBJECT_CLASS (klass);
194
195 parent_class = g_type_class_peek_parent (klass);
196 object_class->dispose = gda_ldap_connection_dispose;
197 GDA_VCONNECTION_DATA_MODEL_CLASS (klass)->vtable_created = vtable_created;
198 GDA_VCONNECTION_DATA_MODEL_CLASS (klass)->vtable_dropped = vtable_dropped;
199
200 /* Properties */
201 object_class->set_property = gda_ldap_connection_set_property;
202 object_class->get_property = gda_ldap_connection_get_property;
203 g_object_class_install_property (object_class, PROP_STARTUP_FILE,
204 g_param_spec_string ("startup-file", NULL, _("File used to store startup data"), NULL,
205 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
206 }
207
208 static void
dsn_set_cb(GdaLdapConnection * cnc,G_GNUC_UNUSED GParamSpec * pspec,G_GNUC_UNUSED gpointer data)209 dsn_set_cb (GdaLdapConnection *cnc, G_GNUC_UNUSED GParamSpec *pspec, G_GNUC_UNUSED gpointer data)
210 {
211 gchar *fname, *tmp, *dsn;
212 g_object_get (cnc, "dsn", &dsn, NULL);
213 tmp = g_strdup_printf ("ldap-%s.start", dsn);
214 g_free (dsn);
215 fname = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
216 "libgda", tmp, NULL);
217 g_free (tmp);
218 g_free (cnc->priv->startup_file);
219 cnc->priv->startup_file = fname;
220 }
221
222 static void
conn_opened_cb(GdaLdapConnection * cnc,G_GNUC_UNUSED gpointer data)223 conn_opened_cb (GdaLdapConnection *cnc, G_GNUC_UNUSED gpointer data)
224 {
225 if (!cnc->priv->startup_file)
226 return;
227
228 cnc->priv->loading_startup_file = TRUE;
229
230 GdaSqlParser *parser;
231 GdaBatch *batch;
232 GError *lerror = NULL;
233 parser = gda_connection_create_parser (GDA_CONNECTION (cnc));
234 if (!parser)
235 parser = gda_sql_parser_new ();
236 batch = gda_sql_parser_parse_file_as_batch (parser, cnc->priv->startup_file, &lerror);
237 if (batch) {
238 GSList *list;
239 list = gda_connection_batch_execute (GDA_CONNECTION (cnc), batch, NULL, 0, &lerror);
240 g_slist_foreach (list, (GFunc) g_object_unref, NULL);
241 g_slist_free (list);
242 g_object_unref (batch);
243 }
244 if (lerror) {
245 GdaConnectionEvent *event;
246 gchar *msg;
247 event = gda_connection_point_available_event (GDA_CONNECTION (cnc),
248 GDA_CONNECTION_EVENT_WARNING);
249 msg = g_strdup_printf (_("Error recreating LDAP tables: %s"),
250 lerror && lerror->message ? lerror->message : _("No detail"));
251 gda_connection_event_set_description (event, msg);
252 gda_connection_add_event (GDA_CONNECTION (cnc), event);
253 g_free (msg);
254 g_clear_error (&lerror);
255 }
256 g_object_unref (parser);
257
258 cnc->priv->loading_startup_file = FALSE;
259 }
260
261 static void
gda_ldap_connection_init(GdaLdapConnection * cnc,G_GNUC_UNUSED GdaLdapConnectionClass * klass)262 gda_ldap_connection_init (GdaLdapConnection *cnc, G_GNUC_UNUSED GdaLdapConnectionClass *klass)
263 {
264 cnc->priv = g_new (GdaLdapConnectionPrivate, 1);
265 cnc->priv->maps = NULL;
266 cnc->priv->startup_file = NULL;
267 cnc->priv->loading_startup_file = FALSE;
268
269 g_signal_connect (cnc, "notify::dsn",
270 G_CALLBACK (dsn_set_cb), NULL);
271 g_signal_connect (cnc, "conn-opened",
272 G_CALLBACK (conn_opened_cb), NULL);
273 }
274
275 static void
gda_ldap_connection_dispose(GObject * object)276 gda_ldap_connection_dispose (GObject *object)
277 {
278 GdaLdapConnection *cnc = (GdaLdapConnection *) object;
279
280 g_return_if_fail (GDA_IS_LDAP_CONNECTION (cnc));
281
282 /* free memory */
283 if (cnc->priv) {
284 if (cnc->priv->maps)
285 g_slist_free (cnc->priv->maps);
286 g_free (cnc->priv->startup_file);
287 g_free (cnc->priv);
288 cnc->priv = NULL;
289 }
290
291 /* chain to parent class */
292 parent_class->dispose (object);
293 }
294
295 GType
gda_ldap_connection_get_type(void)296 gda_ldap_connection_get_type (void)
297 {
298 static GType type = 0;
299
300 if (G_UNLIKELY (type == 0)) {
301 static GMutex registering;
302 if (type == 0) {
303 static GTypeInfo info = {
304 sizeof (GdaLdapConnectionClass),
305 (GBaseInitFunc) NULL,
306 (GBaseFinalizeFunc) NULL,
307 (GClassInitFunc) gda_ldap_connection_class_init,
308 NULL, NULL,
309 sizeof (GdaLdapConnection),
310 0,
311 (GInstanceInitFunc) gda_ldap_connection_init,
312 0
313 };
314
315 g_mutex_lock (®istering);
316 if (type == 0)
317 type = g_type_register_static (GDA_TYPE_VCONNECTION_DATA_MODEL, "GdaLdapConnection", &info, 0);
318 g_mutex_unlock (®istering);
319 }
320 }
321
322 return type;
323 }
324
325 static void
gda_ldap_connection_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)326 gda_ldap_connection_set_property (GObject *object,
327 guint param_id,
328 const GValue *value,
329 GParamSpec *pspec)
330 {
331 GdaLdapConnection *cnc;
332 cnc = GDA_LDAP_CONNECTION (object);
333 if (cnc->priv) {
334 switch (param_id) {
335 case PROP_STARTUP_FILE: {
336 if (cnc->priv->startup_file) {
337 /* don't override any preexisting setting from a DSN */
338 gchar *dsn;
339 g_object_get (cnc, "dsn", &dsn, NULL);
340 if (dsn)
341 g_free (dsn);
342 else {
343 g_free (cnc->priv->startup_file);
344 cnc->priv->startup_file = NULL;
345 }
346 }
347 if (! cnc->priv->startup_file) {
348 if (g_value_get_string (value))
349 cnc->priv->startup_file = g_value_dup_string (value);
350 }
351 break;
352 }
353 default:
354 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
355 break;
356 }
357 }
358 }
359
360 static void
gda_ldap_connection_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)361 gda_ldap_connection_get_property (GObject *object,
362 guint param_id,
363 GValue *value,
364 GParamSpec *pspec)
365 {
366 GdaLdapConnection *cnc;
367 cnc = GDA_LDAP_CONNECTION (object);
368 if (cnc->priv) {
369 switch (param_id) {
370 case PROP_STARTUP_FILE:
371 g_value_set_string (value, cnc->priv->startup_file);
372 break;
373 default:
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
375 break;
376 }
377 }
378 }
379
380 static GList *
_ldap_create_columns_func(GdaVconnectionDataModelSpec * spec,G_GNUC_UNUSED GError ** error)381 _ldap_create_columns_func (GdaVconnectionDataModelSpec *spec, G_GNUC_UNUSED GError **error)
382 {
383 LdapTableMap *map = (LdapTableMap *) spec;
384 if (!map->columns)
385 map->columns = gda_data_model_ldap_compute_columns (map->ldap_cnc, map->attributes);
386 g_list_foreach (map->columns, (GFunc) g_object_ref, NULL);
387 return g_list_copy (map->columns);
388 }
389
390 static gchar *
make_string_for_filter(GdaVconnectionDataModelFilter * info)391 make_string_for_filter (GdaVconnectionDataModelFilter *info)
392 {
393 GString *string;
394 gint i;
395
396 string = g_string_new ("");
397 for (i = 0; i < info->nConstraint; i++) {
398 const struct GdaVirtualConstraint *cons;
399 cons = &(info->aConstraint [i]);
400 g_string_append_printf (string, "|%d,%d", cons->iColumn, cons->op);
401 }
402 return g_string_free (string, FALSE);
403 }
404
405 typedef struct {
406 gint dn_constindex; /* constraint number to set the DN from when actually executing the LDAP search, or -1 */
407 gchar *ldap_filter; /* in LDAP format, with @xxx@ to bind values */
408 struct GdaVirtualConstraintUsage *out_const;
409 } ComputedFilter;
410
411 static void
computed_filter_free(ComputedFilter * filter)412 computed_filter_free (ComputedFilter *filter)
413 {
414 g_free (filter->out_const);
415 g_free (filter->ldap_filter);
416 g_free (filter);
417 }
418
419 #define MARKER_ESCAPE_CHAR 1
420 #define MARKER_GLOB_CHAR 2
421 static void
_ldap_table_create_filter(GdaVconnectionDataModelSpec * spec,GdaVconnectionDataModelFilter * info)422 _ldap_table_create_filter (GdaVconnectionDataModelSpec *spec, GdaVconnectionDataModelFilter *info)
423 {
424 /*
425 * REM:
426 * - LDAP does not allow filtering on the DN => filter only is some cases
427 * - LDAP does not handle ordering of results => the 'ORDER BY' constraint is ignored
428 * - the '>' and '<' operators are not allowed in search strings => using '>=' and '<=' and
429 * have SQLite do the actual check
430 */
431 LdapTableMap *map = (LdapTableMap *) spec;
432 GString *filter_string = NULL;
433 gint i, ncols;
434 gint dn_constindex = -1;
435 gchar *hash;
436
437 info->orderByConsumed = FALSE;
438 hash = make_string_for_filter (info);
439 if (map->filters_hash) {
440 ComputedFilter *filter;
441 filter = g_hash_table_lookup (map->filters_hash, hash);
442 if (filter) {
443 info->idxPointer = (gpointer) filter;
444 info->orderByConsumed = FALSE;
445 memcpy (info->aConstraintUsage,
446 filter->out_const,
447 sizeof (struct GdaVirtualConstraintUsage) * info->nConstraint);
448 /*g_print ("Reusing filter %p, hash=[%s]\n", filter, hash);*/
449 g_free (hash);
450 return;
451 }
452 }
453
454 if (!map->columns)
455 map->columns = gda_data_model_ldap_compute_columns (map->ldap_cnc, map->attributes);
456
457 ncols = g_list_length (map->columns);
458 for (i = 0; i < info->nConstraint; i++) {
459 const struct GdaVirtualConstraint *cons;
460 cons = &(info->aConstraint [i]);
461 const gchar *attrname;
462
463 info->aConstraintUsage[i].argvIndex = i+1;
464 info->aConstraintUsage[i].omit = TRUE;
465
466 if (cons->iColumn < 0) {
467 g_warning ("Internal error: negative column number!");
468 goto nofilter;
469 }
470 if (cons->iColumn >= ncols) {
471 g_warning ("Internal error: SQLite's virtual table column %d is not known for "
472 "table '%s', which has %d column(s)", cons->iColumn, map->table_name,
473 ncols);
474 goto nofilter;
475 }
476 if (cons->iColumn == 0) {
477 /* try to optimize on the DN column */
478 if ((map->scope == GDA_LDAP_SEARCH_BASE) ||
479 (map->scope == GDA_LDAP_SEARCH_ONELEVEL))
480 goto nofilter;
481 if (cons->op != GDA_SQL_OPERATOR_TYPE_EQ)
482 goto nofilter;
483 if (dn_constindex != -1) /* DN is already filtered by a constraint */
484 goto nofilter;
485 dn_constindex = i;
486 continue;
487 }
488
489 attrname = gda_column_get_name (GDA_COLUMN (g_list_nth_data (map->columns, cons->iColumn)));
490 if (! filter_string) {
491 if ((info->nConstraint > 1) || map->filter)
492 filter_string = g_string_new ("(& ");
493 else
494 filter_string = g_string_new ("");
495 if (map->filter)
496 g_string_append (filter_string, map->filter);
497 }
498 switch (cons->op) {
499 case GDA_SQL_OPERATOR_TYPE_EQ:
500 g_string_append_printf (filter_string, "(%s=%c)", attrname, MARKER_ESCAPE_CHAR);
501 break;
502 case GDA_SQL_OPERATOR_TYPE_GT:
503 g_string_append_printf (filter_string, "(%s>=%c)", attrname, MARKER_ESCAPE_CHAR);
504 info->aConstraintUsage[i].omit = FALSE;
505 break;
506 case GDA_SQL_OPERATOR_TYPE_LEQ:
507 g_string_append_printf (filter_string, "(%s<=%c)", attrname, MARKER_ESCAPE_CHAR);
508 info->aConstraintUsage[i].omit = FALSE;
509 break;
510 case GDA_SQL_OPERATOR_TYPE_LT:
511 g_string_append_printf (filter_string, "(%s<=%c)", attrname, MARKER_ESCAPE_CHAR);
512 break;
513 case GDA_SQL_OPERATOR_TYPE_GEQ:
514 g_string_append_printf (filter_string, "(%s>=%c)", attrname, MARKER_ESCAPE_CHAR);
515 break;
516 case GDA_SQL_OPERATOR_TYPE_REGEXP:
517 g_string_append_printf (filter_string, "(%s=%c)", attrname, MARKER_GLOB_CHAR);
518 break;
519 default:
520 /* Can't be done with LDAP */
521 goto nofilter;
522 }
523 }
524
525 if (!filter_string && (dn_constindex == -1))
526 goto nofilter;
527
528 if (filter_string && ((info->nConstraint > 1) || map->filter))
529 g_string_append_c (filter_string, ')');
530 /*g_print ("FILTER: [%s]\n", filter_string->str);*/
531
532 ComputedFilter *filter;
533 filter = g_new0 (ComputedFilter, 1);
534 filter->dn_constindex = dn_constindex;
535 if (filter_string)
536 filter->ldap_filter = g_string_free (filter_string, FALSE);
537 else if (map->filter)
538 filter->ldap_filter = g_strdup (map->filter);
539 filter->out_const = g_new (struct GdaVirtualConstraintUsage, info->nConstraint);
540 memcpy (filter->out_const,
541 info->aConstraintUsage,
542 sizeof (struct GdaVirtualConstraintUsage) * info->nConstraint);
543
544 info->idxPointer = (gpointer) filter;
545 if (! map->filters_hash)
546 map->filters_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
547 g_free,
548 (GDestroyNotify) computed_filter_free);
549 g_hash_table_insert (map->filters_hash, hash, filter);
550 /*g_print ("There are now %d statements in store...\n", g_hash_table_size (map->filters_hash));*/
551 return;
552
553 nofilter:
554 if (filter_string)
555 g_string_free (filter_string, TRUE);
556 for (i = 0; i < info->nConstraint; i++) {
557 info->aConstraintUsage[i].argvIndex = 0;
558 info->aConstraintUsage[i].omit = TRUE;
559 }
560 info->idxPointer = NULL;
561 }
562
563 static GdaDataModel *
_ldap_table_create_model_func(GdaVconnectionDataModelSpec * spec,G_GNUC_UNUSED int idxNum,const char * idxStr,int argc,GValue ** argv)564 _ldap_table_create_model_func (GdaVconnectionDataModelSpec *spec, G_GNUC_UNUSED int idxNum, const char *idxStr,
565 int argc, GValue **argv)
566 {
567 LdapTableMap *map = (LdapTableMap *) spec;
568 GdaDataModel *model;
569
570 if (idxStr) {
571 const gchar *ptr;
572 gint pos;
573 GString *real_filter = NULL;
574 ComputedFilter *filter = (ComputedFilter *) idxStr;
575
576 for (pos = 0, ptr = filter->ldap_filter ? filter->ldap_filter : ""; *ptr; ptr++) {
577 if (pos == filter->dn_constindex)
578 pos++; /* skip this constraint position */
579 if (! real_filter)
580 real_filter = g_string_new ("");
581 if ((*ptr == MARKER_ESCAPE_CHAR) || (*ptr == MARKER_GLOB_CHAR)){
582 gchar *str, *sptr;
583 gchar marker;
584 marker = *ptr;
585 g_assert (pos < argc);
586 str = gda_value_stringify (argv[pos]);
587 for (sptr = str; *sptr; sptr++) {
588 if ((*sptr == ')') || (*sptr == '(') || (*sptr == '\\') || (*sptr == '*'))
589 break;
590 if ((marker == MARKER_GLOB_CHAR) && (*sptr == '%'))
591 break;
592 }
593 if (*sptr) {
594 /* make the substitutions */
595 GString *string;
596 string = g_string_new ("");
597 for (sptr = str; *sptr; sptr++) {
598 if (*sptr == ')')
599 g_string_append (string, "\\29");
600 else if (*sptr == '(')
601 g_string_append (string, "\\28");
602 else if (*sptr == '\\')
603 g_string_append (string, "\\5c");
604 else if (*sptr == '*')
605 g_string_append (string, "\\2a");
606 else if ((marker == MARKER_GLOB_CHAR) && (*sptr == '%'))
607 g_string_append_c (string, '*');
608 else
609 g_string_append_c (string, *sptr);
610 }
611 g_free (str);
612 str = g_string_free (string, FALSE);
613 }
614 g_string_append (real_filter, str);
615 g_free (str);
616 pos++;
617 }
618 else
619 g_string_append_c (real_filter, *ptr);
620 }
621
622 gchar *real_dn = NULL;
623 GdaLdapSearchScope real_scope = map->scope;
624 if (filter->dn_constindex != -1) {
625 /* check that the DN is a child of the data model's base DN */
626 const gchar *bdn;
627 gchar *tmp;
628 bdn = map->base_dn;
629 if (!bdn)
630 bdn = gda_ldap_connection_get_base_dn (GDA_LDAP_CONNECTION (map->ldap_cnc));
631 g_assert (bdn);
632 tmp = gda_value_stringify (argv[filter->dn_constindex]);
633 if (g_str_has_suffix (tmp, bdn)) {
634 real_scope = GDA_LDAP_SEARCH_BASE;
635 real_dn = gda_value_stringify (argv[filter->dn_constindex]);
636 }
637 else {
638 /* return empty set */
639 if (real_filter)
640 g_string_free (real_filter, TRUE);
641 real_filter = g_string_new ("(objectClass=)");
642 }
643 g_free (tmp);
644 }
645
646 /*g_print ("FILTER to use: LDAPFilter=> [%s] LDAPDn => [%s] SCOPE => [%d]\n",
647 real_filter ? real_filter->str : NULL,
648 real_dn ? real_dn : map->base_dn, real_scope);*/
649 model = gda_data_model_ldap_new (map->ldap_cnc,
650 real_dn ? real_dn : map->base_dn,
651 real_filter ? real_filter->str : NULL,
652 map->attributes, real_scope);
653 if (real_filter)
654 g_string_free (real_filter, TRUE);
655 g_free (real_dn);
656 }
657 else
658 model = gda_data_model_ldap_new (map->ldap_cnc, map->base_dn, map->filter,
659 map->attributes, map->scope);
660
661 return model;
662 }
663
664 /**
665 * gda_ldap_connection_declare_table:
666 * @cnc: a #GdaLdapConnection
667 * @table_name: a table name, not %NULL
668 * @base_dn: (allow-none): the base DN of the LDAP search, or %NULL for @cnc's own base DN
669 * @filter: (allow-none): the search filter of the LDAP search, or %NULL for a default filter of "(ObjectClass=*)"
670 * @attributes: (allow-none): the search attributes of the LDAP search, or %NULL if only the DN is required
671 * @scope: the search scope of the LDAP search
672 * @error: a place to store errors, or %NULL
673 *
674 * Declare a virtual table based on an LDAP search.
675 *
676 * The @filter argument, if not %NULL, must be a valid LDAP filter string (including the opening and
677 * closing parenthesis).
678 *
679 * The @attribute, if not %NULL, is a list of comma separated LDAP entry attribute names. For each attribute
680 * it is also possible to specify a requested #GType, and how to behave in case of multi valued attributes
681 * So the general format for an attribute is:
682 * "<attribute name>[::<type>][::<muti value handler>]", where:
683 * <itemizedlist>
684 * <listitem><para>"::<type>" is optional, see gda_g_type_from_string() for more
685 * information about valie values for <type></para></listitem>
686 * <listitem><para>"::<muti value handler>" is also optional and specifies how a multi
687 * values attributed is treated. The possibilities for <muti value handler> are:
688 * <itemizedlist>
689 * <listitem><para>"NULL" or "0": a NULL value will be returned</para></listitem>
690 * <listitem><para>"CSV": a comma separated value with all the values of the attribute will be
691 * returned. This only works for G_TYPE_STRING attribute types.</para></listitem>
692 * <listitem><para>"MULT" of "*": a row will be returned for each value of the attribute, effectively
693 * multiplying the number of returned rows</para></listitem>
694 * <listitem><para>"1": only the first vakue of the attribute will be used, the other values ignored</para></listitem>
695 * <listitem><para>"CONCAT": the attributes' values are concatenated (with a newline char between each value)</para></listitem>
696 * <listitem><para>"ERROR": an error value will be returned (this is the default behaviour)</para></listitem>
697 * </itemizedlist>
698 * </para></listitem>
699 * </itemizedlist>
700 *
701 * After each attribute
702 * name (and before the comma for the next attribute if any), it is possible to specify the #GType type using
703 * the "::<type>" syntax (see gda_g_type_from_string() for more information).
704 *
705 * The following example specifies the "uidNumber" attribute to be returned as a string, the "mail" attribute,
706 * and the "objectClass" attribute to be handled as one row per value of that attribute:
707 * <programlisting>"uidNumber::string,mail,objectClass::*"</programlisting>
708 *
709 * Returns: %TRUE if no error occurred
710 *
711 * Since: 4.2.8
712 */
713 gboolean
gda_ldap_connection_declare_table(GdaLdapConnection * cnc,const gchar * table_name,const gchar * base_dn,const gchar * filter,const gchar * attributes,GdaLdapSearchScope scope,GError ** error)714 gda_ldap_connection_declare_table (GdaLdapConnection *cnc, const gchar *table_name,
715 const gchar *base_dn, const gchar *filter,
716 const gchar *attributes, GdaLdapSearchScope scope,
717 GError **error)
718 {
719 LdapTableMap *map;
720 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
721 g_return_val_if_fail (table_name && *table_name, FALSE);
722
723 map = g_new0 (LdapTableMap, 1);
724 GDA_VCONNECTION_DATA_MODEL_SPEC (map)->data_model = NULL;
725 GDA_VCONNECTION_DATA_MODEL_SPEC (map)->create_columns_func = (GdaVconnectionDataModelCreateColumnsFunc) _ldap_create_columns_func;
726 GDA_VCONNECTION_DATA_MODEL_SPEC (map)->create_model_func = NULL;
727 GDA_VCONNECTION_DATA_MODEL_SPEC (map)->create_filter_func = _ldap_table_create_filter;
728 GDA_VCONNECTION_DATA_MODEL_SPEC (map)->create_filtered_model_func = _ldap_table_create_model_func;
729 map->ldap_cnc = g_object_ref (cnc);
730 map->table_name = gda_sql_identifier_quote (table_name, GDA_CONNECTION (cnc), NULL, TRUE, FALSE);
731 map->filters_hash = NULL;
732 if (base_dn)
733 map->base_dn = g_strdup (base_dn);
734 if (filter)
735 map->filter = g_strdup (filter);
736 if (attributes)
737 map->attributes = g_strdup (attributes);
738 map->scope = scope ? scope : GDA_LDAP_SEARCH_BASE;
739
740 cnc->priv->maps = g_slist_append (cnc->priv->maps, map);
741 if (!gda_vconnection_data_model_add (GDA_VCONNECTION_DATA_MODEL (cnc),
742 (GdaVconnectionDataModelSpec*) map,
743 (GDestroyNotify) _ldap_table_map_free, table_name, error)) {
744 cnc->priv->maps = g_slist_remove (cnc->priv->maps, map);
745 return FALSE;
746 }
747
748 return TRUE;
749 }
750
751 /**
752 * gda_ldap_connection_undeclare_table:
753 * @cnc: a #GdaLdapConnection
754 * @table_name: a table name, not %NULL
755 * @error: a place to store errors, or %NULL
756 *
757 * Remove a table which has been declared using gda_ldap_connection_declare_table().
758 *
759 * Returns: %TRUE if no error occurred
760 *
761 * Since: 4.2.8
762 */
763 gboolean
gda_ldap_connection_undeclare_table(GdaLdapConnection * cnc,const gchar * table_name,GError ** error)764 gda_ldap_connection_undeclare_table (GdaLdapConnection *cnc, const gchar *table_name, GError **error)
765 {
766 GdaVconnectionDataModelSpec *specs;
767 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
768 g_return_val_if_fail (table_name && *table_name, FALSE);
769
770 specs = gda_vconnection_data_model_get (GDA_VCONNECTION_DATA_MODEL (cnc), table_name);
771 if (specs && ! g_slist_find (cnc->priv->maps, specs)) {
772 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
773 GDA_SERVER_PROVIDER_MISUSE_ERROR,
774 "%s", _("Can't remove non LDAP virtual table"));
775 return FALSE;
776 }
777 return gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (cnc), table_name, error);
778 }
779
780 /**
781 * gda_ldap_connection_describe_table:
782 * @cnc: a #GdaLdapConnection
783 * @table_name: a table name, not %NULL
784 * @out_base_dn: (allow-none) (transfer none): a place to store the LDAP search base DN, or %NULL
785 * @out_filter: (allow-none) (transfer none): a place to store the LDAP search filter, or %NULL
786 * @out_attributes: (allow-none) (transfer none): a place to store the LDAP search attributes, or %NULL
787 * @out_scope: (allow-none) (transfer none): a place to store the LDAP search scope, or %NULL
788 * @error: a place to store errors, or %NULL
789 *
790 * Get information about a virtual table, the information which has been passed to
791 * gda_ldap_connection_declare_table() when the table was created.
792 *
793 * Returns: %TRUE if no error occurred
794 *
795 * Since: 4.2.8
796 */
797 gboolean
gda_ldap_connection_describe_table(GdaLdapConnection * cnc,const gchar * table_name,const gchar ** out_base_dn,const gchar ** out_filter,const gchar ** out_attributes,GdaLdapSearchScope * out_scope,GError ** error)798 gda_ldap_connection_describe_table (GdaLdapConnection *cnc, const gchar *table_name,
799 const gchar **out_base_dn, const gchar **out_filter,
800 const gchar **out_attributes,
801 GdaLdapSearchScope *out_scope, GError **error)
802 {
803 GdaVconnectionDataModelSpec *specs;
804 LdapTableMap *map;
805
806 if (out_base_dn)
807 *out_base_dn = NULL;
808 if (out_filter)
809 *out_filter = NULL;
810 if (out_attributes)
811 *out_attributes = NULL;
812 if (out_scope)
813 *out_scope = GDA_LDAP_SEARCH_BASE;
814
815 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
816 g_return_val_if_fail (table_name && *table_name, FALSE);
817
818 specs = gda_vconnection_data_model_get (GDA_VCONNECTION_DATA_MODEL (cnc), table_name);
819 if (specs && ! g_slist_find (cnc->priv->maps, specs)) {
820 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
821 GDA_SERVER_PROVIDER_MISUSE_ERROR,
822 "%s", _("Can't describe non LDAP virtual table"));
823 return FALSE;
824 }
825
826 if (!specs) {
827 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
828 GDA_SERVER_PROVIDER_MISUSE_ERROR,
829 "%s", _("Unknown LDAP virtual table"));
830 return FALSE;
831 }
832
833 map = (LdapTableMap*) specs;
834 if (out_base_dn)
835 *out_base_dn = map->base_dn;
836 if (out_filter)
837 *out_filter = map->filter;
838 if (out_attributes)
839 *out_attributes = map->attributes;
840 if (out_scope)
841 *out_scope = map->scope;
842 return TRUE;
843 }
844
845 static void
gda_ldap_attribute_free(GdaLdapAttribute * attr)846 gda_ldap_attribute_free (GdaLdapAttribute *attr)
847 {
848 if (attr) {
849 gint i;
850 g_free (attr->attr_name);
851 for (i = 0; attr->values[i]; i++)
852 gda_value_free (attr->values[i]);
853 g_free (attr->values);
854 }
855 }
856
857 /**
858 * gda_ldap_entry_free:
859 * @entry: (transfer full): a #GdaLdapEntry pointer
860 *
861 * Frees @entry
862 *
863 * Since: 4.2.8
864 */
865 void
gda_ldap_entry_free(GdaLdapEntry * entry)866 gda_ldap_entry_free (GdaLdapEntry *entry)
867 {
868 if (entry) {
869 g_free (entry->dn);
870 if (entry->attributes) {
871 gint i;
872 for (i = 0; entry->attributes[i]; i++)
873 gda_ldap_attribute_free (entry->attributes[i]);
874 g_free (entry->attributes);
875 }
876 if (entry->attributes_hash)
877 g_hash_table_destroy (entry->attributes_hash);
878 g_free (entry);
879 }
880 }
881
882 /**
883 * gda_ldap_entry_new:
884 * @dn: (allow-none): a Distinguished name, or %NULL
885 *
886 * Creates a new #GdaLdapEntry. This function is useful when using gda_ldap_modify_entry()
887 *
888 * Returns: a new #GdaLdapEntry
889 *
890 * Since: 5.2.0
891 */
892 GdaLdapEntry *
gda_ldap_entry_new(const gchar * dn)893 gda_ldap_entry_new (const gchar *dn)
894 {
895 GdaLdapEntry *entry;
896 entry = g_new0 (GdaLdapEntry, 1);
897 if (dn)
898 entry->dn = g_strdup (dn);
899 entry->attributes_hash = g_hash_table_new (g_str_hash, g_str_equal);
900 entry->nb_attributes = 0;
901 entry->attributes = g_new0 (GdaLdapAttribute*, 1);
902 return entry;
903 }
904
905 /**
906 * gda_ldap_entry_add_attribute:
907 * @entry: a #GdaLdapEntry pointer
908 * @merge: set to %TRUE to merge the values in case of an existing attribute in @entry, and %FALSE to replace any existing attribute's values in @entry
909 * @attr_name: the name of the attribute to add
910 * @nb_values: number of values in @values
911 * @values: (array length=nb_values): an array of #GValue (as much values as specified by @nb_values)
912 *
913 * Add an attribute (ans its values) to @entry. If the attribute is already present in @entry,
914 * then the attribute's values are merged or replaced depending on the @merge argument.
915 *
916 * Since: 5.2.0
917 */
918 void
gda_ldap_entry_add_attribute(GdaLdapEntry * entry,gboolean merge,const gchar * attr_name,guint nb_values,GValue ** values)919 gda_ldap_entry_add_attribute (GdaLdapEntry *entry, gboolean merge, const gchar *attr_name,
920 guint nb_values, GValue **values)
921 {
922 guint i;
923 g_return_if_fail (entry);
924 g_return_if_fail (nb_values > 0);
925 g_return_if_fail (values);
926 g_return_if_fail (attr_name && *attr_name);
927
928 GdaLdapAttribute *att = NULL;
929 GdaLdapAttribute *natt = NULL;
930 guint replace_pos = G_MAXUINT;
931
932 if (entry->attributes_hash)
933 att = g_hash_table_lookup (entry->attributes_hash, attr_name);
934 else
935 entry->attributes_hash = g_hash_table_new (g_str_hash, g_str_equal);
936
937 if (att) {
938 if (merge) {
939 TO_IMPLEMENT;
940 return;
941 }
942 else {
943 /* get rid of @attr */
944 g_hash_table_remove (entry->attributes_hash, att->attr_name);
945 for (i = 0; i < entry->nb_attributes; i++) {
946 if (entry->attributes [i] == att) {
947 replace_pos = i;
948 entry->attributes [i] = NULL;
949 break;
950 }
951 }
952 gda_ldap_attribute_free (att);
953 }
954 }
955
956 natt = g_new0 (GdaLdapAttribute, 1);
957 natt->attr_name = g_strdup (attr_name);
958 natt->nb_values = nb_values;
959 if (natt->nb_values > 0) {
960 natt->values = g_new0 (GValue *, natt->nb_values + 1);
961 for (i = 0; i < natt->nb_values; i++) {
962 if (values [i])
963 natt->values [i] = gda_value_copy (values [i]);
964 else
965 natt->values [i] = NULL;
966 }
967 }
968 g_hash_table_insert (entry->attributes_hash, natt->attr_name, natt);
969 if (replace_pos != G_MAXUINT)
970 entry->attributes [replace_pos] = natt;
971 else {
972 entry->nb_attributes++;
973 entry->attributes = g_renew (GdaLdapAttribute*, entry->attributes, entry->nb_attributes + 1);
974 entry->attributes [entry->nb_attributes - 1] = natt;
975 entry->attributes [entry->nb_attributes] = NULL;
976 }
977 }
978
979
980 /* proxy declaration */
981 GdaLdapEntry *_gda_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **error);
982 GdaLdapEntry **_gda_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar **attributes, GError **error);
983
984 /**
985 * gda_ldap_describe_entry:
986 * @cnc: a #GdaLdapConnection connection
987 * @dn: (allow-none): the Distinguished Name of the LDAP entry to describe
988 * @error: (allow-none): a place to store errors, or %NULL
989 *
990 * Describes the LDAP entry which DN is @dn. If @dn is %NULL, then the top entry (as specified when
991 * the LDAP connection was opened) is described.
992 *
993 * Returns: (transfer full) (Free-function: gda_ldap_entry_free): a new #GdaLdapEntry, or %NULL if an error occurred or if the @dn entry does not exist
994 *
995 * Since: 4.2.8
996 */
997 GdaLdapEntry *
gda_ldap_describe_entry(GdaLdapConnection * cnc,const gchar * dn,GError ** error)998 gda_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **error)
999 {
1000 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1001
1002 return _gda_ldap_describe_entry (cnc, dn, error);
1003 }
1004
1005 /**
1006 * gda_ldap_get_entry_children:
1007 * @cnc: a #GdaLdapConnection connection
1008 * @dn: (allow-none): the Distinguished Name of the LDAP entry to get children from
1009 * @attributes: (allow-none) (array zero-terminated=1) (element-type gchar*): a %NULL terminated array of attributes to fetch for each child, or %NULL if no attribute is requested
1010 * @error: (allow-none): a place to store errors, or %NULL
1011 *
1012 * Get the list of children entries for the LDAP entry which DN is @dn. If the @dn entry does not have any
1013 * child, then this function returns an array which first element is %NULL.
1014 *
1015 * If @dn is %NULL, then the top entry (as specified when the LDAP connection was opened) is used.
1016 *
1017 * Returns: (transfer full) (element_type GdaLdapEntry) (array zero-terminated=1): a %NULL terminated array of #GdaLdapEntry for each child entry, or %NULL if an error occurred or if the @dn entry does not exist
1018 *
1019 * Since: 4.2.8
1020 */
1021 GdaLdapEntry **
gda_ldap_get_entry_children(GdaLdapConnection * cnc,const gchar * dn,gchar ** attributes,GError ** error)1022 gda_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar **attributes, GError **error)
1023 {
1024 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1025
1026 return _gda_ldap_get_entry_children (cnc, dn, attributes, error);
1027 }
1028
1029 gchar **_gda_ldap_dn_split (const gchar *dn, gboolean all);
1030
1031 /**
1032 * gda_ldap_dn_split
1033 * @dn: a Distinguished Name string
1034 * @all: set to %FALSE to split @dn into its RND and its parent DN, or %TRUE to completely split @dn
1035 *
1036 * Splits @dn into its components.
1037 *
1038 * Returns: (transfer full) (Free-function: g_strfreev): a %NULL terminated array containing the DN parts (free using g_strfreev()), or %NULL if an error occurred because @dn is not a valid DN expression
1039 *
1040 * Since: 4.2.8
1041 */
1042 gchar **
gda_ldap_dn_split(const gchar * dn,gboolean all)1043 gda_ldap_dn_split (const gchar *dn, gboolean all)
1044 {
1045 return _gda_ldap_dn_split (dn, all);
1046 }
1047
1048 gboolean _gda_ldap_is_dn (const gchar *dn);
1049
1050 /**
1051 * gda_ldap_is_dn:
1052 * @dn: a Distinguished Name string
1053 *
1054 * Tells if @dn represents a distinguished name (it only checks for the syntax, not for
1055 * the actual existence of the entry with that distinguished name).
1056 *
1057 * Returns: %TRUE if @dn is a valid representation of a distinguished name
1058 *
1059 * Since: 4.2.8
1060 */
1061 gboolean
gda_ldap_is_dn(const gchar * dn)1062 gda_ldap_is_dn (const gchar *dn)
1063 {
1064 return _gda_ldap_is_dn (dn);
1065 }
1066
1067 const gchar *_gda_ldap_get_base_dn (GdaLdapConnection *cnc);
1068
1069 /**
1070 * gda_ldap_connection_get_base_dn:
1071 * @cnc: a #GdaLdapConnection
1072 *
1073 * Get the base DN which was used when the LDAP connection was opened
1074 *
1075 * Returns: the base DN, or %NULL
1076 *
1077 * Since: 4.2.8
1078 */
1079 const gchar *
gda_ldap_connection_get_base_dn(GdaLdapConnection * cnc)1080 gda_ldap_connection_get_base_dn (GdaLdapConnection *cnc)
1081 {
1082 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
1083
1084 return _gda_ldap_get_base_dn (cnc);
1085 }
1086
1087 GdaLdapClass *_gda_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname);
1088 /**
1089 * gda_ldap_get_class_info:
1090 * @cnc: a #GdaLdapConnection
1091 * @classname: an LDAP class name
1092 *
1093 * Get information about an LDAP class
1094 *
1095 * Returns: (transfer none): a #GdaLdapClass
1096 *
1097 * Since: 4.2.8
1098 */
1099 GdaLdapClass*
gda_ldap_get_class_info(GdaLdapConnection * cnc,const gchar * classname)1100 gda_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
1101 {
1102 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
1103
1104 return _gda_ldap_get_class_info (cnc, classname);
1105 }
1106
1107 const GSList *_gda_ldap_get_top_classes (GdaLdapConnection *cnc);
1108 /**
1109 * gda_ldap_get_top_classes:
1110 * @cnc: a #GdaLdapConnection
1111 *
1112 * get a list of the top level LDAP classes (ie. classes which don't have any parent)
1113 *
1114 * Returns: (transfer none) (element-type GdaLdapClass): a list of #GdaLdapClass pointers (don't modify it)
1115 *
1116 * Since: 4.2.8
1117 */
1118 const GSList *
gda_ldap_get_top_classes(GdaLdapConnection * cnc)1119 gda_ldap_get_top_classes (GdaLdapConnection *cnc)
1120 {
1121 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
1122
1123 return _gda_ldap_get_top_classes (cnc);
1124 }
1125
1126 GSList *_gda_ldap_entry_get_attributes_list (GdaLdapConnection *cnc, GdaLdapEntry *entry, GdaLdapAttribute *object_class_attr);
1127 /**
1128 * gda_ldap_entry_get_attributes_list:
1129 * @cnc: a #GdaLdapConnection
1130 * @entry: a #GdaLdapEntry
1131 *
1132 * Get a list of all the possible attributes which @entry can have. Each possible attribute is represented
1133 * by a #GdaLdapAttributeDefinition strunture.
1134 *
1135 * Returns: (transfer full) (element-type GdaLdapAttributeDefinition): a #GSList of #GdaLdapAttributeDefinition pointers, free the list using gda_ldap_attributes_list_free()
1136 *
1137 * Since: 5.2.0
1138 */
1139 GSList *
gda_ldap_entry_get_attributes_list(GdaLdapConnection * cnc,GdaLdapEntry * entry)1140 gda_ldap_entry_get_attributes_list (GdaLdapConnection *cnc, GdaLdapEntry *entry)
1141 {
1142 g_return_val_if_fail (entry, NULL);
1143
1144 return _gda_ldap_entry_get_attributes_list (cnc, entry, NULL);
1145 }
1146
1147 /**
1148 * gda_ldap_attributes_list_free:
1149 * @list: (allow-none): a #GSList of #GdaLdapAttributeDefinition pointers, or %NULL
1150 *
1151 * Frees the list returned by gda_ldap_entry_get_attributes_list().
1152 *
1153 * Since: 5.2.0
1154 */
1155 void
gda_ldap_attributes_list_free(GSList * list)1156 gda_ldap_attributes_list_free (GSList *list)
1157 {
1158 GSList *l;
1159 if (!list)
1160 return;
1161 for (l = list; l; l = l->next) {
1162 GdaLdapAttributeDefinition *def;
1163 def = (GdaLdapAttributeDefinition*) l->data;
1164 if (def) {
1165 g_free (def->name);
1166 g_free (def);
1167 }
1168 }
1169 g_slist_free (list);
1170 }
1171
1172
1173 gboolean
1174 _gda_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
1175 GdaLdapEntry *entry, GdaLdapEntry *ref_entry, GError **error);
1176
1177 /**
1178 * gda_ldap_add_entry:
1179 * @cnc: a #GdaLdapConnection
1180 * @entry: a #GdaLDapEntry describing the LDAP entry to add
1181 * @error: (allow-none): a place to store an error, or %NULL
1182 *
1183 * Creates a new LDAP entry.
1184 *
1185 * Returns: %TRUE if no error occurred
1186 *
1187 * Since: 5.2.0
1188 */
1189 gboolean
gda_ldap_add_entry(GdaLdapConnection * cnc,GdaLdapEntry * entry,GError ** error)1190 gda_ldap_add_entry (GdaLdapConnection *cnc, GdaLdapEntry *entry, GError **error)
1191 {
1192 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1193 g_return_val_if_fail (entry, FALSE);
1194 g_return_val_if_fail (entry->dn && *(entry->dn), FALSE);
1195
1196 return _gda_ldap_modify (cnc, GDA_LDAP_MODIFICATION_INSERT, entry, NULL, error);
1197 }
1198
1199 /**
1200 * gda_ldap_remove_entry:
1201 * @cnc: a #GdaLdapConnection
1202 * @entry: a #GdaLDapEntry describing the LDAP entry to remove
1203 * @error: (allow-none): a place to store an error, or %NULL
1204 *
1205 * Delete an LDAP entry.
1206 *
1207 * Returns: %TRUE if no error occurred
1208 *
1209 * Since: 5.2.0
1210 */
1211 gboolean
gda_ldap_remove_entry(GdaLdapConnection * cnc,const gchar * dn,GError ** error)1212 gda_ldap_remove_entry (GdaLdapConnection *cnc, const gchar *dn, GError **error)
1213 {
1214 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1215 g_return_val_if_fail (dn && *dn, FALSE);
1216
1217 GdaLdapEntry entry;
1218 memset (&entry, 0, sizeof (GdaLdapEntry));
1219 entry.dn = (gchar*) dn;
1220
1221 return _gda_ldap_modify (cnc, GDA_LDAP_MODIFICATION_DELETE, &entry, NULL, error);
1222 }
1223
1224 gboolean
1225 _gda_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, const gchar *new_dn, GError **error);
1226
1227 /**
1228 * gda_ldap_rename_entry:
1229 * @cnc: a #GdaLdapConnection
1230 * @current_dn: the current DN of the entry
1231 * @new_dn: the new DN of the entry
1232 * @error: (allow-none): a place to store an error, or %NULL
1233 *
1234 * Renames an LDAP entry.
1235 *
1236 * Returns: %TRUE if no error occurred
1237 *
1238 * Since: 5.2.0
1239 */
1240 gboolean
gda_ldap_rename_entry(GdaLdapConnection * cnc,const gchar * current_dn,const gchar * new_dn,GError ** error)1241 gda_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, const gchar *new_dn, GError **error)
1242 {
1243 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1244 g_return_val_if_fail (current_dn && *current_dn, FALSE);
1245 g_return_val_if_fail (new_dn && *new_dn, FALSE);
1246
1247 return _gda_ldap_rename_entry (cnc, current_dn, new_dn, error);
1248 }
1249
1250 /**
1251 * gda_ldap_modify_entry:
1252 * @cnc: a #GdaLdapConnection
1253 * @modtype: the type of modification to perform
1254 * @entry: a #GdaLDapEntry describing the LDAP entry to apply modifications, along with the attributes which will be modified
1255 * @ref_entry: (allow-none): a #GdaLDapEntry describing the reference LDAP entry, if @modtype is %GDA_LDAP_MODIFICATION_ATTR_DIFF
1256 * @error: (allow-none): a place to store an error, or %NULL
1257 *
1258 * Modifies an LDAP entry.
1259 *
1260 * Returns: %TRUE if no error occurred
1261 *
1262 * Since: 5.2.0
1263 */
1264 gboolean
gda_ldap_modify_entry(GdaLdapConnection * cnc,GdaLdapModificationType modtype,GdaLdapEntry * entry,GdaLdapEntry * ref_entry,GError ** error)1265 gda_ldap_modify_entry (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
1266 GdaLdapEntry *entry, GdaLdapEntry *ref_entry, GError **error)
1267 {
1268 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
1269 g_return_val_if_fail (entry, FALSE);
1270 g_return_val_if_fail (entry->dn && *(entry->dn), FALSE);
1271
1272 return _gda_ldap_modify (cnc, modtype, entry, ref_entry, error);
1273 }
1274